/*
	Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
	Available via Academic Free License >= 2.1 OR the modified BSD license.
	see: http://dojotoolkit.org/license for details
*/

/*
	This is an optimized version of Dojo, built for deployment and not for
	development. To get sources and documentation, please visit:

		http://dojotoolkit.org
*/

// summary:
//		This is the "source loader" for Dojo. This dojo.js ensures that all
//		Base APIs are available once its execution is complete and attempts to
//		automatically determine the correct host environment to use.
// description:
//		"dojo.js" is the basic entry point into the toolkit for all uses and
//		users. The "source loader" is replaced by environment-specific builds
//		and so you should not assume that built versions of the toolkit will
//		function in all supported platforms (Browsers, Rhino, Spidermonkey,
//		etc.). In most cases, users will receive pre-built dojo.js files which
//		contain all of the Base APIs in a single file and which specialize for
//		the Browser platform. After loading dojo.js, you will be able to do the
//		following with the toolkit:
//			All platforms:
//				- load other packages (dojo core, dijit, dojox, and custom
//				  modules) to better structure your code and take advantage of
//				  the inventive capabilities developed by the broad Dojo
//				  community
//				- perform basic network I/O
//				- use Dojo's powerful language supplementing APIs
//				- take advantage of the Dojo event system to better structure
//				  your application
//			Browser only:
//				- use Dojo's powerful and blisteringly-fast CSS query engine to
//				  upgrade and active your web pages without embedding
//				  JavaScript in your markup
//				- get and set accurate information about element style 
//				- shorten the time it takes to build and manipulate DOM
//				  structures with Dojo's HTML handling APIs
//				- create more fluid UI transitions with Dojo's robust and
//				  battle-tested animation facilities

// NOTE:
//		If you are reading this file, you have received a "source" build of
//		Dojo. Unless you are a Dojo developer, it is very unlikely that this is
//		what you want. While functionally identical to builds, source versions
//		of Dojo load more slowly than pre-processed builds.
//
//		We strongly recommend that your applications always use a build of
//		Dojo. To download such a build or find out how you can create
//		customized, high-performance packages of Dojo suitable for use with
//		your application, please visit:
//
//			http://dojotoolkit.org
//
//		Regards,
//		The Dojo Team

if(typeof dojo == "undefined"){
	// only try to load Dojo if we don't already have one. Dojo always follows
	// a "first Dojo wins" policy.
	(function(){
		var getRootNode = function(){
			// attempt to figure out the path to dojo if it isn't set in the config
			if(this["document"] && this["document"]["getElementsByTagName"]){
				var scripts = document.getElementsByTagName("script");
				var rePkg = /dojo\.js(\W|$)/i;
				for(var i = 0; i < scripts.length; i++){
					var src = scripts[i].getAttribute("src");
					if(!src){ continue; }
					var m = src.match(rePkg);
					if(m){
						return { 
							node: scripts[i], 
							root: src.substring(0, m.index)
						};
						/*
						root = src.substring(0, m.index);
						if(!this["djConfig"]){ djConfig = {}; }
						djConfig["baseUrl"] = root;
						break;
						*/
					}
				}
			}
		}

		// we default to a browser environment if we can't figure it out
		var hostEnv = "browser";
		if(typeof djConfig !== "undefined" && djConfig.hostEnv){
			hostEnv = djConfig.hostEnv;
		}else if(
			typeof this["load"] == "function" &&
			(
				typeof this["Packages"] == "function" ||
				typeof this["Packages"] == "object"
			)
		){
			// Rhino environments make Java code available via the Packages
			// object. Obviously, this check could be "juiced" if someone
			// creates a "Packages" object and a "load" function, but we've
			// never seen this happen in the wild yet.
			hostEnv = "rhino";
		}else if(typeof this["load"] == "function"){
			// Spidermonkey has a very spartan environment. The only thing we
			// can count on from it is a "load" function.
			hostEnv = "spidermonkey";
		}
		var tmps = ["bootstrap.js", "loader.js", "hostenv_"+hostEnv+".js"];
		if (this.Jaxer && this.Jaxer.isOnServer) {
			this.load = Jaxer.load;
		}
	
		if(
			this["djConfig"]&&
			(
				djConfig["forceXDomain"] ||
				djConfig["useXDomain"]
			)
		){
			tmps.push("loader_xd.js");
		}
	
		if(this["djConfig"] && djConfig["baseUrl"]){
			// if the user explicitly tells us where Dojo has been loaded from
			// (or should be loaded from) via djConfig, skip the auto-detection
			// routines.
			var root = djConfig["baseUrl"];
		}else{
			var root = "./";
			if(hostEnv === "spidermonkey"){
				// auto-detect the base path via an exception. Hack!
				try{
					throw new Error(""); 
				}catch(e){ 
					root = String(e.fileName || e.sourceURL).split("dojo.js")[0];
				}
			}
			if(!this["djConfig"]){
				djConfig = { baseUrl: root };
			}
	
			// attempt to figure out the path to dojo if it isn't set in the config
			if(this["document"] && this["document"]["getElementsByTagName"]){
				var root = getRootNode().root;	
				if(!this["djConfig"]){ djConfig = {}; }
				djConfig["baseUrl"] = root;
			}
		}
		// FIXME: should we be adding the lang stuff here so we can count on it
		// before the bootstrap stuff?
		for(var x=0; x < tmps.length; x++){
			tmps[x] = root+"_base/_loader/"+tmps[x];
		}
		// the "_base.js" file ensures that the rest of Dojo Base is available.
		// It counts on the package system functioning in order to work, so add
		// it last
		tmps.push(root+"_base.js");

		var lastRoot;
		var isOpera = 0;
		var isWebKit = 0;

		if(hostEnv == "browser"){
			try{
				lastRoot = getRootNode().node;
				var ua = navigator.userAgent;
				isOpera = (ua.indexOf("Opera") >= 0);
				isWebKit = (ua.indexOf("WebKit") >= 0);
			}catch(e){ /* squelch */ }
		}

		// Opera and Safari don't handle injected script tags in the right
		// order, so we resort to XHR to make things work there when we find
		// ourselves in a strict XHTML environment (e.g., document.write bombs
		// out)
		var injectXHRCode = function(src){
			var xhr = new XMLHttpRequest();
			xhr.open("GET", src, false);
			xhr.send();
			eval(xhr.responseText);
		}
	
		var injectScriptNode = function(src){
			if(isWebKit){ return injectXHRCode(src); }
			var head = document.getElementsByTagName("head")[0];
			var script = document.createElement("script");
			script.setAttribute("type", "text/javascript");
			if(head.lastChild === lastRoot){
				head.appendChild(script);
			}else{
				lastRoot.parentNode.insertBefore(script, lastRoot.nextSibling);
			}
			script.src = src;
			lastRoot = script;
		}
		for(var x=0; x < tmps.length; x++){
			if(hostEnv === "rhino" || hostEnv === "spidermonkey" || (this.Jaxer && this.Jaxer.isOnServer)){
				load(tmps[x]);
			}else if(hostEnv === "ff_ext"){
				var l = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
					.getService(Components.interfaces.mozIJSSubScriptLoader);
				l.loadSubScript(tmps[x], this)
			}else if(isOpera){ // opera fails silently!!
				injectXHRCode(tmps[x]);
			}else{
				try{
					document.write("<scr"+"ipt type='text/javascript' src='"+tmps[x]+"'></scr"+"ipt>");
				}catch(e){
					// strict XHTML mode, no document.write
					injectScriptNode(tmps[x]);
				}
			}
		}
	})();
};

if(!dojo._hasResource["dojo.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.window"] = true;
dojo.provide("dojo.window");

dojo.window.getBox = function(){
	// summary:
	//		Returns the dimensions and scroll position of the viewable area of a browser window

	var scrollRoot = (dojo.doc.compatMode == 'BackCompat') ? dojo.body() : dojo.doc.documentElement;

	// get scroll position
	var scroll = dojo._docScroll(); // scrollRoot.scrollTop/Left should work
	return { w: scrollRoot.clientWidth, h: scrollRoot.clientHeight, l: scroll.x, t: scroll.y };
};

dojo.window.get = function(doc){
	// summary:
	// 		Get window object associated with document doc

	// In some IE versions (at least 6.0), document.parentWindow does not return a
	// reference to the real window object (maybe a copy), so we must fix it as well
	// We use IE specific execScript to attach the real window reference to
	// document._parentWindow for later use
	if(dojo.isIE && window !== document.parentWindow){
		/*
		In IE 6, only the variable "window" can be used to connect events (others
		may be only copies).
		*/
		doc.parentWindow.execScript("document._parentWindow = window;", "Javascript");
		//to prevent memory leak, unset it after use
		//another possibility is to add an onUnload handler which seems overkill to me (liucougar)
		var win = doc._parentWindow;
		doc._parentWindow = null;
		return win;	//	Window
	}

	return doc.parentWindow || doc.defaultView;	//	Window
};

dojo.window.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
	// summary:
	//		Scroll the passed node into view, if it is not already.
	
	// don't rely on node.scrollIntoView working just because the function is there

	try{ // catch unexpected/unrecreatable errors (#7808) since we can recover using a semi-acceptable native method
		node = dojo.byId(node);
		var doc = node.ownerDocument || dojo.doc,
			body = doc.body || dojo.body(),
			html = doc.documentElement || body.parentNode,
			isIE = dojo.isIE, isWK = dojo.isWebKit;
		// if an untested browser, then use the native method
		if((!(dojo.isMoz || isIE || isWK || dojo.isOpera) || node == body || node == html) && (typeof node.scrollIntoView != "undefined")){
			node.scrollIntoView(false); // short-circuit to native if possible
			return;
		}
		var backCompat = doc.compatMode == 'BackCompat',
			clientAreaRoot = backCompat? body : html,
			scrollRoot = isWK ? body : clientAreaRoot,
			rootWidth = clientAreaRoot.clientWidth,
			rootHeight = clientAreaRoot.clientHeight,
			rtl = !dojo._isBodyLtr(),
			nodePos = pos || dojo.position(node),
			el = node.parentNode,
			isFixed = function(el){
				return ((isIE <= 6 || (isIE && backCompat))? false : (dojo.style(el, 'position').toLowerCase() == "fixed"));
			};
		if(isFixed(node)){ return; } // nothing to do

		while(el){
			if(el == body){ el = scrollRoot; }
			var elPos = dojo.position(el),
				fixedPos = isFixed(el);
	
			if(el == scrollRoot){
				elPos.w = rootWidth; elPos.h = rootHeight;
				if(scrollRoot == html && isIE && rtl){ elPos.x += scrollRoot.offsetWidth-elPos.w; } // IE workaround where scrollbar causes negative x
				if(elPos.x < 0 || !isIE){ elPos.x = 0; } // IE can have values > 0
				if(elPos.y < 0 || !isIE){ elPos.y = 0; }
			}else{
				var pb = dojo._getPadBorderExtents(el);
				elPos.w -= pb.w; elPos.h -= pb.h; elPos.x += pb.l; elPos.y += pb.t;
			}
	
			if(el != scrollRoot){ // body, html sizes already have the scrollbar removed
				var clientSize = el.clientWidth,
					scrollBarSize = elPos.w - clientSize;
				if(clientSize > 0 && scrollBarSize > 0){
					elPos.w = clientSize;
					if(isIE && rtl){ elPos.x += scrollBarSize; }
				}
				clientSize = el.clientHeight;
				scrollBarSize = elPos.h - clientSize;
				if(clientSize > 0 && scrollBarSize > 0){
					elPos.h = clientSize;
				}
			}
			if(fixedPos){ // bounded by viewport, not parents
				if(elPos.y < 0){
					elPos.h += elPos.y; elPos.y = 0;
				}
				if(elPos.x < 0){
					elPos.w += elPos.x; elPos.x = 0;
				}
				if(elPos.y + elPos.h > rootHeight){
					elPos.h = rootHeight - elPos.y;
				}
				if(elPos.x + elPos.w > rootWidth){
					elPos.w = rootWidth - elPos.x;
				}
			}
			// calculate overflow in all 4 directions
			var l = nodePos.x - elPos.x, // beyond left: < 0
				t = nodePos.y - Math.max(elPos.y, 0), // beyond top: < 0
				r = l + nodePos.w - elPos.w, // beyond right: > 0
				bot = t + nodePos.h - elPos.h; // beyond bottom: > 0
			if(r * l > 0){
				var s = Math[l < 0? "max" : "min"](l, r);
				nodePos.x += el.scrollLeft;
				el.scrollLeft += (isIE >= 8 && !backCompat && rtl)? -s : s;
				nodePos.x -= el.scrollLeft;
			}
			if(bot * t > 0){
				nodePos.y += el.scrollTop;
				el.scrollTop += Math[t < 0? "max" : "min"](t, bot);
				nodePos.y -= el.scrollTop;
			}
			el = (el != scrollRoot) && !fixedPos && el.parentNode;
		}	
	}catch(error){
		console.error('scrollIntoView: ' + error);
		node.scrollIntoView(false);
	}
};

}

if(!dojo._hasResource["dijit._base.manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.manager"] = true;
dojo.provide("dijit._base.manager");

dojo.declare("dijit.WidgetSet", null, {
	// summary:
	//		A set of widgets indexed by id. A default instance of this class is
	//		available as `dijit.registry`
	//
	// example:
	//		Create a small list of widgets:
	//		|	var ws = new dijit.WidgetSet();
	//		|	ws.add(dijit.byId("one"));
	//		| 	ws.add(dijit.byId("two"));
	//		|	// destroy both:
	//		|	ws.forEach(function(w){ w.destroy(); });
	//
	// example:
	//		Using dijit.registry:
	//		|	dijit.registry.forEach(function(w){ /* do something */ });

	constructor: function(){
		this._hash = {};
		this.length = 0;
	},

	add: function(/*dijit._Widget*/ widget){
		// summary:
		//		Add a widget to this list. If a duplicate ID is detected, a error is thrown.
		//
		// widget: dijit._Widget
		//		Any dijit._Widget subclass.
		if(this._hash[widget.id]){
			throw new Error("Tried to register widget with id==" + widget.id + " but that id is already registered");
		}
		this._hash[widget.id] = widget;
		this.length++;
	},

	remove: function(/*String*/ id){
		// summary:
		//		Remove a widget from this WidgetSet. Does not destroy the widget; simply
		//		removes the reference.
		if(this._hash[id]){
			delete this._hash[id];
			this.length--;
		}
	},

	forEach: function(/*Function*/ func, /* Object? */thisObj){
		// summary:
		//		Call specified function for each widget in this set.
		//
		// func:
		//		A callback function to run for each item. Is passed the widget, the index
		//		in the iteration, and the full hash, similar to `dojo.forEach`.
		//
		// thisObj:
		//		An optional scope parameter
		//
		// example:
		//		Using the default `dijit.registry` instance:
		//		|	dijit.registry.forEach(function(widget){
		//		|		console.log(widget.declaredClass);
		//		|	});
		//
		// returns:
		//		Returns self, in order to allow for further chaining.

		thisObj = thisObj || dojo.global;
		var i = 0, id;
		for(id in this._hash){
			func.call(thisObj, this._hash[id], i++, this._hash);
		}
		return this;	// dijit.WidgetSet
	},

	filter: function(/*Function*/ filter, /* Object? */thisObj){
		// summary:
		//		Filter down this WidgetSet to a smaller new WidgetSet
		//		Works the same as `dojo.filter` and `dojo.NodeList.filter`
		//
		// filter:
		//		Callback function to test truthiness. Is passed the widget
		//		reference and the pseudo-index in the object.
		//
		// thisObj: Object?
		//		Option scope to use for the filter function.
		//
		// example:
		//		Arbitrary: select the odd widgets in this list
		//		|	dijit.registry.filter(function(w, i){
		//		|		return i % 2 == 0;
		//		|	}).forEach(function(w){ /* odd ones */ });

		thisObj = thisObj || dojo.global;
		var res = new dijit.WidgetSet(), i = 0, id;
		for(id in this._hash){
			var w = this._hash[id];
			if(filter.call(thisObj, w, i++, this._hash)){
				res.add(w);
			}
		}
		return res; // dijit.WidgetSet
	},

	byId: function(/*String*/ id){
		// summary:
		//		Find a widget in this list by it's id.
		// example:
		//		Test if an id is in a particular WidgetSet
		//		| var ws = new dijit.WidgetSet();
		//		| ws.add(dijit.byId("bar"));
		//		| var t = ws.byId("bar") // returns a widget
		//		| var x = ws.byId("foo"); // returns undefined

		return this._hash[id];	// dijit._Widget
	},

	byClass: function(/*String*/ cls){
		// summary:
		//		Reduce this widgetset to a new WidgetSet of a particular `declaredClass`
		//
		// cls: String
		//		The Class to scan for. Full dot-notated string.
		//
		// example:
		//		Find all `dijit.TitlePane`s in a page:
		//		|	dijit.registry.byClass("dijit.TitlePane").forEach(function(tp){ tp.close(); });

		var res = new dijit.WidgetSet(), id, widget;
		for(id in this._hash){
			widget = this._hash[id];
			if(widget.declaredClass == cls){
				res.add(widget);
			}
		 }
		 return res; // dijit.WidgetSet
},

	toArray: function(){
		// summary:
		//		Convert this WidgetSet into a true Array
		//
		// example:
		//		Work with the widget .domNodes in a real Array
		//		|	dojo.map(dijit.registry.toArray(), function(w){ return w.domNode; });

		var ar = [];
		for(var id in this._hash){
			ar.push(this._hash[id]);
		}
		return ar;	// dijit._Widget[]
},

	map: function(/* Function */func, /* Object? */thisObj){
		// summary:
		//		Create a new Array from this WidgetSet, following the same rules as `dojo.map`
		// example:
		//		|	var nodes = dijit.registry.map(function(w){ return w.domNode; });
		//
		// returns:
		//		A new array of the returned values.
		return dojo.map(this.toArray(), func, thisObj); // Array
	},

	every: function(func, thisObj){
		// summary:
		// 		A synthetic clone of `dojo.every` acting explicitly on this WidgetSet
		//
		// func: Function
		//		A callback function run for every widget in this list. Exits loop
		//		when the first false return is encountered.
		//
		// thisObj: Object?
		//		Optional scope parameter to use for the callback

		thisObj = thisObj || dojo.global;
		var x = 0, i;
		for(i in this._hash){
			if(!func.call(thisObj, this._hash[i], x++, this._hash)){
				return false; // Boolean
			}
		}
		return true; // Boolean
	},

	some: function(func, thisObj){
		// summary:
		// 		A synthetic clone of `dojo.some` acting explictly on this WidgetSet
		//
		// func: Function
		//		A callback function run for every widget in this list. Exits loop
		//		when the first true return is encountered.
		//
		// thisObj: Object?
		//		Optional scope parameter to use for the callback

		thisObj = thisObj || dojo.global;
		var x = 0, i;
		for(i in this._hash){
			if(func.call(thisObj, this._hash[i], x++, this._hash)){
				return true; // Boolean
			}
		}
		return false; // Boolean
	}

});

(function(){

	/*=====
	dijit.registry = {
		// summary:
		//		A list of widgets on a page.
		// description:
		//		Is an instance of `dijit.WidgetSet`
	};
	=====*/
	dijit.registry = new dijit.WidgetSet();

	var hash = dijit.registry._hash,
		attr = dojo.attr,
		hasAttr = dojo.hasAttr,
		style = dojo.style;

	dijit.byId = function(/*String|dijit._Widget*/ id){
		// summary:
		//		Returns a widget by it's id, or if passed a widget, no-op (like dojo.byId())
		return typeof id == "string" ? hash[id] : id; // dijit._Widget
	};

	var _widgetTypeCtr = {};
	dijit.getUniqueId = function(/*String*/widgetType){
		// summary:
		//		Generates a unique id for a given widgetType
	
		var id;
		do{
			id = widgetType + "_" +
				(widgetType in _widgetTypeCtr ?
					++_widgetTypeCtr[widgetType] : _widgetTypeCtr[widgetType] = 0);
		}while(hash[id]);
		return dijit._scopeName == "dijit" ? id : dijit._scopeName + "_" + id; // String
	};
	
	dijit.findWidgets = function(/*DomNode*/ root){
		// summary:
		//		Search subtree under root returning widgets found.
		//		Doesn't search for nested widgets (ie, widgets inside other widgets).
	
		var outAry = [];
	
		function getChildrenHelper(root){
			for(var node = root.firstChild; node; node = node.nextSibling){
				if(node.nodeType == 1){
					var widgetId = node.getAttribute("widgetId");
					if(widgetId){
						outAry.push(hash[widgetId]);
					}else{
						getChildrenHelper(node);
					}
				}
			}
		}
	
		getChildrenHelper(root);
		return outAry;
	};
	
	dijit._destroyAll = function(){
		// summary:
		//		Code to destroy all widgets and do other cleanup on page unload
	
		// Clean up focus manager lingering references to widgets and nodes
		dijit._curFocus = null;
		dijit._prevFocus = null;
		dijit._activeStack = [];
	
		// Destroy all the widgets, top down
		dojo.forEach(dijit.findWidgets(dojo.body()), function(widget){
			// Avoid double destroy of widgets like Menu that are attached to <body>
			// even though they are logically children of other widgets.
			if(!widget._destroyed){
				if(widget.destroyRecursive){
					widget.destroyRecursive();
				}else if(widget.destroy){
					widget.destroy();
				}
			}
		});
	};
	
	if(dojo.isIE){
		// Only run _destroyAll() for IE because we think it's only necessary in that case,
		// and because it causes problems on FF.  See bug #3531 for details.
		dojo.addOnWindowUnload(function(){
			dijit._destroyAll();
		});
	}
	
	dijit.byNode = function(/*DOMNode*/ node){
		// summary:
		//		Returns the widget corresponding to the given DOMNode
		return hash[node.getAttribute("widgetId")]; // dijit._Widget
	};
	
	dijit.getEnclosingWidget = function(/*DOMNode*/ node){
		// summary:
		//		Returns the widget whose DOM tree contains the specified DOMNode, or null if
		//		the node is not contained within the DOM tree of any widget
		while(node){
			var id = node.getAttribute && node.getAttribute("widgetId");
			if(id){
				return hash[id];
			}
			node = node.parentNode;
		}
		return null;
	};

	var shown = (dijit._isElementShown = function(/*Element*/ elem){
		var s = style(elem);
		return (s.visibility != "hidden")
			&& (s.visibility != "collapsed")
			&& (s.display != "none")
			&& (attr(elem, "type") != "hidden");
	});
	
	dijit.hasDefaultTabStop = function(/*Element*/ elem){
		// summary:
		//		Tests if element is tab-navigable even without an explicit tabIndex setting
	
		// No explicit tabIndex setting, need to investigate node type
		switch(elem.nodeName.toLowerCase()){
			case "a":
				// An <a> w/out a tabindex is only navigable if it has an href
				return hasAttr(elem, "href");
			case "area":
			case "button":
			case "input":
			case "object":
			case "select":
			case "textarea":
				// These are navigable by default
				return true;
			case "iframe":
				// If it's an editor <iframe> then it's tab navigable.
				//TODO: feature detect "designMode" in elem.contentDocument?
				if(dojo.isMoz){
					try{
						return elem.contentDocument.designMode == "on";
					}catch(err){
						return false;
					}
				}else if(dojo.isWebKit){
					var doc = elem.contentDocument,
						body = doc && doc.body;
					return body && body.contentEditable == 'true';
				}else{
					// contentWindow.document isn't accessible within IE7/8
					// if the iframe.src points to a foreign url and this
					// page contains an element, that could get focus
					try{
						doc = elem.contentWindow.document;
						body = doc && doc.body;
						return body && body.firstChild && body.firstChild.contentEditable == 'true';
					}catch(e){
						return false;
					}
				}
			default:
				return elem.contentEditable == 'true';
		}
	};
	
	var isTabNavigable = (dijit.isTabNavigable = function(/*Element*/ elem){
		// summary:
		//		Tests if an element is tab-navigable
	
		// TODO: convert (and rename method) to return effective tabIndex; will save time in _getTabNavigable()
		if(attr(elem, "disabled")){
			return false;
		}else if(hasAttr(elem, "tabIndex")){
			// Explicit tab index setting
			return attr(elem, "tabIndex") >= 0; // boolean
		}else{
			// No explicit tabIndex setting, so depends on node type
			return dijit.hasDefaultTabStop(elem);
		}
	});

	dijit._getTabNavigable = function(/*DOMNode*/ root){
		// summary:
		//		Finds descendants of the specified root node.
		//
		// description:
		//		Finds the following descendants of the specified root node:
		//		* the first tab-navigable element in document order
		//		  without a tabIndex or with tabIndex="0"
		//		* the last tab-navigable element in document order
		//		  without a tabIndex or with tabIndex="0"
		//		* the first element in document order with the lowest
		//		  positive tabIndex value
		//		* the last element in document order with the highest
		//		  positive tabIndex value
		var first, last, lowest, lowestTabindex, highest, highestTabindex;
		var walkTree = function(/*DOMNode*/parent){
			dojo.query("> *", parent).forEach(function(child){
				// Skip hidden elements, and also non-HTML elements (those in custom namespaces) in IE,
				// since show() invokes getAttribute("type"), which crash on VML nodes in IE.
				if((dojo.isIE && child.scopeName!=="HTML") || !shown(child)){
					return;
				}

				if(isTabNavigable(child)){
					var tabindex = attr(child, "tabIndex");
					if(!hasAttr(child, "tabIndex") || tabindex == 0){
						if(!first){ first = child; }
						last = child;
					}else if(tabindex > 0){
						if(!lowest || tabindex < lowestTabindex){
							lowestTabindex = tabindex;
							lowest = child;
						}
						if(!highest || tabindex >= highestTabindex){
							highestTabindex = tabindex;
							highest = child;
						}
					}
				}
				if(child.nodeName.toUpperCase() != 'SELECT'){
					walkTree(child);
				}
			});
		};
		if(shown(root)){ walkTree(root) }
		return { first: first, last: last, lowest: lowest, highest: highest };
	}
	dijit.getFirstInTabbingOrder = function(/*String|DOMNode*/ root){
		// summary:
		//		Finds the descendant of the specified root node
		//		that is first in the tabbing order
		var elems = dijit._getTabNavigable(dojo.byId(root));
		return elems.lowest ? elems.lowest : elems.first; // DomNode
	};
	
	dijit.getLastInTabbingOrder = function(/*String|DOMNode*/ root){
		// summary:
		//		Finds the descendant of the specified root node
		//		that is last in the tabbing order
		var elems = dijit._getTabNavigable(dojo.byId(root));
		return elems.last ? elems.last : elems.highest; // DomNode
	};
	
	/*=====
	dojo.mixin(dijit, {
		// defaultDuration: Integer
		//		The default animation speed (in ms) to use for all Dijit
		//		transitional animations, unless otherwise specified
		//		on a per-instance basis. Defaults to 200, overrided by
		//		`djConfig.defaultDuration`
		defaultDuration: 200
	});
	=====*/
	
	dijit.defaultDuration = dojo.config["defaultDuration"] || 200;

})();

}

if(!dojo._hasResource["dijit._base.focus"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.focus"] = true;
dojo.provide("dijit._base.focus");


	// for dijit.isTabNavigable()

// summary:
//		These functions are used to query or set the focus and selection.
//
//		Also, they trace when widgets become activated/deactivated,
//		so that the widget can fire _onFocus/_onBlur events.
//		"Active" here means something similar to "focused", but
//		"focus" isn't quite the right word because we keep track of
//		a whole stack of "active" widgets.  Example: ComboButton --> Menu -->
//		MenuItem.  The onBlur event for ComboButton doesn't fire due to focusing
//		on the Menu or a MenuItem, since they are considered part of the
//		ComboButton widget.  It only happens when focus is shifted
//		somewhere completely different.

dojo.mixin(dijit, {
	// _curFocus: DomNode
	//		Currently focused item on screen
	_curFocus: null,

	// _prevFocus: DomNode
	//		Previously focused item on screen
	_prevFocus: null,

	isCollapsed: function(){
		// summary:
		//		Returns true if there is no text selected
		return dijit.getBookmark().isCollapsed;
	},

	getBookmark: function(){
		// summary:
		//		Retrieves a bookmark that can be used with moveToBookmark to return to the same range
		var bm, rg, tg, sel = dojo.doc.selection, cf = dijit._curFocus;

		if(dojo.global.getSelection){
			//W3C Range API for selections.
			sel = dojo.global.getSelection();
			if(sel){
				if(sel.isCollapsed){
					tg = cf? cf.tagName : "";
					if(tg){
						//Create a fake rangelike item to restore selections.
						tg = tg.toLowerCase();
						if(tg == "textarea" ||
								(tg == "input" && (!cf.type || cf.type.toLowerCase() == "text"))){
							sel = {
								start: cf.selectionStart,
								end: cf.selectionEnd,
								node: cf,
								pRange: true
							};
							return {isCollapsed: (sel.end <= sel.start), mark: sel}; //Object.
						}
					}
					bm = {isCollapsed:true};
				}else{
					rg = sel.getRangeAt(0);
					bm = {isCollapsed: false, mark: rg.cloneRange()};
				}
			}
		}else if(sel){
			// If the current focus was a input of some sort and no selection, don't bother saving
			// a native bookmark.  This is because it causes issues with dialog/page selection restore.
			// So, we need to create psuedo bookmarks to work with.
			tg = cf ? cf.tagName : "";
			tg = tg.toLowerCase();
			if(cf && tg && (tg == "button" || tg == "textarea" || tg == "input")){
				if(sel.type && sel.type.toLowerCase() == "none"){
					return {
						isCollapsed: true,
						mark: null
					}
				}else{
					rg = sel.createRange();
					return {
						isCollapsed: rg.text && rg.text.length?false:true,
						mark: {
							range: rg,
							pRange: true
						}
					};
				}
			}
			bm = {};

			//'IE' way for selections.
			try{
				// createRange() throws exception when dojo in iframe
				//and nothing selected, see #9632
				rg = sel.createRange();
				bm.isCollapsed = !(sel.type == 'Text' ? rg.htmlText.length : rg.length);
			}catch(e){
				bm.isCollapsed = true;
				return bm;
			}
			if(sel.type.toUpperCase() == 'CONTROL'){
				if(rg.length){
					bm.mark=[];
					var i=0,len=rg.length;
					while(i<len){
						bm.mark.push(rg.item(i++));
					}
				}else{
					bm.isCollapsed = true;
					bm.mark = null;
				}
			}else{
				bm.mark = rg.getBookmark();
			}
		}else{
			console.warn("No idea how to store the current selection for this browser!");
		}
		return bm; // Object
	},

	moveToBookmark: function(/*Object*/bookmark){
		// summary:
		//		Moves current selection to a bookmark
		// bookmark:
		//		This should be a returned object from dijit.getBookmark()

		var _doc = dojo.doc,
			mark = bookmark.mark;
		if(mark){
			if(dojo.global.getSelection){
				//W3C Rangi API (FF, WebKit, Opera, etc)
				var sel = dojo.global.getSelection();
				if(sel && sel.removeAllRanges){
					if(mark.pRange){
						var r = mark;
						var n = r.node;
						n.selectionStart = r.start;
						n.selectionEnd = r.end;
					}else{
						sel.removeAllRanges();
						sel.addRange(mark);
					}
				}else{
					console.warn("No idea how to restore selection for this browser!");
				}
			}else if(_doc.selection && mark){
				//'IE' way.
				var rg;
				if(mark.pRange){
					rg = mark.range;
				}else if(dojo.isArray(mark)){
					rg = _doc.body.createControlRange();
					//rg.addElement does not have call/apply method, so can not call it directly
					//rg is not available in "range.addElement(item)", so can't use that either
					dojo.forEach(mark, function(n){
						rg.addElement(n);
					});
				}else{
					rg = _doc.body.createTextRange();
					rg.moveToBookmark(mark);
				}
				rg.select();
			}
		}
	},

	getFocus: function(/*Widget?*/ menu, /*Window?*/ openedForWindow){
		// summary:
		//		Called as getFocus(), this returns an Object showing the current focus
		//		and selected text.
		//
		//		Called as getFocus(widget), where widget is a (widget representing) a button
		//		that was just pressed, it returns where focus was before that button
		//		was pressed.   (Pressing the button may have either shifted focus to the button,
		//		or removed focus altogether.)   In this case the selected text is not returned,
		//		since it can't be accurately determined.
		//
		// menu: dijit._Widget or {domNode: DomNode} structure
		//		The button that was just pressed.  If focus has disappeared or moved
		//		to this button, returns the previous focus.  In this case the bookmark
		//		information is already lost, and null is returned.
		//
		// openedForWindow:
		//		iframe in which menu was opened
		//
		// returns:
		//		A handle to restore focus/selection, to be passed to `dijit.focus`
		var node = !dijit._curFocus || (menu && dojo.isDescendant(dijit._curFocus, menu.domNode)) ? dijit._prevFocus : dijit._curFocus;
		return {
			node: node,
			bookmark: (node == dijit._curFocus) && dojo.withGlobal(openedForWindow || dojo.global, dijit.getBookmark),
			openedForWindow: openedForWindow
		}; // Object
	},

	focus: function(/*Object || DomNode */ handle){
		// summary:
		//		Sets the focused node and the selection according to argument.
		//		To set focus to an iframe's content, pass in the iframe itself.
		// handle:
		//		object returned by get(), or a DomNode

		if(!handle){ return; }

		var node = "node" in handle ? handle.node : handle,		// because handle is either DomNode or a composite object
			bookmark = handle.bookmark,
			openedForWindow = handle.openedForWindow,
			collapsed = bookmark ? bookmark.isCollapsed : false;

		// Set the focus
		// Note that for iframe's we need to use the <iframe> to follow the parentNode chain,
		// but we need to set focus to iframe.contentWindow
		if(node){
			var focusNode = (node.tagName.toLowerCase() == "iframe") ? node.contentWindow : node;
			if(focusNode && focusNode.focus){
				try{
					// Gecko throws sometimes if setting focus is impossible,
					// node not displayed or something like that
					focusNode.focus();
				}catch(e){/*quiet*/}
			}
			dijit._onFocusNode(node);
		}

		// set the selection
		// do not need to restore if current selection is not empty
		// (use keyboard to select a menu item) or if previous selection was collapsed
		// as it may cause focus shift (Esp in IE).
		if(bookmark && dojo.withGlobal(openedForWindow || dojo.global, dijit.isCollapsed) && !collapsed){
			if(openedForWindow){
				openedForWindow.focus();
			}
			try{
				dojo.withGlobal(openedForWindow || dojo.global, dijit.moveToBookmark, null, [bookmark]);
			}catch(e2){
				/*squelch IE internal error, see http://trac.dojotoolkit.org/ticket/1984 */
			}
		}
	},

	// _activeStack: dijit._Widget[]
	//		List of currently active widgets (focused widget and it's ancestors)
	_activeStack: [],

	registerIframe: function(/*DomNode*/ iframe){
		// summary:
		//		Registers listeners on the specified iframe so that any click
		//		or focus event on that iframe (or anything in it) is reported
		//		as a focus/click event on the <iframe> itself.
		// description:
		//		Currently only used by editor.
		// returns:
		//		Handle to pass to unregisterIframe()
		return dijit.registerWin(iframe.contentWindow, iframe);
	},

	unregisterIframe: function(/*Object*/ handle){
		// summary:
		//		Unregisters listeners on the specified iframe created by registerIframe.
		//		After calling be sure to delete or null out the handle itself.
		// handle:
		//		Handle returned by registerIframe()

		dijit.unregisterWin(handle);
	},

	registerWin: function(/*Window?*/targetWindow, /*DomNode?*/ effectiveNode){
		// summary:
		//		Registers listeners on the specified window (either the main
		//		window or an iframe's window) to detect when the user has clicked somewhere
		//		or focused somewhere.
		// description:
		//		Users should call registerIframe() instead of this method.
		// targetWindow:
		//		If specified this is the window associated with the iframe,
		//		i.e. iframe.contentWindow.
		// effectiveNode:
		//		If specified, report any focus events inside targetWindow as
		//		an event on effectiveNode, rather than on evt.target.
		// returns:
		//		Handle to pass to unregisterWin()

		// TODO: make this function private in 2.0; Editor/users should call registerIframe(),

		var mousedownListener = function(evt){
			dijit._justMouseDowned = true;
			setTimeout(function(){ dijit._justMouseDowned = false; }, 0);
			
			// workaround weird IE bug where the click is on an orphaned node
			// (first time clicking a Select/DropDownButton inside a TooltipDialog)
			if(dojo.isIE && evt && evt.srcElement && evt.srcElement.parentNode == null){
				return;
			}

			dijit._onTouchNode(effectiveNode || evt.target || evt.srcElement, "mouse");
		};
		//dojo.connect(targetWindow, "onscroll", ???);

		// Listen for blur and focus events on targetWindow's document.
		// IIRC, I'm using attachEvent() rather than dojo.connect() because focus/blur events don't bubble
		// through dojo.connect(), and also maybe to catch the focus events early, before onfocus handlers
		// fire.
		// Connect to <html> (rather than document) on IE to avoid memory leaks, but document on other browsers because
		// (at least for FF) the focus event doesn't fire on <html> or <body>.
		var doc = dojo.isIE ? targetWindow.document.documentElement : targetWindow.document;
		if(doc){
			if(dojo.isIE){
				doc.attachEvent('onmousedown', mousedownListener);
				var activateListener = function(evt){
					// IE reports that nodes like <body> have gotten focus, even though they have tabIndex=-1,
					// Should consider those more like a mouse-click than a focus....
					if(evt.srcElement.tagName.toLowerCase() != "#document" &&
						dijit.isTabNavigable(evt.srcElement)){
						dijit._onFocusNode(effectiveNode || evt.srcElement);
					}else{
						dijit._onTouchNode(effectiveNode || evt.srcElement);
					}
				};
				doc.attachEvent('onactivate', activateListener);
				var deactivateListener =  function(evt){
					dijit._onBlurNode(effectiveNode || evt.srcElement);
				};
				doc.attachEvent('ondeactivate', deactivateListener);

				return function(){
					doc.detachEvent('onmousedown', mousedownListener);
					doc.detachEvent('onactivate', activateListener);
					doc.detachEvent('ondeactivate', deactivateListener);
					doc = null;	// prevent memory leak (apparent circular reference via closure)
				};
			}else{
				doc.addEventListener('mousedown', mousedownListener, true);
				var focusListener = function(evt){
					dijit._onFocusNode(effectiveNode || evt.target);
				};
				doc.addEventListener('focus', focusListener, true);
				var blurListener = function(evt){
					dijit._onBlurNode(effectiveNode || evt.target);
				};
				doc.addEventListener('blur', blurListener, true);

				return function(){
					doc.removeEventListener('mousedown', mousedownListener, true);
					doc.removeEventListener('focus', focusListener, true);
					doc.removeEventListener('blur', blurListener, true);
					doc = null;	// prevent memory leak (apparent circular reference via closure)
				};
			}
		}
	},

	unregisterWin: function(/*Handle*/ handle){
		// summary:
		//		Unregisters listeners on the specified window (either the main
		//		window or an iframe's window) according to handle returned from registerWin().
		//		After calling be sure to delete or null out the handle itself.

		// Currently our handle is actually a function
		handle && handle();
	},

	_onBlurNode: function(/*DomNode*/ node){
		// summary:
		// 		Called when focus leaves a node.
		//		Usually ignored, _unless_ it *isn't* follwed by touching another node,
		//		which indicates that we tabbed off the last field on the page,
		//		in which case every widget is marked inactive
		dijit._prevFocus = dijit._curFocus;
		dijit._curFocus = null;

		if(dijit._justMouseDowned){
			// the mouse down caused a new widget to be marked as active; this blur event
			// is coming late, so ignore it.
			return;
		}

		// if the blur event isn't followed by a focus event then mark all widgets as inactive.
		if(dijit._clearActiveWidgetsTimer){
			clearTimeout(dijit._clearActiveWidgetsTimer);
		}
		dijit._clearActiveWidgetsTimer = setTimeout(function(){
			delete dijit._clearActiveWidgetsTimer;
			dijit._setStack([]);
			dijit._prevFocus = null;
		}, 100);
	},

	_onTouchNode: function(/*DomNode*/ node, /*String*/ by){
		// summary:
		//		Callback when node is focused or mouse-downed
		// node:
		//		The node that was touched.
		// by:
		//		"mouse" if the focus/touch was caused by a mouse down event

		// ignore the recent blurNode event
		if(dijit._clearActiveWidgetsTimer){
			clearTimeout(dijit._clearActiveWidgetsTimer);
			delete dijit._clearActiveWidgetsTimer;
		}

		// compute stack of active widgets (ex: ComboButton --> Menu --> MenuItem)
		var newStack=[];
		try{
			while(node){
				var popupParent = dojo.attr(node, "dijitPopupParent");
				if(popupParent){
					node=dijit.byId(popupParent).domNode;
				}else if(node.tagName && node.tagName.toLowerCase() == "body"){
					// is this the root of the document or just the root of an iframe?
					if(node === dojo.body()){
						// node is the root of the main document
						break;
					}
					// otherwise, find the iframe this node refers to (can't access it via parentNode,
					// need to do this trick instead). window.frameElement is supported in IE/FF/Webkit
					node=dojo.window.get(node.ownerDocument).frameElement;
				}else{
					// if this node is the root node of a widget, then add widget id to stack,
					// except ignore clicks on disabled widgets (actually focusing a disabled widget still works,
					// to support MenuItem)
					var id = node.getAttribute && node.getAttribute("widgetId"),
						widget = id && dijit.byId(id);
					if(widget && !(by == "mouse" && widget.get("disabled"))){
						newStack.unshift(id);
					}
					node=node.parentNode;
				}
			}
		}catch(e){ /* squelch */ }

		dijit._setStack(newStack, by);
	},

	_onFocusNode: function(/*DomNode*/ node){
		// summary:
		//		Callback when node is focused

		if(!node){
			return;
		}

		if(node.nodeType == 9){
			// Ignore focus events on the document itself.  This is here so that
			// (for example) clicking the up/down arrows of a spinner
			// (which don't get focus) won't cause that widget to blur. (FF issue)
			return;
		}

		dijit._onTouchNode(node);

		if(node == dijit._curFocus){ return; }
		if(dijit._curFocus){
			dijit._prevFocus = dijit._curFocus;
		}
		dijit._curFocus = node;
		dojo.publish("focusNode", [node]);
	},

	_setStack: function(/*String[]*/ newStack, /*String*/ by){
		// summary:
		//		The stack of active widgets has changed.  Send out appropriate events and records new stack.
		// newStack:
		//		array of widget id's, starting from the top (outermost) widget
		// by:
		//		"mouse" if the focus/touch was caused by a mouse down event

		var oldStack = dijit._activeStack;
		dijit._activeStack = newStack;

		// compare old stack to new stack to see how many elements they have in common
		for(var nCommon=0; nCommon<Math.min(oldStack.length, newStack.length); nCommon++){
			if(oldStack[nCommon] != newStack[nCommon]){
				break;
			}
		}

		var widget;
		// for all elements that have gone out of focus, send blur event
		for(var i=oldStack.length-1; i>=nCommon; i--){
			widget = dijit.byId(oldStack[i]);
			if(widget){
				widget._focused = false;
				widget._hasBeenBlurred = true;
				if(widget._onBlur){
					widget._onBlur(by);
				}
				dojo.publish("widgetBlur", [widget, by]);
			}
		}

		// for all element that have come into focus, send focus event
		for(i=nCommon; i<newStack.length; i++){
			widget = dijit.byId(newStack[i]);
			if(widget){
				widget._focused = true;
				if(widget._onFocus){
					widget._onFocus(by);
				}
				dojo.publish("widgetFocus", [widget, by]);
			}
		}
	}
});

// register top window and all the iframes it contains
dojo.addOnLoad(function(){
	var handle = dijit.registerWin(window);
	if(dojo.isIE){
		dojo.addOnWindowUnload(function(){
			dijit.unregisterWin(handle);
			handle = null;
		})
	}
});

}

if(!dojo._hasResource["dojo.AdapterRegistry"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.AdapterRegistry"] = true;
dojo.provide("dojo.AdapterRegistry");

dojo.AdapterRegistry = function(/*Boolean?*/ returnWrappers){
	//	summary:
	//		A registry to make contextual calling/searching easier.
	//	description:
	//		Objects of this class keep list of arrays in the form [name, check,
	//		wrap, directReturn] that are used to determine what the contextual
	//		result of a set of checked arguments is. All check/wrap functions
	//		in this registry should be of the same arity.
	//	example:
	//	|	// create a new registry
	//	|	var reg = new dojo.AdapterRegistry();
	//	|	reg.register("handleString",
	//	|		dojo.isString,
	//	|		function(str){
	//	|			// do something with the string here
	//	|		}
	//	|	);
	//	|	reg.register("handleArr",
	//	|		dojo.isArray,
	//	|		function(arr){
	//	|			// do something with the array here
	//	|		}
	//	|	);
	//	|
	//	|	// now we can pass reg.match() *either* an array or a string and
	//	|	// the value we pass will get handled by the right function
	//	|	reg.match("someValue"); // will call the first function
	//	|	reg.match(["someValue"]); // will call the second

	this.pairs = [];
	this.returnWrappers = returnWrappers || false; // Boolean
}

dojo.extend(dojo.AdapterRegistry, {
	register: function(/*String*/ name, /*Function*/ check, /*Function*/ wrap, /*Boolean?*/ directReturn, /*Boolean?*/ override){
		//	summary: 
		//		register a check function to determine if the wrap function or
		//		object gets selected
		//	name:
		//		a way to identify this matcher.
		//	check:
		//		a function that arguments are passed to from the adapter's
		//		match() function.  The check function should return true if the
		//		given arguments are appropriate for the wrap function.
		//	directReturn:
		//		If directReturn is true, the value passed in for wrap will be
		//		returned instead of being called. Alternately, the
		//		AdapterRegistry can be set globally to "return not call" using
		//		the returnWrappers property. Either way, this behavior allows
		//		the registry to act as a "search" function instead of a
		//		function interception library.
		//	override:
		//		If override is given and true, the check function will be given
		//		highest priority. Otherwise, it will be the lowest priority
		//		adapter.
		this.pairs[((override) ? "unshift" : "push")]([name, check, wrap, directReturn]);
	},

	match: function(/* ... */){
		// summary:
		//		Find an adapter for the given arguments. If no suitable adapter
		//		is found, throws an exception. match() accepts any number of
		//		arguments, all of which are passed to all matching functions
		//		from the registered pairs.
		for(var i = 0; i < this.pairs.length; i++){
			var pair = this.pairs[i];
			if(pair[1].apply(this, arguments)){
				if((pair[3])||(this.returnWrappers)){
					return pair[2];
				}else{
					return pair[2].apply(this, arguments);
				}
			}
		}
		throw new Error("No match found");
	},

	unregister: function(name){
		// summary: Remove a named adapter from the registry

		// FIXME: this is kind of a dumb way to handle this. On a large
		// registry this will be slow-ish and we can use the name as a lookup
		// should we choose to trade memory for speed.
		for(var i = 0; i < this.pairs.length; i++){
			var pair = this.pairs[i];
			if(pair[0] == name){
				this.pairs.splice(i, 1);
				return true;
			}
		}
		return false;
	}
});

}

if(!dojo._hasResource["dijit._base.place"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.place"] = true;
dojo.provide("dijit._base.place");





dijit.getViewport = function(){
	// summary:
	//		Returns the dimensions and scroll position of the viewable area of a browser window

	return dojo.window.getBox();
};

/*=====
dijit.__Position = function(){
	// x: Integer
	//		horizontal coordinate in pixels, relative to document body
	// y: Integer
	//		vertical coordinate in pixels, relative to document body

	thix.x = x;
	this.y = y;
}
=====*/


dijit.placeOnScreen = function(
	/* DomNode */			node,
	/* dijit.__Position */	pos,
	/* String[] */			corners,
	/* dijit.__Position? */	padding){
	// summary:
	//		Positions one of the node's corners at specified position
	//		such that node is fully visible in viewport.
	// description:
	//		NOTE: node is assumed to be absolutely or relatively positioned.
	//	pos:
	//		Object like {x: 10, y: 20}
	//	corners:
	//		Array of Strings representing order to try corners in, like ["TR", "BL"].
	//		Possible values are:
	//			* "BL" - bottom left
	//			* "BR" - bottom right
	//			* "TL" - top left
	//			* "TR" - top right
	//	padding:
	//		set padding to put some buffer around the element you want to position.
	// example:
	//		Try to place node's top right corner at (10,20).
	//		If that makes node go (partially) off screen, then try placing
	//		bottom left corner at (10,20).
	//	|	placeOnScreen(node, {x: 10, y: 20}, ["TR", "BL"])

	var choices = dojo.map(corners, function(corner){
		var c = { corner: corner, pos: {x:pos.x,y:pos.y} };
		if(padding){
			c.pos.x += corner.charAt(1) == 'L' ? padding.x : -padding.x;
			c.pos.y += corner.charAt(0) == 'T' ? padding.y : -padding.y;
		}
		return c;
	});

	return dijit._place(node, choices);
}

dijit._place = function(/*DomNode*/ node, /* Array */ choices, /* Function */ layoutNode){
	// summary:
	//		Given a list of spots to put node, put it at the first spot where it fits,
	//		of if it doesn't fit anywhere then the place with the least overflow
	// choices: Array
	//		Array of elements like: {corner: 'TL', pos: {x: 10, y: 20} }
	//		Above example says to put the top-left corner of the node at (10,20)
	// layoutNode: Function(node, aroundNodeCorner, nodeCorner)
	//		for things like tooltip, they are displayed differently (and have different dimensions)
	//		based on their orientation relative to the parent.   This adjusts the popup based on orientation.

	// get {x: 10, y: 10, w: 100, h:100} type obj representing position of
	// viewport over document
	var view = dojo.window.getBox();

	// This won't work if the node is inside a <div style="position: relative">,
	// so reattach it to dojo.doc.body.   (Otherwise, the positioning will be wrong
	// and also it might get cutoff)
	if(!node.parentNode || String(node.parentNode.tagName).toLowerCase() != "body"){
		dojo.body().appendChild(node);
	}

	var best = null;
	dojo.some(choices, function(choice){
		var corner = choice.corner;
		var pos = choice.pos;

		// configure node to be displayed in given position relative to button
		// (need to do this in order to get an accurate size for the node, because
		// a tooltips size changes based on position, due to triangle)
		if(layoutNode){
			layoutNode(node, choice.aroundCorner, corner);
		}

		// get node's size
		var style = node.style;
		var oldDisplay = style.display;
		var oldVis = style.visibility;
		style.visibility = "hidden";
		style.display = "";
		var mb = dojo.marginBox(node);
		style.display = oldDisplay;
		style.visibility = oldVis;

		// coordinates and size of node with specified corner placed at pos,
		// and clipped by viewport
		var startX = Math.max(view.l, corner.charAt(1) == 'L' ? pos.x : (pos.x - mb.w)),
			startY = Math.max(view.t, corner.charAt(0) == 'T' ? pos.y : (pos.y - mb.h)),
			endX = Math.min(view.l + view.w, corner.charAt(1) == 'L' ? (startX + mb.w) : pos.x),
			endY = Math.min(view.t + view.h, corner.charAt(0) == 'T' ? (startY + mb.h) : pos.y),
			width = endX - startX,
			height = endY - startY,
			overflow = (mb.w - width) + (mb.h - height);

		if(best == null || overflow < best.overflow){
			best = {
				corner: corner,
				aroundCorner: choice.aroundCorner,
				x: startX,
				y: startY,
				w: width,
				h: height,
				overflow: overflow
			};
		}
		return !overflow;
	});

	node.style.left = best.x + "px";
	node.style.top = best.y + "px";
	if(best.overflow && layoutNode){
		layoutNode(node, best.aroundCorner, best.corner);
	}
	return best;
}

dijit.placeOnScreenAroundNode = function(
	/* DomNode */		node,
	/* DomNode */		aroundNode,
	/* Object */		aroundCorners,
	/* Function? */		layoutNode){

	// summary:
	//		Position node adjacent or kitty-corner to aroundNode
	//		such that it's fully visible in viewport.
	//
	// description:
	//		Place node such that corner of node touches a corner of
	//		aroundNode, and that node is fully visible.
	//
	// aroundCorners:
	//		Ordered list of pairs of corners to try matching up.
	//		Each pair of corners is represented as a key/value in the hash,
	//		where the key corresponds to the aroundNode's corner, and
	//		the value corresponds to the node's corner:
	//
	//	|	{ aroundNodeCorner1: nodeCorner1, aroundNodeCorner2: nodeCorner2, ...}
	//
	//		The following strings are used to represent the four corners:
	//			* "BL" - bottom left
	//			* "BR" - bottom right
	//			* "TL" - top left
	//			* "TR" - top right
	//
	// layoutNode: Function(node, aroundNodeCorner, nodeCorner)
	//		For things like tooltip, they are displayed differently (and have different dimensions)
	//		based on their orientation relative to the parent.   This adjusts the popup based on orientation.
	//
	// example:
	//	|	dijit.placeOnScreenAroundNode(node, aroundNode, {'BL':'TL', 'TR':'BR'});
	//		This will try to position node such that node's top-left corner is at the same position
	//		as the bottom left corner of the aroundNode (ie, put node below
	//		aroundNode, with left edges aligned).  If that fails it will try to put
	// 		the bottom-right corner of node where the top right corner of aroundNode is
	//		(ie, put node above aroundNode, with right edges aligned)
	//

	// get coordinates of aroundNode
	aroundNode = dojo.byId(aroundNode);
	var oldDisplay = aroundNode.style.display;
	aroundNode.style.display="";
	// #3172: use the slightly tighter border box instead of marginBox
	var aroundNodePos = dojo.position(aroundNode, true);
	aroundNode.style.display=oldDisplay;

	// place the node around the calculated rectangle
	return dijit._placeOnScreenAroundRect(node,
		aroundNodePos.x, aroundNodePos.y, aroundNodePos.w, aroundNodePos.h,	// rectangle
		aroundCorners, layoutNode);
};

/*=====
dijit.__Rectangle = function(){
	// x: Integer
	//		horizontal offset in pixels, relative to document body
	// y: Integer
	//		vertical offset in pixels, relative to document body
	// width: Integer
	//		width in pixels
	// height: Integer
	//		height in pixels

	this.x = x;
	this.y = y;
	this.width = width;
	this.height = height;
}
=====*/


dijit.placeOnScreenAroundRectangle = function(
	/* DomNode */			node,
	/* dijit.__Rectangle */	aroundRect,
	/* Object */			aroundCorners,
	/* Function */			layoutNode){

	// summary:
	//		Like dijit.placeOnScreenAroundNode(), except that the "around"
	//		parameter is an arbitrary rectangle on the screen (x, y, width, height)
	//		instead of a dom node.

	return dijit._placeOnScreenAroundRect(node,
		aroundRect.x, aroundRect.y, aroundRect.width, aroundRect.height,	// rectangle
		aroundCorners, layoutNode);
};

dijit._placeOnScreenAroundRect = function(
	/* DomNode */		node,
	/* Number */		x,
	/* Number */		y,
	/* Number */		width,
	/* Number */		height,
	/* Object */		aroundCorners,
	/* Function */		layoutNode){

	// summary:
	//		Like dijit.placeOnScreenAroundNode(), except it accepts coordinates
	//		of a rectangle to place node adjacent to.

	// TODO: combine with placeOnScreenAroundRectangle()

	// Generate list of possible positions for node
	var choices = [];
	for(var nodeCorner in aroundCorners){
		choices.push( {
			aroundCorner: nodeCorner,
			corner: aroundCorners[nodeCorner],
			pos: {
				x: x + (nodeCorner.charAt(1) == 'L' ? 0 : width),
				y: y + (nodeCorner.charAt(0) == 'T' ? 0 : height)
			}
		});
	}

	return dijit._place(node, choices, layoutNode);
};

dijit.placementRegistry= new dojo.AdapterRegistry();
dijit.placementRegistry.register("node",
	function(n, x){
		return typeof x == "object" &&
			typeof x.offsetWidth != "undefined" && typeof x.offsetHeight != "undefined";
	},
	dijit.placeOnScreenAroundNode);
dijit.placementRegistry.register("rect",
	function(n, x){
		return typeof x == "object" &&
			"x" in x && "y" in x && "width" in x && "height" in x;
	},
	dijit.placeOnScreenAroundRectangle);

dijit.placeOnScreenAroundElement = function(
	/* DomNode */		node,
	/* Object */		aroundElement,
	/* Object */		aroundCorners,
	/* Function */		layoutNode){

	// summary:
	//		Like dijit.placeOnScreenAroundNode(), except it accepts an arbitrary object
	//		for the "around" argument and finds a proper processor to place a node.

	return dijit.placementRegistry.match.apply(dijit.placementRegistry, arguments);
};

dijit.getPopupAroundAlignment = function(/*Array*/ position, /*Boolean*/ leftToRight){
	// summary:
	//		Transforms the passed array of preferred positions into a format suitable for passing as the aroundCorners argument to dijit.placeOnScreenAroundElement.
	//
	// position: String[]
	//		This variable controls the position of the drop down.
	//		It's an array of strings with the following values:
	//
	//			* before: places drop down to the left of the target node/widget, or to the right in
	//			  the case of RTL scripts like Hebrew and Arabic
	//			* after: places drop down to the right of the target node/widget, or to the left in
	//			  the case of RTL scripts like Hebrew and Arabic
	//			* above: drop down goes above target node
	//			* below: drop down goes below target node
	//
	//		The list is positions is tried, in order, until a position is found where the drop down fits
	//		within the viewport.
	//
	// leftToRight: Boolean
	//		Whether the popup will be displaying in leftToRight mode.
	//
	var align = {};
	dojo.forEach(position, function(pos){
		switch(pos){
			case "after":
				align[leftToRight ? "BR" : "BL"] = leftToRight ? "BL" : "BR";
				break;
			case "before":
				align[leftToRight ? "BL" : "BR"] = leftToRight ? "BR" : "BL";
				break;
			case "below":
				// first try to align left borders, next try to align right borders (or reverse for RTL mode)
				align[leftToRight ? "BL" : "BR"] = leftToRight ? "TL" : "TR";
				align[leftToRight ? "BR" : "BL"] = leftToRight ? "TR" : "TL";
				break;
			case "above":
			default:
				// first try to align left borders, next try to align right borders (or reverse for RTL mode)
				align[leftToRight ? "TL" : "TR"] = leftToRight ? "BL" : "BR";
				align[leftToRight ? "TR" : "TL"] = leftToRight ? "BR" : "BL";
				break;
		}
	});
	return align;
};

}

if(!dojo._hasResource["dijit._base.window"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.window"] = true;
dojo.provide("dijit._base.window");



dijit.getDocumentWindow = function(doc){
	return dojo.window.get(doc);
};

}

if(!dojo._hasResource["dijit._base.popup"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.popup"] = true;
dojo.provide("dijit._base.popup");





/*=====
dijit.popup.__OpenArgs = function(){
	// popup: Widget
	//		widget to display
	// parent: Widget
	//		the button etc. that is displaying this popup
	// around: DomNode
	//		DOM node (typically a button); place popup relative to this node.  (Specify this *or* "x" and "y" parameters.)
	// x: Integer
	//		Absolute horizontal position (in pixels) to place node at.  (Specify this *or* "around" parameter.)
	// y: Integer
	//		Absolute vertical position (in pixels) to place node at.  (Specify this *or* "around" parameter.)
	// orient: Object|String
	//		When the around parameter is specified, orient should be an
	//		ordered list of tuples of the form (around-node-corner, popup-node-corner).
	//		dijit.popup.open() tries to position the popup according to each tuple in the list, in order,
	//		until the popup appears fully within the viewport.
	//
	//		The default value is {BL:'TL', TL:'BL'}, which represents a list of two tuples:
	//			1. (BL, TL)
	//			2. (TL, BL)
	//		where BL means "bottom left" and "TL" means "top left".
	//		So by default, it first tries putting the popup below the around node, left-aligning them,
	//		and then tries to put it above the around node, still left-aligning them.   Note that the
	//		default is horizontally reversed when in RTL mode.
	//
	//		When an (x,y) position is specified rather than an around node, orient is either
	//		"R" or "L".  R (for right) means that it tries to put the popup to the right of the mouse,
	//		specifically positioning the popup's top-right corner at the mouse position, and if that doesn't
	//		fit in the viewport, then it tries, in order, the bottom-right corner, the top left corner,
	//		and the top-right corner.
	// onCancel: Function
	//		callback when user has canceled the popup by
	//			1. hitting ESC or
	//			2. by using the popup widget's proprietary cancel mechanism (like a cancel button in a dialog);
	//			   i.e. whenever popupWidget.onCancel() is called, args.onCancel is called
	// onClose: Function
	//		callback whenever this popup is closed
	// onExecute: Function
	//		callback when user "executed" on the popup/sub-popup by selecting a menu choice, etc. (top menu only)
	// padding: dijit.__Position
	//		adding a buffer around the opening position. This is only useful when around is not set.
	this.popup = popup;
	this.parent = parent;
	this.around = around;
	this.x = x;
	this.y = y;
	this.orient = orient;
	this.onCancel = onCancel;
	this.onClose = onClose;
	this.onExecute = onExecute;
	this.padding = padding;
}
=====*/

dijit.popup = {
	// summary:
	//		This singleton is used to show/hide widgets as popups.

	// _stack: dijit._Widget[]
	//		Stack of currently popped up widgets.
	//		(someone opened _stack[0], and then it opened _stack[1], etc.)
	_stack: [],
	
	// _beginZIndex: Number
	//		Z-index of the first popup.   (If first popup opens other
	//		popups they get a higher z-index.)
	_beginZIndex: 1000,

	_idGen: 1,

	moveOffScreen: function(/*DomNode*/ node){
		// summary:
		//		Initialization for nodes that will be used as popups
		//
		// description:
		//		Puts node inside a wrapper <div>, and
		//		positions wrapper div off screen, but not display:none, so that
		//		the widget doesn't appear in the page flow and/or cause a blank
		//		area at the bottom of the viewport (making scrollbar longer), but
		//		initialization of contained widgets works correctly

		var wrapper = node.parentNode;

		// Create a wrapper widget for when this node (in the future) will be used as a popup.
		// This is done early because of IE bugs where creating/moving DOM nodes causes focus
		// to go wonky, see tests/robot/Toolbar.html to reproduce
		if(!wrapper || !dojo.hasClass(wrapper, "dijitPopup")){
			wrapper = dojo.create("div",{
				"class":"dijitPopup",
				style:{
					visibility:"hidden",
					top: "-9999px"
				}
			}, dojo.body());
			dijit.setWaiRole(wrapper, "presentation");
			wrapper.appendChild(node);
		}


		var s = node.style;
		s.display = "";
		s.visibility = "";
		s.position = "";
		s.top = "0px";

		dojo.style(wrapper, {
			visibility: "hidden",
			// prevent transient scrollbar causing misalign (#5776), and initial flash in upper left (#10111)
			top: "-9999px"
		});
	},

	getTopPopup: function(){
		// summary:
		//		Compute the closest ancestor popup that's *not* a child of another popup.
		//		Ex: For a TooltipDialog with a button that spawns a tree of menus, find the popup of the button.
		var stack = this._stack;
		for(var pi=stack.length-1; pi > 0 && stack[pi].parent === stack[pi-1].widget; pi--){
			/* do nothing, just trying to get right value for pi */
		}
		return stack[pi];
	},

	open: function(/*dijit.popup.__OpenArgs*/ args){
		// summary:
		//		Popup the widget at the specified position
		//
		// example:
		//		opening at the mouse position
		//		|		dijit.popup.open({popup: menuWidget, x: evt.pageX, y: evt.pageY});
		//
		// example:
		//		opening the widget as a dropdown
		//		|		dijit.popup.open({parent: this, popup: menuWidget, around: this.domNode, onClose: function(){...}});
		//
		//		Note that whatever widget called dijit.popup.open() should also listen to its own _onBlur callback
		//		(fired from _base/focus.js) to know that focus has moved somewhere else and thus the popup should be closed.

		var stack = this._stack,
			widget = args.popup,
			orient = args.orient || (
				(args.parent ? args.parent.isLeftToRight() : dojo._isBodyLtr()) ?
				{'BL':'TL', 'BR':'TR', 'TL':'BL', 'TR':'BR'} :
				{'BR':'TR', 'BL':'TL', 'TR':'BR', 'TL':'BL'}
			),
			around = args.around,
			id = (args.around && args.around.id) ? (args.around.id+"_dropdown") : ("popup_"+this._idGen++);


		// The wrapper may have already been created, but in case it wasn't, create here
		var wrapper = widget.domNode.parentNode;
		if(!wrapper || !dojo.hasClass(wrapper, "dijitPopup")){
			this.moveOffScreen(widget.domNode);
			wrapper = widget.domNode.parentNode;
		}

		dojo.attr(wrapper, {
			id: id,
			style: {
				zIndex: this._beginZIndex + stack.length
			},
			"class": "dijitPopup " + (widget.baseClass || widget["class"] || "").split(" ")[0] +"Popup",
			dijitPopupParent: args.parent ? args.parent.id : ""
		});

		if(dojo.isIE || dojo.isMoz){
			var iframe = wrapper.childNodes[1];
			if(!iframe){
				iframe = new dijit.BackgroundIframe(wrapper);
			}
		}

		// position the wrapper node and make it visible
		var best = around ?
			dijit.placeOnScreenAroundElement(wrapper, around, orient, widget.orient ? dojo.hitch(widget, "orient") : null) :
			dijit.placeOnScreen(wrapper, args, orient == 'R' ? ['TR','BR','TL','BL'] : ['TL','BL','TR','BR'], args.padding);

		wrapper.style.visibility = "visible";
		widget.domNode.style.visibility = "visible";	// counteract effects from _HasDropDown

		var handlers = [];

		// provide default escape and tab key handling
		// (this will work for any widget, not just menu)
		handlers.push(dojo.connect(wrapper, "onkeypress", this, function(evt){
			if(evt.charOrCode == dojo.keys.ESCAPE && args.onCancel){
				dojo.stopEvent(evt);
				args.onCancel();
			}else if(evt.charOrCode === dojo.keys.TAB){
				dojo.stopEvent(evt);
				var topPopup = this.getTopPopup();
				if(topPopup && topPopup.onCancel){
					topPopup.onCancel();
				}
			}
		}));

		// watch for cancel/execute events on the popup and notify the caller
		// (for a menu, "execute" means clicking an item)
		if(widget.onCancel){
			handlers.push(dojo.connect(widget, "onCancel", args.onCancel));
		}

		handlers.push(dojo.connect(widget, widget.onExecute ? "onExecute" : "onChange", this, function(){
			var topPopup = this.getTopPopup();
			if(topPopup && topPopup.onExecute){
				topPopup.onExecute();
			}
		}));

		stack.push({
			wrapper: wrapper,
			iframe: iframe,
			widget: widget,
			parent: args.parent,
			onExecute: args.onExecute,
			onCancel: args.onCancel,
 			onClose: args.onClose,
			handlers: handlers
		});

		if(widget.onOpen){
			// TODO: in 2.0 standardize onShow() (used by StackContainer) and onOpen() (used here)
			widget.onOpen(best);
		}

		return best;
	},

	close: function(/*dijit._Widget*/ popup){
		// summary:
		//		Close specified popup and any popups that it parented

		var stack = this._stack;

		// Basically work backwards from the top of the stack closing popups
		// until we hit the specified popup, but IIRC there was some issue where closing
		// a popup would cause others to close too.  Thus if we are trying to close B in [A,B,C]
		// closing C might close B indirectly and then the while() condition will run where stack==[A]...
		// so the while condition is constructed defensively.
		while(dojo.some(stack, function(elem){return elem.widget == popup;})){
			var top = stack.pop(),
				wrapper = top.wrapper,
				iframe = top.iframe,
				widget = top.widget,
				onClose = top.onClose;

			if(widget.onClose){
				// TODO: in 2.0 standardize onHide() (used by StackContainer) and onClose() (used here)
				widget.onClose();
			}
			dojo.forEach(top.handlers, dojo.disconnect);

			// Move the widget plus it's wrapper off screen, unless it has already been destroyed in above onClose() etc.
			if(widget && widget.domNode){
				this.moveOffScreen(widget.domNode);
			}else{
				dojo.destroy(wrapper);
			}
                        
			if(onClose){
				onClose();
			}
		}
	}
};

dijit._frames = new function(){
	// summary:
	//		cache of iframes
	var queue = [];

	this.pop = function(){
		var iframe;
		if(queue.length){
			iframe = queue.pop();
			iframe.style.display="";
		}else{
			if(dojo.isIE){
				var burl = dojo.config["dojoBlankHtmlUrl"] || (dojo.moduleUrl("dojo", "resources/blank.html")+"") || "javascript:\"\"";
				var html="<iframe src='" + burl + "'"
					+ " style='position: absolute; left: 0px; top: 0px;"
					+ "z-index: -1; filter:Alpha(Opacity=\"0\");'>";
				iframe = dojo.doc.createElement(html);
			}else{
			 	iframe = dojo.create("iframe");
				iframe.src = 'javascript:""';
				iframe.className = "dijitBackgroundIframe";
				dojo.style(iframe, "opacity", 0.1);
			}
			iframe.tabIndex = -1; // Magic to prevent iframe from getting focus on tab keypress - as style didnt work.
			dijit.setWaiRole(iframe,"presentation");
		}
		return iframe;
	};

	this.push = function(iframe){
		iframe.style.display="none";
		queue.push(iframe);
	}
}();


dijit.BackgroundIframe = function(/* DomNode */node){
	// summary:
	//		For IE/FF z-index schenanigans. id attribute is required.
	//
	// description:
	//		new dijit.BackgroundIframe(node)
	//			Makes a background iframe as a child of node, that fills
	//			area (and position) of node

	if(!node.id){ throw new Error("no id"); }
	if(dojo.isIE || dojo.isMoz){
		var iframe = dijit._frames.pop();
		node.appendChild(iframe);
		if(dojo.isIE<7){
			this.resize(node);
			this._conn = dojo.connect(node, 'onresize', this, function(){
				this.resize(node);
			});
		}else{
			dojo.style(iframe, {
				width: '100%',
				height: '100%'
			});
		}
		this.iframe = iframe;
	}
};

dojo.extend(dijit.BackgroundIframe, {
	resize: function(node){
		// summary:
		// 		resize the iframe so its the same size as node
		// description:
		//		this function is a no-op in all browsers except
		//		IE6, which does not support 100% width/height 
		//		of absolute positioned iframes
		if(this.iframe && dojo.isIE<7){
			dojo.style(this.iframe, {
				width: node.offsetWidth + 'px',
				height: node.offsetHeight + 'px'
			});
		}
	},
	destroy: function(){
		// summary:
		//		destroy the iframe
		if(this._conn){
			dojo.disconnect(this._conn);
			this._conn = null;
		}
		if(this.iframe){
			dijit._frames.push(this.iframe);
			delete this.iframe;
		}
	}
});

}

if(!dojo._hasResource["dijit._base.scroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.scroll"] = true;
dojo.provide("dijit._base.scroll");



dijit.scrollIntoView = function(/*DomNode*/ node, /*Object?*/ pos){
	// summary:
	//		Scroll the passed node into view, if it is not already.
	//		Deprecated, use `dojo.window.scrollIntoView` instead.
	
	dojo.window.scrollIntoView(node, pos);
};

}

if(!dojo._hasResource["dojo.uacss"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.uacss"] = true;
dojo.provide("dojo.uacss");

(function(){
	// summary:
	//		Applies pre-set CSS classes to the top-level HTML node, based on:
	// 			- browser (ex: dj_ie)
	//			- browser version (ex: dj_ie6)
	//			- box model (ex: dj_contentBox)
	//			- text direction (ex: dijitRtl)
	//
	//		In addition, browser, browser version, and box model are
	//		combined with an RTL flag when browser text is RTL.  ex: dj_ie-rtl.

	var d = dojo,
		html = d.doc.documentElement,
		ie = d.isIE,
		opera = d.isOpera,
		maj = Math.floor,
		ff = d.isFF,
		boxModel = d.boxModel.replace(/-/,''),

		classes = {
			dj_ie: ie,
			dj_ie6: maj(ie) == 6,
			dj_ie7: maj(ie) == 7,
			dj_ie8: maj(ie) == 8,
			dj_quirks: d.isQuirks,
			dj_iequirks: ie && d.isQuirks,

			// NOTE: Opera not supported by dijit
			dj_opera: opera,

			dj_khtml: d.isKhtml,

			dj_webkit: d.isWebKit,
			dj_safari: d.isSafari,
			dj_chrome: d.isChrome,

			dj_gecko: d.isMozilla,
			dj_ff3: maj(ff) == 3
		}; // no dojo unsupported browsers

	classes["dj_" + boxModel] = true;

	// apply browser, browser version, and box model class names
	var classStr = "";
	for(var clz in classes){
		if(classes[clz]){
			classStr += clz + " ";
		}
	}
	html.className = d.trim(html.className + " " + classStr);

	// If RTL mode, then add dj_rtl flag plus repeat existing classes with -rtl extension.
	// We can't run the code below until the <body> tag has loaded (so we can check for dir=rtl).  
	// Unshift() is to run sniff code before the parser.
	dojo._loaders.unshift(function(){
		if(!dojo._isBodyLtr()){
			var rtlClassStr = "dj_rtl dijitRtl " + classStr.replace(/ /g, "-rtl ")
			html.className = d.trim(html.className + " " + rtlClassStr);
		}
	});
})();

}

if(!dojo._hasResource["dijit._base.sniff"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.sniff"] = true;
// summary:
//		Applies pre-set CSS classes to the top-level HTML node, see
//		`dojo.uacss` for details.
//
//		Simply doing a require on this module will
//		establish this CSS.  Modified version of Morris' CSS hack.

dojo.provide("dijit._base.sniff");



}

if(!dojo._hasResource["dijit._base.typematic"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.typematic"] = true;
dojo.provide("dijit._base.typematic");

dijit.typematic = {
	// summary:
	//		These functions are used to repetitively call a user specified callback
	//		method when a specific key or mouse click over a specific DOM node is
	//		held down for a specific amount of time.
	//		Only 1 such event is allowed to occur on the browser page at 1 time.

	_fireEventAndReload: function(){
		this._timer = null;
		this._callback(++this._count, this._node, this._evt);
		
		// Schedule next event, timer is at most minDelay (default 10ms) to avoid
		// browser overload (particularly avoiding starving DOH robot so it never gets to send a mouseup)
		this._currentTimeout = Math.max(
			this._currentTimeout < 0 ? this._initialDelay :
				(this._subsequentDelay > 1 ? this._subsequentDelay : Math.round(this._currentTimeout * this._subsequentDelay)),
			this._minDelay);
		this._timer = setTimeout(dojo.hitch(this, "_fireEventAndReload"), this._currentTimeout);
	},

	trigger: function(/*Event*/ evt, /*Object*/ _this, /*DOMNode*/ node, /*Function*/ callback, /*Object*/ obj, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
		// summary:
		//		Start a timed, repeating callback sequence.
		//		If already started, the function call is ignored.
		//		This method is not normally called by the user but can be
		//		when the normal listener code is insufficient.
		// evt:
		//		key or mouse event object to pass to the user callback
		// _this:
		//		pointer to the user's widget space.
		// node:
		//		the DOM node object to pass the the callback function
		// callback:
		//		function to call until the sequence is stopped called with 3 parameters:
		// count:
		//		integer representing number of repeated calls (0..n) with -1 indicating the iteration has stopped
		// node:
		//		the DOM node object passed in
		// evt:
		//		key or mouse event object
		// obj:
		//		user space object used to uniquely identify each typematic sequence
		// subsequentDelay (optional):
		//		if > 1, the number of milliseconds until the 3->n events occur
		//		or else the fractional time multiplier for the next event's delay, default=0.9
		// initialDelay (optional):
		//		the number of milliseconds until the 2nd event occurs, default=500ms
		// minDelay (optional):
		//		the maximum delay in milliseconds for event to fire, default=10ms
		if(obj != this._obj){
			this.stop();
			this._initialDelay = initialDelay || 500;
			this._subsequentDelay = subsequentDelay || 0.90;
			this._minDelay = minDelay || 10;
			this._obj = obj;
			this._evt = evt;
			this._node = node;
			this._currentTimeout = -1;
			this._count = -1;
			this._callback = dojo.hitch(_this, callback);
			this._fireEventAndReload();
			this._evt = dojo.mixin({faux: true}, evt);
		}
	},

	stop: function(){
		// summary:
		//		Stop an ongoing timed, repeating callback sequence.
		if(this._timer){
			clearTimeout(this._timer);
			this._timer = null;
		}
		if(this._obj){
			this._callback(-1, this._node, this._evt);
			this._obj = null;
		}
	},

	addKeyListener: function(/*DOMNode*/ node, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
		// summary:
		//		Start listening for a specific typematic key.
		//		See also the trigger method for other parameters.
		// keyObject:
		//		an object defining the key to listen for:
		// 		charOrCode:
		//			the printable character (string) or keyCode (number) to listen for.
		// 		keyCode:
		//			(deprecated - use charOrCode) the keyCode (number) to listen for (implies charCode = 0).
		// 		charCode:
		//			(deprecated - use charOrCode) the charCode (number) to listen for.
		// 		ctrlKey:
		//			desired ctrl key state to initiate the callback sequence:
		//			- pressed (true)
		//			- released (false)
		//			- either (unspecified)
		// 		altKey:
		//			same as ctrlKey but for the alt key
		// 		shiftKey:
		//			same as ctrlKey but for the shift key
		// returns:
		//		an array of dojo.connect handles
		if(keyObject.keyCode){
			keyObject.charOrCode = keyObject.keyCode;
			dojo.deprecated("keyCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
		}else if(keyObject.charCode){
			keyObject.charOrCode = String.fromCharCode(keyObject.charCode);
			dojo.deprecated("charCode attribute parameter for dijit.typematic.addKeyListener is deprecated. Use charOrCode instead.", "", "2.0");
		}
		return [
			dojo.connect(node, "onkeypress", this, function(evt){
				if(evt.charOrCode == keyObject.charOrCode &&
				(keyObject.ctrlKey === undefined || keyObject.ctrlKey == evt.ctrlKey) &&
				(keyObject.altKey === undefined || keyObject.altKey == evt.altKey) &&
				(keyObject.metaKey === undefined || keyObject.metaKey == (evt.metaKey || false)) && // IE doesn't even set metaKey
				(keyObject.shiftKey === undefined || keyObject.shiftKey == evt.shiftKey)){
					dojo.stopEvent(evt);
					dijit.typematic.trigger(evt, _this, node, callback, keyObject, subsequentDelay, initialDelay, minDelay);
				}else if(dijit.typematic._obj == keyObject){
					dijit.typematic.stop();
				}
			}),
			dojo.connect(node, "onkeyup", this, function(evt){
				if(dijit.typematic._obj == keyObject){
					dijit.typematic.stop();
				}
			})
		];
	},

	addMouseListener: function(/*DOMNode*/ node, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
		// summary:
		//		Start listening for a typematic mouse click.
		//		See the trigger method for other parameters.
		// returns:
		//		an array of dojo.connect handles
		var dc = dojo.connect;
		return [
			dc(node, "mousedown", this, function(evt){
				dojo.stopEvent(evt);
				dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
			}),
			dc(node, "mouseup", this, function(evt){
				dojo.stopEvent(evt);
				dijit.typematic.stop();
			}),
			dc(node, "mouseout", this, function(evt){
				dojo.stopEvent(evt);
				dijit.typematic.stop();
			}),
			dc(node, "mousemove", this, function(evt){
				evt.preventDefault();
			}),
			dc(node, "dblclick", this, function(evt){
				dojo.stopEvent(evt);
				if(dojo.isIE){
					dijit.typematic.trigger(evt, _this, node, callback, node, subsequentDelay, initialDelay, minDelay);
					setTimeout(dojo.hitch(this, dijit.typematic.stop), 50);
				}
			})
		];
	},

	addListener: function(/*Node*/ mouseNode, /*Node*/ keyNode, /*Object*/ keyObject, /*Object*/ _this, /*Function*/ callback, /*Number*/ subsequentDelay, /*Number*/ initialDelay, /*Number?*/ minDelay){
		// summary:
		//		Start listening for a specific typematic key and mouseclick.
		//		This is a thin wrapper to addKeyListener and addMouseListener.
		//		See the addMouseListener and addKeyListener methods for other parameters.
		// mouseNode:
		//		the DOM node object to listen on for mouse events.
		// keyNode:
		//		the DOM node object to listen on for key events.
		// returns:
		//		an array of dojo.connect handles
		return this.addKeyListener(keyNode, keyObject, _this, callback, subsequentDelay, initialDelay, minDelay).concat(
			this.addMouseListener(mouseNode, _this, callback, subsequentDelay, initialDelay, minDelay));
	}
};

}

if(!dojo._hasResource["dijit._base.wai"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base.wai"] = true;
dojo.provide("dijit._base.wai");

dijit.wai = {
	onload: function(){
		// summary:
		//		Detects if we are in high-contrast mode or not

		// This must be a named function and not an anonymous
		// function, so that the widget parsing code can make sure it
		// registers its onload function after this function.
		// DO NOT USE "this" within this function.

		// create div for testing if high contrast mode is on or images are turned off
		var div = dojo.create("div",{
			id: "a11yTestNode",
			style:{
				cssText:'border: 1px solid;'
					+ 'border-color:red green;'
					+ 'position: absolute;'
					+ 'height: 5px;'
					+ 'top: -999px;'
					+ 'background-image: url("' + (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")) + '");'
			}
		}, dojo.body());

		// test it
		var cs = dojo.getComputedStyle(div);
		if(cs){
			var bkImg = cs.backgroundImage;
			var needsA11y = (cs.borderTopColor == cs.borderRightColor) || (bkImg != null && (bkImg == "none" || bkImg == "url(invalid-url:)" ));
			dojo[needsA11y ? "addClass" : "removeClass"](dojo.body(), "dijit_a11y");
			if(dojo.isIE){
				div.outerHTML = "";		// prevent mixed-content warning, see http://support.microsoft.com/kb/925014
			}else{
				dojo.body().removeChild(div);
			}
		}
	}
};

// Test if computer is in high contrast mode.
// Make sure the a11y test runs first, before widgets are instantiated.
if(dojo.isIE || dojo.isMoz){	// NOTE: checking in Safari messes things up
	dojo._loaders.unshift(dijit.wai.onload);
}

dojo.mixin(dijit, {
	_XhtmlRoles: /banner|contentinfo|definition|main|navigation|search|note|secondary|seealso/,

	hasWaiRole: function(/*Element*/ elem, /*String*/ role){
		// summary:
		//		Determines if an element has a particular non-XHTML role.
		// returns:
		//		True if elem has the specific non-XHTML role attribute and false if not.
		// 		For backwards compatibility if role parameter not provided,
		// 		returns true if has non XHTML role
		var waiRole = this.getWaiRole(elem);
		return role ? (waiRole.indexOf(role) > -1) : (waiRole.length > 0);
	},

	getWaiRole: function(/*Element*/ elem){
		// summary:
		//		Gets the non-XHTML role for an element (which should be a wai role).
		// returns:
		//		The non-XHTML role of elem or an empty string if elem
		//		does not have a role.
		 return dojo.trim((dojo.attr(elem, "role") || "").replace(this._XhtmlRoles,"").replace("wairole:",""));
	},

	setWaiRole: function(/*Element*/ elem, /*String*/ role){
		// summary:
		//		Sets the role on an element.
		// description:
		//		Replace existing role attribute with new role.
		//		If elem already has an XHTML role, append this role to XHTML role
		//		and remove other ARIA roles.

		var curRole = dojo.attr(elem, "role") || "";
		if(!this._XhtmlRoles.test(curRole)){
			dojo.attr(elem, "role", role);
		}else{
			if((" "+ curRole +" ").indexOf(" " + role + " ") < 0){
				var clearXhtml = dojo.trim(curRole.replace(this._XhtmlRoles, ""));
				var cleanRole = dojo.trim(curRole.replace(clearXhtml, ""));
				dojo.attr(elem, "role", cleanRole + (cleanRole ? ' ' : '') + role);
			}
		}
	},

	removeWaiRole: function(/*Element*/ elem, /*String*/ role){
		// summary:
		//		Removes the specified non-XHTML role from an element.
		// 		Removes role attribute if no specific role provided (for backwards compat.)

		var roleValue = dojo.attr(elem, "role");
		if(!roleValue){ return; }
		if(role){
			var t = dojo.trim((" " + roleValue + " ").replace(" " + role + " ", " "));
			dojo.attr(elem, "role", t);
		}else{
			elem.removeAttribute("role");
		}
	},

	hasWaiState: function(/*Element*/ elem, /*String*/ state){
		// summary:
		//		Determines if an element has a given state.
		// description:
		//		Checks for an attribute called "aria-"+state.
		// returns:
		//		true if elem has a value for the given state and
		//		false if it does not.

		return elem.hasAttribute ? elem.hasAttribute("aria-"+state) : !!elem.getAttribute("aria-"+state);
	},

	getWaiState: function(/*Element*/ elem, /*String*/ state){
		// summary:
		//		Gets the value of a state on an element.
		// description:
		//		Checks for an attribute called "aria-"+state.
		// returns:
		//		The value of the requested state on elem
		//		or an empty string if elem has no value for state.

		return elem.getAttribute("aria-"+state) || "";
	},

	setWaiState: function(/*Element*/ elem, /*String*/ state, /*String*/ value){
		// summary:
		//		Sets a state on an element.
		// description:
		//		Sets an attribute called "aria-"+state.

		elem.setAttribute("aria-"+state, value);
	},

	removeWaiState: function(/*Element*/ elem, /*String*/ state){
		// summary:
		//		Removes a state from an element.
		// description:
		//		Sets an attribute called "aria-"+state.

		elem.removeAttribute("aria-"+state);
	}
});

}

if(!dojo._hasResource["dijit._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._base"] = true;
dojo.provide("dijit._base");











}

if(!dojo._hasResource["dojo.date.stamp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.date.stamp"] = true;
dojo.provide("dojo.date.stamp");

// Methods to convert dates to or from a wire (string) format using well-known conventions

dojo.date.stamp.fromISOString = function(/*String*/formattedString, /*Number?*/defaultTime){
	//	summary:
	//		Returns a Date object given a string formatted according to a subset of the ISO-8601 standard.
	//
	//	description:
	//		Accepts a string formatted according to a profile of ISO8601 as defined by
	//		[RFC3339](http://www.ietf.org/rfc/rfc3339.txt), except that partial input is allowed.
	//		Can also process dates as specified [by the W3C](http://www.w3.org/TR/NOTE-datetime)
	//		The following combinations are valid:
	//
	//			* dates only
	//			|	* yyyy
	//			|	* yyyy-MM
	//			|	* yyyy-MM-dd
	// 			* times only, with an optional time zone appended
	//			|	* THH:mm
	//			|	* THH:mm:ss
	//			|	* THH:mm:ss.SSS
	// 			* and "datetimes" which could be any combination of the above
	//
	//		timezones may be specified as Z (for UTC) or +/- followed by a time expression HH:mm
	//		Assumes the local time zone if not specified.  Does not validate.  Improperly formatted
	//		input may return null.  Arguments which are out of bounds will be handled
	// 		by the Date constructor (e.g. January 32nd typically gets resolved to February 1st)
	//		Only years between 100 and 9999 are supported.
	//
  	//	formattedString:
	//		A string such as 2005-06-30T08:05:00-07:00 or 2005-06-30 or T08:05:00
	//
	//	defaultTime:
	//		Used for defaults for fields omitted in the formattedString.
	//		Uses 1970-01-01T00:00:00.0Z by default.

	if(!dojo.date.stamp._isoRegExp){
		dojo.date.stamp._isoRegExp =
//TODO: could be more restrictive and check for 00-59, etc.
			/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(.\d+)?)?((?:[+-](\d{2}):(\d{2}))|Z)?)?$/;
	}

	var match = dojo.date.stamp._isoRegExp.exec(formattedString),
		result = null;

	if(match){
		match.shift();
		if(match[1]){match[1]--;} // Javascript Date months are 0-based
		if(match[6]){match[6] *= 1000;} // Javascript Date expects fractional seconds as milliseconds

		if(defaultTime){
			// mix in defaultTime.  Relatively expensive, so use || operators for the fast path of defaultTime === 0
			defaultTime = new Date(defaultTime);
			dojo.forEach(dojo.map(["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"], function(prop){
				return defaultTime["get" + prop]();
			}), function(value, index){
				match[index] = match[index] || value;
			});
		}
		result = new Date(match[0]||1970, match[1]||0, match[2]||1, match[3]||0, match[4]||0, match[5]||0, match[6]||0); //TODO: UTC defaults
		if(match[0] < 100){
			result.setFullYear(match[0] || 1970);
		}

		var offset = 0,
			zoneSign = match[7] && match[7].charAt(0);
		if(zoneSign != 'Z'){
			offset = ((match[8] || 0) * 60) + (Number(match[9]) || 0);
			if(zoneSign != '-'){ offset *= -1; }
		}
		if(zoneSign){
			offset -= result.getTimezoneOffset();
		}
		if(offset){
			result.setTime(result.getTime() + offset * 60000);
		}
	}

	return result; // Date or null
}

/*=====
	dojo.date.stamp.__Options = function(){
		//	selector: String
		//		"date" or "time" for partial formatting of the Date object.
		//		Both date and time will be formatted by default.
		//	zulu: Boolean
		//		if true, UTC/GMT is used for a timezone
		//	milliseconds: Boolean
		//		if true, output milliseconds
		this.selector = selector;
		this.zulu = zulu;
		this.milliseconds = milliseconds;
	}
=====*/

dojo.date.stamp.toISOString = function(/*Date*/dateObject, /*dojo.date.stamp.__Options?*/options){
	//	summary:
	//		Format a Date object as a string according a subset of the ISO-8601 standard
	//
	//	description:
	//		When options.selector is omitted, output follows [RFC3339](http://www.ietf.org/rfc/rfc3339.txt)
	//		The local time zone is included as an offset from GMT, except when selector=='time' (time without a date)
	//		Does not check bounds.  Only years between 100 and 9999 are supported.
	//
	//	dateObject:
	//		A Date object

	var _ = function(n){ return (n < 10) ? "0" + n : n; };
	options = options || {};
	var formattedDate = [],
		getter = options.zulu ? "getUTC" : "get",
		date = "";
	if(options.selector != "time"){
		var year = dateObject[getter+"FullYear"]();
		date = ["0000".substr((year+"").length)+year, _(dateObject[getter+"Month"]()+1), _(dateObject[getter+"Date"]())].join('-');
	}
	formattedDate.push(date);
	if(options.selector != "date"){
		var time = [_(dateObject[getter+"Hours"]()), _(dateObject[getter+"Minutes"]()), _(dateObject[getter+"Seconds"]())].join(':');
		var millis = dateObject[getter+"Milliseconds"]();
		if(options.milliseconds){
			time += "."+ (millis < 100 ? "0" : "") + _(millis);
		}
		if(options.zulu){
			time += "Z";
		}else if(options.selector != "time"){
			var timezoneOffset = dateObject.getTimezoneOffset();
			var absOffset = Math.abs(timezoneOffset);
			time += (timezoneOffset > 0 ? "-" : "+") + 
				_(Math.floor(absOffset/60)) + ":" + _(absOffset%60);
		}
		formattedDate.push(time);
	}
	return formattedDate.join('T'); // String
}

}

if(!dojo._hasResource["dojo.parser"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.parser"] = true;
dojo.provide("dojo.parser");


new Date("X"); // workaround for #11279, new Date("") == NaN

dojo.parser = new function(){
	// summary: The Dom/Widget parsing package

	var d = dojo;
	this._attrName = d._scopeName + "Type";
	this._query = "[" + this._attrName + "]";

	function val2type(/*Object*/ value){
		// summary:
		//		Returns name of type of given value.

		if(d.isString(value)){ return "string"; }
		if(typeof value == "number"){ return "number"; }
		if(typeof value == "boolean"){ return "boolean"; }
		if(d.isFunction(value)){ return "function"; }
		if(d.isArray(value)){ return "array"; } // typeof [] == "object"
		if(value instanceof Date) { return "date"; } // assume timestamp
		if(value instanceof d._Url){ return "url"; }
		return "object";
	}

	function str2obj(/*String*/ value, /*String*/ type){
		// summary:
		//		Convert given string value to given type
		switch(type){
			case "string":
				return value;
			case "number":
				return value.length ? Number(value) : NaN;
			case "boolean":
				// for checked/disabled value might be "" or "checked".  interpret as true.
				return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
			case "function":
				if(d.isFunction(value)){
					// IE gives us a function, even when we say something like onClick="foo"
					// (in which case it gives us an invalid function "function(){ foo }"). 
					//  Therefore, convert to string
					value=value.toString();
					value=d.trim(value.substring(value.indexOf('{')+1, value.length-1));
				}
				try{
					if(value === "" || value.search(/[^\w\.]+/i) != -1){
						// The user has specified some text for a function like "return x+5"
						return new Function(value);
					}else{
						// The user has specified the name of a function like "myOnClick"
						// or a single word function "return"
						return d.getObject(value, false) || new Function(value);
					}
				}catch(e){ return new Function(); }
			case "array":
				return value ? value.split(/\s*,\s*/) : [];
			case "date":
				switch(value){
					case "": return new Date("");	// the NaN of dates
					case "now": return new Date();	// current date
					default: return d.date.stamp.fromISOString(value);
				}
			case "url":
				return d.baseUrl + value;
			default:
				return d.fromJson(value);
		}
	}

	var instanceClasses = {
		// map from fully qualified name (like "dijit.Button") to structure like
		// { cls: dijit.Button, params: {label: "string", disabled: "boolean"} }
	};

	// Widgets like BorderContainer add properties to _Widget via dojo.extend().
	// If BorderContainer is loaded after _Widget's parameter list has been cached,
	// we need to refresh that parameter list (for _Widget and all widgets that extend _Widget).
	dojo.connect(dojo, "extend", function(){
		instanceClasses = {};
	});

	function getClassInfo(/*String*/ className){
		// className:
		//		fully qualified name (like "dijit.form.Button")
		// returns:
		//		structure like
		//			{ 
		//				cls: dijit.Button, 
		//				params: { label: "string", disabled: "boolean"}
		//			}

		if(!instanceClasses[className]){
			// get pointer to widget class
			var cls = d.getObject(className);
			if(!cls){ return null; }		// class not defined [yet]

			var proto = cls.prototype;
	
			// get table of parameter names & types
			var params = {}, dummyClass = {};
			for(var name in proto){
				if(name.charAt(0)=="_"){ continue; } 	// skip internal properties
				if(name in dummyClass){ continue; }		// skip "constructor" and "toString"
				var defVal = proto[name];
				params[name]=val2type(defVal);
			}

			instanceClasses[className] = { cls: cls, params: params };
		}
		return instanceClasses[className];
	}

	this._functionFromScript = function(script){
		var preamble = "";
		var suffix = "";
		var argsStr = script.getAttribute("args");
		if(argsStr){
			d.forEach(argsStr.split(/\s*,\s*/), function(part, idx){
				preamble += "var "+part+" = arguments["+idx+"]; ";
			});
		}
		var withStr = script.getAttribute("with");
		if(withStr && withStr.length){
			d.forEach(withStr.split(/\s*,\s*/), function(part){
				preamble += "with("+part+"){";
				suffix += "}";
			});
		}
		return new Function(preamble+script.innerHTML+suffix);
	}

	this.instantiate = function(/* Array */nodes, /* Object? */mixin, /* Object? */args){
		// summary:
		//		Takes array of nodes, and turns them into class instances and
		//		potentially calls a startup method to allow them to connect with
		//		any children.
		// nodes: Array
		//		Array of nodes or objects like
		//	|		{
		//	|			type: "dijit.form.Button",
		//	|			node: DOMNode,
		//	|			scripts: [ ... ],	// array of <script type="dojo/..."> children of node
		//	|			inherited: { ... }	// settings inherited from ancestors like dir, theme, etc.
		//	|		}
		// mixin: Object?
		//		An object that will be mixed in with each node in the array.
		//		Values in the mixin will override values in the node, if they
		//		exist.
		// args: Object?
		//		An object used to hold kwArgs for instantiation.
		//		Supports 'noStart' and inherited.
		var thelist = [], dp = dojo.parser;
		mixin = mixin||{};
		args = args||{};
		
		d.forEach(nodes, function(obj){
			if(!obj){ return; }

			// Get pointers to DOMNode, dojoType string, and clsInfo (metadata about the dojoType), etc.s
			var node, type, clsInfo, clazz, scripts;
			if(obj.node){
				// new format of nodes[] array, object w/lots of properties pre-computed for me
				node = obj.node;
				type = obj.type;
				clsInfo = obj.clsInfo || (type && getClassInfo(type));
				clazz = clsInfo && clsInfo.cls;
				scripts = obj.scripts;
			}else{
				// old (backwards compatible) format of nodes[] array, simple array of DOMNodes
				node = obj;
				type = dp._attrName in mixin ? mixin[dp._attrName] : node.getAttribute(dp._attrName);
				clsInfo = type && getClassInfo(type);
				clazz = clsInfo && clsInfo.cls;
				scripts = (clazz && (clazz._noScript || clazz.prototype._noScript) ? [] : 
							d.query("> script[type^='dojo/']", node));
			}
			if(!clsInfo){
				throw new Error("Could not load class '" + type);
			}

			// Setup hash to hold parameter settings for this widget.   Start with the parameter
			// settings inherited from ancestors ("dir" and "lang").
			// Inherited setting may later be overridden by explicit settings on node itself.
			var params = {},
				attributes = node.attributes;
			if(args.defaults){
				// settings for the document itself (or whatever subtree is being parsed)
				dojo.mixin(params, args.defaults);
			}
			if(obj.inherited){
				// settings from dir=rtl or lang=... on a node above this node
				dojo.mixin(params, obj.inherited);
			}

			// read parameters (ie, attributes) specified on DOMNode
			// clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
			for(var name in clsInfo.params){
				var item = name in mixin?{value:mixin[name],specified:true}:attributes.getNamedItem(name);
				if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
				var value = item.value;
				// Deal with IE quirks for 'class' and 'style'
				switch(name){
				case "class":
					value = "className" in mixin?mixin.className:node.className;
					break;
				case "style":
					value = "style" in mixin?mixin.style:(node.style && node.style.cssText); // FIXME: Opera?
				}
				var _type = clsInfo.params[name];
				if(typeof value == "string"){
					params[name] = str2obj(value, _type);
				}else{
					params[name] = value;
				}
			}

			// Process <script type="dojo/*"> script tags
			// <script type="dojo/method" event="foo"> tags are added to params, and passed to
			// the widget on instantiation.
			// <script type="dojo/method"> tags (with no event) are executed after instantiation
			// <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation
			// note: dojo/* script tags cannot exist in self closing widgets, like <input />
			var connects = [],	// functions to connect after instantiation
				calls = [];		// functions to call after instantiation

			d.forEach(scripts, function(script){
				node.removeChild(script);
				var event = script.getAttribute("event"),
					type = script.getAttribute("type"),
					nf = d.parser._functionFromScript(script);
				if(event){
					if(type == "dojo/connect"){
						connects.push({event: event, func: nf});
					}else{
						params[event] = nf;
					}
				}else{
					calls.push(nf);
				}
			});

			var markupFactory = clazz.markupFactory || clazz.prototype && clazz.prototype.markupFactory;
			// create the instance
			var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node);
			thelist.push(instance);

			// map it to the JS namespace if that makes sense
			var jsname = node.getAttribute("jsId");
			if(jsname){
				d.setObject(jsname, instance);
			}

			// process connections and startup functions
			d.forEach(connects, function(connect){
				d.connect(instance, connect.event, null, connect.func);
			});
			d.forEach(calls, function(func){
				func.call(instance);
			});
		});

		// Call startup on each top level instance if it makes sense (as for
		// widgets).  Parent widgets will recursively call startup on their
		// (non-top level) children
		if(!mixin._started){
			// TODO: for 2.0, when old instantiate() API is desupported, store parent-child
			// relationships in the nodes[] array so that no getParent() call is needed.
			// Note that will  require a parse() call from ContentPane setting a param that the
			// ContentPane is the parent widget (so that the parse doesn't call startup() on the
			// ContentPane's children)
			d.forEach(thelist, function(instance){
				if(	!args.noStart && instance  && 
					instance.startup &&
					!instance._started && 
					(!instance.getParent || !instance.getParent())
				){
					instance.startup();
				}
			});
		}
		return thelist;
	};

	this.parse = function(/*DomNode?*/ rootNode, /* Object? */ args){
		// summary:
		//		Scan the DOM for class instances, and instantiate them.
		//
		// description:
		//		Search specified node (or root node) recursively for class instances,
		//		and instantiate them Searches for
		//		dojoType="qualified.class.name"
		//
		// rootNode: DomNode?
		//		A default starting root node from which to start the parsing. Can be
		//		omitted, defaulting to the entire document. If omitted, the `args`
		//		object can be passed in this place. If the `args` object has a 
		//		`rootNode` member, that is used.
		//
		// args:
		//		a kwArgs object passed along to instantiate()
		//		
		//			* noStart: Boolean?
		//				when set will prevent the parser from calling .startup()
		//				when locating the nodes. 
		//			* rootNode: DomNode?
		//				identical to the function's `rootNode` argument, though
		//				allowed to be passed in via this `args object. 
		//			* inherited: Object
		//				Hash possibly containing dir and lang settings to be applied to
		//				parsed widgets, unless there's another setting on a sub-node that overrides
		//
		//
		// example:
		//		Parse all widgets on a page:
		//	|		dojo.parser.parse();
		//
		// example:
		//		Parse all classes within the node with id="foo"
		//	|		dojo.parser.parse(dojo.byId(foo));
		//
		// example:
		//		Parse all classes in a page, but do not call .startup() on any 
		//		child
		//	|		dojo.parser.parse({ noStart: true })
		//
		// example:
		//		Parse all classes in a node, but do not call .startup()
		//	|		dojo.parser.parse(someNode, { noStart:true });
		//	|		// or
		// 	|		dojo.parser.parse({ noStart:true, rootNode: someNode });

		// determine the root node based on the passed arguments.
		var root;
		if(!args && rootNode && rootNode.rootNode){
			args = rootNode;
			root = args.rootNode;
		}else{
			root = rootNode;
		}

		var attrName = this._attrName;
		function scan(parent, list){
			// summary:
			//		Parent is an Object representing a DOMNode, with or without a dojoType specified.
			//		Scan parent's children looking for nodes with dojoType specified, storing in list[].
			//		If parent has a dojoType, also collects <script type=dojo/*> children and stores in parent.scripts[].
			// parent: Object
			//		Object representing the parent node, like
			//	|	{
			//	|		node: DomNode, 			// scan children of this node
			//	|		inherited: {dir: "rtl"},	// dir/lang setting inherited from above node
			//	|
			//	|		// attributes only set if node has dojoType specified
			//	|		scripts: [],			// empty array, put <script type=dojo/*> in here
			//	|		clsInfo: { cls: dijit.form.Button, ...}
			//	|	}
			// list: DomNode[]
			//		Output array of objects (same format as parent) representing nodes to be turned into widgets

			// Effective dir and lang settings on parent node, either set directly or inherited from grandparent
			var inherited = dojo.clone(parent.inherited);
			dojo.forEach(["dir", "lang"], function(name){
				var val = parent.node.getAttribute(name);
				if(val){
					inherited[name] = val;
				}
			});

			// if parent is a widget, then search for <script type=dojo/*> tags and put them in scripts[].
			var scripts = parent.scripts;

			// unless parent is a widget with the stopParser flag set, continue search for dojoType, recursively
			var recurse = !parent.clsInfo || !parent.clsInfo.cls.prototype.stopParser;

			// scan parent's children looking for dojoType and <script type=dojo/*>
			for(var child = parent.node.firstChild; child; child = child.nextSibling){
				if(child.nodeType == 1){
					var type = recurse && child.getAttribute(attrName);
					if(type){
						// if dojoType specified, add to output array of nodes to instantiate
						var params = {
							"type": type,
							clsInfo: getClassInfo(type),	// note: won't find classes declared via dojo.Declaration
							node: child,
							scripts: [], // <script> nodes that are parent's children
							inherited: inherited // dir & lang attributes inherited from parent
						};
						list.push(params);

						// Recurse, collecting <script type="dojo/..."> children, and also looking for
						// descendant nodes with dojoType specified (unless the widget has the stopParser flag),
						scan(params, list);
					}else if(scripts && child.nodeName.toLowerCase() == "script"){
						// if <script type="dojo/...">, save in scripts[]
						type = child.getAttribute("type");
						if (type && /^dojo\//i.test(type)) {
							scripts.push(child);
						}
					}else if(recurse){
						// Recurse, looking for grandchild nodes with dojoType specified
						scan({
							node: child,
							inherited: inherited
						}, list);
					}
				}
			}
		}

		// Make list of all nodes on page w/dojoType specified
		var list = [];
		scan({
			node: root ? dojo.byId(root) : dojo.body(),
			inherited: (args && args.inherited) || {
				dir: dojo._isBodyLtr() ? "ltr" : "rtl"
			}
		}, list);

		// go build the object instances
		return this.instantiate(list, null, args); // Array
	};
}();

//Register the parser callback. It should be the first callback
//after the a11y test.

(function(){
	var parseRunner = function(){ 
		if(dojo.config.parseOnLoad){
			dojo.parser.parse(); 
		}
	};

	// FIXME: need to clobber cross-dependency!!
	if(dojo.exists("dijit.wai.onload") && (dijit.wai.onload === dojo._loaders[0])){
		dojo._loaders.splice(1, 0, parseRunner);
	}else{
		dojo._loaders.unshift(parseRunner);
	}
})();

}

if(!dojo._hasResource["dijit._Widget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._Widget"] = true;
dojo.provide("dijit._Widget");

dojo.require( "dijit._base" );


// This code is to assist deferring dojo.connect() calls in widgets (connecting to events on the widgets'
// DOM nodes) until someone actually needs to monitor that event.
dojo.connect(dojo, "_connect",
	function(/*dijit._Widget*/ widget, /*String*/ event){
		if(widget && dojo.isFunction(widget._onConnect)){
			widget._onConnect(event);
		}
	});

dijit._connectOnUseEventHandler = function(/*Event*/ event){};

// Keep track of where the last keydown event was, to help avoid generating
// spurious ondijitclick events when:
// 1. focus is on a <button> or <a>
// 2. user presses then releases the ENTER key
// 3. onclick handler fires and shifts focus to another node, with an ondijitclick handler
// 4. onkeyup event fires, causing the ondijitclick handler to fire
dijit._lastKeyDownNode = null;
if(dojo.isIE){
	(function(){
		var keydownCallback = function(evt){
			dijit._lastKeyDownNode = evt.srcElement;
		};
		dojo.doc.attachEvent('onkeydown', keydownCallback);
		dojo.addOnWindowUnload(function(){
			dojo.doc.detachEvent('onkeydown', keydownCallback);
		});
	})();
}else{
	dojo.doc.addEventListener('keydown', function(evt){
		dijit._lastKeyDownNode = evt.target;
	}, true);
}

(function(){

var _attrReg = {},	// cached results from getSetterAttributes
	getSetterAttributes = function(widget){
		// summary:
		//		Returns list of attributes with custom setters for specified widget
		var dc = widget.declaredClass;
		if(!_attrReg[dc]){
			var r = [],
				attrs,
				proto = widget.constructor.prototype;
			for(var fxName in proto){
				if(dojo.isFunction(proto[fxName]) && (attrs = fxName.match(/^_set([a-zA-Z]*)Attr$/)) && attrs[1]){
					r.push(attrs[1].charAt(0).toLowerCase() + attrs[1].substr(1));
				}
			}
			_attrReg[dc] = r;
		}
		return _attrReg[dc] || [];	// String[]
	};

dojo.declare("dijit._Widget", null, {
	// summary:
	//		Base class for all Dijit widgets.

	// id: [const] String
	//		A unique, opaque ID string that can be assigned by users or by the
	//		system. If the developer passes an ID which is known not to be
	//		unique, the specified ID is ignored and the system-generated ID is
	//		used instead.
	id: "",

	// lang: [const] String
	//		Rarely used.  Overrides the default Dojo locale used to render this widget,
	//		as defined by the [HTML LANG](http://www.w3.org/TR/html401/struct/dirlang.html#adef-lang) attribute.
	//		Value must be among the list of locales specified during by the Dojo bootstrap,
	//		formatted according to [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt) (like en-us).
	lang: "",

	// dir: [const] String
	//		Bi-directional support, as defined by the [HTML DIR](http://www.w3.org/TR/html401/struct/dirlang.html#adef-dir)
	//		attribute. Either left-to-right "ltr" or right-to-left "rtl".  If undefined, widgets renders in page's
	//		default direction.
	dir: "",

	// class: String
	//		HTML class attribute
	"class": "",

	// style: String||Object
	//		HTML style attributes as cssText string or name/value hash
	style: "",

	// title: String
	//		HTML title attribute.
	//
	//		For form widgets this specifies a tooltip to display when hovering over
	//		the widget (just like the native HTML title attribute).
	//
	//		For TitlePane or for when this widget is a child of a TabContainer, AccordionContainer,
	//		etc., it's used to specify the tab label, accordion pane title, etc.
	title: "",

	// tooltip: String
	//		When this widget's title attribute is used to for a tab label, accordion pane title, etc.,
	//		this specifies the tooltip to appear when the mouse is hovered over that text.
	tooltip: "",

	// baseClass: [protected] String
	//		Root CSS class of the widget (ex: dijitTextBox), used to construct CSS classes to indicate
	//		widget state.
	baseClass: "",

	// srcNodeRef: [readonly] DomNode
	//		pointer to original DOM node
	srcNodeRef: null,

	// domNode: [readonly] DomNode
	//		This is our visible representation of the widget! Other DOM
	//		Nodes may by assigned to other properties, usually through the
	//		template system's dojoAttachPoint syntax, but the domNode
	//		property is the canonical "top level" node in widget UI.
	domNode: null,

	// containerNode: [readonly] DomNode
	//		Designates where children of the source DOM node will be placed.
	//		"Children" in this case refers to both DOM nodes and widgets.
	//		For example, for myWidget:
	//
	//		|	<div dojoType=myWidget>
	//		|		<b> here's a plain DOM node
	//		|		<span dojoType=subWidget>and a widget</span>
	//		|		<i> and another plain DOM node </i>
	//		|	</div>
	//
	//		containerNode would point to:
	//
	//		|		<b> here's a plain DOM node
	//		|		<span dojoType=subWidget>and a widget</span>
	//		|		<i> and another plain DOM node </i>
	//
	//		In templated widgets, "containerNode" is set via a
	//		dojoAttachPoint assignment.
	//
	//		containerNode must be defined for any widget that accepts innerHTML
	//		(like ContentPane or BorderContainer or even Button), and conversely
	//		is null for widgets that don't, like TextBox.
	containerNode: null,

/*=====
	// _started: Boolean
	//		startup() has completed.
	_started: false,
=====*/

	// attributeMap: [protected] Object
	//		attributeMap sets up a "binding" between attributes (aka properties)
	//		of the widget and the widget's DOM.
	//		Changes to widget attributes listed in attributeMap will be
	//		reflected into the DOM.
	//
	//		For example, calling attr('title', 'hello')
	//		on a TitlePane will automatically cause the TitlePane's DOM to update
	//		with the new title.
	//
	//		attributeMap is a hash where the key is an attribute of the widget,
	//		and the value reflects a binding to a:
	//
	//		- DOM node attribute
	// |		focus: {node: "focusNode", type: "attribute"}
	// 		Maps this.focus to this.focusNode.focus
	//
	//		- DOM node innerHTML
	//	|		title: { node: "titleNode", type: "innerHTML" }
	//		Maps this.title to this.titleNode.innerHTML
	//
	//		- DOM node innerText
	//	|		title: { node: "titleNode", type: "innerText" }
	//		Maps this.title to this.titleNode.innerText
	//
	//		- DOM node CSS class
	// |		myClass: { node: "domNode", type: "class" }
	//		Maps this.myClass to this.domNode.className
	//
	//		If the value is an array, then each element in the array matches one of the
	//		formats of the above list.
	//
	//		There are also some shorthands for backwards compatibility:
	//		- string --> { node: string, type: "attribute" }, for example:
	//	|	"focusNode" ---> { node: "focusNode", type: "attribute" }
	//		- "" --> { node: "domNode", type: "attribute" }
	attributeMap: {id:"", dir:"", lang:"", "class":"", style:"", title:""},

	// _deferredConnects: [protected] Object
	//		attributeMap addendum for event handlers that should be connected only on first use
	_deferredConnects: {
		onClick: "",
		onDblClick: "",
		onKeyDown: "",
		onKeyPress: "",
		onKeyUp: "",
		onMouseMove: "",
		onMouseDown: "",
		onMouseOut: "",
		onMouseOver: "",
		onMouseLeave: "",
		onMouseEnter: "",
		onMouseUp: ""
	},

	onClick: dijit._connectOnUseEventHandler,
	/*=====
	onClick: function(event){
		// summary:
		//		Connect to this function to receive notifications of mouse click events.
		// event:
		//		mouse Event
		// tags:
		//		callback
	},
	=====*/
	onDblClick: dijit._connectOnUseEventHandler,
	/*=====
	onDblClick: function(event){
		// summary:
		//		Connect to this function to receive notifications of mouse double click events.
		// event:
		//		mouse Event
		// tags:
		//		callback
	},
	=====*/
	onKeyDown: dijit._connectOnUseEventHandler,
	/*=====
	onKeyDown: function(event){
		// summary:
		//		Connect to this function to receive notifications of keys being pressed down.
		// event:
		//		key Event
		// tags:
		//		callback
	},
	=====*/
	onKeyPress: dijit._connectOnUseEventHandler,
	/*=====
	onKeyPress: function(event){
		// summary:
		//		Connect to this function to receive notifications of printable keys being typed.
		// event:
		//		key Event
		// tags:
		//		callback
	},
	=====*/
	onKeyUp: dijit._connectOnUseEventHandler,
	/*=====
	onKeyUp: function(event){
		// summary:
		//		Connect to this function to receive notifications of keys being released.
		// event:
		//		key Event
		// tags:
		//		callback
	},
	=====*/
	onMouseDown: dijit._connectOnUseEventHandler,
	/*=====
	onMouseDown: function(event){
		// summary:
		//		Connect to this function to receive notifications of when the mouse button is pressed down.
		// event:
		//		mouse Event
		// tags:
		//		callback
	},
	=====*/
	onMouseMove: dijit._connectOnUseEventHandler,
	/*=====
	onMouseMove: function(event){
		// summary:
		//		Connect to this function to receive notifications of when the mouse moves over nodes contained within this widget.
		// event:
		//		mouse Event
		// tags:
		//		callback
	},
	=====*/
	onMouseOut: dijit._connectOnUseEventHandler,
	/*=====
	onMouseOut: function(event){
		// summary:
		//		Connect to this function to receive notifications of when the mouse moves off of nodes contained within this widget.
		// event:
		//		mouse Event
		// tags:
		//		callback
	},
	=====*/
	onMouseOver: dijit._connectOnUseEventHandler,
	/*=====
	onMouseOver: function(event){
		// summary:
		//		Connect to this function to receive notifications of when the mouse moves onto nodes contained within this widget.
		// event:
		//		mouse Event
		// tags:
		//		callback
	},
	=====*/
	onMouseLeave: dijit._connectOnUseEventHandler,
	/*=====
	onMouseLeave: function(event){
		// summary:
		//		Connect to this function to receive notifications of when the mouse moves off of this widget.
		// event:
		//		mouse Event
		// tags:
		//		callback
	},
	=====*/
	onMouseEnter: dijit._connectOnUseEventHandler,
	/*=====
	onMouseEnter: function(event){
		// summary:
		//		Connect to this function to receive notifications of when the mouse moves onto this widget.
		// event:
		//		mouse Event
		// tags:
		//		callback
	},
	=====*/
	onMouseUp: dijit._connectOnUseEventHandler,
	/*=====
	onMouseUp: function(event){
		// summary:
		//		Connect to this function to receive notifications of when the mouse button is released.
		// event:
		//		mouse Event
		// tags:
		//		callback
	},
	=====*/

	// Constants used in templates

	// _blankGif: [protected] String
	//		Path to a blank 1x1 image.
	//		Used by <img> nodes in templates that really get their image via CSS background-image.
	_blankGif: (dojo.config.blankGif || dojo.moduleUrl("dojo", "resources/blank.gif")).toString(),

	//////////// INITIALIZATION METHODS ///////////////////////////////////////

	postscript: function(/*Object?*/params, /*DomNode|String*/srcNodeRef){
		// summary:
		//		Kicks off widget instantiation.  See create() for details.
		// tags:
		//		private
		this.create(params, srcNodeRef);
	},

	create: function(/*Object?*/params, /*DomNode|String?*/srcNodeRef){
		// summary:
		//		Kick off the life-cycle of a widget
		// params:
		//		Hash of initialization parameters for widget, including
		//		scalar values (like title, duration etc.) and functions,
		//		typically callbacks like onClick.
		// srcNodeRef:
		//		If a srcNodeRef (DOM node) is specified:
		//			- use srcNodeRef.innerHTML as my contents
		//			- if this is a behavioral widget then apply behavior
		//			  to that srcNodeRef
		//			- otherwise, replace srcNodeRef with my generated DOM
		//			  tree
		// description:
		//		Create calls a number of widget methods (postMixInProperties, buildRendering, postCreate,
		//		etc.), some of which of you'll want to override. See http://docs.dojocampus.org/dijit/_Widget
		//		for a discussion of the widget creation lifecycle.
		//
		//		Of course, adventurous developers could override create entirely, but this should
		//		only be done as a last resort.
		// tags:
		//		private

		// store pointer to original DOM tree
		this.srcNodeRef = dojo.byId(srcNodeRef);

		// For garbage collection.  An array of handles returned by Widget.connect()
		// Each handle returned from Widget.connect() is an array of handles from dojo.connect()
		this._connects = [];

		// For garbage collection.  An array of handles returned by Widget.subscribe()
		// The handle returned from Widget.subscribe() is the handle returned from dojo.subscribe()
		this._subscribes = [];

		// To avoid double-connects, remove entries from _deferredConnects
		// that have been setup manually by a subclass (ex, by dojoAttachEvent).
		// If a subclass has redefined a callback (ex: onClick) then assume it's being
		// connected to manually.
		this._deferredConnects = dojo.clone(this._deferredConnects);
		for(var attr in this.attributeMap){
			delete this._deferredConnects[attr]; // can't be in both attributeMap and _deferredConnects
		}
		for(attr in this._deferredConnects){
			if(this[attr] !== dijit._connectOnUseEventHandler){
				delete this._deferredConnects[attr];	// redefined, probably dojoAttachEvent exists
			}
		}

		//mixin our passed parameters
		if(this.srcNodeRef && (typeof this.srcNodeRef.id == "string")){ this.id = this.srcNodeRef.id; }
		if(params){
			this.params = params;
			dojo.mixin(this,params);
		}
		this.postMixInProperties();

		// generate an id for the widget if one wasn't specified
		// (be sure to do this before buildRendering() because that function might
		// expect the id to be there.)
		if(!this.id){
			this.id = dijit.getUniqueId(this.declaredClass.replace(/\./g,"_"));
		}
		dijit.registry.add(this);

		this.buildRendering();

		if(this.domNode){
			// Copy attributes listed in attributeMap into the [newly created] DOM for the widget.
			this._applyAttributes();

			var source = this.srcNodeRef;
			if(source && source.parentNode){
				source.parentNode.replaceChild(this.domNode, source);
			}

			// If the developer has specified a handler as a widget parameter
			// (ex: new Button({onClick: ...})
			// then naturally need to connect from DOM node to that handler immediately,
			for(attr in this.params){
				this._onConnect(attr);
			}
		}

		if(this.domNode){
			this.domNode.setAttribute("widgetId", this.id);
		}
		this.postCreate();

		// If srcNodeRef has been processed and removed from the DOM (e.g. TemplatedWidget) then delete it to allow GC.
		if(this.srcNodeRef && !this.srcNodeRef.parentNode){
			delete this.srcNodeRef;
		}

		this._created = true;
	},

	_applyAttributes: function(){
		// summary:
		//		Step during widget creation to copy all widget attributes to the
		//		DOM as per attributeMap and _setXXXAttr functions.
		// description:
		//		Skips over blank/false attribute values, unless they were explicitly specified
		//		as parameters to the widget, since those are the default anyway,
		//		and setting tabIndex="" is different than not setting tabIndex at all.
		//
		//		It processes the attributes in the attribute map first, and then
		//		it goes through and processes the attributes for the _setXXXAttr
		//		functions that have been specified
		// tags:
		//		private
		var condAttrApply = function(attr, scope){
			if((scope.params && attr in scope.params) || scope[attr]){
				scope.set(attr, scope[attr]);
			}
		};

		// Do the attributes in attributeMap
		for(var attr in this.attributeMap){
			condAttrApply(attr, this);
		}

		// And also any attributes with custom setters
		dojo.forEach(getSetterAttributes(this), function(a){
			if(!(a in this.attributeMap)){
				condAttrApply(a, this);
			}
		}, this);
	},

	postMixInProperties: function(){
		// summary:
		//		Called after the parameters to the widget have been read-in,
		//		but before the widget template is instantiated. Especially
		//		useful to set properties that are referenced in the widget
		//		template.
		// tags:
		//		protected
	},

	buildRendering: function(){
		// summary:
		//		Construct the UI for this widget, setting this.domNode
		// description:
		//		Most widgets will mixin `dijit._Templated`, which implements this
		//		method.
		// tags:
		//		protected
		this.domNode = this.srcNodeRef || dojo.create('div');
	},

	postCreate: function(){
		// summary:
		//		Processing after the DOM fragment is created
		// description:
		//		Called after the DOM fragment has been created, but not necessarily
		//		added to the document.  Do not include any operations which rely on
		//		node dimensions or placement.
		// tags:
		//		protected

		// baseClass is a single class name or occasionally a space-separated list of names.
		// Add those classes to the DOMNod.  If RTL mode then also add with Rtl suffix.		
		if(this.baseClass){
			var classes = this.baseClass.split(" ");
			if(!this.isLeftToRight()){
				classes = classes.concat( dojo.map(classes, function(name){ return name+"Rtl"; }));
			}
			dojo.addClass(this.domNode, classes);
		}
	},

	startup: function(){
		// summary:
		//		Processing after the DOM fragment is added to the document
		// description:
		//		Called after a widget and its children have been created and added to the page,
		//		and all related widgets have finished their create() cycle, up through postCreate().
		//		This is useful for composite widgets that need to control or layout sub-widgets.
		//		Many layout widgets can use this as a wiring phase.
		this._started = true;
	},

	//////////// DESTROY FUNCTIONS ////////////////////////////////

	destroyRecursive: function(/*Boolean?*/ preserveDom){
		// summary:
		// 		Destroy this widget and its descendants
		// description:
		//		This is the generic "destructor" function that all widget users
		// 		should call to cleanly discard with a widget. Once a widget is
		// 		destroyed, it is removed from the manager object.
		// preserveDom:
		//		If true, this method will leave the original DOM structure
		//		alone of descendant Widgets. Note: This will NOT work with
		//		dijit._Templated widgets.

		this._beingDestroyed = true;
		this.destroyDescendants(preserveDom);
		this.destroy(preserveDom);
	},

	destroy: function(/*Boolean*/ preserveDom){
		// summary:
		// 		Destroy this widget, but not its descendants.
		//		This method will, however, destroy internal widgets such as those used within a template.
		// preserveDom: Boolean
		//		If true, this method will leave the original DOM structure alone.
		//		Note: This will not yet work with _Templated widgets

		this._beingDestroyed = true;
		this.uninitialize();
		var d = dojo,
			dfe = d.forEach,
			dun = d.unsubscribe;
		dfe(this._connects, function(array){
			dfe(array, d.disconnect);
		});
		dfe(this._subscribes, function(handle){
			dun(handle);
		});

		// destroy widgets created as part of template, etc.
		dfe(this._supportingWidgets || [], function(w){
			if(w.destroyRecursive){
				w.destroyRecursive();
			}else if(w.destroy){
				w.destroy();
			}
		});

		this.destroyRendering(preserveDom);
		dijit.registry.remove(this.id);
		this._destroyed = true;
	},

	destroyRendering: function(/*Boolean?*/ preserveDom){
		// summary:
		//		Destroys the DOM nodes associated with this widget
		// preserveDom:
		//		If true, this method will leave the original DOM structure alone
		//		during tear-down. Note: this will not work with _Templated
		//		widgets yet.
		// tags:
		//		protected

		if(this.bgIframe){
			this.bgIframe.destroy(preserveDom);
			delete this.bgIframe;
		}

		if(this.domNode){
			if(preserveDom){
				dojo.removeAttr(this.domNode, "widgetId");
			}else{
				dojo.destroy(this.domNode);
			}
			delete this.domNode;
		}

		if(this.srcNodeRef){
			if(!preserveDom){
				dojo.destroy(this.srcNodeRef);
			}
			delete this.srcNodeRef;
		}
	},

	destroyDescendants: function(/*Boolean?*/ preserveDom){
		// summary:
		//		Recursively destroy the children of this widget and their
		//		descendants.
		// preserveDom:
		//		If true, the preserveDom attribute is passed to all descendant
		//		widget's .destroy() method. Not for use with _Templated
		//		widgets.

		// get all direct descendants and destroy them recursively
		dojo.forEach(this.getChildren(), function(widget){
			if(widget.destroyRecursive){
				widget.destroyRecursive(preserveDom);
			}
		});
	},


	uninitialize: function(){
		// summary:
		//		Stub function. Override to implement custom widget tear-down
		//		behavior.
		// tags:
		//		protected
		return false;
	},

	////////////////// MISCELLANEOUS METHODS ///////////////////

	onFocus: function(){
		// summary:
		//		Called when the widget becomes "active" because
		//		it or a widget inside of it either has focus, or has recently
		//		been clicked.
		// tags:
		//		callback
	},

	onBlur: function(){
		// summary:
		//		Called when the widget stops being "active" because
		//		focus moved to something outside of it, or the user
		//		clicked somewhere outside of it, or the widget was
		//		hidden.
		// tags:
		//		callback
	},

	_onFocus: function(e){
		// summary:
		//		This is where widgets do processing for when they are active,
		//		such as changing CSS classes.  See onFocus() for more details.
		// tags:
		//		protected
		this.onFocus();
	},

	_onBlur: function(){
		// summary:
		//		This is where widgets do processing for when they stop being active,
		//		such as changing CSS classes.  See onBlur() for more details.
		// tags:
		//		protected
		this.onBlur();
	},

	_onConnect: function(/*String*/ event){
		// summary:
		//		Called when someone connects to one of my handlers.
		//		"Turn on" that handler if it isn't active yet.
		//
		//		This is also called for every single initialization parameter
		//		so need to do nothing for parameters like "id".
		// tags:
		//		private
		if(event in this._deferredConnects){
			var mapNode = this[this._deferredConnects[event] || 'domNode'];
			this.connect(mapNode, event.toLowerCase(), event);
			delete this._deferredConnects[event];
		}
	},

	_setClassAttr: function(/*String*/ value){
		// summary:
		//		Custom setter for the CSS "class" attribute
		// tags:
		//		protected
		var mapNode = this[this.attributeMap["class"] || 'domNode'];
		dojo.removeClass(mapNode, this["class"])
		this["class"] = value;
		dojo.addClass(mapNode, value);
	},

	_setStyleAttr: function(/*String||Object*/ value){
		// summary:
		//		Sets the style attribut of the widget according to value,
		//		which is either a hash like {height: "5px", width: "3px"}
		//		or a plain string
		// description:
		//		Determines which node to set the style on based on style setting
		//		in attributeMap.
		// tags:
		//		protected

		var mapNode = this[this.attributeMap.style || 'domNode'];

		// Note: technically we should revert any style setting made in a previous call
		// to his method, but that's difficult to keep track of.

		if(dojo.isObject(value)){
			dojo.style(mapNode, value);
		}else{
			if(mapNode.style.cssText){
				mapNode.style.cssText += "; " + value;
			}else{
				mapNode.style.cssText = value;
			}
		}

		this.style = value;
	},

	setAttribute: function(/*String*/ attr, /*anything*/ value){
		// summary:
		//		Deprecated.  Use set() instead.
		// tags:
		//		deprecated
		dojo.deprecated(this.declaredClass+"::setAttribute(attr, value) is deprecated. Use set() instead.", "", "2.0");
		this.set(attr, value);
	},

	_attrToDom: function(/*String*/ attr, /*String*/ value){
		// summary:
		//		Reflect a widget attribute (title, tabIndex, duration etc.) to
		//		the widget DOM, as specified in attributeMap.
		//
		// description:
		//		Also sets this["attr"] to the new value.
		//		Note some attributes like "type"
		//		cannot be processed this way as they are not mutable.
		//
		// tags:
		//		private

		var commands = this.attributeMap[attr];
		dojo.forEach(dojo.isArray(commands) ? commands : [commands], function(command){

			// Get target node and what we are doing to that node
			var mapNode = this[command.node || command || "domNode"];	// DOM node
			var type = command.type || "attribute";	// class, innerHTML, innerText, or attribute

			switch(type){
				case "attribute":
					if(dojo.isFunction(value)){ // functions execute in the context of the widget
						value = dojo.hitch(this, value);
					}

					// Get the name of the DOM node attribute; usually it's the same
					// as the name of the attribute in the widget (attr), but can be overridden.
					// Also maps handler names to lowercase, like onSubmit --> onsubmit
					var attrName = command.attribute ? command.attribute :
						(/^on[A-Z][a-zA-Z]*$/.test(attr) ? attr.toLowerCase() : attr);

					dojo.attr(mapNode, attrName, value);
					break;
				case "innerText":
					mapNode.innerHTML = "";
					mapNode.appendChild(dojo.doc.createTextNode(value));
					break;
				case "innerHTML":
					mapNode.innerHTML = value;
					break;
				case "class":
					dojo.removeClass(mapNode, this[attr]);
					dojo.addClass(mapNode, value);
					break;
			}
		}, this);
		this[attr] = value;
	},

	attr: function(/*String|Object*/name, /*Object?*/value){
		// summary:
		//		Set or get properties on a widget instance.
		//	name:
		//		The property to get or set. If an object is passed here and not
		//		a string, its keys are used as names of attributes to be set
		//		and the value of the object as values to set in the widget.
		//	value:
		//		Optional. If provided, attr() operates as a setter. If omitted,
		//		the current value of the named property is returned.
		// description:
		//		This method is deprecated, use get() or set() directly.

		// Print deprecation warning but only once per calling function
		if(dojo.config.isDebug){
			var alreadyCalledHash = arguments.callee._ach || (arguments.callee._ach = {}),
				caller = (arguments.callee.caller || "unknown caller").toString();
			if(!alreadyCalledHash[caller]){
				dojo.deprecated(this.declaredClass + "::attr() is deprecated. Use get() or set() instead, called from " +
				caller, "", "2.0");
				alreadyCalledHash[caller] = true;
			}
		}

		var args = arguments.length;
		if(args >= 2 || typeof name === "object"){ // setter
			return this.set.apply(this, arguments);
		}else{ // getter
			return this.get(name);
		}
	},
	
	get: function(name){
		// summary:
		//		Get a property from a widget.
		//	name:
		//		The property to get.
		// description:
		//		Get a named property from a widget. The property may
		//		potentially be retrieved via a getter method. If no getter is defined, this
		// 		just retrieves the object's property.  
		// 		For example, if the widget has a properties "foo"
		//		and "bar" and a method named "_getFooAttr", calling:
		//	|	myWidget.get("foo");
		//		would be equivalent to writing:
		//	|	widget._getFooAttr();
		//		and:
		//	|	myWidget.get("bar");
		//		would be equivalent to writing:
		//	|	widget.bar;
		var names = this._getAttrNames(name);
		return this[names.g] ? this[names.g]() : this[name];
	},
	
	set: function(name, value){
		// summary:
		//		Set a property on a widget
		//	name:
		//		The property to set. 
		//	value:
		//		The value to set in the property.
		// description:
		//		Sets named properties on a widget which may potentially be handled by a 
		// 		setter in the widget.
		// 		For example, if the widget has a properties "foo"
		//		and "bar" and a method named "_setFooAttr", calling:
		//	|	myWidget.set("foo", "Howdy!");
		//		would be equivalent to writing:
		//	|	widget._setFooAttr("Howdy!");
		//		and:
		//	|	myWidget.set("bar", 3);
		//		would be equivalent to writing:
		//	|	widget.bar = 3;
		//
		//	set() may also be called with a hash of name/value pairs, ex:
		//	|	myWidget.set({
		//	|		foo: "Howdy",
		//	|		bar: 3
		//	|	})
		//	This is equivalent to calling set(foo, "Howdy") and set(bar, 3)

		if(typeof name === "object"){
			for(var x in name){
				this.set(x, name[x]); 
			}
			return this;
		}
		var names = this._getAttrNames(name);
		if(this[names.s]){
			// use the explicit setter
			var result = this[names.s].apply(this, Array.prototype.slice.call(arguments, 1));
		}else{
			// if param is specified as DOM node attribute, copy it
			if(name in this.attributeMap){
				this._attrToDom(name, value);
			}
			var oldValue = this[name];
			// FIXME: what about function assignments? Any way to connect() here?
			this[name] = value;
		}
		return result || this;
	},
	
	_attrPairNames: {},		// shared between all widgets
	_getAttrNames: function(name){
		// summary:
		//		Helper function for get() and set().
		//		Caches attribute name values so we don't do the string ops every time.
		// tags:
		//		private

		var apn = this._attrPairNames;
		if(apn[name]){ return apn[name]; }
		var uc = name.charAt(0).toUpperCase() + name.substr(1);
		return (apn[name] = {
			n: name+"Node",
			s: "_set"+uc+"Attr",
			g: "_get"+uc+"Attr"
		});
	},

	toString: function(){
		// summary:
		//		Returns a string that represents the widget
		// description:
		//		When a widget is cast to a string, this method will be used to generate the
		//		output. Currently, it does not implement any sort of reversible
		//		serialization.
		return '[Widget ' + this.declaredClass + ', ' + (this.id || 'NO ID') + ']'; // String
	},

	getDescendants: function(){
		// summary:
		//		Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
		//		This method should generally be avoided as it returns widgets declared in templates, which are
		//		supposed to be internal/hidden, but it's left here for back-compat reasons.

		return this.containerNode ? dojo.query('[widgetId]', this.containerNode).map(dijit.byNode) : []; // dijit._Widget[]
	},

	getChildren: function(){
		// summary:
		//		Returns all the widgets contained by this, i.e., all widgets underneath this.containerNode.
		//		Does not return nested widgets, nor widgets that are part of this widget's template.
		return this.containerNode ? dijit.findWidgets(this.containerNode) : []; // dijit._Widget[]
	},

	// nodesWithKeyClick: [private] String[]
	//		List of nodes that correctly handle click events via native browser support,
	//		and don't need dijit's help
	nodesWithKeyClick: ["input", "button"],

	connect: function(
			/*Object|null*/ obj,
			/*String|Function*/ event,
			/*String|Function*/ method){
		// summary:
		//		Connects specified obj/event to specified method of this object
		//		and registers for disconnect() on widget destroy.
		// description:
		//		Provide widget-specific analog to dojo.connect, except with the
		//		implicit use of this widget as the target object.
		//		This version of connect also provides a special "ondijitclick"
		//		event which triggers on a click or space or enter keyup
		// returns:
		//		A handle that can be passed to `disconnect` in order to disconnect before
		//		the widget is destroyed.
		// example:
		//	|	var btn = new dijit.form.Button();
		//	|	// when foo.bar() is called, call the listener we're going to
		//	|	// provide in the scope of btn
		//	|	btn.connect(foo, "bar", function(){
		//	|		console.debug(this.toString());
		//	|	});
		// tags:
		//		protected

		var d = dojo,
			dc = d._connect,
			handles = [];
		if(event == "ondijitclick"){
			// add key based click activation for unsupported nodes.
			// do all processing onkey up to prevent spurious clicks
			// for details see comments at top of this file where _lastKeyDownNode is defined
			if(dojo.indexOf(this.nodesWithKeyClick, obj.nodeName.toLowerCase()) == -1){ // is NOT input or button
				var m = d.hitch(this, method);
				handles.push(
					dc(obj, "onkeydown", this, function(e){
						//console.log(this.id + ": onkeydown, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
						if((e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
							!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
							// needed on IE for when focus changes between keydown and keyup - otherwise dropdown menus do not work
							dijit._lastKeyDownNode = e.target;
							e.preventDefault();		// stop event to prevent scrolling on space key in IE
						}
			 		}),
					dc(obj, "onkeyup", this, function(e){
						//console.log(this.id + ": onkeyup, e.target = ", e.target, ", lastKeyDownNode was ", dijit._lastKeyDownNode, ", equality is ", (e.target === dijit._lastKeyDownNode));
						if( (e.keyCode == d.keys.ENTER || e.keyCode == d.keys.SPACE) &&
							e.target === dijit._lastKeyDownNode &&
							!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey){
								//need reset here or have problems in FF when focus returns to trigger element after closing popup/alert
								dijit._lastKeyDownNode = null;
								return m(e);
						}
					})
				);
			}
			event = "onclick";
		}
		handles.push(dc(obj, event, this, method));

		this._connects.push(handles);
		return handles;		// _Widget.Handle
	},

	disconnect: function(/* _Widget.Handle */ handles){
		// summary:
		//		Disconnects handle created by `connect`.
		//		Also removes handle from this widget's list of connects.
		// tags:
		//		protected
		for(var i=0; i<this._connects.length; i++){
			if(this._connects[i] == handles){
				dojo.forEach(handles, dojo.disconnect);
				this._connects.splice(i, 1);
				return;
			}
		}
	},

	subscribe: function(
			/*String*/ topic,
			/*String|Function*/ method){
		// summary:
		//		Subscribes to the specified topic and calls the specified method
		//		of this object and registers for unsubscribe() on widget destroy.
		// description:
		//		Provide widget-specific analog to dojo.subscribe, except with the
		//		implicit use of this widget as the target object.
		// example:
		//	|	var btn = new dijit.form.Button();
		//	|	// when /my/topic is published, this button changes its label to
		//	|   // be the parameter of the topic.
		//	|	btn.subscribe("/my/topic", function(v){
		//	|		this.set("label", v);
		//	|	});
		var d = dojo,
			handle = d.subscribe(topic, this, method);

		// return handles for Any widget that may need them
		this._subscribes.push(handle);
		return handle;
	},

	unsubscribe: function(/*Object*/ handle){
		// summary:
		//		Unsubscribes handle created by this.subscribe.
		//		Also removes handle from this widget's list of subscriptions
		for(var i=0; i<this._subscribes.length; i++){
			if(this._subscribes[i] == handle){
				dojo.unsubscribe(handle);
				this._subscribes.splice(i, 1);
				return;
			}
		}
	},

	isLeftToRight: function(){
		// summary:
		//		Return this widget's explicit or implicit orientation (true for LTR, false for RTL)
		// tags:
		//		protected
		return this.dir ? (this.dir == "ltr") : dojo._isBodyLtr(); //Boolean
	},

	isFocusable: function(){
		// summary:
		//		Return true if this widget can currently be focused
		//		and false if not
		return this.focus && (dojo.style(this.domNode, "display") != "none");
	},

	placeAt: function(/* String|DomNode|_Widget */reference, /* String?|Int? */position){
		// summary:
		//		Place this widget's domNode reference somewhere in the DOM based
		//		on standard dojo.place conventions, or passing a Widget reference that
		//		contains and addChild member.
		//
		// description:
		//		A convenience function provided in all _Widgets, providing a simple
		//		shorthand mechanism to put an existing (or newly created) Widget
		//		somewhere in the dom, and allow chaining.
		//
		// reference:
		//		The String id of a domNode, a domNode reference, or a reference to a Widget posessing
		//		an addChild method.
		//
		// position:
		//		If passed a string or domNode reference, the position argument
		//		accepts a string just as dojo.place does, one of: "first", "last",
		//		"before", or "after".
		//
		//		If passed a _Widget reference, and that widget reference has an ".addChild" method,
		//		it will be called passing this widget instance into that method, supplying the optional
		//		position index passed.
		//
		// returns:
		//		dijit._Widget
		//		Provides a useful return of the newly created dijit._Widget instance so you
		//		can "chain" this function by instantiating, placing, then saving the return value
		//		to a variable.
		//
		// example:
		// | 	// create a Button with no srcNodeRef, and place it in the body:
		// | 	var button = new dijit.form.Button({ label:"click" }).placeAt(dojo.body());
		// | 	// now, 'button' is still the widget reference to the newly created button
		// | 	dojo.connect(button, "onClick", function(e){ console.log('click'); });
		//
		// example:
		// |	// create a button out of a node with id="src" and append it to id="wrapper":
		// | 	var button = new dijit.form.Button({},"src").placeAt("wrapper");
		//
		// example:
		// |	// place a new button as the first element of some div
		// |	var button = new dijit.form.Button({ label:"click" }).placeAt("wrapper","first");
		//
		// example:
		// |	// create a contentpane and add it to a TabContainer
		// |	var tc = dijit.byId("myTabs");
		// |	new dijit.layout.ContentPane({ href:"foo.html", title:"Wow!" }).placeAt(tc)

		if(reference.declaredClass && reference.addChild){
			reference.addChild(this, position);
		}else{
			dojo.place(this.domNode, reference, position);
		}
		return this;
	},

	_onShow: function(){
		// summary:
		//		Internal method called when this widget is made visible.
		//		See `onShow` for details.
		this.onShow();
	},

	onShow: function(){
		// summary:
		//		Called when this widget becomes the selected pane in a
		//		`dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
		//		`dijit.layout.AccordionContainer`, etc.
		//
		//		Also called to indicate display of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
		// tags:
		//		callback
	},

	onHide: function(){
		// summary:
			//		Called when another widget becomes the selected pane in a
			//		`dijit.layout.TabContainer`, `dijit.layout.StackContainer`,
			//		`dijit.layout.AccordionContainer`, etc.
			//
			//		Also called to indicate hide of a `dijit.Dialog`, `dijit.TooltipDialog`, or `dijit.TitlePane`.
			// tags:
			//		callback
	},

	onClose: function(){
		// summary:
		//		Called when this widget is being displayed as a popup (ex: a Calendar popped
		//		up from a DateTextBox), and it is hidden.
		//		This is called from the dijit.popup code, and should not be called directly.
		//
		//		Also used as a parameter for children of `dijit.layout.StackContainer` or subclasses.
		//		Callback if a user tries to close the child.   Child will be closed if this function returns true.
		// tags:
		//		extension

		return true;		// Boolean
	}
});

})();

}

if(!dojo._hasResource["dojo.string"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.string"] = true;
dojo.provide("dojo.string");

/*=====
dojo.string = { 
	// summary: String utilities for Dojo
};
=====*/

dojo.string.rep = function(/*String*/str, /*Integer*/num){
	//	summary:
	//		Efficiently replicate a string `n` times.
	//	str:
	//		the string to replicate
	//	num:
	//		number of times to replicate the string
	
	if(num <= 0 || !str){ return ""; }
	
	var buf = [];
	for(;;){
		if(num & 1){
			buf.push(str);
		}
		if(!(num >>= 1)){ break; }
		str += str;
	}
	return buf.join("");	// String
};

dojo.string.pad = function(/*String*/text, /*Integer*/size, /*String?*/ch, /*Boolean?*/end){
	//	summary:
	//		Pad a string to guarantee that it is at least `size` length by
	//		filling with the character `ch` at either the start or end of the
	//		string. Pads at the start, by default.
	//	text:
	//		the string to pad
	//	size:
	//		length to provide padding
	//	ch:
	//		character to pad, defaults to '0'
	//	end:
	//		adds padding at the end if true, otherwise pads at start
	//	example:
	//	|	// Fill the string to length 10 with "+" characters on the right.  Yields "Dojo++++++".
	//	|	dojo.string.pad("Dojo", 10, "+", true);

	if(!ch){
		ch = '0';
	}
	var out = String(text),
		pad = dojo.string.rep(ch, Math.ceil((size - out.length) / ch.length));
	return end ? out + pad : pad + out;	// String
};

dojo.string.substitute = function(	/*String*/		template, 
									/*Object|Array*/map, 
									/*Function?*/	transform, 
									/*Object?*/		thisObject){
	//	summary:
	//		Performs parameterized substitutions on a string. Throws an
	//		exception if any parameter is unmatched.
	//	template: 
	//		a string with expressions in the form `${key}` to be replaced or
	//		`${key:format}` which specifies a format function. keys are case-sensitive. 
	//	map:
	//		hash to search for substitutions
	//	transform: 
	//		a function to process all parameters before substitution takes
	//		place, e.g. mylib.encodeXML
	//	thisObject: 
	//		where to look for optional format function; default to the global
	//		namespace
	//	example:
	//		Substitutes two expressions in a string from an Array or Object
	//	|	// returns "File 'foo.html' is not found in directory '/temp'."
	//	|	// by providing substitution data in an Array
	//	|	dojo.string.substitute(
	//	|		"File '${0}' is not found in directory '${1}'.",
	//	|		["foo.html","/temp"]
	//	|	);
	//	|
	//	|	// also returns "File 'foo.html' is not found in directory '/temp'."
	//	|	// but provides substitution data in an Object structure.  Dotted
	//	|	// notation may be used to traverse the structure.
	//	|	dojo.string.substitute(
	//	|		"File '${name}' is not found in directory '${info.dir}'.",
	//	|		{ name: "foo.html", info: { dir: "/temp" } }
	//	|	);
	//	example:
	//		Use a transform function to modify the values:
	//	|	// returns "file 'foo.html' is not found in directory '/temp'."
	//	|	dojo.string.substitute(
	//	|		"${0} is not found in ${1}.",
	//	|		["foo.html","/temp"],
	//	|		function(str){
	//	|			// try to figure out the type
	//	|			var prefix = (str.charAt(0) == "/") ? "directory": "file";
	//	|			return prefix + " '" + str + "'";
	//	|		}
	//	|	);
	//	example:
	//		Use a formatter
	//	|	// returns "thinger -- howdy"
	//	|	dojo.string.substitute(
	//	|		"${0:postfix}", ["thinger"], null, {
	//	|			postfix: function(value, key){
	//	|				return value + " -- howdy";
	//	|			}
	//	|		}
	//	|	);

	thisObject = thisObject || dojo.global;
	transform = transform ? 
		dojo.hitch(thisObject, transform) : function(v){ return v; };

	return template.replace(/\$\{([^\s\:\}]+)(?:\:([^\s\:\}]+))?\}/g,
		function(match, key, format){
			var value = dojo.getObject(key, false, map);
			if(format){
				value = dojo.getObject(format, false, thisObject).call(thisObject, value, key);
			}
			return transform(value, key).toString();
		}); // String
};

/*=====
dojo.string.trim = function(str){
	//	summary:
	//		Trims whitespace from both sides of the string
	//	str: String
	//		String to be trimmed
	//	returns: String
	//		Returns the trimmed string
	//	description:
	//		This version of trim() was taken from [Steven Levithan's blog](http://blog.stevenlevithan.com/archives/faster-trim-javascript).
	//		The short yet performant version of this function is dojo.trim(),
	//		which is part of Dojo base.  Uses String.prototype.trim instead, if available.
	return "";	// String
}
=====*/

dojo.string.trim = String.prototype.trim ?
	dojo.trim : // aliasing to the native function
	function(str){
		str = str.replace(/^\s+/, '');
		for(var i = str.length - 1; i >= 0; i--){
			if(/\S/.test(str.charAt(i))){
				str = str.substring(0, i + 1);
				break;
			}
		}
		return str;
	};

}

if(!dojo._hasResource["dojo.cache"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.cache"] = true;
dojo.provide("dojo.cache");

/*=====
dojo.cache = { 
	// summary:
	// 		A way to cache string content that is fetchable via `dojo.moduleUrl`.
};
=====*/

(function(){
	var cache = {};
	dojo.cache = function(/*String||Object*/module, /*String*/url, /*String||Object?*/value){
		// summary:
		// 		A getter and setter for storing the string content associated with the
		// 		module and url arguments.
		// description:
		// 		module and url are used to call `dojo.moduleUrl()` to generate a module URL.
		// 		If value is specified, the cache value for the moduleUrl will be set to
		// 		that value. Otherwise, dojo.cache will fetch the moduleUrl and store it
		// 		in its internal cache and return that cached value for the URL. To clear
		// 		a cache value pass null for value. Since XMLHttpRequest (XHR) is used to fetch the
		// 		the URL contents, only modules on the same domain of the page can use this capability.
		// 		The build system can inline the cache values though, to allow for xdomain hosting.
		// module: String||Object
		// 		If a String, the module name to use for the base part of the URL, similar to module argument
		// 		to `dojo.moduleUrl`. If an Object, something that has a .toString() method that
		// 		generates a valid path for the cache item. For example, a dojo._Url object.
		// url: String
		// 		The rest of the path to append to the path derived from the module argument. If
		// 		module is an object, then this second argument should be the "value" argument instead.
		// value: String||Object?
		// 		If a String, the value to use in the cache for the module/url combination.
		// 		If an Object, it can have two properties: value and sanitize. The value property
		// 		should be the value to use in the cache, and sanitize can be set to true or false,
		// 		to indicate if XML declarations should be removed from the value and if the HTML
		// 		inside a body tag in the value should be extracted as the real value. The value argument
		// 		or the value property on the value argument are usually only used by the build system
		// 		as it inlines cache content.
		//	example:
		//		To ask dojo.cache to fetch content and store it in the cache (the dojo["cache"] style
		// 		of call is used to avoid an issue with the build system erroneously trying to intern
		// 		this example. To get the build system to intern your dojo.cache calls, use the
		// 		"dojo.cache" style of call):
		// 		|	//If template.html contains "<h1>Hello</h1>" that will be
		// 		|	//the value for the text variable.
		//		|	var text = dojo["cache"]("my.module", "template.html");
		//	example:
		//		To ask dojo.cache to fetch content and store it in the cache, and sanitize the input
		// 		 (the dojo["cache"] style of call is used to avoid an issue with the build system 
		// 		erroneously trying to intern this example. To get the build system to intern your
		// 		dojo.cache calls, use the "dojo.cache" style of call):
		// 		|	//If template.html contains "<html><body><h1>Hello</h1></body></html>", the
		// 		|	//text variable will contain just "<h1>Hello</h1>".
		//		|	var text = dojo["cache"]("my.module", "template.html", {sanitize: true});
		//	example:
		//		Same example as previous, but demostrates how an object can be passed in as
		//		the first argument, then the value argument can then be the second argument.
		// 		|	//If template.html contains "<html><body><h1>Hello</h1></body></html>", the
		// 		|	//text variable will contain just "<h1>Hello</h1>".
		//		|	var text = dojo["cache"](new dojo._Url("my/module/template.html"), {sanitize: true});

		//Module could be a string, or an object that has a toString() method
		//that will return a useful path. If it is an object, then the "url" argument
		//will actually be the value argument.
		if(typeof module == "string"){
			var pathObj = dojo.moduleUrl(module, url);
		}else{
			pathObj = module;
			value = url;
		}
		var key = pathObj.toString();

		var val = value;
		if(value != undefined && !dojo.isString(value)){
			val = ("value" in value ? value.value : undefined);
		}

		var sanitize = value && value.sanitize ? true : false;

		if(typeof val == "string"){
			//We have a string, set cache value
			val = cache[key] = sanitize ? dojo.cache._sanitize(val) : val;
		}else if(val === null){
			//Remove cached value
			delete cache[key];
		}else{
			//Allow cache values to be empty strings. If key property does
			//not exist, fetch it.
			if(!(key in cache)){
				val = dojo._getText(key);
				cache[key] = sanitize ? dojo.cache._sanitize(val) : val;
			}
			val = cache[key];
		}
		return val; //String
	};

	dojo.cache._sanitize = function(/*String*/val){
		// summary: 
		//		Strips <?xml ...?> declarations so that external SVG and XML
		// 		documents can be added to a document without worry. Also, if the string
		//		is an HTML document, only the part inside the body tag is returned.
		// description:
		// 		Copied from dijit._Templated._sanitizeTemplateString.
		if(val){
			val = val.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
			var matches = val.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
			if(matches){
				val = matches[1];
			}
		}else{
			val = "";
		}
		return val; //String
	};
})();

}

if(!dojo._hasResource["dijit._Templated"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._Templated"] = true;
dojo.provide("dijit._Templated");






dojo.declare("dijit._Templated",
	null,
	{
		// summary:
		//		Mixin for widgets that are instantiated from a template

		// templateString: [protected] String
		//		A string that represents the widget template. Pre-empts the
		//		templatePath. In builds that have their strings "interned", the
		//		templatePath is converted to an inline templateString, thereby
		//		preventing a synchronous network call.
		//
		//		Use in conjunction with dojo.cache() to load from a file.
		templateString: null,

		// templatePath: [protected deprecated] String
		//		Path to template (HTML file) for this widget relative to dojo.baseUrl.
		//		Deprecated: use templateString with dojo.cache() instead.
		templatePath: null,

		// widgetsInTemplate: [protected] Boolean
		//		Should we parse the template to find widgets that might be
		//		declared in markup inside it?  False by default.
		widgetsInTemplate: false,

		// skipNodeCache: [protected] Boolean
		//		If using a cached widget template node poses issues for a
		//		particular widget class, it can set this property to ensure
		//		that its template is always re-built from a string
		_skipNodeCache: false,

		// _earlyTemplatedStartup: Boolean
		//		A fallback to preserve the 1.0 - 1.3 behavior of children in
		//		templates having their startup called before the parent widget
		//		fires postCreate. Defaults to 'false', causing child widgets to
		//		have their .startup() called immediately before a parent widget
		//		.startup(), but always after the parent .postCreate(). Set to
		//		'true' to re-enable to previous, arguably broken, behavior.
		_earlyTemplatedStartup: false,

		// _attachPoints: [private] String[]
		//		List of widget attribute names associated with dojoAttachPoint=... in the
		//		template, ex: ["containerNode", "labelNode"]
/*=====
 		_attachPoints: [],
 =====*/

		constructor: function(){
			this._attachPoints = [];
		},

		_stringRepl: function(tmpl){
			// summary:
			//		Does substitution of ${foo} type properties in template string
			// tags:
			//		private
			var className = this.declaredClass, _this = this;
			// Cache contains a string because we need to do property replacement
			// do the property replacement
			return dojo.string.substitute(tmpl, this, function(value, key){
				if(key.charAt(0) == '!'){ value = dojo.getObject(key.substr(1), false, _this); }
				if(typeof value == "undefined"){ throw new Error(className+" template:"+key); } // a debugging aide
				if(value == null){ return ""; }

				// Substitution keys beginning with ! will skip the transform step,
				// in case a user wishes to insert unescaped markup, e.g. ${!foo}
				return key.charAt(0) == "!" ? value :
					// Safer substitution, see heading "Attribute values" in
					// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
					value.toString().replace(/"/g,"&quot;"); //TODO: add &amp? use encodeXML method?
			}, this);
		},

		// method over-ride
		buildRendering: function(){
			// summary:
			//		Construct the UI for this widget from a template, setting this.domNode.
			// tags:
			//		protected

			// Lookup cached version of template, and download to cache if it
			// isn't there already.  Returns either a DomNode or a string, depending on
			// whether or not the template contains ${foo} replacement parameters.
			var cached = dijit._Templated.getCachedTemplate(this.templatePath, this.templateString, this._skipNodeCache);

			var node;
			if(dojo.isString(cached)){
				node = dojo._toDom(this._stringRepl(cached));
				if(node.nodeType != 1){
					// Flag common problems such as templates with multiple top level nodes (nodeType == 11)
					throw new Error("Invalid template: " + cached);
				}
			}else{
				// if it's a node, all we have to do is clone it
				node = cached.cloneNode(true);
			}

			this.domNode = node;

			// recurse through the node, looking for, and attaching to, our
			// attachment points and events, which should be defined on the template node.
			this._attachTemplateNodes(node);

			if(this.widgetsInTemplate){
				// Make sure dojoType is used for parsing widgets in template.
				// The dojo.parser.query could be changed from multiversion support.
				var parser = dojo.parser, qry, attr;
				if(parser._query != "[dojoType]"){
					qry = parser._query;
					attr = parser._attrName;
					parser._query = "[dojoType]";
					parser._attrName = "dojoType";
				}

				// Store widgets that we need to start at a later point in time
				var cw = (this._startupWidgets = dojo.parser.parse(node, {
					noStart: !this._earlyTemplatedStartup,
					inherited: {dir: this.dir, lang: this.lang}
				}));

				// Restore the query.
				if(qry){
					parser._query = qry;
					parser._attrName = attr;
				}

				this._supportingWidgets = dijit.findWidgets(node);

				this._attachTemplateNodes(cw, function(n,p){
					return n[p];
				});
			}

			this._fillContent(this.srcNodeRef);
		},

		_fillContent: function(/*DomNode*/ source){
			// summary:
			//		Relocate source contents to templated container node.
			//		this.containerNode must be able to receive children, or exceptions will be thrown.
			// tags:
			//		protected
			var dest = this.containerNode;
			if(source && dest){
				while(source.hasChildNodes()){
					dest.appendChild(source.firstChild);
				}
			}
		},

		_attachTemplateNodes: function(rootNode, getAttrFunc){
			// summary:
			//		Iterate through the template and attach functions and nodes accordingly.
			// description:
			//		Map widget properties and functions to the handlers specified in
			//		the dom node and it's descendants. This function iterates over all
			//		nodes and looks for these properties:
			//			* dojoAttachPoint
			//			* dojoAttachEvent
			//			* waiRole
			//			* waiState
			// rootNode: DomNode|Array[Widgets]
			//		the node to search for properties. All children will be searched.
			// getAttrFunc: Function?
			//		a function which will be used to obtain property for a given
			//		DomNode/Widget
			// tags:
			//		private

			getAttrFunc = getAttrFunc || function(n,p){ return n.getAttribute(p); };

			var nodes = dojo.isArray(rootNode) ? rootNode : (rootNode.all || rootNode.getElementsByTagName("*"));
			var x = dojo.isArray(rootNode) ? 0 : -1;
			for(; x<nodes.length; x++){
				var baseNode = (x == -1) ? rootNode : nodes[x];
				if(this.widgetsInTemplate && getAttrFunc(baseNode, "dojoType")){
					continue;
				}
				// Process dojoAttachPoint
				var attachPoint = getAttrFunc(baseNode, "dojoAttachPoint");
				if(attachPoint){
					var point, points = attachPoint.split(/\s*,\s*/);
					while((point = points.shift())){
						if(dojo.isArray(this[point])){
							this[point].push(baseNode);
						}else{
							this[point]=baseNode;
						}
						this._attachPoints.push(point);
					}
				}

				// Process dojoAttachEvent
				var attachEvent = getAttrFunc(baseNode, "dojoAttachEvent");
				if(attachEvent){
					// NOTE: we want to support attributes that have the form
					// "domEvent: nativeEvent; ..."
					var event, events = attachEvent.split(/\s*,\s*/);
					var trim = dojo.trim;
					while((event = events.shift())){
						if(event){
							var thisFunc = null;
							if(event.indexOf(":") != -1){
								// oh, if only JS had tuple assignment
								var funcNameArr = event.split(":");
								event = trim(funcNameArr[0]);
								thisFunc = trim(funcNameArr[1]);
							}else{
								event = trim(event);
							}
							if(!thisFunc){
								thisFunc = event;
							}
							this.connect(baseNode, event, thisFunc);
						}
					}
				}

				// waiRole, waiState
				var role = getAttrFunc(baseNode, "waiRole");
				if(role){
					dijit.setWaiRole(baseNode, role);
				}
				var values = getAttrFunc(baseNode, "waiState");
				if(values){
					dojo.forEach(values.split(/\s*,\s*/), function(stateValue){
						if(stateValue.indexOf('-') != -1){
							var pair = stateValue.split('-');
							dijit.setWaiState(baseNode, pair[0], pair[1]);
						}
					});
				}
			}
		},

		startup: function(){
			dojo.forEach(this._startupWidgets, function(w){
				if(w && !w._started && w.startup){
					w.startup();
				}
			});
			this.inherited(arguments);
		},

		destroyRendering: function(){
			// Delete all attach points to prevent IE6 memory leaks.
			dojo.forEach(this._attachPoints, function(point){
				delete this[point];
			}, this);
			this._attachPoints = [];

			this.inherited(arguments);
		}
	}
);

// key is either templatePath or templateString; object is either string or DOM tree
dijit._Templated._templateCache = {};

dijit._Templated.getCachedTemplate = function(templatePath, templateString, alwaysUseString){
	// summary:
	//		Static method to get a template based on the templatePath or
	//		templateString key
	// templatePath: String||dojo.uri.Uri
	//		The URL to get the template from.
	// templateString: String?
	//		a string to use in lieu of fetching the template from a URL. Takes precedence
	//		over templatePath
	// returns: Mixed
	//		Either string (if there are ${} variables that need to be replaced) or just
	//		a DOM tree (if the node can be cloned directly)

	// is it already cached?
	var tmplts = dijit._Templated._templateCache;
	var key = templateString || templatePath;
	var cached = tmplts[key];
	if(cached){
		try{
			// if the cached value is an innerHTML string (no ownerDocument) or a DOM tree created within the current document, then use the current cached value
			if(!cached.ownerDocument || cached.ownerDocument == dojo.doc){
				// string or node of the same document
				return cached;
			}
		}catch(e){ /* squelch */ } // IE can throw an exception if cached.ownerDocument was reloaded
		dojo.destroy(cached);
	}

	// If necessary, load template string from template path
	if(!templateString){
		templateString = dojo.cache(templatePath, {sanitize: true});
	}
	templateString = dojo.string.trim(templateString);

	if(alwaysUseString || templateString.match(/\$\{([^\}]+)\}/g)){
		// there are variables in the template so all we can do is cache the string
		return (tmplts[key] = templateString); //String
	}else{
		// there are no variables in the template so we can cache the DOM tree
		var node = dojo._toDom(templateString);
		if(node.nodeType != 1){
			throw new Error("Invalid template: " + templateString);
		}
		return (tmplts[key] = node); //Node
	}
};

if(dojo.isIE){
	dojo.addOnWindowUnload(function(){
		var cache = dijit._Templated._templateCache;
		for(var key in cache){
			var value = cache[key];
			if(typeof value == "object"){ // value is either a string or a DOM node template
				dojo.destroy(value);
			}
			delete cache[key];
		}
	});
}

// These arguments can be specified for widgets which are used in templates.
// Since any widget can be specified as sub widgets in template, mix it
// into the base widget class.  (This is a hack, but it's effective.)
dojo.extend(dijit._Widget,{
	dojoAttachEvent: "",
	dojoAttachPoint: "",
	waiRole: "",
	waiState:""
});

}

if(!dojo._hasResource["dijit._Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._Container"] = true;
dojo.provide("dijit._Container");

dojo.declare("dijit._Container",
	null,
	{
		// summary:
		//		Mixin for widgets that contain a set of widget children.
		// description:
		//		Use this mixin for widgets that needs to know about and
		//		keep track of their widget children. Suitable for widgets like BorderContainer
		//		and TabContainer which contain (only) a set of child widgets.
		//
		//		It's not suitable for widgets like ContentPane
		//		which contains mixed HTML (plain DOM nodes in addition to widgets),
		//		and where contained widgets are not necessarily directly below
		//		this.containerNode.   In that case calls like addChild(node, position)
		//		wouldn't make sense.

		// isContainer: [protected] Boolean
		//		Indicates that this widget acts as a "parent" to the descendant widgets.
		//		When the parent is started it will call startup() on the child widgets.
		//		See also `isLayoutContainer`.
		isContainer: true,

		buildRendering: function(){
			this.inherited(arguments);
			if(!this.containerNode){
				// all widgets with descendants must set containerNode
	 				this.containerNode = this.domNode;
			}
		},

		addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
			// summary:
			//		Makes the given widget a child of this widget.
			// description:
			//		Inserts specified child widget's dom node as a child of this widget's
			//		container node, and possibly does other processing (such as layout).

			var refNode = this.containerNode;
			if(insertIndex && typeof insertIndex == "number"){
				var children = this.getChildren();
				if(children && children.length >= insertIndex){
					refNode = children[insertIndex-1].domNode;
					insertIndex = "after";
				}
			}
			dojo.place(widget.domNode, refNode, insertIndex);

			// If I've been started but the child widget hasn't been started,
			// start it now.  Make sure to do this after widget has been
			// inserted into the DOM tree, so it can see that it's being controlled by me,
			// so it doesn't try to size itself.
			if(this._started && !widget._started){
				widget.startup();
			}
		},

		removeChild: function(/*Widget or int*/ widget){
			// summary:
			//		Removes the passed widget instance from this widget but does
			//		not destroy it.  You can also pass in an integer indicating
			//		the index within the container to remove

			if(typeof widget == "number" && widget > 0){
				widget = this.getChildren()[widget];
			}

			if(widget){
				var node = widget.domNode;
				if(node && node.parentNode){
					node.parentNode.removeChild(node); // detach but don't destroy
				}
			}
		},

		hasChildren: function(){
			// summary:
			//		Returns true if widget has children, i.e. if this.containerNode contains something.
			return this.getChildren().length > 0;	// Boolean
		},

		destroyDescendants: function(/*Boolean*/ preserveDom){
			// summary:
			//      Destroys all the widgets inside this.containerNode,
			//      but not this widget itself
			dojo.forEach(this.getChildren(), function(child){ child.destroyRecursive(preserveDom); });
		},

		_getSiblingOfChild: function(/*dijit._Widget*/ child, /*int*/ dir){
			// summary:
			//		Get the next or previous widget sibling of child
			// dir:
			//		if 1, get the next sibling
			//		if -1, get the previous sibling
			// tags:
			//      private
			var node = child.domNode,
				which = (dir>0 ? "nextSibling" : "previousSibling");
			do{
				node = node[which];
			}while(node && (node.nodeType != 1 || !dijit.byNode(node)));
			return node && dijit.byNode(node);	// dijit._Widget
		},

		getIndexOfChild: function(/*dijit._Widget*/ child){
			// summary:
			//		Gets the index of the child in this container or -1 if not found
			return dojo.indexOf(this.getChildren(), child);	// int
		},

		startup: function(){
			// summary:
			//		Called after all the widgets have been instantiated and their
			//		dom nodes have been inserted somewhere under dojo.doc.body.
			//
			//		Widgets should override this method to do any initialization
			//		dependent on other widgets existing, and then call
			//		this superclass method to finish things off.
			//
			//		startup() in subclasses shouldn't do anything
			//		size related because the size of the widget hasn't been set yet.

			if(this._started){ return; }

			// Startup all children of this widget
			dojo.forEach(this.getChildren(), function(child){ child.startup(); });

			this.inherited(arguments);
		}
	}
);

}

if(!dojo._hasResource["dijit._Contained"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._Contained"] = true;
dojo.provide("dijit._Contained");

dojo.declare("dijit._Contained",
		null,
		{
			// summary:
			//		Mixin for widgets that are children of a container widget
			//
			// example:
			// | 	// make a basic custom widget that knows about it's parents
			// |	dojo.declare("my.customClass",[dijit._Widget,dijit._Contained],{});

			getParent: function(){
				// summary:
				//		Returns the parent widget of this widget, assuming the parent
				//		specifies isContainer
				var parent = dijit.getEnclosingWidget(this.domNode.parentNode);
				return parent && parent.isContainer ? parent : null;
			},

			_getSibling: function(/*String*/ which){
				// summary:
				//      Returns next or previous sibling
				// which:
				//      Either "next" or "previous"
				// tags:
				//      private
				var node = this.domNode;
				do{
					node = node[which+"Sibling"];
				}while(node && node.nodeType != 1);
				return node && dijit.byNode(node);	// dijit._Widget
			},

			getPreviousSibling: function(){
				// summary:
				//		Returns null if this is the first child of the parent,
				//		otherwise returns the next element sibling to the "left".

				return this._getSibling("previous"); // dijit._Widget
			},

			getNextSibling: function(){
				// summary:
				//		Returns null if this is the last child of the parent,
				//		otherwise returns the next element sibling to the "right".

				return this._getSibling("next"); // dijit._Widget
			},

			getIndexInParent: function(){
				// summary:
				//		Returns the index of this widget within its container parent.
				//		It returns -1 if the parent does not exist, or if the parent
				//		is not a dijit._Container

				var p = this.getParent();
				if(!p || !p.getIndexOfChild){
					return -1; // int
				}
				return p.getIndexOfChild(this); // int
			}
		}
	);


}

if(!dojo._hasResource["dijit.layout._LayoutWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout._LayoutWidget"] = true;
dojo.provide("dijit.layout._LayoutWidget");





dojo.declare("dijit.layout._LayoutWidget",
	[dijit._Widget, dijit._Container, dijit._Contained],
	{
		// summary:
		//		Base class for a _Container widget which is responsible for laying out its children.
		//		Widgets which mixin this code must define layout() to manage placement and sizing of the children.

		// baseClass: [protected extension] String
		//		This class name is applied to the widget's domNode
		//		and also may be used to generate names for sub nodes,
		//		for example dijitTabContainer-content.
		baseClass: "dijitLayoutContainer",

		// isLayoutContainer: [protected] Boolean
		//		Indicates that this widget is going to call resize() on its
		//		children widgets, setting their size, when they become visible.
		isLayoutContainer: true,

		postCreate: function(){
			dojo.addClass(this.domNode, "dijitContainer");

			this.inherited(arguments);
		},

		startup: function(){
			// summary:
			//		Called after all the widgets have been instantiated and their
			//		dom nodes have been inserted somewhere under dojo.doc.body.
			//
			//		Widgets should override this method to do any initialization
			//		dependent on other widgets existing, and then call
			//		this superclass method to finish things off.
			//
			//		startup() in subclasses shouldn't do anything
			//		size related because the size of the widget hasn't been set yet.

			if(this._started){ return; }

			// Need to call inherited first - so that child widgets get started
			// up correctly
			this.inherited(arguments);

			// If I am a not being controlled by a parent layout widget...
			var parent = this.getParent && this.getParent()
			if(!(parent && parent.isLayoutContainer)){
				// Do recursive sizing and layout of all my descendants
				// (passing in no argument to resize means that it has to glean the size itself)
				this.resize();

				// Since my parent isn't a layout container, and my style *may be* width=height=100%
				// or something similar (either set directly or via a CSS class),
				// monitor when my size changes so that I can re-layout.
				// For browsers where I can't directly monitor when my size changes,
				// monitor when the viewport changes size, which *may* indicate a size change for me.
				this.connect(dojo.isIE ? this.domNode : dojo.global, 'onresize', function(){
					// Using function(){} closure to ensure no arguments to resize.
					this.resize();
				});
			}
		},

		resize: function(changeSize, resultSize){
			// summary:
			//		Call this to resize a widget, or after its size has changed.
			// description:
			//		Change size mode:
			//			When changeSize is specified, changes the marginBox of this widget
			//			and forces it to relayout its contents accordingly.
			//			changeSize may specify height, width, or both.
			//
			//			If resultSize is specified it indicates the size the widget will
			//			become after changeSize has been applied.
			//
			//		Notification mode:
			//			When changeSize is null, indicates that the caller has already changed
			//			the size of the widget, or perhaps it changed because the browser
			//			window was resized.  Tells widget to relayout its contents accordingly.
			//
			//			If resultSize is also specified it indicates the size the widget has
			//			become.
			//
			//		In either mode, this method also:
			//			1. Sets this._borderBox and this._contentBox to the new size of
			//				the widget.  Queries the current domNode size if necessary.
			//			2. Calls layout() to resize contents (and maybe adjust child widgets).
			//
			// changeSize: Object?
			//		Sets the widget to this margin-box size and position.
			//		May include any/all of the following properties:
			//	|	{w: int, h: int, l: int, t: int}
			//
			// resultSize: Object?
			//		The margin-box size of this widget after applying changeSize (if
			//		changeSize is specified).  If caller knows this size and
			//		passes it in, we don't need to query the browser to get the size.
			//	|	{w: int, h: int}

			var node = this.domNode;

			// set margin box size, unless it wasn't specified, in which case use current size
			if(changeSize){
				dojo.marginBox(node, changeSize);

				// set offset of the node
				if(changeSize.t){ node.style.top = changeSize.t + "px"; }
				if(changeSize.l){ node.style.left = changeSize.l + "px"; }
			}

			// If either height or width wasn't specified by the user, then query node for it.
			// But note that setting the margin box and then immediately querying dimensions may return
			// inaccurate results, so try not to depend on it.
			var mb = resultSize || {};
			dojo.mixin(mb, changeSize || {});	// changeSize overrides resultSize
			if( !("h" in mb) || !("w" in mb) ){
				mb = dojo.mixin(dojo.marginBox(node), mb);	// just use dojo.marginBox() to fill in missing values
			}

			// Compute and save the size of my border box and content box
			// (w/out calling dojo.contentBox() since that may fail if size was recently set)
			var cs = dojo.getComputedStyle(node);
			var me = dojo._getMarginExtents(node, cs);
			var be = dojo._getBorderExtents(node, cs);
			var bb = (this._borderBox = {
				w: mb.w - (me.w + be.w),
				h: mb.h - (me.h + be.h)
			});
			var pe = dojo._getPadExtents(node, cs);
			this._contentBox = {
				l: dojo._toPixelValue(node, cs.paddingLeft),
				t: dojo._toPixelValue(node, cs.paddingTop),
				w: bb.w - pe.w,
				h: bb.h - pe.h
			};

			// Callback for widget to adjust size of its children
			this.layout();
		},

		layout: function(){
			// summary:
			//		Widgets override this method to size and position their contents/children.
			//		When this is called this._contentBox is guaranteed to be set (see resize()).
			//
			//		This is called after startup(), and also when the widget's size has been
			//		changed.
			// tags:
			//		protected extension
		},

		_setupChild: function(/*dijit._Widget*/child){
			// summary:
			//		Common setup for initial children and children which are added after startup
			// tags:
			//		protected extension

			dojo.addClass(child.domNode, this.baseClass+"-child");
			if(child.baseClass){
				dojo.addClass(child.domNode, this.baseClass+"-"+child.baseClass);
			}
		},

		addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
			// Overrides _Container.addChild() to call _setupChild()
			this.inherited(arguments);
			if(this._started){
				this._setupChild(child);
			}
		},

		removeChild: function(/*dijit._Widget*/ child){
			// Overrides _Container.removeChild() to remove class added by _setupChild()
			dojo.removeClass(child.domNode, this.baseClass+"-child");
			if(child.baseClass){
				dojo.removeClass(child.domNode, this.baseClass+"-"+child.baseClass);
			}
			this.inherited(arguments);
		}
	}
);

dijit.layout.marginBox2contentBox = function(/*DomNode*/ node, /*Object*/ mb){
	// summary:
	//		Given the margin-box size of a node, return its content box size.
	//		Functions like dojo.contentBox() but is more reliable since it doesn't have
	//		to wait for the browser to compute sizes.
	var cs = dojo.getComputedStyle(node);
	var me = dojo._getMarginExtents(node, cs);
	var pb = dojo._getPadBorderExtents(node, cs);
	return {
		l: dojo._toPixelValue(node, cs.paddingLeft),
		t: dojo._toPixelValue(node, cs.paddingTop),
		w: mb.w - (me.w + pb.w),
		h: mb.h - (me.h + pb.h)
	};
};

(function(){
	var capitalize = function(word){
		return word.substring(0,1).toUpperCase() + word.substring(1);
	};

	var size = function(widget, dim){
		// size the child
		widget.resize ? widget.resize(dim) : dojo.marginBox(widget.domNode, dim);

		// record child's size, but favor our own numbers when we have them.
		// the browser lies sometimes
		dojo.mixin(widget, dojo.marginBox(widget.domNode));
		dojo.mixin(widget, dim);
	};

	dijit.layout.layoutChildren = function(/*DomNode*/ container, /*Object*/ dim, /*Object[]*/ children){
		// summary
		//		Layout a bunch of child dom nodes within a parent dom node
		// container:
		//		parent node
		// dim:
		//		{l, t, w, h} object specifying dimensions of container into which to place children
		// children:
		//		an array like [ {domNode: foo, layoutAlign: "bottom" }, {domNode: bar, layoutAlign: "client"} ]

		// copy dim because we are going to modify it
		dim = dojo.mixin({}, dim);

		dojo.addClass(container, "dijitLayoutContainer");

		// Move "client" elements to the end of the array for layout.  a11y dictates that the author
		// needs to be able to put them in the document in tab-order, but this algorithm requires that
		// client be last.
		children = dojo.filter(children, function(item){ return item.layoutAlign != "client"; })
			.concat(dojo.filter(children, function(item){ return item.layoutAlign == "client"; }));

		// set positions/sizes
		dojo.forEach(children, function(child){
			var elm = child.domNode,
				pos = child.layoutAlign;

			// set elem to upper left corner of unused space; may move it later
			var elmStyle = elm.style;
			elmStyle.left = dim.l+"px";
			elmStyle.top = dim.t+"px";
			elmStyle.bottom = elmStyle.right = "auto";

			dojo.addClass(elm, "dijitAlign" + capitalize(pos));

			// set size && adjust record of remaining space.
			// note that setting the width of a <div> may affect its height.
			if(pos == "top" || pos == "bottom"){
				size(child, { w: dim.w });
				dim.h -= child.h;
				if(pos == "top"){
					dim.t += child.h;
				}else{
					elmStyle.top = dim.t + dim.h + "px";
				}
			}else if(pos == "left" || pos == "right"){
				size(child, { h: dim.h });
				dim.w -= child.w;
				if(pos == "left"){
					dim.l += child.w;
				}else{
					elmStyle.left = dim.l + dim.w + "px";
				}
			}else if(pos == "client"){
				size(child, dim);
			}
		});
	};

})();

}

if(!dojo._hasResource["dijit._CssStateMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._CssStateMixin"] = true;
dojo.provide("dijit._CssStateMixin");


dojo.declare("dijit._CssStateMixin", [], {
	// summary:
	//		Mixin for widgets to set CSS classes on the widget DOM nodes depending on hover/mouse press/focus
	//		state changes, and also higher-level state changes such becoming disabled or selected.
	//
	// description:
	//		By mixing this class into your widget, and setting the this.baseClass attribute, it will automatically
	//		maintain CSS classes on the widget root node (this.domNode) depending on hover,
	//		active, focus, etc. state.   Ex: with a baseClass of dijitButton, it will apply the classes
	//		dijitButtonHovered and dijitButtonActive, as the user moves the mouse over the widget and clicks it.
	//
	//		It also sets CSS like dijitButtonDisabled based on widget semantic state.
	//
	//		By setting the cssStateNodes attribute, a widget can also track events on subnodes (like buttons
	//		within the widget).

	// cssStateNodes: [protected] Object
	//		List of sub-nodes within the widget that need CSS classes applied on mouse hover/press and focus
	//.
	//		Each entry in the hash is a an attachpoint names (like "upArrowButton") mapped to a CSS class names
	//		(like "dijitUpArrowButton"). Example:
	//	|		{
	//	|			"upArrowButton": "dijitUpArrowButton",
	//	|			"downArrowButton": "dijitDownArrowButton"
	//	|		}
	//		The above will set the CSS class dijitUpArrowButton to the this.upArrowButton DOMNode when it
	//		is hovered, etc.
	cssStateNodes: {},

	postCreate: function(){
		this.inherited(arguments);

		// Automatically monitor mouse events (essentially :hover and :active) on this.domNode
		dojo.forEach(["onmouseenter", "onmouseleave", "onmousedown"], function(e){
			this.connect(this.domNode, e, "_cssMouseEvent");
		}, this);
		
		// Monitoring changes to disabled, readonly, etc. state, and update CSS class of root node
		this.connect(this, "set", function(name, value){
			if(arguments.length >= 2 && {disabled: true, readOnly: true, checked:true, selected:true}[name]){
				this._setStateClass();
			}
		});

		// The widget coming in/out of the focus change affects it's state
		dojo.forEach(["_onFocus", "_onBlur"], function(ap){
			this.connect(this, ap, "_setStateClass");
		}, this);

		// Events on sub nodes within the widget
		for(var ap in this.cssStateNodes){
			this._trackMouseState(this[ap], this.cssStateNodes[ap]);
		}
		// Set state initially; there's probably no hover/active/focus state but widget might be
		// disabled/readonly so we want to set CSS classes for those conditions.
		this._setStateClass();
	},

	_cssMouseEvent: function(/*Event*/ event){
		// summary:
		//	Sets _hovering and _active properties depending on mouse state,
		//	then calls _setStateClass() to set appropriate CSS classes for this.domNode.

		if(!this.disabled){
			switch(event.type){
				case "mouseenter":
				case "mouseover":	// generated on non-IE browsers even though we connected to mouseenter
					this._hovering = true;
					this._active = this._mouseDown;
					break;

				case "mouseleave":
				case "mouseout":	// generated on non-IE browsers even though we connected to mouseleave
					this._hovering = false;
					this._active = false;
					break;

				case "mousedown" :
					this._active = true;
					this._mouseDown = true;
					// Set a global event to handle mouseup, so it fires properly
					// even if the cursor leaves this.domNode before the mouse up event.
					// Alternately could set active=false on mouseout.
					var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
						this._active = false;
						this._mouseDown = false;
						this._setStateClass();
						this.disconnect(mouseUpConnector);
					});
					break;
			}
			this._setStateClass();
		}
	},

	_setStateClass: function(){
		// summary:
		//		Update the visual state of the widget by setting the css classes on this.domNode
		//		(or this.stateNode if defined) by combining this.baseClass with
		//		various suffixes that represent the current widget state(s).
		//
		// description:
		//		In the case where a widget has multiple
		//		states, it sets the class based on all possible
		//	 	combinations.  For example, an invalid form widget that is being hovered
		//		will be "dijitInput dijitInputInvalid dijitInputHover dijitInputInvalidHover".
		//
		//		The widget may have one or more of the following states, determined
		//		by this.state, this.checked, this.valid, and this.selected:
		//			- Error - ValidationTextBox sets this.state to "Error" if the current input value is invalid
		//			- Checked - ex: a checkmark or a ToggleButton in a checked state, will have this.checked==true
		//			- Selected - ex: currently selected tab will have this.selected==true
		//
		//		In addition, it may have one or more of the following states,
		//		based on this.disabled and flags set in _onMouse (this._active, this._hovering, this._focused):
		//			- Disabled	- if the widget is disabled
		//			- Active		- if the mouse (or space/enter key?) is being pressed down
		//			- Focused		- if the widget has focus
		//			- Hover		- if the mouse is over the widget

		// Compute new set of classes
		var newStateClasses = this.baseClass.split(" ");

		function multiply(modifier){
			newStateClasses = newStateClasses.concat(dojo.map(newStateClasses, function(c){ return c+modifier; }), "dijit"+modifier);
		}

		if(!this.isLeftToRight()){
			// For RTL mode we need to set an addition class like dijitTextBoxRtl.
			multiply("Rtl");
		}

		if(this.checked){
			multiply("Checked");
		}
		if(this.state){
			multiply(this.state);
		}
		if(this.selected){
			multiply("Selected");
		}

		if(this.disabled){
			multiply("Disabled");
		}else if(this.readOnly){
			multiply("ReadOnly");
		}else{
			if(this._active){
				multiply("Active");
			}else if(this._hovering){
				multiply("Hover");
			}
		}

		if(this._focused){
			multiply("Focused");
		}

		// Remove old state classes and add new ones.
		// For performance concerns we only write into domNode.className once.
		var tn = this.stateNode || this.domNode,
			classHash = {};	// set of all classes (state and otherwise) for node

		dojo.forEach(tn.className.split(" "), function(c){ classHash[c] = true; });

		if("_stateClasses" in this){
			dojo.forEach(this._stateClasses, function(c){ delete classHash[c]; });
		}

		dojo.forEach(newStateClasses, function(c){ classHash[c] = true; });

		var newClasses = [];
		for(var c in classHash){
			newClasses.push(c);
		}
		tn.className = newClasses.join(" ");

		this._stateClasses = newStateClasses;
	},

	_trackMouseState: function(/*DomNode*/ node, /*String*/ clazz){
		// summary:
		//		Track mouse/focus events on specified node and set CSS class on that node to indicate
		//		current state.   Usually not called directly, but via cssStateNodes attribute.
		// description:
		//		Given class=foo, will set the following CSS class on the node
		//			- fooActive: if the user is currently pressing down the mouse button while over the node
		//			- fooHover: if the user is hovering the mouse over the node, but not pressing down a button
		//			- fooFocus: if the node is focused
		//
		//		Note that it won't set any classes if the widget is disabled.
		// node: DomNode
		//		Should be a sub-node of the widget, not the top node (this.domNode), since the top node
		//		is handled specially and automatically just by mixing in this class.
		// clazz: String
		//		CSS class name (ex: dijitSliderUpArrow).

		// Current state of node (initially false)
		// NB: setting specifically to false because dojo.toggleClass() needs true boolean as third arg
		var hovering=false, active=false, focused=false;

		var self = this,
			cn = dojo.hitch(this, "connect", node);

		function setClass(){
			var disabled = ("disabled" in self && self.disabled) || ("readonly" in self && self.readonly);
			dojo.toggleClass(node, clazz+"Hover", hovering && !active && !disabled);
			dojo.toggleClass(node, clazz+"Active", active && !disabled);
			dojo.toggleClass(node, clazz+"Focused", focused && !disabled);
		}

		// Mouse
		cn("onmouseenter", function(){
			hovering = true;
			setClass();
		});
		cn("onmouseleave", function(){
			hovering = false;
			active = false;
			setClass();
		});
		cn("onmousedown", function(){
			active = true;
			setClass();
		});
		cn("onmouseup", function(){
			active = false;
			setClass();
		});

		// Focus
		cn("onfocus", function(){
			focused = true;
			setClass();
		});
		cn("onblur", function(){
			focused = false;
			setClass();
		});

		// Just in case widget is enabled/disabled while it has focus/hover/active state.
		// Maybe this is overkill.
		this.connect(this, "set", function(name, value){
			if(name == "disabled" || name == "readOnly"){
				setClass();
			}
		});
	}
});

}

if(!dojo._hasResource["dijit.form._FormWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form._FormWidget"] = true;
dojo.provide("dijit.form._FormWidget");







dojo.declare("dijit.form._FormWidget", [dijit._Widget, dijit._Templated, dijit._CssStateMixin],
	{
	// summary:
	//		Base class for widgets corresponding to native HTML elements such as <checkbox> or <button>,
	//		which can be children of a <form> node or a `dijit.form.Form` widget.
	//
	// description:
	//		Represents a single HTML element.
	//		All these widgets should have these attributes just like native HTML input elements.
	//		You can set them during widget construction or afterwards, via `dijit._Widget.attr`.
	//
	//		They also share some common methods.

	// name: String
	//		Name used when submitting form; same as "name" attribute or plain HTML elements
	name: "",

	// alt: String
	//		Corresponds to the native HTML <input> element's attribute.
	alt: "",

	// value: String
	//		Corresponds to the native HTML <input> element's attribute.
	value: "",

	// type: String
	//		Corresponds to the native HTML <input> element's attribute.
	type: "text",

	// tabIndex: Integer
	//		Order fields are traversed when user hits the tab key
	tabIndex: "0",

	// disabled: Boolean
	//		Should this widget respond to user input?
	//		In markup, this is specified as "disabled='disabled'", or just "disabled".
	disabled: false,

	// intermediateChanges: Boolean
	//		Fires onChange for each value change or only on demand
	intermediateChanges: false,

	// scrollOnFocus: Boolean
	//		On focus, should this widget scroll into view?
	scrollOnFocus: true,

	// These mixins assume that the focus node is an INPUT, as many but not all _FormWidgets are.
	attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
		value: "focusNode",
		id: "focusNode",
		tabIndex: "focusNode",
		alt: "focusNode",
		title: "focusNode"
	}),

	postMixInProperties: function(){
		// Setup name=foo string to be referenced from the template (but only if a name has been specified)
		// Unfortunately we can't use attributeMap to set the name due to IE limitations, see #8660
		// Regarding escaping, see heading "Attribute values" in
		// http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
		this.nameAttrSetting = this.name ? ('name="' + this.name.replace(/'/g, "&quot;") + '"') : '';
		this.inherited(arguments);
	},

	postCreate: function(){
		this.inherited(arguments);
		this.connect(this.domNode, "onmousedown", "_onMouseDown");
	},

	_setDisabledAttr: function(/*Boolean*/ value){
		this.disabled = value;
		dojo.attr(this.focusNode, 'disabled', value);
		if(this.valueNode){
			dojo.attr(this.valueNode, 'disabled', value);
		}
		dijit.setWaiState(this.focusNode, "disabled", value);

		if(value){
			// reset these, because after the domNode is disabled, we can no longer receive
			// mouse related events, see #4200
			this._hovering = false;
			this._active = false;

			// clear tab stop(s) on this widget's focusable node(s)  (ComboBox has two focusable nodes)
			var attachPointNames = "tabIndex" in this.attributeMap ? this.attributeMap.tabIndex : "focusNode";
			dojo.forEach(dojo.isArray(attachPointNames) ? attachPointNames : [attachPointNames], function(attachPointName){
				var node = this[attachPointName];
				// complex code because tabIndex=-1 on a <div> doesn't work on FF
				if(dojo.isWebKit || dijit.hasDefaultTabStop(node)){	// see #11064 about webkit bug
					node.setAttribute('tabIndex', "-1");
				}else{
					node.removeAttribute('tabIndex');				
				}
			}, this);
		}else{
			this.focusNode.setAttribute('tabIndex', this.tabIndex);
		}
	},

	setDisabled: function(/*Boolean*/ disabled){
		// summary:
		//		Deprecated.   Use set('disabled', ...) instead.
		dojo.deprecated("setDisabled("+disabled+") is deprecated. Use set('disabled',"+disabled+") instead.", "", "2.0");
		this.set('disabled', disabled);
	},

	_onFocus: function(e){
		if(this.scrollOnFocus){
			dojo.window.scrollIntoView(this.domNode);
		}
		this.inherited(arguments);
	},

	isFocusable: function(){
		// summary:
		//		Tells if this widget is focusable or not.   Used internally by dijit.
		// tags:
		//		protected
		return !this.disabled && !this.readOnly && this.focusNode && (dojo.style(this.domNode, "display") != "none");
	},

	focus: function(){
		// summary:
		//		Put focus on this widget
		dijit.focus(this.focusNode);
	},

	compare: function(/*anything*/val1, /*anything*/val2){
		// summary:
		//		Compare 2 values (as returned by attr('value') for this widget).
		// tags:
		//		protected
		if(typeof val1 == "number" && typeof val2 == "number"){
			return (isNaN(val1) && isNaN(val2)) ? 0 : val1 - val2;
		}else if(val1 > val2){
			return 1;
		}else if(val1 < val2){
			return -1;
		}else{
			return 0;
		}
	},

	onChange: function(newValue){
		// summary:
		//		Callback when this widget's value is changed.
		// tags:
		//		callback
	},

	// _onChangeActive: [private] Boolean
	//		Indicates that changes to the value should call onChange() callback.
	//		This is false during widget initialization, to avoid calling onChange()
	//		when the initial value is set.
	_onChangeActive: false,

	_handleOnChange: function(/*anything*/ newValue, /* Boolean? */ priorityChange){
		// summary:
		//		Called when the value of the widget is set.  Calls onChange() if appropriate
		// newValue:
		//		the new value
		// priorityChange:
		//		For a slider, for example, dragging the slider is priorityChange==false,
		//		but on mouse up, it's priorityChange==true.  If intermediateChanges==true,
		//		onChange is only called form priorityChange=true events.
		// tags:
		//		private
		this._lastValue = newValue;
		if(this._lastValueReported == undefined && (priorityChange === null || !this._onChangeActive)){
			// this block executes not for a change, but during initialization,
			// and is used to store away the original value (or for ToggleButton, the original checked state)
			this._resetValue = this._lastValueReported = newValue;
		}
		if((this.intermediateChanges || priorityChange || priorityChange === undefined) &&
			((typeof newValue != typeof this._lastValueReported) ||
				this.compare(newValue, this._lastValueReported) != 0)){
			this._lastValueReported = newValue;
			if(this._onChangeActive){
				if(this._onChangeHandle){
					clearTimeout(this._onChangeHandle);
				}
				// setTimout allows hidden value processing to run and
				// also the onChange handler can safely adjust focus, etc
				this._onChangeHandle = setTimeout(dojo.hitch(this,
					function(){
						this._onChangeHandle = null;
						this.onChange(newValue);
					}), 0); // try to collapse multiple onChange's fired faster than can be processed
			}
		}
	},

	create: function(){
		// Overrides _Widget.create()
		this.inherited(arguments);
		this._onChangeActive = true;
	},

	destroy: function(){
		if(this._onChangeHandle){ // destroy called before last onChange has fired
			clearTimeout(this._onChangeHandle);
			this.onChange(this._lastValueReported);
		}
		this.inherited(arguments);
	},

	setValue: function(/*String*/ value){
		// summary:
		//		Deprecated.   Use set('value', ...) instead.
		dojo.deprecated("dijit.form._FormWidget:setValue("+value+") is deprecated.  Use set('value',"+value+") instead.", "", "2.0");
		this.set('value', value);
	},

	getValue: function(){
		// summary:
		//		Deprecated.   Use get('value') instead.
		dojo.deprecated(this.declaredClass+"::getValue() is deprecated. Use get('value') instead.", "", "2.0");
		return this.get('value');
	},
	
	_onMouseDown: function(e){
		// If user clicks on the button, even if the mouse is released outside of it,
		// this button should get focus (to mimics native browser buttons).
		// This is also needed on chrome because otherwise buttons won't get focus at all,
		// which leads to bizarre focus restore on Dialog close etc.
		if(!e.ctrlKey && this.isFocusable()){ // !e.ctrlKey to ignore right-click on mac
			// Set a global event to handle mouseup, so it fires properly
			// even if the cursor leaves this.domNode before the mouse up event.
			var mouseUpConnector = this.connect(dojo.body(), "onmouseup", function(){
				if (this.isFocusable()) {
					this.focus();
				}
				this.disconnect(mouseUpConnector);
			});
		}
	}
});

dojo.declare("dijit.form._FormValueWidget", dijit.form._FormWidget,
{
	// summary:
	//		Base class for widgets corresponding to native HTML elements such as <input> or <select> that have user changeable values.
	// description:
	//		Each _FormValueWidget represents a single input value, and has a (possibly hidden) <input> element,
	//		to which it serializes it's input value, so that form submission (either normal submission or via FormBind?)
	//		works as expected.

	// Don't attempt to mixin the 'type', 'name' attributes here programatically -- they must be declared
	// directly in the template as read by the parser in order to function. IE is known to specifically
	// require the 'name' attribute at element creation time.   See #8484, #8660.
	// TODO: unclear what that {value: ""} is for; FormWidget.attributeMap copies value to focusNode,
	// so maybe {value: ""} is so the value *doesn't* get copied to focusNode?
	// Seems like we really want value removed from attributeMap altogether
	// (although there's no easy way to do that now)

	// readOnly: Boolean
	//		Should this widget respond to user input?
	//		In markup, this is specified as "readOnly".
	//		Similar to disabled except readOnly form values are submitted.
	readOnly: false,

	attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
		value: "",
		readOnly: "focusNode"
	}),

	_setReadOnlyAttr: function(/*Boolean*/ value){
		this.readOnly = value;
		dojo.attr(this.focusNode, 'readOnly', value);
		dijit.setWaiState(this.focusNode, "readonly", value);
	},

	postCreate: function(){
		this.inherited(arguments);

		if(dojo.isIE){ // IE won't stop the event with keypress
			this.connect(this.focusNode || this.domNode, "onkeydown", this._onKeyDown);
		}
		// Update our reset value if it hasn't yet been set (because this.set()
		// is only called when there *is* a value)
		if(this._resetValue === undefined){
			this._resetValue = this.value;
		}
	},

	_setValueAttr: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
		// summary:
		//		Hook so attr('value', value) works.
		// description:
		//		Sets the value of the widget.
		//		If the value has changed, then fire onChange event, unless priorityChange
		//		is specified as null (or false?)
		this.value = newValue;
		this._handleOnChange(newValue, priorityChange);
	},

	_getValueAttr: function(){
		// summary:
		//		Hook so attr('value') works.
		return this._lastValue;
	},

	undo: function(){
		// summary:
		//		Restore the value to the last value passed to onChange
		this._setValueAttr(this._lastValueReported, false);
	},

	reset: function(){
		// summary:
		//		Reset the widget's value to what it was at initialization time
		this._hasBeenBlurred = false;
		this._setValueAttr(this._resetValue, true);
	},

	_onKeyDown: function(e){
		if(e.keyCode == dojo.keys.ESCAPE && !(e.ctrlKey || e.altKey || e.metaKey)){
			var te;
			if(dojo.isIE){
				e.preventDefault(); // default behavior needs to be stopped here since keypress is too late
				te = document.createEventObject();
				te.keyCode = dojo.keys.ESCAPE;
				te.shiftKey = e.shiftKey;
				e.srcElement.fireEvent('onkeypress', te);
			}
		}
	},

	_layoutHackIE7: function(){
		// summary:
		//		Work around table sizing bugs on IE7 by forcing redraw

		if(dojo.isIE == 7){ // fix IE7 layout bug when the widget is scrolled out of sight
			var domNode = this.domNode;
			var parent = domNode.parentNode;
			var pingNode = domNode.firstChild || domNode; // target node most unlikely to have a custom filter
			var origFilter = pingNode.style.filter; // save custom filter, most likely nothing
			var _this = this;
			while(parent && parent.clientHeight == 0){ // search for parents that haven't rendered yet
				(function ping(){
					var disconnectHandle = _this.connect(parent, "onscroll",
						function(e){
							_this.disconnect(disconnectHandle); // only call once
							pingNode.style.filter = (new Date()).getMilliseconds(); // set to anything that's unique
							setTimeout(function(){ pingNode.style.filter = origFilter }, 0); // restore custom filter, if any
						}
					);
				})();
				parent = parent.parentNode;
			}
		}
	}
});

}

if(!dojo._hasResource["dijit.dijit"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.dijit"] = true;
dojo.provide("dijit.dijit");

/*=====
dijit.dijit = {
	// summary:
	//		A roll-up for common dijit methods
	// description:
	//	A rollup file for the build system including the core and common
	//	dijit files.
	//
	// example:
	// | <script type="text/javascript" src="js/dojo/dijit/dijit.js"></script>
	//
};
=====*/

// All the stuff in _base (these are the function that are guaranteed available without an explicit dojo.require)


// And some other stuff that we tend to pull in all the time anyway







}

if(!dojo._hasResource["com.sixnet.services.widgets.dndSource"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.dndSource"] = true;

dojo.provide("com.sixnet.services.widgets.dndSource");

dojo.declare('com.sixnet.services.widgets.dndSource',[dijit._Widget], {
	droppedNodes: [],
	type: "notypeset", 
	title: "notitleset", 
	symbol: "nosymbolset",
	dropMarkupFactory: null,
	constructor: function(){
		this.droppedNodes = [];
	},
	postMixInProperties: function(){
		this.media = {
				m: this.title + ".png",
				dndSource: this
		};
	},
	addNodeHandle: function(node){
		var dndHandle = dojo.create('span');
		dojo.addClass(dndHandle, "dojoDndHandle");
		dndHandle.innerHTML = '<img style="height:1.5em; width:1.5em" src="./images/handle.png" />';
		node.appendChild(dndHandle);
	},
	markupFactory: function(){
		// build a source widget and return the main node.
		var node = dojo.create('span');
		node.innerHTML = "<img class='image' src='dojo/com/sixnet/services/widgets/templates/images/" + this.media.m + "'/>";
//		node.innerHTML = this.title;
		node.id = dojo.dnd.getUniqueId();
		_sixnet_framework.log(1, node, " << node at markupFactory");
		return node;
	},
	dropMarkup: function(){
		_sixnet_framework.log(1, node, " << node at dndSource.dropMarkup()");
		var node = dojo.create('span');
		node.innerHTML = "<img class='image' src='./images/" + this.media.m + "'/>";
		node.id = dojo.dnd.getUniqueId();
		return node;
	}
});



}

if(!dojo._hasResource["dojo.dnd.common"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.dnd.common"] = true;
dojo.provide("dojo.dnd.common");

dojo.dnd.getCopyKeyState = dojo.isCopyKey;

dojo.dnd._uniqueId = 0;
dojo.dnd.getUniqueId = function(){
	// summary:
	//		returns a unique string for use with any DOM element
	var id;
	do{
		id = dojo._scopeName + "Unique" + (++dojo.dnd._uniqueId);
	}while(dojo.byId(id));
	return id;
};

dojo.dnd._empty = {};

dojo.dnd.isFormElement = function(/*Event*/ e){
	// summary:
	//		returns true if user clicked on a form element
	var t = e.target;
	if(t.nodeType == 3 /*TEXT_NODE*/){
		t = t.parentNode;
	}
	return " button textarea input select option ".indexOf(" " + t.tagName.toLowerCase() + " ") >= 0;	// Boolean
};

}

if(!dojo._hasResource["dojo.dnd.Container"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.dnd.Container"] = true;
dojo.provide("dojo.dnd.Container");




/*
	Container states:
		""		- normal state
		"Over"	- mouse over a container
	Container item states:
		""		- normal state
		"Over"	- mouse over a container item
*/

/*=====
dojo.declare("dojo.dnd.__ContainerArgs", [], {
	creator: function(){
		// summary:
		//		a creator function, which takes a data item, and returns an object like that:
		//		{node: newNode, data: usedData, type: arrayOfStrings}
	},

	// skipForm: Boolean
	//		don't start the drag operation, if clicked on form elements
	skipForm: false,

	// dropParent: Node||String
	//		node or node's id to use as the parent node for dropped items
	//		(must be underneath the 'node' parameter in the DOM)
	dropParent: null,

	// _skipStartup: Boolean
	//		skip startup(), which collects children, for deferred initialization
	//		(this is used in the markup mode)
	_skipStartup: false
});

dojo.dnd.Item = function(){
	// summary:
	//		Represents (one of) the source node(s) being dragged.
	//		Contains (at least) the "type" and "data" attributes.
	// type: String[]
	//		Type(s) of this item, by default this is ["text"]
	// data: Object
	//		Logical representation of the object being dragged.
	//		If the drag object's type is "text" then data is a String,
	//		if it's another type then data could be a different Object,
	//		perhaps a name/value hash.
	
	this.type = type;
	this.data = data;
}
=====*/

dojo.declare("dojo.dnd.Container", null, {
	// summary:
	//		a Container object, which knows when mouse hovers over it, 
	//		and over which element it hovers
	
	// object attributes (for markup)
	skipForm: false,
	
	/*=====
	// current: DomNode
	//		The DOM node the mouse is currently hovered over
	current: null,
	
	// map: Hash<String, dojo.dnd.Item>
	//		Map from an item's id (which is also the DOMNode's id) to
	//		the dojo.dnd.Item itself.
	map: {},
	=====*/
	
	constructor: function(node, params){
		// summary:
		//		a constructor of the Container
		// node: Node
		//		node or node's id to build the container on
		// params: dojo.dnd.__ContainerArgs
		//		a dictionary of parameters
		this.node = dojo.byId(node);
		if(!params){ params = {}; }
		this.creator = params.creator || null;
		this.skipForm = params.skipForm;
		this.parent = params.dropParent && dojo.byId(params.dropParent);
		
		// class-specific variables
		this.map = {};
		this.current = null;

		// states
		this.containerState = "";
		dojo.addClass(this.node, "dojoDndContainer");
		
		// mark up children
		if(!(params && params._skipStartup)){
			this.startup();
		}

		// set up events
		this.events = [
			dojo.connect(this.node, "onmouseover", this, "onMouseOver"),
			dojo.connect(this.node, "onmouseout",  this, "onMouseOut"),
			// cancel text selection and text dragging
			dojo.connect(this.node, "ondragstart",   this, "onSelectStart"),
			dojo.connect(this.node, "onselectstart", this, "onSelectStart")
		];
	},
	
	// object attributes (for markup)
	creator: function(){
		// summary:
		//		creator function, dummy at the moment
	},
	
	// abstract access to the map
	getItem: function(/*String*/ key){
		// summary:
		//		returns a data item by its key (id)
		return this.map[key];	// dojo.dnd.Item
	},
	setItem: function(/*String*/ key, /*dojo.dnd.Item*/ data){
		// summary:
		//		associates a data item with its key (id)
		this.map[key] = data;
	},
	delItem: function(/*String*/ key){
		// summary:
		//		removes a data item from the map by its key (id)
		delete this.map[key];
	},
	forInItems: function(/*Function*/ f, /*Object?*/ o){
		// summary:
		//		iterates over a data map skipping members that 
		//		are present in the empty object (IE and/or 3rd-party libraries).
		o = o || dojo.global;
		var m = this.map, e = dojo.dnd._empty;
		for(var i in m){
			if(i in e){ continue; }
			f.call(o, m[i], i, this);
		}
		return o;	// Object
	},
	clearItems: function(){
		// summary:
		//		removes all data items from the map
		this.map = {};
	},
	
	// methods
	getAllNodes: function(){
		// summary:
		//		returns a list (an array) of all valid child nodes
		return dojo.query("> .dojoDndItem", this.parent);	// NodeList
	},
	sync: function(){
		// summary:
		//		sync up the node list with the data map
		var map = {};
		this.getAllNodes().forEach(function(node){
			if(node.id){
				var item = this.getItem(node.id);
				if(item){
					map[node.id] = item;
					return;
				}
			}else{
				node.id = dojo.dnd.getUniqueId();
			}
			var type = node.getAttribute("dndType"),
				data = node.getAttribute("dndData");
			map[node.id] = {
				data: data || node.innerHTML,
				type: type ? type.split(/\s*,\s*/) : ["text"]
			};
		}, this);
		this.map = map;
		return this;	// self
	},
	insertNodes: function(data, before, anchor){
		// summary:
		//		inserts an array of new nodes before/after an anchor node
		// data: Array
		//		a list of data items, which should be processed by the creator function
		// before: Boolean
		//		insert before the anchor, if true, and after the anchor otherwise
		// anchor: Node
		//		the anchor node to be used as a point of insertion
		if(!this.parent.firstChild){
			anchor = null;
		}else if(before){
			if(!anchor){
				anchor = this.parent.firstChild;
			}
		}else{
			if(anchor){
				anchor = anchor.nextSibling;
			}
		}
		if(anchor){
			for(var i = 0; i < data.length; ++i){
				var t = this._normalizedCreator(data[i]);
				this.setItem(t.node.id, {data: t.data, type: t.type});
				this.parent.insertBefore(t.node, anchor);
			}
		}else{
			for(var i = 0; i < data.length; ++i){
				var t = this._normalizedCreator(data[i]);
				this.setItem(t.node.id, {data: t.data, type: t.type});
				this.parent.appendChild(t.node);
			}
		}
		return this;	// self
	},
	destroy: function(){
		// summary:
		//		prepares this object to be garbage-collected
		dojo.forEach(this.events, dojo.disconnect);
		this.clearItems();
		this.node = this.parent = this.current = null;
	},

	// markup methods
	markupFactory: function(params, node){
		params._skipStartup = true;
		return new dojo.dnd.Container(node, params);
	},
	startup: function(){
		// summary:
		//		collects valid child items and populate the map
		
		// set up the real parent node
		if(!this.parent){
			// use the standard algorithm, if not assigned
			this.parent = this.node;
			if(this.parent.tagName.toLowerCase() == "table"){
				var c = this.parent.getElementsByTagName("tbody");
				if(c && c.length){ this.parent = c[0]; }
			}
		}
		this.defaultCreator = dojo.dnd._defaultCreator(this.parent);

		// process specially marked children
		this.sync();
	},

	// mouse events
	onMouseOver: function(e){
		// summary:
		//		event processor for onmouseover
		// e: Event
		//		mouse event
		var n = e.relatedTarget;
		while(n){
			if(n == this.node){ break; }
			try{
				n = n.parentNode;
			}catch(x){
				n = null;
			}
		}
		if(!n){
			this._changeState("Container", "Over");
			this.onOverEvent();
		}
		n = this._getChildByEvent(e);
		if(this.current == n){ return; }
		if(this.current){ this._removeItemClass(this.current, "Over"); }
		if(n){ this._addItemClass(n, "Over"); }
		this.current = n;
	},
	onMouseOut: function(e){
		// summary:
		//		event processor for onmouseout
		// e: Event
		//		mouse event
		for(var n = e.relatedTarget; n;){
			if(n == this.node){ return; }
			try{
				n = n.parentNode;
			}catch(x){
				n = null;
			}
		}
		if(this.current){
			this._removeItemClass(this.current, "Over");
			this.current = null;
		}
		this._changeState("Container", "");
		this.onOutEvent();
	},
	onSelectStart: function(e){
		// summary:
		//		event processor for onselectevent and ondragevent
		// e: Event
		//		mouse event
		if(!this.skipForm || !dojo.dnd.isFormElement(e)){
			dojo.stopEvent(e);
		}
	},
	
	// utilities
	onOverEvent: function(){
		// summary:
		//		this function is called once, when mouse is over our container
	},
	onOutEvent: function(){
		// summary:
		//		this function is called once, when mouse is out of our container
	},
	_changeState: function(type, newState){
		// summary:
		//		changes a named state to new state value
		// type: String
		//		a name of the state to change
		// newState: String
		//		new state
		var prefix = "dojoDnd" + type;
		var state  = type.toLowerCase() + "State";
		//dojo.replaceClass(this.node, prefix + newState, prefix + this[state]);
		dojo.removeClass(this.node, prefix + this[state]);
		dojo.addClass(this.node, prefix + newState);
		this[state] = newState;
	},
	_addItemClass: function(node, type){
		// summary:
		//		adds a class with prefix "dojoDndItem"
		// node: Node
		//		a node
		// type: String
		//		a variable suffix for a class name
		dojo.addClass(node, "dojoDndItem" + type);
	},
	_removeItemClass: function(node, type){
		// summary:
		//		removes a class with prefix "dojoDndItem"
		// node: Node
		//		a node
		// type: String
		//		a variable suffix for a class name
		dojo.removeClass(node, "dojoDndItem" + type);
	},
	_getChildByEvent: function(e){
		// summary:
		//		gets a child, which is under the mouse at the moment, or null
		// e: Event
		//		a mouse event
		var node = e.target;
		if(node){
			for(var parent = node.parentNode; parent; node = parent, parent = node.parentNode){
				if(parent == this.parent && dojo.hasClass(node, "dojoDndItem")){ return node; }
			}
		}
		return null;
	},
	_normalizedCreator: function(/*dojo.dnd.Item*/ item, /*String*/ hint){
		// summary:
		//		adds all necessary data to the output of the user-supplied creator function
		var t = (this.creator || this.defaultCreator).call(this, item, hint);
		if(!dojo.isArray(t.type)){ t.type = ["text"]; }
		if(!t.node.id){ t.node.id = dojo.dnd.getUniqueId(); }
		dojo.addClass(t.node, "dojoDndItem");
		return t;
	}
});

dojo.dnd._createNode = function(tag){
	// summary:
	//		returns a function, which creates an element of given tag 
	//		(SPAN by default) and sets its innerHTML to given text
	// tag: String
	//		a tag name or empty for SPAN
	if(!tag){ return dojo.dnd._createSpan; }
	return function(text){	// Function
		return dojo.create(tag, {innerHTML: text});	// Node
	};
};

dojo.dnd._createTrTd = function(text){
	// summary:
	//		creates a TR/TD structure with given text as an innerHTML of TD
	// text: String
	//		a text for TD
	var tr = dojo.create("tr");
	dojo.create("td", {innerHTML: text}, tr);
	return tr;	// Node
};

dojo.dnd._createSpan = function(text){
	// summary:
	//		creates a SPAN element with given text as its innerHTML
	// text: String
	//		a text for SPAN
	return dojo.create("span", {innerHTML: text});	// Node
};

// dojo.dnd._defaultCreatorNodes: Object
//		a dictionary that maps container tag names to child tag names
dojo.dnd._defaultCreatorNodes = {ul: "li", ol: "li", div: "div", p: "div"};

dojo.dnd._defaultCreator = function(node){
	// summary:
	//		takes a parent node, and returns an appropriate creator function
	// node: Node
	//		a container node
	var tag = node.tagName.toLowerCase();
	var c = tag == "tbody" || tag == "thead" ? dojo.dnd._createTrTd :
			dojo.dnd._createNode(dojo.dnd._defaultCreatorNodes[tag]);
	return function(item, hint){	// Function
		var isObj = item && dojo.isObject(item), data, type, n;
		if(isObj && item.tagName && item.nodeType && item.getAttribute){
			// process a DOM node
			data = item.getAttribute("dndData") || item.innerHTML;
			type = item.getAttribute("dndType");
			type = type ? type.split(/\s*,\s*/) : ["text"];
			n = item;	// this node is going to be moved rather than copied
		}else{
			// process a DnD item object or a string
			data = (isObj && item.data) ? item.data : item;
			type = (isObj && item.type) ? item.type : ["text"];
			n = (hint == "avatar" ? dojo.dnd._createSpan : c)(String(data));
		}
		if(!n.id){
			n.id = dojo.dnd.getUniqueId();
		}
		return {node: n, data: data, type: type};
	};
};

}

if(!dojo._hasResource["dojo.dnd.Selector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.dnd.Selector"] = true;
dojo.provide("dojo.dnd.Selector");




/*
	Container item states:
		""			- an item is not selected
		"Selected"	- an item is selected
		"Anchor"	- an item is selected, and is an anchor for a "shift" selection
*/

/*=====
dojo.declare("dojo.dnd.__SelectorArgs", [dojo.dnd.__ContainerArgs], {
	//	singular: Boolean
	//		allows selection of only one element, if true
	singular: false,

	//	autoSync: Boolean
	//		autosynchronizes the source with its list of DnD nodes,
	autoSync: false
});
=====*/

dojo.declare("dojo.dnd.Selector", dojo.dnd.Container, {
	// summary:
	//		a Selector object, which knows how to select its children
	
	/*=====
	// selection: Set<String>
	//		The set of id's that are currently selected, such that this.selection[id] == 1
	//		if the node w/that id is selected.  Can iterate over selected node's id's like:
	//	|		for(var id in this.selection)
	selection: {},
	=====*/

	constructor: function(node, params){
		// summary:
		//		constructor of the Selector
		// node: Node||String
		//		node or node's id to build the selector on
		// params: dojo.dnd.__SelectorArgs?
		//		a dictionary of parameters
		if(!params){ params = {}; }
		this.singular = params.singular;
		this.autoSync = params.autoSync;
		// class-specific variables
		this.selection = {};
		this.anchor = null;
		this.simpleSelection = false;
		// set up events
		this.events.push(
			dojo.connect(this.node, "onmousedown", this, "onMouseDown"),
			dojo.connect(this.node, "onmouseup",   this, "onMouseUp"));
	},
	
	// object attributes (for markup)
	singular: false,	// is singular property
	
	// methods
	getSelectedNodes: function(){
		// summary:
		//		returns a list (an array) of selected nodes
		var t = new dojo.NodeList();
		var e = dojo.dnd._empty;
		for(var i in this.selection){
			if(i in e){ continue; }
			t.push(dojo.byId(i));
		}
		return t;	// NodeList
	},
	selectNone: function(){
		// summary:
		//		unselects all items
		return this._removeSelection()._removeAnchor();	// self
	},
	selectAll: function(){
		// summary:
		//		selects all items
		this.forInItems(function(data, id){
			this._addItemClass(dojo.byId(id), "Selected");
			this.selection[id] = 1;
		}, this);
		return this._removeAnchor();	// self
	},
	deleteSelectedNodes: function(){
		// summary:
		//		deletes all selected items
		var e = dojo.dnd._empty;
		for(var i in this.selection){
			if(i in e){ continue; }
			var n = dojo.byId(i);
			this.delItem(i);
			dojo.destroy(n);
		}
		this.anchor = null;
		this.selection = {};
		return this;	// self
	},
	forInSelectedItems: function(/*Function*/ f, /*Object?*/ o){
		// summary:
		//		iterates over selected items;
		//		see `dojo.dnd.Container.forInItems()` for details
		o = o || dojo.global;
		var s = this.selection, e = dojo.dnd._empty;
		for(var i in s){
			if(i in e){ continue; }
			f.call(o, this.getItem(i), i, this);
		}
	},
	sync: function(){
		// summary:
		//		sync up the node list with the data map
		
		dojo.dnd.Selector.superclass.sync.call(this);
		
		// fix the anchor
		if(this.anchor){
			if(!this.getItem(this.anchor.id)){
				this.anchor = null;
			}
		}
		
		// fix the selection
		var t = [], e = dojo.dnd._empty;
		for(var i in this.selection){
			if(i in e){ continue; }
			if(!this.getItem(i)){
				t.push(i);
			}
		}
		dojo.forEach(t, function(i){
			delete this.selection[i];
		}, this);
		
		return this;	// self
	},
	insertNodes: function(addSelected, data, before, anchor){
		// summary:
		//		inserts new data items (see `dojo.dnd.Container.insertNodes()` method for details)
		// addSelected: Boolean
		//		all new nodes will be added to selected items, if true, no selection change otherwise
		// data: Array
		//		a list of data items, which should be processed by the creator function
		// before: Boolean
		//		insert before the anchor, if true, and after the anchor otherwise
		// anchor: Node
		//		the anchor node to be used as a point of insertion
		var oldCreator = this._normalizedCreator;
		this._normalizedCreator = function(item, hint){
			var t = oldCreator.call(this, item, hint);
			if(addSelected){
				if(!this.anchor){
					this.anchor = t.node;
					this._removeItemClass(t.node, "Selected");
					this._addItemClass(this.anchor, "Anchor");
				}else if(this.anchor != t.node){
					this._removeItemClass(t.node, "Anchor");
					this._addItemClass(t.node, "Selected");
				}
				this.selection[t.node.id] = 1;
			}else{
				this._removeItemClass(t.node, "Selected");
				this._removeItemClass(t.node, "Anchor");
			}
			return t;
		};
		dojo.dnd.Selector.superclass.insertNodes.call(this, data, before, anchor);
		this._normalizedCreator = oldCreator;
		return this;	// self
	},
	destroy: function(){
		// summary:
		//		prepares the object to be garbage-collected
		dojo.dnd.Selector.superclass.destroy.call(this);
		this.selection = this.anchor = null;
	},

	// markup methods
	markupFactory: function(params, node){
		params._skipStartup = true;
		return new dojo.dnd.Selector(node, params);
	},

	// mouse events
	onMouseDown: function(e){
		// summary:
		//		event processor for onmousedown
		// e: Event
		//		mouse event
		if(this.autoSync){ this.sync(); }
		if(!this.current){ return; }
		if(!this.singular && !dojo.isCopyKey(e) && !e.shiftKey && (this.current.id in this.selection)){
			this.simpleSelection = true;
			if(e.button === dojo.mouseButtons.LEFT){
				// accept the left button and stop the event
				// for IE we don't stop event when multiple buttons are pressed
				dojo.stopEvent(e);
			}
			return;
		}
		if(!this.singular && e.shiftKey){
			if(!dojo.isCopyKey(e)){
				this._removeSelection();
			}
			var c = this.getAllNodes();
			if(c.length){
				if(!this.anchor){
					this.anchor = c[0];
					this._addItemClass(this.anchor, "Anchor");
				}
				this.selection[this.anchor.id] = 1;
				if(this.anchor != this.current){
					var i = 0;
					for(; i < c.length; ++i){
						var node = c[i];
						if(node == this.anchor || node == this.current){ break; }
					}
					for(++i; i < c.length; ++i){
						var node = c[i];
						if(node == this.anchor || node == this.current){ break; }
						this._addItemClass(node, "Selected");
						this.selection[node.id] = 1;
					}
					this._addItemClass(this.current, "Selected");
					this.selection[this.current.id] = 1;
				}
			}
		}else{
			if(this.singular){
				if(this.anchor == this.current){
					if(dojo.isCopyKey(e)){
						this.selectNone();
					}
				}else{
					this.selectNone();
					this.anchor = this.current;
					this._addItemClass(this.anchor, "Anchor");
					this.selection[this.current.id] = 1;
				}
			}else{
				if(dojo.isCopyKey(e)){
					if(this.anchor == this.current){
						delete this.selection[this.anchor.id];
						this._removeAnchor();
					}else{
						if(this.current.id in this.selection){
							this._removeItemClass(this.current, "Selected");
							delete this.selection[this.current.id];
						}else{
							if(this.anchor){
								this._removeItemClass(this.anchor, "Anchor");
								this._addItemClass(this.anchor, "Selected");
							}
							this.anchor = this.current;
							this._addItemClass(this.current, "Anchor");
							this.selection[this.current.id] = 1;
						}
					}
				}else{
					if(!(this.current.id in this.selection)){
						this.selectNone();
						this.anchor = this.current;
						this._addItemClass(this.current, "Anchor");
						this.selection[this.current.id] = 1;
					}
				}
			}
		}
		dojo.stopEvent(e);
	},
	onMouseUp: function(e){
		// summary:
		//		event processor for onmouseup
		// e: Event
		//		mouse event
		if(!this.simpleSelection){ return; }
		this.simpleSelection = false;
		this.selectNone();
		if(this.current){
			this.anchor = this.current;
			this._addItemClass(this.anchor, "Anchor");
			this.selection[this.current.id] = 1;
		}
	},
	onMouseMove: function(e){
		// summary
		//		event processor for onmousemove
		// e: Event
		//		mouse event
		this.simpleSelection = false;
	},
	
	// utilities
	onOverEvent: function(){
		// summary:
		//		this function is called once, when mouse is over our container
		this.onmousemoveEvent = dojo.connect(this.node, "onmousemove", this, "onMouseMove");
	},
	onOutEvent: function(){
		// summary:
		//		this function is called once, when mouse is out of our container
		dojo.disconnect(this.onmousemoveEvent);
		delete this.onmousemoveEvent;
	},
	_removeSelection: function(){
		// summary:
		//		unselects all items
		var e = dojo.dnd._empty;
		for(var i in this.selection){
			if(i in e){ continue; }
			var node = dojo.byId(i);
			if(node){ this._removeItemClass(node, "Selected"); }
		}
		this.selection = {};
		return this;	// self
	},
	_removeAnchor: function(){
		if(this.anchor){
			this._removeItemClass(this.anchor, "Anchor");
			this.anchor = null;
		}
		return this;	// self
	}
});

}

if(!dojo._hasResource["dojo.dnd.autoscroll"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.dnd.autoscroll"] = true;
dojo.provide("dojo.dnd.autoscroll");

dojo.dnd.getViewport = function(){
	// summary:
	//		Returns a viewport size (visible part of the window)

	// TODO: remove this when getViewport() moved to dojo core, see #7028

	// FIXME: need more docs!!
	var d = dojo.doc, dd = d.documentElement, w = window, b = dojo.body();
	if(dojo.isMozilla){
		return {w: dd.clientWidth, h: w.innerHeight};	// Object
	}else if(!dojo.isOpera && w.innerWidth){
		return {w: w.innerWidth, h: w.innerHeight};		// Object
	}else if (!dojo.isOpera && dd && dd.clientWidth){
		return {w: dd.clientWidth, h: dd.clientHeight};	// Object
	}else if (b.clientWidth){
		return {w: b.clientWidth, h: b.clientHeight};	// Object
	}
	return null;	// Object
};

dojo.dnd.V_TRIGGER_AUTOSCROLL = 32;
dojo.dnd.H_TRIGGER_AUTOSCROLL = 32;

dojo.dnd.V_AUTOSCROLL_VALUE = 16;
dojo.dnd.H_AUTOSCROLL_VALUE = 16;

dojo.dnd.autoScroll = function(e){
	// summary:
	//		a handler for onmousemove event, which scrolls the window, if
	//		necesary
	// e: Event
	//		onmousemove event

	// FIXME: needs more docs!
	var v = dojo.dnd.getViewport(), dx = 0, dy = 0;
	if(e.clientX < dojo.dnd.H_TRIGGER_AUTOSCROLL){
		dx = -dojo.dnd.H_AUTOSCROLL_VALUE;
	}else if(e.clientX > v.w - dojo.dnd.H_TRIGGER_AUTOSCROLL){
		dx = dojo.dnd.H_AUTOSCROLL_VALUE;
	}
	if(e.clientY < dojo.dnd.V_TRIGGER_AUTOSCROLL){
		dy = -dojo.dnd.V_AUTOSCROLL_VALUE;
	}else if(e.clientY > v.h - dojo.dnd.V_TRIGGER_AUTOSCROLL){
		dy = dojo.dnd.V_AUTOSCROLL_VALUE;
	}
	window.scrollBy(dx, dy);
};

dojo.dnd._validNodes = {"div": 1, "p": 1, "td": 1};
dojo.dnd._validOverflow = {"auto": 1, "scroll": 1};

dojo.dnd.autoScrollNodes = function(e){
	// summary:
	//		a handler for onmousemove event, which scrolls the first avaialble
	//		Dom element, it falls back to dojo.dnd.autoScroll()
	// e: Event
	//		onmousemove event

	// FIXME: needs more docs!
	for(var n = e.target; n;){
		if(n.nodeType == 1 && (n.tagName.toLowerCase() in dojo.dnd._validNodes)){
			var s = dojo.getComputedStyle(n);
			if(s.overflow.toLowerCase() in dojo.dnd._validOverflow){
				var b = dojo._getContentBox(n, s), t = dojo.position(n, true);
				//console.log(b.l, b.t, t.x, t.y, n.scrollLeft, n.scrollTop);
				var w = Math.min(dojo.dnd.H_TRIGGER_AUTOSCROLL, b.w / 2), 
					h = Math.min(dojo.dnd.V_TRIGGER_AUTOSCROLL, b.h / 2),
					rx = e.pageX - t.x, ry = e.pageY - t.y, dx = 0, dy = 0;
				if(dojo.isWebKit || dojo.isOpera){
					// FIXME: this code should not be here, it should be taken into account 
					// either by the event fixing code, or the dojo.position()
					// FIXME: this code doesn't work on Opera 9.5 Beta
					rx += dojo.body().scrollLeft, ry += dojo.body().scrollTop;
				}
				if(rx > 0 && rx < b.w){
					if(rx < w){
						dx = -w;
					}else if(rx > b.w - w){
						dx = w;
					}
				}
				//console.log("ry =", ry, "b.h =", b.h, "h =", h);
				if(ry > 0 && ry < b.h){
					if(ry < h){
						dy = -h;
					}else if(ry > b.h - h){
						dy = h;
					}
				}
				var oldLeft = n.scrollLeft, oldTop = n.scrollTop;
				n.scrollLeft = n.scrollLeft + dx;
				n.scrollTop  = n.scrollTop  + dy;
				if(oldLeft != n.scrollLeft || oldTop != n.scrollTop){ return; }
			}
		}
		try{
			n = n.parentNode;
		}catch(x){
			n = null;
		}
	}
	dojo.dnd.autoScroll(e);
};

}

if(!dojo._hasResource["dojo.dnd.Avatar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.dnd.Avatar"] = true;
dojo.provide("dojo.dnd.Avatar");



dojo.declare("dojo.dnd.Avatar", null, {
	// summary:
	//		Object that represents transferred DnD items visually
	// manager: Object
	//		a DnD manager object

	constructor: function(manager){
		this.manager = manager;
		this.construct();
	},

	// methods
	construct: function(){
		// summary:
		//		constructor function;
		//		it is separate so it can be (dynamically) overwritten in case of need
		this.isA11y = dojo.hasClass(dojo.body(),"dijit_a11y");
		var a = dojo.create("table", {
				"class": "dojoDndAvatar",
				style: {
					position: "absolute",
					zIndex:   "1999",
					margin:   "0px"
				}
			}),
			source = this.manager.source, node,
			b = dojo.create("tbody", null, a),
			tr = dojo.create("tr", null, b),
			td = dojo.create("td", null, tr),
			icon = this.isA11y ? dojo.create("span", {
						id : "a11yIcon",
						innerHTML : this.manager.copy ? '+' : "<"
					}, td) : null,
			span = dojo.create("span", {
				innerHTML: source.generateText ? this._generateText() : ""
			}, td),
			k = Math.min(5, this.manager.nodes.length), i = 0;
		// we have to set the opacity on IE only after the node is live
		dojo.attr(tr, {
			"class": "dojoDndAvatarHeader",
			style: {opacity: 0.9}
		});
		for(; i < k; ++i){
			if(source.creator){
				// create an avatar representation of the node
				node = source._normalizedCreator(source.getItem(this.manager.nodes[i].id).data, "avatar").node;
			}else{
				// or just clone the node and hope it works
				node = this.manager.nodes[i].cloneNode(true);
				if(node.tagName.toLowerCase() == "tr"){
					// insert extra table nodes
					var table = dojo.create("table"),
						tbody = dojo.create("tbody", null, table);
					tbody.appendChild(node);
					node = table;
				}
			}
			node.id = "";
			tr = dojo.create("tr", null, b);
			td = dojo.create("td", null, tr);
			td.appendChild(node);
			dojo.attr(tr, {
				"class": "dojoDndAvatarItem",
				style: {opacity: (9 - i) / 10}
			});
		}
		this.node = a;
	},
	destroy: function(){
		// summary:
		//		destructor for the avatar; called to remove all references so it can be garbage-collected
		dojo.destroy(this.node);
		this.node = false;
	},
	update: function(){
		// summary:
		//		updates the avatar to reflect the current DnD state
		dojo[(this.manager.canDropFlag ? "add" : "remove") + "Class"](this.node, "dojoDndAvatarCanDrop");
		if (this.isA11y){
			var icon = dojo.byId("a11yIcon");
			var text = '+';   // assume canDrop && copy
			if (this.manager.canDropFlag && !this.manager.copy) {
				text = '< '; // canDrop && move 
			}else if (!this.manager.canDropFlag && !this.manager.copy) {
				text = "o"; //!canDrop && move
			}else if(!this.manager.canDropFlag){
				text = 'x';  // !canDrop && copy
			}
			icon.innerHTML=text;
		}
		// replace text
		dojo.query(("tr.dojoDndAvatarHeader td span" +(this.isA11y ? " span" : "")), this.node).forEach(
			function(node){
				node.innerHTML = this._generateText();
			}, this);
	},
	_generateText: function(){
		// summary: generates a proper text to reflect copying or moving of items
		return this.manager.nodes.length.toString();
	}
});

}

if(!dojo._hasResource["dojo.dnd.Manager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.dnd.Manager"] = true;
dojo.provide("dojo.dnd.Manager");





dojo.declare("dojo.dnd.Manager", null, {
	// summary:
	//		the manager of DnD operations (usually a singleton)
	constructor: function(){
		this.avatar  = null;
		this.source = null;
		this.nodes = [];
		this.copy  = true;
		this.target = null;
		this.canDropFlag = false;
		this.events = [];
	},

	// avatar's offset from the mouse
	OFFSET_X: 16,
	OFFSET_Y: 16,
	
	// methods
	overSource: function(source){
		// summary:
		//		called when a source detected a mouse-over condition
		// source: Object
		//		the reporter
		if(this.avatar){
			this.target = (source && source.targetState != "Disabled") ? source : null;
			this.canDropFlag = Boolean(this.target);
			this.avatar.update();
		}
		dojo.publish("/dnd/source/over", [source]);
	},
	outSource: function(source){
		// summary:
		//		called when a source detected a mouse-out condition
		// source: Object
		//		the reporter
		if(this.avatar){
			if(this.target == source){
				this.target = null;
				this.canDropFlag = false;
				this.avatar.update();
				dojo.publish("/dnd/source/over", [null]);
			}
		}else{
			dojo.publish("/dnd/source/over", [null]);
		}
	},
	startDrag: function(source, nodes, copy){
		// summary:
		//		called to initiate the DnD operation
		// source: Object
		//		the source which provides items
		// nodes: Array
		//		the list of transferred items
		// copy: Boolean
		//		copy items, if true, move items otherwise
		this.source = source;
		this.nodes  = nodes;
		this.copy   = Boolean(copy); // normalizing to true boolean
		this.avatar = this.makeAvatar();
		dojo.body().appendChild(this.avatar.node);
		dojo.publish("/dnd/start", [source, nodes, this.copy]);
		this.events = [
			dojo.connect(dojo.doc, "onmousemove", this, "onMouseMove"),
			dojo.connect(dojo.doc, "onmouseup",   this, "onMouseUp"),
			dojo.connect(dojo.doc, "onkeydown",   this, "onKeyDown"),
			dojo.connect(dojo.doc, "onkeyup",     this, "onKeyUp"),
			// cancel text selection and text dragging
			dojo.connect(dojo.doc, "ondragstart",   dojo.stopEvent),
			dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent)
		];
		var c = "dojoDnd" + (copy ? "Copy" : "Move");
		dojo.addClass(dojo.body(), c); 
	},
	canDrop: function(flag){
		// summary:
		//		called to notify if the current target can accept items
		var canDropFlag = Boolean(this.target && flag);
		if(this.canDropFlag != canDropFlag){
			this.canDropFlag = canDropFlag;
			this.avatar.update();
		}
	},
	stopDrag: function(){
		// summary:
		//		stop the DnD in progress
		dojo.removeClass(dojo.body(), "dojoDndCopy");
		dojo.removeClass(dojo.body(), "dojoDndMove");
		dojo.forEach(this.events, dojo.disconnect);
		this.events = [];
		this.avatar.destroy();
		this.avatar = null;
		this.source = this.target = null;
		this.nodes = [];
	},
	makeAvatar: function(){
		// summary:
		//		makes the avatar; it is separate to be overwritten dynamically, if needed
		return new dojo.dnd.Avatar(this);
	},
	updateAvatar: function(){
		// summary:
		//		updates the avatar; it is separate to be overwritten dynamically, if needed
		this.avatar.update();
	},
	
	// mouse event processors
	onMouseMove: function(e){
		// summary:
		//		event processor for onmousemove
		// e: Event
		//		mouse event
		var a = this.avatar;
		if(a){
			dojo.dnd.autoScrollNodes(e);
			//dojo.dnd.autoScroll(e);
			var s = a.node.style;
			s.left = (e.pageX + this.OFFSET_X) + "px";
			s.top  = (e.pageY + this.OFFSET_Y) + "px";
			var copy = Boolean(this.source.copyState(dojo.isCopyKey(e)));
			if(this.copy != copy){ 
				this._setCopyStatus(copy);
			}
		}
	},
	onMouseUp: function(e){
		// summary:
		//		event processor for onmouseup
		// e: Event
		//		mouse event
		if(this.avatar){
			if(this.target && this.canDropFlag){
				var copy = Boolean(this.source.copyState(dojo.isCopyKey(e))),
				params = [this.source, this.nodes, copy, this.target, e];
				dojo.publish("/dnd/drop/before", params);
				dojo.publish("/dnd/drop", params);
			}else{
				dojo.publish("/dnd/cancel");
			}
			this.stopDrag();
		}
	},
	
	// keyboard event processors
	onKeyDown: function(e){
		// summary:
		//		event processor for onkeydown:
		//		watching for CTRL for copy/move status, watching for ESCAPE to cancel the drag
		// e: Event
		//		keyboard event
		if(this.avatar){
			switch(e.keyCode){
				case dojo.keys.CTRL:
					var copy = Boolean(this.source.copyState(true));
					if(this.copy != copy){ 
						this._setCopyStatus(copy);
					}
					break;
				case dojo.keys.ESCAPE:
					dojo.publish("/dnd/cancel");
					this.stopDrag();
					break;
			}
		}
	},
	onKeyUp: function(e){
		// summary:
		//		event processor for onkeyup, watching for CTRL for copy/move status
		// e: Event
		//		keyboard event
		if(this.avatar && e.keyCode == dojo.keys.CTRL){
			var copy = Boolean(this.source.copyState(false));
			if(this.copy != copy){ 
				this._setCopyStatus(copy);
			}
		}
	},
	
	// utilities
	_setCopyStatus: function(copy){
		// summary:
		//		changes the copy status
		// copy: Boolean
		//		the copy status
		this.copy = copy;
		this.source._markDndStatus(this.copy);
		this.updateAvatar();
		dojo.removeClass(dojo.body(), "dojoDnd" + (this.copy ? "Move" : "Copy"));
		dojo.addClass(dojo.body(), "dojoDnd" + (this.copy ? "Copy" : "Move"));
	}
});

// dojo.dnd._manager:
//		The manager singleton variable. Can be overwritten if needed.
dojo.dnd._manager = null;

dojo.dnd.manager = function(){
	// summary:
	//		Returns the current DnD manager.  Creates one if it is not created yet.
	if(!dojo.dnd._manager){
		dojo.dnd._manager = new dojo.dnd.Manager();
	}
	return dojo.dnd._manager;	// Object
};

}

if(!dojo._hasResource["dojo.dnd.Source"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.dnd.Source"] = true;
dojo.provide("dojo.dnd.Source");




/*
	Container property:
		"Horizontal"- if this is the horizontal container
	Source states:
		""			- normal state
		"Moved"		- this source is being moved
		"Copied"	- this source is being copied
	Target states:
		""			- normal state
		"Disabled"	- the target cannot accept an avatar
	Target anchor state:
		""			- item is not selected
		"Before"	- insert point is before the anchor
		"After"		- insert point is after the anchor
*/

/*=====
dojo.dnd.__SourceArgs = function(){
	//	summary:
	//		a dict of parameters for DnD Source configuration. Note that any
	//		property on Source elements may be configured, but this is the
	//		short-list
	//	isSource: Boolean?
	//		can be used as a DnD source. Defaults to true.
	//	accept: Array?
	//		list of accepted types (text strings) for a target; defaults to
	//		["text"]
	//	autoSync: Boolean
	//		if true refreshes the node list on every operation; false by default
	//	copyOnly: Boolean?
	//		copy items, if true, use a state of Ctrl key otherwise,
	//		see selfCopy and selfAccept for more details
	//	delay: Number
	//		the move delay in pixels before detecting a drag; 0 by default
	//	horizontal: Boolean?
	//		a horizontal container, if true, vertical otherwise or when omitted
	//	selfCopy: Boolean?
	//		copy items by default when dropping on itself,
	//		false by default, works only if copyOnly is true
	//	selfAccept: Boolean?
	//		accept its own items when copyOnly is true,
	//		true by default, works only if copyOnly is true
	//	withHandles: Boolean?
	//		allows dragging only by handles, false by default
	//  generateText: Boolean?
	//		generate text node for drag and drop, true by default
	this.isSource = isSource;
	this.accept = accept;
	this.autoSync = autoSync;
	this.copyOnly = copyOnly;
	this.delay = delay;
	this.horizontal = horizontal;
	this.selfCopy = selfCopy;
	this.selfAccept = selfAccept;
	this.withHandles = withHandles;
	this.generateText = true;
}
=====*/

dojo.declare("dojo.dnd.Source", dojo.dnd.Selector, {
	// summary:
	//		a Source object, which can be used as a DnD source, or a DnD target
	
	// object attributes (for markup)
	isSource: true,
	horizontal: false,
	copyOnly: false,
	selfCopy: false,
	selfAccept: true,
	skipForm: false,
	withHandles: false,
	autoSync: false,
	delay: 0, // pixels
	accept: ["text"],
	generateText: true,
	
	constructor: function(/*DOMNode|String*/node, /*dojo.dnd.__SourceArgs?*/params){
		// summary: 
		//		a constructor of the Source
		// node:
		//		node or node's id to build the source on
		// params: 
		//		any property of this class may be configured via the params
		//		object which is mixed-in to the `dojo.dnd.Source` instance
		dojo.mixin(this, dojo.mixin({}, params));
		var type = this.accept;
		if(type.length){
			this.accept = {};
			for(var i = 0; i < type.length; ++i){
				this.accept[type[i]] = 1;
			}
		}
		// class-specific variables
		this.isDragging = false;
		this.mouseDown = false;
		this.targetAnchor = null;
		this.targetBox = null;
		this.before = true;
		this._lastX = 0;
		this._lastY = 0;
		// states
		this.sourceState  = "";
		if(this.isSource){
			dojo.addClass(this.node, "dojoDndSource");
		}
		this.targetState  = "";
		if(this.accept){
			dojo.addClass(this.node, "dojoDndTarget");
		}
		if(this.horizontal){
			dojo.addClass(this.node, "dojoDndHorizontal");
		}
		// set up events
		this.topics = [
			dojo.subscribe("/dnd/source/over", this, "onDndSourceOver"),
			dojo.subscribe("/dnd/start",  this, "onDndStart"),
			dojo.subscribe("/dnd/drop",   this, "onDndDrop"),
			dojo.subscribe("/dnd/cancel", this, "onDndCancel")
		];
	},
	
	// methods
	checkAcceptance: function(source, nodes){
		// summary:
		//		checks if the target can accept nodes from this source
		// source: Object
		//		the source which provides items
		// nodes: Array
		//		the list of transferred items
		if(this == source){
			return !this.copyOnly || this.selfAccept;
		}
		for(var i = 0; i < nodes.length; ++i){
			var type = source.getItem(nodes[i].id).type;
			// type instanceof Array
			var flag = false;
			for(var j = 0; j < type.length; ++j){
				if(type[j] in this.accept){
					flag = true;
					break;
				}
			}
			if(!flag){
				return false;	// Boolean
			}
		}
		return true;	// Boolean
	},
	copyState: function(keyPressed, self){
		// summary:
		//		Returns true if we need to copy items, false to move.
		//		It is separated to be overwritten dynamically, if needed.
		// keyPressed: Boolean
		//		the "copy" key was pressed
		// self: Boolean?
		//		optional flag that means that we are about to drop on itself
		
		if(keyPressed){ return true; }
		if(arguments.length < 2){
			self = this == dojo.dnd.manager().target;
		}
		if(self){
			if(this.copyOnly){
				return this.selfCopy;
			}
		}else{
			return this.copyOnly;
		}
		return false;	// Boolean
	},
	destroy: function(){
		// summary:
		//		prepares the object to be garbage-collected
		dojo.dnd.Source.superclass.destroy.call(this);
		dojo.forEach(this.topics, dojo.unsubscribe);
		this.targetAnchor = null;
	},

	// markup methods
	markupFactory: function(params, node){
		params._skipStartup = true;
		return new dojo.dnd.Source(node, params);
	},

	// mouse event processors
	onMouseMove: function(e){
		// summary:
		//		event processor for onmousemove
		// e: Event
		//		mouse event
		if(this.isDragging && this.targetState == "Disabled"){ return; }
		dojo.dnd.Source.superclass.onMouseMove.call(this, e);
		var m = dojo.dnd.manager();
		if(!this.isDragging){
			if(this.mouseDown && this.isSource &&
					(Math.abs(e.pageX - this._lastX) > this.delay || Math.abs(e.pageY - this._lastY) > this.delay)){
				var nodes = this.getSelectedNodes();
				if(nodes.length){
					m.startDrag(this, nodes, this.copyState(dojo.isCopyKey(e), true));
				}
			}
		}
		if(this.isDragging){
			// calculate before/after
			var before = false;
			if(this.current){
				if(!this.targetBox || this.targetAnchor != this.current){
					this.targetBox = dojo.position(this.current, true);
				}
				if(this.horizontal){
					before = (e.pageX - this.targetBox.x) < (this.targetBox.w / 2);
				}else{
					before = (e.pageY - this.targetBox.y) < (this.targetBox.h / 2);
				}
			}
			if(this.current != this.targetAnchor || before != this.before){
				this._markTargetAnchor(before);
				m.canDrop(!this.current || m.source != this || !(this.current.id in this.selection));
			}
		}
	},
	onMouseDown: function(e){
		// summary:
		//		event processor for onmousedown
		// e: Event
		//		mouse event
		if(!this.mouseDown && this._legalMouseDown(e) && (!this.skipForm || !dojo.dnd.isFormElement(e))){
			this.mouseDown = true;
			this._lastX = e.pageX;
			this._lastY = e.pageY;
			dojo.dnd.Source.superclass.onMouseDown.call(this, e);
		}
	},
	onMouseUp: function(e){
		// summary:
		//		event processor for onmouseup
		// e: Event
		//		mouse event
		if(this.mouseDown){
			this.mouseDown = false;
			dojo.dnd.Source.superclass.onMouseUp.call(this, e);
		}
	},
	
	// topic event processors
	onDndSourceOver: function(source){
		// summary:
		//		topic event processor for /dnd/source/over, called when detected a current source
		// source: Object
		//		the source which has the mouse over it
		if(this != source){
			this.mouseDown = false;
			if(this.targetAnchor){
				this._unmarkTargetAnchor();
			}
		}else if(this.isDragging){
			var m = dojo.dnd.manager();
			m.canDrop(this.targetState != "Disabled" && (!this.current || m.source != this || !(this.current.id in this.selection)));
		}
	},
	onDndStart: function(source, nodes, copy){
		// summary:
		//		topic event processor for /dnd/start, called to initiate the DnD operation
		// source: Object
		//		the source which provides items
		// nodes: Array
		//		the list of transferred items
		// copy: Boolean
		//		copy items, if true, move items otherwise
		if(this.autoSync){ this.sync(); }
		if(this.isSource){
			this._changeState("Source", this == source ? (copy ? "Copied" : "Moved") : "");
		}
		var accepted = this.accept && this.checkAcceptance(source, nodes);
		this._changeState("Target", accepted ? "" : "Disabled");
		if(this == source){
			dojo.dnd.manager().overSource(this);
		}
		this.isDragging = true;
	},
	onDndDrop: function(source, nodes, copy, target){
		// summary:
		//		topic event processor for /dnd/drop, called to finish the DnD operation
		// source: Object
		//		the source which provides items
		// nodes: Array
		//		the list of transferred items
		// copy: Boolean
		//		copy items, if true, move items otherwise
		// target: Object
		//		the target which accepts items
		if(this == target){
			// this one is for us => move nodes!
			this.onDrop(source, nodes, copy);
		}
		this.onDndCancel();
	},
	onDndCancel: function(){
		// summary:
		//		topic event processor for /dnd/cancel, called to cancel the DnD operation
		if(this.targetAnchor){
			this._unmarkTargetAnchor();
			this.targetAnchor = null;
		}
		this.before = true;
		this.isDragging = false;
		this.mouseDown = false;
		this._changeState("Source", "");
		this._changeState("Target", "");
	},
	
	// local events
	onDrop: function(source, nodes, copy){
		// summary:
		//		called only on the current target, when drop is performed
		// source: Object
		//		the source which provides items
		// nodes: Array
		//		the list of transferred items
		// copy: Boolean
		//		copy items, if true, move items otherwise
		
		if(this != source){
			this.onDropExternal(source, nodes, copy);
		}else{
			this.onDropInternal(nodes, copy);
		}
	},
	onDropExternal: function(source, nodes, copy){
		// summary:
		//		called only on the current target, when drop is performed
		//		from an external source
		// source: Object
		//		the source which provides items
		// nodes: Array
		//		the list of transferred items
		// copy: Boolean
		//		copy items, if true, move items otherwise
		
		var oldCreator = this._normalizedCreator;
		// transferring nodes from the source to the target
		if(this.creator){
			// use defined creator
			this._normalizedCreator = function(node, hint){
				return oldCreator.call(this, source.getItem(node.id).data, hint);
			};
		}else{
			// we have no creator defined => move/clone nodes
			if(copy){
				// clone nodes
				this._normalizedCreator = function(node, hint){
					var t = source.getItem(node.id);
					var n = node.cloneNode(true);
					n.id = dojo.dnd.getUniqueId();
					return {node: n, data: t.data, type: t.type};
				};
			}else{
				// move nodes
				this._normalizedCreator = function(node, hint){
					var t = source.getItem(node.id);
					source.delItem(node.id);
					return {node: node, data: t.data, type: t.type};
				};
			}
		}
		this.selectNone();
		if(!copy && !this.creator){
			source.selectNone();
		}
		this.insertNodes(true, nodes, this.before, this.current);
		if(!copy && this.creator){
			source.deleteSelectedNodes();
		}
		this._normalizedCreator = oldCreator;
	},
	onDropInternal: function(nodes, copy){
		// summary:
		//		called only on the current target, when drop is performed
		//		from the same target/source
		// nodes: Array
		//		the list of transferred items
		// copy: Boolean
		//		copy items, if true, move items otherwise
		
		var oldCreator = this._normalizedCreator;
		// transferring nodes within the single source
		if(this.current && this.current.id in this.selection){
			// do nothing
			return;
		}
		if(copy){
			if(this.creator){
				// create new copies of data items
				this._normalizedCreator = function(node, hint){
					return oldCreator.call(this, this.getItem(node.id).data, hint);
				};
			}else{
				// clone nodes
				this._normalizedCreator = function(node, hint){
					var t = this.getItem(node.id);
					var n = node.cloneNode(true);
					n.id = dojo.dnd.getUniqueId();
					return {node: n, data: t.data, type: t.type};
				};
			}
		}else{
			// move nodes
			if(!this.current){
				// do nothing
				return;
			}
			this._normalizedCreator = function(node, hint){
				var t = this.getItem(node.id);
				return {node: node, data: t.data, type: t.type};
			};
		}
		this._removeSelection();
		this.insertNodes(true, nodes, this.before, this.current);
		this._normalizedCreator = oldCreator;
	},
	onDraggingOver: function(){
		// summary:
		//		called during the active DnD operation, when items
		//		are dragged over this target, and it is not disabled
	},
	onDraggingOut: function(){
		// summary:
		//		called during the active DnD operation, when items
		//		are dragged away from this target, and it is not disabled
	},
	
	// utilities
	onOverEvent: function(){
		// summary:
		//		this function is called once, when mouse is over our container
		dojo.dnd.Source.superclass.onOverEvent.call(this);
		dojo.dnd.manager().overSource(this);
		if(this.isDragging && this.targetState != "Disabled"){
			this.onDraggingOver();
		}
	},
	onOutEvent: function(){
		// summary:
		//		this function is called once, when mouse is out of our container
		dojo.dnd.Source.superclass.onOutEvent.call(this);
		dojo.dnd.manager().outSource(this);
		if(this.isDragging && this.targetState != "Disabled"){
			this.onDraggingOut();
		}
	},
	_markTargetAnchor: function(before){
		// summary:
		//		assigns a class to the current target anchor based on "before" status
		// before: Boolean
		//		insert before, if true, after otherwise
		if(this.current == this.targetAnchor && this.before == before){ return; }
		if(this.targetAnchor){
			this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
		}
		this.targetAnchor = this.current;
		this.targetBox = null;
		this.before = before;
		if(this.targetAnchor){
			this._addItemClass(this.targetAnchor, this.before ? "Before" : "After");
		}
	},
	_unmarkTargetAnchor: function(){
		// summary:
		//		removes a class of the current target anchor based on "before" status
		if(!this.targetAnchor){ return; }
		this._removeItemClass(this.targetAnchor, this.before ? "Before" : "After");
		this.targetAnchor = null;
		this.targetBox = null;
		this.before = true;
	},
	_markDndStatus: function(copy){
		// summary:
		//		changes source's state based on "copy" status
		this._changeState("Source", copy ? "Copied" : "Moved");
	},
	_legalMouseDown: function(e){
		// summary:
		//		checks if user clicked on "approved" items
		// e: Event
		//		mouse event
		
		// accept only the left mouse button
		if(!dojo.mouseButtons.isLeft(e)){ return false; }
		
		if(!this.withHandles){ return true; }
		
		// check for handles
		for(var node = e.target; node && node !== this.node; node = node.parentNode){
			if(dojo.hasClass(node, "dojoDndHandle")){ return true; }
			if(dojo.hasClass(node, "dojoDndItem") || dojo.hasClass(node, "dojoDndIgnore")){ break; }
		}
		return false;	// Boolean
	}
});

dojo.declare("dojo.dnd.Target", dojo.dnd.Source, {
	// summary: a Target object, which can be used as a DnD target
	
	constructor: function(node, params){
		// summary:
		//		a constructor of the Target --- see the `dojo.dnd.Source.constructor` for details
		this.isSource = false;
		dojo.removeClass(this.node, "dojoDndSource");
	},

	// markup methods
	markupFactory: function(params, node){
		params._skipStartup = true;
		return new dojo.dnd.Target(node, params);
	}
});

dojo.declare("dojo.dnd.AutoSource", dojo.dnd.Source, {
	// summary:
	//		a source that syncs its DnD nodes by default
	
	constructor: function(node, params){
		// summary:
		//		constructor of the AutoSource --- see the Source constructor for details
		this.autoSync = true;
	},

	// markup methods
	markupFactory: function(params, node){
		params._skipStartup = true;
		return new dojo.dnd.AutoSource(node, params);
	}
});

}

if(!dojo._hasResource["com.sixnet.services.widgets.dndDropZoneSource"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.dndDropZoneSource"] = true;



//dojo.require("dojo.dnd");
dojo.provide("com.sixnet.services.widgets.dndDropZoneSource");

dojo.declare('com.sixnet.services.widgets.dndDropZoneSource',[dijit._Widget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div class=\"dijit dijitInline dijitLeft\">\n\t\t<div dojoAttachPoint=\"dropZoneNode\" style=\"padding: 5px\" class=\"container dropZoneNode\">\n\t\t</div>\n</div>\n",
	_filled: false,
	source: {},
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.source = new dojo.dnd.Source( this.dropZoneNode, { creator: dojo.hitch(this, "dropZoneCreator"), skipForm:true, selfCopy: false, selfAccept:true, copyOnly:false, accept:["comparison","parens", "operands"], horizontal:true });
		//container"dojoType="dojo.dnd.Source" creator="dropZoneCreator" skipForm="true" selfCopy="false" accept="comparison, parens" horizontal="true" class="container"
//		var dzs = dojo.dnd.Source(this.dropZoneHolder);
//		for(var i = 0; i < this.accepts.length; i++){
//			this.dropZone.accepts.push(this.accepts[i]);
//		}
		_sixnet_framework.log(1, this, " << dropZoneSource");
		dojo.connect(dojo.dnd.manager(), "ondragstart", dojo.hitch(this, "startDrag"));
		dojo.subscribe("/dnd/start", null, this.highlightTargets);
//		startDrag(source, nodes, copy)
	},
	
	highlightTargets: function(){
		_sixnet_framework.log(1, "highlightTargets");
//	    var props = {
//	            margin: { start: ‘0′, end: ‘-5′, unit: ‘px’ },
//	            borderWidth: { start: ‘0′, end: ‘5′, unit: ‘px’ }
//	    };
//	    var m = dojo.dnd.manager();
//	    var hasZero = false;
//	    dojo.forEach(m.nodes, function(node){
//	        // check the selected item(s) to look for a zero quantity
//	        // so we know whether we can highlight the cart
//	        if(m.source.getItem(node.id).data.quantity == 0){
//	            hasZero = true;
//	        }
//	    });
//	    dojo.style("wishlistPaneNode", "borderColor", "#97e68d");
//	    dojo.style("cartPaneNode", "borderColor", "#97e68d");
//	    dojo.anim("wishlistPaneNode", props, 250);
//	    if(!hasZero){
//	        dojo.anim("cartPaneNode", props, 250);
//	        dojo.byId("cartPaneNode").isHighlighted = true;
//	    }
	},
	
	startDrag: function(source, nodes, copy){
		_sixnet_framework.log(1, "startDrag", arguments);
	},

	onDrop: function(node){
		_sixnet_framework.log(1, "onDrop, dndDropZoneSource");
	
	},
	
	isFilled: function(){
		return this._filled;
	},
	
	dropZoneCreator: function(item, hint){
		_sixnet_framework.log(1, "dropZoneCreator fired::Perform magic  Type:", item.type, "Item: ", item, arguments);
		var type = [item.type];
		var node = item.media.dndSource.dropMarkup(item, hint);
		this.source.accept = [];
		this._filled = true;
		setTimeout(dojo.hitch(this, "onDrop", node), 0); 
		//  TODO: ask Paul if all these css classes coming from dndQueryBuilder are okay
		dojo.addClass(this.dropZoneNode, "removeBorder");
		return {node: node, data: item, type: type};
	},
	 
	limitTarget: function(source, nodes){
		//  return false when limit (1) is reached
		_sixnet_framework.log(1, "limitTarget", source, nodes, nodes.length);
//		

		if(this == source){ 
			_sixnet_framework.log(1, "returning false");
			return false; 
			}
		for(var i = 0; i < nodes.length; i++){
			_sixnet_framework.log(1, "past this is source / not check", nodes[i]);
			if(nodes.length == 0){
				_sixnet_framework.log(1, "returning false");
				return false;
			}else{
				_sixnet_framework.log(1, "returning true");
//				dojo.addClass(nodes[i], "dojoDndTargetDisabled");
				return true;
			}
		}
	}
});

}

if(!dojo._hasResource["com.sixnet.services.widgets.dropParens"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.dropParens"] = true;




//dojo.require("dojo.dnd");
dojo.provide("com.sixnet.services.widgets.dropParens");

dojo.declare('com.sixnet.services.widgets.dropParens',[dijit._Widget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div class=\"dijit dijitInline dijitLeft\">\n\t\t<span style=\"font-size:1.5em;\"><strong>(</strong></span>\n\t\t<div  dojoType=\"com.sixnet.services.widgets.dndDropZoneSource\" dojoAttachEvent=\"onDrop:onChildDrop\">\n\t\t</div>\n\t\t<span style=\"font-size:1.5em;\"><strong>)</strong></span>\n</div>\n",
	fields:{},

	
	setFields: function(data){
		this.fields = data;
		_sixnet_framework.log(1, this.fields, "parenFields");
	},
	
	clear: function(){
		// remove all children
		// add a single dndDropZoneSource
	},
	onChildDrop: function(node){
		// build any dndDropZoneSources needed according to psuedo code.
//		dijit.getEnclosingWidget($1).onSelect = dojo.hitch(
//				  dijit.getEnclosingWidget($1),
//				  function(){ dojo.addClass(this.domNode, "showing") }
//				)
		//var tester = new com.sixnet.services.widgets.dndDropZoneSource({}).placeAt(dijit.getEnclosingWidget(this.domNode), "last");
		// we will be checking for: [dropZone]._filled = true/false
		_sixnet_framework.log(1, "onChildDrop (dropParens 31) >> ", node, node.previousSibling, node.nextSibling);
		var nodeWidget = dijit.getEnclosingWidget(dojo.byId(node));
		if(dojo.exists("setFields", nodeWidget)){
			nodeWidget.setFields(this.fields);
		}
//		_sixnet_framework.log(1, dijit.getEnclosingWidget(node.previousSibling).isFilled, dijit.getEnclosingWidget(node.nextSibling).isFilled);
		//
		var dropZoneBefore = {};
		var dropZoneAfter = {};
		if(node.previousSibling != null){
			//var filled = dijit.getEnclosingWidget(node.nextSibling);
			if(!dojo.hasClass(node.previousSibling, "dropZoneNode")){
				dropZoneBefore = new com.sixnet.services.widgets.dndDropZoneSource({}).placeAt(node, "before");
				///                onDrop:onChildDrop
			}else{
				if((dijit.getEnclosingWidget(node.previousSibling).isFilled)){
					dropZoneBefore = new com.sixnet.services.widgets.dndDropZoneSource({}).placeAt(node, "before");
				}
			}
			_sixnet_framework.log(1, "add before");
		}else{
			_sixnet_framework.log(1, "add before NULL");
			dropZoneBefore = new com.sixnet.services.widgets.dndDropZoneSource({}).placeAt(node, "before");
		}
	
		if(node.nextSibling != null){
			if(!dojo.hasClass(node.nextSibling, "dropZoneNode")){
				dropZoneAfter = new com.sixnet.services.widgets.dndDropZoneSource({}).placeAt(node, "after");
			}else{
				if(dijit.getEnclosingWidget(node.nextSibling).isFilled){
					dropZoneAfter = new com.sixnet.services.widgets.dndDropZoneSource({}).placeAt(node, "after");
				}
			}
			_sixnet_framework.log(1, "add after");
		}else{
			_sixnet_framework.log(1, "add after NULL");
			dropZoneAfter = new com.sixnet.services.widgets.dndDropZoneSource({}).placeAt(node, "after");
		}
		//
		if(dojo.exists("onDrop", dropZoneBefore)){
			dojo.connect(dropZoneBefore, "onDrop", this, "onChildDrop");
		}
		if(dojo.exists("onDrop", dropZoneAfter)){
			dojo.connect(dropZoneAfter, "onDrop", this, "onChildDrop");
		}
//////////////////////////////////////////////////////////////////////////////////////
//		var dropZones = dojo.query(".dropZoneNode", this.domNode);
//		if(dropZones.length > 0){
//			for(var i = 0; i < dropZones.length; i++){
//				var dz = dijit.getEnclosingWidget(dropZones[i]);
//				if(dz._filled){
//					_sixnet_framework.log(1, "previousSibling:  ", dz.domNode.previousSibling);
//					var psdz = dijit.getEnclosingWidget(dz.domNode.previousSibling);
//					var nsdz = dijit.getEnclosingWidget(dz.domNode.nextSibling);
//					if(!dojo.hasClass(dz.domNode.previousSibling, "dropZoneNode")){
//						new com.sixnet.services.widgets.dndDropZoneSource({}).placeAt(dz.domNode, "before");
//					}
//					if(!dojo.hasClass(dz.domNode.nextSibling, "dropZoneNode")){
//						new com.sixnet.services.widgets.dndDropZoneSource({}).placeAt(dz.domNode, "after");
//					}
//				}
//			}
//		}else{
//			new com.sixnet.services.widgets.dndDropZoneSource({}).placeAt(this.domNode, "before");
//			new com.sixnet.services.widgets.dndDropZoneSource({}).placeAt(this.domNode, "after");
//		}
//		_sixnet_framework.log(1, "Drop parens detects child drop event", this.domNode, dijit.getEnclosingWidget(dropZones[0]));
	}
});

}

if(!dojo._hasResource["dijit.form.TextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.TextBox"] = true;
dojo.provide("dijit.form.TextBox");



dojo.declare(
	"dijit.form.TextBox",
	dijit.form._FormValueWidget,
	{
		// summary:
		//		A base class for textbox form inputs

		// trim: Boolean
		//		Removes leading and trailing whitespace if true.  Default is false.
		trim: false,

		// uppercase: Boolean
		//		Converts all characters to uppercase if true.  Default is false.
		uppercase: false,

		// lowercase: Boolean
		//		Converts all characters to lowercase if true.  Default is false.
		lowercase: false,

		// propercase: Boolean
		//		Converts the first character of each word to uppercase if true.
		propercase: false,

		//	maxLength: String
		//		HTML INPUT tag maxLength declaration.
		maxLength: "",

		//	selectOnClick: [const] Boolean
		//		If true, all text will be selected when focused with mouse
		selectOnClick: false,

		//	placeHolder: String
		//		Defines a hint to help users fill out the input field (as defined in HTML 5).
		//		This should only contain plain text (no html markup).
		placeHolder: "",
		
		templateString: dojo.cache("dijit.form", "templates/TextBox.html", "<div class=\"dijit dijitReset dijitInline dijitLeft\" id=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),
		_singleNodeTemplate: '<input class="dijit dijitReset dijitLeft dijitInputField" dojoAttachPoint="textbox,focusNode" autocomplete="off" type="${type}" ${!nameAttrSetting} />',

		_buttonInputDisabled: dojo.isIE ? "disabled" : "", // allows IE to disallow focus, but Firefox cannot be disabled for mousedown events

		baseClass: "dijitTextBox",

		attributeMap: dojo.delegate(dijit.form._FormValueWidget.prototype.attributeMap, {
			maxLength: "focusNode"
		}),
		
		postMixInProperties: function(){
			var type = this.type.toLowerCase();
			if(this.templateString.toLowerCase() == "input" || ((type == "hidden" || type == "file") && this.templateString == dijit.form.TextBox.prototype.templateString)){
				this.templateString = this._singleNodeTemplate;
			}
			this.inherited(arguments);
		},

		_setPlaceHolderAttr: function(v){
			this.placeHolder = v;
			if(!this._phspan){
				this._attachPoints.push('_phspan');
				/* dijitInputField class gives placeHolder same padding as the input field
				 * parent node already has dijitInputField class but it doesn't affect this <span>
				 * since it's position: absolute.
				 */
				this._phspan = dojo.create('span',{className:'dijitPlaceHolder dijitInputField'},this.textbox,'after');
			}
			this._phspan.innerHTML="";
			this._phspan.appendChild(document.createTextNode(v));
			
			this._updatePlaceHolder();
		},
		
		_updatePlaceHolder: function(){
			if(this._phspan){
				this._phspan.style.display=(this.placeHolder&&!this._focused&&!this.textbox.value)?"":"none";
			}
		},

		_getValueAttr: function(){
			// summary:
			//		Hook so attr('value') works as we like.
			// description:
			//		For `dijit.form.TextBox` this basically returns the value of the <input>.
			//
			//		For `dijit.form.MappedTextBox` subclasses, which have both
			//		a "displayed value" and a separate "submit value",
			//		This treats the "displayed value" as the master value, computing the
			//		submit value from it via this.parse().
			return this.parse(this.get('displayedValue'), this.constraints);
		},

		_setValueAttr: function(value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
			// summary:
			//		Hook so attr('value', ...) works.
			//
			// description:
			//		Sets the value of the widget to "value" which can be of
			//		any type as determined by the widget.
			//
			// value:
			//		The visual element value is also set to a corresponding,
			//		but not necessarily the same, value.
			//
			// formattedValue:
			//		If specified, used to set the visual element value,
			//		otherwise a computed visual value is used.
			//
			// priorityChange:
			//		If true, an onChange event is fired immediately instead of
			//		waiting for the next blur event.

			var filteredValue;
			if(value !== undefined){
				// TODO: this is calling filter() on both the display value and the actual value.
				// I added a comment to the filter() definition about this, but it should be changed.
				filteredValue = this.filter(value);
				if(typeof formattedValue != "string"){
					if(filteredValue !== null && ((typeof filteredValue != "number") || !isNaN(filteredValue))){
						formattedValue = this.filter(this.format(filteredValue, this.constraints));
					}else{ formattedValue = ''; }
				}
			}
			if(formattedValue != null && formattedValue != undefined && ((typeof formattedValue) != "number" || !isNaN(formattedValue)) && this.textbox.value != formattedValue){
				this.textbox.value = formattedValue;
			}

			this._updatePlaceHolder();

			this.inherited(arguments, [filteredValue, priorityChange]);
		},

		// displayedValue: String
		//		For subclasses like ComboBox where the displayed value
		//		(ex: Kentucky) and the serialized value (ex: KY) are different,
		//		this represents the displayed value.
		//
		//		Setting 'displayedValue' through attr('displayedValue', ...)
		//		updates 'value', and vice-versa.  Otherwise 'value' is updated
		//		from 'displayedValue' periodically, like onBlur etc.
		//
		//		TODO: move declaration to MappedTextBox?
		//		Problem is that ComboBox references displayedValue,
		//		for benefit of FilteringSelect.
		displayedValue: "",

		getDisplayedValue: function(){
			// summary:
			//		Deprecated.   Use set('displayedValue') instead.
			// tags:
			//		deprecated
			dojo.deprecated(this.declaredClass+"::getDisplayedValue() is deprecated. Use set('displayedValue') instead.", "", "2.0");
			return this.get('displayedValue');
		},

		_getDisplayedValueAttr: function(){
			// summary:
			//		Hook so attr('displayedValue') works.
			// description:
			//		Returns the displayed value (what the user sees on the screen),
			// 		after filtering (ie, trimming spaces etc.).
			//
			//		For some subclasses of TextBox (like ComboBox), the displayed value
			//		is different from the serialized value that's actually
			//		sent to the server (see dijit.form.ValidationTextBox.serialize)

			return this.filter(this.textbox.value);
		},

		setDisplayedValue: function(/*String*/value){
			// summary:
			//		Deprecated.   Use set('displayedValue', ...) instead.
			// tags:
			//		deprecated
			dojo.deprecated(this.declaredClass+"::setDisplayedValue() is deprecated. Use set('displayedValue', ...) instead.", "", "2.0");
			this.set('displayedValue', value);
		},

		_setDisplayedValueAttr: function(/*String*/value){
			// summary:
			//		Hook so attr('displayedValue', ...) works.
			// description:
			//		Sets the value of the visual element to the string "value".
			//		The widget value is also set to a corresponding,
			//		but not necessarily the same, value.

			if(value === null || value === undefined){ value = '' }
			else if(typeof value != "string"){ value = String(value) }
			this.textbox.value = value;
			this._setValueAttr(this.get('value'), undefined, value);
		},

		format: function(/* String */ value, /* Object */ constraints){
			// summary:
			//		Replacable function to convert a value to a properly formatted string.
			// tags:
			//		protected extension
			return ((value == null || value == undefined) ? "" : (value.toString ? value.toString() : value));
		},

		parse: function(/* String */ value, /* Object */ constraints){
			// summary:
			//		Replacable function to convert a formatted string to a value
			// tags:
			//		protected extension

			return value;	// String
		},

		_refreshState: function(){
			// summary:
			//		After the user types some characters, etc., this method is
			//		called to check the field for validity etc.  The base method
			//		in `dijit.form.TextBox` does nothing, but subclasses override.
			// tags:
			//		protected
		},

		_onInput: function(e){
			if(e && e.type && /key/i.test(e.type) && e.keyCode){
				switch(e.keyCode){
					case dojo.keys.SHIFT:
					case dojo.keys.ALT:
					case dojo.keys.CTRL:
					case dojo.keys.TAB:
						return;
				}
			}
			if(this.intermediateChanges){
				var _this = this;
				// the setTimeout allows the key to post to the widget input box
				setTimeout(function(){ _this._handleOnChange(_this.get('value'), false); }, 0);
			}
			this._refreshState();
		},

		postCreate: function(){
			// setting the value here is needed since value="" in the template causes "undefined"
			// and setting in the DOM (instead of the JS object) helps with form reset actions
			if(dojo.isIE){ // IE INPUT tag fontFamily has to be set directly using STYLE
				var s = dojo.getComputedStyle(this.domNode);
				if(s){
					var ff = s.fontFamily;
					if(ff){
						var inputs = this.domNode.getElementsByTagName("INPUT");
						if(inputs){
							for(var i=0; i < inputs.length; i++){
								inputs[i].style.fontFamily = ff;
							}
						}
					}
				}
			}
			this.textbox.setAttribute("value", this.textbox.value); // DOM and JS values shuld be the same
			this.inherited(arguments);
			if(dojo.isMoz || dojo.isOpera){
				this.connect(this.textbox, "oninput", this._onInput);
			}else{
				this.connect(this.textbox, "onkeydown", this._onInput);
				this.connect(this.textbox, "onkeyup", this._onInput);
				this.connect(this.textbox, "onpaste", this._onInput);
				this.connect(this.textbox, "oncut", this._onInput);
			}
		},

		_blankValue: '', // if the textbox is blank, what value should be reported
		filter: function(val){
			// summary:
			//		Auto-corrections (such as trimming) that are applied to textbox
			//		value on blur or form submit.
			// description:
			//		For MappedTextBox subclasses, this is called twice
			// 			- once with the display value
			//			- once the value as set/returned by attr('value', ...)
			//		and attr('value'), ex: a Number for NumberTextBox.
			//
			//		In the latter case it does corrections like converting null to NaN.  In
			//		the former case the NumberTextBox.filter() method calls this.inherited()
			//		to execute standard trimming code in TextBox.filter().
			//
			//		TODO: break this into two methods in 2.0
			//
			// tags:
			//		protected extension
			if(val === null){ return this._blankValue; }
			if(typeof val != "string"){ return val; }
			if(this.trim){
				val = dojo.trim(val);
			}
			if(this.uppercase){
				val = val.toUpperCase();
			}
			if(this.lowercase){
				val = val.toLowerCase();
			}
			if(this.propercase){
				val = val.replace(/[^\s]+/g, function(word){
					return word.substring(0,1).toUpperCase() + word.substring(1);
				});
			}
			return val;
		},

		_setBlurValue: function(){
			this._setValueAttr(this.get('value'), true);
		},

		_onBlur: function(e){
			if(this.disabled){ return; }
			this._setBlurValue();
			this.inherited(arguments);

			if(this._selectOnClickHandle){
				this.disconnect(this._selectOnClickHandle);
			}
			if(this.selectOnClick && dojo.isMoz){
				this.textbox.selectionStart = this.textbox.selectionEnd = undefined; // clear selection so that the next mouse click doesn't reselect
			}
			
			this._updatePlaceHolder();
		},

		_onFocus: function(/*String*/ by){
			if(this.disabled || this.readOnly){ return; }

			// Select all text on focus via click if nothing already selected.
			// Since mouse-up will clear the selection need to defer selection until after mouse-up.
			// Don't do anything on focus by tabbing into the widget since there's no associated mouse-up event.
			if(this.selectOnClick && by == "mouse"){
				this._selectOnClickHandle = this.connect(this.domNode, "onmouseup", function(){
					// Only select all text on first click; otherwise users would have no way to clear
					// the selection.
					this.disconnect(this._selectOnClickHandle);

					// Check if the user selected some text manually (mouse-down, mouse-move, mouse-up)
					// and if not, then select all the text
					var textIsNotSelected;
					if(dojo.isIE){
						var range = dojo.doc.selection.createRange();
						var parent = range.parentElement();
						textIsNotSelected = parent == this.textbox && range.text.length == 0;
					}else{
						textIsNotSelected = this.textbox.selectionStart == this.textbox.selectionEnd;
					}
					if(textIsNotSelected){
						dijit.selectInputText(this.textbox);
					}
				});
			}

			this._updatePlaceHolder();
			
			this._refreshState();
			this.inherited(arguments);
		},

		reset: function(){
			// Overrides dijit._FormWidget.reset().
			// Additionally resets the displayed textbox value to ''
			this.textbox.value = '';
			this.inherited(arguments);
		}
	}
);

dijit.selectInputText = function(/*DomNode*/element, /*Number?*/ start, /*Number?*/ stop){
	// summary:
	//		Select text in the input element argument, from start (default 0), to stop (default end).

	// TODO: use functions in _editor/selection.js?
	var _window = dojo.global;
	var _document = dojo.doc;
	element = dojo.byId(element);
	if(isNaN(start)){ start = 0; }
	if(isNaN(stop)){ stop = element.value ? element.value.length : 0; }
	dijit.focus(element);
	if(_document["selection"] && dojo.body()["createTextRange"]){ // IE
		if(element.createTextRange){
			var range = element.createTextRange();
			with(range){
				collapse(true);
				moveStart("character", -99999); // move to 0
				moveStart("character", start); // delta from 0 is the correct position
				moveEnd("character", stop-start);
				select();
			}
		}
	}else if(_window["getSelection"]){
		if(element.setSelectionRange){
			element.setSelectionRange(start, stop);
		}
	}
};

}

if(!dojo._hasResource["dijit.form._FormMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form._FormMixin"] = true;
dojo.provide("dijit.form._FormMixin");



dojo.declare("dijit.form._FormMixin", null,
	{
	// summary:
	//		Mixin for containers of form widgets (i.e. widgets that represent a single value
	//		and can be children of a <form> node or dijit.form.Form widget)
	// description:
	//		Can extract all the form widgets
	//		values and combine them into a single javascript object, or alternately
	//		take such an object and set the values for all the contained
	//		form widgets

/*=====
    // value: Object
	//		Name/value hash for each child widget with a name and value.
	//		Child widgets without names are not part of the hash.
	// 
	//		If there are multiple child widgets w/the same name, value is an array,
	//		unless they are radio buttons in which case value is a scalar (since only
	//		one radio button can be checked at a time).
	//
	//		If a child widget's name is a dot separated list (like a.b.c.d), it's a nested structure.
	//
	//		Example:
	//	|	{ name: "John Smith", interests: ["sports", "movies"] }
=====*/

	//	TODO:
	//	* Repeater
	//	* better handling for arrays.  Often form elements have names with [] like
	//	* people[3].sex (for a list of people [{name: Bill, sex: M}, ...])
	//
	//

		reset: function(){
			dojo.forEach(this.getDescendants(), function(widget){
				if(widget.reset){
					widget.reset();
				}
			});
		},

		validate: function(){
			// summary:
			//		returns if the form is valid - same as isValid - but
			//			provides a few additional (ui-specific) features.
			//			1 - it will highlight any sub-widgets that are not
			//				valid
			//			2 - it will call focus() on the first invalid
			//				sub-widget
			var didFocus = false;
			return dojo.every(dojo.map(this.getDescendants(), function(widget){
				// Need to set this so that "required" widgets get their
				// state set.
				widget._hasBeenBlurred = true;
				var valid = widget.disabled || !widget.validate || widget.validate();
				if(!valid && !didFocus){
					// Set focus of the first non-valid widget
					dojo.window.scrollIntoView(widget.containerNode || widget.domNode);
					widget.focus();
					didFocus = true;
				}
	 			return valid;
	 		}), function(item){ return item; });
		},

		setValues: function(val){
			dojo.deprecated(this.declaredClass+"::setValues() is deprecated. Use set('value', val) instead.", "", "2.0");
			return this.set('value', val);
		},
		_setValueAttr: function(/*object*/obj){
			// summary:
			//		Fill in form values from according to an Object (in the format returned by attr('value'))

			// generate map from name --> [list of widgets with that name]
			var map = { };
			dojo.forEach(this.getDescendants(), function(widget){
				if(!widget.name){ return; }
				var entry = map[widget.name] || (map[widget.name] = [] );
				entry.push(widget);
			});

			for(var name in map){
				if(!map.hasOwnProperty(name)){
					continue;
				}
				var widgets = map[name],						// array of widgets w/this name
					values = dojo.getObject(name, false, obj);	// list of values for those widgets

				if(values === undefined){
					continue;
				}
				if(!dojo.isArray(values)){
					values = [ values ];
				}
				if(typeof widgets[0].checked == 'boolean'){
					// for checkbox/radio, values is a list of which widgets should be checked
					dojo.forEach(widgets, function(w, i){
						w.set('value', dojo.indexOf(values, w.value) != -1);
					});
				}else if(widgets[0].multiple){
					// it takes an array (e.g. multi-select)
					widgets[0].set('value', values);
				}else{
					// otherwise, values is a list of values to be assigned sequentially to each widget
					dojo.forEach(widgets, function(w, i){
						w.set('value', values[i]);
					});
				}
			}

			/***
			 * 	TODO: code for plain input boxes (this shouldn't run for inputs that are part of widgets)

			dojo.forEach(this.containerNode.elements, function(element){
				if(element.name == ''){return};	// like "continue"
				var namePath = element.name.split(".");
				var myObj=obj;
				var name=namePath[namePath.length-1];
				for(var j=1,len2=namePath.length;j<len2;++j){
					var p=namePath[j - 1];
					// repeater support block
					var nameA=p.split("[");
					if(nameA.length > 1){
						if(typeof(myObj[nameA[0]]) == "undefined"){
							myObj[nameA[0]]=[ ];
						} // if

						nameIndex=parseInt(nameA[1]);
						if(typeof(myObj[nameA[0]][nameIndex]) == "undefined"){
							myObj[nameA[0]][nameIndex] = { };
						}
						myObj=myObj[nameA[0]][nameIndex];
						continue;
					} // repeater support ends

					if(typeof(myObj[p]) == "undefined"){
						myObj=undefined;
						break;
					};
					myObj=myObj[p];
				}

				if(typeof(myObj) == "undefined"){
					return;		// like "continue"
				}
				if(typeof(myObj[name]) == "undefined" && this.ignoreNullValues){
					return;		// like "continue"
				}

				// TODO: widget values (just call attr('value', ...) on the widget)

				// TODO: maybe should call dojo.getNodeProp() instead
				switch(element.type){
					case "checkbox":
						element.checked = (name in myObj) &&
							dojo.some(myObj[name], function(val){ return val == element.value; });
						break;
					case "radio":
						element.checked = (name in myObj) && myObj[name] == element.value;
						break;
					case "select-multiple":
						element.selectedIndex=-1;
						dojo.forEach(element.options, function(option){
							option.selected = dojo.some(myObj[name], function(val){ return option.value == val; });
						});
						break;
					case "select-one":
						element.selectedIndex="0";
						dojo.forEach(element.options, function(option){
							option.selected = option.value == myObj[name];
						});
						break;
					case "hidden":
					case "text":
					case "textarea":
					case "password":
						element.value = myObj[name] || "";
						break;
				}
	  		});
	  		*/
		},

		getValues: function(){
			dojo.deprecated(this.declaredClass+"::getValues() is deprecated. Use get('value') instead.", "", "2.0");
			return this.get('value');
		},
		_getValueAttr: function(){
			// summary:
			// 		Returns Object representing form values.
			// description:
			//		Returns name/value hash for each form element.
			//		If there are multiple elements w/the same name, value is an array,
			//		unless they are radio buttons in which case value is a scalar since only
			//		one can be checked at a time.
			//
			//		If the name is a dot separated list (like a.b.c.d), creates a nested structure.
			//		Only works on widget form elements.
			// example:
			//		| { name: "John Smith", interests: ["sports", "movies"] }

			// get widget values
			var obj = { };
			dojo.forEach(this.getDescendants(), function(widget){
				var name = widget.name;
				if(!name || widget.disabled){ return; }

				// Single value widget (checkbox, radio, or plain <input> type widget
				var value = widget.get('value');

				// Store widget's value(s) as a scalar, except for checkboxes which are automatically arrays
				if(typeof widget.checked == 'boolean'){
					if(/Radio/.test(widget.declaredClass)){
						// radio button
						if(value !== false){
							dojo.setObject(name, value, obj);
						}else{
							// give radio widgets a default of null
							value = dojo.getObject(name, false, obj);
							if(value === undefined){
								dojo.setObject(name, null, obj);
							}
						}
					}else{
						// checkbox/toggle button
						var ary=dojo.getObject(name, false, obj);
						if(!ary){
							ary=[];
							dojo.setObject(name, ary, obj);
						}
						if(value !== false){
							ary.push(value);
						}
					}
				}else{
					var prev=dojo.getObject(name, false, obj);
					if(typeof prev != "undefined"){
						if(dojo.isArray(prev)){
							prev.push(value);
						}else{
							dojo.setObject(name, [prev, value], obj);
						}
					}else{
						// unique name
						dojo.setObject(name, value, obj);
					}
				}
			});

			/***
			 * code for plain input boxes (see also dojo.formToObject, can we use that instead of this code?
			 * but it doesn't understand [] notation, presumably)
			var obj = { };
			dojo.forEach(this.containerNode.elements, function(elm){
				if(!elm.name)	{
					return;		// like "continue"
				}
				var namePath = elm.name.split(".");
				var myObj=obj;
				var name=namePath[namePath.length-1];
				for(var j=1,len2=namePath.length;j<len2;++j){
					var nameIndex = null;
					var p=namePath[j - 1];
					var nameA=p.split("[");
					if(nameA.length > 1){
						if(typeof(myObj[nameA[0]]) == "undefined"){
							myObj[nameA[0]]=[ ];
						} // if
						nameIndex=parseInt(nameA[1]);
						if(typeof(myObj[nameA[0]][nameIndex]) == "undefined"){
							myObj[nameA[0]][nameIndex] = { };
						}
					} else if(typeof(myObj[nameA[0]]) == "undefined"){
						myObj[nameA[0]] = { }
					} // if

					if(nameA.length == 1){
						myObj=myObj[nameA[0]];
					} else{
						myObj=myObj[nameA[0]][nameIndex];
					} // if
				} // for

				if((elm.type != "select-multiple" && elm.type != "checkbox" && elm.type != "radio") || (elm.type == "radio" && elm.checked)){
					if(name == name.split("[")[0]){
						myObj[name]=elm.value;
					} else{
						// can not set value when there is no name
					}
				} else if(elm.type == "checkbox" && elm.checked){
					if(typeof(myObj[name]) == 'undefined'){
						myObj[name]=[ ];
					}
					myObj[name].push(elm.value);
				} else if(elm.type == "select-multiple"){
					if(typeof(myObj[name]) == 'undefined'){
						myObj[name]=[ ];
					}
					for(var jdx=0,len3=elm.options.length; jdx<len3; ++jdx){
						if(elm.options[jdx].selected){
							myObj[name].push(elm.options[jdx].value);
						}
					}
				} // if
				name=undefined;
			}); // forEach
			***/
			return obj;
		},

		// TODO: ComboBox might need time to process a recently input value.  This should be async?
	 	isValid: function(){
	 		// summary:
	 		//		Returns true if all of the widgets are valid

	 		// This also populate this._invalidWidgets[] array with list of invalid widgets...
	 		// TODO: put that into separate function?   It's confusing to have that as a side effect
	 		// of a method named isValid().

			this._invalidWidgets = dojo.filter(this.getDescendants(), function(widget){
				return !widget.disabled && widget.isValid && !widget.isValid();
	 		});
			return !this._invalidWidgets.length;
		},


		onValidStateChange: function(isValid){
			// summary:
			//		Stub function to connect to if you want to do something
			//		(like disable/enable a submit button) when the valid
			//		state changes on the form as a whole.
		},

		_widgetChange: function(widget){
			// summary:
			//		Connected to a widget's onChange function - update our
			//		valid state, if needed.
			var isValid = this._lastValidState;
			if(!widget || this._lastValidState === undefined){
				// We have passed a null widget, or we haven't been validated
				// yet - let's re-check all our children
				// This happens when we connect (or reconnect) our children
				isValid = this.isValid();
				if(this._lastValidState === undefined){
					// Set this so that we don't fire an onValidStateChange
					// the first time
					this._lastValidState = isValid;
				}
			}else if(widget.isValid){
				this._invalidWidgets = dojo.filter(this._invalidWidgets || [], function(w){
					return (w != widget);
				}, this);
				if(!widget.isValid() && !widget.get("disabled")){
					this._invalidWidgets.push(widget);
				}
				isValid = (this._invalidWidgets.length === 0);
			}
			if(isValid !== this._lastValidState){
				this._lastValidState = isValid;
				this.onValidStateChange(isValid);
			}
		},

		connectChildren: function(){
			// summary:
			//		Connects to the onChange function of all children to
			//		track valid state changes.  You can call this function
			//		directly, ex. in the event that you programmatically
			//		add a widget to the form *after* the form has been
			//		initialized.
			dojo.forEach(this._changeConnections, dojo.hitch(this, "disconnect"));
			var _this = this;

			// we connect to validate - so that it better reflects the states
			// of the widgets - also, we only connect if it has a validate
			// function (to avoid too many unneeded connections)
			var conns = (this._changeConnections = []);
			dojo.forEach(dojo.filter(this.getDescendants(),
				function(item){ return item.validate; }
			),
			function(widget){
				// We are interested in whenever the widget is validated - or
				// whenever the disabled attribute on that widget is changed
				conns.push(_this.connect(widget, "validate",
									dojo.hitch(_this, "_widgetChange", widget)));
				conns.push(_this.connect(widget, "_setDisabledAttr",
									dojo.hitch(_this, "_widgetChange", widget)));
			});

			// Call the widget change function to update the valid state, in
			// case something is different now.
			this._widgetChange(null);
		},

		startup: function(){
			this.inherited(arguments);
			// Initialize our valid state tracking.  Needs to be done in startup
			// because it's not guaranteed that our children are initialized
			// yet.
			this._changeConnections = [];
			this.connectChildren();
		}
	});

}

if(!dojo._hasResource["dijit.form.Form"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.Form"] = true;
dojo.provide("dijit.form.Form");





dojo.declare(
	"dijit.form.Form",
	[dijit._Widget, dijit._Templated, dijit.form._FormMixin],
	{
		// summary:
		//		Widget corresponding to HTML form tag, for validation and serialization
		//
		// example:
		//	|	<form dojoType="dijit.form.Form" id="myForm">
		//	|		Name: <input type="text" name="name" />
		//	|	</form>
		//	|	myObj = {name: "John Doe"};
		//	|	dijit.byId('myForm').set('value', myObj);
		//	|
		//	|	myObj=dijit.byId('myForm').get('value');

		// HTML <FORM> attributes

		// name: String?
		//		Name of form for scripting.
		name: "",

		// action: String?
		//		Server-side form handler.
		action: "",

		// method: String?
		//		HTTP method used to submit the form, either "GET" or "POST".
		method: "",

		// encType: String?
		//		Encoding type for the form, ex: application/x-www-form-urlencoded.
		encType: "",

		// accept-charset: String?
		//		List of supported charsets.
		"accept-charset": "",

		// accept: String?
		//		List of MIME types for file upload.
		accept: "",

		// target: String?
		//		Target frame for the document to be opened in.
		target: "",

		templateString: "<form dojoAttachPoint='containerNode' dojoAttachEvent='onreset:_onReset,onsubmit:_onSubmit' ${!nameAttrSetting}></form>",

		attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
			action: "",
			method: "",
			encType: "",
			"accept-charset": "",
			accept: "",
			target: ""
		}),

		postMixInProperties: function(){
			// Setup name=foo string to be referenced from the template (but only if a name has been specified)
			// Unfortunately we can't use attributeMap to set the name due to IE limitations, see #8660
			this.nameAttrSetting = this.name ? ("name='" + this.name + "'") : "";
			this.inherited(arguments);
		},

		execute: function(/*Object*/ formContents){
			// summary:
			//		Deprecated: use submit()
			// tags:
			//		deprecated
		},

		onExecute: function(){
			// summary:
			//		Deprecated: use onSubmit()
			// tags:
			//		deprecated
		},

		_setEncTypeAttr: function(/*String*/ value){
			this.encType = value;
			dojo.attr(this.domNode, "encType", value);
			if(dojo.isIE){ this.domNode.encoding = value; }
		},

		postCreate: function(){
			// IE tries to hide encType
			// TODO: this code should be in parser, not here.
			if(dojo.isIE && this.srcNodeRef && this.srcNodeRef.attributes){
				var item = this.srcNodeRef.attributes.getNamedItem('encType');
				if(item && !item.specified && (typeof item.value == "string")){
					this.set('encType', item.value);
				}
			}
			this.inherited(arguments);
		},

		reset: function(/*Event?*/ e){
			// summary:
			//		restores all widget values back to their init values,
			//		calls onReset() which can cancel the reset by returning false

			// create fake event so we can know if preventDefault() is called
			var faux = {
				returnValue: true, // the IE way
				preventDefault: function(){ // not IE
							this.returnValue = false;
						},
				stopPropagation: function(){}, 
				currentTarget: e ? e.target : this.domNode, 
				target: e ? e.target : this.domNode
			};
			// if return value is not exactly false, and haven't called preventDefault(), then reset
			if(!(this.onReset(faux) === false) && faux.returnValue){
				this.inherited(arguments, []);
			}
		},

		onReset: function(/*Event?*/ e){
			// summary:
			//		Callback when user resets the form. This method is intended
			//		to be over-ridden. When the `reset` method is called
			//		programmatically, the return value from `onReset` is used
			//		to compute whether or not resetting should proceed
			// tags:
			//		callback
			return true; // Boolean
		},

		_onReset: function(e){
			this.reset(e);
			dojo.stopEvent(e);
			return false;
		},

		_onSubmit: function(e){
			var fp = dijit.form.Form.prototype;
			// TODO: remove this if statement beginning with 2.0
			if(this.execute != fp.execute || this.onExecute != fp.onExecute){
				dojo.deprecated("dijit.form.Form:execute()/onExecute() are deprecated. Use onSubmit() instead.", "", "2.0");
				this.onExecute();
				this.execute(this.getValues());
			}
			if(this.onSubmit(e) === false){ // only exactly false stops submit
				dojo.stopEvent(e);
			}
		},

		onSubmit: function(/*Event?*/e){
			// summary:
			//		Callback when user submits the form.
			// description:
			//		This method is intended to be over-ridden, but by default it checks and
			//		returns the validity of form elements. When the `submit`
			//		method is called programmatically, the return value from
			//		`onSubmit` is used to compute whether or not submission
			//		should proceed
			// tags:
			//		extension

			return this.isValid(); // Boolean
		},

		submit: function(){
			// summary:
			//		programmatically submit form if and only if the `onSubmit` returns true
			if(!(this.onSubmit() === false)){
				this.containerNode.submit();
			}
		}
	}
);

}

if(!dojo._hasResource["dijit._HasDropDown"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._HasDropDown"] = true;
dojo.provide("dijit._HasDropDown");




dojo.declare("dijit._HasDropDown",
	null,
	{
		// summary:
		//		Mixin for widgets that need drop down ability.

		// _buttonNode: [protected] DomNode
		//		The button/icon/node to click to display the drop down.
		//		Can be set via a dojoAttachPoint assignment.
		//		If missing, then either focusNode or domNode (if focusNode is also missing) will be used.
		_buttonNode: null,

		// _arrowWrapperNode: [protected] DomNode
		//		Will set CSS class dijitUpArrow, dijitDownArrow, dijitRightArrow etc. on this node depending
		//		on where the drop down is set to be positioned.
		//		Can be set via a dojoAttachPoint assignment.
		//		If missing, then _buttonNode will be used.
		_arrowWrapperNode: null,

		// _popupStateNode: [protected] DomNode
		//		The node to set the popupActive class on.
		//		Can be set via a dojoAttachPoint assignment.
		//		If missing, then focusNode or _buttonNode (if focusNode is missing) will be used.
		_popupStateNode: null,

		// _aroundNode: [protected] DomNode
		//		The node to display the popup around.
		//		Can be set via a dojoAttachPoint assignment.
		//		If missing, then domNode will be used.
		_aroundNode: null,

		// dropDown: [protected] Widget
		//		The widget to display as a popup.  This widget *must* be
		//		defined before the startup function is called.
		dropDown: null,

		// autoWidth: [protected] Boolean
		//		Set to true to make the drop down at least as wide as this
		//		widget.  Set to false if the drop down should just be its
		//		default width
		autoWidth: true,

		// forceWidth: [protected] Boolean
		//		Set to true to make the drop down exactly as wide as this
		//		widget.  Overrides autoWidth.
		forceWidth: false,

		// maxHeight: [protected] Integer
		//		The max height for our dropdown.  Set to 0 for no max height.
		//		any dropdown taller than this will have scrollbars
		maxHeight: 0,

		// dropDownPosition: [const] String[]
		//		This variable controls the position of the drop down.
		//		It's an array of strings with the following values:
		//
		//			* before: places drop down to the left of the target node/widget, or to the right in
		//			  the case of RTL scripts like Hebrew and Arabic
		//			* after: places drop down to the right of the target node/widget, or to the left in
		//			  the case of RTL scripts like Hebrew and Arabic
		//			* above: drop down goes above target node
		//			* below: drop down goes below target node
		//
		//		The list is positions is tried, in order, until a position is found where the drop down fits
		//		within the viewport.
		//
		dropDownPosition: ["below","above"],

		// _stopClickEvents: Boolean
		//		When set to false, the click events will not be stopped, in
		//		case you want to use them in your subwidget
		_stopClickEvents: true,

		_onDropDownMouseDown: function(/*Event*/ e){
			// summary:
			//		Callback when the user mousedown's on the arrow icon

			if(this.disabled || this.readOnly){ return; }

			this._docHandler = this.connect(dojo.doc, "onmouseup", "_onDropDownMouseUp");

			this.toggleDropDown();
		},

		_onDropDownMouseUp: function(/*Event?*/ e){
			// summary:
			//		Callback when the user lifts their mouse after mouse down on the arrow icon.
			//		If the drop is a simple menu and the mouse is over the menu, we execute it, otherwise, we focus our
			//		dropDown node.  If the event is missing, then we are not
			//		a mouseup event.
			//
			//		This is useful for the common mouse movement pattern
			//		with native browser <select> nodes:
			//			1. mouse down on the select node (probably on the arrow)
			//			2. move mouse to a menu item while holding down the mouse button
			//			3. mouse up.  this selects the menu item as though the user had clicked it.
			if(e && this._docHandler){
				this.disconnect(this._docHandler);
			}
			var dropDown = this.dropDown, overMenu = false;

			if(e && this._opened){
				// This code deals with the corner-case when the drop down covers the original widget,
				// because it's so large.  In that case mouse-up shouldn't select a value from the menu.
				// Find out if our target is somewhere in our dropdown widget,
				// but not over our _buttonNode (the clickable node)
				var c = dojo.position(this._buttonNode, true);
				if(!(e.pageX >= c.x && e.pageX <= c.x + c.w) ||
					!(e.pageY >= c.y && e.pageY <= c.y + c.h)){
					var t = e.target;
					while(t && !overMenu){
						if(dojo.hasClass(t, "dijitPopup")){
							overMenu = true;
						}else{
							t = t.parentNode;
						}
					}
					if(overMenu){
						t = e.target;
						if(dropDown.onItemClick){
							var menuItem;
							while(t && !(menuItem = dijit.byNode(t))){
								t = t.parentNode;
							}
							if(menuItem && menuItem.onClick && menuItem.getParent){
								menuItem.getParent().onItemClick(menuItem, e);
							}
						}
						return;
					}
				}
			}
			if(this._opened && dropDown.focus){
				// Focus the dropdown widget - do it on a delay so that we
				// don't steal our own focus.
				window.setTimeout(dojo.hitch(dropDown, "focus"), 1);
			}
		},

		_onDropDownClick: function(/*Event*/ e){
			// the drop down was already opened on mousedown/keydown; just need to call stopEvent()
			if(this._stopClickEvents){
				dojo.stopEvent(e);
			}			
		},

		_setupDropdown: function(){
			// summary:
			//		set up nodes and connect our mouse and keypress events
			this._buttonNode = this._buttonNode || this.focusNode || this.domNode;
			this._popupStateNode = this._popupStateNode || this.focusNode || this._buttonNode;
			this._aroundNode = this._aroundNode || this.domNode;
			this.connect(this._buttonNode, "onmousedown", "_onDropDownMouseDown");
			this.connect(this._buttonNode, "onclick", "_onDropDownClick");
			this.connect(this._buttonNode, "onkeydown", "_onDropDownKeydown");
			this.connect(this._buttonNode, "onkeyup", "_onKey");

			// If we have a _setStateClass function (which happens when
			// we are a form widget), then we need to connect our open/close
			// functions to it
			if(this._setStateClass){
				this.connect(this, "openDropDown", "_setStateClass");
				this.connect(this, "closeDropDown", "_setStateClass");
			}

			// Add a class to the "dijitDownArrowButton" type class to _buttonNode so theme can set direction of arrow
			// based on where drop down will normally appear
			var defaultPos = {
					"after" : this.isLeftToRight() ? "Right" : "Left",
					"before" : this.isLeftToRight() ? "Left" : "Right",
					"above" : "Up",
					"below" : "Down",
					"left" : "Left",
					"right" : "Right"
			}[this.dropDownPosition[0]] || this.dropDownPosition[0] || "Down";
			dojo.addClass(this._arrowWrapperNode || this._buttonNode, "dijit" + defaultPos + "ArrowButton");
		},

		postCreate: function(){
			this._setupDropdown();
			this.inherited(arguments);
		},

		destroyDescendants: function(){
			if(this.dropDown){
				// Destroy the drop down, unless it's already been destroyed.  This can happen because
				// the drop down is a direct child of <body> even though it's logically my child.
				if(!this.dropDown._destroyed){
					this.dropDown.destroyRecursive();
				}
				delete this.dropDown;
			}
			this.inherited(arguments);
		},

		_onDropDownKeydown: function(/*Event*/ e){
			if(e.keyCode == dojo.keys.DOWN_ARROW || e.keyCode == dojo.keys.ENTER || e.keyCode == dojo.keys.SPACE){
				e.preventDefault();	// stop IE screen jump
			}
		},

		_onKey: function(/*Event*/ e){
			// summary:
			//		Callback when the user presses a key while focused on the button node

			if(this.disabled || this.readOnly){ return; }
			var d = this.dropDown;
			if(d && this._opened && d.handleKey){
				if(d.handleKey(e) === false){ return; }
			}
			if(d && this._opened && e.keyCode == dojo.keys.ESCAPE){
				this.toggleDropDown();
			}else if(d && !this._opened && 
					(e.keyCode == dojo.keys.DOWN_ARROW || e.keyCode == dojo.keys.ENTER || e.keyCode == dojo.keys.SPACE)){
				this.toggleDropDown();
				if(d.focus){
					setTimeout(dojo.hitch(d, "focus"), 1);
				}
			}
		},

		_onBlur: function(){
			// summary:
			//		Called magically when focus has shifted away from this widget and it's dropdown

			this.closeDropDown();
			// don't focus on button.  the user has explicitly focused on something else.
			this.inherited(arguments);
		},

		isLoaded: function(){
			// summary:
			//		Returns whether or not the dropdown is loaded.  This can
			//		be overridden in order to force a call to loadDropDown().
			// tags:
			//		protected

			return true;
		},

		loadDropDown: function(/* Function */ loadCallback){
			// summary:
			//		Loads the data for the dropdown, and at some point, calls
			//		the given callback
			// tags:
			//		protected

			loadCallback();
		},

		toggleDropDown: function(){
			// summary:
			//		Toggle the drop-down widget; if it is up, close it, if not, open it
			// tags:
			//		protected

			if(this.disabled || this.readOnly){ return; }
			this.focus();
			var dropDown = this.dropDown;
			if(!dropDown){ return; }
			if(!this._opened){
				// If we aren't loaded, load it first so there isn't a flicker
				if(!this.isLoaded()){
					this.loadDropDown(dojo.hitch(this, "openDropDown"));
					return;
				}else{
					this.openDropDown();
				}
			}else{
				this.closeDropDown();
			}
		},

		openDropDown: function(){
			// summary:
			//		Opens the dropdown for this widget - it returns the
			//		return value of dijit.popup.open
			// tags:
			//		protected

			var dropDown = this.dropDown;
			var ddNode = dropDown.domNode;
			var self = this;

			// Prepare our popup's height and honor maxHeight if it exists.

			// TODO: isn't maxHeight dependent on the return value from dijit.popup.open(),
			// ie, dependent on how much space is available (BK)

			if(!this._preparedNode){
				dijit.popup.moveOffScreen(ddNode);
				this._preparedNode = true;			
				// Check if we have explicitly set width and height on the dropdown widget dom node
				if(ddNode.style.width){
					this._explicitDDWidth = true;
				}
				if(ddNode.style.height){
					this._explicitDDHeight = true;
				}
			}

			// Code for resizing dropdown (height limitation, or increasing width to match my width)
			if(this.maxHeight || this.forceWidth || this.autoWidth){
				var myStyle = {
					display: "",
					visibility: "hidden"
				};
				if(!this._explicitDDWidth){
					myStyle.width = "";
				}
				if(!this._explicitDDHeight){
					myStyle.height = "";
				}
				dojo.style(ddNode, myStyle);
				
				// Get size of drop down, and determine if vertical scroll bar needed
				var mb = dojo.marginBox(ddNode);
				var overHeight = (this.maxHeight && mb.h > this.maxHeight);
				dojo.style(ddNode, {
					overflowX: "hidden",
					overflowY: overHeight ? "auto" : "hidden"
				});
				if(overHeight){
					mb.h = this.maxHeight;
					if("w" in mb){
						mb.w += 16;	// room for vertical scrollbar
					}
				}else{
					delete mb.h;
				}
				delete mb.t;
				delete mb.l;

				// Adjust dropdown width to match or be larger than my width
				if(this.forceWidth){
					mb.w = this.domNode.offsetWidth;
				}else if(this.autoWidth){
					mb.w = Math.max(mb.w, this.domNode.offsetWidth);
				}else{
					delete mb.w;
				}
				
				// And finally, resize the dropdown to calculated height and width
				if(dojo.isFunction(dropDown.resize)){
					dropDown.resize(mb);
				}else{
					dojo.marginBox(ddNode, mb);
				}
			}

			var retVal = dijit.popup.open({
				parent: this,
				popup: dropDown,
				around: this._aroundNode,
				orient: dijit.getPopupAroundAlignment((this.dropDownPosition && this.dropDownPosition.length) ? this.dropDownPosition : ["below"],this.isLeftToRight()),
				onExecute: function(){
					self.closeDropDown(true);
				},
				onCancel: function(){
					self.closeDropDown(true);
				},
				onClose: function(){
					dojo.attr(self._popupStateNode, "popupActive", false);
					dojo.removeClass(self._popupStateNode, "dijitHasDropDownOpen");
					self._opened = false;
					self.state = "";
				}
			});
			dojo.attr(this._popupStateNode, "popupActive", "true");
			dojo.addClass(self._popupStateNode, "dijitHasDropDownOpen");
			this._opened=true;
			this.state="Opened";
			// TODO: set this.checked and call setStateClass(), to affect button look while drop down is shown
			return retVal;
		},

		closeDropDown: function(/*Boolean*/ focus){
			// summary:
			//		Closes the drop down on this widget
			// tags:
			//		protected

			if(this._opened){
				if(focus){ this.focus(); }
				dijit.popup.close(this.dropDown);
				this._opened = false;
				this.state = "";
			}
		}

	}
);

}

if(!dojo._hasResource["dijit.form.Button"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.Button"] = true;
dojo.provide("dijit.form.Button");





dojo.declare("dijit.form.Button",
	dijit.form._FormWidget,
	{
	// summary:
	//		Basically the same thing as a normal HTML button, but with special styling.
	// description:
	//		Buttons can display a label, an icon, or both.
	//		A label should always be specified (through innerHTML) or the label
	//		attribute.  It can be hidden via showLabel=false.
	// example:
	// |	<button dojoType="dijit.form.Button" onClick="...">Hello world</button>
	//
	// example:
	// |	var button1 = new dijit.form.Button({label: "hello world", onClick: foo});
	// |	dojo.body().appendChild(button1.domNode);

	// label: HTML String
	//		Text to display in button.
	//		If the label is hidden (showLabel=false) then and no title has
	//		been specified, then label is also set as title attribute of icon.
	label: "",

	// showLabel: Boolean
	//		Set this to true to hide the label text and display only the icon.
	//		(If showLabel=false then iconClass must be specified.)
	//		Especially useful for toolbars.
	//		If showLabel=true, the label will become the title (a.k.a. tooltip/hint) of the icon.
	//
	//		The exception case is for computers in high-contrast mode, where the label
	//		will still be displayed, since the icon doesn't appear.
	showLabel: true,

	// iconClass: String
	//		Class to apply to DOMNode in button to make it display an icon
	iconClass: "",

	// type: String
	//		Defines the type of button.  "button", "submit", or "reset".
	type: "button",

	baseClass: "dijitButton",

	templateString: dojo.cache("dijit.form", "templates/Button.html", "<span class=\"dijit dijitReset dijitInline\"\n\t><span class=\"dijitReset dijitInline dijitButtonNode\"\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode,focusNode\"\n\t\t\twaiRole=\"button\" waiState=\"labelledby-${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\"></span\n\t\t\t><span class=\"dijitReset dijitToggleButtonIconChar\">&#x25CF;</span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t\tdojoAttachPoint=\"containerNode\"\n\t\t\t></span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),

	attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
		value: "valueNode",
		iconClass: { node: "iconNode", type: "class" }
	}),


	_onClick: function(/*Event*/ e){
		// summary:
		//		Internal function to handle click actions
		if(this.disabled){
			return false;
		}
		this._clicked(); // widget click actions
		return this.onClick(e); // user click actions
	},

	_onButtonClick: function(/*Event*/ e){
		// summary:
		//		Handler when the user activates the button portion.
		if(this._onClick(e) === false){ // returning nothing is same as true
			e.preventDefault(); // needed for checkbox
		}else if(this.type == "submit" && !(this.valueNode||this.focusNode).form){ // see if a nonform widget needs to be signalled
			for(var node=this.domNode; node.parentNode/*#5935*/; node=node.parentNode){
				var widget=dijit.byNode(node);
				if(widget && typeof widget._onSubmit == "function"){
					widget._onSubmit(e);
					break;
				}
			}
		}else if(this.valueNode){
			this.valueNode.click();
			e.preventDefault(); // cancel BUTTON click and continue with hidden INPUT click
		}
	},

	_fillContent: function(/*DomNode*/ source){
		// Overrides _Templated._fillContent().
		// If button label is specified as srcNodeRef.innerHTML rather than
		// this.params.label, handle it here.
		if(source && (!this.params || !("label" in this.params))){
			this.set('label', source.innerHTML);
		}
	},

	postCreate: function(){
		dojo.setSelectable(this.focusNode, false);
		this.inherited(arguments);
	},

	_setShowLabelAttr: function(val){
		if(this.containerNode){
			dojo.toggleClass(this.containerNode, "dijitDisplayNone", !val);
		}
		this.showLabel = val;
	},

	onClick: function(/*Event*/ e){
		// summary:
		//		Callback for when button is clicked.
		//		If type="submit", return true to perform submit, or false to cancel it.
		// type:
		//		callback
		return true;		// Boolean
	},

	_clicked: function(/*Event*/ e){
		// summary:
		//		Internal overridable function for when the button is clicked
	},

	setLabel: function(/*String*/ content){
		// summary:
		//		Deprecated.  Use set('label', ...) instead.
		dojo.deprecated("dijit.form.Button.setLabel() is deprecated.  Use set('label', ...) instead.", "", "2.0");
		this.set("label", content);
	},

	_setLabelAttr: function(/*String*/ content){
		// summary:
		//		Hook for attr('label', ...) to work.
		// description:
		//		Set the label (text) of the button; takes an HTML string.
		this.containerNode.innerHTML = this.label = content;
		if(this.showLabel == false && !this.params.title){
			this.titleNode.title = dojo.trim(this.containerNode.innerText || this.containerNode.textContent || '');
		}
	}
});


dojo.declare("dijit.form.DropDownButton", [dijit.form.Button, dijit._Container, dijit._HasDropDown], {
	// summary:
	//		A button with a drop down
	//
	// example:
	// |	<button dojoType="dijit.form.DropDownButton" label="Hello world">
	// |		<div dojotype="dijit.Menu">...</div>
	// |	</button>
	//
	// example:
	// |	var button1 = new dijit.form.DropDownButton({ label: "hi", dropDown: new dijit.Menu(...) });
	// |	dojo.body().appendChild(button1);
	//

	baseClass : "dijitDropDownButton",

	templateString: dojo.cache("dijit.form", "templates/DropDownButton.html", "<span class=\"dijit dijitReset dijitInline\"\n\t><span class='dijitReset dijitInline dijitButtonNode'\n\t\tdojoAttachEvent=\"ondijitclick:_onButtonClick\" dojoAttachPoint=\"_buttonNode\"\n\t\t><span class=\"dijitReset dijitStretch dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"focusNode,titleNode,_arrowWrapperNode\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true,labelledby-${id}_label\"\n\t\t\t><span class=\"dijitReset dijitInline dijitIcon\"\n\t\t\t\tdojoAttachPoint=\"iconNode\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"\n\t\t\t\tdojoAttachPoint=\"containerNode,_popupStateNode\"\n\t\t\t\tid=\"${id}_label\"\n\t\t\t></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonInner\"></span\n\t\t\t><span class=\"dijitReset dijitInline dijitArrowButtonChar\">&#9660;</span\n\t\t></span\n\t></span\n\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" class=\"dijitOffScreen\"\n\t\tdojoAttachPoint=\"valueNode\"\n/></span>\n"),

	_fillContent: function(){
		// Overrides Button._fillContent().
		//
		// My inner HTML contains both the button contents and a drop down widget, like
		// <DropDownButton>  <span>push me</span>  <Menu> ... </Menu> </DropDownButton>
		// The first node is assumed to be the button content. The widget is the popup.

		if(this.srcNodeRef){ // programatically created buttons might not define srcNodeRef
			//FIXME: figure out how to filter out the widget and use all remaining nodes as button
			//	content, not just nodes[0]
			var nodes = dojo.query("*", this.srcNodeRef);
			dijit.form.DropDownButton.superclass._fillContent.call(this, nodes[0]);

			// save pointer to srcNode so we can grab the drop down widget after it's instantiated
			this.dropDownContainer = this.srcNodeRef;
		}
	},

	startup: function(){
		if(this._started){ return; }

		// the child widget from srcNodeRef is the dropdown widget.  Insert it in the page DOM,
		// make it invisible, and store a reference to pass to the popup code.
		if(!this.dropDown){
			var dropDownNode = dojo.query("[widgetId]", this.dropDownContainer)[0];
			this.dropDown = dijit.byNode(dropDownNode);
			delete this.dropDownContainer;
		}
		dijit.popup.moveOffScreen(this.dropDown.domNode);

		this.inherited(arguments);
	},

	isLoaded: function(){
		// Returns whether or not we are loaded - if our dropdown has an href,
		// then we want to check that.
		var dropDown = this.dropDown;
		return (!dropDown.href || dropDown.isLoaded);
	},

	loadDropDown: function(){
		// Loads our dropdown
		var dropDown = this.dropDown;
		if(!dropDown){ return; }
		if(!this.isLoaded()){
			var handler = dojo.connect(dropDown, "onLoad", this, function(){
				dojo.disconnect(handler);
				this.openDropDown();
			});
			dropDown.refresh();
		}else{
			this.openDropDown();
		}
	},

	isFocusable: function(){
		// Overridden so that focus is handled by the _HasDropDown mixin, not by
		// the _FormWidget mixin.
		return this.inherited(arguments) && !this._mouseDown;
	}
});

dojo.declare("dijit.form.ComboButton", dijit.form.DropDownButton, {
	// summary:
	//		A combination button and drop-down button.
	//		Users can click one side to "press" the button, or click an arrow
	//		icon to display the drop down.
	//
	// example:
	// |	<button dojoType="dijit.form.ComboButton" onClick="...">
	// |		<span>Hello world</span>
	// |		<div dojoType="dijit.Menu">...</div>
	// |	</button>
	//
	// example:
	// |	var button1 = new dijit.form.ComboButton({label: "hello world", onClick: foo, dropDown: "myMenu"});
	// |	dojo.body().appendChild(button1.domNode);
	//

	templateString: dojo.cache("dijit.form", "templates/ComboButton.html", "<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tcellspacing='0' cellpadding='0' waiRole=\"presentation\"\n\t><tbody waiRole=\"presentation\"><tr waiRole=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonNode\" dojoAttachPoint=\"buttonNode\" dojoAttachEvent=\"ondijitclick:_onButtonClick,onkeypress:_onButtonKeyPress\"\n\t\t><div id=\"${id}_button\" class=\"dijitReset dijitButtonContents\"\n\t\t\tdojoAttachPoint=\"titleNode\"\n\t\t\twaiRole=\"button\" waiState=\"labelledby-${id}_label\"\n\t\t\t><div class=\"dijitReset dijitInline dijitIcon\" dojoAttachPoint=\"iconNode\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitInline dijitButtonText\" id=\"${id}_label\" dojoAttachPoint=\"containerNode\" waiRole=\"presentation\"></div\n\t\t></div\n\t\t></td\n\t\t><td id=\"${id}_arrow\" class='dijitReset dijitRight dijitButtonNode dijitArrowButton'\n\t\t\tdojoAttachPoint=\"_popupStateNode,focusNode,_buttonNode\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onArrowKeyPress\"\n\t\t\ttitle=\"${optionsTitle}\"\n\t\t\twaiRole=\"button\" waiState=\"haspopup-true\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" waiRole=\"presentation\">&#9660;</div\n\t\t></td\n\t\t><td style=\"display:none !important;\"\n\t\t\t><input ${!nameAttrSetting} type=\"${type}\" value=\"${value}\" dojoAttachPoint=\"valueNode\"\n\t\t/></td></tr></tbody\n></table>\n"),

	attributeMap: dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap), {
		id: "",
		tabIndex: ["focusNode", "titleNode"],
		title: "titleNode"
	}),

	// optionsTitle: String
	//		Text that describes the options menu (accessibility)
	optionsTitle: "",

	baseClass: "dijitComboButton",

	// Set classes like dijitButtonContentsHover or dijitArrowButtonActive depending on
	// mouse action over specified node
	cssStateNodes: {
		"buttonNode": "dijitButtonNode",
		"titleNode": "dijitButtonContents",
		"_popupStateNode": "dijitDownArrowButton"
	},

	_focusedNode: null,

	_onButtonKeyPress: function(/*Event*/ evt){
		// summary:
		//		Handler for right arrow key when focus is on left part of button
		if(evt.charOrCode == dojo.keys[this.isLeftToRight() ? "RIGHT_ARROW" : "LEFT_ARROW"]){
			dijit.focus(this._popupStateNode);
			dojo.stopEvent(evt);
		}
	},

	_onArrowKeyPress: function(/*Event*/ evt){
		// summary:
		//		Handler for left arrow key when focus is on right part of button
		if(evt.charOrCode == dojo.keys[this.isLeftToRight() ? "LEFT_ARROW" : "RIGHT_ARROW"]){
			dijit.focus(this.titleNode);
			dojo.stopEvent(evt);
		}
	},
	
	focus: function(/*String*/ position){
		// summary:
		//		Focuses this widget to according to position, if specified,
		//		otherwise on arrow node
		// position:
		//		"start" or "end"
		
		dijit.focus(position == "start" ? this.titleNode : this._popupStateNode);
	}
});

dojo.declare("dijit.form.ToggleButton", dijit.form.Button, {
	// summary:
	//		A button that can be in two states (checked or not).
	//		Can be base class for things like tabs or checkbox or radio buttons

	baseClass: "dijitToggleButton",

	// checked: Boolean
	//		Corresponds to the native HTML <input> element's attribute.
	//		In markup, specified as "checked='checked'" or just "checked".
	//		True if the button is depressed, or the checkbox is checked,
	//		or the radio button is selected, etc.
	checked: false,

	attributeMap: dojo.mixin(dojo.clone(dijit.form.Button.prototype.attributeMap), {
		checked:"focusNode"
	}),

	_clicked: function(/*Event*/ evt){
		this.set('checked', !this.checked);
	},

	_setCheckedAttr: function(/*Boolean*/ value, /* Boolean? */ priorityChange){
		this.checked = value;
		dojo.attr(this.focusNode || this.domNode, "checked", value);
		dijit.setWaiState(this.focusNode || this.domNode, "pressed", value);
		this._handleOnChange(value, priorityChange);
	},

	setChecked: function(/*Boolean*/ checked){
		// summary:
		//		Deprecated.   Use set('checked', true/false) instead.
		dojo.deprecated("setChecked("+checked+") is deprecated. Use set('checked',"+checked+") instead.", "", "2.0");
		this.set('checked', checked);
	},

	reset: function(){
		// summary:
		//		Reset the widget's value to what it was at initialization time

		this._hasBeenBlurred = false;

		// set checked state to original setting
		this.set('checked', this.params.checked || false);
	}
});

}

if(!dojo._hasResource['com.sixnet.services.core.dashWidgetEmbedded']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.core.dashWidgetEmbedded'] = true;

dojo.provide('com.sixnet.services.core.dashWidgetEmbedded');

dojo.declare('com.sixnet.services.core.dashWidgetEmbedded', [dijit._Widget], {
	constructor: function(){
		var splitClass = this.declaredClass.split('.');
		var splitlength = splitClass.length;
		this.iconUrl = 'dojo/'.concat( splitClass.slice(0,-1).join('/'), '/templates/images/');
		this.templateUrl = 'dojo/'.concat( splitClass.slice(0,-1).join('/'), '/templates/');
		this.moduleUrl = 'dojo/'.concat( splitClass.slice(0,-1).join('/'), '/');
	},
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.containerNode = this.domNode;
		this.connect( this, "resize", "onResize");		
	},
	cleanPath: function(path, trim){
		var parts = path.split('/');
		var pathParts = [];
		if( !trim) trim = 0;
		parts = parts.slice(0, parts.length - trim);
		dojo.forEach(parts, function(part){ 
			if( part == '..'){ pathParts.pop(); return ; }
			pathParts.push(part);
		});
		pathParts.pop();
		return pathParts.join('/');
	},
	onResize: function(){
		try{
			var newsize = { w: this.domNode.parentNode.offsetWidth,
					h: this.domNode.parentNode.offsetHeight  };
			if( newsize.w == 0) return;
			dojo.forEach( this.getChildren(), function(child){
				if( child.resize){
					child.resize();
				}
			});
		}catch(e){
			//_sixnet_framework.log(3, 'onResize', e);
		}
	},
	destroyRecursive: function(preserveDom){
		this.containerNode = null;
		//_sixnet_framework.log(3, 'in dashWidgetEmbedded destroyRecursive', this);
		this.inherited("destroyRecursive", arguments);	
	}
});

}

if(!dojo._hasResource["com.sixnet.services.core.data.formatters"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.core.data.formatters"] = true;


dojo.provide("com.sixnet.services.core.data.formatters");
dojo.declare("com.sixnet.services.core.data.formatters", [com.sixnet.services.core.dashWidgetEmbedded], {
	grid: false,
	store: null,
	_widgets: [],
	_paneList: null,
	getContentPane: function(name, init){
		if( null == this._paneList) this._paneList = {};
		if( init || ( 'undefined' == typeof(this._paneList[name]))){
			this._paneList[name] = new dijit.layout.ContentPane({content:''}); 
		}
		return this._paneList[name];
	},
	constructor: function(kwArgs){
		this.store = kwArgs.store;
		this._widgets = [];
	},
	setGrid: function(grid){
		this.grid = grid;
	},
	invalidateCache: function(){
		// Called when we need to clean our cache and destroy our
		// widgets.
		dojo.forEach(this._widgets, function(w){
			if(w && w.destroy){
				w.destroy();
			}
		});
		this._widgets = [];
	},
	timeToDate: function(value,idx){
		var time = '';
		var adate = new Date();
		if(value != 0){
			adate.setTime(value * 1000);
			return dojo.date.locale.format(adate,{datePattern:'M/d/y '});
		}else{
			//  you need to know how to make sort work with formATTERS.
			var cp = new dijit.layout.ContentPane({content:"Never", value:value});
			return cp;
		}
	}
});
		
/* examples from dojox
fmtABBR: function(value, idx){
				if(value == "continent"){
					return "BIG";
				}else if(value == "country"){
					return "MID";
				}else if(value == "city"){
					return "SML";
				}
				return "???";
			},
			fmtWidget: function(value, idx){
				if(!this._widgets[idx]){
					this._widgets[idx] = new dijit.form.TextBox({value: value, disabled: true});
				}
				return this._widgets[idx];
			},
			fmtValue: function(value, idx){
				return value;
			},
			fmtBool: function(value, idx){
				return (value == "country");
			},
			fmtInt: function(value, idx){
				return dojo.filter(["continent", "country", "city"], function(i){ return i == value; })[0]||null;
			},
			fmtChildren: function(value, idx){
				return dojo.map(value, function(i){
					return this.store.getLabel(i);
				}, this).join(", ") || "&nbsp;";
			},
			fmtItem: function(value, idx){
				if(!this.store.isItem(value)){
					return "&nbsp;";
				}
				var d = new dojo.Deferred();
				var fx = function(items){
					if(items.length){
						d.callback(this.store.getLabel(items[0]))
					}else{
						d.callback("&nbsp;");
					}
				};
				window.setTimeout(dojo.hitch(this, function(){
					this.store.fetch({query: {children: value}, onComplete: fx, onError: function(e){d.errback(e)}, scope: this});
				}), 5000);
				return d;
			}

*/

}

if(!dojo._hasResource["dojo.regexp"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.regexp"] = true;
dojo.provide("dojo.regexp");

/*=====
dojo.regexp = {
	// summary: Regular expressions and Builder resources
};
=====*/

dojo.regexp.escapeString = function(/*String*/str, /*String?*/except){
	//	summary:
	//		Adds escape sequences for special characters in regular expressions
	// except:
	//		a String with special characters to be left unescaped

	return str.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, function(ch){
		if(except && except.indexOf(ch) != -1){
			return ch;
		}
		return "\\" + ch;
	}); // String
}

dojo.regexp.buildGroupRE = function(/*Object|Array*/arr, /*Function*/re, /*Boolean?*/nonCapture){
	//	summary:
	//		Builds a regular expression that groups subexpressions
	//	description:
	//		A utility function used by some of the RE generators. The
	//		subexpressions are constructed by the function, re, in the second
	//		parameter.  re builds one subexpression for each elem in the array
	//		a, in the first parameter. Returns a string for a regular
	//		expression that groups all the subexpressions.
	// arr:
	//		A single value or an array of values.
	// re:
	//		A function. Takes one parameter and converts it to a regular
	//		expression. 
	// nonCapture:
	//		If true, uses non-capturing match, otherwise matches are retained
	//		by regular expression. Defaults to false

	// case 1: a is a single value.
	if(!(arr instanceof Array)){
		return re(arr); // String
	}

	// case 2: a is an array
	var b = [];
	for(var i = 0; i < arr.length; i++){
		// convert each elem to a RE
		b.push(re(arr[i]));
	}

	 // join the REs as alternatives in a RE group.
	return dojo.regexp.group(b.join("|"), nonCapture); // String
}

dojo.regexp.group = function(/*String*/expression, /*Boolean?*/nonCapture){
	// summary:
	//		adds group match to expression
	// nonCapture:
	//		If true, uses non-capturing match, otherwise matches are retained
	//		by regular expression. 
	return "(" + (nonCapture ? "?:":"") + expression + ")"; // String
}

}

if(!dojo._hasResource["dojo.cookie"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.cookie"] = true;
dojo.provide("dojo.cookie");



/*=====
dojo.__cookieProps = function(){
	//	expires: Date|String|Number?
	//		If a number, the number of days from today at which the cookie
	//		will expire. If a date, the date past which the cookie will expire.
	//		If expires is in the past, the cookie will be deleted.
	//		If expires is omitted or is 0, the cookie will expire when the browser closes. << FIXME: 0 seems to disappear right away? FF3.
	//	path: String?
	//		The path to use for the cookie.
	//	domain: String?
	//		The domain to use for the cookie.
	//	secure: Boolean?
	//		Whether to only send the cookie on secure connections
	this.expires = expires;
	this.path = path;
	this.domain = domain;
	this.secure = secure;
}
=====*/


dojo.cookie = function(/*String*/name, /*String?*/value, /*dojo.__cookieProps?*/props){
	//	summary: 
	//		Get or set a cookie.
	//	description:
	// 		If one argument is passed, returns the value of the cookie
	// 		For two or more arguments, acts as a setter.
	//	name:
	//		Name of the cookie
	//	value:
	//		Value for the cookie
	//	props: 
	//		Properties for the cookie
	//	example:
	//		set a cookie with the JSON-serialized contents of an object which
	//		will expire 5 days from now:
	//	|	dojo.cookie("configObj", dojo.toJson(config), { expires: 5 });
	//	
	//	example:
	//		de-serialize a cookie back into a JavaScript object:
	//	|	var config = dojo.fromJson(dojo.cookie("configObj"));
	//	
	//	example:
	//		delete a cookie:
	//	|	dojo.cookie("configObj", null, {expires: -1});
	var c = document.cookie;
	if(arguments.length == 1){
		var matches = c.match(new RegExp("(?:^|; )" + dojo.regexp.escapeString(name) + "=([^;]*)"));
		return matches ? decodeURIComponent(matches[1]) : undefined; // String or undefined
	}else{
		props = props || {};
// FIXME: expires=0 seems to disappear right away, not on close? (FF3)  Change docs?
		var exp = props.expires;
		if(typeof exp == "number"){ 
			var d = new Date();
			d.setTime(d.getTime() + exp*24*60*60*1000);
			exp = props.expires = d;
		}
		if(exp && exp.toUTCString){ props.expires = exp.toUTCString(); }

		value = encodeURIComponent(value);
		var updatedCookie = name + "=" + value, propName;
		for(propName in props){
			updatedCookie += "; " + propName;
			var propValue = props[propName];
			if(propValue !== true){ updatedCookie += "=" + propValue; }
		}
		document.cookie = updatedCookie;
	}
};

dojo.cookie.isSupported = function(){
	//	summary:
	//		Use to determine if the current browser supports cookies or not.
	//		
	//		Returns true if user allows cookies.
	//		Returns false if user doesn't allow cookies.

	if(!("cookieEnabled" in navigator)){
		this("__djCookieTest__", "CookiesAllowed");
		navigator.cookieEnabled = this("__djCookieTest__") == "CookiesAllowed";
		if(navigator.cookieEnabled){
			this("__djCookieTest__", "", {expires: -1});
		}
	}
	return navigator.cookieEnabled;
};

}

if(!dojo._hasResource["dijit.layout.BorderContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.BorderContainer"] = true;
dojo.provide("dijit.layout.BorderContainer");




dojo.declare(
	"dijit.layout.BorderContainer",
	dijit.layout._LayoutWidget,
{
	// summary:
	//		Provides layout in up to 5 regions, a mandatory center with optional borders along its 4 sides.
	//
	// description:
	//		A BorderContainer is a box with a specified size, such as style="width: 500px; height: 500px;",
	//		that contains a child widget marked region="center" and optionally children widgets marked
	//		region equal to "top", "bottom", "leading", "trailing", "left" or "right".
	//		Children along the edges will be laid out according to width or height dimensions and may
	//		include optional splitters (splitter="true") to make them resizable by the user.  The remaining
	//		space is designated for the center region.
	//
	//		NOTE: Splitters must not be more than 50 pixels in width.
	//
	//		The outer size must be specified on the BorderContainer node.  Width must be specified for the sides
	//		and height for the top and bottom, respectively.  No dimensions should be specified on the center;
	//		it will fill the remaining space.  Regions named "leading" and "trailing" may be used just like
	//		"left" and "right" except that they will be reversed in right-to-left environments.
	//
	// example:
	// |	<div dojoType="dijit.layout.BorderContainer" design="sidebar" gutters="false"
	// |            style="width: 400px; height: 300px;">
	// |		<div dojoType="ContentPane" region="top">header text</div>
	// |		<div dojoType="ContentPane" region="right" splitter="true" style="width: 200px;">table of contents</div>
	// |		<div dojoType="ContentPane" region="center">client area</div>
	// |	</div>

	// design: String
	//		Which design is used for the layout:
	//			- "headline" (default) where the top and bottom extend
	//				the full width of the container
	//			- "sidebar" where the left and right sides extend from top to bottom.
	design: "headline",

	// gutters: Boolean
	//		Give each pane a border and margin.
	//		Margin determined by domNode.paddingLeft.
	//		When false, only resizable panes have a gutter (i.e. draggable splitter) for resizing.
	gutters: true,

	// liveSplitters: Boolean
	//		Specifies whether splitters resize as you drag (true) or only upon mouseup (false)
	liveSplitters: true,

	// persist: Boolean
	//		Save splitter positions in a cookie.
	persist: false,

	baseClass: "dijitBorderContainer",

	// _splitterClass: String
	// 		Optional hook to override the default Splitter widget used by BorderContainer
	_splitterClass: "dijit.layout._Splitter",

	postMixInProperties: function(){
		// change class name to indicate that BorderContainer is being used purely for
		// layout (like LayoutContainer) rather than for pretty formatting.
		if(!this.gutters){
			this.baseClass += "NoGutter";
		}
		this.inherited(arguments);
	},

	postCreate: function(){
		this.inherited(arguments);

		this._splitters = {};
		this._splitterThickness = {};
	},

	startup: function(){
		if(this._started){ return; }
		dojo.forEach(this.getChildren(), this._setupChild, this);
		this.inherited(arguments);
	},

	_setupChild: function(/*dijit._Widget*/ child){
		// Override _LayoutWidget._setupChild().

		var region = child.region;
		if(region){
			this.inherited(arguments);

			dojo.addClass(child.domNode, this.baseClass+"Pane");

			var ltr = this.isLeftToRight();
			if(region == "leading"){ region = ltr ? "left" : "right"; }
			if(region == "trailing"){ region = ltr ? "right" : "left"; }

			//FIXME: redundant?
			this["_"+region] = child.domNode;
			this["_"+region+"Widget"] = child;

			// Create draggable splitter for resizing pane,
			// or alternately if splitter=false but BorderContainer.gutters=true then
			// insert dummy div just for spacing
			if((child.splitter || this.gutters) && !this._splitters[region]){
				var _Splitter = dojo.getObject(child.splitter ? this._splitterClass : "dijit.layout._Gutter");
				var splitter = new _Splitter({
					id: child.id + "_splitter",
					container: this,
					child: child,
					region: region,
					live: this.liveSplitters
				});
				splitter.isSplitter = true;
				this._splitters[region] = splitter.domNode;
				dojo.place(this._splitters[region], child.domNode, "after");

				// Splitters arent added as Contained children, so we need to call startup explicitly
				splitter.startup();
			}
			child.region = region;
		}
	},

	_computeSplitterThickness: function(region){
		this._splitterThickness[region] = this._splitterThickness[region] ||
			dojo.marginBox(this._splitters[region])[(/top|bottom/.test(region) ? 'h' : 'w')];
	},

	layout: function(){
		// Implement _LayoutWidget.layout() virtual method.
		for(var region in this._splitters){ this._computeSplitterThickness(region); }
		this._layoutChildren();
	},

	addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
		// Override _LayoutWidget.addChild().
		this.inherited(arguments);
		if(this._started){
			this.layout(); //OPT
		}
	},

	removeChild: function(/*dijit._Widget*/ child){
		// Override _LayoutWidget.removeChild().
		var region = child.region;
		var splitter = this._splitters[region];
		if(splitter){
			dijit.byNode(splitter).destroy();
			delete this._splitters[region];
			delete this._splitterThickness[region];
		}
		this.inherited(arguments);
		delete this["_"+region];
		delete this["_" +region+"Widget"];
		if(this._started){
			this._layoutChildren();
		}
		dojo.removeClass(child.domNode, this.baseClass+"Pane");
	},

	getChildren: function(){
		// Override _LayoutWidget.getChildren() to only return real children, not the splitters.
		return dojo.filter(this.inherited(arguments), function(widget){
			return !widget.isSplitter;
		});
	},

	getSplitter: function(/*String*/region){
		// summary:
		//		Returns the widget responsible for rendering the splitter associated with region
		var splitter = this._splitters[region];
		return splitter ? dijit.byNode(splitter) : null;
	},

	resize: function(newSize, currentSize){
		// Overrides _LayoutWidget.resize().

		// resetting potential padding to 0px to provide support for 100% width/height + padding
		// TODO: this hack doesn't respect the box model and is a temporary fix
		if(!this.cs || !this.pe){
			var node = this.domNode;
			this.cs = dojo.getComputedStyle(node);
			this.pe = dojo._getPadExtents(node, this.cs);
			this.pe.r = dojo._toPixelValue(node, this.cs.paddingRight);
			this.pe.b = dojo._toPixelValue(node, this.cs.paddingBottom);

			dojo.style(node, "padding", "0px");
		}

		this.inherited(arguments);
	},

	_layoutChildren: function(/*String?*/changedRegion, /*Number?*/ changedRegionSize){
		// summary:
		//		This is the main routine for setting size/position of each child.
		// description:
		//		With no arguments, measures the height of top/bottom panes, the width
		//		of left/right panes, and then sizes all panes accordingly.
		//
		//		With changedRegion specified (as "left", "top", "bottom", or "right"),
		//		it changes that region's width/height to changedRegionSize and
		//		then resizes other regions that were affected.
		// changedRegion:
		//		The region should be changed because splitter was dragged.
		//		"left", "right", "top", or "bottom".
		// changedRegionSize:
		//		The new width/height (in pixels) to make changedRegion

		if(!this._borderBox || !this._borderBox.h){
			// We are currently hidden, or we haven't been sized by our parent yet.
			// Abort.   Someone will resize us later.
			return;
		}

		var sidebarLayout = (this.design == "sidebar");
		var topHeight = 0, bottomHeight = 0, leftWidth = 0, rightWidth = 0;
		var topStyle = {}, leftStyle = {}, rightStyle = {}, bottomStyle = {},
			centerStyle = (this._center && this._center.style) || {};

		var changedSide = /left|right/.test(changedRegion);

		var layoutSides = !changedRegion || (!changedSide && !sidebarLayout);
		var layoutTopBottom = !changedRegion || (changedSide && sidebarLayout);

		// Ask browser for width/height of side panes.
		// Would be nice to cache this but height can change according to width
		// (because words wrap around).  I don't think width will ever change though
		// (except when the user drags a splitter).
		if(this._top){
			topStyle = (changedRegion == "top" || layoutTopBottom) && this._top.style;
			topHeight = changedRegion == "top" ? changedRegionSize : dojo.marginBox(this._top).h;
		}
		if(this._left){
			leftStyle = (changedRegion == "left" || layoutSides) && this._left.style;
			leftWidth = changedRegion == "left" ? changedRegionSize : dojo.marginBox(this._left).w;
		}
		if(this._right){
			rightStyle = (changedRegion == "right" || layoutSides) && this._right.style;
			rightWidth = changedRegion == "right" ? changedRegionSize : dojo.marginBox(this._right).w;
		}
		if(this._bottom){
			bottomStyle = (changedRegion == "bottom" || layoutTopBottom) && this._bottom.style;
			bottomHeight = changedRegion == "bottom" ? changedRegionSize : dojo.marginBox(this._bottom).h;
		}

		var splitters = this._splitters;
		var topSplitter = splitters.top, bottomSplitter = splitters.bottom,
			leftSplitter = splitters.left, rightSplitter = splitters.right;
		var splitterThickness = this._splitterThickness;
		var topSplitterThickness = splitterThickness.top || 0,
			leftSplitterThickness = splitterThickness.left || 0,
			rightSplitterThickness = splitterThickness.right || 0,
			bottomSplitterThickness = splitterThickness.bottom || 0;

		// Check for race condition where CSS hasn't finished loading, so
		// the splitter width == the viewport width (#5824)
		if(leftSplitterThickness > 50 || rightSplitterThickness > 50){
			setTimeout(dojo.hitch(this, function(){
				// Results are invalid.  Clear them out.
				this._splitterThickness = {};

				for(var region in this._splitters){
					this._computeSplitterThickness(region);
				}
				this._layoutChildren();
			}), 50);
			return false;
		}

		var pe = this.pe;

		var splitterBounds = {
			left: (sidebarLayout ? leftWidth + leftSplitterThickness: 0) + pe.l + "px",
			right: (sidebarLayout ? rightWidth + rightSplitterThickness: 0) + pe.r + "px"
		};

		if(topSplitter){
			dojo.mixin(topSplitter.style, splitterBounds);
			topSplitter.style.top = topHeight + pe.t + "px";
		}

		if(bottomSplitter){
			dojo.mixin(bottomSplitter.style, splitterBounds);
			bottomSplitter.style.bottom = bottomHeight + pe.b + "px";
		}

		splitterBounds = {
			top: (sidebarLayout ? 0 : topHeight + topSplitterThickness) + pe.t + "px",
			bottom: (sidebarLayout ? 0 : bottomHeight + bottomSplitterThickness) + pe.b + "px"
		};

		if(leftSplitter){
			dojo.mixin(leftSplitter.style, splitterBounds);
			leftSplitter.style.left = leftWidth + pe.l + "px";
		}

		if(rightSplitter){
			dojo.mixin(rightSplitter.style, splitterBounds);
			rightSplitter.style.right = rightWidth + pe.r +	"px";
		}

		dojo.mixin(centerStyle, {
			top: pe.t + topHeight + topSplitterThickness + "px",
			left: pe.l + leftWidth + leftSplitterThickness + "px",
			right: pe.r + rightWidth + rightSplitterThickness + "px",
			bottom: pe.b + bottomHeight + bottomSplitterThickness + "px"
		});

		var bounds = {
			top: sidebarLayout ? pe.t + "px" : centerStyle.top,
			bottom: sidebarLayout ? pe.b + "px" : centerStyle.bottom
		};
		dojo.mixin(leftStyle, bounds);
		dojo.mixin(rightStyle, bounds);
		leftStyle.left = pe.l + "px"; rightStyle.right = pe.r + "px"; topStyle.top = pe.t + "px"; bottomStyle.bottom = pe.b + "px";
		if(sidebarLayout){
			topStyle.left = bottomStyle.left = leftWidth + leftSplitterThickness + pe.l + "px";
			topStyle.right = bottomStyle.right = rightWidth + rightSplitterThickness + pe.r + "px";
		}else{
			topStyle.left = bottomStyle.left = pe.l + "px";
			topStyle.right = bottomStyle.right = pe.r + "px";
		}

		// More calculations about sizes of panes
		var containerHeight = this._borderBox.h - pe.t - pe.b,
			middleHeight = containerHeight - ( topHeight + topSplitterThickness + bottomHeight + bottomSplitterThickness),
			sidebarHeight = sidebarLayout ? containerHeight : middleHeight;

		var containerWidth = this._borderBox.w - pe.l - pe.r,
			middleWidth = containerWidth - (leftWidth + leftSplitterThickness + rightWidth + rightSplitterThickness),
			sidebarWidth = sidebarLayout ? middleWidth : containerWidth;

		// New margin-box size of each pane
		var dim = {
			top:	{ w: sidebarWidth, h: topHeight },
			bottom: { w: sidebarWidth, h: bottomHeight },
			left:	{ w: leftWidth, h: sidebarHeight },
			right:	{ w: rightWidth, h: sidebarHeight },
			center:	{ h: middleHeight, w: middleWidth }
		};

		if(changedRegion){
			// Respond to splitter drag event by changing changedRegion's width or height
			var child = this["_" + changedRegion + "Widget"],
				mb = {};
				mb[ /top|bottom/.test(changedRegion) ? "h" : "w"] = changedRegionSize;
			child.resize ? child.resize(mb, dim[child.region]) : dojo.marginBox(child.domNode, mb);
		}

		// Nodes in IE<8 don't respond to t/l/b/r, and TEXTAREA doesn't respond in any browser
		var janky = dojo.isIE < 8 || (dojo.isIE && dojo.isQuirks) || dojo.some(this.getChildren(), function(child){
			return child.domNode.tagName == "TEXTAREA" || child.domNode.tagName == "INPUT";
		});
		if(janky){
			// Set the size of the children the old fashioned way, by setting
			// CSS width and height

			var resizeWidget = function(widget, changes, result){
				if(widget){
					(widget.resize ? widget.resize(changes, result) : dojo.marginBox(widget.domNode, changes));
				}
			};

			if(leftSplitter){ leftSplitter.style.height = sidebarHeight; }
			if(rightSplitter){ rightSplitter.style.height = sidebarHeight; }
			resizeWidget(this._leftWidget, {h: sidebarHeight}, dim.left);
			resizeWidget(this._rightWidget, {h: sidebarHeight}, dim.right);

			if(topSplitter){ topSplitter.style.width = sidebarWidth; }
			if(bottomSplitter){ bottomSplitter.style.width = sidebarWidth; }
			resizeWidget(this._topWidget, {w: sidebarWidth}, dim.top);
			resizeWidget(this._bottomWidget, {w: sidebarWidth}, dim.bottom);

			resizeWidget(this._centerWidget, dim.center);
		}else{
			// Calculate which panes need a notification that their size has been changed
			// (we've already set style.top/bottom/left/right on those other panes).
			var notifySides = !changedRegion || (/top|bottom/.test(changedRegion) && this.design != "sidebar"),
				notifyTopBottom = !changedRegion || (/left|right/.test(changedRegion) && this.design == "sidebar"),
				notifyList = {
					center: true,
					left: notifySides,
					right: notifySides,
					top: notifyTopBottom,
					bottom: notifyTopBottom
				};
			
			// Send notification to those panes that have changed size
			dojo.forEach(this.getChildren(), function(child){
				if(child.resize && notifyList[child.region]){
					child.resize(null, dim[child.region]);
				}
			}, this);
		}
	},

	destroy: function(){
		for(var region in this._splitters){
			var splitter = this._splitters[region];
			dijit.byNode(splitter).destroy();
			dojo.destroy(splitter);
		}
		delete this._splitters;
		delete this._splitterThickness;
		this.inherited(arguments);
	}
});

// This argument can be specified for the children of a BorderContainer.
// Since any widget can be specified as a LayoutContainer child, mix it
// into the base widget class.  (This is a hack, but it's effective.)
dojo.extend(dijit._Widget, {
	// region: [const] String
	//		Parameter for children of `dijit.layout.BorderContainer`.
	//		Values: "top", "bottom", "leading", "trailing", "left", "right", "center".
	//		See the `dijit.layout.BorderContainer` description for details.
	region: '',

	// splitter: [const] Boolean
	//		Parameter for child of `dijit.layout.BorderContainer` where region != "center".
	//		If true, enables user to resize the widget by putting a draggable splitter between
	//		this widget and the region=center widget.
	splitter: false,

	// minSize: [const] Number
	//		Parameter for children of `dijit.layout.BorderContainer`.
	//		Specifies a minimum size (in pixels) for this widget when resized by a splitter.
	minSize: 0,

	// maxSize: [const] Number
	//		Parameter for children of `dijit.layout.BorderContainer`.
	//		Specifies a maximum size (in pixels) for this widget when resized by a splitter.
	maxSize: Infinity
});



dojo.declare("dijit.layout._Splitter", [ dijit._Widget, dijit._Templated ],
{
	// summary:
	//		A draggable spacer between two items in a `dijit.layout.BorderContainer`.
	// description:
	//		This is instantiated by `dijit.layout.BorderContainer`.  Users should not
	//		create it directly.
	// tags:
	//		private

/*=====
 	// container: [const] dijit.layout.BorderContainer
 	//		Pointer to the parent BorderContainer
	container: null,

	// child: [const] dijit.layout._LayoutWidget
	//		Pointer to the pane associated with this splitter
	child: null,

	// region: String
	//		Region of pane associated with this splitter.
	//		"top", "bottom", "left", "right".
	region: null,
=====*/

	// live: [const] Boolean
	//		If true, the child's size changes and the child widget is redrawn as you drag the splitter;
	//		otherwise, the size doesn't change until you drop the splitter (by mouse-up)
	live: true,

	templateString: '<div class="dijitSplitter" dojoAttachEvent="onkeypress:_onKeyPress,onmousedown:_startDrag,onmouseenter:_onMouse,onmouseleave:_onMouse" tabIndex="0" waiRole="separator"><div class="dijitSplitterThumb"></div></div>',

	postCreate: function(){
		this.inherited(arguments);
		this.horizontal = /top|bottom/.test(this.region);
		dojo.addClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V"));
//		dojo.addClass(this.child.domNode, "dijitSplitterPane");
//		dojo.setSelectable(this.domNode, false); //TODO is this necessary?

		this._factor = /top|left/.test(this.region) ? 1 : -1;

		this._cookieName = this.container.id + "_" + this.region;
		if(this.container.persist){
			// restore old size
			var persistSize = dojo.cookie(this._cookieName);
			if(persistSize){
				this.child.domNode.style[this.horizontal ? "height" : "width"] = persistSize;
			}
		}
	},

	_computeMaxSize: function(){
		// summary:
		//		Compute the maximum size that my corresponding pane can be set to

		var dim = this.horizontal ? 'h' : 'w',
			thickness = this.container._splitterThickness[this.region];
			
		// Get DOMNode of opposite pane, if an opposite pane exists.
		// Ex: if I am the _Splitter for the left pane, then get the right pane.
		var flip = {left:'right', right:'left', top:'bottom', bottom:'top', leading:'trailing', trailing:'leading'},
			oppNode = this.container["_" + flip[this.region]];
		
		// I can expand up to the edge of the opposite pane, or if there's no opposite pane, then to
		// edge of BorderContainer
		var available = dojo.contentBox(this.container.domNode)[dim] -
				(oppNode ? dojo.marginBox(oppNode)[dim] : 0) -
				20 - thickness * 2;

		return Math.min(this.child.maxSize, available);
	},

	_startDrag: function(e){
		if(!this.cover){
			this.cover = dojo.doc.createElement('div');
			dojo.addClass(this.cover, "dijitSplitterCover");
			dojo.place(this.cover, this.child.domNode, "after");
		}
		dojo.addClass(this.cover, "dijitSplitterCoverActive");

		// Safeguard in case the stop event was missed.  Shouldn't be necessary if we always get the mouse up.
		if(this.fake){ dojo.destroy(this.fake); }
		if(!(this._resize = this.live)){ //TODO: disable live for IE6?
			// create fake splitter to display at old position while we drag
			(this.fake = this.domNode.cloneNode(true)).removeAttribute("id");
			dojo.addClass(this.domNode, "dijitSplitterShadow");
			dojo.place(this.fake, this.domNode, "after");
		}
		dojo.addClass(this.domNode, "dijitSplitterActive");
		dojo.addClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
		if(this.fake){
			dojo.removeClass(this.fake, "dijitSplitterHover");
			dojo.removeClass(this.fake, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover");
		}

		//Performance: load data info local vars for onmousevent function closure
		var factor = this._factor,
			max = this._computeMaxSize(),
			min = this.child.minSize || 20,
			isHorizontal = this.horizontal,
			axis = isHorizontal ? "pageY" : "pageX",
			pageStart = e[axis],
			splitterStyle = this.domNode.style,
			dim = isHorizontal ? 'h' : 'w',
			childStart = dojo.marginBox(this.child.domNode)[dim],
			region = this.region,
			splitterStart = parseInt(this.domNode.style[region], 10),
			resize = this._resize,
			childNode = this.child.domNode,
			layoutFunc = dojo.hitch(this.container, this.container._layoutChildren),
			de = dojo.doc;

		this._handlers = (this._handlers || []).concat([
			dojo.connect(de, "onmousemove", this._drag = function(e, forceResize){
				var delta = e[axis] - pageStart,
					childSize = factor * delta + childStart,
					boundChildSize = Math.max(Math.min(childSize, max), min);

				if(resize || forceResize){
					layoutFunc(region, boundChildSize);
				}
				splitterStyle[region] = factor * delta + splitterStart + (boundChildSize - childSize) + "px";
			}),
			dojo.connect(de, "ondragstart", dojo.stopEvent),
			dojo.connect(dojo.body(), "onselectstart", dojo.stopEvent),
			dojo.connect(de, "onmouseup", this, "_stopDrag")
		]);
		dojo.stopEvent(e);
	},

	_onMouse: function(e){
		var o = (e.type == "mouseover" || e.type == "mouseenter");
		dojo.toggleClass(this.domNode, "dijitSplitterHover", o);
		dojo.toggleClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Hover", o);
	},

	_stopDrag: function(e){
		try{
			if(this.cover){
				dojo.removeClass(this.cover, "dijitSplitterCoverActive");
			}
			if(this.fake){ dojo.destroy(this.fake); }
			dojo.removeClass(this.domNode, "dijitSplitterActive");
			dojo.removeClass(this.domNode, "dijitSplitter" + (this.horizontal ? "H" : "V") + "Active");
			dojo.removeClass(this.domNode, "dijitSplitterShadow");
			this._drag(e); //TODO: redundant with onmousemove?
			this._drag(e, true);
		}finally{
			this._cleanupHandlers();
			delete this._drag;
		}

		if(this.container.persist){
			dojo.cookie(this._cookieName, this.child.domNode.style[this.horizontal ? "height" : "width"], {expires:365});
		}
	},

	_cleanupHandlers: function(){
		dojo.forEach(this._handlers, dojo.disconnect);
		delete this._handlers;
	},

	_onKeyPress: function(/*Event*/ e){
		// should we apply typematic to this?
		this._resize = true;
		var horizontal = this.horizontal;
		var tick = 1;
		var dk = dojo.keys;
		switch(e.charOrCode){
			case horizontal ? dk.UP_ARROW : dk.LEFT_ARROW:
				tick *= -1;
//				break;
			case horizontal ? dk.DOWN_ARROW : dk.RIGHT_ARROW:
				break;
			default:
//				this.inherited(arguments);
				return;
		}
		var childSize = dojo.marginBox(this.child.domNode)[ horizontal ? 'h' : 'w' ] + this._factor * tick;
		this.container._layoutChildren(this.region, Math.max(Math.min(childSize, this._computeMaxSize()), this.child.minSize));
		dojo.stopEvent(e);
	},

	destroy: function(){
		this._cleanupHandlers();
		delete this.child;
		delete this.container;
		delete this.cover;
		delete this.fake;
		this.inherited(arguments);
	}
});

dojo.declare("dijit.layout._Gutter", [dijit._Widget, dijit._Templated ],
{
	// summary:
	// 		Just a spacer div to separate side pane from center pane.
	//		Basically a trick to lookup the gutter/splitter width from the theme.
	// description:
	//		Instantiated by `dijit.layout.BorderContainer`.  Users should not
	//		create directly.
	// tags:
	//		private

	templateString: '<div class="dijitGutter" waiRole="presentation"></div>',

	postCreate: function(){
		this.horizontal = /top|bottom/.test(this.region);
		dojo.addClass(this.domNode, "dijitGutter" + (this.horizontal ? "H" : "V"));
	}
});

}

if(!dojo._hasResource["dojo.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.html"] = true;
dojo.provide("dojo.html");

// the parser might be needed..
 

(function(){ // private scope, sort of a namespace

	// idCounter is incremented with each instantiation to allow asignment of a unique id for tracking, logging purposes
	var idCounter = 0, 
		d = dojo;
	
	dojo.html._secureForInnerHtml = function(/*String*/ cont){
		// summary:
		//		removes !DOCTYPE and title elements from the html string.
		// 
		//		khtml is picky about dom faults, you can't attach a style or <title> node as child of body
		//		must go into head, so we need to cut out those tags
		//	cont:
		//		An html string for insertion into the dom
		//	
		return cont.replace(/(?:\s*<!DOCTYPE\s[^>]+>|<title[^>]*>[\s\S]*?<\/title>)/ig, ""); // String
	};

/*====
	dojo.html._emptyNode = function(node){
		// summary:
		//		removes all child nodes from the given node
		//	node: DOMNode
		//		the parent element
	};
=====*/
	dojo.html._emptyNode = dojo.empty;

	dojo.html._setNodeContent = function(/* DomNode */ node, /* String|DomNode|NodeList */ cont){
		// summary:
		//		inserts the given content into the given node
		//	node:
		//		the parent element
		//	content:
		//		the content to be set on the parent element. 
		//		This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
		
		// always empty
		d.empty(node);

		if(cont) {
			if(typeof cont == "string") {
				cont = d._toDom(cont, node.ownerDocument);
			}
			if(!cont.nodeType && d.isArrayLike(cont)) {
				// handle as enumerable, but it may shrink as we enumerate it
				for(var startlen=cont.length, i=0; i<cont.length; i=startlen==cont.length ? i+1 : 0) {
					d.place( cont[i], node, "last");
				}
			} else {
				// pass nodes, documentFragments and unknowns through to dojo.place
				d.place(cont, node, "last");
			}
		}

		// return DomNode
		return node;
	};

	// we wrap up the content-setting operation in a object
	dojo.declare("dojo.html._ContentSetter", null, 
		{
			// node: DomNode|String
			//		An node which will be the parent element that we set content into
			node: "",

			// content: String|DomNode|DomNode[]
			//		The content to be placed in the node. Can be an HTML string, a node reference, or a enumerable list of nodes
			content: "",
			
			// id: String?
			//		Usually only used internally, and auto-generated with each instance 
			id: "",

			// cleanContent: Boolean
			//		Should the content be treated as a full html document, 
			//		and the real content stripped of <html>, <body> wrapper before injection
			cleanContent: false,
			
			// extractContent: Boolean
			//		Should the content be treated as a full html document, and the real content stripped of <html>, <body> wrapper before injection
			extractContent: false,

			// parseContent: Boolean
			//		Should the node by passed to the parser after the new content is set
			parseContent: false,
			
			// lifecyle methods
			constructor: function(/* Object */params, /* String|DomNode */node){
				//	summary:
				//		Provides a configurable, extensible object to wrap the setting on content on a node
				//		call the set() method to actually set the content..
 
				// the original params are mixed directly into the instance "this"
				dojo.mixin(this, params || {});

				// give precedence to params.node vs. the node argument
				// and ensure its a node, not an id string
				node = this.node = dojo.byId( this.node || node );
	
				if(!this.id){
					this.id = [
						"Setter",
						(node) ? node.id || node.tagName : "", 
						idCounter++
					].join("_");
				}
			},
			set: function(/* String|DomNode|NodeList? */ cont, /* Object? */ params){
				// summary:
				//		front-end to the set-content sequence 
				//	cont:
				//		An html string, node or enumerable list of nodes for insertion into the dom
				//		If not provided, the object's content property will be used
				if(undefined !== cont){
					this.content = cont;
				}
				// in the re-use scenario, set needs to be able to mixin new configuration
				if(params){
					this._mixin(params);
				}

				this.onBegin();
				this.setContent();
				this.onEnd();

				return this.node;
			},
			setContent: function(){
				// summary:
				//		sets the content on the node 

				var node = this.node; 
				if(!node) {
				    // can't proceed
					throw new Error(this.declaredClass + ": setContent given no node");
				}
				try{
					node = dojo.html._setNodeContent(node, this.content);
				}catch(e){
					// check if a domfault occurs when we are appending this.errorMessage
					// like for instance if domNode is a UL and we try append a DIV
	
					// FIXME: need to allow the user to provide a content error message string
					var errMess = this.onContentError(e); 
					try{
						node.innerHTML = errMess;
					}catch(e){
						console.error('Fatal ' + this.declaredClass + '.setContent could not change content due to '+e.message, e);
					}
				}
				// always put back the node for the next method
				this.node = node; // DomNode
			},
			
			empty: function() {
				// summary
				//	cleanly empty out existing content

				// destroy any widgets from a previous run
				// NOTE: if you dont want this you'll need to empty 
				// the parseResults array property yourself to avoid bad things happenning
				if(this.parseResults && this.parseResults.length) {
					dojo.forEach(this.parseResults, function(w) {
						if(w.destroy){
							w.destroy();
						}
					});
					delete this.parseResults;
				}
				// this is fast, but if you know its already empty or safe, you could 
				// override empty to skip this step
				dojo.html._emptyNode(this.node);
			},
	
			onBegin: function(){
				// summary
				//		Called after instantiation, but before set(); 
				//		It allows modification of any of the object properties 
				//		- including the node and content provided - before the set operation actually takes place
				//		This default implementation checks for cleanContent and extractContent flags to 
				//		optionally pre-process html string content
				var cont = this.content;
	
				if(dojo.isString(cont)){
					if(this.cleanContent){
						cont = dojo.html._secureForInnerHtml(cont);
					}
  
					if(this.extractContent){
						var match = cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
						if(match){ cont = match[1]; }
					}
				}

				// clean out the node and any cruft associated with it - like widgets
				this.empty();
				
				this.content = cont;
				return this.node; /* DomNode */
			},
	
			onEnd: function(){
				// summary
				//		Called after set(), when the new content has been pushed into the node
				//		It provides an opportunity for post-processing before handing back the node to the caller
				//		This default implementation checks a parseContent flag to optionally run the dojo parser over the new content
				if(this.parseContent){
					// populates this.parseResults if you need those..
					this._parse();
				}
				return this.node; /* DomNode */
			},
	
			tearDown: function(){
				// summary
				//		manually reset the Setter instance if its being re-used for example for another set()
				// description
				//		tearDown() is not called automatically. 
				//		In normal use, the Setter instance properties are simply allowed to fall out of scope
				//		but the tearDown method can be called to explicitly reset this instance.
				delete this.parseResults; 
				delete this.node; 
				delete this.content; 
			},
  
			onContentError: function(err){
				return "Error occured setting content: " + err; 
			},
			
			_mixin: function(params){
				// mix properties/methods into the instance
				// TODO: the intention with tearDown is to put the Setter's state 
				// back to that of the original constructor (vs. deleting/resetting everything regardless of ctor params)
				// so we could do something here to move the original properties aside for later restoration
				var empty = {}, key;
				for(key in params){
					if(key in empty){ continue; }
					// TODO: here's our opportunity to mask the properties we dont consider configurable/overridable
					// .. but history shows we'll almost always guess wrong
					this[key] = params[key]; 
				}
			},
			_parse: function(){
				// summary: 
				//		runs the dojo parser over the node contents, storing any results in this.parseResults
				//		Any errors resulting from parsing are passed to _onError for handling

				var rootNode = this.node;
				try{
					// store the results (widgets, whatever) for potential retrieval
					this.parseResults = dojo.parser.parse({
						rootNode: rootNode,
						dir: this.dir,
						lang: this.lang
					});
				}catch(e){
					this._onError('Content', e, "Error parsing in _ContentSetter#"+this.id);
				}
			},
  
			_onError: function(type, err, consoleText){
				// summary:
				//		shows user the string that is returned by on[type]Error
				//		overide/implement on[type]Error and return your own string to customize
				var errText = this['on' + type + 'Error'].call(this, err);
				if(consoleText){
					console.error(consoleText, err);
				}else if(errText){ // a empty string won't change current content
					dojo.html._setNodeContent(this.node, errText, true);
				}
			}
	}); // end dojo.declare()

	dojo.html.set = function(/* DomNode */ node, /* String|DomNode|NodeList */ cont, /* Object? */ params){
			// summary:
			//		inserts (replaces) the given content into the given node. dojo.place(cont, node, "only")
			//		may be a better choice for simple HTML insertion.
			// description:
			//		Unless you need to use the params capabilities of this method, you should use
			//		dojo.place(cont, node, "only"). dojo.place() has more robust support for injecting
			//		an HTML string into the DOM, but it only handles inserting an HTML string as DOM
			//		elements, or inserting a DOM node. dojo.place does not handle NodeList insertions
			//		or the other capabilities as defined by the params object for this method.
			//	node:
			//		the parent element that will receive the content
			//	cont:
			//		the content to be set on the parent element. 
			//		This can be an html string, a node reference or a NodeList, dojo.NodeList, Array or other enumerable list of nodes
			//	params: 
			//		Optional flags/properties to configure the content-setting. See dojo.html._ContentSetter
			//	example:
			//		A safe string/node/nodelist content replacement/injection with hooks for extension
			//		Example Usage: 
			//		dojo.html.set(node, "some string"); 
			//		dojo.html.set(node, contentNode, {options}); 
			//		dojo.html.set(node, myNode.childNodes, {options}); 
		if(undefined == cont){
			console.warn("dojo.html.set: no cont argument provided, using empty string");
			cont = "";
		}	
		if(!params){
			// simple and fast
			return dojo.html._setNodeContent(node, cont, true);
		}else{ 
			// more options but slower
			// note the arguments are reversed in order, to match the convention for instantiation via the parser
			var op = new dojo.html._ContentSetter(dojo.mixin( 
					params, 
					{ content: cont, node: node } 
			));
			return op.set();
		}
	};
})();

}

if(!dojo._hasResource["dojo.i18n"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.i18n"] = true;
dojo.provide("dojo.i18n");

/*=====
dojo.i18n = {
	// summary: Utility classes to enable loading of resources for internationalization (i18n)
};
=====*/

dojo.i18n.getLocalization = function(/*String*/packageName, /*String*/bundleName, /*String?*/locale){
	//	summary:
	//		Returns an Object containing the localization for a given resource
	//		bundle in a package, matching the specified locale.
	//	description:
	//		Returns a hash containing name/value pairs in its prototypesuch
	//		that values can be easily overridden.  Throws an exception if the
	//		bundle is not found.  Bundle must have already been loaded by
	//		`dojo.requireLocalization()` or by a build optimization step.  NOTE:
	//		try not to call this method as part of an object property
	//		definition (`var foo = { bar: dojo.i18n.getLocalization() }`).  In
	//		some loading situations, the bundle may not be available in time
	//		for the object definition.  Instead, call this method inside a
	//		function that is run after all modules load or the page loads (like
	//		in `dojo.addOnLoad()`), or in a widget lifecycle method.
	//	packageName:
	//		package which is associated with this resource
	//	bundleName:
	//		the base filename of the resource bundle (without the ".js" suffix)
	//	locale:
	//		the variant to load (optional).  By default, the locale defined by
	//		the host environment: dojo.locale

	locale = dojo.i18n.normalizeLocale(locale);

	// look for nearest locale match
	var elements = locale.split('-');
	var module = [packageName,"nls",bundleName].join('.');
	var bundle = dojo._loadedModules[module];
	if(bundle){
		var localization;
		for(var i = elements.length; i > 0; i--){
			var loc = elements.slice(0, i).join('_');
			if(bundle[loc]){
				localization = bundle[loc];
				break;
			}
		}
		if(!localization){
			localization = bundle.ROOT;
		}

		// make a singleton prototype so that the caller won't accidentally change the values globally
		if(localization){
			var clazz = function(){};
			clazz.prototype = localization;
			return new clazz(); // Object
		}
	}

	throw new Error("Bundle not found: " + bundleName + " in " + packageName+" , locale=" + locale);
};

dojo.i18n.normalizeLocale = function(/*String?*/locale){
	//	summary:
	//		Returns canonical form of locale, as used by Dojo.
	//
	//  description:
	//		All variants are case-insensitive and are separated by '-' as specified in [RFC 3066](http://www.ietf.org/rfc/rfc3066.txt).
	//		If no locale is specified, the dojo.locale is returned.  dojo.locale is defined by
	//		the user agent's locale unless overridden by djConfig.

	var result = locale ? locale.toLowerCase() : dojo.locale;
	if(result == "root"){
		result = "ROOT";
	}
	return result; // String
};

dojo.i18n._requireLocalization = function(/*String*/moduleName, /*String*/bundleName, /*String?*/locale, /*String?*/availableFlatLocales){
	//	summary:
	//		See dojo.requireLocalization()
	//	description:
	// 		Called by the bootstrap, but factored out so that it is only
	// 		included in the build when needed.

	var targetLocale = dojo.i18n.normalizeLocale(locale);
 	var bundlePackage = [moduleName, "nls", bundleName].join(".");
	// NOTE: 
	//		When loading these resources, the packaging does not match what is
	//		on disk.  This is an implementation detail, as this is just a
	//		private data structure to hold the loaded resources.  e.g.
	//		`tests/hello/nls/en-us/salutations.js` is loaded as the object
	//		`tests.hello.nls.salutations.en_us={...}` The structure on disk is
	//		intended to be most convenient for developers and translators, but
	//		in memory it is more logical and efficient to store in a different
	//		order.  Locales cannot use dashes, since the resulting path will
	//		not evaluate as valid JS, so we translate them to underscores.
	
	//Find the best-match locale to load if we have available flat locales.
	var bestLocale = "";
	if(availableFlatLocales){
		var flatLocales = availableFlatLocales.split(",");
		for(var i = 0; i < flatLocales.length; i++){
			//Locale must match from start of string.
			//Using ["indexOf"] so customBase builds do not see
			//this as a dojo._base.array dependency.
			if(targetLocale["indexOf"](flatLocales[i]) == 0){
				if(flatLocales[i].length > bestLocale.length){
					bestLocale = flatLocales[i];
				}
			}
		}
		if(!bestLocale){
			bestLocale = "ROOT";
		}		
	}

	//See if the desired locale is already loaded.
	var tempLocale = availableFlatLocales ? bestLocale : targetLocale;
	var bundle = dojo._loadedModules[bundlePackage];
	var localizedBundle = null;
	if(bundle){
		if(dojo.config.localizationComplete && bundle._built){return;}
		var jsLoc = tempLocale.replace(/-/g, '_');
		var translationPackage = bundlePackage+"."+jsLoc;
		localizedBundle = dojo._loadedModules[translationPackage];
	}

	if(!localizedBundle){
		bundle = dojo["provide"](bundlePackage);
		var syms = dojo._getModuleSymbols(moduleName);
		var modpath = syms.concat("nls").join("/");
		var parent;

		dojo.i18n._searchLocalePath(tempLocale, availableFlatLocales, function(loc){
			var jsLoc = loc.replace(/-/g, '_');
			var translationPackage = bundlePackage + "." + jsLoc;
			var loaded = false;
			if(!dojo._loadedModules[translationPackage]){
				// Mark loaded whether it's found or not, so that further load attempts will not be made
				dojo["provide"](translationPackage);
				var module = [modpath];
				if(loc != "ROOT"){module.push(loc);}
				module.push(bundleName);
				var filespec = module.join("/") + '.js';
				loaded = dojo._loadPath(filespec, null, function(hash){
					// Use singleton with prototype to point to parent bundle, then mix-in result from loadPath
					var clazz = function(){};
					clazz.prototype = parent;
					bundle[jsLoc] = new clazz();
					for(var j in hash){ bundle[jsLoc][j] = hash[j]; }
				});
			}else{
				loaded = true;
			}
			if(loaded && bundle[jsLoc]){
				parent = bundle[jsLoc];
			}else{
				bundle[jsLoc] = parent;
			}
			
			if(availableFlatLocales){
				//Stop the locale path searching if we know the availableFlatLocales, since
				//the first call to this function will load the only bundle that is needed.
				return true;
			}
		});
	}

	//Save the best locale bundle as the target locale bundle when we know the
	//the available bundles.
	if(availableFlatLocales && targetLocale != bestLocale){
		bundle[targetLocale.replace(/-/g, '_')] = bundle[bestLocale.replace(/-/g, '_')];
	}
};

(function(){
	// If other locales are used, dojo.requireLocalization should load them as
	// well, by default. 
	// 
	// Override dojo.requireLocalization to do load the default bundle, then
	// iterate through the extraLocale list and load those translations as
	// well, unless a particular locale was requested.

	var extra = dojo.config.extraLocale;
	if(extra){
		if(!extra instanceof Array){
			extra = [extra];
		}

		var req = dojo.i18n._requireLocalization;
		dojo.i18n._requireLocalization = function(m, b, locale, availableFlatLocales){
			req(m,b,locale, availableFlatLocales);
			if(locale){return;}
			for(var i=0; i<extra.length; i++){
				req(m,b,extra[i], availableFlatLocales);
			}
		};
	}
})();

dojo.i18n._searchLocalePath = function(/*String*/locale, /*Boolean*/down, /*Function*/searchFunc){
	//	summary:
	//		A helper method to assist in searching for locale-based resources.
	//		Will iterate through the variants of a particular locale, either up
	//		or down, executing a callback function.  For example, "en-us" and
	//		true will try "en-us" followed by "en" and finally "ROOT".

	locale = dojo.i18n.normalizeLocale(locale);

	var elements = locale.split('-');
	var searchlist = [];
	for(var i = elements.length; i > 0; i--){
		searchlist.push(elements.slice(0, i).join('-'));
	}
	searchlist.push(false);
	if(down){searchlist.reverse();}

	for(var j = searchlist.length - 1; j >= 0; j--){
		var loc = searchlist[j] || "ROOT";
		var stop = searchFunc(loc);
		if(stop){ break; }
	}
};

dojo.i18n._preloadLocalizations = function(/*String*/bundlePrefix, /*Array*/localesGenerated){
	//	summary:
	//		Load built, flattened resource bundles, if available for all
	//		locales used in the page. Only called by built layer files.

	function preload(locale){
		locale = dojo.i18n.normalizeLocale(locale);
		dojo.i18n._searchLocalePath(locale, true, function(loc){
			for(var i=0; i<localesGenerated.length;i++){
				if(localesGenerated[i] == loc){
					dojo["require"](bundlePrefix+"_"+loc);
					return true; // Boolean
				}
			}
			return false; // Boolean
		});
	}
	preload();
	var extra = dojo.config.extraLocale||[];
	for(var i=0; i<extra.length; i++){
		preload(extra[i]);
	}
};

}

if(!dojo._hasResource["dijit.layout.ContentPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.ContentPane"] = true;
dojo.provide("dijit.layout.ContentPane");



	// for dijit.layout.marginBox2contentBox()






dojo.declare(
	"dijit.layout.ContentPane", dijit._Widget,
{
	// summary:
	//		A widget that acts as a container for mixed HTML and widgets, and includes an Ajax interface
	// description:
	//		A widget that can be used as a stand alone widget
	//		or as a base class for other widgets.
	//
	//		Handles replacement of document fragment using either external uri or javascript
	//		generated markup or DOM content, instantiating widgets within that content.
	//		Don't confuse it with an iframe, it only needs/wants document fragments.
	//		It's useful as a child of LayoutContainer, SplitContainer, or TabContainer.
	//		But note that those classes can contain any widget as a child.
	// example:
	//		Some quick samples:
	//		To change the innerHTML use .set('content', '<b>new content</b>')
	//
	//		Or you can send it a NodeList, .set('content', dojo.query('div [class=selected]', userSelection))
	//		please note that the nodes in NodeList will copied, not moved
	//
	//		To do a ajax update use .set('href', url)

	// href: String
	//		The href of the content that displays now.
	//		Set this at construction if you want to load data externally when the
	//		pane is shown.  (Set preload=true to load it immediately.)
	//		Changing href after creation doesn't have any effect; Use set('href', ...);
	href: "",

/*=====
	// content: String || DomNode || NodeList || dijit._Widget
	//		The innerHTML of the ContentPane.
	//		Note that the initialization parameter / argument to attr("content", ...)
	//		can be a String, DomNode, Nodelist, or _Widget.
	content: "",
=====*/

	// extractContent: Boolean
	//		Extract visible content from inside of <body> .... </body>.
	//		I.e., strip <html> and <head> (and it's contents) from the href
	extractContent: false,

	// parseOnLoad: Boolean
	//		Parse content and create the widgets, if any.
	parseOnLoad: true,

	// preventCache: Boolean
	//		Prevent caching of data from href's by appending a timestamp to the href.
	preventCache: false,

	// preload: Boolean
	//		Force load of data on initialization even if pane is hidden.
	preload: false,

	// refreshOnShow: Boolean
	//		Refresh (re-download) content when pane goes from hidden to shown
	refreshOnShow: false,

	// loadingMessage: String
	//		Message that shows while downloading
	loadingMessage: "<span class='dijitContentPaneLoading'>${loadingState}</span>",

	// errorMessage: String
	//		Message that shows if an error occurs
	errorMessage: "<span class='dijitContentPaneError'>${errorState}</span>",

	// isLoaded: [readonly] Boolean
	//		True if the ContentPane has data in it, either specified
	//		during initialization (via href or inline content), or set
	//		via attr('content', ...) / attr('href', ...)
	//
	//		False if it doesn't have any content, or if ContentPane is
	//		still in the process of downloading href.
	isLoaded: false,

	baseClass: "dijitContentPane",

	// doLayout: Boolean
	//		- false - don't adjust size of children
	//		- true - if there is a single visible child widget, set it's size to
	//				however big the ContentPane is
	doLayout: true,

	// ioArgs: Object
	//		Parameters to pass to xhrGet() request, for example:
	// |	<div dojoType="dijit.layout.ContentPane" href="./bar" ioArgs="{timeout: 500}">
	ioArgs: {},

	// isContainer: [protected] Boolean
	//		Indicates that this widget acts as a "parent" to the descendant widgets.
	//		When the parent is started it will call startup() on the child widgets.
	//		See also `isLayoutContainer`.
	isContainer: true,

	// isLayoutContainer: [protected] Boolean
	//		Indicates that this widget will call resize() on it's child widgets
	//		when they become visible.
	isLayoutContainer: true,

	// onLoadDeferred: [readonly] dojo.Deferred
	//		This is the `dojo.Deferred` returned by attr('href', ...) and refresh().
	//		Calling onLoadDeferred.addCallback() or addErrback() registers your
	//		callback to be called only once, when the prior attr('href', ...) call or
	//		the initial href parameter to the constructor finishes loading.
	//
	//		This is different than an onLoad() handler which gets called any time any href is loaded.
	onLoadDeferred: null,

	// Override _Widget's attributeMap because we don't want the title attribute (used to specify
	// tab labels) to be copied to ContentPane.domNode... otherwise a tooltip shows up over the
	// entire pane.
	attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
		title: []
	}),

	postMixInProperties: function(){
		this.inherited(arguments);
		var messages = dojo.i18n.getLocalization("dijit", "loading", this.lang);
		this.loadingMessage = dojo.string.substitute(this.loadingMessage, messages);
		this.errorMessage = dojo.string.substitute(this.errorMessage, messages);

		// Detect if we were initialized with data
		if(!this.href && this.srcNodeRef && this.srcNodeRef.innerHTML){
			this.isLoaded = true;
		}
	},

	buildRendering: function(){
		// Overrides Widget.buildRendering().
		// Since we have no template we need to set this.containerNode ourselves.
		// For subclasses of ContentPane do have a template, does nothing.
		this.inherited(arguments);
		if(!this.containerNode){
			// make getDescendants() work
			this.containerNode = this.domNode;
		}
	},

	postCreate: function(){
		// remove the title attribute so it doesn't show up when hovering
		// over a node
		this.domNode.title = "";

		if(!dojo.attr(this.domNode,"role")){
			dijit.setWaiRole(this.domNode, "group");
		}

		dojo.addClass(this.domNode, this.baseClass);
	},

	startup: function(){
		// summary:
		//		See `dijit.layout._LayoutWidget.startup` for description.
		//		Although ContentPane doesn't extend _LayoutWidget, it does implement
		//		the same API.
		if(this._started){ return; }

		var parent = dijit._Contained.prototype.getParent.call(this);
		this._childOfLayoutWidget = parent && parent.isLayoutContainer;

		// I need to call resize() on my child/children (when I become visible), unless
		// I'm the child of a layout widget in which case my parent will call resize() on me and I'll do it then.
		this._needLayout = !this._childOfLayoutWidget;

		if(this.isLoaded){
			dojo.forEach(this.getChildren(), function(child){
				child.startup();
			});
		}

		if(this._isShown() || this.preload){
			this._onShow();
		}

		this.inherited(arguments);
	},

	_checkIfSingleChild: function(){
		// summary:
		//		Test if we have exactly one visible widget as a child,
		//		and if so assume that we are a container for that widget,
		//		and should propogate startup() and resize() calls to it.
		//		Skips over things like data stores since they aren't visible.

		var childNodes = dojo.query("> *", this.containerNode).filter(function(node){
				return node.tagName !== "SCRIPT"; // or a regexp for hidden elements like script|area|map|etc..
			}),
			childWidgetNodes = childNodes.filter(function(node){
				return dojo.hasAttr(node, "dojoType") || dojo.hasAttr(node, "widgetId");
			}),
			candidateWidgets = dojo.filter(childWidgetNodes.map(dijit.byNode), function(widget){
				return widget && widget.domNode && widget.resize;
			});

		if(
			// all child nodes are widgets
			childNodes.length == childWidgetNodes.length &&

			// all but one are invisible (like dojo.data)
			candidateWidgets.length == 1
		){
			this._singleChild = candidateWidgets[0];
		}else{
			delete this._singleChild;
		}

		// So we can set overflow: hidden to avoid a safari bug w/scrollbars showing up (#9449)
		dojo.toggleClass(this.containerNode, this.baseClass + "SingleChild", !!this._singleChild);
	},

	setHref: function(/*String|Uri*/ href){
		// summary:
		//		Deprecated.   Use set('href', ...) instead.
		dojo.deprecated("dijit.layout.ContentPane.setHref() is deprecated. Use set('href', ...) instead.", "", "2.0");
		return this.set("href", href);
	},
	_setHrefAttr: function(/*String|Uri*/ href){
		// summary:
		//		Hook so attr("href", ...) works.
		// description:
		//		Reset the (external defined) content of this pane and replace with new url
		//		Note: It delays the download until widget is shown if preload is false.
		//	href:
		//		url to the page you want to get, must be within the same domain as your mainpage

		// Cancel any in-flight requests (an attr('href') will cancel any in-flight attr('href', ...))
		this.cancel();

		this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));

		this.href = href;

		// _setHrefAttr() is called during creation and by the user, after creation.
		// only in the second case do we actually load the URL; otherwise it's done in startup()
		if(this._created && (this.preload || this._isShown())){
			this._load();
		}else{
			// Set flag to indicate that href needs to be loaded the next time the
			// ContentPane is made visible
			this._hrefChanged = true;
		}

		return this.onLoadDeferred;		// dojo.Deferred
	},

	setContent: function(/*String|DomNode|Nodelist*/data){
		// summary:
		//		Deprecated.   Use set('content', ...) instead.
		dojo.deprecated("dijit.layout.ContentPane.setContent() is deprecated.  Use set('content', ...) instead.", "", "2.0");
		this.set("content", data);
	},
	_setContentAttr: function(/*String|DomNode|Nodelist*/data){
		// summary:
		//		Hook to make attr("content", ...) work.
		//		Replaces old content with data content, include style classes from old content
		//	data:
		//		the new Content may be String, DomNode or NodeList
		//
		//		if data is a NodeList (or an array of nodes) nodes are copied
		//		so you can import nodes from another document implicitly

		// clear href so we can't run refresh and clear content
		// refresh should only work if we downloaded the content
		this.href = "";

		// Cancel any in-flight requests (an attr('content') will cancel any in-flight attr('href', ...))
		this.cancel();

		// Even though user is just setting content directly, still need to define an onLoadDeferred
		// because the _onLoadHandler() handler is still getting called from setContent()
		this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));

		this._setContent(data || "");

		this._isDownloaded = false; // mark that content is from a attr('content') not an attr('href')

		return this.onLoadDeferred; 	// dojo.Deferred
	},
	_getContentAttr: function(){
		// summary:
		//		Hook to make attr("content") work
		return this.containerNode.innerHTML;
	},

	cancel: function(){
		// summary:
		//		Cancels an in-flight download of content
		if(this._xhrDfd && (this._xhrDfd.fired == -1)){
			this._xhrDfd.cancel();
		}
		delete this._xhrDfd; // garbage collect

		this.onLoadDeferred = null;
	},

	uninitialize: function(){
		if(this._beingDestroyed){
			this.cancel();
		}
		this.inherited(arguments);
	},

	destroyRecursive: function(/*Boolean*/ preserveDom){
		// summary:
		//		Destroy the ContentPane and its contents

		// if we have multiple controllers destroying us, bail after the first
		if(this._beingDestroyed){
			return;
		}
		this.inherited(arguments);
	},

	resize: function(changeSize, resultSize){
		// summary:
		//		See `dijit.layout._LayoutWidget.resize` for description.
		//		Although ContentPane doesn't extend _LayoutWidget, it does implement
		//		the same API.

		// For the TabContainer --> BorderContainer --> ContentPane case, _onShow() is
		// never called, so resize() is our trigger to do the initial href download.
		if(!this._wasShown){
			this._onShow();
		}

		this._resizeCalled = true;

		// Set margin box size, unless it wasn't specified, in which case use current size.
		if(changeSize){
			dojo.marginBox(this.domNode, changeSize);
		}

		// Compute content box size of containerNode in case we [later] need to size our single child.
		var cn = this.containerNode;
		if(cn === this.domNode){
			// If changeSize or resultSize was passed to this method and this.containerNode ==
			// this.domNode then we can compute the content-box size without querying the node,
			// which is more reliable (similar to LayoutWidget.resize) (see for example #9449).
			var mb = resultSize || {};
			dojo.mixin(mb, changeSize || {}); // changeSize overrides resultSize
			if(!("h" in mb) || !("w" in mb)){
				mb = dojo.mixin(dojo.marginBox(cn), mb); // just use dojo.marginBox() to fill in missing values
			}
			this._contentBox = dijit.layout.marginBox2contentBox(cn, mb);
		}else{
			this._contentBox = dojo.contentBox(cn);
		}

		// Make my children layout, or size my single child widget
		this._layoutChildren();
	},

	_isShown: function(){
		// summary:
		//		Returns true if the content is currently shown.
		// description:
		//		If I am a child of a layout widget then it actually returns true if I've ever been visible,
		//		not whether I'm currently visible, since that's much faster than tracing up the DOM/widget
		//		tree every call, and at least solves the performance problem on page load by deferring loading
		//		hidden ContentPanes until they are first shown

		if(this._childOfLayoutWidget){
			// If we are TitlePane, etc - we return that only *IF* we've been resized
			if(this._resizeCalled && "open" in this){
				return this.open;
			}
			return this._resizeCalled;
		}else if("open" in this){
			return this.open;		// for TitlePane, etc.
		}else{
			// TODO: with _childOfLayoutWidget check maybe this branch no longer necessary?
			var node = this.domNode;
			return (node.style.display != 'none') && (node.style.visibility != 'hidden') && !dojo.hasClass(node, "dijitHidden");
		}
	},

	_onShow: function(){
		// summary:
		//		Called when the ContentPane is made visible
		// description:
		//		For a plain ContentPane, this is called on initialization, from startup().
		//		If the ContentPane is a hidden pane of a TabContainer etc., then it's
		//		called whenever the pane is made visible.
		//
		//		Does necessary processing, including href download and layout/resize of
		//		child widget(s)

		if(this.href){
			if(!this._xhrDfd && // if there's an href that isn't already being loaded
				(!this.isLoaded || this._hrefChanged || this.refreshOnShow)
			){
				this.refresh();
			}
		}else{
			// If we are the child of a layout widget then the layout widget will call resize() on
			// us, and then we will size our child/children.   Otherwise, we need to do it now.
			if(!this._childOfLayoutWidget && this._needLayout){
				// If a layout has been scheduled for when we become visible, do it now
				this._layoutChildren();
			}
		}

		this.inherited(arguments);

		// Need to keep track of whether ContentPane has been shown (which is different than
		// whether or not it's currently visible).
		this._wasShown = true;
	},

	refresh: function(){
		// summary:
		//		[Re]download contents of href and display
		// description:
		//		1. cancels any currently in-flight requests
		//		2. posts "loading..." message
		//		3. sends XHR to download new data

		// Cancel possible prior in-flight request
		this.cancel();

		this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel"));
		this._load();
		return this.onLoadDeferred;
	},

	_load: function(){
		// summary:
		//		Load/reload the href specified in this.href

		// display loading message
		this._setContent(this.onDownloadStart(), true);

		var self = this;
		var getArgs = {
			preventCache: (this.preventCache || this.refreshOnShow),
			url: this.href,
			handleAs: "text"
		};
		if(dojo.isObject(this.ioArgs)){
			dojo.mixin(getArgs, this.ioArgs);
		}

		var hand = (this._xhrDfd = (this.ioMethod || dojo.xhrGet)(getArgs));

		hand.addCallback(function(html){
			try{
				self._isDownloaded = true;
				self._setContent(html, false);
				self.onDownloadEnd();
			}catch(err){
				self._onError('Content', err); // onContentError
			}
			delete self._xhrDfd;
			return html;
		});

		hand.addErrback(function(err){
			if(!hand.canceled){
				// show error message in the pane
				self._onError('Download', err); // onDownloadError
			}
			delete self._xhrDfd;
			return err;
		});

		// Remove flag saying that a load is needed
		delete this._hrefChanged;
	},

	_onLoadHandler: function(data){
		// summary:
		//		This is called whenever new content is being loaded
		this.isLoaded = true;
		try{
			this.onLoadDeferred.callback(data);
			this.onLoad(data);
		}catch(e){
			console.error('Error '+this.widgetId+' running custom onLoad code: ' + e.message);
		}
	},

	_onUnloadHandler: function(){
		// summary:
		//		This is called whenever the content is being unloaded
		this.isLoaded = false;
		try{
			this.onUnload();
		}catch(e){
			console.error('Error '+this.widgetId+' running custom onUnload code: ' + e.message);
		}
	},

	destroyDescendants: function(){
		// summary:
		//		Destroy all the widgets inside the ContentPane and empty containerNode

		// Make sure we call onUnload (but only when the ContentPane has real content)
		if(this.isLoaded){
			this._onUnloadHandler();
		}

		// Even if this.isLoaded == false there might still be a "Loading..." message
		// to erase, so continue...

		// For historical reasons we need to delete all widgets under this.containerNode,
		// even ones that the user has created manually.
		var setter = this._contentSetter;
		dojo.forEach(this.getChildren(), function(widget){
			if(widget.destroyRecursive){
				widget.destroyRecursive();
			}
		});
		if(setter){
			// Most of the widgets in setter.parseResults have already been destroyed, but
			// things like Menu that have been moved to <body> haven't yet
			dojo.forEach(setter.parseResults, function(widget){
				if(widget.destroyRecursive && widget.domNode && widget.domNode.parentNode == dojo.body()){
					widget.destroyRecursive();
				}
			});
			delete setter.parseResults;
		}

		// And then clear away all the DOM nodes
		dojo.html._emptyNode(this.containerNode);

		// Delete any state information we have about current contents
		delete this._singleChild;
	},

	_setContent: function(cont, isFakeContent){
		// summary:
		//		Insert the content into the container node

		// first get rid of child widgets
		this.destroyDescendants();

		// dojo.html.set will take care of the rest of the details
		// we provide an override for the error handling to ensure the widget gets the errors
		// configure the setter instance with only the relevant widget instance properties
		// NOTE: unless we hook into attr, or provide property setters for each property,
		// we need to re-configure the ContentSetter with each use
		var setter = this._contentSetter;
		if(! (setter && setter instanceof dojo.html._ContentSetter)){
			setter = this._contentSetter = new dojo.html._ContentSetter({
				node: this.containerNode,
				_onError: dojo.hitch(this, this._onError),
				onContentError: dojo.hitch(this, function(e){
					// fires if a domfault occurs when we are appending this.errorMessage
					// like for instance if domNode is a UL and we try append a DIV
					var errMess = this.onContentError(e);
					try{
						this.containerNode.innerHTML = errMess;
					}catch(e){
						console.error('Fatal '+this.id+' could not change content due to '+e.message, e);
					}
				})/*,
				_onError */
			});
		};

		var setterParams = dojo.mixin({
			cleanContent: this.cleanContent,
			extractContent: this.extractContent,
			parseContent: this.parseOnLoad,
			dir: this.dir,
			lang: this.lang
		}, this._contentSetterParams || {});

		dojo.mixin(setter, setterParams);

		setter.set( (dojo.isObject(cont) && cont.domNode) ? cont.domNode : cont );

		// setter params must be pulled afresh from the ContentPane each time
		delete this._contentSetterParams;

		if(!isFakeContent){
			// Startup each top level child widget (and they will start their children, recursively)
			dojo.forEach(this.getChildren(), function(child){
				// The parser has already called startup on all widgets *without* a getParent() method
				if(!this.parseOnLoad || child.getParent){
					child.startup();
				}
			}, this);

			// Call resize() on each of my child layout widgets,
			// or resize() on my single child layout widget...
			// either now (if I'm currently visible)
			// or when I become visible
			this._scheduleLayout();

			this._onLoadHandler(cont);
		}
	},

	_onError: function(type, err, consoleText){
		this.onLoadDeferred.errback(err);

		// shows user the string that is returned by on[type]Error
		// overide on[type]Error and return your own string to customize
		var errText = this['on' + type + 'Error'].call(this, err);
		if(consoleText){
			console.error(consoleText, err);
		}else if(errText){// a empty string won't change current content
			this._setContent(errText, true);
		}
	},

	_scheduleLayout: function(){
		// summary:
		//		Call resize() on each of my child layout widgets, either now
		//		(if I'm currently visible) or when I become visible
		if(this._isShown()){
			this._layoutChildren();
		}else{
			this._needLayout = true;
		}
	},

	_layoutChildren: function(){
		// summary:
		//		Since I am a Container widget, each of my children expects me to
		//		call resize() or layout() on them.
		// description:
		//		Should be called on initialization and also whenever we get new content
		//		(from an href, or from attr('content', ...))... but deferred until
		//		the ContentPane is visible

		if(this.doLayout){
			this._checkIfSingleChild();
		}

		if(this._singleChild && this._singleChild.resize){
			var cb = this._contentBox || dojo.contentBox(this.containerNode);

			// note: if widget has padding this._contentBox will have l and t set,
			// but don't pass them to resize() or it will doubly-offset the child
			this._singleChild.resize({w: cb.w, h: cb.h});
		}else{
			// All my child widgets are independently sized (rather than matching my size),
			// but I still need to call resize() on each child to make it layout.
			dojo.forEach(this.getChildren(), function(widget){
				if(widget.resize){
					widget.resize();
				}
			});
		}
		delete this._needLayout;
	},

	// EVENT's, should be overide-able
	onLoad: function(data){
		// summary:
		//		Event hook, is called after everything is loaded and widgetified
		// tags:
		//		callback
	},

	onUnload: function(){
		// summary:
		//		Event hook, is called before old content is cleared
		// tags:
		//		callback
	},

	onDownloadStart: function(){
		// summary:
		//		Called before download starts.
		// description:
		//		The string returned by this function will be the html
		//		that tells the user we are loading something.
		//		Override with your own function if you want to change text.
		// tags:
		//		extension
		return this.loadingMessage;
	},

	onContentError: function(/*Error*/ error){
		// summary:
		//		Called on DOM faults, require faults etc. in content.
		//
		//		In order to display an error message in the pane, return
		//		the error message from this method, as an HTML string.
		//
		//		By default (if this method is not overriden), it returns
		//		nothing, so the error message is just printed to the console.
		// tags:
		//		extension
	},

	onDownloadError: function(/*Error*/ error){
		// summary:
		//		Called when download error occurs.
		//
		//		In order to display an error message in the pane, return
		//		the error message from this method, as an HTML string.
		//
		//		Default behavior (if this method is not overriden) is to display
		//		the error message inside the pane.
		// tags:
		//		extension
		return this.errorMessage;
	},

	onDownloadEnd: function(){
		// summary:
		//		Called when download is finished.
		// tags:
		//		callback
	}
});

}

if(!dojo._hasResource["dojo.fx.Toggler"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.fx.Toggler"] = true;
dojo.provide("dojo.fx.Toggler");

dojo.declare("dojo.fx.Toggler", null, {
	// summary:
	//		A simple `dojo.Animation` toggler API.
	//
	// description:
	//		class constructor for an animation toggler. It accepts a packed
	//		set of arguments about what type of animation to use in each
	//		direction, duration, etc. All available members are mixed into 
	//		these animations from the constructor (for example, `node`, 
	//		`showDuration`, `hideDuration`). 
	//
	// example:
	//	|	var t = new dojo.fx.Toggler({
	//	|		node: "nodeId",
	//	|		showDuration: 500,
	//	|		// hideDuration will default to "200"
	//	|		showFunc: dojo.fx.wipeIn, 
	//	|		// hideFunc will default to "fadeOut"
	//	|	});
	//	|	t.show(100); // delay showing for 100ms
	//	|	// ...time passes...
	//	|	t.hide();

	// node: DomNode
	//		the node to target for the showing and hiding animations
	node: null,

	// showFunc: Function
	//		The function that returns the `dojo.Animation` to show the node
	showFunc: dojo.fadeIn,

	// hideFunc: Function	
	//		The function that returns the `dojo.Animation` to hide the node
	hideFunc: dojo.fadeOut,

	// showDuration:
	//		Time in milliseconds to run the show Animation
	showDuration: 200,

	// hideDuration:
	//		Time in milliseconds to run the hide Animation
	hideDuration: 200,

	// FIXME: need a policy for where the toggler should "be" the next
	// time show/hide are called if we're stopped somewhere in the
	// middle.
	// FIXME: also would be nice to specify individual showArgs/hideArgs mixed into
	// each animation individually. 
	// FIXME: also would be nice to have events from the animations exposed/bridged

	/*=====
	_showArgs: null,
	_showAnim: null,

	_hideArgs: null,
	_hideAnim: null,

	_isShowing: false,
	_isHiding: false,
	=====*/

	constructor: function(args){
		var _t = this;

		dojo.mixin(_t, args);
		_t.node = args.node;
		_t._showArgs = dojo.mixin({}, args);
		_t._showArgs.node = _t.node;
		_t._showArgs.duration = _t.showDuration;
		_t.showAnim = _t.showFunc(_t._showArgs);

		_t._hideArgs = dojo.mixin({}, args);
		_t._hideArgs.node = _t.node;
		_t._hideArgs.duration = _t.hideDuration;
		_t.hideAnim = _t.hideFunc(_t._hideArgs);

		dojo.connect(_t.showAnim, "beforeBegin", dojo.hitch(_t.hideAnim, "stop", true));
		dojo.connect(_t.hideAnim, "beforeBegin", dojo.hitch(_t.showAnim, "stop", true));
	},

	show: function(delay){
		// summary: Toggle the node to showing
		// delay: Integer?
		//		Ammount of time to stall playing the show animation
		return this.showAnim.play(delay || 0);
	},

	hide: function(delay){
		// summary: Toggle the node to hidden
		// delay: Integer?
		//		Ammount of time to stall playing the hide animation
		return this.hideAnim.play(delay || 0);
	}
});

}

if(!dojo._hasResource["dojo.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.fx"] = true;
dojo.provide("dojo.fx");
 // FIXME: remove this back-compat require in 2.0 
/*=====
dojo.fx = {
	// summary: Effects library on top of Base animations
};
=====*/
(function(){
	
	var d = dojo, 
		_baseObj = {
			_fire: function(evt, args){
				if(this[evt]){
					this[evt].apply(this, args||[]);
				}
				return this;
			}
		};

	var _chain = function(animations){
		this._index = -1;
		this._animations = animations||[];
		this._current = this._onAnimateCtx = this._onEndCtx = null;

		this.duration = 0;
		d.forEach(this._animations, function(a){
			this.duration += a.duration;
			if(a.delay){ this.duration += a.delay; }
		}, this);
	};
	d.extend(_chain, {
		_onAnimate: function(){
			this._fire("onAnimate", arguments);
		},
		_onEnd: function(){
			d.disconnect(this._onAnimateCtx);
			d.disconnect(this._onEndCtx);
			this._onAnimateCtx = this._onEndCtx = null;
			if(this._index + 1 == this._animations.length){
				this._fire("onEnd");
			}else{
				// switch animations
				this._current = this._animations[++this._index];
				this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
				this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
				this._current.play(0, true);
			}
		},
		play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
			if(!this._current){ this._current = this._animations[this._index = 0]; }
			if(!gotoStart && this._current.status() == "playing"){ return this; }
			var beforeBegin = d.connect(this._current, "beforeBegin", this, function(){
					this._fire("beforeBegin");
				}),
				onBegin = d.connect(this._current, "onBegin", this, function(arg){
					this._fire("onBegin", arguments);
				}),
				onPlay = d.connect(this._current, "onPlay", this, function(arg){
					this._fire("onPlay", arguments);
					d.disconnect(beforeBegin);
					d.disconnect(onBegin);
					d.disconnect(onPlay);
				});
			if(this._onAnimateCtx){
				d.disconnect(this._onAnimateCtx);
			}
			this._onAnimateCtx = d.connect(this._current, "onAnimate", this, "_onAnimate");
			if(this._onEndCtx){
				d.disconnect(this._onEndCtx);
			}
			this._onEndCtx = d.connect(this._current, "onEnd", this, "_onEnd");
			this._current.play.apply(this._current, arguments);
			return this;
		},
		pause: function(){
			if(this._current){
				var e = d.connect(this._current, "onPause", this, function(arg){
						this._fire("onPause", arguments);
						d.disconnect(e);
					});
				this._current.pause();
			}
			return this;
		},
		gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
			this.pause();
			var offset = this.duration * percent;
			this._current = null;
			d.some(this._animations, function(a){
				if(a.duration <= offset){
					this._current = a;
					return true;
				}
				offset -= a.duration;
				return false;
			});
			if(this._current){
				this._current.gotoPercent(offset / this._current.duration, andPlay);
			}
			return this;
		},
		stop: function(/*boolean?*/ gotoEnd){
			if(this._current){
				if(gotoEnd){
					for(; this._index + 1 < this._animations.length; ++this._index){
						this._animations[this._index].stop(true);
					}
					this._current = this._animations[this._index];
				}
				var e = d.connect(this._current, "onStop", this, function(arg){
						this._fire("onStop", arguments);
						d.disconnect(e);
					});
				this._current.stop();
			}
			return this;
		},
		status: function(){
			return this._current ? this._current.status() : "stopped";
		},
		destroy: function(){
			if(this._onAnimateCtx){ d.disconnect(this._onAnimateCtx); }
			if(this._onEndCtx){ d.disconnect(this._onEndCtx); }
		}
	});
	d.extend(_chain, _baseObj);

	dojo.fx.chain = function(/*dojo.Animation[]*/ animations){
		// summary: 
		//		Chain a list of `dojo.Animation`s to run in sequence
		//
		// description:
		//		Return a `dojo.Animation` which will play all passed
		//		`dojo.Animation` instances in sequence, firing its own
		//		synthesized events simulating a single animation. (eg:
		//		onEnd of this animation means the end of the chain, 
		//		not the individual animations within)
		//
		// example:
		//	Once `node` is faded out, fade in `otherNode`
		//	|	dojo.fx.chain([
		//	|		dojo.fadeIn({ node:node }),
		//	|		dojo.fadeOut({ node:otherNode })
		//	|	]).play();
		//
		return new _chain(animations) // dojo.Animation
	};

	var _combine = function(animations){
		this._animations = animations||[];
		this._connects = [];
		this._finished = 0;

		this.duration = 0;
		d.forEach(animations, function(a){
			var duration = a.duration;
			if(a.delay){ duration += a.delay; }
			if(this.duration < duration){ this.duration = duration; }
			this._connects.push(d.connect(a, "onEnd", this, "_onEnd"));
		}, this);
		
		this._pseudoAnimation = new d.Animation({curve: [0, 1], duration: this.duration});
		var self = this;
		d.forEach(["beforeBegin", "onBegin", "onPlay", "onAnimate", "onPause", "onStop", "onEnd"], 
			function(evt){
				self._connects.push(d.connect(self._pseudoAnimation, evt,
					function(){ self._fire(evt, arguments); }
				));
			}
		);
	};
	d.extend(_combine, {
		_doAction: function(action, args){
			d.forEach(this._animations, function(a){
				a[action].apply(a, args);
			});
			return this;
		},
		_onEnd: function(){
			if(++this._finished > this._animations.length){
				this._fire("onEnd");
			}
		},
		_call: function(action, args){
			var t = this._pseudoAnimation;
			t[action].apply(t, args);
		},
		play: function(/*int?*/ delay, /*Boolean?*/ gotoStart){
			this._finished = 0;
			this._doAction("play", arguments);
			this._call("play", arguments);
			return this;
		},
		pause: function(){
			this._doAction("pause", arguments);
			this._call("pause", arguments);
			return this;
		},
		gotoPercent: function(/*Decimal*/percent, /*Boolean?*/ andPlay){
			var ms = this.duration * percent;
			d.forEach(this._animations, function(a){
				a.gotoPercent(a.duration < ms ? 1 : (ms / a.duration), andPlay);
			});
			this._call("gotoPercent", arguments);
			return this;
		},
		stop: function(/*boolean?*/ gotoEnd){
			this._doAction("stop", arguments);
			this._call("stop", arguments);
			return this;
		},
		status: function(){
			return this._pseudoAnimation.status();
		},
		destroy: function(){
			d.forEach(this._connects, dojo.disconnect);
		}
	});
	d.extend(_combine, _baseObj);

	dojo.fx.combine = function(/*dojo.Animation[]*/ animations){
		// summary: 
		//		Combine a list of `dojo.Animation`s to run in parallel
		//
		// description:
		//		Combine an array of `dojo.Animation`s to run in parallel, 
		//		providing a new `dojo.Animation` instance encompasing each
		//		animation, firing standard animation events.
		//
		// example:
		//	Fade out `node` while fading in `otherNode` simultaneously
		//	|	dojo.fx.combine([
		//	|		dojo.fadeIn({ node:node }),
		//	|		dojo.fadeOut({ node:otherNode })
		//	|	]).play();
		//
		// example:
		//	When the longest animation ends, execute a function:
		//	|	var anim = dojo.fx.combine([
		//	|		dojo.fadeIn({ node: n, duration:700 }),
		//	|		dojo.fadeOut({ node: otherNode, duration: 300 })
		//	|	]);
		//	|	dojo.connect(anim, "onEnd", function(){
		//	|		// overall animation is done.
		//	|	});
		//	|	anim.play(); // play the animation
		//
		return new _combine(animations); // dojo.Animation
	};

	dojo.fx.wipeIn = function(/*Object*/ args){
		// summary:
		//		Expand a node to it's natural height.
		//
		// description:
		//		Returns an animation that will expand the
		//		node defined in 'args' object from it's current height to
		//		it's natural height (with no scrollbar).
		//		Node must have no margin/border/padding.
		//
		// args: Object
		//		A hash-map of standard `dojo.Animation` constructor properties
		//		(such as easing: node: duration: and so on)
		//
		// example:
		//	|	dojo.fx.wipeIn({
		//	|		node:"someId"
		//	|	}).play()
		var node = args.node = d.byId(args.node), s = node.style, o;

		var anim = d.animateProperty(d.mixin({
			properties: {
				height: {
					// wrapped in functions so we wait till the last second to query (in case value has changed)
					start: function(){
						// start at current [computed] height, but use 1px rather than 0
						// because 0 causes IE to display the whole panel
						o = s.overflow;
						s.overflow = "hidden";
						if(s.visibility == "hidden" || s.display == "none"){
							s.height = "1px";
							s.display = "";
							s.visibility = "";
							return 1;
						}else{
							var height = d.style(node, "height");
							return Math.max(height, 1);
						}
					},
					end: function(){
						return node.scrollHeight;
					}
				}
			}
		}, args));

		d.connect(anim, "onEnd", function(){ 
			s.height = "auto";
			s.overflow = o;
		});

		return anim; // dojo.Animation
	}

	dojo.fx.wipeOut = function(/*Object*/ args){
		// summary:
		//		Shrink a node to nothing and hide it. 
		//
		// description:
		//		Returns an animation that will shrink node defined in "args"
		//		from it's current height to 1px, and then hide it.
		//
		// args: Object
		//		A hash-map of standard `dojo.Animation` constructor properties
		//		(such as easing: node: duration: and so on)
		// 
		// example:
		//	|	dojo.fx.wipeOut({ node:"someId" }).play()
		
		var node = args.node = d.byId(args.node), s = node.style, o;
		
		var anim = d.animateProperty(d.mixin({
			properties: {
				height: {
					end: 1 // 0 causes IE to display the whole panel
				}
			}
		}, args));

		d.connect(anim, "beforeBegin", function(){
			o = s.overflow;
			s.overflow = "hidden";
			s.display = "";
		});
		d.connect(anim, "onEnd", function(){
			s.overflow = o;
			s.height = "auto";
			s.display = "none";
		});

		return anim; // dojo.Animation
	}

	dojo.fx.slideTo = function(/*Object*/ args){
		// summary:
		//		Slide a node to a new top/left position
		//
		// description:
		//		Returns an animation that will slide "node" 
		//		defined in args Object from its current position to
		//		the position defined by (args.left, args.top).
		//
		// args: Object
		//		A hash-map of standard `dojo.Animation` constructor properties
		//		(such as easing: node: duration: and so on). Special args members
		//		are `top` and `left`, which indicate the new position to slide to.
		//
		// example:
		//	|	dojo.fx.slideTo({ node: node, left:"40", top:"50", units:"px" }).play()

		var node = args.node = d.byId(args.node), 
			top = null, left = null;

		var init = (function(n){
			return function(){
				var cs = d.getComputedStyle(n);
				var pos = cs.position;
				top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0);
				left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0);
				if(pos != 'absolute' && pos != 'relative'){
					var ret = d.position(n, true);
					top = ret.y;
					left = ret.x;
					n.style.position="absolute";
					n.style.top=top+"px";
					n.style.left=left+"px";
				}
			};
		})(node);
		init();

		var anim = d.animateProperty(d.mixin({
			properties: {
				top: args.top || 0,
				left: args.left || 0
			}
		}, args));
		d.connect(anim, "beforeBegin", anim, init);

		return anim; // dojo.Animation
	}

})();

}

if(!dojo._hasResource["dijit.form.ToggleButton"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.ToggleButton"] = true;
dojo.provide("dijit.form.ToggleButton");


}

if(!dojo._hasResource["dijit.layout.StackController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.StackController"] = true;
dojo.provide("dijit.layout.StackController");







dojo.declare(
		"dijit.layout.StackController",
		[dijit._Widget, dijit._Templated, dijit._Container],
		{
			// summary:
			//		Set of buttons to select a page in a page list.
			// description:
			//		Monitors the specified StackContainer, and whenever a page is
			//		added, deleted, or selected, updates itself accordingly.

			templateString: "<span wairole='tablist' dojoAttachEvent='onkeypress' class='dijitStackController'></span>",

			// containerId: [const] String
			//		The id of the page container that I point to
			containerId: "",

			// buttonWidget: [const] String
			//		The name of the button widget to create to correspond to each page
			buttonWidget: "dijit.layout._StackButton",

			postCreate: function(){
				dijit.setWaiRole(this.domNode, "tablist");

				this.pane2button = {};		// mapping from pane id to buttons
				this.pane2handles = {};		// mapping from pane id to this.connect() handles

				// Listen to notifications from StackContainer
				this.subscribe(this.containerId+"-startup", "onStartup");
				this.subscribe(this.containerId+"-addChild", "onAddChild");
				this.subscribe(this.containerId+"-removeChild", "onRemoveChild");
				this.subscribe(this.containerId+"-selectChild", "onSelectChild");
				this.subscribe(this.containerId+"-containerKeyPress", "onContainerKeyPress");
			},

			onStartup: function(/*Object*/ info){
				// summary:
				//		Called after StackContainer has finished initializing
				// tags:
				//		private
				dojo.forEach(info.children, this.onAddChild, this);
				if(info.selected){
					// Show button corresponding to selected pane (unless selected
					// is null because there are no panes)
					this.onSelectChild(info.selected);
				}
			},

			destroy: function(){
				for(var pane in this.pane2button){
					this.onRemoveChild(dijit.byId(pane));
				}
				this.inherited(arguments);
			},

			onAddChild: function(/*dijit._Widget*/ page, /*Integer?*/ insertIndex){
				// summary:
				//		Called whenever a page is added to the container.
				//		Create button corresponding to the page.
				// tags:
				//		private

				// create an instance of the button widget
				var cls = dojo.getObject(this.buttonWidget);
				var button = new cls({
					id: this.id + "_" + page.id,
					label: page.title,
					dir: page.dir,
					lang: page.lang,
					showLabel: page.showTitle,
					iconClass: page.iconClass,
					closeButton: page.closable,
					title: page.tooltip
				});
				dijit.setWaiState(button.focusNode,"selected", "false");
				this.pane2handles[page.id] = [
					this.connect(page, 'set', function(name, value){
						var buttonAttr = {
							title: 'label',
							showTitle: 'showLabel',
							iconClass: 'iconClass',
							closable: 'closeButton',
							tooltip: 'title'
						}[name];
						if(buttonAttr){
							button.set(buttonAttr, value);
						}
					}),
					this.connect(button, 'onClick', dojo.hitch(this,"onButtonClick", page)),
					this.connect(button, 'onClickCloseButton', dojo.hitch(this,"onCloseButtonClick", page))
				];
				this.addChild(button, insertIndex);
				this.pane2button[page.id] = button;
				page.controlButton = button;	// this value might be overwritten if two tabs point to same container
				if(!this._currentChild){ // put the first child into the tab order
					button.focusNode.setAttribute("tabIndex", "0");
					dijit.setWaiState(button.focusNode, "selected", "true");
					this._currentChild = page;
				}
				// make sure all tabs have the same length
				if(!this.isLeftToRight() && dojo.isIE && this._rectifyRtlTabList){
					this._rectifyRtlTabList();
				}
			},

			onRemoveChild: function(/*dijit._Widget*/ page){
				// summary:
				//		Called whenever a page is removed from the container.
				//		Remove the button corresponding to the page.
				// tags:
				//		private

				if(this._currentChild === page){ this._currentChild = null; }
				dojo.forEach(this.pane2handles[page.id], this.disconnect, this);
				delete this.pane2handles[page.id];
				var button = this.pane2button[page.id];
				if(button){
					this.removeChild(button);
					delete this.pane2button[page.id];
					button.destroy();
				}
				delete page.controlButton;
			},

			onSelectChild: function(/*dijit._Widget*/ page){
				// summary:
				//		Called when a page has been selected in the StackContainer, either by me or by another StackController
				// tags:
				//		private

				if(!page){ return; }

				if(this._currentChild){
					var oldButton=this.pane2button[this._currentChild.id];
					oldButton.set('checked', false);
					dijit.setWaiState(oldButton.focusNode, "selected", "false");
					oldButton.focusNode.setAttribute("tabIndex", "-1");
				}

				var newButton=this.pane2button[page.id];
				newButton.set('checked', true);
				dijit.setWaiState(newButton.focusNode, "selected", "true");
				this._currentChild = page;
				newButton.focusNode.setAttribute("tabIndex", "0");
				var container = dijit.byId(this.containerId);
				dijit.setWaiState(container.containerNode, "labelledby", newButton.id);
			},

			onButtonClick: function(/*dijit._Widget*/ page){
				// summary:
				//		Called whenever one of my child buttons is pressed in an attempt to select a page
				// tags:
				//		private

				var container = dijit.byId(this.containerId);
				container.selectChild(page);
			},

			onCloseButtonClick: function(/*dijit._Widget*/ page){
				// summary:
				//		Called whenever one of my child buttons [X] is pressed in an attempt to close a page
				// tags:
				//		private

				var container = dijit.byId(this.containerId);
				container.closeChild(page);
				if(this._currentChild){
					var b = this.pane2button[this._currentChild.id];
					if(b){
						dijit.focus(b.focusNode || b.domNode);
					}
				}
			},

			// TODO: this is a bit redundant with forward, back api in StackContainer
			adjacent: function(/*Boolean*/ forward){
				// summary:
				//		Helper for onkeypress to find next/previous button
				// tags:
				//		private

				if(!this.isLeftToRight() && (!this.tabPosition || /top|bottom/.test(this.tabPosition))){ forward = !forward; }
				// find currently focused button in children array
				var children = this.getChildren();
				var current = dojo.indexOf(children, this.pane2button[this._currentChild.id]);
				// pick next button to focus on
				var offset = forward ? 1 : children.length - 1;
				return children[ (current + offset) % children.length ]; // dijit._Widget
			},

			onkeypress: function(/*Event*/ e){
				// summary:
				//		Handle keystrokes on the page list, for advancing to next/previous button
				//		and closing the current page if the page is closable.
				// tags:
				//		private

				if(this.disabled || e.altKey ){ return; }
				var forward = null;
				if(e.ctrlKey || !e._djpage){
					var k = dojo.keys;
					switch(e.charOrCode){
						case k.LEFT_ARROW:
						case k.UP_ARROW:
							if(!e._djpage){ forward = false; }
							break;
						case k.PAGE_UP:
							if(e.ctrlKey){ forward = false; }
							break;
						case k.RIGHT_ARROW:
						case k.DOWN_ARROW:
							if(!e._djpage){ forward = true; }
							break;
						case k.PAGE_DOWN:
							if(e.ctrlKey){ forward = true; }
							break;
						case k.DELETE:
							if(this._currentChild.closable){
								this.onCloseButtonClick(this._currentChild);
							}
							dojo.stopEvent(e);
							break;
						default:
							if(e.ctrlKey){
								if(e.charOrCode === k.TAB){
									this.adjacent(!e.shiftKey).onClick();
									dojo.stopEvent(e);
								}else if(e.charOrCode == "w"){
									if(this._currentChild.closable){
										this.onCloseButtonClick(this._currentChild);
									}
									dojo.stopEvent(e); // avoid browser tab closing.
								}
							}
					}
					// handle page navigation
					if(forward !== null){
						this.adjacent(forward).onClick();
						dojo.stopEvent(e);
					}
				}
			},

			onContainerKeyPress: function(/*Object*/ info){
				// summary:
				//		Called when there was a keypress on the container
				// tags:
				//		private
				info.e._djpage = info.page;
				this.onkeypress(info.e);
			}
	});


dojo.declare("dijit.layout._StackButton",
		dijit.form.ToggleButton,
		{
		// summary:
		//		Internal widget used by StackContainer.
		// description:
		//		The button-like or tab-like object you click to select or delete a page
		// tags:
		//		private

		// Override _FormWidget.tabIndex.
		// StackContainer buttons are not in the tab order by default.
		// Probably we should be calling this.startupKeyNavChildren() instead.
		tabIndex: "-1",

		postCreate: function(/*Event*/ evt){
			dijit.setWaiRole((this.focusNode || this.domNode), "tab");
			this.inherited(arguments);
		},

		onClick: function(/*Event*/ evt){
			// summary:
			//		This is for TabContainer where the tabs are <span> rather than button,
			//		so need to set focus explicitly (on some browsers)
			//		Note that you shouldn't override this method, but you can connect to it.
			dijit.focus(this.focusNode);

			// ... now let StackController catch the event and tell me what to do
		},

		onClickCloseButton: function(/*Event*/ evt){
			// summary:
			//		StackContainer connects to this function; if your widget contains a close button
			//		then clicking it should call this function.
			//		Note that you shouldn't override this method, but you can connect to it.
			evt.stopPropagation();
		}
	});


}

if(!dojo._hasResource["dijit.layout.StackContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.StackContainer"] = true;
dojo.provide("dijit.layout.StackContainer");






dojo.declare(
	"dijit.layout.StackContainer",
	dijit.layout._LayoutWidget,
	{
	// summary:
	//		A container that has multiple children, but shows only
	//		one child at a time
	//
	// description:
	//		A container for widgets (ContentPanes, for example) That displays
	//		only one Widget at a time.
	//
	//		Publishes topics [widgetId]-addChild, [widgetId]-removeChild, and [widgetId]-selectChild
	//
	//		Can be base class for container, Wizard, Show, etc.

	// doLayout: Boolean
	//		If true, change the size of my currently displayed child to match my size
	doLayout: true,

	// persist: Boolean
	//		Remembers the selected child across sessions
	persist: false,

	baseClass: "dijitStackContainer",

/*=====
	// selectedChildWidget: [readonly] dijit._Widget
	//		References the currently selected child widget, if any.
	//		Adjust selected child with selectChild() method.
	selectedChildWidget: null,
=====*/

	postCreate: function(){
		this.inherited(arguments);
		dojo.addClass(this.domNode, "dijitLayoutContainer");
		dijit.setWaiRole(this.containerNode, "tabpanel");
		this.connect(this.domNode, "onkeypress", this._onKeyPress);
	},

	startup: function(){
		if(this._started){ return; }

		var children = this.getChildren();

		// Setup each page panel to be initially hidden
		dojo.forEach(children, this._setupChild, this);

		// Figure out which child to initially display, defaulting to first one
		if(this.persist){
			this.selectedChildWidget = dijit.byId(dojo.cookie(this.id + "_selectedChild"));
		}else{
			dojo.some(children, function(child){
				if(child.selected){
					this.selectedChildWidget = child;
				}
				return child.selected;
			}, this);
		}
		var selected = this.selectedChildWidget;
		if(!selected && children[0]){
			selected = this.selectedChildWidget = children[0];
			selected.selected = true;
		}

		// Publish information about myself so any StackControllers can initialize.
		// This needs to happen before this.inherited(arguments) so that for
		// TabContainer, this._contentBox doesn't include the space for the tab labels.
		dojo.publish(this.id+"-startup", [{children: children, selected: selected}]);

		// Startup each child widget, and do initial layout like setting this._contentBox,
		// then calls this.resize() which does the initial sizing on the selected child.
		this.inherited(arguments);
	},

	resize: function(){
		// Resize is called when we are first made visible (it's called from startup()
		// if we are initially visible).   If this is the first time we've been made
		// visible then show our first child.
		var selected = this.selectedChildWidget;
		if(selected && !this._hasBeenShown){
			this._hasBeenShown = true;
			this._showChild(selected);
		}
		this.inherited(arguments);
	},

	_setupChild: function(/*dijit._Widget*/ child){
		// Overrides _LayoutWidget._setupChild()

		this.inherited(arguments);

		dojo.removeClass(child.domNode, "dijitVisible");
		dojo.addClass(child.domNode, "dijitHidden");

		// remove the title attribute so it doesn't show up when i hover
		// over a node
		child.domNode.title = "";
	},

	addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
		// Overrides _Container.addChild() to do layout and publish events

		this.inherited(arguments);

		if(this._started){
			dojo.publish(this.id+"-addChild", [child, insertIndex]);

			// in case the tab titles have overflowed from one line to two lines
			// (or, if this if first child, from zero lines to one line)
			// TODO: w/ScrollingTabController this is no longer necessary, although
			// ScrollTabController.resize() does need to get called to show/hide
			// the navigation buttons as appropriate, but that's handled in ScrollingTabController.onAddChild()
			this.layout();

			// if this is the first child, then select it
			if(!this.selectedChildWidget){
				this.selectChild(child);
			}
		}
	},

	removeChild: function(/*dijit._Widget*/ page){
		// Overrides _Container.removeChild() to do layout and publish events

		this.inherited(arguments);

		if(this._started){
			// this will notify any tablists to remove a button; do this first because it may affect sizing
			dojo.publish(this.id + "-removeChild", [page]);
		}

		// If we are being destroyed than don't run the code below (to select another page), because we are deleting
		// every page one by one
		if(this._beingDestroyed){ return; }

		// Select new page to display, also updating TabController to show the respective tab.
		// Do this before layout call because it can affect the height of the TabController.
		if(this.selectedChildWidget === page){
			this.selectedChildWidget = undefined;
			if(this._started){
				var children = this.getChildren();
				if(children.length){
					this.selectChild(children[0]);
				}
			}
		}

		if(this._started){
			// In case the tab titles now take up one line instead of two lines
			// (note though that ScrollingTabController never overflows to multiple lines),
			// or the height has changed slightly because of addition/removal of tab which close icon
			this.layout();
		}
	},

	selectChild: function(/*dijit._Widget|String*/ page, /*Boolean*/ animate){
		// summary:
		//		Show the given widget (which must be one of my children)
		// page:
		//		Reference to child widget or id of child widget

		page = dijit.byId(page);

		if(this.selectedChildWidget != page){
			// Deselect old page and select new one
			this._transition(page, this.selectedChildWidget, animate);
			this.selectedChildWidget = page;
			dojo.publish(this.id+"-selectChild", [page]);

			if(this.persist){
				dojo.cookie(this.id + "_selectedChild", this.selectedChildWidget.id);
			}
		}
	},

	_transition: function(/*dijit._Widget*/newWidget, /*dijit._Widget*/oldWidget){
		// summary:
		//		Hide the old widget and display the new widget.
		//		Subclasses should override this.
		// tags:
		//		protected extension
		if(oldWidget){
			this._hideChild(oldWidget);
		}
		this._showChild(newWidget);

		// Size the new widget, in case this is the first time it's being shown,
		// or I have been resized since the last time it was shown.
		// Note that page must be visible for resizing to work.
		if(newWidget.resize){
			if(this.doLayout){
				newWidget.resize(this._containerContentBox || this._contentBox);
			}else{
				// the child should pick it's own size but we still need to call resize()
				// (with no arguments) to let the widget lay itself out
				newWidget.resize();
			}
		}
	},

	_adjacent: function(/*Boolean*/ forward){
		// summary:
		//		Gets the next/previous child widget in this container from the current selection.
		var children = this.getChildren();
		var index = dojo.indexOf(children, this.selectedChildWidget);
		index += forward ? 1 : children.length - 1;
		return children[ index % children.length ]; // dijit._Widget
	},

	forward: function(){
		// summary:
		//		Advance to next page.
		this.selectChild(this._adjacent(true), true);
	},

	back: function(){
		// summary:
		//		Go back to previous page.
		this.selectChild(this._adjacent(false), true);
	},

	_onKeyPress: function(e){
		dojo.publish(this.id+"-containerKeyPress", [{ e: e, page: this}]);
	},

	layout: function(){
		// Implement _LayoutWidget.layout() virtual method.
		if(this.doLayout && this.selectedChildWidget && this.selectedChildWidget.resize){
			this.selectedChildWidget.resize(this._containerContentBox || this._contentBox);
		}
	},

	_showChild: function(/*dijit._Widget*/ page){
		// summary:
		//		Show the specified child by changing it's CSS, and call _onShow()/onShow() so
		//		it can do any updates it needs regarding loading href's etc.
		var children = this.getChildren();
		page.isFirstChild = (page == children[0]);
		page.isLastChild = (page == children[children.length-1]);
		page.selected = true;

		dojo.removeClass(page.domNode, "dijitHidden");
		dojo.addClass(page.domNode, "dijitVisible");

		page._onShow();
	},

	_hideChild: function(/*dijit._Widget*/ page){
		// summary:
		//		Hide the specified child by changing it's CSS, and call _onHide() so
		//		it's notified.
		page.selected=false;
		dojo.removeClass(page.domNode, "dijitVisible");
		dojo.addClass(page.domNode, "dijitHidden");

		page.onHide();
	},

	closeChild: function(/*dijit._Widget*/ page){
		// summary:
		//		Callback when user clicks the [X] to remove a page.
		//		If onClose() returns true then remove and destroy the child.
		// tags:
		//		private
		var remove = page.onClose(this, page);
		if(remove){
			this.removeChild(page);
			// makes sure we can clean up executeScripts in ContentPane onUnLoad
			page.destroyRecursive();
		}
	},

	destroyDescendants: function(/*Boolean*/preserveDom){
		dojo.forEach(this.getChildren(), function(child){
			this.removeChild(child);
			child.destroyRecursive(preserveDom);
		}, this);
	}
});

// For back-compat, remove for 2.0



// These arguments can be specified for the children of a StackContainer.
// Since any widget can be specified as a StackContainer child, mix them
// into the base widget class.  (This is a hack, but it's effective.)
dojo.extend(dijit._Widget, {
	// selected: Boolean
	//		Parameter for children of `dijit.layout.StackContainer` or subclasses.
	//		Specifies that this widget should be the initially displayed pane.
	//		Note: to change the selected child use `dijit.layout.StackContainer.selectChild`
	selected: false,

	// closable: Boolean
	//		Parameter for children of `dijit.layout.StackContainer` or subclasses.
	//		True if user can close (destroy) this child, such as (for example) clicking the X on the tab.
	closable: false,

	// iconClass: String
	//		Parameter for children of `dijit.layout.StackContainer` or subclasses.
	//		CSS Class specifying icon to use in label associated with this pane.
	iconClass: "",

	// showTitle: Boolean
	//		Parameter for children of `dijit.layout.StackContainer` or subclasses.
	//		When true, display title of this widget as tab label etc., rather than just using
	//		icon specified in iconClass
	showTitle: true
});

}

if(!dojo._hasResource["dijit.layout.AccordionPane"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.AccordionPane"] = true;
dojo.provide("dijit.layout.AccordionPane");



dojo.declare("dijit.layout.AccordionPane", dijit.layout.ContentPane, {
	// summary:
	//		Deprecated widget.   Use `dijit.layout.ContentPane` instead.
	// tags:
	//		deprecated

	constructor: function(){
		dojo.deprecated("dijit.layout.AccordionPane deprecated, use ContentPane instead", "", "2.0");
	},

	onSelected: function(){
		// summary:
		//		called when this pane is selected
	}
});

}

if(!dojo._hasResource["dijit.layout.AccordionContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.AccordionContainer"] = true;
dojo.provide("dijit.layout.AccordionContainer");









	// for back compat, remove for 2.0

dojo.declare(
	"dijit.layout.AccordionContainer",
	dijit.layout.StackContainer,
	{
		// summary:
		//		Holds a set of panes where every pane's title is visible, but only one pane's content is visible at a time,
		//		and switching between panes is visualized by sliding the other panes up/down.
		// example:
		//	| 	<div dojoType="dijit.layout.AccordionContainer">
		//	|		<div dojoType="dijit.layout.ContentPane" title="pane 1">
		//	|		</div>
		//	|		<div dojoType="dijit.layout.ContentPane" title="pane 2">
		//	|			<p>This is some text</p>
		//	|		</div>
		//	|	</div>

		// duration: Integer
		//		Amount of time (in ms) it takes to slide panes
		duration: dijit.defaultDuration,

		// buttonWidget: [const] String
		//		The name of the widget used to display the title of each pane
		buttonWidget: "dijit.layout._AccordionButton",

		// _verticalSpace: Number
		//		Pixels of space available for the open pane
		//		(my content box size minus the cumulative size of all the title bars)
		_verticalSpace: 0,

		baseClass: "dijitAccordionContainer",

		postCreate: function(){
			this.domNode.style.overflow = "hidden";
			this.inherited(arguments);
			dijit.setWaiRole(this.domNode, "tablist");
		},

		startup: function(){
			if(this._started){ return; }
			this.inherited(arguments);
			if(this.selectedChildWidget){
				var style = this.selectedChildWidget.containerNode.style;
				style.display = "";
				style.overflow = "auto";
				this.selectedChildWidget._wrapperWidget.set("selected", true);
			}
		},

		_getTargetHeight: function(/* Node */ node){
			// summary:
			//		For the given node, returns the height that should be
			//		set to achieve our vertical space (subtract any padding
			//		we may have).
			//
			//		This is used by the animations.
			//
			//		TODO: I don't think this works correctly in IE quirks when an elements
			//		style.height including padding and borders
			var cs = dojo.getComputedStyle(node);
			return Math.max(this._verticalSpace - dojo._getPadBorderExtents(node, cs).h - dojo._getMarginExtents(node, cs).h, 0);
		},

		layout: function(){
			// Implement _LayoutWidget.layout() virtual method.
			// Set the height of the open pane based on what room remains.

			var openPane = this.selectedChildWidget;
			
			if(!openPane){ return;}

			var openPaneContainer = openPane._wrapperWidget.domNode,
				openPaneContainerMargin = dojo._getMarginExtents(openPaneContainer),
				openPaneContainerPadBorder = dojo._getPadBorderExtents(openPaneContainer),
				mySize = this._contentBox;

			// get cumulative height of all the unselected title bars
			var totalCollapsedHeight = 0;
			dojo.forEach(this.getChildren(), function(child){
	            if(child != openPane){
					totalCollapsedHeight += dojo.marginBox(child._wrapperWidget.domNode).h;
				}
			});
			this._verticalSpace = mySize.h - totalCollapsedHeight - openPaneContainerMargin.h 
			 	- openPaneContainerPadBorder.h - openPane._buttonWidget.getTitleHeight();

			// Memo size to make displayed child
			this._containerContentBox = {
				h: this._verticalSpace,
				w: this._contentBox.w - openPaneContainerMargin.w - openPaneContainerPadBorder.w
			};

			if(openPane){
				openPane.resize(this._containerContentBox);
			}
		},

		_setupChild: function(child){
			// Overrides _LayoutWidget._setupChild().
			// Put wrapper widget around the child widget, showing title

			child._wrapperWidget = new dijit.layout._AccordionInnerContainer({
				contentWidget: child,
				buttonWidget: this.buttonWidget,
				id: child.id + "_wrapper",
				dir: child.dir,
				lang: child.lang,
				parent: this
			});

			this.inherited(arguments);
		},

		addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){	
			if(this._started){
				// Adding a child to a started Accordion is complicated because children have
				// wrapper widgets.  Default code path (calling this.inherited()) would add
				// the new child inside another child's wrapper.

				// First add in child as a direct child of this AccordionContainer
				dojo.place(child.domNode, this.containerNode, insertIndex);

				if(!child._started){
					child.startup();
				}
				
				// Then stick the wrapper widget around the child widget
				this._setupChild(child);

				// Code below copied from StackContainer	
				dojo.publish(this.id+"-addChild", [child, insertIndex]);
				this.layout();
				if(!this.selectedChildWidget){
					this.selectChild(child);
				}
			}else{
				// We haven't been started yet so just add in the child widget directly,
				// and the wrapper will be created on startup()
				this.inherited(arguments);
			}
		},

		removeChild: function(child){
			// Overrides _LayoutWidget.removeChild().

			// destroy wrapper widget first, before StackContainer.getChildren() call
			child._wrapperWidget.destroy();
			delete child._wrapperWidget;
			dojo.removeClass(child.domNode, "dijitHidden");

			this.inherited(arguments);
		},

		getChildren: function(){
			// Overrides _Container.getChildren() to return content panes rather than internal AccordionInnerContainer panes
			return dojo.map(this.inherited(arguments), function(child){
				return child.declaredClass == "dijit.layout._AccordionInnerContainer" ? child.contentWidget : child;
			}, this);
		},

		destroy: function(){
			dojo.forEach(this.getChildren(), function(child){
				child._wrapperWidget.destroy();
			});
			this.inherited(arguments);
		},

		_transition: function(/*dijit._Widget?*/newWidget, /*dijit._Widget?*/oldWidget, /*Boolean*/ animate){
			// Overrides StackContainer._transition() to provide sliding of title bars etc.

//TODO: should be able to replace this with calls to slideIn/slideOut
			if(this._inTransition){ return; }
			var animations = [];
			var paneHeight = this._verticalSpace;
			if(newWidget){
				newWidget._wrapperWidget.set("selected", true);

				this._showChild(newWidget);	// prepare widget to be slid in

				// Size the new widget, in case this is the first time it's being shown,
				// or I have been resized since the last time it was shown.
				// Note that page must be visible for resizing to work.
				if(this.doLayout && newWidget.resize){
					newWidget.resize(this._containerContentBox);
				}

				var newContents = newWidget.domNode;
				dojo.addClass(newContents, "dijitVisible");
				dojo.removeClass(newContents, "dijitHidden");
				
				if(animate){
					var newContentsOverflow = newContents.style.overflow;
					newContents.style.overflow = "hidden";
					animations.push(dojo.animateProperty({
						node: newContents,
						duration: this.duration,
						properties: {
							height: { start: 1, end: this._getTargetHeight(newContents) }
						},
						onEnd: function(){
							newContents.style.overflow = newContentsOverflow;

							// Kick IE to workaround layout bug, see #11415
							if(dojo.isIE){
								setTimeout(function(){
									dojo.removeClass(newContents.parentNode, "dijitAccordionInnerContainerFocused");
									setTimeout(function(){
										dojo.addClass(newContents.parentNode, "dijitAccordionInnerContainerFocused");
									}, 0);
								}, 0);
							}
						}
					}));
				}
			}
			if(oldWidget){
				oldWidget._wrapperWidget.set("selected", false);
				var oldContents = oldWidget.domNode;
				if(animate){
					var oldContentsOverflow = oldContents.style.overflow;
					oldContents.style.overflow = "hidden";
					animations.push(dojo.animateProperty({
						node: oldContents,
						duration: this.duration,
						properties: {
							height: { start: this._getTargetHeight(oldContents), end: 1 }
						},
						onEnd: function(){
							dojo.addClass(oldContents, "dijitHidden");
							dojo.removeClass(oldContents, "dijitVisible");
							oldContents.style.overflow = oldContentsOverflow;
							if(oldWidget.onHide){
								oldWidget.onHide();
							}
						}
					}));
				}else{
					dojo.addClass(oldContents, "dijitHidden");
					dojo.removeClass(oldContents, "dijitVisible");
					if(oldWidget.onHide){
						oldWidget.onHide();
					}
				}
			}

			if(animate){
				this._inTransition = true;
				var combined = dojo.fx.combine(animations);
				combined.onEnd = dojo.hitch(this, function(){
					delete this._inTransition;
				});
				combined.play();
			}			
		},

		// note: we are treating the container as controller here
		_onKeyPress: function(/*Event*/ e, /*dijit._Widget*/ fromTitle){
			// summary:
			//		Handle keypress events
			// description:
			//		This is called from a handler on AccordionContainer.domNode
			//		(setup in StackContainer), and is also called directly from
			//		the click handler for accordion labels
			if(this._inTransition || this.disabled || e.altKey || !(fromTitle || e.ctrlKey)){
				if(this._inTransition){
					dojo.stopEvent(e);
				}
				return;
			}
			var k = dojo.keys,
				c = e.charOrCode;
			if((fromTitle && (c == k.LEFT_ARROW || c == k.UP_ARROW)) ||
					(e.ctrlKey && c == k.PAGE_UP)){
				this._adjacent(false)._buttonWidget._onTitleClick();
				dojo.stopEvent(e);
			}else if((fromTitle && (c == k.RIGHT_ARROW || c == k.DOWN_ARROW)) ||
					(e.ctrlKey && (c == k.PAGE_DOWN || c == k.TAB))){
				this._adjacent(true)._buttonWidget._onTitleClick();
				dojo.stopEvent(e);
			}
		}
	}
);

dojo.declare("dijit.layout._AccordionInnerContainer",
	[dijit._Widget, dijit._CssStateMixin], {
		// summary:
		//		Internal widget placed as direct child of AccordionContainer.containerNode.
		//		When other widgets are added as children to an AccordionContainer they are wrapped in
		//		this widget.
		
		// buttonWidget: String
		//		Name of class to use to instantiate title
		//		(Wish we didn't have a separate widget for just the title but maintaining it
		//		for backwards compatibility, is it worth it?)
/*=====
		 buttonWidget: null,
=====*/
		// contentWidget: dijit._Widget
		//		Pointer to the real child widget
/*=====
	 	contentWidget: null,
=====*/

		baseClass: "dijitAccordionInnerContainer",

		// tell nested layout widget that we will take care of sizing
		isContainer: true,
		isLayoutContainer: true,

		buildRendering: function(){			
			// Create wrapper div, placed where the child is now
			this.domNode = dojo.place("<div class='" + this.baseClass + "'>", this.contentWidget.domNode, "after");
			
			// wrapper div's first child is the button widget (ie, the title bar)
			var child = this.contentWidget,
				cls = dojo.getObject(this.buttonWidget);
			this.button = child._buttonWidget = (new cls({
				contentWidget: child,
				label: child.title,
				title: child.tooltip,
				dir: child.dir,
				lang: child.lang,
				iconClass: child.iconClass,
				id: child.id + "_button",
				parent: this.parent
			})).placeAt(this.domNode);
			
			// and then the actual content widget (changing it from prior-sibling to last-child)
			dojo.place(this.contentWidget.domNode, this.domNode);
		},

		postCreate: function(){
			this.inherited(arguments);
			this.connect(this.contentWidget, 'set', function(name, value){
				var mappedName = {title: "label", tooltip: "title", iconClass: "iconClass"}[name];
				if(mappedName){
					this.button.set(mappedName, value);
				}
			}, this);
		},

		_setSelectedAttr: function(/*Boolean*/ isSelected){
			this.selected = isSelected;
			this.button.set("selected", isSelected);
			if(isSelected){
				var cw = this.contentWidget;
				if(cw.onSelected){ cw.onSelected(); }
			}
		},

		startup: function(){
			// Called by _Container.addChild()
			this.contentWidget.startup();
		},

		destroy: function(){
			this.button.destroyRecursive();
			
			delete this.contentWidget._buttonWidget;
			delete this.contentWidget._wrapperWidget;

			this.inherited(arguments);
		},
		
		destroyDescendants: function(){
			// since getChildren isn't working for me, have to code this manually
			this.contentWidget.destroyRecursive();
		}
});

dojo.declare("dijit.layout._AccordionButton",
	[dijit._Widget, dijit._Templated, dijit._CssStateMixin],
	{
	// summary:
	//		The title bar to click to open up an accordion pane.
	//		Internal widget used by AccordionContainer.
	// tags:
	//		private

	templateString: dojo.cache("dijit.layout", "templates/AccordionButton.html", "<div dojoAttachEvent='onclick:_onTitleClick' class='dijitAccordionTitle'>\n\t<div dojoAttachPoint='titleNode,focusNode' dojoAttachEvent='onkeypress:_onTitleKeyPress'\n\t\t\tclass='dijitAccordionTitleFocus' wairole=\"tab\" waiState=\"expanded-false\"\n\t\t><span class='dijitInline dijitAccordionArrow' waiRole=\"presentation\"></span\n\t\t><span class='arrowTextUp' waiRole=\"presentation\">+</span\n\t\t><span class='arrowTextDown' waiRole=\"presentation\">-</span\n\t\t><img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' style=\"vertical-align: middle\" waiRole=\"presentation\"/>\n\t\t<span waiRole=\"presentation\" dojoAttachPoint='titleTextNode' class='dijitAccordionText'></span>\n\t</div>\n</div>\n"),
	attributeMap: dojo.mixin(dojo.clone(dijit.layout.ContentPane.prototype.attributeMap), {
		label: {node: "titleTextNode", type: "innerHTML" },
		title: {node: "titleTextNode", type: "attribute", attribute: "title"},
		iconClass: { node: "iconNode", type: "class" }
	}),

	baseClass: "dijitAccordionTitle",

	getParent: function(){
		// summary:
		//		Returns the AccordionContainer parent.
		// tags:
		//		private
		return this.parent;
	},

	postCreate: function(){
		this.inherited(arguments);
		dojo.setSelectable(this.domNode, false);
		var titleTextNodeId = dojo.attr(this.domNode,'id').replace(' ','_');
		dojo.attr(this.titleTextNode, "id", titleTextNodeId+"_title");
		dijit.setWaiState(this.focusNode, "labelledby", dojo.attr(this.titleTextNode, "id"));
	},

	getTitleHeight: function(){
		// summary:
		//		Returns the height of the title dom node.
		return dojo.marginBox(this.domNode).h;	// Integer
	},

	// TODO: maybe the parent should set these methods directly rather than forcing the code
	// into the button widget?
	_onTitleClick: function(){
		// summary:
		//		Callback when someone clicks my title.
		var parent = this.getParent();
		if(!parent._inTransition){
			parent.selectChild(this.contentWidget, true);
			dijit.focus(this.focusNode);
		}
	},

	_onTitleKeyPress: function(/*Event*/ evt){
		return this.getParent()._onKeyPress(evt, this.contentWidget);
	},

	_setSelectedAttr: function(/*Boolean*/ isSelected){
		this.selected = isSelected;
		dijit.setWaiState(this.focusNode, "expanded", isSelected);
		dijit.setWaiState(this.focusNode, "selected", isSelected);
		this.focusNode.setAttribute("tabIndex", isSelected ? "0" : "-1");
	}
});

}

if(!dojo._hasResource["dijit.form.CheckBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.CheckBox"] = true;
dojo.provide("dijit.form.CheckBox");



dojo.declare(
	"dijit.form.CheckBox",
	dijit.form.ToggleButton,
	{
		// summary:
		// 		Same as an HTML checkbox, but with fancy styling.
		//
		// description:
		//		User interacts with real html inputs.
		//		On onclick (which occurs by mouse click, space-bar, or
		//		using the arrow keys to switch the selected radio button),
		//		we update the state of the checkbox/radio.
		//
		//		There are two modes:
		//			1. High contrast mode
		//			2. Normal mode
		//
		//		In case 1, the regular html inputs are shown and used by the user.
		//		In case 2, the regular html inputs are invisible but still used by
		//		the user. They are turned quasi-invisible and overlay the background-image.

		templateString: dojo.cache("dijit.form", "templates/CheckBox.html", "<div class=\"dijit dijitReset dijitInline\" waiRole=\"presentation\"\n\t><input\n\t \t${!nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\n\t\tdojoAttachPoint=\"focusNode\"\n\t \tdojoAttachEvent=\"onclick:_onClick\"\n/></div>\n"),

		baseClass: "dijitCheckBox",

		// type: [private] String
		//		type attribute on <input> node.
		//		Overrides `dijit.form.Button.type`.   Users should not change this value.
		type: "checkbox",

		// value: String
		//		As an initialization parameter, equivalent to value field on normal checkbox
		//		(if checked, the value is passed as the value when form is submitted).
		//
		//		However, attr('value') will return either the string or false depending on
		//		whether or not the checkbox is checked.
		//
		//		attr('value', string) will check the checkbox and change the value to the
		//		specified string
		//
		//		attr('value', boolean) will change the checked state.
		value: "on",

		// readOnly: Boolean
		//		Should this widget respond to user input?
		//		In markup, this is specified as "readOnly".
		//		Similar to disabled except readOnly form values are submitted.
		readOnly: false,
		
		// the attributeMap should inherit from dijit.form._FormWidget.prototype.attributeMap 
		// instead of ToggleButton as the icon mapping has no meaning for a CheckBox
		attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
			readOnly: "focusNode"
		}),

		_setReadOnlyAttr: function(/*Boolean*/ value){
			this.readOnly = value;
			dojo.attr(this.focusNode, 'readOnly', value);
			dijit.setWaiState(this.focusNode, "readonly", value);
		},

		_setValueAttr: function(/*String or Boolean*/ newValue, /*Boolean*/ priorityChange){
			// summary:
			//		Handler for value= attribute to constructor, and also calls to
			//		attr('value', val).
			// description:
			//		During initialization, just saves as attribute to the <input type=checkbox>.
			//
			//		After initialization,
			//		when passed a boolean, controls whether or not the CheckBox is checked.
			//		If passed a string, changes the value attribute of the CheckBox (the one
			//		specified as "value" when the CheckBox was constructed (ex: <input
			//		dojoType="dijit.CheckBox" value="chicken">)
			if(typeof newValue == "string"){
				this.value = newValue;
				dojo.attr(this.focusNode, 'value', newValue);
				newValue = true;
			}
			if(this._created){
				this.set('checked', newValue, priorityChange);
			}
		},
		_getValueAttr: function(){
			// summary:
			//		Hook so attr('value') works.
			// description:
			//		If the CheckBox is checked, returns the value attribute.
			//		Otherwise returns false.
			return (this.checked ? this.value : false);
		},

		// Override dijit.form.Button._setLabelAttr() since we don't even have a containerNode.
		// Normally users won't try to set label, except when CheckBox or RadioButton is the child of a dojox.layout.TabContainer
		_setLabelAttr: undefined,

		postMixInProperties: function(){
			if(this.value == ""){
				this.value = "on";
			}

			// Need to set initial checked state as part of template, so that form submit works.
			// dojo.attr(node, "checked", bool) doesn't work on IEuntil node has been attached
			// to <body>, see #8666
			this.checkedAttrSetting = this.checked ? "checked" : "";

			this.inherited(arguments);
		},

		 _fillContent: function(/*DomNode*/ source){
			// Override Button::_fillContent() since it doesn't make sense for CheckBox,
			// since CheckBox doesn't even have a container
		},

		reset: function(){
			// Override ToggleButton.reset()

			this._hasBeenBlurred = false;

			this.set('checked', this.params.checked || false);

			// Handle unlikely event that the <input type=checkbox> value attribute has changed
			this.value = this.params.value || "on";
			dojo.attr(this.focusNode, 'value', this.value);
		},

		_onFocus: function(){
			if(this.id){
				dojo.query("label[for='"+this.id+"']").addClass("dijitFocusedLabel");
			}
			this.inherited(arguments);
		},

		_onBlur: function(){
			if(this.id){
				dojo.query("label[for='"+this.id+"']").removeClass("dijitFocusedLabel");
			}
			this.inherited(arguments);
		},

		_onClick: function(/*Event*/ e){
			// summary:
			//		Internal function to handle click actions - need to check
			//		readOnly, since button no longer does that check.
			if(this.readOnly){
				return false;
			}
			return this.inherited(arguments);
		}
	}
);

dojo.declare(
	"dijit.form.RadioButton",
	dijit.form.CheckBox,
	{
		// summary:
		// 		Same as an HTML radio, but with fancy styling.

		type: "radio",
		baseClass: "dijitRadio",

		_setCheckedAttr: function(/*Boolean*/ value){
			// If I am being checked then have to deselect currently checked radio button
			this.inherited(arguments);
			if(!this._created){ return; }
			if(value){
				var _this = this;
				// search for radio buttons with the same name that need to be unchecked
				dojo.query("INPUT[type=radio]", this.focusNode.form || dojo.doc).forEach( // can't use name= since dojo.query doesn't support [] in the name
					function(inputNode){
						if(inputNode.name == _this.name && inputNode != _this.focusNode && inputNode.form == _this.focusNode.form){
							var widget = dijit.getEnclosingWidget(inputNode);
							if(widget && widget.checked){
								widget.set('checked', false);
							}
						}
					}
				);
			}
		},

		_clicked: function(/*Event*/ e){
			if(!this.checked){
				this.set('checked', true);
			}
		}
	}
);

}

if(!dojo._hasResource["com.sixnet.services.widgets.LabeledCheckBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.LabeledCheckBox"] = true;
dojo.provide("com.sixnet.services.widgets.LabeledCheckBox");


dojo.declare('com.sixnet.services.widgets.LabeledCheckBox',[dijit.form.CheckBox], {
	templateString:dojo.cache("com.sixnet.services.widgets", "templates/LabeledCheckBox.html", "<div style=\"float:left; margin-left:5px; width:15px;\" class=\"dijitReset dijitInline\" waiRole=\"presentation\">\n\t<input\n\t \t${nameAttrSetting} type=\"${type}\" ${checkedAttrSetting}\n\t\tclass=\"dijitReset dijitCheckBoxInput\"\n\t\tdojoAttachPoint=\"focusNode\"\n\t\tdojoAttachEvent=\"onclick:_onClick\"\n/></div>\n")
});

}

if(!dojo._hasResource["dojo.data.util.filter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.data.util.filter"] = true;
dojo.provide("dojo.data.util.filter");

dojo.data.util.filter.patternToRegExp = function(/*String*/pattern, /*boolean?*/ ignoreCase){
	//	summary:  
	//		Helper function to convert a simple pattern to a regular expression for matching.
	//	description:
	//		Returns a regular expression object that conforms to the defined conversion rules.
	//		For example:  
	//			ca*   -> /^ca.*$/
	//			*ca*  -> /^.*ca.*$/
	//			*c\*a*  -> /^.*c\*a.*$/
	//			*c\*a?*  -> /^.*c\*a..*$/
	//			and so on.
	//
	//	pattern: string
	//		A simple matching pattern to convert that follows basic rules:
	//			* Means match anything, so ca* means match anything starting with ca
	//			? Means match single character.  So, b?b will match to bob and bab, and so on.
	//      	\ is an escape character.  So for example, \* means do not treat * as a match, but literal character *.
	//				To use a \ as a character in the string, it must be escaped.  So in the pattern it should be 
	//				represented by \\ to be treated as an ordinary \ character instead of an escape.
	//
	//	ignoreCase:
	//		An optional flag to indicate if the pattern matching should be treated as case-sensitive or not when comparing
	//		By default, it is assumed case sensitive.

	var rxp = "^";
	var c = null;
	for(var i = 0; i < pattern.length; i++){
		c = pattern.charAt(i);
		switch(c){
			case '\\':
				rxp += c;
				i++;
				rxp += pattern.charAt(i);
				break;
			case '*':
				rxp += ".*"; break;
			case '?':
				rxp += "."; break;
			case '$':
			case '^':
			case '/':
			case '+':
			case '.':
			case '|':
			case '(':
			case ')':
			case '{':
			case '}':
			case '[':
			case ']':
				rxp += "\\"; //fallthrough
			default:
				rxp += c;
		}
	}
	rxp += "$";
	if(ignoreCase){
		return new RegExp(rxp,"mi"); //RegExp
	}else{
		return new RegExp(rxp,"m"); //RegExp
	}
	
};

}

if(!dojo._hasResource["dojo.data.util.sorter"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.data.util.sorter"] = true;
dojo.provide("dojo.data.util.sorter");

dojo.data.util.sorter.basicComparator = function(	/*anything*/ a, 
													/*anything*/ b){
	//	summary:  
	//		Basic comparision function that compares if an item is greater or less than another item
	//	description:  
	//		returns 1 if a > b, -1 if a < b, 0 if equal.
	//		'null' values (null, undefined) are treated as larger values so that they're pushed to the end of the list.
	//		And compared to each other, null is equivalent to undefined.
	
	//null is a problematic compare, so if null, we set to undefined.
	//Makes the check logic simple, compact, and consistent
	//And (null == undefined) === true, so the check later against null
	//works for undefined and is less bytes.
	var r = -1;
	if(a === null){
		a = undefined;
	}
	if(b === null){
		b = undefined;
	}
	if(a == b){
		r = 0; 
	}else if(a > b || a == null){
		r = 1; 
	}
	return r; //int {-1,0,1}
};

dojo.data.util.sorter.createSortFunction = function(	/* attributes array */sortSpec,
														/*dojo.data.core.Read*/ store){
	//	summary:  
	//		Helper function to generate the sorting function based off the list of sort attributes.
	//	description:  
	//		The sort function creation will look for a property on the store called 'comparatorMap'.  If it exists
	//		it will look in the mapping for comparisons function for the attributes.  If one is found, it will
	//		use it instead of the basic comparator, which is typically used for strings, ints, booleans, and dates.
	//		Returns the sorting function for this particular list of attributes and sorting directions.
	//
	//	sortSpec: array
	//		A JS object that array that defines out what attribute names to sort on and whether it should be descenting or asending.
	//		The objects should be formatted as follows:
	//		{
	//			attribute: "attributeName-string" || attribute,
	//			descending: true|false;   // Default is false.
	//		}
	//	store: object
	//		The datastore object to look up item values from.
	//
	var sortFunctions=[];

	function createSortFunction(attr, dir, comp, s){
		//Passing in comp and s (comparator and store), makes this
		//function much faster.
		return function(itemA, itemB){
			var a = s.getValue(itemA, attr);
			var b = s.getValue(itemB, attr);
			return dir * comp(a,b); //int
		};
	}
	var sortAttribute;
	var map = store.comparatorMap;
	var bc = dojo.data.util.sorter.basicComparator;
	for(var i = 0; i < sortSpec.length; i++){
		sortAttribute = sortSpec[i];
		var attr = sortAttribute.attribute;
		if(attr){
			var dir = (sortAttribute.descending) ? -1 : 1;
			var comp = bc;
			if(map){
				if(typeof attr !== "string" && ("toString" in attr)){
					 attr = attr.toString();
				}
				comp = map[attr] || bc;
			}
			sortFunctions.push(createSortFunction(attr, 
				dir, comp, store));
		}
	}
	return function(rowA, rowB){
		var i=0;
		while(i < sortFunctions.length){
			var ret = sortFunctions[i++](rowA, rowB);
			if(ret !== 0){
				return ret;//int
			}
		}
		return 0; //int  
	}; // Function
};

}

if(!dojo._hasResource["dojo.data.util.simpleFetch"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.data.util.simpleFetch"] = true;
dojo.provide("dojo.data.util.simpleFetch");


dojo.data.util.simpleFetch.fetch = function(/* Object? */ request){
	//	summary:
	//		The simpleFetch mixin is designed to serve as a set of function(s) that can
	//		be mixed into other datastore implementations to accelerate their development.  
	//		The simpleFetch mixin should work well for any datastore that can respond to a _fetchItems() 
	//		call by returning an array of all the found items that matched the query.  The simpleFetch mixin
	//		is not designed to work for datastores that respond to a fetch() call by incrementally
	//		loading items, or sequentially loading partial batches of the result
	//		set.  For datastores that mixin simpleFetch, simpleFetch 
	//		implements a fetch method that automatically handles eight of the fetch()
	//		arguments -- onBegin, onItem, onComplete, onError, start, count, sort and scope
	//		The class mixing in simpleFetch should not implement fetch(),
	//		but should instead implement a _fetchItems() method.  The _fetchItems() 
	//		method takes three arguments, the keywordArgs object that was passed 
	//		to fetch(), a callback function to be called when the result array is
	//		available, and an error callback to be called if something goes wrong.
	//		The _fetchItems() method should ignore any keywordArgs parameters for
	//		start, count, onBegin, onItem, onComplete, onError, sort, and scope.  
	//		The _fetchItems() method needs to correctly handle any other keywordArgs
	//		parameters, including the query parameter and any optional parameters 
	//		(such as includeChildren).  The _fetchItems() method should create an array of 
	//		result items and pass it to the fetchHandler along with the original request object 
	//		-- or, the _fetchItems() method may, if it wants to, create an new request object 
	//		with other specifics about the request that are specific to the datastore and pass 
	//		that as the request object to the handler.
	//
	//		For more information on this specific function, see dojo.data.api.Read.fetch()
	request = request || {};
	if(!request.store){
		request.store = this;
	}
	var self = this;

	var _errorHandler = function(errorData, requestObject){
		if(requestObject.onError){
			var scope = requestObject.scope || dojo.global;
			requestObject.onError.call(scope, errorData, requestObject);
		}
	};

	var _fetchHandler = function(items, requestObject){
		var oldAbortFunction = requestObject.abort || null;
		var aborted = false;

		var startIndex = requestObject.start?requestObject.start:0;
		var endIndex = (requestObject.count && (requestObject.count !== Infinity))?(startIndex + requestObject.count):items.length;

		requestObject.abort = function(){
			aborted = true;
			if(oldAbortFunction){
				oldAbortFunction.call(requestObject);
			}
		};

		var scope = requestObject.scope || dojo.global;
		if(!requestObject.store){
			requestObject.store = self;
		}
		if(requestObject.onBegin){
			requestObject.onBegin.call(scope, items.length, requestObject);
		}
		if(requestObject.sort){
			items.sort(dojo.data.util.sorter.createSortFunction(requestObject.sort, self));
		}
		if(requestObject.onItem){
			for(var i = startIndex; (i < items.length) && (i < endIndex); ++i){
				var item = items[i];
				if(!aborted){
					requestObject.onItem.call(scope, item, requestObject);
				}
			}
		}
		if(requestObject.onComplete && !aborted){
			var subset = null;
			if(!requestObject.onItem){
				subset = items.slice(startIndex, endIndex);
			}
			requestObject.onComplete.call(scope, subset, requestObject);
		}
	};
	this._fetchItems(request, _fetchHandler, _errorHandler);
	return request;	// Object
};

}

if(!dojo._hasResource["dojo.data.ItemFileReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.data.ItemFileReadStore"] = true;
dojo.provide("dojo.data.ItemFileReadStore");





dojo.declare("dojo.data.ItemFileReadStore", null,{
	//	summary:
	//		The ItemFileReadStore implements the dojo.data.api.Read API and reads
	//		data from JSON files that have contents in this format --
	//		{ items: [
	//			{ name:'Kermit', color:'green', age:12, friends:['Gonzo', {_reference:{name:'Fozzie Bear'}}]},
	//			{ name:'Fozzie Bear', wears:['hat', 'tie']},
	//			{ name:'Miss Piggy', pets:'Foo-Foo'}
	//		]}
	//		Note that it can also contain an 'identifer' property that specified which attribute on the items 
	//		in the array of items that acts as the unique identifier for that item.
	//
	constructor: function(/* Object */ keywordParameters){
		//	summary: constructor
		//	keywordParameters: {url: String}
		//	keywordParameters: {data: jsonObject}
		//	keywordParameters: {typeMap: object)
		//		The structure of the typeMap object is as follows:
		//		{
		//			type0: function || object,
		//			type1: function || object,
		//			...
		//			typeN: function || object
		//		}
		//		Where if it is a function, it is assumed to be an object constructor that takes the 
		//		value of _value as the initialization parameters.  If it is an object, then it is assumed
		//		to be an object of general form:
		//		{
		//			type: function, //constructor.
		//			deserialize:	function(value) //The function that parses the value and constructs the object defined by type appropriately.
		//		}
	
		this._arrayOfAllItems = [];
		this._arrayOfTopLevelItems = [];
		this._loadFinished = false;
		this._jsonFileUrl = keywordParameters.url;
		this._ccUrl = keywordParameters.url;
		this.url = keywordParameters.url;
		this._jsonData = keywordParameters.data;
		this.data = null;
		this._datatypeMap = keywordParameters.typeMap || {};
		if(!this._datatypeMap['Date']){
			//If no default mapping for dates, then set this as default.
			//We use the dojo.date.stamp here because the ISO format is the 'dojo way'
			//of generically representing dates.
			this._datatypeMap['Date'] = {
											type: Date,
											deserialize: function(value){
												return dojo.date.stamp.fromISOString(value);
											}
										};
		}
		this._features = {'dojo.data.api.Read':true, 'dojo.data.api.Identity':true};
		this._itemsByIdentity = null;
		this._storeRefPropName = "_S"; // Default name for the store reference to attach to every item.
		this._itemNumPropName = "_0"; // Default Item Id for isItem to attach to every item.
		this._rootItemPropName = "_RI"; // Default Item Id for isItem to attach to every item.
		this._reverseRefMap = "_RRM"; // Default attribute for constructing a reverse reference map for use with reference integrity
		this._loadInProgress = false; //Got to track the initial load to prevent duelling loads of the dataset.
		this._queuedFetches = [];
		if(keywordParameters.urlPreventCache !== undefined){
			this.urlPreventCache = keywordParameters.urlPreventCache?true:false;
		}
		if(keywordParameters.hierarchical !== undefined){
			this.hierarchical = keywordParameters.hierarchical?true:false;
		}
		if(keywordParameters.clearOnClose){
			this.clearOnClose = true;
		}
		if("failOk" in keywordParameters){
			this.failOk = keywordParameters.failOk?true:false;
		}
	},
	
	url: "",	// use "" rather than undefined for the benefit of the parser (#3539)

	//Internal var, crossCheckUrl.  Used so that setting either url or _jsonFileUrl, can still trigger a reload
	//when clearOnClose and close is used.
	_ccUrl: "",

	data: null,	// define this so that the parser can populate it

	typeMap: null, //Define so parser can populate.
	
	//Parameter to allow users to specify if a close call should force a reload or not.
	//By default, it retains the old behavior of not clearing if close is called.  But
	//if set true, the store will be reset to default state.  Note that by doing this,
	//all item handles will become invalid and a new fetch must be issued.
	clearOnClose: false,

	//Parameter to allow specifying if preventCache should be passed to the xhrGet call or not when loading data from a url.  
	//Note this does not mean the store calls the server on each fetch, only that the data load has preventCache set as an option.
	//Added for tracker: #6072
	urlPreventCache: false,
	
	//Parameter for specifying that it is OK for the xhrGet call to fail silently.
	failOk: false,

	//Parameter to indicate to process data from the url as hierarchical 
	//(data items can contain other data items in js form).  Default is true 
	//for backwards compatibility.  False means only root items are processed 
	//as items, all child objects outside of type-mapped objects and those in 
	//specific reference format, are left straight JS data objects.
	hierarchical: true,

	_assertIsItem: function(/* item */ item){
		//	summary:
		//		This function tests whether the item passed in is indeed an item in the store.
		//	item: 
		//		The item to test for being contained by the store.
		if(!this.isItem(item)){ 
			throw new Error("dojo.data.ItemFileReadStore: Invalid item argument.");
		}
	},

	_assertIsAttribute: function(/* attribute-name-string */ attribute){
		//	summary:
		//		This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
		//	attribute: 
		//		The attribute to test for being contained by the store.
		if(typeof attribute !== "string"){ 
			throw new Error("dojo.data.ItemFileReadStore: Invalid attribute argument.");
		}
	},

	getValue: function(	/* item */ item, 
						/* attribute-name-string */ attribute, 
						/* value? */ defaultValue){
		//	summary: 
		//		See dojo.data.api.Read.getValue()
		var values = this.getValues(item, attribute);
		return (values.length > 0)?values[0]:defaultValue; // mixed
	},

	getValues: function(/* item */ item, 
						/* attribute-name-string */ attribute){
		//	summary: 
		//		See dojo.data.api.Read.getValues()

		this._assertIsItem(item);
		this._assertIsAttribute(attribute);
		// Clone it before returning.  refs: #10474
		return (item[attribute] || []).slice(0); // Array
	},

	getAttributes: function(/* item */ item){
		//	summary: 
		//		See dojo.data.api.Read.getAttributes()
		this._assertIsItem(item);
		var attributes = [];
		for(var key in item){
			// Save off only the real item attributes, not the special id marks for O(1) isItem.
			if((key !== this._storeRefPropName) && (key !== this._itemNumPropName) && (key !== this._rootItemPropName) && (key !== this._reverseRefMap)){
				attributes.push(key);
			}
		}
		return attributes; // Array
	},

	hasAttribute: function(	/* item */ item,
							/* attribute-name-string */ attribute){
		//	summary: 
		//		See dojo.data.api.Read.hasAttribute()
		this._assertIsItem(item);
		this._assertIsAttribute(attribute);
		return (attribute in item);
	},

	containsValue: function(/* item */ item, 
							/* attribute-name-string */ attribute, 
							/* anything */ value){
		//	summary: 
		//		See dojo.data.api.Read.containsValue()
		var regexp = undefined;
		if(typeof value === "string"){
			regexp = dojo.data.util.filter.patternToRegExp(value, false);
		}
		return this._containsValue(item, attribute, value, regexp); //boolean.
	},

	_containsValue: function(	/* item */ item, 
								/* attribute-name-string */ attribute, 
								/* anything */ value,
								/* RegExp?*/ regexp){
		//	summary: 
		//		Internal function for looking at the values contained by the item.
		//	description: 
		//		Internal function for looking at the values contained by the item.  This 
		//		function allows for denoting if the comparison should be case sensitive for
		//		strings or not (for handling filtering cases where string case should not matter)
		//	
		//	item:
		//		The data item to examine for attribute values.
		//	attribute:
		//		The attribute to inspect.
		//	value:	
		//		The value to match.
		//	regexp:
		//		Optional regular expression generated off value if value was of string type to handle wildcarding.
		//		If present and attribute values are string, then it can be used for comparison instead of 'value'
		return dojo.some(this.getValues(item, attribute), function(possibleValue){
			if(possibleValue !== null && !dojo.isObject(possibleValue) && regexp){
				if(possibleValue.toString().match(regexp)){
					return true; // Boolean
				}
			}else if(value === possibleValue){
				return true; // Boolean
			}
		});
	},

	isItem: function(/* anything */ something){
		//	summary: 
		//		See dojo.data.api.Read.isItem()
		if(something && something[this._storeRefPropName] === this){
			if(this._arrayOfAllItems[something[this._itemNumPropName]] === something){
				return true;
			}
		}
		return false; // Boolean
	},

	isItemLoaded: function(/* anything */ something){
		//	summary: 
		//		See dojo.data.api.Read.isItemLoaded()
		return this.isItem(something); //boolean
	},

	loadItem: function(/* object */ keywordArgs){
		//	summary: 
		//		See dojo.data.api.Read.loadItem()
		this._assertIsItem(keywordArgs.item);
	},

	getFeatures: function(){
		//	summary: 
		//		See dojo.data.api.Read.getFeatures()
		return this._features; //Object
	},

	getLabel: function(/* item */ item){
		//	summary: 
		//		See dojo.data.api.Read.getLabel()
		if(this._labelAttr && this.isItem(item)){
			return this.getValue(item,this._labelAttr); //String
		}
		return undefined; //undefined
	},

	getLabelAttributes: function(/* item */ item){
		//	summary: 
		//		See dojo.data.api.Read.getLabelAttributes()
		if(this._labelAttr){
			return [this._labelAttr]; //array
		}
		return null; //null
	},

	_fetchItems: function(	/* Object */ keywordArgs, 
							/* Function */ findCallback, 
							/* Function */ errorCallback){
		//	summary: 
		//		See dojo.data.util.simpleFetch.fetch()
		var self = this,
		    filter = function(requestArgs, arrayOfItems){
			var items = [],
			    i, key;
			if(requestArgs.query){
				var value,
				    ignoreCase = requestArgs.queryOptions ? requestArgs.queryOptions.ignoreCase : false;

				//See if there are any string values that can be regexp parsed first to avoid multiple regexp gens on the
				//same value for each item examined.  Much more efficient.
				var regexpList = {};
				for(key in requestArgs.query){
					value = requestArgs.query[key];
					if(typeof value === "string"){
						regexpList[key] = dojo.data.util.filter.patternToRegExp(value, ignoreCase);
					}else if(value instanceof RegExp){
						regexpList[key] = value;
					}
				}
				for(i = 0; i < arrayOfItems.length; ++i){
					var match = true;
					var candidateItem = arrayOfItems[i];
					if(candidateItem === null){
						match = false;
					}else{
						for(key in requestArgs.query){
							value = requestArgs.query[key];
							if(!self._containsValue(candidateItem, key, value, regexpList[key])){
								match = false;
							}
						}
					}
					if(match){
						items.push(candidateItem);
					}
				}
				findCallback(items, requestArgs);
			}else{
				// We want a copy to pass back in case the parent wishes to sort the array. 
				// We shouldn't allow resort of the internal list, so that multiple callers 
				// can get lists and sort without affecting each other.  We also need to
				// filter out any null values that have been left as a result of deleteItem()
				// calls in ItemFileWriteStore.
				for(i = 0; i < arrayOfItems.length; ++i){
					var item = arrayOfItems[i];
					if(item !== null){
						items.push(item);
					}
				}
				findCallback(items, requestArgs);
			}
		};

		if(this._loadFinished){
			filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
		}else{
			//Do a check on the JsonFileUrl and crosscheck it.
			//If it doesn't match the cross-check, it needs to be updated
			//This allows for either url or _jsonFileUrl to he changed to
			//reset the store load location.  Done this way for backwards 
			//compatibility.  People use _jsonFileUrl (even though officially
			//private.
			if(this._jsonFileUrl !== this._ccUrl){
				dojo.deprecated("dojo.data.ItemFileReadStore: ", 
					"To change the url, set the url property of the store," +
					" not _jsonFileUrl.  _jsonFileUrl support will be removed in 2.0");
				this._ccUrl = this._jsonFileUrl;
				this.url = this._jsonFileUrl;
			}else if(this.url !== this._ccUrl){
				this._jsonFileUrl = this.url;
				this._ccUrl = this.url;
			}

			//See if there was any forced reset of data.
			if(this.data != null && this._jsonData == null){
				this._jsonData = this.data;
				this.data = null;
			}

			if(this._jsonFileUrl){
				//If fetches come in before the loading has finished, but while
				//a load is in progress, we have to defer the fetching to be 
				//invoked in the callback.
				if(this._loadInProgress){
					this._queuedFetches.push({args: keywordArgs, filter: filter});
				}else{
					this._loadInProgress = true;
					var getArgs = {
							url: self._jsonFileUrl, 
							handleAs: "json-comment-optional",
							preventCache: this.urlPreventCache,
							failOk: this.failOk
						};
					var getHandler = dojo.xhrGet(getArgs);
					getHandler.addCallback(function(data){
						try{
							self._getItemsFromLoadedData(data);
							self._loadFinished = true;
							self._loadInProgress = false;
							
							filter(keywordArgs, self._getItemsArray(keywordArgs.queryOptions));
							self._handleQueuedFetches();
						}catch(e){
							self._loadFinished = true;
							self._loadInProgress = false;
							errorCallback(e, keywordArgs);
						}
					});
					getHandler.addErrback(function(error){
						self._loadInProgress = false;
						errorCallback(error, keywordArgs);
					});

					//Wire up the cancel to abort of the request
					//This call cancel on the deferred if it hasn't been called
					//yet and then will chain to the simple abort of the
					//simpleFetch keywordArgs
					var oldAbort = null;
					if(keywordArgs.abort){
						oldAbort = keywordArgs.abort;
					}
					keywordArgs.abort = function(){
						var df = getHandler;
						if(df && df.fired === -1){
							df.cancel();
							df = null;
						}
						if(oldAbort){
							oldAbort.call(keywordArgs);
						}
					};
				}
			}else if(this._jsonData){
				try{
					this._loadFinished = true;
					this._getItemsFromLoadedData(this._jsonData);
					this._jsonData = null;
					filter(keywordArgs, this._getItemsArray(keywordArgs.queryOptions));
				}catch(e){
					errorCallback(e, keywordArgs);
				}
			}else{
				errorCallback(new Error("dojo.data.ItemFileReadStore: No JSON source data was provided as either URL or a nested Javascript object."), keywordArgs);
			}
		}
	},

	_handleQueuedFetches: function(){
		//	summary: 
		//		Internal function to execute delayed request in the store.
		//Execute any deferred fetches now.
		if(this._queuedFetches.length > 0){
			for(var i = 0; i < this._queuedFetches.length; i++){
				var fData = this._queuedFetches[i],
				    delayedQuery = fData.args,
				    delayedFilter = fData.filter;
				if(delayedFilter){
					delayedFilter(delayedQuery, this._getItemsArray(delayedQuery.queryOptions)); 
				}else{
					this.fetchItemByIdentity(delayedQuery);
				}
			}
			this._queuedFetches = [];
		}
	},

	_getItemsArray: function(/*object?*/queryOptions){
		//	summary: 
		//		Internal function to determine which list of items to search over.
		//	queryOptions: The query options parameter, if any.
		if(queryOptions && queryOptions.deep){
			return this._arrayOfAllItems; 
		}
		return this._arrayOfTopLevelItems;
	},

	close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
		 //	summary: 
		 //		See dojo.data.api.Read.close()
		 if(this.clearOnClose && 
			this._loadFinished && 
			!this._loadInProgress){
			 //Reset all internalsback to default state.  This will force a reload
			 //on next fetch.  This also checks that the data or url param was set 
			 //so that the store knows it can get data.  Without one of those being set,
			 //the next fetch will trigger an error.

			 if(((this._jsonFileUrl == "" || this._jsonFileUrl == null) && 
				 (this.url == "" || this.url == null)
				) && this.data == null){
				 console.debug("dojo.data.ItemFileReadStore: WARNING!  Data reload " +
					" information has not been provided." + 
					"  Please set 'url' or 'data' to the appropriate value before" +
					" the next fetch");
			 }
			 this._arrayOfAllItems = [];
			 this._arrayOfTopLevelItems = [];
			 this._loadFinished = false;
			 this._itemsByIdentity = null;
			 this._loadInProgress = false;
			 this._queuedFetches = [];
		 }
	},

	_getItemsFromLoadedData: function(/* Object */ dataObject){
		//	summary:
		//		Function to parse the loaded data into item format and build the internal items array.
		//	description:
		//		Function to parse the loaded data into item format and build the internal items array.
		//
		//	dataObject:
		//		The JS data object containing the raw data to convery into item format.
		//
		// 	returns: array
		//		Array of items in store item format.
		
		// First, we define a couple little utility functions...
		var addingArrays = false,
		    self = this;
		
		function valueIsAnItem(/* anything */ aValue){
			// summary:
			//		Given any sort of value that could be in the raw json data,
			//		return true if we should interpret the value as being an
			//		item itself, rather than a literal value or a reference.
			// example:
			// 	|	false == valueIsAnItem("Kermit");
			// 	|	false == valueIsAnItem(42);
			// 	|	false == valueIsAnItem(new Date());
			// 	|	false == valueIsAnItem({_type:'Date', _value:'May 14, 1802'});
			// 	|	false == valueIsAnItem({_reference:'Kermit'});
			// 	|	true == valueIsAnItem({name:'Kermit', color:'green'});
			// 	|	true == valueIsAnItem({iggy:'pop'});
			// 	|	true == valueIsAnItem({foo:42});
			var isItem = (
				(aValue !== null) &&
				(typeof aValue === "object") &&
				(!dojo.isArray(aValue) || addingArrays) &&
				(!dojo.isFunction(aValue)) &&
				(aValue.constructor == Object || dojo.isArray(aValue)) &&
				(typeof aValue._reference === "undefined") && 
				(typeof aValue._type === "undefined") && 
				(typeof aValue._value === "undefined") &&
				self.hierarchical
			);
			return isItem;
		}
		
		function addItemAndSubItemsToArrayOfAllItems(/* Item */ anItem){
			self._arrayOfAllItems.push(anItem);
			for(var attribute in anItem){
				var valueForAttribute = anItem[attribute];
				if(valueForAttribute){
					if(dojo.isArray(valueForAttribute)){
						var valueArray = valueForAttribute;
						for(var k = 0; k < valueArray.length; ++k){
							var singleValue = valueArray[k];
							if(valueIsAnItem(singleValue)){
								addItemAndSubItemsToArrayOfAllItems(singleValue);
							}
						}
					}else{
						if(valueIsAnItem(valueForAttribute)){
							addItemAndSubItemsToArrayOfAllItems(valueForAttribute);
						}
					}
				}
			}
		}

		this._labelAttr = dataObject.label;

		// We need to do some transformations to convert the data structure
		// that we read from the file into a format that will be convenient
		// to work with in memory.

		// Step 1: Walk through the object hierarchy and build a list of all items
		var i,
		    item;
		this._arrayOfAllItems = [];
		this._arrayOfTopLevelItems = dataObject.items;

		for(i = 0; i < this._arrayOfTopLevelItems.length; ++i){
			item = this._arrayOfTopLevelItems[i];
			if(dojo.isArray(item)){
				addingArrays = true;
			}
			addItemAndSubItemsToArrayOfAllItems(item);
			item[this._rootItemPropName]=true;
		}

		// Step 2: Walk through all the attribute values of all the items, 
		// and replace single values with arrays.  For example, we change this:
		//		{ name:'Miss Piggy', pets:'Foo-Foo'}
		// into this:
		//		{ name:['Miss Piggy'], pets:['Foo-Foo']}
		// 
		// We also store the attribute names so we can validate our store  
		// reference and item id special properties for the O(1) isItem
		var allAttributeNames = {},
		    key;

		for(i = 0; i < this._arrayOfAllItems.length; ++i){
			item = this._arrayOfAllItems[i];
			for(key in item){
				if(key !== this._rootItemPropName){
					var value = item[key];
					if(value !== null){
						if(!dojo.isArray(value)){
							item[key] = [value];
						}
					}else{
						item[key] = [null];
					}
				}
				allAttributeNames[key]=key;
			}
		}

		// Step 3: Build unique property names to use for the _storeRefPropName and _itemNumPropName
		// This should go really fast, it will generally never even run the loop.
		while(allAttributeNames[this._storeRefPropName]){
			this._storeRefPropName += "_";
		}
		while(allAttributeNames[this._itemNumPropName]){
			this._itemNumPropName += "_";
		}
		while(allAttributeNames[this._reverseRefMap]){
			this._reverseRefMap += "_";
		}

		// Step 4: Some data files specify an optional 'identifier', which is 
		// the name of an attribute that holds the identity of each item. 
		// If this data file specified an identifier attribute, then build a 
		// hash table of items keyed by the identity of the items.
		var arrayOfValues;

		var identifier = dataObject.identifier;
		if(identifier){
			this._itemsByIdentity = {};
			this._features['dojo.data.api.Identity'] = identifier;
			for(i = 0; i < this._arrayOfAllItems.length; ++i){
				item = this._arrayOfAllItems[i];
				arrayOfValues = item[identifier];
				var identity = arrayOfValues[0];
				if(!this._itemsByIdentity[identity]){
					this._itemsByIdentity[identity] = item;
				}else{
					if(this._jsonFileUrl){
						throw new Error("dojo.data.ItemFileReadStore:  The json data as specified by: [" + this._jsonFileUrl + "] is malformed.  Items within the list have identifier: [" + identifier + "].  Value collided: [" + identity + "]");
					}else if(this._jsonData){
						throw new Error("dojo.data.ItemFileReadStore:  The json data provided by the creation arguments is malformed.  Items within the list have identifier: [" + identifier + "].  Value collided: [" + identity + "]");
					}
				}
			}
		}else{
			this._features['dojo.data.api.Identity'] = Number;
		}

		// Step 5: Walk through all the items, and set each item's properties 
		// for _storeRefPropName and _itemNumPropName, so that store.isItem() will return true.
		for(i = 0; i < this._arrayOfAllItems.length; ++i){
			item = this._arrayOfAllItems[i];
			item[this._storeRefPropName] = this;
			item[this._itemNumPropName] = i;
		}

		// Step 6: We walk through all the attribute values of all the items,
		// looking for type/value literals and item-references.
		//
		// We replace item-references with pointers to items.  For example, we change:
		//		{ name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
		// into this:
		//		{ name:['Kermit'], friends:[miss_piggy] } 
		// (where miss_piggy is the object representing the 'Miss Piggy' item).
		//
		// We replace type/value pairs with typed-literals.  For example, we change:
		//		{ name:['Nelson Mandela'], born:[{_type:'Date', _value:'July 18, 1918'}] }
		// into this:
		//		{ name:['Kermit'], born:(new Date('July 18, 1918')) } 
		//
		// We also generate the associate map for all items for the O(1) isItem function.
		for(i = 0; i < this._arrayOfAllItems.length; ++i){
			item = this._arrayOfAllItems[i]; // example: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
			for(key in item){
				arrayOfValues = item[key]; // example: [{_reference:{name:'Miss Piggy'}}]
				for(var j = 0; j < arrayOfValues.length; ++j){
					value = arrayOfValues[j]; // example: {_reference:{name:'Miss Piggy'}}
					if(value !== null && typeof value == "object"){
						if(("_type" in value) && ("_value" in value)){
							var type = value._type; // examples: 'Date', 'Color', or 'ComplexNumber'
							var mappingObj = this._datatypeMap[type]; // examples: Date, dojo.Color, foo.math.ComplexNumber, {type: dojo.Color, deserialize(value){ return new dojo.Color(value)}}
							if(!mappingObj){ 
								throw new Error("dojo.data.ItemFileReadStore: in the typeMap constructor arg, no object class was specified for the datatype '" + type + "'");
							}else if(dojo.isFunction(mappingObj)){
								arrayOfValues[j] = new mappingObj(value._value);
							}else if(dojo.isFunction(mappingObj.deserialize)){
								arrayOfValues[j] = mappingObj.deserialize(value._value);
							}else{
								throw new Error("dojo.data.ItemFileReadStore: Value provided in typeMap was neither a constructor, nor a an object with a deserialize function");
							}
						}
						if(value._reference){
							var referenceDescription = value._reference; // example: {name:'Miss Piggy'}
							if(!dojo.isObject(referenceDescription)){
								// example: 'Miss Piggy'
								// from an item like: { name:['Kermit'], friends:[{_reference:'Miss Piggy'}]}
								arrayOfValues[j] = this._getItemByIdentity(referenceDescription);
							}else{
								// example: {name:'Miss Piggy'}
								// from an item like: { name:['Kermit'], friends:[{_reference:{name:'Miss Piggy'}}] }
								for(var k = 0; k < this._arrayOfAllItems.length; ++k){
									var candidateItem = this._arrayOfAllItems[k],
									    found = true;
									for(var refKey in referenceDescription){
										if(candidateItem[refKey] != referenceDescription[refKey]){ 
											found = false; 
										}
									}
									if(found){ 
										arrayOfValues[j] = candidateItem; 
									}
								}
							}
							if(this.referenceIntegrity){
								var refItem = arrayOfValues[j];
								if(this.isItem(refItem)){
									this._addReferenceToMap(refItem, item, key);
								}
							}
						}else if(this.isItem(value)){
							//It's a child item (not one referenced through _reference).  
							//We need to treat this as a referenced item, so it can be cleaned up
							//in a write store easily.
							if(this.referenceIntegrity){
								this._addReferenceToMap(value, item, key);
							}
						}
					}
				}
			}
		}
	},

	_addReferenceToMap: function(/*item*/ refItem, /*item*/ parentItem, /*string*/ attribute){
		 //	summary:
		 //		Method to add an reference map entry for an item and attribute.
		 //	description:
		 //		Method to add an reference map entry for an item and attribute. 		 //
		 //	refItem:
		 //		The item that is referenced.
		 //	parentItem:
		 //		The item that holds the new reference to refItem.
		 //	attribute:
		 //		The attribute on parentItem that contains the new reference.
		 
		 //Stub function, does nothing.  Real processing is in ItemFileWriteStore.
	},

	getIdentity: function(/* item */ item){
		//	summary: 
		//		See dojo.data.api.Identity.getIdentity()
		var identifier = this._features['dojo.data.api.Identity'];
		if(identifier === Number){
			return item[this._itemNumPropName]; // Number
		}else{
			var arrayOfValues = item[identifier];
			if(arrayOfValues){
				return arrayOfValues[0]; // Object || String
			}
		}
		return null; // null
	},

	fetchItemByIdentity: function(/* Object */ keywordArgs){
		//	summary: 
		//		See dojo.data.api.Identity.fetchItemByIdentity()

		// Hasn't loaded yet, we have to trigger the load.
		var item,
		    scope;
		if(!this._loadFinished){
			var self = this;
			//Do a check on the JsonFileUrl and crosscheck it.
			//If it doesn't match the cross-check, it needs to be updated
			//This allows for either url or _jsonFileUrl to he changed to
			//reset the store load location.  Done this way for backwards 
			//compatibility.  People use _jsonFileUrl (even though officially
			//private.
			if(this._jsonFileUrl !== this._ccUrl){
				dojo.deprecated("dojo.data.ItemFileReadStore: ", 
					"To change the url, set the url property of the store," +
					" not _jsonFileUrl.  _jsonFileUrl support will be removed in 2.0");
				this._ccUrl = this._jsonFileUrl;
				this.url = this._jsonFileUrl;
			}else if(this.url !== this._ccUrl){
				this._jsonFileUrl = this.url;
				this._ccUrl = this.url;
			}
			
			//See if there was any forced reset of data.
			if(this.data != null && this._jsonData == null){
				this._jsonData = this.data;
				this.data = null;
			}

			if(this._jsonFileUrl){

				if(this._loadInProgress){
					this._queuedFetches.push({args: keywordArgs});
				}else{
					this._loadInProgress = true;
					var getArgs = {
							url: self._jsonFileUrl, 
							handleAs: "json-comment-optional",
							preventCache: this.urlPreventCache,
							failOk: this.failOk
					};
					var getHandler = dojo.xhrGet(getArgs);
					getHandler.addCallback(function(data){
						var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
						try{
							self._getItemsFromLoadedData(data);
							self._loadFinished = true;
							self._loadInProgress = false;
							item = self._getItemByIdentity(keywordArgs.identity);
							if(keywordArgs.onItem){
								keywordArgs.onItem.call(scope, item);
							}
							self._handleQueuedFetches();
						}catch(error){
							self._loadInProgress = false;
							if(keywordArgs.onError){
								keywordArgs.onError.call(scope, error);
							}
						}
					});
					getHandler.addErrback(function(error){
						self._loadInProgress = false;
						if(keywordArgs.onError){
							var scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
							keywordArgs.onError.call(scope, error);
						}
					});
				}

			}else if(this._jsonData){
				// Passed in data, no need to xhr.
				self._getItemsFromLoadedData(self._jsonData);
				self._jsonData = null;
				self._loadFinished = true;
				item = self._getItemByIdentity(keywordArgs.identity);
				if(keywordArgs.onItem){
					scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
					keywordArgs.onItem.call(scope, item);
				}
			} 
		}else{
			// Already loaded.  We can just look it up and call back.
			item = this._getItemByIdentity(keywordArgs.identity);
			if(keywordArgs.onItem){
				scope = keywordArgs.scope?keywordArgs.scope:dojo.global;
				keywordArgs.onItem.call(scope, item);
			}
		}
	},

	_getItemByIdentity: function(/* Object */ identity){
		//	summary:
		//		Internal function to look an item up by its identity map.
		var item = null;
		if(this._itemsByIdentity){
			item = this._itemsByIdentity[identity];
		}else{
			item = this._arrayOfAllItems[identity];
		}
		if(item === undefined){
			item = null;
		}
		return item; // Object
	},

	getIdentityAttributes: function(/* item */ item){
		//	summary: 
		//		See dojo.data.api.Identity.getIdentifierAttributes()
		 
		var identifier = this._features['dojo.data.api.Identity'];
		if(identifier === Number){
			// If (identifier === Number) it means getIdentity() just returns
			// an integer item-number for each item.  The dojo.data.api.Identity
			// spec says we need to return null if the identity is not composed 
			// of attributes 
			return null; // null
		}else{
			return [identifier]; // Array
		}
	},
	
	_forceLoad: function(){
		//	summary: 
		//		Internal function to force a load of the store if it hasn't occurred yet.  This is required
		//		for specific functions to work properly.  
		var self = this;
		//Do a check on the JsonFileUrl and crosscheck it.
		//If it doesn't match the cross-check, it needs to be updated
		//This allows for either url or _jsonFileUrl to he changed to
		//reset the store load location.  Done this way for backwards 
		//compatibility.  People use _jsonFileUrl (even though officially
		//private.
		if(this._jsonFileUrl !== this._ccUrl){
			dojo.deprecated("dojo.data.ItemFileReadStore: ", 
				"To change the url, set the url property of the store," +
				" not _jsonFileUrl.  _jsonFileUrl support will be removed in 2.0");
			this._ccUrl = this._jsonFileUrl;
			this.url = this._jsonFileUrl;
		}else if(this.url !== this._ccUrl){
			this._jsonFileUrl = this.url;
			this._ccUrl = this.url;
		}

		//See if there was any forced reset of data.
		if(this.data != null && this._jsonData == null){
			this._jsonData = this.data;
			this.data = null;
		}

		if(this._jsonFileUrl){
				var getArgs = {
					url: this._jsonFileUrl, 
					handleAs: "json-comment-optional",
					preventCache: this.urlPreventCache,
					failOk: this.failOk,
					sync: true
				};
			var getHandler = dojo.xhrGet(getArgs);
			getHandler.addCallback(function(data){
				try{
					//Check to be sure there wasn't another load going on concurrently 
					//So we don't clobber data that comes in on it.  If there is a load going on
					//then do not save this data.  It will potentially clobber current data.
					//We mainly wanted to sync/wait here.
					//TODO:  Revisit the loading scheme of this store to improve multi-initial
					//request handling.
					if(self._loadInProgress !== true && !self._loadFinished){
						self._getItemsFromLoadedData(data);
						self._loadFinished = true;
					}else if(self._loadInProgress){
						//Okay, we hit an error state we can't recover from.  A forced load occurred
						//while an async load was occurring.  Since we cannot block at this point, the best
						//that can be managed is to throw an error.
						throw new Error("dojo.data.ItemFileReadStore:  Unable to perform a synchronous load, an async load is in progress."); 
					}
				}catch(e){
					console.log(e);
					throw e;
				}
			});
			getHandler.addErrback(function(error){
				throw error;
			});
		}else if(this._jsonData){
			self._getItemsFromLoadedData(self._jsonData);
			self._jsonData = null;
			self._loadFinished = true;
		} 
	}
});
//Mix in the simple fetch implementation to this class.
dojo.extend(dojo.data.ItemFileReadStore,dojo.data.util.simpleFetch);

}

if(!dojo._hasResource["dojo.data.ItemFileWriteStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.data.ItemFileWriteStore"] = true;
dojo.provide("dojo.data.ItemFileWriteStore");


dojo.declare("dojo.data.ItemFileWriteStore", dojo.data.ItemFileReadStore, {
	constructor: function(/* object */ keywordParameters){
		//	keywordParameters: {typeMap: object)
		//		The structure of the typeMap object is as follows:
		//		{
		//			type0: function || object,
		//			type1: function || object,
		//			...
		//			typeN: function || object
		//		}
		//		Where if it is a function, it is assumed to be an object constructor that takes the 
		//		value of _value as the initialization parameters.  It is serialized assuming object.toString()
		//		serialization.  If it is an object, then it is assumed
		//		to be an object of general form:
		//		{
		//			type: function, //constructor.
		//			deserialize:	function(value) //The function that parses the value and constructs the object defined by type appropriately.
		//			serialize:	function(object) //The function that converts the object back into the proper file format form.
		//		}

		// ItemFileWriteStore extends ItemFileReadStore to implement these additional dojo.data APIs
		this._features['dojo.data.api.Write'] = true;
		this._features['dojo.data.api.Notification'] = true;
		
		// For keeping track of changes so that we can implement isDirty and revert
		this._pending = {
			_newItems:{}, 
			_modifiedItems:{}, 
			_deletedItems:{}
		};

		if(!this._datatypeMap['Date'].serialize){
			this._datatypeMap['Date'].serialize = function(obj){
				return dojo.date.stamp.toISOString(obj, {zulu:true});
			};
		}
		//Disable only if explicitly set to false.
		if(keywordParameters && (keywordParameters.referenceIntegrity === false)){
			this.referenceIntegrity = false;
		}

		// this._saveInProgress is set to true, briefly, from when save() is first called to when it completes
		this._saveInProgress = false;
	},

	referenceIntegrity: true, //Flag that defaultly enabled reference integrity tracking.  This way it can also be disabled pogrammatially or declaratively.

	_assert: function(/* boolean */ condition){
		if(!condition){
			throw new Error("assertion failed in ItemFileWriteStore");
		}
	},

	_getIdentifierAttribute: function(){
		var identifierAttribute = this.getFeatures()['dojo.data.api.Identity'];
		// this._assert((identifierAttribute === Number) || (dojo.isString(identifierAttribute)));
		return identifierAttribute;
	},
	
	
/* dojo.data.api.Write */

	newItem: function(/* Object? */ keywordArgs, /* Object? */ parentInfo){
		// summary: See dojo.data.api.Write.newItem()

		this._assert(!this._saveInProgress);

		if(!this._loadFinished){
			// We need to do this here so that we'll be able to find out what
			// identifierAttribute was specified in the data file.
			this._forceLoad();
		}

		if(typeof keywordArgs != "object" && typeof keywordArgs != "undefined"){
			throw new Error("newItem() was passed something other than an object");
		}
		var newIdentity = null;
		var identifierAttribute = this._getIdentifierAttribute();
		if(identifierAttribute === Number){
			newIdentity = this._arrayOfAllItems.length;
		}else{
			newIdentity = keywordArgs[identifierAttribute];
			if(typeof newIdentity === "undefined"){
				throw new Error("newItem() was not passed an identity for the new item");
			}
			if(dojo.isArray(newIdentity)){
				throw new Error("newItem() was not passed an single-valued identity");
			}
		}
		
		// make sure this identity is not already in use by another item, if identifiers were 
		// defined in the file.  Otherwise it would be the item count, 
		// which should always be unique in this case.
		if(this._itemsByIdentity){
			this._assert(typeof this._itemsByIdentity[newIdentity] === "undefined");
		}
		this._assert(typeof this._pending._newItems[newIdentity] === "undefined");
		this._assert(typeof this._pending._deletedItems[newIdentity] === "undefined");
		
		var newItem = {};
		newItem[this._storeRefPropName] = this;		
		newItem[this._itemNumPropName] = this._arrayOfAllItems.length;
		if(this._itemsByIdentity){
			this._itemsByIdentity[newIdentity] = newItem;
			//We have to set the identifier now, otherwise we can't look it
			//up at calls to setValueorValues in parentInfo handling.
			newItem[identifierAttribute] = [newIdentity];
		}
		this._arrayOfAllItems.push(newItem);

		//We need to construct some data for the onNew call too...
		var pInfo = null;
		
		// Now we need to check to see where we want to assign this thingm if any.
		if(parentInfo && parentInfo.parent && parentInfo.attribute){
			pInfo = {
				item: parentInfo.parent,
				attribute: parentInfo.attribute,
				oldValue: undefined
			};

			//See if it is multi-valued or not and handle appropriately
			//Generally, all attributes are multi-valued for this store
			//So, we only need to append if there are already values present.
			var values = this.getValues(parentInfo.parent, parentInfo.attribute);
			if(values && values.length > 0){
				var tempValues = values.slice(0, values.length);
				if(values.length === 1){
					pInfo.oldValue = values[0];
				}else{
					pInfo.oldValue = values.slice(0, values.length);
				}
				tempValues.push(newItem);
				this._setValueOrValues(parentInfo.parent, parentInfo.attribute, tempValues, false);
				pInfo.newValue = this.getValues(parentInfo.parent, parentInfo.attribute);
			}else{
				this._setValueOrValues(parentInfo.parent, parentInfo.attribute, newItem, false);
				pInfo.newValue = newItem;
			}
		}else{
			//Toplevel item, add to both top list as well as all list.
			newItem[this._rootItemPropName]=true;
			this._arrayOfTopLevelItems.push(newItem);
		}
		
		this._pending._newItems[newIdentity] = newItem;
		
		//Clone over the properties to the new item
		for(var key in keywordArgs){
			if(key === this._storeRefPropName || key === this._itemNumPropName){
				// Bummer, the user is trying to do something like
				// newItem({_S:"foo"}).  Unfortunately, our superclass,
				// ItemFileReadStore, is already using _S in each of our items
				// to hold private info.  To avoid a naming collision, we 
				// need to move all our private info to some other property 
				// of all the items/objects.  So, we need to iterate over all
				// the items and do something like: 
				//    item.__S = item._S;
				//    item._S = undefined;
				// But first we have to make sure the new "__S" variable is 
				// not in use, which means we have to iterate over all the 
				// items checking for that.
				throw new Error("encountered bug in ItemFileWriteStore.newItem");
			}
			var value = keywordArgs[key];
			if(!dojo.isArray(value)){
				value = [value];
			}
			newItem[key] = value;
			if(this.referenceIntegrity){
				for(var i = 0; i < value.length; i++){
					var val = value[i];
					if(this.isItem(val)){
						this._addReferenceToMap(val, newItem, key);
					}
				}
			}
		}
		this.onNew(newItem, pInfo); // dojo.data.api.Notification call
		return newItem; // item
	},
	
	_removeArrayElement: function(/* Array */ array, /* anything */ element){
		var index = dojo.indexOf(array, element);
		if(index != -1){
			array.splice(index, 1);
			return true;
		}
		return false;
	},
	
	deleteItem: function(/* item */ item){
		// summary: See dojo.data.api.Write.deleteItem()
		this._assert(!this._saveInProgress);
		this._assertIsItem(item);

		// Remove this item from the _arrayOfAllItems, but leave a null value in place
		// of the item, so as not to change the length of the array, so that in newItem() 
		// we can still safely do: newIdentity = this._arrayOfAllItems.length;
		var indexInArrayOfAllItems = item[this._itemNumPropName];
		var identity = this.getIdentity(item);

		//If we have reference integrity on, we need to do reference cleanup for the deleted item
		if(this.referenceIntegrity){
			//First scan all the attributes of this items for references and clean them up in the map 
			//As this item is going away, no need to track its references anymore.

			//Get the attributes list before we generate the backup so it 
			//doesn't pollute the attributes list.
			var attributes = this.getAttributes(item);

			//Backup the map, we'll have to restore it potentially, in a revert.
			if(item[this._reverseRefMap]){
				item["backup_" + this._reverseRefMap] = dojo.clone(item[this._reverseRefMap]);
			}
			
			//TODO:  This causes a reversion problem.  This list won't be restored on revert since it is
			//attached to the 'value'. item, not ours.  Need to back tese up somehow too.
			//Maybe build a map of the backup of the entries and attach it to the deleted item to be restored
			//later.  Or just record them and call _addReferenceToMap on them in revert.
			dojo.forEach(attributes, function(attribute){
				dojo.forEach(this.getValues(item, attribute), function(value){
					if(this.isItem(value)){
						//We have to back up all the references we had to others so they can be restored on a revert.
						if(!item["backupRefs_" + this._reverseRefMap]){
							item["backupRefs_" + this._reverseRefMap] = [];
						}
						item["backupRefs_" + this._reverseRefMap].push({id: this.getIdentity(value), attr: attribute});
						this._removeReferenceFromMap(value, item, attribute);
					}
				}, this);
			}, this);

			//Next, see if we have references to this item, if we do, we have to clean them up too.
			var references = item[this._reverseRefMap];
			if(references){
				//Look through all the items noted as references to clean them up.
				for(var itemId in references){
					var containingItem = null;
					if(this._itemsByIdentity){
						containingItem = this._itemsByIdentity[itemId];
					}else{
						containingItem = this._arrayOfAllItems[itemId];
					}
					//We have a reference to a containing item, now we have to process the
					//attributes and clear all references to the item being deleted.
					if(containingItem){
						for(var attribute in references[itemId]){
							var oldValues = this.getValues(containingItem, attribute) || [];
							var newValues = dojo.filter(oldValues, function(possibleItem){
								return !(this.isItem(possibleItem) && this.getIdentity(possibleItem) == identity);
							}, this);
							//Remove the note of the reference to the item and set the values on the modified attribute.
							this._removeReferenceFromMap(item, containingItem, attribute); 
							if(newValues.length < oldValues.length){
								this._setValueOrValues(containingItem, attribute, newValues, true);
							}
						}
					}
				}
			}
		}

		this._arrayOfAllItems[indexInArrayOfAllItems] = null;

		item[this._storeRefPropName] = null;
		if(this._itemsByIdentity){
			delete this._itemsByIdentity[identity];
		}
		this._pending._deletedItems[identity] = item;
		
		//Remove from the toplevel items, if necessary...
		if(item[this._rootItemPropName]){
			this._removeArrayElement(this._arrayOfTopLevelItems, item);
		}
		this.onDelete(item); // dojo.data.api.Notification call
		return true;
	},

	setValue: function(/* item */ item, /* attribute-name-string */ attribute, /* almost anything */ value){
		// summary: See dojo.data.api.Write.set()
		return this._setValueOrValues(item, attribute, value, true); // boolean
	},
	
	setValues: function(/* item */ item, /* attribute-name-string */ attribute, /* array */ values){
		// summary: See dojo.data.api.Write.setValues()
		return this._setValueOrValues(item, attribute, values, true); // boolean
	},
	
	unsetAttribute: function(/* item */ item, /* attribute-name-string */ attribute){
		// summary: See dojo.data.api.Write.unsetAttribute()
		return this._setValueOrValues(item, attribute, [], true);
	},
	
	_setValueOrValues: function(/* item */ item, /* attribute-name-string */ attribute, /* anything */ newValueOrValues, /*boolean?*/ callOnSet){
		this._assert(!this._saveInProgress);
		
		// Check for valid arguments
		this._assertIsItem(item);
		this._assert(dojo.isString(attribute));
		this._assert(typeof newValueOrValues !== "undefined");

		// Make sure the user isn't trying to change the item's identity
		var identifierAttribute = this._getIdentifierAttribute();
		if(attribute == identifierAttribute){
			throw new Error("ItemFileWriteStore does not have support for changing the value of an item's identifier.");
		}

		// To implement the Notification API, we need to make a note of what
		// the old attribute value was, so that we can pass that info when
		// we call the onSet method.
		var oldValueOrValues = this._getValueOrValues(item, attribute);

		var identity = this.getIdentity(item);
		if(!this._pending._modifiedItems[identity]){
			// Before we actually change the item, we make a copy of it to 
			// record the original state, so that we'll be able to revert if 
			// the revert method gets called.  If the item has already been
			// modified then there's no need to do this now, since we already
			// have a record of the original state.						
			var copyOfItemState = {};
			for(var key in item){
				if((key === this._storeRefPropName) || (key === this._itemNumPropName) || (key === this._rootItemPropName)){
					copyOfItemState[key] = item[key];
				}else if(key === this._reverseRefMap){
					copyOfItemState[key] = dojo.clone(item[key]);
				}else{
					copyOfItemState[key] = item[key].slice(0, item[key].length);
				}
			}
			// Now mark the item as dirty, and save the copy of the original state
			this._pending._modifiedItems[identity] = copyOfItemState;
		}
		
		// Okay, now we can actually change this attribute on the item
		var success = false;
		
		if(dojo.isArray(newValueOrValues) && newValueOrValues.length === 0){
			
			// If we were passed an empty array as the value, that counts
			// as "unsetting" the attribute, so we need to remove this 
			// attribute from the item.
			success = delete item[attribute];
			newValueOrValues = undefined; // used in the onSet Notification call below

			if(this.referenceIntegrity && oldValueOrValues){
				var oldValues = oldValueOrValues;
				if(!dojo.isArray(oldValues)){
					oldValues = [oldValues];
				}
				for(var i = 0; i < oldValues.length; i++){
					var value = oldValues[i];
					if(this.isItem(value)){
						this._removeReferenceFromMap(value, item, attribute);
					}
				}
			}
		}else{
			var newValueArray;
			if(dojo.isArray(newValueOrValues)){
				var newValues = newValueOrValues;
				// Unfortunately, it's not safe to just do this:
				//    newValueArray = newValues;
				// Instead, we need to copy the array, which slice() does very nicely.
				// This is so that our internal data structure won't  
				// get corrupted if the user mucks with the values array *after*
				// calling setValues().
				newValueArray = newValueOrValues.slice(0, newValueOrValues.length);
			}else{
				newValueArray = [newValueOrValues];
			}

			//We need to handle reference integrity if this is on. 
			//In the case of set, we need to see if references were added or removed
			//and update the reference tracking map accordingly.
			if(this.referenceIntegrity){
				if(oldValueOrValues){
					var oldValues = oldValueOrValues;
					if(!dojo.isArray(oldValues)){
						oldValues = [oldValues];
					}
					//Use an associative map to determine what was added/removed from the list.
					//Should be O(n) performant.  First look at all the old values and make a list of them
					//Then for any item not in the old list, we add it.  If it was already present, we remove it.
					//Then we pass over the map and any references left it it need to be removed (IE, no match in
					//the new values list).
					var map = {};
					dojo.forEach(oldValues, function(possibleItem){
						if(this.isItem(possibleItem)){
							var id = this.getIdentity(possibleItem);
							map[id.toString()] = true;
						}
					}, this);
					dojo.forEach(newValueArray, function(possibleItem){
						if(this.isItem(possibleItem)){
							var id = this.getIdentity(possibleItem);
							if(map[id.toString()]){
								delete map[id.toString()];
							}else{
								this._addReferenceToMap(possibleItem, item, attribute); 
							}
						}
					}, this);
					for(var rId in map){
						var removedItem;
						if(this._itemsByIdentity){
							removedItem = this._itemsByIdentity[rId];
						}else{
							removedItem = this._arrayOfAllItems[rId];
						}
						this._removeReferenceFromMap(removedItem, item, attribute);
					}
				}else{
					//Everything is new (no old values) so we have to just
					//insert all the references, if any.
					for(var i = 0; i < newValueArray.length; i++){
						var value = newValueArray[i];
						if(this.isItem(value)){
							this._addReferenceToMap(value, item, attribute);
						}
					}
				}
			}
			item[attribute] = newValueArray;
			success = true;
		}

		// Now we make the dojo.data.api.Notification call
		if(callOnSet){
			this.onSet(item, attribute, oldValueOrValues, newValueOrValues); 
		}
		return success; // boolean
	},

	_addReferenceToMap: function(/*item*/ refItem, /*item*/ parentItem, /*string*/ attribute){
		//	summary:
		//		Method to add an reference map entry for an item and attribute.
		//	description:
		//		Method to add an reference map entry for an item and attribute. 		 //
		//	refItem:
		//		The item that is referenced.
		//	parentItem:
		//		The item that holds the new reference to refItem.
		//	attribute:
		//		The attribute on parentItem that contains the new reference.
		 
		var parentId = this.getIdentity(parentItem);
		var references = refItem[this._reverseRefMap];

		if(!references){
			references = refItem[this._reverseRefMap] = {};
		}
		var itemRef = references[parentId];
		if(!itemRef){
			itemRef = references[parentId] = {};
		}
		itemRef[attribute] = true;
	},

	_removeReferenceFromMap: function(/* item */ refItem, /* item */ parentItem, /*strin*/ attribute){
		//	summary:
		//		Method to remove an reference map entry for an item and attribute.
		//	description:
		//		Method to remove an reference map entry for an item and attribute.  This will
		//		also perform cleanup on the map such that if there are no more references at all to 
		//		the item, its reference object and entry are removed.
		//
		//	refItem:
		//		The item that is referenced.
		//	parentItem:
		//		The item holding a reference to refItem.
		//	attribute:
		//		The attribute on parentItem that contains the reference.
		var identity = this.getIdentity(parentItem);
		var references = refItem[this._reverseRefMap];
		var itemId;
		if(references){
			for(itemId in references){
				if(itemId == identity){
					delete references[itemId][attribute];
					if(this._isEmpty(references[itemId])){
						delete references[itemId];
					}
				}
			}
			if(this._isEmpty(references)){
				delete refItem[this._reverseRefMap];
			}
		}
	},

	_dumpReferenceMap: function(){
		//	summary:
		//		Function to dump the reverse reference map of all items in the store for debug purposes.
		//	description:
		//		Function to dump the reverse reference map of all items in the store for debug purposes.
		var i;
		for(i = 0; i < this._arrayOfAllItems.length; i++){
			var item = this._arrayOfAllItems[i];
			if(item && item[this._reverseRefMap]){
				console.log("Item: [" + this.getIdentity(item) + "] is referenced by: " + dojo.toJson(item[this._reverseRefMap]));
			}
		}
	},
	
	_getValueOrValues: function(/* item */ item, /* attribute-name-string */ attribute){
		var valueOrValues = undefined;
		if(this.hasAttribute(item, attribute)){
			var valueArray = this.getValues(item, attribute);
			if(valueArray.length == 1){
				valueOrValues = valueArray[0];
			}else{
				valueOrValues = valueArray;
			}
		}
		return valueOrValues;
	},
	
	_flatten: function(/* anything */ value){
		if(this.isItem(value)){
			var item = value;
			// Given an item, return an serializable object that provides a 
			// reference to the item.
			// For example, given kermit:
			//    var kermit = store.newItem({id:2, name:"Kermit"});
			// we want to return
			//    {_reference:2}
			var identity = this.getIdentity(item);
			var referenceObject = {_reference: identity};
			return referenceObject;
		}else{
			if(typeof value === "object"){
				for(var type in this._datatypeMap){
					var typeMap = this._datatypeMap[type];
					if(dojo.isObject(typeMap) && !dojo.isFunction(typeMap)){
						if(value instanceof typeMap.type){
							if(!typeMap.serialize){
								throw new Error("ItemFileWriteStore:  No serializer defined for type mapping: [" + type + "]");
							}
							return {_type: type, _value: typeMap.serialize(value)};
						}
					} else if(value instanceof typeMap){
						//SImple mapping, therefore, return as a toString serialization.
						return {_type: type, _value: value.toString()};
					}
				}
			}
			return value;
		}
	},
	
	_getNewFileContentString: function(){
		// summary: 
		//		Generate a string that can be saved to a file.
		//		The result should look similar to:
		//		http://trac.dojotoolkit.org/browser/dojo/trunk/tests/data/countries.json
		var serializableStructure = {};
		
		var identifierAttribute = this._getIdentifierAttribute();
		if(identifierAttribute !== Number){
			serializableStructure.identifier = identifierAttribute;
		}
		if(this._labelAttr){
			serializableStructure.label = this._labelAttr;
		}
		serializableStructure.items = [];
		for(var i = 0; i < this._arrayOfAllItems.length; ++i){
			var item = this._arrayOfAllItems[i];
			if(item !== null){
				var serializableItem = {};
				for(var key in item){
					if(key !== this._storeRefPropName && key !== this._itemNumPropName && key !== this._reverseRefMap && key !== this._rootItemPropName){
						var attribute = key;
						var valueArray = this.getValues(item, attribute);
						if(valueArray.length == 1){
							serializableItem[attribute] = this._flatten(valueArray[0]);
						}else{
							var serializableArray = [];
							for(var j = 0; j < valueArray.length; ++j){
								serializableArray.push(this._flatten(valueArray[j]));
								serializableItem[attribute] = serializableArray;
							}
						}
					}
				}
				serializableStructure.items.push(serializableItem);
			}
		}
		var prettyPrint = true;
		return dojo.toJson(serializableStructure, prettyPrint);
	},

	_isEmpty: function(something){
		//	summary: 
		//		Function to determine if an array or object has no properties or values.
		//	something:
		//		The array or object to examine.
		var empty = true;
		if(dojo.isObject(something)){
			var i;
			for(i in something){
				empty = false;
				break;
			}
		}else if(dojo.isArray(something)){
			if(something.length > 0){
				empty = false;
			}
		}
		return empty; //boolean
	},
	
	save: function(/* object */ keywordArgs){
		// summary: See dojo.data.api.Write.save()
		this._assert(!this._saveInProgress);
		
		// this._saveInProgress is set to true, briefly, from when save is first called to when it completes
		this._saveInProgress = true;
		
		var self = this;
		var saveCompleteCallback = function(){
			self._pending = {
				_newItems:{}, 
				_modifiedItems:{},
				_deletedItems:{}
			};

			self._saveInProgress = false; // must come after this._pending is cleared, but before any callbacks
			if(keywordArgs && keywordArgs.onComplete){
				var scope = keywordArgs.scope || dojo.global;
				keywordArgs.onComplete.call(scope);
			}
		};
		var saveFailedCallback = function(err){
			self._saveInProgress = false;
			if(keywordArgs && keywordArgs.onError){
				var scope = keywordArgs.scope || dojo.global;
				keywordArgs.onError.call(scope, err);
			}
		};
		
		if(this._saveEverything){
			var newFileContentString = this._getNewFileContentString();
			this._saveEverything(saveCompleteCallback, saveFailedCallback, newFileContentString);
		}
		if(this._saveCustom){
			this._saveCustom(saveCompleteCallback, saveFailedCallback);
		}
		if(!this._saveEverything && !this._saveCustom){
			// Looks like there is no user-defined save-handler function.
			// That's fine, it just means the datastore is acting as a "mock-write"
			// store -- changes get saved in memory but don't get saved to disk.
			saveCompleteCallback();
		}
	},
	
	revert: function(){
		// summary: See dojo.data.api.Write.revert()
		this._assert(!this._saveInProgress);

		var identity;
		for(identity in this._pending._modifiedItems){
			// find the original item and the modified item that replaced it
			var copyOfItemState = this._pending._modifiedItems[identity];
			var modifiedItem = null;
			if(this._itemsByIdentity){
				modifiedItem = this._itemsByIdentity[identity];
			}else{
				modifiedItem = this._arrayOfAllItems[identity];
			}
	
			// Restore the original item into a full-fledged item again, we want to try to 
			// keep the same object instance as if we don't it, causes bugs like #9022.
			copyOfItemState[this._storeRefPropName] = this;
			for(key in modifiedItem){
				delete modifiedItem[key];
			}
			dojo.mixin(modifiedItem, copyOfItemState);
		}
		var deletedItem;
		for(identity in this._pending._deletedItems){
			deletedItem = this._pending._deletedItems[identity];
			deletedItem[this._storeRefPropName] = this;
			var index = deletedItem[this._itemNumPropName];

			//Restore the reverse refererence map, if any.
			if(deletedItem["backup_" + this._reverseRefMap]){
				deletedItem[this._reverseRefMap] = deletedItem["backup_" + this._reverseRefMap];
				delete deletedItem["backup_" + this._reverseRefMap];
			}
			this._arrayOfAllItems[index] = deletedItem;
			if(this._itemsByIdentity){
				this._itemsByIdentity[identity] = deletedItem;
			}
			if(deletedItem[this._rootItemPropName]){
				this._arrayOfTopLevelItems.push(deletedItem);
			}
		}
		//We have to pass through it again and restore the reference maps after all the
		//undeletes have occurred.
		for(identity in this._pending._deletedItems){
			deletedItem = this._pending._deletedItems[identity];
			if(deletedItem["backupRefs_" + this._reverseRefMap]){
				dojo.forEach(deletedItem["backupRefs_" + this._reverseRefMap], function(reference){
					var refItem;
					if(this._itemsByIdentity){
						refItem = this._itemsByIdentity[reference.id];
					}else{
						refItem = this._arrayOfAllItems[reference.id];
					}
					this._addReferenceToMap(refItem, deletedItem, reference.attr);
				}, this);
				delete deletedItem["backupRefs_" + this._reverseRefMap]; 
			}
		}

		for(identity in this._pending._newItems){
			var newItem = this._pending._newItems[identity];
			newItem[this._storeRefPropName] = null;
			// null out the new item, but don't change the array index so
			// so we can keep using _arrayOfAllItems.length.
			this._arrayOfAllItems[newItem[this._itemNumPropName]] = null;
			if(newItem[this._rootItemPropName]){
				this._removeArrayElement(this._arrayOfTopLevelItems, newItem);
			}
			if(this._itemsByIdentity){
				delete this._itemsByIdentity[identity];
			}
		}

		this._pending = {
			_newItems:{}, 
			_modifiedItems:{}, 
			_deletedItems:{}
		};
		return true; // boolean
	},
	
	isDirty: function(/* item? */ item){
		// summary: See dojo.data.api.Write.isDirty()
		if(item){
			// return true if the item is dirty
			var identity = this.getIdentity(item);
			return new Boolean(this._pending._newItems[identity] || 
				this._pending._modifiedItems[identity] ||
				this._pending._deletedItems[identity]).valueOf(); // boolean
		}else{
			// return true if the store is dirty -- which means return true
			// if there are any new items, dirty items, or modified items
			if(!this._isEmpty(this._pending._newItems) || 
				!this._isEmpty(this._pending._modifiedItems) ||
				!this._isEmpty(this._pending._deletedItems)){
				return true;
			}
			return false; // boolean
		}
	},

/* dojo.data.api.Notification */

	onSet: function(/* item */ item, 
					/*attribute-name-string*/ attribute, 
					/*object | array*/ oldValue,
					/*object | array*/ newValue){
		// summary: See dojo.data.api.Notification.onSet()
		
		// No need to do anything. This method is here just so that the 
		// client code can connect observers to it.
	},

	onNew: function(/* item */ newItem, /*object?*/ parentInfo){
		// summary: See dojo.data.api.Notification.onNew()
		
		// No need to do anything. This method is here just so that the 
		// client code can connect observers to it. 
	},

	onDelete: function(/* item */ deletedItem){
		// summary: See dojo.data.api.Notification.onDelete()
		
		// No need to do anything. This method is here just so that the 
		// client code can connect observers to it. 
	},

	close: function(/* object? */ request){
		 // summary:
		 //		Over-ride of base close function of ItemFileReadStore to add in check for store state.
		 // description:
		 //		Over-ride of base close function of ItemFileReadStore to add in check for store state.
		 //		If the store is still dirty (unsaved changes), then an error will be thrown instead of
		 //		clearing the internal state for reload from the url.

		 //Clear if not dirty ... or throw an error
		 if(this.clearOnClose){
			 if(!this.isDirty()){
				 this.inherited(arguments);
			 }else{
				 //Only throw an error if the store was dirty and we were loading from a url (cannot reload from url until state is saved).
				 throw new Error("dojo.data.ItemFileWriteStore: There are unsaved changes present in the store.  Please save or revert the changes before invoking close.");
			 }
		 }
	}
});

}

if(!dojo._hasResource["com.sixnet.services.widgets.checkAccordion"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.checkAccordion"] = true;
dojo.provide("com.sixnet.services.widgets.checkAccordion");






//
/*
 * Idea is no data inside...
 * parent: container of sorts, i.e. dialog, contentPane...
 */
dojo.declare('com.sixnet.services.widgets.checkAccordion',[dijit.layout.AccordionContainer], {
	allValues:false,
	actualValues:false,
	addValue:false,
	disabled:false,
	removeValue:false,
	checkedBoxes:false,
	parent:false,
	headers:false,
	theStore:false,
	constructor: function(){
		this.checkedBoxes = {};
		this.headers = [];
    },
    postCreate: function(){
    	this.inherited("postCreate", arguments);
        _sixnet_framework.log(1, "postCreate");
        // WRONG:
        //this.checkedBoxes = this.actualValues(); 
        // RIGHT:
        // pass in obj to hold values, return it.
        this.actualValues(dojo.hitch(this, "setCheckedBoxes"));
    },
    setCheckedBoxes: function(checkedBoxes){
    	this.checkedBoxes = checkedBoxes;
    	_sixnet_framework.log(1, this.checkedBoxes);
        this.allValues( dojo.hitch(this, "buildCheckAccordion"));
    },
    setJSON: function(nm){
    	//url
        this.theJSON = nm;
    },
    setStore: function(store){
    	//store obj
        this.theStore = store;
    },
    buildCheckAccordion: function(data){
//		var accordion = new dijit.layout.AccordionContainer({});
    	console.log("buildCheckAccordian");
    	console.log(data);
		dojo.forEach(data, function(o){
			//  o == JSON 'row' of data
			var tabName = new String(o.header);
			var numChecks = o.checks.length;
			var checkBoxes = o.checks;
			//  add ContentPane to parent Accordion
			acp = new dijit.layout.ContentPane({style:"height:180px;", title:tabName});
			dojo.query(dojo.byId(acp.domNode)).addClass("pane");
			//  Here we have the relative checkedBoxes added.
			for (var j = 0; j < numChecks; j++){
				var checkState = false;
				var checkRoleId = "";
				var checkboxName = checkBoxes[j];
				var cnm = (tabName.replace(" ", "_"))+"_"+(checkboxName.replace(" ", "_"));
				var color = "#000000";
				// make ContentPane per checkBox... only way to label.
				
				//dojo.query(dojo.byId(cp.domNode)).addClass("cb-cp");		
				//_sixnet_framework.log(1, this.checkedBoxes,  "   checkedBoxes in CREATE area")
				if(this.checkedBoxes[tabName] && this.checkedBoxes[tabName][checkboxName]){
					//  user has role assigned - setup for "checked" checkbox
					checkState = true;
					checkRoleId = this.checkedBoxes[tabName][checkboxName].id;
					//color = "#000000";
				}
				cp = new dijit.layout.ContentPane({style:"width:100%; height:16px; color:".concat(color), name:"cp"+tabName});
				var this_accordion = this;
				//  cb-LabeledCheckBox includes:
				//  value: textual value
				//  sid: if empty, is false, if not, is ID correlated to setting to true
				//  section: tab/header where cb is living
				var cb = new com.sixnet.services.widgets.LabeledCheckBox({name:cnm, value: checkboxName, section:tabName, sid:checkRoleId, checked: checkState,                 
					onChange: function(v) {
						if(v == true){
							this_accordion.addValue(this.section,this.value, this);
						}else if(v == false){
							this_accordion.removeValue(this.sid, this);
						}
                 	}
				});
				if(this.disabled){
					cb.attr({disabled:"disabled"});
				}
//				dojo.query(this.fileType).attr({disabled:"disabled"});
				////cb.hitch(this, "onLoad", function(){dojo.attr(this.parent, "style", {color:"#00ff00"});});
				// add CheckBox to cp (content pane)
				dojo.query(dojo.byId(cp.domNode)).addContent(cb.domNode);
				// add label after CheckBox, to cp
				// take the label and x-out ROLE and '_' for display, i.e. ROLE_MY_LUNCH == MY LUNCH
				var visualLabel = checkboxName.replace("ROLE_", " ");
				visualLabel = visualLabel.replace("_", " ");
				//
				dojo.query(dojo.byId(cp.domNode)).addContent("<div style='float:left;margin-left:5px;'>"+visualLabel+"</div>");
				// add to Accordion Content Pane (acp)
				dojo.query(dojo.byId(acp.domNode)).addContent(cp.domNode);
			}
			this.addChild(acp);
			acp.startup();
			acp.resize();			
		}, this);
		this.startup();
		this.resize();
	},
	reportError: function(){
		console.debug("ERROR",this.request, arguments);
	},
	buildAccordionFromStore: function(){
		this.store = new dojo.xhrGet({data:this.theStore, handleAs:'json', load:this.buildChecks, onError:this.reportError});
	},
    buildAccordionFromJSON: function(){
		this.store = new dojo.xhrGet({url:this.theJSON, handleAs:'json', load:this.buildChecks, onError:this.reportError});
	}		
});



}

if(!dojo._hasResource["com.sixnet.services.modules.access.formatters"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.modules.access.formatters"] = true;




//  TODO: see 'serial' formatter, apply to trigger in same way (interfaces)

dojo.provide("com.sixnet.services.modules.access.formatters");
dojo.declare("com.sixnet.services.modules.access.formatters", [com.sixnet.services.core.data.formatters], {
	userManager: false,
	store: false,
	accountManager: false,
	//unitManager: false,
	jobListDetail: false,
	jobList: false,
	grid:false,
	settingsInstall: false,

	setStore: function(store){
	this.store = store;
	},
	booleanCheck: function(value, idx, cell){
		var cb = {};
		if(value == 'TRUE' || parseInt(value) == 1){
			cb = new dijit.form.CheckBox({checked:"true", disabled:"true"});
		}else if(value == 'FALSE' || parseInt(value) == 0){
			cb = new dijit.form.CheckBox({checked:"false", disabled:"true"});
		}
		var result = new dijit.layout.ContentPane({content:cb, style:"text-align:center; margin:auto;"});
		return result;
	},
	
	cellLightbarSignal: function(value, idx, cell){
		if(value == null || value == '')return "";
		var lightbarPic = "<img src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/signal");
		// graphic ...x.gif == ...0.gif
		lightbarPic = lightbarPic.concat(value).concat(".gif\" />");
		return "<div style=\"text-align:center; margin:auto\">".concat(lightbarPic).concat("</div>");
	},
	
	
	
	setGrid: function(grid){
		this.grid = grid;
	},
	/*  Account manager formatters */
	setAccountManager: function(accountManager){
		this.accountManager = accountManager;
	},
	/*  User manager formatters  */
	setUserManager: function(userManager){
		this.userManager = userManager;
	},
	setJobList: function(jobList){
		this.jobList = jobList;
	},
	setJobListDetail: function(jobListDetail){
		this.jobListDetail = jobListDetail;
	},

	setSettingsInstall: function(settingsInstall){
		this.settingsInstall = settingsInstall;
	},
	
//	setSettingsInstall: function(settingsInstall){
//		this.settingsInstall = settingsInstall;
//	},
	
	deleteKey: function(value, idx, cell){
		var item = this.grid.getItem(idx);
		_sixnet_framework.log(3, item, " << delete my key row");
		var deleteKeyPane = new dijit.layout.ContentPane({style:"margin-right:auto;margin-left:auto; text-align:center"});
		var deleteKeyButton = new dijit.form.Button({ label: 'Delete Key', onClick: dojo.hitch(this, function(value, idx){
			this.settingsInstall.deleteItem(idx);
		},value, idx)});
		deleteKeyButton.placeAt( deleteKeyPane.domNode);
		return deleteKeyPane;
	},
	
	shrinkKey: function(value, idx, cell){
		//  return button that fires a dialog holding google key (for copy)
		var item = this.grid.getItem(idx);
		if( value == null) value = '';
		var googleKeyPane = new dijit.layout.ContentPane({style:"margin-right:auto;margin-left:auto"});
		var googleKeyButton = new dijit.form.Button({ label: 'View Google API Key', onClick: dojo.hitch(this, function(value, idx){
			var googleKeyDialog = new dijit.Dialog({
				accountManager: this,
				style:"width:450px;height:90px;",
				title:'Google API Key'
			});
			var cp = new dijit.layout.ContentPane({
				style:"margin-right:auto;margin-left:auto;width:450px"
			}).placeAt(googleKeyDialog.domNode);
			var keyInfo = new dijit.form.TextBox({value:value, style:"width:430px; margin-left:10px"}).placeAt(cp.domNode);
			dojo.connect(googleKeyDialog, "onCancel", function(){
				this.destroyRecursive();
			});
			googleKeyDialog.show();
		},value, idx)}).placeAt(googleKeyPane.domNode);
		return googleKeyPane;
	},
	
	
	username:function(value,idx,cell){
		var item = this.grid.getItem(idx);
		var output = value.concat('<br />');
		var usernamePane = new dijit.layout.ContentPane({content:output});
		usernamePane.domNode.height = '60px';
		setTimeout(dojo.hitch(this, "onFormatUsername", item, usernamePane),100);
		//this.onFormatSerial(item, usernamePane);
		return usernamePane;
	},
	
	accountname:function(value,idx,cell){
		var item = this.grid.getItem(idx);
		var output = value.concat('<br />');
		var accountnamePane = new dijit.layout.ContentPane({content:output});
		accountnamePane.domNode.height = '60px';
		setTimeout(dojo.hitch(this, "onFormatAccount", item, accountnamePane),100);
		//this.onFormatSerial(item, accountnamePane);
		return accountnamePane;
	},
	
	editModules: function(value, idx, cell){
		if(_sixnet_framework._super){
		var item = this.grid.getItem(idx);
		if( value == null) value = '';
		var modChangePane = new dijit.layout.ContentPane({style:"margin-right:auto;margin-left:auto"});
		var modChangeButton = new dijit.form.Button({ label: 'Change', onClick: dojo.hitch(this, function(value, idx){
			var modChangeDialog = new dijit.Dialog({
				accountManager: this,
				style:"width:310px;height:335px;",
				id:"modChangeDialog",
				title:'Account Modules:  '.concat(item.name)
			});
			var modulesInfo = {};

			var modules = new Array("access", "sitesurvey");
			
			var this_accountManager = this.accountManager;
			var accountModules = new Object();
			_sixnet_framework.bc('access', 'getAccountModulesPerId', { accountId: item.account_id }, dojo.hitch(this, function(response){
				if( response.successful ){
					dojo.forEach(modules, function(module){
						var checked = false;
						for(i = 0; i<response.data.length; i++){
							if(module == response.data[i].module){
								checked = true;
							}
						}
						var cp = new dijit.layout.ContentPane({
							style:"margin-right:auto;margin-left:auto; text-transform: capitalize; width:200px"
						}).placeAt(modChangeDialog.domNode);
						var cb = new dijit.form.CheckBox({
							value: module, 
							checked: checked,                 
							onChange: function(v) {
								if(v == true){
//									this_accountManager.addModule(this.value, item.account_id);
//									addModule: function(module, accountId){
//									_sixnet_framework.log(3, accountId, "addModule", module);
									_sixnet_framework.bc('access', 'addModule', { module: this.value, accountId:item.account_id }, dojo.hitch(this, function(response){
										if( response.successful ){
//											alert("success");
										}else{
											alert(response.error);
										}
									}));
//								},
								}else if(v == false){
//									this_accountManager.removeModule(this.value, item.account_id);
//									removeModule: function(module, accountId){
//									_sixnet_framework.log(3, accountId, "removeModule", module);
									_sixnet_framework.bc('access', 'removeModule', { module: this.value, accountId:item.account_id }, dojo.hitch(this, function(response){
										if( response.successful ){
//											alert("success");
										}else{
											alert(response.error);
										}
									}));
//								},
								}
			             	}
						});
						dojo.query(dojo.byId(cp.domNode)).addContent(cb.domNode);
						dojo.query(dojo.byId(cp.domNode)).addContent("  ".concat(module));
						
					});					
				}else{
					alert(response.error);
				}
			}));
//			deferred.addCallbacks(function(){_sixnet_framework.log(3, "Callback 0");},moduleForEach);
			dojo.connect(modChangeDialog, "onCancel", function(){
				this.destroyRecursive();
			});
//				cb.placeAt(cp.domNode);
			modChangeDialog.show();
		},value, idx)});
		modChangeButton.placeAt( modChangePane.domNode);
		return modChangePane;
		} else{
			return "";
		}
	},
	
	
	serial:function(value,idx,cell){
		var item = this.grid.getItem(idx);
		var output = value.concat('<br />');
		var serialPane = new dijit.layout.ContentPane({content:output});
		this.onFormatSerial(item, serialPane);
		return serialPane;
	},
	
	
	emailValidator: function(value, idx, cell){
		if( value == null) value = '';
		var eRegex = /^([a-zA-Z0-9_.-])+@([a-zA-Z0-9_.-])+\.([a-zA-Z])+([a-zA-Z])+/;
		var ePane = new dijit.layout.ContentPane({style:"margin-right:auto;margin-left:auto"});
		var eText = new dijit.form.ValidationTextBox({
			value:value, 
			invalidMessage:'Valid email required.',
			promptMessage:'Valid email required.'
		});
		dojo.attr("regEx", eRegex);
		eText.placeAt(ePane.domNode);
		return ePane;
	},
	assignRoles: function(value, idx, cell){
		var item = this.grid.getItem(idx);
		var uid = item.id;
		
		var allValues = function(onComplete){
    	//  first we need the "headers" of tab/accordion - these will be
    	//  module names - getInstalled is a temp for getAccountModules.
			var headers = [];
			_sixnet_framework.bc('providers', 'getInstalled', {}, dojo.hitch(this, function(response){
				if( response.successful ){
					//_sixnet_framework.log(3, "getInstalled (getAccountModules...tobe)",response.data);
					dojo.forEach(response.data, function(item){
						headers.push(item.name);
					}, this);
					if(headers.length > 0){
				    	var storeStructure = {identifier:'id', label: 'header', items:[]};
				    	var checkList = [];
				    	// now we have headers so build out checks-per
						dojo.forEach(headers, function(item, i){
							_sixnet_framework.bc(item, 'getModuleRoles', {}, dojo.hitch(this, function(response){
								if(response.successful){
									var checks = new Array();
									dojo.forEach(response.data, function(check){
										checks.push(check);
									});
									checkList.push( { header: item, checks: checks} );
									if(i+1 == headers.length){
										onComplete(checkList);
									}
								}else if(response.error){
									_sixnet_framework.log(3, response.error);
								}
							})
							);
						}, this);	
					}
				}else if(response.error){
					_sixnet_framework.log(3, response.error);
				}
			}));
	};
	// get actual current values
		var actualValues = function(onComplete){
			var uid = item.id;
			_sixnet_framework.log(3, "formatters.js-> actualValues UID:  ", uid);
			_sixnet_framework.bc('access', 'getUserRoles', {userId: uid }, dojo.hitch(this, function(response){
				if(response.successful){
					var obj = {};
					dojo.forEach(response.data, function(ur){
						//_sixnet_framework.log(3, 'add item', ur);
						if(!obj[ur.module]){
							obj[ur.module] = {};
						}
						obj[ur.module][ur.role] = ur;
					});
					onComplete(obj);
				}else if(response.error){
					_sixnet_framework.log(3, response.error);
				}
				})
			);
		};
		// true+value
		// addValue(section,value,checkbox)
		var addValue = function ( module, role, cb){
				_sixnet_framework.bc(module, 'addUserRole', {userId: uid, roleModule:module, roleName:role}, dojo.hitch(this, function(response){
					if(response.successful){
						// with this response we have the roleId - add it to the now-positive checkbox.
						cb.sid = response.data;
						//_sixnet_framework.log(3, obj.roleId, "  ->  roleId ADDed");
					}else if(response.error){
						_sixnet_framework.log(3, response.error);
					}
				})
				);		   
		};
		// false-value
		var removeValue = function ( sid, cb){
			//  this is attached to the cb-checkbox, sid being special id.
			_sixnet_framework.bc('access', 'removeUserRole', {roleId:sid}, dojo.hitch(this, function(response){
				if(response.successful){
					// roleId - take it away from the now-false checkbox.
					cb.sid = "";
				}else if(response.error){
					_sixnet_framework.log(3, response.error);
				}
			})
			);
	    };
		if( value == null) value = '';
		var editPane = new dijit.layout.ContentPane({style:"margin-right:auto;margin-left:auto"});
		var editButton = new dijit.form.Button({ label: 'Assign', onClick: dojo.hitch(this, function(value, idx){
			//  make sure uId is set before initiating the visuals.
			var myDialog = new dijit.Dialog({style:"width:310px;height:335px;top:40px;left:100px;", item: item, content:'', title:'Edit User Roles:  '.concat(item.username),
				onLoad: function(){
				// this method fires when the dialog has finished loading its content.allValues:f1, actualValues:f2, addValue:f3, removeValue: f4
					// whether has role to make changes or not we
					//  never allow user to adjust own roles.
					var disabled = true;
					if(uid != _sixnet_framework._userId){
						disabled = false;
					}
					//  check for role 
					this.myWid = new com.sixnet.services.widgets.checkAccordion({allValues:allValues, actualValues:actualValues, addValue:addValue, removeValue: removeValue, disabled:disabled});
					this.myWid.placeAt(this.containerNode, "last");
				}
			});
			//  dojo.connect(myDialog, "onCancel", this, function(){
			//  the second obj param "this" would refer to the whole
			//  formatter object!
			//  disable checkboxes
			
			dojo.connect(myDialog, "onCancel" ,dojo.hitch(myDialog, function(){
				// this method fires when the user clicks the close button in the title bar or presses escape
				// we do not want this dialog to stick around when we are done with it.  Tear it down.
				this.destroyRecursive();
				//_sixnet_framework.log(3, this, " This should be dead.");
			}));
			myDialog.show();
			_sixnet_framework.log(3, myDialog, "  in formatters", dojo.byId(myDialog), dojo.query('.pane').length, dojo.query('input[type="checkbox"]', myDialog.domNode).length);

		}, value, idx)});
		editButton.placeAt( editPane.domNode);
		return editPane;
	},
	changePass: function(value, idx, cell){
		var item = this.grid.getItem(idx);
		var userId = item.id;
		var formatter = this;
//		_sixnet_framework.log(3, userId," uid cp");
		if( value == null) value = '';
		var psChangePane = new dijit.layout.ContentPane({style:"margin-right:auto;margin-left:auto"});
		var psChangeButton = new dijit.form.Button({ label: 'Change', onClick: dojo.hitch(this, function(value, idx){
			//this.userManager.changePass(idx);
			// create an instance of Dialog with the content (loaded from href), id and title.
			this.user = this.grid.getItem(idx);
			_sixnet_framework.log(3, "i have: ", this.user);
			var userId = this.user.id;
			var userName = this.user.username;
			var psChangeDialog = new dijit.Dialog({userId: userId, style:"width:310px;height:205px;", title:'Change Password:  '.concat(userName),
				onLoad: function(){
				// this method fires when the dialog has finished loading its content.
				this.connect(this, "onCancel", function(){
					// this is for the 'x' button built into the Dialog.
					this.hide();
					this.destroyRecursive();
				});
			}});
			var cp = new dijit.layout.ContentPane({
				style:"margin-right:auto; margin-left:auto; width:200px; text-align:right;"
			}).placeAt(psChangeDialog.domNode);
			//
			var p1 = new dijit.form.TextBox({
				style:"font-size:1.1em; width:10em; margin-top:5px; margin-left:5px"
			});
			var p2 = new dijit.form.TextBox({
				style:"font-size:1.1em; width:10em; margin-top:5px; margin-left:5px"
			});
			var cp1 = new dijit.layout.ContentPane({
				style:"margin-right:auto; margin-left:auto; margin-top:10px; width:200px; float:right"
			}).placeAt(psChangeDialog.domNode);
			var apply = new dijit.form.Button({label:"Apply"});
			var cancel = new dijit.form.Button({label:"Cancel"});
			//
			dojo.query(dojo.byId(cp.domNode)).addContent("New ");
			dojo.query(dojo.byId(cp.domNode)).addContent(p1.domNode);
			dojo.query(dojo.byId(cp.domNode)).addContent("<br>Confirm ");
			dojo.query(dojo.byId(cp.domNode)).addContent(p2.domNode);
			dojo.query(dojo.byId(cp.domNode)).addContent(cp1.domNode);
			dojo.query(dojo.byId(cp1.domNode)).addContent(apply.domNode);
			dojo.query(dojo.byId(cp1.domNode)).addContent(cancel.domNode);
			// connectx
			dojo.connect(apply, "onClick", function(){
//				_sixnet_framework.log(3, "works", this.getValues());
//				var v = dijit.byId('psChangeDialog').getValues();
//				var p1 = v.p1;
//				var p2 = v.p2;
				if(p1.getValue() !== p2.getValue()){
					alert("Change and Confirm do not match. Please correct and re-apply.");
				}else{
//					_sixnet_framework.log(3, "Now process......", dijit.byId('psChangeDialog'.domNode).userId);
//					public function changePassword($newPassword);
//					var userId = dijit.byId('psChangeDialog').userId;
					_sixnet_framework.bc('access','changePassword', {newPassword:p1.getValue(), userId:userId}, dojo.hitch(this, function(response){
								if(response.successful){
//									alert("rock on");
									psChangeDialog.hide();
									psChangeDialog.destroyRecursive();
								}
								if(response.error){
									alert(response.error);
							}
						})
					);
				}
				
			});
			dojo.connect(cancel, "onClick", function(){
				psChangeDialog.hide();
				psChangeDialog.destroyRecursive();
			});
			//
			psChangeDialog.show();
//			_sixnet_framework.log(3, dojo.byId(psChangeDialog), " psChangeDialog");
		},value, idx)});
		psChangeButton.placeAt( psChangePane.domNode);
		return psChangePane;
	}
});

}

if(!dojo._hasResource['com.sixnet.services.widgets.rulesDefinitionBox']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.rulesDefinitionBox'] = true;
dojo.provide('com.sixnet.services.widgets.rulesDefinitionBox');







dojo.declare('com.sixnet.services.widgets.rulesDefinitionBox', [dijit._Widget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div style=\"margin:5px; margin-top:0px; width:90%; height:auto; float:left; clear:both; border:1px solid #B41319; -moz-border-radius: 5px; -webkit-border-radius: 5px; background:#fff; padding:5px;\">\n\t<div style=\"width:100%; float:left; clear:both;\">\n\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"fillBoxNode\">\n\t\t</div>\n\t</div>\n\t<div style=\"width:100%; float:left; clear:both;\">\n\t\t<div style=\"position:relative; right:5px; float:right; text-align:right; color:#fff\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"ruleCancelEditButton\" dojoAttachEvent=\"onClick:onCancelEditClick\" style=\"float:left; cursor:pointer; margin-right:5px; display:none;\"><img src=\"/dojo/com/sixnet/services/widgets/templates/images/cancelEdit.png\" /></div><div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"ruleEditButton\" dojoAttachEvent=\"onClick:onEditClick\" style=\"float:left; cursor:pointer; margin-right:5px;\"><img src=\"/dojo/com/sixnet/services/widgets/templates/images/edit.png\" /></div><div dojoType=\"dijit.layout.ContentPane\" dojoAttachEvent=\"onClick:onCloseWidget\" style=\"float:left; cursor:pointer;\"><img src=\"/dojo/com/sixnet/services/widgets/templates/images/trash.png\" /></div>\n\t\t</div>\n\t</div>\n</div>\n",
	dashBoard: false,
	currentDefinitionType: '',
	rules:null, /* set this to null because it is shared by reference */
	alerts:null,
	ruleId:null,
	arrayPosition:0,
	
	//   TODO: separate get data

	postCreate: function(){
		//
		this.addInfo(this.alerts);
		_sixnet_framework.log(1, this.alerts, " <<<< ALERTS BABY", this.arrayPosition);
	},
	
	setRuleId: function(ruleId){
		this.ruleId = ruleId;
	},
	
	getPosition: function(){
		var position = this.arrayPosition;
		return position;
	},
	
	getRuleId: function(){
		var ruleId = this.ruleId;
		return ruleId;
	},
	
	addInfo: function(alerts){
		_sixnet_framework.log(1, "in addInfo");
		for(var prop in this.alerts){
//			//  created per row.
			this.addFillBoxRow(prop, this.alerts[prop]);
		}
	},
	
	addFillBoxRow: function(field, value){
		_sixnet_framework.log(1, "in addFillBoxRow", field, value);
		//  data should be... busted out JSON, i.e. down to single JSON
		//  object with props and values.	
//		dojo.addClass(ruleBox, "ruleBox");
		_sixnet_framework.log(1, this.fillBoxNode);
		var fv = new dijit.layout.ContentPane({});
		var field = new dijit.layout.ContentPane({content:field}).placeAt(fv.domNode, "last");
		var value = new dijit.layout.ContentPane({content:value}).placeAt(fv.domNode, "last");
		dojo.addClass(fv.domNode, "ruleBox");
		dojo.addClass(field.domNode, "ruleBoxLabel");
		dojo.addClass(value.domNode, "ruleBoxDetail");
		fv.placeAt(this.fillBoxNode.domNode, "last");
//		this.fillBoxNode.appendChild(fv.domNode);
		return;
	},
	
	onEditClick: function(){
		
	},

	onCloseWidget: function(){
		
	},
	
	onCancelEditClick: function(){
		
	}
});
	

}

if(!dojo._hasResource["dijit.form.RadioButton"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.RadioButton"] = true;
dojo.provide("dijit.form.RadioButton");


// TODO: for 2.0, move the RadioButton code into this file

}

if(!dojo._hasResource["com.sixnet.services.widgets.LabeledRadioButton"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.LabeledRadioButton"] = true;
dojo.provide("com.sixnet.services.widgets.LabeledRadioButton");


dojo.declare('com.sixnet.services.widgets.LabeledRadioButton',[dijit.form.RadioButton], {
	name:'',
	templateString:"<div style=\"float:left; margin-left:5px;\" class=\"dijitReset dijitInline\" waiRole=\"presentation\">\n\t<input\n\t \t${nameAttrSetting} type=\"${type}\" ${checkedAttrSetting} \n\t\tclass=\"dijitReset dijitCheckBoxInput\"\n\t\tdojoAttachPoint=\"focusNode\"\n\t \tdojoAttachEvent=\"onmouseover:_onMouse,onmouseout:_onMouse,onclick:_onClick\"\n/></div>\n",	
	templateString:""//,		
	//other:""
});

}

if(!dojo._hasResource['com.sixnet.services.widgets.shadow']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.shadow'] = true;
dojo.provide('com.sixnet.services.widgets.shadow');
//



dojo.declare('com.sixnet.services.widgets.shadow', [dijit._Widget], {
	widgetsInTemplate: true,
	_width:0,
	_height:0,
	_dashViewNode:null,
	shadowDiv:null,
	contentDiv:null,
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.shadowDiv = new dijit.layout.ContentPane({});
		this.getDashViewWH(dojo.hitch(this, "setShadowDivStyle"));
		dojo.doc.body.appendChild(this.shadowDiv.domNode);
		this.connect(window, "onresize", "resize");
		//this.toggleVisible();
		_sixnet_framework.log(1, "ninja.....", this, this.shadowDiv, dojo.doc);
	},
	
	resize: function(){
		this.getDashViewWH(dojo.hitch(this, "setShadowDivStyle"));
		this.connect(this.shadowDiv, "onClick", "onShadowDivClick");
	},
	
	onShadowDivClick: function(){
		this.toggleVisible();
	},
	
	setShadowDivContent: function(content){
		//var div = dojo.create("div", {innerHTML:content, style:"margin:auto; width:50%;  vertical-align:middle; text-align:center; margin:auto; background:transparent; opacity:1; color:black; border:2px solid #000"});
		this.contentDiv = new dijit.layout.ContentPane({content:content, style:"margin:auto; postion:relative; top:50px; width:50%;  vertical-align:middle; text-align:center; margin:auto; background:transparent; opacity:1; color:black; border:2px solid #000"});

		//this.shadowDiv.setContent(div);
		this.contentDiv.placeAt(this.shadowDiv.domNode, "last");
		this.showShadow();
	},
	
	showShadow: function(){
		if(this.shadowDiv){
			dojo.style(this.shadowDiv.domNode, "display", "block");
			dojo.style(this.contentDiv.domNode, "display", "block");
		}
	},
	
	hideShadow: function(){
		if(this.shadowDiv){
			dojo.style(this.shadowDiv.domNode, "display", "none");
			dojo.style(this.contentDiv.domNode, "display", "none");
		}
	},
	
	getDashViewWH: function(onComplete){
		var dv = dojo.query('[dojoattachpoint=dashView]')[0];
		var h = dojo.style( dv, "height");
		var w = dojo.style( dv, "width");
		this._dashViewNode = dv;
		this._height = h-1;
		this._width = w-1;
		onComplete();
	},
	
	setShadowDivStyle: function(){
		
		var h = this._height;
		var w = this._width;
		_sixnet_framework.log(1, h, w, "<< h/w");
		dojo.style(this.shadowDiv.domNode,{
			position:"absolute",
			top:"34px",
			left:"156px",
			right:"0px",
			bottom:"22px",
			height:h,
			width:w,
//			backgroundImage:"url('dojo/com/sixnet/services/widgets/templates/images/smallRedBG.png')",
//			opacity:"0.7",
//			filter:"alpha(opacity=70)",
			background:"rgb(181, 67, 67)",
			background:"rgba(181, 67, 67, 0.7)",
			border:"none",
			zIndex:"500"
		});
	},
	
	toggleVisible: function(){
		var currentDisplaySetting = dojo.style(this.shadowDiv.domNode, "display");
		_sixnet_framework.log(1, currentDisplaySetting);
		if( currentDisplaySetting == "none"){
			this.showShadow();
		}else if( currentDisplaySetting == "block"){
			this.hideShadow();
		}
	}
});

}

if(!dojo._hasResource['com.sixnet.services.core.dashWidgetBase']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.core.dashWidgetBase'] = true;




dojo.provide('com.sixnet.services.core.dashWidgetBase');
dojo.declare('com.sixnet.services.core.dashWidgetBase', [com.sixnet.services.core.dashWidgetEmbedded], {
	_widgetPane: false,
	region:"center",
	dashBoard: false,
	widgetCounts: {},
	moduleParent: '',
	iconPath: '',
	icon: '',
	_shadow:null,
	shadowIsOpen: false,
	lockShadow: false,
	templatePath: false,
	constructor: function(params){
		_sixnet_framework.log(3,"dashWidgetBase", this.declaredClass);
		this._subscriptions = [];
		this.dashBoard = params.dashBoard; 
		var classElements = this.declaredClass.split('.');
		this.moduleParent = classElements.slice(0,classElements.length-1).join('.');
		_sixnet_framework.log(3,"dashWidgetBase.moduleParent", this.moduleParent);
//		dojo.cache(this.moduleParent, this.templateName, { value: null} );
		if( this.templatePath){
			var templateElements = this.templatePath.path.split('/');
			this.templateName = templateElements.slice( classElements.length).join('/');
			delete this.templatePath; 
		}
		if(this.templateName ){
			this.templateString = dojo.cache( this.moduleParent, this.templateName);
		}
	},
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this._widgetPane = this.buildWidgetThumbnailPane();
	},
	
	openShadow: function(content){
		dojo.destroy(this._shadow);
		this._shadow = null;
		this._shadow = new com.sixnet.services.widgets.shadow({});
		if(this._shadow){
			this._shadow.setShadowDivContent(content);
			this._shadow.showShadow();
			this.shadowIsOpen = true;
			this.connect(this._shadow.shadowDiv, "onClick", "closeShadow");
			this.connect(this._shadow.contentDiv, "onMouseOver", "keepShadow");
			this.connect(this._shadow.contentDiv, "onMouseLeave", "freeShadow");
		}
	},
	
	keepShadow: function(){
		// we want to keep the shadow if over the content portion
		this.lockShadow = true;
		_sixnet_framework.log(3, "keepShadow(true) user may be trying to interact with for, foo  Keep Shadow??  ", this.lockShadow);
	},
	
	freeShadow: function(){
		this.lockShadow = false;
		_sixnet_framework.log(3, "freeShadow(false)  Keep Shadow??  ", this.lockShadow);

	},
	
	closeShadow: function(){
		_sixnet_framework.log(3, "closeShadow dWB called. Keep Shadow??  ", this.lockShadow);
		if(this.lockShadow == false){
			this._shadow.hideShadow();
	//		dojo.destroy();
			this.shadowIsOpen = false;
		}
	},
	
	setDashBoard: function(dashBoard){
		this.dashBoard = dashBoard;
	},
	resetWidgetCount: function(){
		for(var index in this.widgetCounts){
			if(!this.widgetCounts.hasOwnProperty(index)) continue;
			this.widgetCounts[index] = 0;
		}
	},
	onHide: function(){
		_sixnet_framework.log(3, "onHide fired, check for shadow state/store it holmes");
		if(this.shadowIsOpen){
			this._shadow.hideShadow();
		}
	},
	onShow: function(){
		_sixnet_framework.log(3, "onShow fired in dWB.js");
		if(this.shadowIsOpen && this._shadow){
			this._shadow.showShadow();
		}
	},
	onStart: function(){
	},
	initWidgetCount: function(){
		if( typeof(this.widgetCounts[this.declaredClass]) == 'undefined'){
			this.widgetCounts[this.declaredClass] = 0;
		}
	},
	incrementWidgetCount: function(){
		this.initWidgetCount();
		return ++this.widgetCounts[this.declaredClass]; // increment then return
	},
	buildIconImage: function(){
		this.iconPath = this.cleanPath(dojo.moduleUrl(this.declaredClass).path, 1);
		this.iconPath += "/templates/images/".concat(this.icon);
		this.iconPath = "<img style='width:50px; height: 50px' src='".concat(this.iconPath).concat("' />");
		return this.iconPath;
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce thumbnail in "Running Apps" pane on side of dashboard
		if( this.declaredClass == 'com.sixnet.services.core.dashWidgetBase') return false;
		return new dijit.layout.ContentPane({content:this.buildIconImage()+this.incrementWidgetCount()});
	},
	getWidgetThumbnailPane: function(){
		// Do not override this method, instead override buildWidgetThumbnailPane
		return this._widgetPane;
	},
	unload: function(){
//		_sixnet_framework.log(1, dojo.clone(this._widgetPane), " dashWidgetBase-> unload()  _widgetPane");
		if( this._widgetPane){
			_sixnet_framework.log(3, "true, has _widgetPane");
			if( this.dashBoard){
				this.dashBoard.removeFromWidgetStack(this._widgetPane);
			}
			this._widgetPane.destroyRecursive();
			this._widgetPane = false;
		}else{
			_sixnet_framework.log(3, "False, NO _widgetPane");
		}
	},
	destroy: function(){
		this.unload();
		// parent destructors are called LAST
		this.inherited("destroy", arguments);
	}
	
});

}

if(!dojo._hasResource["dijit.layout.LayoutContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.LayoutContainer"] = true;
dojo.provide("dijit.layout.LayoutContainer");



dojo.declare("dijit.layout.LayoutContainer",
	dijit.layout._LayoutWidget,
	{
	// summary:
	//		Deprecated.  Use `dijit.layout.BorderContainer` instead.
	//
	// description:
	//		Provides Delphi-style panel layout semantics.
	//
	//		A LayoutContainer is a box with a specified size (like style="width: 500px; height: 500px;"),
	//		that contains children widgets marked with "layoutAlign" of "left", "right", "bottom", "top", and "client".
	//		It takes it's children marked as left/top/bottom/right, and lays them out along the edges of the box,
	//		and then it takes the child marked "client" and puts it into the remaining space in the middle.
	//
	//		Left/right positioning is similar to CSS's "float: left" and "float: right",
	//		and top/bottom positioning would be similar to "float: top" and "float: bottom", if there were such
	//		CSS.
	//
	//		Note that there can only be one client element, but there can be multiple left, right, top,
	//		or bottom elements.
	//
	// example:
	// |	<style>
	// |		html, body{ height: 100%; width: 100%; }
	// |	</style>
	// |	<div dojoType="dijit.layout.LayoutContainer" style="width: 100%; height: 100%">
	// |		<div dojoType="dijit.layout.ContentPane" layoutAlign="top">header text</div>
	// |		<div dojoType="dijit.layout.ContentPane" layoutAlign="left" style="width: 200px;">table of contents</div>
	// |		<div dojoType="dijit.layout.ContentPane" layoutAlign="client">client area</div>
	// |	</div>
	//
	//		Lays out each child in the natural order the children occur in.
	//		Basically each child is laid out into the "remaining space", where "remaining space" is initially
	//		the content area of this widget, but is reduced to a smaller rectangle each time a child is added.
	// tags:
	//		deprecated

	baseClass: "dijitLayoutContainer",

	constructor: function(){
		dojo.deprecated("dijit.layout.LayoutContainer is deprecated", "use BorderContainer instead", 2.0);
	},

	layout: function(){
		dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
	},

	addChild: function(/*dijit._Widget*/ child, /*Integer?*/ insertIndex){
		this.inherited(arguments);
		if(this._started){
			dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
		}
	},

	removeChild: function(/*dijit._Widget*/ widget){
		this.inherited(arguments);
		if(this._started){
			dijit.layout.layoutChildren(this.domNode, this._contentBox, this.getChildren());
		}
	}
});

// This argument can be specified for the children of a LayoutContainer.
// Since any widget can be specified as a LayoutContainer child, mix it
// into the base widget class.  (This is a hack, but it's effective.)
dojo.extend(dijit._Widget, {
	// layoutAlign: String
	//		"none", "left", "right", "bottom", "top", and "client".
	//		See the LayoutContainer description for details on this parameter.
	layoutAlign: 'none'
});

}

if(!dojo._hasResource['com.sixnet.services.core.dashWidgetHolder']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.core.dashWidgetHolder'] = true;



dojo.provide('com.sixnet.services.core.dashWidgetHolder');


dojo.declare('com.sixnet.services.core.dashWidgetHolder', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div region=\"center\" dojoAttachPoint=\"dashWidgets\" class=\"dashWidgetsMain\">\t\n\t</div>\n</div>\n",
	addChild: function(widget){
		this.dashWidgets.appendChild(widget.domNode);
		
	},
	onResize: function(){
		// no don't
	},
	/*private*/buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return new dijit.layout.ContentPane({content:'Dashboard'});
	}
});

}

if(!dojo._hasResource["dojo.dnd.Mover"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.dnd.Mover"] = true;
dojo.provide("dojo.dnd.Mover");




dojo.declare("dojo.dnd.Mover", null, {
	constructor: function(node, e, host){
		// summary:
		//		an object, which makes a node follow the mouse. 
		//		Used as a default mover, and as a base class for custom movers.
		// node: Node
		//		a node (or node's id) to be moved
		// e: Event
		//		a mouse event, which started the move;
		//		only pageX and pageY properties are used
		// host: Object?
		//		object which implements the functionality of the move,
		//	 	and defines proper events (onMoveStart and onMoveStop)
		this.node = dojo.byId(node);
		this.marginBox = {l: e.pageX, t: e.pageY};
		this.mouseButton = e.button;
		var h = this.host = host, d = node.ownerDocument, 
			firstEvent = dojo.connect(d, "onmousemove", this, "onFirstMove");
		this.events = [
			dojo.connect(d, "onmousemove", this, "onMouseMove"),
			dojo.connect(d, "onmouseup",   this, "onMouseUp"),
			// cancel text selection and text dragging
			dojo.connect(d, "ondragstart",   dojo.stopEvent),
			dojo.connect(d.body, "onselectstart", dojo.stopEvent),
			firstEvent
		];
		// notify that the move has started
		if(h && h.onMoveStart){
			h.onMoveStart(this);
		}
	},
	// mouse event processors
	onMouseMove: function(e){
		// summary:
		//		event processor for onmousemove
		// e: Event
		//		mouse event
		dojo.dnd.autoScroll(e);
		var m = this.marginBox;
		this.host.onMove(this, {l: m.l + e.pageX, t: m.t + e.pageY}, e);
		dojo.stopEvent(e);
	},
	onMouseUp: function(e){
		if(dojo.isWebKit && dojo.isMac && this.mouseButton == 2 ? 
				e.button == 0 : this.mouseButton == e.button){
			this.destroy();
		}
		dojo.stopEvent(e);
	},
	// utilities
	onFirstMove: function(e){
		// summary:
		//		makes the node absolute; it is meant to be called only once. 
		// 		relative and absolutely positioned nodes are assumed to use pixel units
		var s = this.node.style, l, t, h = this.host;
		switch(s.position){
			case "relative":
			case "absolute":
				// assume that left and top values are in pixels already
				l = Math.round(parseFloat(s.left)) || 0;
				t = Math.round(parseFloat(s.top)) || 0;
				break;
			default:
				s.position = "absolute";	// enforcing the absolute mode
				var m = dojo.marginBox(this.node);
				// event.pageX/pageY (which we used to generate the initial
				// margin box) includes padding and margin set on the body.
				// However, setting the node's position to absolute and then
				// doing dojo.marginBox on it *doesn't* take that additional
				// space into account - so we need to subtract the combined
				// padding and margin.  We use getComputedStyle and
				// _getMarginBox/_getContentBox to avoid the extra lookup of
				// the computed style. 
				var b = dojo.doc.body;
				var bs = dojo.getComputedStyle(b);
				var bm = dojo._getMarginBox(b, bs);
				var bc = dojo._getContentBox(b, bs);
				l = m.l - (bc.l - bm.l);
				t = m.t - (bc.t - bm.t);
				break;
		}
		this.marginBox.l = l - this.marginBox.l;
		this.marginBox.t = t - this.marginBox.t;
		if(h && h.onFirstMove){
			h.onFirstMove(this, e);
		}
		dojo.disconnect(this.events.pop());
	},
	destroy: function(){
		// summary:
		//		stops the move, deletes all references, so the object can be garbage-collected
		dojo.forEach(this.events, dojo.disconnect);
		// undo global settings
		var h = this.host;
		if(h && h.onMoveStop){
			h.onMoveStop(this);
		}
		// destroy objects
		this.events = this.node = this.host = null;
	}
});

}

if(!dojo._hasResource["dojo.dnd.Moveable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.dnd.Moveable"] = true;
dojo.provide("dojo.dnd.Moveable");



/*=====
dojo.declare("dojo.dnd.__MoveableArgs", [], {
	// handle: Node||String
	//		A node (or node's id), which is used as a mouse handle.
	//		If omitted, the node itself is used as a handle.
	handle: null,

	// delay: Number
	//		delay move by this number of pixels
	delay: 0,

	// skip: Boolean
	//		skip move of form elements
	skip: false,

	// mover: Object
	//		a constructor of custom Mover
	mover: dojo.dnd.Mover
});
=====*/

dojo.declare("dojo.dnd.Moveable", null, {
	// object attributes (for markup)
	handle: "",
	delay: 0,
	skip: false,
	
	constructor: function(node, params){
		// summary:
		//		an object, which makes a node moveable
		// node: Node
		//		a node (or node's id) to be moved
		// params: dojo.dnd.__MoveableArgs?
		//		optional parameters
		this.node = dojo.byId(node);
		if(!params){ params = {}; }
		this.handle = params.handle ? dojo.byId(params.handle) : null;
		if(!this.handle){ this.handle = this.node; }
		this.delay = params.delay > 0 ? params.delay : 0;
		this.skip  = params.skip;
		this.mover = params.mover ? params.mover : dojo.dnd.Mover;
		this.events = [
			dojo.connect(this.handle, "onmousedown", this, "onMouseDown"),
			// cancel text selection and text dragging
			dojo.connect(this.handle, "ondragstart",   this, "onSelectStart"),
			dojo.connect(this.handle, "onselectstart", this, "onSelectStart")
		];
	},

	// markup methods
	markupFactory: function(params, node){
		return new dojo.dnd.Moveable(node, params);
	},

	// methods
	destroy: function(){
		// summary:
		//		stops watching for possible move, deletes all references, so the object can be garbage-collected
		dojo.forEach(this.events, dojo.disconnect);
		this.events = this.node = this.handle = null;
	},
	
	// mouse event processors
	onMouseDown: function(e){
		// summary:
		//		event processor for onmousedown, creates a Mover for the node
		// e: Event
		//		mouse event
		if(this.skip && dojo.dnd.isFormElement(e)){ return; }
		if(this.delay){
			this.events.push(
				dojo.connect(this.handle, "onmousemove", this, "onMouseMove"),
				dojo.connect(this.handle, "onmouseup", this, "onMouseUp")
			);
			this._lastX = e.pageX;
			this._lastY = e.pageY;
		}else{
			this.onDragDetected(e);
		}
		dojo.stopEvent(e);
	},
	onMouseMove: function(e){
		// summary:
		//		event processor for onmousemove, used only for delayed drags
		// e: Event
		//		mouse event
		if(Math.abs(e.pageX - this._lastX) > this.delay || Math.abs(e.pageY - this._lastY) > this.delay){
			this.onMouseUp(e);
			this.onDragDetected(e);
		}
		dojo.stopEvent(e);
	},
	onMouseUp: function(e){
		// summary:
		//		event processor for onmouseup, used only for delayed drags
		// e: Event
		//		mouse event
		for(var i = 0; i < 2; ++i){
			dojo.disconnect(this.events.pop());
		}
		dojo.stopEvent(e);
	},
	onSelectStart: function(e){
		// summary:
		//		event processor for onselectevent and ondragevent
		// e: Event
		//		mouse event
		if(!this.skip || !dojo.dnd.isFormElement(e)){
			dojo.stopEvent(e);
		}
	},
	
	// local events
	onDragDetected: function(/* Event */ e){
		// summary:
		//		called when the drag is detected;
		//		responsible for creation of the mover
		new this.mover(this.node, e, this);
	},
	onMoveStart: function(/* dojo.dnd.Mover */ mover){
		// summary:
		//		called before every move operation
		dojo.publish("/dnd/move/start", [mover]);
		dojo.addClass(dojo.body(), "dojoMove"); 
		dojo.addClass(this.node, "dojoMoveItem"); 
	},
	onMoveStop: function(/* dojo.dnd.Mover */ mover){
		// summary:
		//		called after every move operation
		dojo.publish("/dnd/move/stop", [mover]);
		dojo.removeClass(dojo.body(), "dojoMove");
		dojo.removeClass(this.node, "dojoMoveItem");
	},
	onFirstMove: function(/* dojo.dnd.Mover */ mover, /* Event */ e){
		// summary:
		//		called during the very first move notification;
		//		can be used to initialize coordinates, can be overwritten.
		
		// default implementation does nothing
	},
	onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop, /* Event */ e){
		// summary:
		//		called during every move notification;
		//		should actually move the node; can be overwritten.
		this.onMoving(mover, leftTop);
		var s = mover.node.style;
		s.left = leftTop.l + "px";
		s.top  = leftTop.t + "px";
		this.onMoved(mover, leftTop);
	},
	onMoving: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
		// summary:
		//		called before every incremental move; can be overwritten.
		
		// default implementation does nothing
	},
	onMoved: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
		// summary:
		//		called after every incremental move; can be overwritten.
		
		// default implementation does nothing
	}
});

}

if(!dojo._hasResource["dojo.dnd.move"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.dnd.move"] = true;
dojo.provide("dojo.dnd.move");




/*=====
dojo.declare("dojo.dnd.move.__constrainedMoveableArgs", [dojo.dnd.__MoveableArgs], {
	// constraints: Function
	//		Calculates a constraint box.
	//		It is called in a context of the moveable object.
	constraints: function(){},

	// within: Boolean
	//		restrict move within boundaries.
	within: false
});
=====*/

dojo.declare("dojo.dnd.move.constrainedMoveable", dojo.dnd.Moveable, {
	// object attributes (for markup)
	constraints: function(){},
	within: false,
	
	// markup methods
	markupFactory: function(params, node){
		return new dojo.dnd.move.constrainedMoveable(node, params);
	},

	constructor: function(node, params){
		// summary:
		//		an object that makes a node moveable
		// node: Node
		//		a node (or node's id) to be moved
		// params: dojo.dnd.move.__constrainedMoveableArgs?
		//		an optional object with additional parameters;
		//		the rest is passed to the base class
		if(!params){ params = {}; }
		this.constraints = params.constraints;
		this.within = params.within;
	},
	onFirstMove: function(/* dojo.dnd.Mover */ mover){
		// summary:
		//		called during the very first move notification;
		//		can be used to initialize coordinates, can be overwritten.
		var c = this.constraintBox = this.constraints.call(this, mover);
		c.r = c.l + c.w;
		c.b = c.t + c.h;
		if(this.within){
			var mb = dojo.marginBox(mover.node);
			c.r -= mb.w;
			c.b -= mb.h;
		}
	},
	onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
		// summary:
		//		called during every move notification;
		//		should actually move the node; can be overwritten.
		var c = this.constraintBox, s = mover.node.style;
		s.left = (leftTop.l < c.l ? c.l : c.r < leftTop.l ? c.r : leftTop.l) + "px";
		s.top  = (leftTop.t < c.t ? c.t : c.b < leftTop.t ? c.b : leftTop.t) + "px";
	}
});

/*=====
dojo.declare("dojo.dnd.move.__boxConstrainedMoveableArgs", [dojo.dnd.move.__constrainedMoveableArgs], {
	// box: Object
	//		a constraint box
	box: {}
});
=====*/

dojo.declare("dojo.dnd.move.boxConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
	// box:
	//		object attributes (for markup)
	box: {},
	
	// markup methods
	markupFactory: function(params, node){
		return new dojo.dnd.move.boxConstrainedMoveable(node, params);
	},

	constructor: function(node, params){
		// summary:
		//		an object, which makes a node moveable
		// node: Node
		//		a node (or node's id) to be moved
		// params: dojo.dnd.move.__boxConstrainedMoveableArgs?
		//		an optional object with parameters
		var box = params && params.box;
		this.constraints = function(){ return box; };
	}
});

/*=====
dojo.declare("dojo.dnd.move.__parentConstrainedMoveableArgs", [dojo.dnd.move.__constrainedMoveableArgs], {
	// area: String
	//		A parent's area to restrict the move.
	//		Can be "margin", "border", "padding", or "content".
	area: ""
});
=====*/

dojo.declare("dojo.dnd.move.parentConstrainedMoveable", dojo.dnd.move.constrainedMoveable, {
	// area:
	//		object attributes (for markup)
	area: "content",

	// markup methods
	markupFactory: function(params, node){
		return new dojo.dnd.move.parentConstrainedMoveable(node, params);
	},

	constructor: function(node, params){
		// summary:
		//		an object, which makes a node moveable
		// node: Node
		//		a node (or node's id) to be moved
		// params: dojo.dnd.move.__parentConstrainedMoveableArgs?
		//		an optional object with parameters
		var area = params && params.area;
		this.constraints = function(){
			var n = this.node.parentNode, 
				s = dojo.getComputedStyle(n), 
				mb = dojo._getMarginBox(n, s);
			if(area == "margin"){
				return mb;	// Object
			}
			var t = dojo._getMarginExtents(n, s);
			mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
			if(area == "border"){
				return mb;	// Object
			}
			t = dojo._getBorderExtents(n, s);
			mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
			if(area == "padding"){
				return mb;	// Object
			}
			t = dojo._getPadExtents(n, s);
			mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
			return mb;	// Object
		};
	}
});

// WARNING: below are obsolete objects, instead of custom movers use custom moveables (above)

dojo.dnd.move.constrainedMover = function(fun, within){
	// summary:
	//		returns a constrained version of dojo.dnd.Mover
	// description:
	//		this function produces n object, which will put a constraint on 
	//		the margin box of dragged object in absolute coordinates
	// fun: Function
	//		called on drag, and returns a constraint box
	// within: Boolean
	//		if true, constraints the whole dragged object withtin the rectangle, 
	//		otherwise the constraint is applied to the left-top corner

	dojo.deprecated("dojo.dnd.move.constrainedMover, use dojo.dnd.move.constrainedMoveable instead");
	var mover = function(node, e, notifier){
		dojo.dnd.Mover.call(this, node, e, notifier);
	};
	dojo.extend(mover, dojo.dnd.Mover.prototype);
	dojo.extend(mover, {
		onMouseMove: function(e){
			// summary: event processor for onmousemove
			// e: Event: mouse event
			dojo.dnd.autoScroll(e);
			var m = this.marginBox, c = this.constraintBox,
				l = m.l + e.pageX, t = m.t + e.pageY;
			l = l < c.l ? c.l : c.r < l ? c.r : l;
			t = t < c.t ? c.t : c.b < t ? c.b : t;
			this.host.onMove(this, {l: l, t: t});
		},
		onFirstMove: function(){
			// summary: called once to initialize things; it is meant to be called only once
			dojo.dnd.Mover.prototype.onFirstMove.call(this);
			var c = this.constraintBox = fun.call(this);
			c.r = c.l + c.w;
			c.b = c.t + c.h;
			if(within){
				var mb = dojo.marginBox(this.node);
				c.r -= mb.w;
				c.b -= mb.h;
			}
		}
	});
	return mover;	// Object
};

dojo.dnd.move.boxConstrainedMover = function(box, within){
	// summary:
	//		a specialization of dojo.dnd.constrainedMover, which constrains to the specified box
	// box: Object
	//		a constraint box (l, t, w, h)
	// within: Boolean
	//		if true, constraints the whole dragged object withtin the rectangle, 
	//		otherwise the constraint is applied to the left-top corner

	dojo.deprecated("dojo.dnd.move.boxConstrainedMover, use dojo.dnd.move.boxConstrainedMoveable instead");
	return dojo.dnd.move.constrainedMover(function(){ return box; }, within);	// Object
};

dojo.dnd.move.parentConstrainedMover = function(area, within){
	// summary:
	//		a specialization of dojo.dnd.constrainedMover, which constrains to the parent node
	// area: String
	//		"margin" to constrain within the parent's margin box, "border" for the border box,
	//		"padding" for the padding box, and "content" for the content box; "content" is the default value.
	// within: Boolean
	//		if true, constraints the whole dragged object within the rectangle, 
	//		otherwise the constraint is applied to the left-top corner

	dojo.deprecated("dojo.dnd.move.parentConstrainedMover, use dojo.dnd.move.parentConstrainedMoveable instead");
	var fun = function(){
		var n = this.node.parentNode, 
			s = dojo.getComputedStyle(n), 
			mb = dojo._getMarginBox(n, s);
		if(area == "margin"){
			return mb;	// Object
		}
		var t = dojo._getMarginExtents(n, s);
		mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
		if(area == "border"){
			return mb;	// Object
		}
		t = dojo._getBorderExtents(n, s);
		mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
		if(area == "padding"){
			return mb;	// Object
		}
		t = dojo._getPadExtents(n, s);
		mb.l += t.l, mb.t += t.t, mb.w -= t.w, mb.h -= t.h;
		return mb;	// Object
	};
	return dojo.dnd.move.constrainedMover(fun, within);	// Object
};

// patching functions one level up for compatibility

dojo.dnd.constrainedMover = dojo.dnd.move.constrainedMover;
dojo.dnd.boxConstrainedMover = dojo.dnd.move.boxConstrainedMover;
dojo.dnd.parentConstrainedMover = dojo.dnd.move.parentConstrainedMover;

}

if(!dojo._hasResource["dojo.dnd.TimedMoveable"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.dnd.TimedMoveable"] = true;
dojo.provide("dojo.dnd.TimedMoveable");



/*=====
dojo.declare("dojo.dnd.__TimedMoveableArgs", [dojo.dnd.__MoveableArgs], {
	// timeout: Number
	//		delay move by this number of ms,
	//		accumulating position changes during the timeout
	timeout: 0
});
=====*/

(function(){
	// precalculate long expressions
	var oldOnMove = dojo.dnd.Moveable.prototype.onMove;
		
	dojo.declare("dojo.dnd.TimedMoveable", dojo.dnd.Moveable, {
		// summary:
		//		A specialized version of Moveable to support an FPS throttling.
		//		This class puts an upper restriction on FPS, which may reduce 
		//		the CPU load. The additional parameter "timeout" regulates
		//		the delay before actually moving the moveable object.
		
		// object attributes (for markup)
		timeout: 40,	// in ms, 40ms corresponds to 25 fps
	
		constructor: function(node, params){
			// summary:
			//		an object that makes a node moveable with a timer
			// node: Node||String
			//		a node (or node's id) to be moved
			// params: dojo.dnd.__TimedMoveableArgs
			//		object with additional parameters.
			
			// sanitize parameters
			if(!params){ params = {}; }
			if(params.timeout && typeof params.timeout == "number" && params.timeout >= 0){
				this.timeout = params.timeout;
			}
		},
	
		// markup methods
		markupFactory: function(params, node){
			return new dojo.dnd.TimedMoveable(node, params);
		},
	
		onMoveStop: function(/* dojo.dnd.Mover */ mover){
			if(mover._timer){
				// stop timer
				clearTimeout(mover._timer)
				// reflect the last received position
				oldOnMove.call(this, mover, mover._leftTop)
			}
			dojo.dnd.Moveable.prototype.onMoveStop.apply(this, arguments);
		},
		onMove: function(/* dojo.dnd.Mover */ mover, /* Object */ leftTop){
			mover._leftTop = leftTop;
			if(!mover._timer){
				var _t = this;	// to avoid using dojo.hitch()
				mover._timer = setTimeout(function(){
					// we don't have any pending requests
					mover._timer = null;
					// reflect the last received position
					oldOnMove.call(_t, mover, mover._leftTop);
				}, this.timeout);
			}
		}
	});
})();

}

if(!dojo._hasResource["dijit._DialogMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._DialogMixin"] = true;
dojo.provide("dijit._DialogMixin");



dojo.declare("dijit._DialogMixin", null,
	{
		// summary:
		//		This provides functions useful to Dialog and TooltipDialog

		attributeMap: dijit._Widget.prototype.attributeMap,

		execute: function(/*Object*/ formContents){
			// summary:
			//		Callback when the user hits the submit button.
			//		Override this method to handle Dialog execution.
			// description:
			//		After the user has pressed the submit button, the Dialog
			//		first calls onExecute() to notify the container to hide the
			//		dialog and restore focus to wherever it used to be.
			//
			//		*Then* this method is called.
			// type:
			//		callback
		},

		onCancel: function(){
			// summary:
			//	    Called when user has pressed the Dialog's cancel button, to notify container.
			// description:
			//	    Developer shouldn't override or connect to this method;
			//		it's a private communication device between the TooltipDialog
			//		and the thing that opened it (ex: `dijit.form.DropDownButton`)
			// type:
			//		protected
		},

		onExecute: function(){
			// summary:
			//	    Called when user has pressed the dialog's OK button, to notify container.
			// description:
			//	    Developer shouldn't override or connect to this method;
			//		it's a private communication device between the TooltipDialog
			//		and the thing that opened it (ex: `dijit.form.DropDownButton`)
			// type:
			//		protected
		},

		_onSubmit: function(){
			// summary:
			//		Callback when user hits submit button
			// type:
			//		protected
			this.onExecute();	// notify container that we are about to execute
			this.execute(this.get('value'));
		},

		_getFocusItems: function(/*Node*/ dialogNode){
			// summary:
			//		Find focusable Items each time a dialog is opened,
			//		setting _firstFocusItem and _lastFocusItem
			// tags:
			//		protected

			var elems = dijit._getTabNavigable(dojo.byId(dialogNode));
			this._firstFocusItem = elems.lowest || elems.first || dialogNode;
			this._lastFocusItem = elems.last || elems.highest || this._firstFocusItem;
			if(dojo.isMoz && this._firstFocusItem.tagName.toLowerCase() == "input" &&
					dojo.getNodeProp(this._firstFocusItem, "type").toLowerCase() == "file"){
				// FF doesn't behave well when first element is input type=file, set first focusable to dialog container
				dojo.attr(dialogNode, "tabIndex", "0");
				this._firstFocusItem = dialogNode;
			}
		}
	}
);

}

if(!dojo._hasResource["dijit.DialogUnderlay"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.DialogUnderlay"] = true;
dojo.provide("dijit.DialogUnderlay");






dojo.declare(
	"dijit.DialogUnderlay",
	[dijit._Widget, dijit._Templated],
	{
		// summary:
		//		The component that blocks the screen behind a `dijit.Dialog`
		//
		// description:
		// 		A component used to block input behind a `dijit.Dialog`. Only a single
		//		instance of this widget is created by `dijit.Dialog`, and saved as
		//		a reference to be shared between all Dialogs as `dijit._underlay`
		//
		//		The underlay itself can be styled based on and id:
		//	|	#myDialog_underlay { background-color:red; }
		//
		//		In the case of `dijit.Dialog`, this id is based on the id of the Dialog,
		//		suffixed with _underlay.

		// Template has two divs; outer div is used for fade-in/fade-out, and also to hold background iframe.
		// Inner div has opacity specified in CSS file.
		templateString: "<div class='dijitDialogUnderlayWrapper'><div class='dijitDialogUnderlay' dojoAttachPoint='node'></div></div>",

		// Parameters on creation or updatable later

		// dialogId: String
		//		Id of the dialog.... DialogUnderlay's id is based on this id
		dialogId: "",

		// class: String
		//		This class name is used on the DialogUnderlay node, in addition to dijitDialogUnderlay
		"class": "",

		attributeMap: { id: "domNode" },

		_setDialogIdAttr: function(id){
			dojo.attr(this.node, "id", id + "_underlay");
		},

		_setClassAttr: function(clazz){
			this.node.className = "dijitDialogUnderlay " + clazz;
		},

		postCreate: function(){
			// summary:
			//		Append the underlay to the body
			dojo.body().appendChild(this.domNode);
		},

		layout: function(){
			// summary:
			//		Sets the background to the size of the viewport
			//
			// description:
			//		Sets the background to the size of the viewport (rather than the size
			//		of the document) since we need to cover the whole browser window, even
			//		if the document is only a few lines long.
			// tags:
			//		private

			var is = this.node.style,
				os = this.domNode.style;

			// hide the background temporarily, so that the background itself isn't
			// causing scrollbars to appear (might happen when user shrinks browser
			// window and then we are called to resize)
			os.display = "none";

			// then resize and show
			var viewport = dojo.window.getBox();
			os.top = viewport.t + "px";
			os.left = viewport.l + "px";
			is.width = viewport.w + "px";
			is.height = viewport.h + "px";
			os.display = "block";
		},

		show: function(){
			// summary:
			//		Show the dialog underlay
			this.domNode.style.display = "block";
			this.layout();
			this.bgIframe = new dijit.BackgroundIframe(this.domNode);
		},

		hide: function(){
			// summary:
			//		Hides the dialog underlay
			this.bgIframe.destroy();
			this.domNode.style.display = "none";
		},

		uninitialize: function(){
			if(this.bgIframe){
				this.bgIframe.destroy();
			}
			this.inherited(arguments);
		}
	}
);

}

if(!dojo._hasResource["dijit.TooltipDialog"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.TooltipDialog"] = true;
dojo.provide("dijit.TooltipDialog");






dojo.declare(
		"dijit.TooltipDialog",
		[dijit.layout.ContentPane, dijit._Templated, dijit.form._FormMixin, dijit._DialogMixin],
		{
			// summary:
			//		Pops up a dialog that appears like a Tooltip

			// title: String
			// 		Description of tooltip dialog (required for a11y)
			title: "",

			// doLayout: [protected] Boolean
			//		Don't change this parameter from the default value.
			//		This ContentPane parameter doesn't make sense for TooltipDialog, since TooltipDialog
			//		is never a child of a layout container, nor can you specify the size of
			//		TooltipDialog in order to control the size of an inner widget.
			doLayout: false,

			// autofocus: Boolean
			// 		A Toggle to modify the default focus behavior of a Dialog, which
			// 		is to focus on the first dialog element after opening the dialog.
			//		False will disable autofocusing. Default: true
			autofocus: true,

			// baseClass: [protected] String
			//		The root className to use for the various states of this widget
			baseClass: "dijitTooltipDialog",

			// _firstFocusItem: [private] [readonly] DomNode
			//		The pointer to the first focusable node in the dialog.
			//		Set by `dijit._DialogMixin._getFocusItems`.
			_firstFocusItem: null,

			// _lastFocusItem: [private] [readonly] DomNode
			//		The pointer to which node has focus prior to our dialog.
			//		Set by `dijit._DialogMixin._getFocusItems`.
			_lastFocusItem: null,

			templateString: dojo.cache("dijit", "templates/TooltipDialog.html", "<div waiRole=\"presentation\">\n\t<div class=\"dijitTooltipContainer\" waiRole=\"presentation\">\n\t\t<div class =\"dijitTooltipContents dijitTooltipFocusNode\" dojoAttachPoint=\"containerNode\" tabindex=\"-1\" waiRole=\"dialog\"></div>\n\t</div>\n\t<div class=\"dijitTooltipConnector\" waiRole=\"presentation\"></div>\n</div>\n"),

			postCreate: function(){
				this.inherited(arguments);
				this.connect(this.containerNode, "onkeypress", "_onKey");
				this.containerNode.title = this.title;
			},

			orient: function(/*DomNode*/ node, /*String*/ aroundCorner, /*String*/ corner){
				// summary:
				//		Configure widget to be displayed in given position relative to the button.
				//		This is called from the dijit.popup code, and should not be called
				//		directly.
				// tags:
				//		protected
				var c = this._currentOrientClass;
				if(c){
					dojo.removeClass(this.domNode, c);
				}
				c = "dijitTooltipAB"+(corner.charAt(1) == 'L'?"Left":"Right")+" dijitTooltip"+(corner.charAt(0) == 'T' ? "Below" : "Above");
				dojo.addClass(this.domNode, c);
				this._currentOrientClass = c;
			},

			onOpen: function(/*Object*/ pos){
				// summary:
				//		Called when dialog is displayed.
				//		This is called from the dijit.popup code, and should not be called directly.
				// tags:
				//		protected

				this.orient(this.domNode,pos.aroundCorner, pos.corner);
				this._onShow(); // lazy load trigger

				if(this.autofocus){
					this._getFocusItems(this.containerNode);
					dijit.focus(this._firstFocusItem);
				}
			},

			onClose: function(){
				// summary:
				//		Called when dialog is hidden.
				//		This is called from the dijit.popup code, and should not be called directly.
				// tags:
				//		protected
				this.onHide();
			},

			_onKey: function(/*Event*/ evt){
				// summary:
				//		Handler for keyboard events
				// description:
				//		Keep keyboard focus in dialog; close dialog on escape key
				// tags:
				//		private

				var node = evt.target;
				var dk = dojo.keys;
				if(evt.charOrCode === dk.TAB){
					this._getFocusItems(this.containerNode);
				}
				var singleFocusItem = (this._firstFocusItem == this._lastFocusItem);
				if(evt.charOrCode == dk.ESCAPE){
					// Use setTimeout to avoid crash on IE, see #10396.
					setTimeout(dojo.hitch(this, "onCancel"), 0);
					dojo.stopEvent(evt);
				}else if(node == this._firstFocusItem && evt.shiftKey && evt.charOrCode === dk.TAB){
					if(!singleFocusItem){
						dijit.focus(this._lastFocusItem); // send focus to last item in dialog
					}
					dojo.stopEvent(evt);
				}else if(node == this._lastFocusItem && evt.charOrCode === dk.TAB && !evt.shiftKey){
					if(!singleFocusItem){
						dijit.focus(this._firstFocusItem); // send focus to first item in dialog
					}
					dojo.stopEvent(evt);
				}else if(evt.charOrCode === dk.TAB){
					// we want the browser's default tab handling to move focus
					// but we don't want the tab to propagate upwards
					evt.stopPropagation();
				}
			}
		}
	);

}

if(!dojo._hasResource["dijit.Dialog"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Dialog"] = true;
dojo.provide("dijit.Dialog");















/*=====
dijit._underlay = function(kwArgs){
	// summary:
	//		A shared instance of a `dijit.DialogUnderlay`
	//
	// description:
	//		A shared instance of a `dijit.DialogUnderlay` created and
	//		used by `dijit.Dialog`, though never created until some Dialog
	//		or subclass thereof is shown.
};
=====*/

dojo.declare(
	"dijit._DialogBase",
	[dijit._Templated, dijit.form._FormMixin, dijit._DialogMixin, dijit._CssStateMixin],
	{
		// summary:
		//		A modal dialog Widget
		//
		// description:
		//		Pops up a modal dialog window, blocking access to the screen
		//		and also graying out the screen Dialog is extended from
		//		ContentPane so it supports all the same parameters (href, etc.)
		//
		// example:
		// |	<div dojoType="dijit.Dialog" href="test.html"></div>
		//
		// example:
		// |	var foo = new dijit.Dialog({ title: "test dialog", content: "test content" };
		// |	dojo.body().appendChild(foo.domNode);
		// |	foo.startup();

		templateString: dojo.cache("dijit", "templates/Dialog.html", "<div class=\"dijitDialog\" tabindex=\"-1\" waiRole=\"dialog\" waiState=\"labelledby-${id}_title\">\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"></span>\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"onclick: onCancel\" title=\"${buttonCancel}\">\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t</span>\n\t</div>\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n</div>\n"),
		
		baseClass: "dijitDialog",
		
		cssStateNodes: {
			closeButtonNode: "dijitDialogCloseIcon"
		},

		attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
			title: [
				{ node: "titleNode", type: "innerHTML" },
				{ node: "titleBar", type: "attribute" }
			],
			"aria-describedby":""
		}),

		// open: Boolean
		//		True if Dialog is currently displayed on screen.
		open: false,

		// duration: Integer
		//		The time in milliseconds it takes the dialog to fade in and out
		duration: dijit.defaultDuration,

		// refocus: Boolean
		// 		A Toggle to modify the default focus behavior of a Dialog, which
		// 		is to re-focus the element which had focus before being opened.
		//		False will disable refocusing. Default: true
		refocus: true,

		// autofocus: Boolean
		// 		A Toggle to modify the default focus behavior of a Dialog, which
		// 		is to focus on the first dialog element after opening the dialog.
		//		False will disable autofocusing. Default: true
		autofocus: true,

		// _firstFocusItem: [private] [readonly] DomNode
		//		The pointer to the first focusable node in the dialog.
		//		Set by `dijit._DialogMixin._getFocusItems`.
		_firstFocusItem: null,

		// _lastFocusItem: [private] [readonly] DomNode
		//		The pointer to which node has focus prior to our dialog.
		//		Set by `dijit._DialogMixin._getFocusItems`.
		_lastFocusItem: null,

		// doLayout: [protected] Boolean
		//		Don't change this parameter from the default value.
		//		This ContentPane parameter doesn't make sense for Dialog, since Dialog
		//		is never a child of a layout container, nor can you specify the size of
		//		Dialog in order to control the size of an inner widget.
		doLayout: false,

		// draggable: Boolean
		//		Toggles the moveable aspect of the Dialog. If true, Dialog
		//		can be dragged by it's title. If false it will remain centered
		//		in the viewport.
		draggable: true,

		//aria-describedby: String
		//		Allows the user to add an aria-describedby attribute onto the dialog.   The value should
		//		be the id of the container element of text that describes the dialog purpose (usually
		//		the first text in the dialog).
		//		<div dojoType="dijit.Dialog" aria-describedby="intro" .....>
		//			<div id="intro">Introductory text</div>
		//			<div>rest of dialog contents</div>
		//		</div>
		"aria-describedby":"",

		postMixInProperties: function(){
			var _nlsResources = dojo.i18n.getLocalization("dijit", "common");
			dojo.mixin(this, _nlsResources);
			this.inherited(arguments);
		},

		postCreate: function(){
			dojo.style(this.domNode, {
				display: "none",
				position:"absolute"
			});
			dojo.body().appendChild(this.domNode);

			this.inherited(arguments);

			this.connect(this, "onExecute", "hide");
			this.connect(this, "onCancel", "hide");
			this._modalconnects = [];
		},

		onLoad: function(){
			// summary:
			//		Called when data has been loaded from an href.
			//		Unlike most other callbacks, this function can be connected to (via `dojo.connect`)
			//		but should *not* be overriden.
			// tags:
			//		callback

			// when href is specified we need to reposition the dialog after the data is loaded
			// and find the focusable elements
			this._position();
			if(this.autofocus){
				this._getFocusItems(this.domNode);
				dijit.focus(this._firstFocusItem);
			}
			this.inherited(arguments);
		},

		_endDrag: function(e){
			// summary:
			//		Called after dragging the Dialog. Saves the position of the dialog in the viewport.
			// tags:
			//		private
			if(e && e.node && e.node === this.domNode){
				this._relativePosition = dojo.position(e.node);
			}
		},

		_setup: function(){
			// summary:
			//		Stuff we need to do before showing the Dialog for the first
			//		time (but we defer it until right beforehand, for
			//		performance reasons).
			// tags:
			//		private

			var node = this.domNode;

			if(this.titleBar && this.draggable){
				this._moveable = (dojo.isIE == 6) ?
					new dojo.dnd.TimedMoveable(node, { handle: this.titleBar }) :	// prevent overload, see #5285
					new dojo.dnd.Moveable(node, { handle: this.titleBar, timeout: 0 });
				dojo.subscribe("/dnd/move/stop",this,"_endDrag");
			}else{
				dojo.addClass(node,"dijitDialogFixed");
			}

			this.underlayAttrs = {
				dialogId: this.id,
				"class": dojo.map(this["class"].split(/\s/), function(s){ return s+"_underlay"; }).join(" ")
			};

			this._fadeIn = dojo.fadeIn({
				node: node,
				duration: this.duration,
				beforeBegin: dojo.hitch(this, function(){
					var underlay = dijit._underlay;
					if(!underlay){
						underlay = dijit._underlay = new dijit.DialogUnderlay(this.underlayAttrs);
					}else{
						underlay.set(this.underlayAttrs);
					}

					var ds = dijit._dialogStack,
						zIndex = 948 + ds.length*2;
					if(ds.length == 1){	// first dialog
						underlay.show();
					}
					dojo.style(dijit._underlay.domNode, 'zIndex', zIndex);
					dojo.style(this.domNode, 'zIndex', zIndex + 1);
				}),
				onEnd: dojo.hitch(this, function(){
					if(this.autofocus){
						// find focusable Items each time dialog is shown since if dialog contains a widget the
						// first focusable items can change
						this._getFocusItems(this.domNode);
						dijit.focus(this._firstFocusItem);
					}
				})
			 });

			this._fadeOut = dojo.fadeOut({
				node: node,
				duration: this.duration,
				onEnd: dojo.hitch(this, function(){
					node.style.display = "none";

					// Restore the previous dialog in the stack, or if this is the only dialog
					// then restore to original page
					var ds = dijit._dialogStack;
					if(ds.length == 0){
						dijit._underlay.hide();
					}else{
						dojo.style(dijit._underlay.domNode, 'zIndex', 948 + ds.length*2);
						dijit._underlay.set(ds[ds.length-1].underlayAttrs);
					}

					// Restore focus to wherever it was before this dialog was displayed
					if(this.refocus){
						var focus = this._savedFocus;

						// If we are returning control to a previous dialog but for some reason
						// that dialog didn't have a focused field, set focus to first focusable item.
						// This situation could happen if two dialogs appeared at nearly the same time,
						// since a dialog doesn't set it's focus until the fade-in is finished.
						if(ds.length > 0){
							var pd = ds[ds.length-1];
							if(!dojo.isDescendant(focus.node, pd.domNode)){
								pd._getFocusItems(pd.domNode);
								focus = pd._firstFocusItem;
							}
						}

						dijit.focus(focus);
					}
				})
			 });
		},

		uninitialize: function(){
			var wasPlaying = false;
			if(this._fadeIn && this._fadeIn.status() == "playing"){
				wasPlaying = true;
				this._fadeIn.stop();
			}
			if(this._fadeOut && this._fadeOut.status() == "playing"){
				wasPlaying = true;
				this._fadeOut.stop();
			}
			
			// Hide the underlay, unless the underlay widget has already been destroyed
			// because we are being called during page unload (when all widgets are destroyed)
			if((this.open || wasPlaying) && !dijit._underlay._destroyed){
				dijit._underlay.hide();
			}

			if(this._moveable){
				this._moveable.destroy();
			}
			this.inherited(arguments);
		},

		_size: function(){
			// summary:
			// 		If necessary, shrink dialog contents so dialog fits in viewport
			// tags:
			//		private

			this._checkIfSingleChild();

			// If we resized the dialog contents earlier, reset them back to original size, so
			// that if the user later increases the viewport size, the dialog can display w/out a scrollbar.
			// Need to do this before the dojo.marginBox(this.domNode) call below.
			if(this._singleChild){
				if(this._singleChildOriginalStyle){
					this._singleChild.domNode.style.cssText = this._singleChildOriginalStyle;
				}
				delete this._singleChildOriginalStyle;
			}else{
				dojo.style(this.containerNode, {
					width:"auto",
					height:"auto"
				});
			}

			var mb = dojo.marginBox(this.domNode);
			var viewport = dojo.window.getBox();
			if(mb.w >= viewport.w || mb.h >= viewport.h){
				// Reduce size of dialog contents so that dialog fits in viewport

				var w = Math.min(mb.w, Math.floor(viewport.w * 0.75)),
					h = Math.min(mb.h, Math.floor(viewport.h * 0.75));

				if(this._singleChild && this._singleChild.resize){
					this._singleChildOriginalStyle = this._singleChild.domNode.style.cssText;
					this._singleChild.resize({w: w, h: h});
				}else{
					dojo.style(this.containerNode, {
						width: w + "px",
						height: h + "px",
						overflow: "auto",
						position: "relative"	// workaround IE bug moving scrollbar or dragging dialog
					});
				}
			}else{
				if(this._singleChild && this._singleChild.resize){
					this._singleChild.resize();
				}
			}
		},

		_position: function(){
			// summary:
			//		Position modal dialog in the viewport. If no relative offset
			//		in the viewport has been determined (by dragging, for instance),
			//		center the node. Otherwise, use the Dialog's stored relative offset,
			//		and position the node to top: left: values based on the viewport.
			// tags:
			//		private
			if(!dojo.hasClass(dojo.body(),"dojoMove")){
				var node = this.domNode,
					viewport = dojo.window.getBox(),
					p = this._relativePosition,
					bb = p ? null : dojo._getBorderBox(node),
					l = Math.floor(viewport.l + (p ? p.x : (viewport.w - bb.w) / 2)),
					t = Math.floor(viewport.t + (p ? p.y : (viewport.h - bb.h) / 2))
				;
				dojo.style(node,{
					left: l + "px",
					top: t + "px"
				});
			}
		},

		_onKey: function(/*Event*/ evt){
			// summary:
			//		Handles the keyboard events for accessibility reasons
			// tags:
			//		private

			var ds = dijit._dialogStack;
			if(ds[ds.length-1] != this){
				// console.debug(this.id + ': skipping because', this, 'is not the active dialog');
				return;
			}

			if(evt.charOrCode){
				var dk = dojo.keys;
				var node = evt.target;
				if(evt.charOrCode === dk.TAB){
					this._getFocusItems(this.domNode);
				}
				var singleFocusItem = (this._firstFocusItem == this._lastFocusItem);
				// see if we are shift-tabbing from first focusable item on dialog
				if(node == this._firstFocusItem && evt.shiftKey && evt.charOrCode === dk.TAB){
					if(!singleFocusItem){
						dijit.focus(this._lastFocusItem); // send focus to last item in dialog
					}
					dojo.stopEvent(evt);
				}else if(node == this._lastFocusItem && evt.charOrCode === dk.TAB && !evt.shiftKey){
					if(!singleFocusItem){
						dijit.focus(this._firstFocusItem); // send focus to first item in dialog
					}
					dojo.stopEvent(evt);
				}else{
					// see if the key is for the dialog
					while(node){
						if(node == this.domNode || dojo.hasClass(node, "dijitPopup")){
							if(evt.charOrCode == dk.ESCAPE){
								this.onCancel();
							}else{
								return; // just let it go
							}
						}
						node = node.parentNode;
					}
					// this key is for the disabled document window
					if(evt.charOrCode !== dk.TAB){ // allow tabbing into the dialog for a11y
						dojo.stopEvent(evt);
					// opera won't tab to a div
					}else if(!dojo.isOpera){
						try{
							this._firstFocusItem.focus();
						}catch(e){ /*squelch*/ }
					}
				}
			}
		},

		show: function(){
			// summary:
			//		Display the dialog
			if(this.open){ return; }

			// first time we show the dialog, there's some initialization stuff to do
			if(!this._alreadyInitialized){
				this._setup();
				this._alreadyInitialized=true;
			}

			if(this._fadeOut.status() == "playing"){
				this._fadeOut.stop();
			}

			this._modalconnects.push(dojo.connect(window, "onscroll", this, "layout"));
			this._modalconnects.push(dojo.connect(window, "onresize", this, function(){
				// IE gives spurious resize events and can actually get stuck
				// in an infinite loop if we don't ignore them
				var viewport = dojo.window.getBox();
				if(!this._oldViewport ||
						viewport.h != this._oldViewport.h ||
						viewport.w != this._oldViewport.w){
					this.layout();
					this._oldViewport = viewport;
				}
			}));
			this._modalconnects.push(dojo.connect(dojo.doc.documentElement, "onkeypress", this, "_onKey"));

			dojo.style(this.domNode, {
				opacity:0,
				display:""
			});

			this.open = true;
			this._onShow(); // lazy load trigger

			this._size();
			this._position();
			dijit._dialogStack.push(this);
			this._fadeIn.play();

			this._savedFocus = dijit.getFocus(this);
		},

		hide: function(){
			// summary:
			//		Hide the dialog

			// if we haven't been initialized yet then we aren't showing and we can just return
			// or if we aren't the active dialog, don't allow us to close yet
			var ds = dijit._dialogStack;
			if(!this._alreadyInitialized || this != ds[ds.length-1]){
				return;
			}

			if(this._fadeIn.status() == "playing"){
				this._fadeIn.stop();
			}

			// throw away current active dialog from stack -- making the previous dialog or the node on the original page active
			ds.pop();

			this._fadeOut.play();

			if(this._scrollConnected){
				this._scrollConnected = false;
			}
			dojo.forEach(this._modalconnects, dojo.disconnect);
			this._modalconnects = [];

			if(this._relativePosition){
				delete this._relativePosition;
			}
			this.open = false;

			this.onHide();
		},

		layout: function(){
			// summary:
			//		Position the Dialog and the underlay
			// tags:
			//		private
			if(this.domNode.style.display != "none"){
				if(dijit._underlay){	// avoid race condition during show()
					dijit._underlay.layout();
				}
				this._position();
			}
		},

		destroy: function(){
			dojo.forEach(this._modalconnects, dojo.disconnect);
			if(this.refocus && this.open){
				setTimeout(dojo.hitch(dijit,"focus",this._savedFocus), 25);
			}
			this.inherited(arguments);
		}
	}
);

dojo.declare(
	"dijit.Dialog",
	[dijit.layout.ContentPane, dijit._DialogBase],
	{}
);

// Stack of currenctly displayed dialogs, layered on top of each other
dijit._dialogStack = [];

// For back-compat.  TODO: remove in 2.0


}

if(!dojo._hasResource['com.sixnet.services.core.dashBoard']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.core.dashBoard'] = true;

dojo.provide('com.sixnet.services.core.dashBoard');










dojo.provide('com.sixnet.services.core.dashBoardDialog');
dojo.declare('com.sixnet.services.core.dashBoardDialog', [dijit.Dialog], {
//	templateString:"<div class=\"dijitDialog dashBoardDialog\" tabindex=\"-1\" waiRole=\"dialog\" waiState=\"labelledby-${id}_title\">\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\">\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\"></span>\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" dojoAttachEvent=\"onclick: onCancel, onmouseenter: _onCloseEnter, onmouseleave: _onCloseLeave\" title=\"${buttonCancel}\">\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\">x</span>\n\t</span>\n\t</div>\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\"></div>\n</div>\n"
	//templateString:"<div class=\"dijitDialog dashBoardDialog\" style=\"background-color:transparent; border:none; text-decoration:none; outline:none\" tabindex=\"100\" waiRole=\"dialog\" waiState=\"labelledby-${id}_title\">\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\" style=\"background:transparent; border:none;\"></div>\n</div>\n"
templateString: "<div class=\"dijitDialog\" style=\"background-color:transparent; border:none; text-decoration:none; outline:none\" tabindex=\"-1\" waiRole=\"dialog\" waiState=\"labelledby-${id}_title\">\n\t<div dojoAttachPoint=\"titleBar\" class=\"dijitDialogTitleBar\" style=\"display:none\">\n\t<span dojoAttachPoint=\"titleNode\" class=\"dijitDialogTitle\" id=\"${id}_title\" style=\"display:none\"></span>\n\t<span dojoAttachPoint=\"closeButtonNode\" class=\"dijitDialogCloseIcon\" style=\"display:none\" dojoAttachEvent=\"onclick: onCancel\" title=\"${buttonCancel}\">\n\t\t<span dojoAttachPoint=\"closeText\" class=\"closeText\" title=\"${buttonCancel}\" style=\"display:none\">x</span>\n\t</span>\n\t</div>\n\t\t<div dojoAttachPoint=\"containerNode\" class=\"dijitDialogPaneContent\" style=\"background:transparent; border:none\"></div>\n</div>\n"
});

dojo.declare('com.sixnet.services.core.dashBoard', [dijit._Widget, dijit._Templated], {
	paneWrappers: false,
	widgetsInTemplate: true,
	parseOnLoad: true,
	_app: null,
	_instances: false,
	_subscriptions: false,
	_dashPane: false,
	_currentWidgetPane: false,
	dashHolder: false,
	region: "center",
	templateString:"<div>\n\t<div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\" liveSplitters=\"false\" dojoAttachPoint=\"_body\" style=\"border:none;\" >\n\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"_header\" region=\"top\" parseOnLoad=\"true\" href=\"dojo/com/sixnet/services/core/templates/dashBoardHeader.html\" style=\"height:33px\" >\n\t\t</div>\n\n\t\t<div class=\"headerChild3\"></div>\n\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"left\" class=\"runningAppsMain\" title=\"Running Apps\"  splitter=\"false\">\n\t\t\t<div class=\"runningAppsGR\"><img alt=\"Runnning Apps\" src=\"dojo/com/sixnet/services/core/templates/images/running_apps.png\" /></div>\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"text-align:center;\" dojoAttachPoint=\"dashStack\" splitter=\"false\">\n\t\t\t</div>\n\t\t</div>\n\t\t\n\n\t\t<div dojoType=\"dijit.layout.BorderContainer\" region=\"center\" dojoAttachPoint=\"dashView\"  gutters=\"false\" liveSplitters=\"false\" class=\"dashViewMain\" >\n\t\t</div>\n\n\t\n\t\t<div dojoType=\"dijit.layout.ContentPane\" splitter=\"false\" dojoAttachPoint=\"_footer\" region=\"bottom\" href=\"dojo/com/sixnet/services/core/templates/dashBoardFooter.html\" class=\"dashBoardFooter\">\n\t\t\n\t\t</div>\n\t</div>\n</div>\n",
	constructor: function(){
		this.paneWrappers = {};
		this._instances = [];
		this._subscriptions = [];
		this._dashPane = new dijit.layout.ContentPane({ parseOnLoad:true});
		this._dashPane.attr("href", dojo.moduleUrl('com.sixnet.services.core', 'templates/dashStackPane.html'));
	},
	destroy:function(){
		this.unloadDash();
		this._dashPane.destroyRecursive();
	},
	criticalFail: function(message){
		alert(message);
		this.showDashWidgets();
	},	
	postCreate: function(){
		this.inherited(arguments);
		this.containerNode = this.domNode;
		this.connect( this, "resize", "onResize");		
		this._app.addChild(this);
		_sixnet_framework.log(1, this, "  << postCreate in dashBoard.js");
	},
	dismount: function(){
		this._app.removeChild(this);
	},
	showDashBoard: function(){
		try{
			if( this._app._centerWidget ) this._app.removeChild(this._app._centerWidget);
			this._app.addChild(this);
		}catch(e){console.debug(e);}
		this.showDashWidgets();
	},
	unloadDash: function(){
		// unload the current dash widgets.
		this.switchDashWidgets( function(){}, false, true);
	},
	switchDashWidgets: function(callback, instance, outOnly){
// ----=- replace end -=----
		var dashView = this.dashView;
		var dashNode = dashView.domNode;
		if(!dashNode) return;
		dashNode.style.opacity = 1;
		try{
			// Putting the dash board client widget in place. 
			// Since this hides the dashboard, we need a way to get back.. remove our node and put it back.
			try{
				this.removeFromWidgetStack( this._dashPane);
			}catch(e){
				// we may not have added it yet...
				_sixnet_framework.log("dashBoard.js ERROR ln79:  ", e);
			}
			
			this.addToWidgetStack( this._dashPane, false);
			var viewport = dijit.getViewport();
			var outAnim = dojo._fade({ duration: 400, node: dashNode, start:1, end:0.1});
			//  something up here, in IE, of course.
			outAnim.play(0.1);
			/* IE: Invalid argument.  dojo.js, line 16 character 45031
			 * breaks at dojo.connect. 			 */
			dojo.connect(outAnim, "onEnd", this, dojo.hitch(this, function(){
				// never gets here.  Invalid argument.  dojo.js, line 16 character 45031
				dojo.forEach( this.dashView.getChildren(), dojo.hitch(this, function(dashWidget){
					this.dashView.removeChild(dashWidget);
					if(dashWidget.onHide) dashWidget.onHide();
				}));
//				dojo.forEach( dojo.query('div.dashBoardWidget', dashView.domNode), dojo.hitch( this, function(node){
//					try{
//						var dashWidget = dijit.byId(node.id);
//						if( typeof(dashWidget) != 'undefined' ){
//							if(dashWidget.onHide) dashWidget.onHide();
//						}
//					}catch(e){
//						_sixnet_framework.log(1, 'ah..no', node.id, dashWidget, this, e);
//					}
//					try{
//						dashView.domNode.removeChild(node);
//					}catch(e){
//						// not a real solution.  Bandaid.
//					}
//				}));
				
				callback();
				

				if(outOnly){
					this._currentWidgetPane = false;
					return;
				}
				var inAnim = dojo._fade({ duration: 400, node: dashNode, start:0.1, end:1});
				inAnim.play(0.1);
				dojo.connect( inAnim, "onEnd", dojo.hitch(this, function(){
					if( instance){
						instance.resize();
						instance.onShow();
					}
				}));
			}));
			if( instance)
				this._currentWidgetPane = instance.getWidgetThumbnailPane();
			else
				this._currentWidgetPane = false;
		}catch(e){
			console.debug(e, dojo, " switchDashWidgets catch of error");
		}
		
	},
	onHideWidget: function( widget){
		// connect to this method to be alerted when your widget is hidden
	},
	
	onShowWidget: function( widget){
		// connect to this method to be alerted when your widget is shown
	},
	
	runApp: function(widgetName, appParams, background){
		if(_sixnet_framework.workingCount) return;
		try{
				
			if( dojo.bumpCache) {
				dojo.bumpCache();
			}
			
			if(typeof(appParams)=='undefined') appParams = {};
			if(typeof(background)=='undefined') background = false;
			
			
			
			dojo["require"]( widgetName);
			var self = this;
			var loadWidgetCallback = function(){
				var cls = dojo.getObject(widgetName);
				if(!dojo.isFunction(cls)){
					setTimeout(loadWidgetCallback, 50);
					return;
				}
				
				var instance ;
				
	//			if(_sixnet_framework.noCache){
	//				instance = self.instantiate(widgetName, { dashBoard: self, region:"center", appParams: appParams});
	//				if(	instance  && 
	//						instance.startup &&
	//						!instance._started && 
	//						(!instance.getParent || !instance.getParent())
	//					){
	//					instance.startup();
	//				}
	//			}else{
					var elem = dojo.doc.createElement('div');
					elem.setAttribute('dojoType', widgetName);
					var instances = dojo.parser.instantiate([elem], { dashBoard: self, region:"center", appParams: appParams});
					instance = instances[0];
				//}
				var thumbPane = instance.getWidgetThumbnailPane();
				if( thumbPane){
					self.addToWidgetStack( thumbPane, instance);
				}
				if( !background){
					self.switchDashWidgets( dojo.hitch(self, function(){
						dojo.addClass( instance.domNode, "dashApp");
						dojo.addClass( instance.domNode, "dashBoardWidget");
						try{
						this.dashView.addChild(instance);
						}catch(e){
							_sixnet_framework.log(1, "Could not add dash Child", e);
						}
					}), instance, false);
				}else{
					
				}
			};
			dojo.addOnLoad(loadWidgetCallback);
		}catch(e){
			_sixnet_framework.log(1, "In Runapp:", e);
		}
	},
	removeFromWidgetStack: function(pane){
		var wrapper = this.paneWrappers[pane.id];
		if( typeof(wrapper) != 'undefined'){
			if(dojo.exists("dashStack.domNode", this)){
				this.dashStack.domNode.removeChild(wrapper.domNode);
				delete this.paneWrappers[pane.id];
			}
		}
		if( this._currentWidgetPane == pane){
			this.showDashWidgets();
		}
	},
	addToWidgetStack: function(newPane, instance, noCloseButton){
		if( typeof(noCloseButton)=='undefined') noCloseButton = false;
		// hand build some layout divs.
		// TODO: Put this in a templated class
		var wrapper = {};
		this.paneWrappers[newPane.id] = wrapper;
		
		var wrapperDiv = dojo.doc.createElement('div');
		wrapper.domNode = wrapperDiv;
		
		dojo.addClass( wrapper.domNode, "paneWrapper");
		
		var leftDiv = dojo.doc.createElement('div');
		if( instance){
			dojo.addClass( leftDiv, "leftWrapperPane2");
		}else{
			dojo.addClass( leftDiv, "centerWrapperPane");
		}
		
		leftDiv.appendChild( newPane.domNode);

		wrapperDiv.appendChild(leftDiv);
		
		if( instance && !noCloseButton){
			var rightDiv = dojo.doc.createElement('div');
			dojo.addClass(rightDiv, "rightWrapperPane2");		
			wrapperDiv.appendChild(rightDiv);
			dojo.attr(rightDiv, {onclick:
				dojo.hitch(this,function(instance, pane){
				if(this._currentWidgetPane == instance.getWidgetThumbnailPane()){
					this.dashView.removeChild(instance);
				}
				instance.destroyRecursive();}, instance, wrapperDiv)
			});


		}
		
		this.dashStack.domNode.appendChild(wrapperDiv);
		
		
		
		newPane.connect( leftDiv, "onclick", dojo.hitch(this, function(instance){
			if( !instance){
				if( this._currentWidgetPane) // or don't do anything, the dash is already showing.
					this.showDashWidgets();
				}else{			 
				if( instance.getWidgetThumbnailPane() == this._currentWidgetPane) return;  // this app is already showing
				this.switchDashWidgets( dojo.hitch( this, function(){
					this.dashView.addChild( instance);
					//instance.placeAt( this.dashView.domNode);
					//this.onShowWidget(instance);
					//if(instance.onShow) instance.onShow();
				}), instance, false);
			}
		}, instance)); // close instance inside here
	},
	showDashWidgets: function(){		
		var interval = setInterval( dojo.hitch( this, function(){
			if( !this.dashView) return;
			clearInterval(interval);
			this.switchDashWidgets( dojo.hitch(this, function(){
				if( !this.dashHolder ){
					this.dashHolder = new com.sixnet.services.core.dashWidgetHolder({ dashBoard: this});
					dojo.forEach( this._instances, dojo.hitch(this, function(instance){
						this.dashHolder.addChild(instance);
					}));	
				}
				this.dashView.addChild(this.dashHolder);	
			}), false, false);
			// NEIL TODO
			//dojo.forEach(dojo.query(".dashBoard"), function(node){_sixnet_framework.log(1, dojo.style(node, "background", "#000"));});

			//
		}), 10);
	},
	addWidget: function(dashWidget){
		
		dojo["require"]( dashWidget);
		var self = this;
		
		var loadWidgetCallback = function(){
			var cls = dojo.getObject(dashWidget);
			if(!dojo.isFunction(cls)){
				setTimeout(loadWidgetCallback, 10);
				return;
			}
			var elem = dojo.doc.createElement('div');
			elem.setAttribute('dojoType', dashWidget);
			var params = {parseOnLoad: true,  widgetsInTemplate: true, dashBoard: self, style:{ bottom:''} };
			var instances = dojo.parser.instantiate([elem], params);
			var instance = instances[0];
			dojo.addClass(instance.domNode, 'dashBoard');
			dojo.addClass(instance.domNode, 'dashBoardWidget');
			instance.domNode.style.bottom = '';
			self._instances.push(instance);
		};
		dojo.addOnLoad(loadWidgetCallback);
	},
	onResize: function(){
		var newsize;
		var viewport = dijit.getViewport();
		newsize = { w: this.domNode.parentNode.clientWidth,
					h: this.domNode.parentNode.clientHeight};
		this._body.resize( newsize);
	},
	instantiate: function(type, mixin){
		var thelist = [];
		mixin = mixin||{};
		if(!type || !type.length){ return; }
		var clsInfo = this.getClassInfo(type),
			clazz = clsInfo.cls;

		// read parameters (ie, attributes).
		// clsInfo.params lists expected params like {"checked": "boolean", "n": "number"}
		var params = {};
		for(var name in clsInfo.params){
			var item = (typeof(mixin[name])!='undefined')?{value:mixin[name],specified:true}:false;
			if(!item || (!item.specified && (!dojo.isIE || name.toLowerCase()!="value"))){ continue; }
			var value = item.value;
			// Deal with IE quirks for 'class' and 'style'
			switch(name){
			case "class":
				value = "className" in mixin?mixin.className:'';
				break;
			case "style":
				value = "style" in mixin?mixin.style:'';
			}
			var _type = clsInfo.params[name];
			if(typeof value == "string"){
				params[name] = this.str2obj(value, _type);
			}else{
				params[name] = value;
			}
		}

		// Process <script type="dojo/*"> script tags
		// <script type="dojo/method" event="foo"> tags are added to params, and passed to
		// the widget on instantiation.
		// <script type="dojo/method"> tags (with no event) are executed after instantiation
		// <script type="dojo/connect" event="foo"> tags are dojo.connected after instantiation
		// note: dojo/* script tags cannot exist in self closing widgets, like <input />
		var markupFactory = clazz["markupFactory"];
		if(!markupFactory && clazz["prototype"]){
			markupFactory = clazz.prototype["markupFactory"];
		}
		// create the instance
		var node = dojo.create('div');
		var instance = markupFactory ? markupFactory(params, node, clazz) : new clazz(params, node);
		return instance;

	},
	getClassInfo: function(className){
		var d = dojo;
		var cls = d.getObject(className);
		if(!d.isFunction(cls)){
			throw new Error("Could not load class '" + className +
				"'. Did you spell the name correctly and use a full path, like 'dijit.form.Button'?");
		}
		var proto = cls.prototype;

		// get table of parameter names & types
		var params = {}, dummyClass = {};
		for(var name in proto){
			if(name.charAt(0)=="_"){ continue; } 	// skip internal properties
			if(name in dummyClass){ continue; }		// skip "constructor" and "toString"
			var defVal = proto[name];
			params[name]=this.val2type(defVal);
		}

		return { cls: cls, params: params };
	},
	str2obj: function(/*String*/ value, /*String*/ type){
		// summary:
		//		Convert given string value to given type
		var d = dojo;
		switch(type){
			case "string":
				return value;
			case "number":
				return value.length ? Number(value) : NaN;
			case "boolean":
				// for checked/disabled value might be "" or "checked".  interpret as true.
				return typeof value == "boolean" ? value : !(value.toLowerCase()=="false");
			case "function":
				if(d.isFunction(value)){
					// IE gives us a function, even when we say something like onClick="foo"
					// (in which case it gives us an invalid function "function(){ foo }"). 
					//  Therefore, convert to string
					value=value.toString();
					value=d.trim(value.substring(value.indexOf('{')+1, value.length-1));
				}
				try{
					if(value.search(/[^\w\.]+/i) != -1){
						// TODO: "this" here won't work
						value = nameAnonFunc(new Function(value), this);
					}
					return d.getObject(value, false);
				}catch(e){ return new Function(); }
			case "array":
				return value ? value.split(/\s*,\s*/) : [];
			case "date":
				switch(value){
					case "": return new Date("");	// the NaN of dates
					case "now": return new Date();	// current date
					default: return d.date.stamp.fromISOString(value);
				}
			case "url":
				return d.baseUrl + value;
			default:
				return d.fromJson(value);
		}
	},
	val2type: function(/*Object*/ value){
		// summary:
		//		Returns name of type of given value.
		var d = dojo;
		if(d.isString(value)){ return "string"; }
		if(typeof value == "number"){ return "number"; }
		if(typeof value == "boolean"){ return "boolean"; }
		if(d.isFunction(value)){ return "function"; }
		if(d.isArray(value)){ return "array"; } // typeof [] == "object"
		if(value instanceof Date) { return "date"; } // assume timestamp
		if(value instanceof d._Url){ return "url"; }
		return "object";
	}


});


}

if(!dojo._hasResource["dojo.number"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.number"] = true;
dojo.provide("dojo.number");







/*=====
dojo.number = {
	// summary: localized formatting and parsing routines for Number
}

dojo.number.__FormatOptions = function(){
	//	pattern: String?
	//		override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
	//		with this string.  Default value is based on locale.  Overriding this property will defeat
	//		localization.  Literal characters in patterns are not supported.
	//	type: String?
	//		choose a format type based on the locale from the following:
	//		decimal, scientific (not yet supported), percent, currency. decimal by default.
	//	places: Number?
	//		fixed number of decimal places to show.  This overrides any
	//		information in the provided pattern.
	//	round: Number?
	//		5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
	//		means do not round.
	//	locale: String?
	//		override the locale used to determine formatting rules
	//	fractional: Boolean?
	//		If false, show no decimal places, overriding places and pattern settings.
	this.pattern = pattern;
	this.type = type;
	this.places = places;
	this.round = round;
	this.locale = locale;
	this.fractional = fractional;
}
=====*/

dojo.number.format = function(/*Number*/value, /*dojo.number.__FormatOptions?*/options){
	// summary:
	//		Format a Number as a String, using locale-specific settings
	// description:
	//		Create a string from a Number using a known localized pattern.
	//		Formatting patterns appropriate to the locale are chosen from the
	//		[Common Locale Data Repository](http://unicode.org/cldr) as well as the appropriate symbols and
	//		delimiters.
	//		If value is Infinity, -Infinity, or is not a valid JavaScript number, return null.
	// value:
	//		the number to be formatted

	options = dojo.mixin({}, options || {});
	var locale = dojo.i18n.normalizeLocale(options.locale),
		bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale);
	options.customs = bundle;
	var pattern = options.pattern || bundle[(options.type || "decimal") + "Format"];
	if(isNaN(value) || Math.abs(value) == Infinity){ return null; } // null
	return dojo.number._applyPattern(value, pattern, options); // String
};

//dojo.number._numberPatternRE = /(?:[#0]*,?)*[#0](?:\.0*#*)?/; // not precise, but good enough
dojo.number._numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/; // not precise, but good enough

dojo.number._applyPattern = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatOptions?*/options){
	// summary:
	//		Apply pattern to format value as a string using options. Gives no
	//		consideration to local customs.
	// value:
	//		the number to be formatted.
	// pattern:
	//		a pattern string as described by
	//		[unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
	// options: dojo.number.__FormatOptions?
	//		_applyPattern is usually called via `dojo.number.format()` which
	//		populates an extra property in the options parameter, "customs".
	//		The customs object specifies group and decimal parameters if set.

	//TODO: support escapes
	options = options || {};
	var group = options.customs.group,
		decimal = options.customs.decimal,
		patternList = pattern.split(';'),
		positivePattern = patternList[0];
	pattern = patternList[(value < 0) ? 1 : 0] || ("-" + positivePattern);

	//TODO: only test against unescaped
	if(pattern.indexOf('%') != -1){
		value *= 100;
	}else if(pattern.indexOf('\u2030') != -1){
		value *= 1000; // per mille
	}else if(pattern.indexOf('\u00a4') != -1){
		group = options.customs.currencyGroup || group;//mixins instead?
		decimal = options.customs.currencyDecimal || decimal;// Should these be mixins instead?
		pattern = pattern.replace(/\u00a4{1,3}/, function(match){
			var prop = ["symbol", "currency", "displayName"][match.length-1];
			return options[prop] || options.currency || "";
		});
	}else if(pattern.indexOf('E') != -1){
		throw new Error("exponential notation not supported");
	}
	
	//TODO: support @ sig figs?
	var numberPatternRE = dojo.number._numberPatternRE;
	var numberPattern = positivePattern.match(numberPatternRE);
	if(!numberPattern){
		throw new Error("unable to find a number expression in pattern: "+pattern);
	}
	if(options.fractional === false){ options.places = 0; }
	return pattern.replace(numberPatternRE,
		dojo.number._formatAbsolute(value, numberPattern[0], {decimal: decimal, group: group, places: options.places, round: options.round}));
}

dojo.number.round = function(/*Number*/value, /*Number?*/places, /*Number?*/increment){
	//	summary:
	//		Rounds to the nearest value with the given number of decimal places, away from zero
	//	description:
	//		Rounds to the nearest value with the given number of decimal places, away from zero if equal.
	//		Similar to Number.toFixed(), but compensates for browser quirks. Rounding can be done by
	//		fractional increments also, such as the nearest quarter.
	//		NOTE: Subject to floating point errors.  See dojox.math.round for experimental workaround.
	//	value:
	//		The number to round
	//	places:
	//		The number of decimal places where rounding takes place.  Defaults to 0 for whole rounding.
	//		Must be non-negative.
	//	increment:
	//		Rounds next place to nearest value of increment/10.  10 by default.
	//	example:
	//		>>> dojo.number.round(-0.5)
	//		-1
	//		>>> dojo.number.round(162.295, 2)
	//		162.29  // note floating point error.  Should be 162.3
	//		>>> dojo.number.round(10.71, 0, 2.5)
	//		10.75
	var factor = 10 / (increment || 10);
	return (factor * +value).toFixed(places) / factor; // Number
}

if((0.9).toFixed() == 0){
	// (isIE) toFixed() bug workaround: Rounding fails on IE when most significant digit
	// is just after the rounding place and is >=5
	(function(){
		var round = dojo.number.round;
		dojo.number.round = function(v, p, m){
			var d = Math.pow(10, -p || 0), a = Math.abs(v);
			if(!v || a >= d || a * Math.pow(10, p + 1) < 5){
				d = 0;
			}
			return round(v, p, m) + (v > 0 ? d : -d);
		}
	})();
}

/*=====
dojo.number.__FormatAbsoluteOptions = function(){
	//	decimal: String?
	//		the decimal separator
	//	group: String?
	//		the group separator
	//	places: Number?|String?
	//		number of decimal places.  the range "n,m" will format to m places.
	//	round: Number?
	//		5 rounds to nearest .5; 0 rounds to nearest whole (default). -1
	//		means don't round.
	this.decimal = decimal;
	this.group = group;
	this.places = places;
	this.round = round;
}
=====*/

dojo.number._formatAbsolute = function(/*Number*/value, /*String*/pattern, /*dojo.number.__FormatAbsoluteOptions?*/options){
	// summary: 
	//		Apply numeric pattern to absolute value using options. Gives no
	//		consideration to local customs.
	// value:
	//		the number to be formatted, ignores sign
	// pattern:
	//		the number portion of a pattern (e.g. `#,##0.00`)
	options = options || {};
	if(options.places === true){options.places=0;}
	if(options.places === Infinity){options.places=6;} // avoid a loop; pick a limit

	var patternParts = pattern.split("."),
		comma = typeof options.places == "string" && options.places.indexOf(","),
		maxPlaces = options.places;
	if(comma){
		maxPlaces = options.places.substring(comma + 1);
	}else if(!(maxPlaces >= 0)){
		maxPlaces = (patternParts[1] || []).length;
	}
	if(!(options.round < 0)){
		value = dojo.number.round(value, maxPlaces, options.round);
	}

	var valueParts = String(Math.abs(value)).split("."),
		fractional = valueParts[1] || "";
	if(patternParts[1] || options.places){
		if(comma){
			options.places = options.places.substring(0, comma);
		}
		// Pad fractional with trailing zeros
		var pad = options.places !== undefined ? options.places : (patternParts[1] && patternParts[1].lastIndexOf("0") + 1);
		if(pad > fractional.length){
			valueParts[1] = dojo.string.pad(fractional, pad, '0', true);
		}

		// Truncate fractional
		if(maxPlaces < fractional.length){
			valueParts[1] = fractional.substr(0, maxPlaces);
		}
	}else{
		if(valueParts[1]){ valueParts.pop(); }
	}

	// Pad whole with leading zeros
	var patternDigits = patternParts[0].replace(',', '');
	pad = patternDigits.indexOf("0");
	if(pad != -1){
		pad = patternDigits.length - pad;
		if(pad > valueParts[0].length){
			valueParts[0] = dojo.string.pad(valueParts[0], pad);
		}

		// Truncate whole
		if(patternDigits.indexOf("#") == -1){
			valueParts[0] = valueParts[0].substr(valueParts[0].length - pad);
		}
	}

	// Add group separators
	var index = patternParts[0].lastIndexOf(','),
		groupSize, groupSize2;
	if(index != -1){
		groupSize = patternParts[0].length - index - 1;
		var remainder = patternParts[0].substr(0, index);
		index = remainder.lastIndexOf(',');
		if(index != -1){
			groupSize2 = remainder.length - index - 1;
		}
	}
	var pieces = [];
	for(var whole = valueParts[0]; whole;){
		var off = whole.length - groupSize;
		pieces.push((off > 0) ? whole.substr(off) : whole);
		whole = (off > 0) ? whole.slice(0, off) : "";
		if(groupSize2){
			groupSize = groupSize2;
			delete groupSize2;
		}
	}
	valueParts[0] = pieces.reverse().join(options.group || ",");

	return valueParts.join(options.decimal || ".");
};

/*=====
dojo.number.__RegexpOptions = function(){
	//	pattern: String?
	//		override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
	//		with this string.  Default value is based on locale.  Overriding this property will defeat
	//		localization.
	//	type: String?
	//		choose a format type based on the locale from the following:
	//		decimal, scientific (not yet supported), percent, currency. decimal by default.
	//	locale: String?
	//		override the locale used to determine formatting rules
	//	strict: Boolean?
	//		strict parsing, false by default.  Strict parsing requires input as produced by the format() method.
	//		Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
	//	places: Number|String?
	//		number of decimal places to accept: Infinity, a positive number, or
	//		a range "n,m".  Defined by pattern or Infinity if pattern not provided.
	this.pattern = pattern;
	this.type = type;
	this.locale = locale;
	this.strict = strict;
	this.places = places;
}
=====*/
dojo.number.regexp = function(/*dojo.number.__RegexpOptions?*/options){
	//	summary:
	//		Builds the regular needed to parse a number
	//	description:
	//		Returns regular expression with positive and negative match, group
	//		and decimal separators
	return dojo.number._parseInfo(options).regexp; // String
}

dojo.number._parseInfo = function(/*Object?*/options){
	options = options || {};
	var locale = dojo.i18n.normalizeLocale(options.locale),
		bundle = dojo.i18n.getLocalization("dojo.cldr", "number", locale),
		pattern = options.pattern || bundle[(options.type || "decimal") + "Format"],
//TODO: memoize?
		group = bundle.group,
		decimal = bundle.decimal,
		factor = 1;

	if(pattern.indexOf('%') != -1){
		factor /= 100;
	}else if(pattern.indexOf('\u2030') != -1){
		factor /= 1000; // per mille
	}else{
		var isCurrency = pattern.indexOf('\u00a4') != -1;
		if(isCurrency){
			group = bundle.currencyGroup || group;
			decimal = bundle.currencyDecimal || decimal;
		}
	}

	//TODO: handle quoted escapes
	var patternList = pattern.split(';');
	if(patternList.length == 1){
		patternList.push("-" + patternList[0]);
	}

	var re = dojo.regexp.buildGroupRE(patternList, function(pattern){
		pattern = "(?:"+dojo.regexp.escapeString(pattern, '.')+")";
		return pattern.replace(dojo.number._numberPatternRE, function(format){
			var flags = {
				signed: false,
				separator: options.strict ? group : [group,""],
				fractional: options.fractional,
				decimal: decimal,
				exponent: false
				},

				parts = format.split('.'),
				places = options.places;

			// special condition for percent (factor != 1)
			// allow decimal places even if not specified in pattern
			if(parts.length == 1 && factor != 1){
			    parts[1] = "###";
			}
			if(parts.length == 1 || places === 0){
				flags.fractional = false;
			}else{
				if(places === undefined){ places = options.pattern ? parts[1].lastIndexOf('0') + 1 : Infinity; }
				if(places && options.fractional == undefined){flags.fractional = true;} // required fractional, unless otherwise specified
				if(!options.places && (places < parts[1].length)){ places += "," + parts[1].length; }
				flags.places = places;
			}
			var groups = parts[0].split(',');
			if(groups.length > 1){
				flags.groupSize = groups.pop().length;
				if(groups.length > 1){
					flags.groupSize2 = groups.pop().length;
				}
			}
			return "("+dojo.number._realNumberRegexp(flags)+")";
		});
	}, true);

	if(isCurrency){
		// substitute the currency symbol for the placeholder in the pattern
		re = re.replace(/([\s\xa0]*)(\u00a4{1,3})([\s\xa0]*)/g, function(match, before, target, after){
			var prop = ["symbol", "currency", "displayName"][target.length-1],
				symbol = dojo.regexp.escapeString(options[prop] || options.currency || "");
			before = before ? "[\\s\\xa0]" : "";
			after = after ? "[\\s\\xa0]" : "";
			if(!options.strict){
				if(before){before += "*";}
				if(after){after += "*";}
				return "(?:"+before+symbol+after+")?";
			}
			return before+symbol+after;
		});
	}

//TODO: substitute localized sign/percent/permille/etc.?

	// normalize whitespace and return
	return {regexp: re.replace(/[\xa0 ]/g, "[\\s\\xa0]"), group: group, decimal: decimal, factor: factor}; // Object
}

/*=====
dojo.number.__ParseOptions = function(){
	//	pattern: String?
	//		override [formatting pattern](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
	//		with this string.  Default value is based on locale.  Overriding this property will defeat
	//		localization.  Literal characters in patterns are not supported.
	//	type: String?
	//		choose a format type based on the locale from the following:
	//		decimal, scientific (not yet supported), percent, currency. decimal by default.
	//	locale: String?
	//		override the locale used to determine formatting rules
	//	strict: Boolean?
	//		strict parsing, false by default.  Strict parsing requires input as produced by the format() method.
	//		Non-strict is more permissive, e.g. flexible on white space, omitting thousands separators
	//	fractional: Boolean?|Array?
	//		Whether to include the fractional portion, where the number of decimal places are implied by pattern
	//		or explicit 'places' parameter.  The value [true,false] makes the fractional portion optional.
	this.pattern = pattern;
	this.type = type;
	this.locale = locale;
	this.strict = strict;
	this.fractional = fractional;
}
=====*/
dojo.number.parse = function(/*String*/expression, /*dojo.number.__ParseOptions?*/options){
	// summary:
	//		Convert a properly formatted string to a primitive Number, using
	//		locale-specific settings.
	// description:
	//		Create a Number from a string using a known localized pattern.
	//		Formatting patterns are chosen appropriate to the locale
	//		and follow the syntax described by
	//		[unicode.org TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
    	//		Note that literal characters in patterns are not supported.
	// expression:
	//		A string representation of a Number
	var info = dojo.number._parseInfo(options),
		results = (new RegExp("^"+info.regexp+"$")).exec(expression);
	if(!results){
		return NaN; //NaN
	}
	var absoluteMatch = results[1]; // match for the positive expression
	if(!results[1]){
		if(!results[2]){
			return NaN; //NaN
		}
		// matched the negative pattern
		absoluteMatch =results[2];
		info.factor *= -1;
	}

	// Transform it to something Javascript can parse as a number.  Normalize
	// decimal point and strip out group separators or alternate forms of whitespace
	absoluteMatch = absoluteMatch.
		replace(new RegExp("["+info.group + "\\s\\xa0"+"]", "g"), "").
		replace(info.decimal, ".");
	// Adjust for negative sign, percent, etc. as necessary
	return absoluteMatch * info.factor; //Number
};

/*=====
dojo.number.__RealNumberRegexpFlags = function(){
	//	places: Number?
	//		The integer number of decimal places or a range given as "n,m".  If
	//		not given, the decimal part is optional and the number of places is
	//		unlimited.
	//	decimal: String?
	//		A string for the character used as the decimal point.  Default
	//		is ".".
	//	fractional: Boolean?|Array?
	//		Whether decimal places are used.  Can be true, false, or [true,
	//		false].  Default is [true, false] which means optional.
	//	exponent: Boolean?|Array?
	//		Express in exponential notation.  Can be true, false, or [true,
	//		false]. Default is [true, false], (i.e. will match if the
	//		exponential part is present are not).
	//	eSigned: Boolean?|Array?
	//		The leading plus-or-minus sign on the exponent.  Can be true,
	//		false, or [true, false].  Default is [true, false], (i.e. will
	//		match if it is signed or unsigned).  flags in regexp.integer can be
	//		applied.
	this.places = places;
	this.decimal = decimal;
	this.fractional = fractional;
	this.exponent = exponent;
	this.eSigned = eSigned;
}
=====*/

dojo.number._realNumberRegexp = function(/*dojo.number.__RealNumberRegexpFlags?*/flags){
	// summary:
	//		Builds a regular expression to match a real number in exponential
	//		notation

	// assign default values to missing parameters
	flags = flags || {};
	//TODO: use mixin instead?
	if(!("places" in flags)){ flags.places = Infinity; }
	if(typeof flags.decimal != "string"){ flags.decimal = "."; }
	if(!("fractional" in flags) || /^0/.test(flags.places)){ flags.fractional = [true, false]; }
	if(!("exponent" in flags)){ flags.exponent = [true, false]; }
	if(!("eSigned" in flags)){ flags.eSigned = [true, false]; }

	var integerRE = dojo.number._integerRegexp(flags),
		decimalRE = dojo.regexp.buildGroupRE(flags.fractional,
		function(q){
			var re = "";
			if(q && (flags.places!==0)){
				re = "\\" + flags.decimal;
				if(flags.places == Infinity){ 
					re = "(?:" + re + "\\d+)?"; 
				}else{
					re += "\\d{" + flags.places + "}"; 
				}
			}
			return re;
		},
		true
	);

	var exponentRE = dojo.regexp.buildGroupRE(flags.exponent,
		function(q){ 
			if(q){ return "([eE]" + dojo.number._integerRegexp({ signed: flags.eSigned}) + ")"; }
			return ""; 
		}
	);

	var realRE = integerRE + decimalRE;
	// allow for decimals without integers, e.g. .25
	if(decimalRE){realRE = "(?:(?:"+ realRE + ")|(?:" + decimalRE + "))";}
	return realRE + exponentRE; // String
};

/*=====
dojo.number.__IntegerRegexpFlags = function(){
	//	signed: Boolean?
	//		The leading plus-or-minus sign. Can be true, false, or `[true,false]`.
	//		Default is `[true, false]`, (i.e. will match if it is signed
	//		or unsigned).
	//	separator: String?
	//		The character used as the thousands separator. Default is no
	//		separator. For more than one symbol use an array, e.g. `[",", ""]`,
	//		makes ',' optional.
	//	groupSize: Number?
	//		group size between separators
	//	groupSize2: Number?
	//		second grouping, where separators 2..n have a different interval than the first separator (for India)
	this.signed = signed;
	this.separator = separator;
	this.groupSize = groupSize;
	this.groupSize2 = groupSize2;
}
=====*/

dojo.number._integerRegexp = function(/*dojo.number.__IntegerRegexpFlags?*/flags){
	// summary: 
	//		Builds a regular expression that matches an integer

	// assign default values to missing parameters
	flags = flags || {};
	if(!("signed" in flags)){ flags.signed = [true, false]; }
	if(!("separator" in flags)){
		flags.separator = "";
	}else if(!("groupSize" in flags)){
		flags.groupSize = 3;
	}

	var signRE = dojo.regexp.buildGroupRE(flags.signed,
		function(q){ return q ? "[-+]" : ""; },
		true
	);

	var numberRE = dojo.regexp.buildGroupRE(flags.separator,
		function(sep){
			if(!sep){
				return "(?:\\d+)";
			}

			sep = dojo.regexp.escapeString(sep);
			if(sep == " "){ sep = "\\s"; }
			else if(sep == "\xa0"){ sep = "\\s\\xa0"; }

			var grp = flags.groupSize, grp2 = flags.groupSize2;
			//TODO: should we continue to enforce that numbers with separators begin with 1-9?  See #6933
			if(grp2){
				var grp2RE = "(?:0|[1-9]\\d{0," + (grp2-1) + "}(?:[" + sep + "]\\d{" + grp2 + "})*[" + sep + "]\\d{" + grp + "})";
				return ((grp-grp2) > 0) ? "(?:" + grp2RE + "|(?:0|[1-9]\\d{0," + (grp-1) + "}))" : grp2RE;
			}
			return "(?:0|[1-9]\\d{0," + (grp-1) + "}(?:[" + sep + "]\\d{" + grp + "})*)";
		},
		true
	);

	return signRE + numberRE; // String
}

}

if(!dojo._hasResource["dijit.ProgressBar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.ProgressBar"] = true;
dojo.provide("dijit.ProgressBar");







dojo.declare("dijit.ProgressBar", [dijit._Widget, dijit._Templated], {
	// summary:
	//		A progress indication widget, showing the amount completed
	//		(often the percentage completed) of a task.
	//
	// example:
	// |	<div dojoType="ProgressBar"
	// |		 places="0"
	// |		 progress="..." maximum="...">
	// |	</div>
	//
	// description:
	//		Note that the progress bar is updated via (a non-standard)
	//		update() method, rather than via attr() like other widgets.

	// progress: [const] String (Percentage or Number)
	//		Number or percentage indicating amount of task completed.
	// 		With "%": percentage value, 0% <= progress <= 100%, or
	// 		without "%": absolute value, 0 <= progress <= maximum
	// TODO: rename to value for 2.0
	progress: "0",

	// maximum: [const] Float
	//		Max sample number
	maximum: 100,

	// places: [const] Number
	//		Number of places to show in values; 0 by default
	places: 0,

	// indeterminate: [const] Boolean
	// 		If false: show progress value (number or percentage).
	// 		If true: show that a process is underway but that the amount completed is unknown.
	indeterminate: false,

	// name: String
	//		this is the field name (for a form) if set. This needs to be set if you want to use
	//		this widget in a dijit.form.Form widget (such as dijit.Dialog)
	name: '',

	templateString: dojo.cache("dijit", "templates/ProgressBar.html", "<div class=\"dijitProgressBar dijitProgressBarEmpty\"\n\t><div waiRole=\"progressbar\" dojoAttachPoint=\"internalProgress\" class=\"dijitProgressBarFull\"\n\t\t><div class=\"dijitProgressBarTile\"></div\n\t\t><span style=\"visibility:hidden\">&nbsp;</span\n\t></div\n\t><div dojoAttachPoint=\"label\" class=\"dijitProgressBarLabel\" id=\"${id}_label\">&nbsp;</div\n\t><img dojoAttachPoint=\"indeterminateHighContrastImage\" class=\"dijitProgressBarIndeterminateHighContrastImage\" alt=\"\"\n/></div>\n"),

	// _indeterminateHighContrastImagePath: [private] dojo._URL
	//		URL to image to use for indeterminate progress bar when display is in high contrast mode
	_indeterminateHighContrastImagePath:
		dojo.moduleUrl("dijit", "themes/a11y/indeterminate_progress.gif"),

	// public functions
	postCreate: function(){
		this.inherited(arguments);
		this.indeterminateHighContrastImage.setAttribute("src",
			this._indeterminateHighContrastImagePath.toString());
		this.update();
	},

	update: function(/*Object?*/attributes){
		// summary:
		//		Change attributes of ProgressBar, similar to attr(hash).
		//
		// attributes:
		//		May provide progress and/or maximum properties on this parameter;
		//		see attribute specs for details.
		//
		// example:
		//	|	myProgressBar.update({'indeterminate': true});
		//	|	myProgressBar.update({'progress': 80});

		// TODO: deprecate this method and use set() instead

		dojo.mixin(this, attributes || {});
		var tip = this.internalProgress;
		var percent = 1, classFunc;
		if(this.indeterminate){
			classFunc = "addClass";
			dijit.removeWaiState(tip, "valuenow");
			dijit.removeWaiState(tip, "valuemin");
			dijit.removeWaiState(tip, "valuemax");
		}else{
			classFunc = "removeClass";
			if(String(this.progress).indexOf("%") != -1){
				percent = Math.min(parseFloat(this.progress)/100, 1);
				this.progress = percent * this.maximum;
			}else{
				this.progress = Math.min(this.progress, this.maximum);
				percent = this.progress / this.maximum;
			}
			var text = this.report(percent);
			this.label.firstChild.nodeValue = text;
			dijit.setWaiState(tip, "describedby", this.label.id);
			dijit.setWaiState(tip, "valuenow", this.progress);
			dijit.setWaiState(tip, "valuemin", 0);
			dijit.setWaiState(tip, "valuemax", this.maximum);
		}
		dojo[classFunc](this.domNode, "dijitProgressBarIndeterminate");
		tip.style.width = (percent * 100) + "%";
		this.onChange();
	},

	_setValueAttr: function(v){
		if(v == Infinity){
			this.update({indeterminate:true});
		}else{
			this.update({indeterminate:false, progress:v});
		}
	},

	_getValueAttr: function(){
		return this.progress;
	},

	report: function(/*float*/percent){
		// summary:
		//		Generates message to show inside progress bar (normally indicating amount of task completed).
		//		May be overridden.
		// tags:
		//		extension

		return dojo.number.format(percent, { type: "percent", places: this.places, locale: this.lang });
	},

	onChange: function(){
		// summary:
		//		Callback fired when progress updates.
		// tags:
		//		progress
	}
});

}

if(!dojo._hasResource['com.sixnet.services.core.loader']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.core.loader'] = true;








dojo.provide('com.sixnet.services.core.loader');

dojo.declare('com.sixnet.services.core.loader',[dijit._Widget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div style=\"height: 5em; margin-top:200px; margin-bottom:auto; margin-left: auto; margin-right: auto; width: 31em;\">\n\t<div style=\"float:left; color:#fff;\">Loading Sixnet Dashboard engine...</div>\n\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"stepLabel\">Initializing</div>\n\t<div dojoType=\"dijit.ProgressBar\" style=\"width: 31em\" dojoAttachPoint=\"loaderProgress\">\n\t</div>\n\n</div>\n",
	updateCount: 1,
	_dashBoard: false,
	_requests: 0,
	postCreate: function(){
//		dijit.byId('body').innerHTML = '';
//		dijit.byId('body').addChild(this);
//		this.loaderProgress.maximum = 4;
		this._dashBoard = new com.sixnet.services.core.dashBoard({ _app: dijit.byId('body')});
		
		this._dashBoard.runApp('com.sixnet.services.modules.access.loginManager');
		//this.discoverServices();
	},
	getDash: function(){
		return this._dashBoard;
	},
	bumpProgress: function(){
//		var updatePosition = Math.floor(this.updateCount++ * ( 100 / this.loaderProgress.maximum)) + '%';
//		this.loaderProgress.update({ progress: updatePosition});
	},
	onDiscoverServices:function(serviceList){
		_sixnet_framework.log(1, serviceList, " onDiscoverServices loader.js");
		//this.bumpProgress();
		//this.stepLabel.setContent('Building Dashboard');
		// Next step.  Build the dashboard
		this.buildDashboard(serviceList);
	},
	onBuildDashboard: function(){
		this.bumpProgress();
//		dijit.byId('body').removeChild(this);
		this._dashBoard.showDashBoard();
	},
	discoverServices: function(){
		// query the sixnet server for available services.
//		dijit.byId('body').innerHTML = '';
//		dijit.byId('body').addChild(this);
//		this.loaderProgress.maximum = 4;
		if(this._dashBoard){
			this._dashBoard.dismount();
		}
		this._dashBoard = new com.sixnet.services.core.dashBoard({ _app: dijit.byId('body')});
		
		//this.stepLabel.setContent('Discovering Services');
		_sixnet_framework.bc('providers', 'getInstalled', {}, dojo.hitch(this, function(servicesCall){
			if( servicesCall.successful ){
				// Server responded correctly.
				// How many services are there?
				var serviceList = [];
				dojo.forEach(servicesCall.data, function(serviceSublist){
					dojo.forEach(serviceSublist.dash, function(item){
							serviceList.push(item);
					});
				});
				_sixnet_framework.log(3, "load me: ", serviceList);
				this.onDiscoverServices(serviceList);
			}else{
				_sixnet_framework.log(3, 'Could not discover services. Server error.'.concat( servicesCall.error));
			}
		}));
	},
	buildDashboard: function(serviceList){
	
		if( serviceList.length == 0){
			_sixnet_framework.log(1, "?IE FIX HERE? Calling onBuildDashboard in buildDashboard");
			dojo.addOnLoad(this, "onBuildDashboard");
			return;
		}
		
		var currentWidget = serviceList.shift();
		// do not attempt to load code for empty widgets
		if(typeof(currentWidget) == 'string' && currentWidget.length == 0) return;
		dojo['require'](currentWidget);
		dojo.addOnLoad( dojo.hitch(this, function(currentWidget, serviceList){
				this._dashBoard.addWidget(currentWidget);
				this.buildDashboard(serviceList); // recurse the remainder of the list
		}, currentWidget, serviceList));
	}
	
});

}

if(!dojo._hasResource['com.sixnet.services.core.poller']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.core.poller'] = true;
dojo.provide('com.sixnet.services.core.poller');

dojo.declare('com.sixnet.services.core.poller',[], {
	_subscriptionCount: 0,
	_pollDeferred: false,
	_pollCanceled: true,
	_subscriptionsById: false,
	_subscriptionsByPath: false,
	_activeSubscriptions: 0,
	constructor: function(){
		this._subscriptionsById = {};
		this._subscriptionsByPath = {};
		this._activeSubscriptions = 0;
	},
	subscribe: function(eventPath, eventHandler){
		var handle = {
				id: this._subscriptionCount++,
				path: eventPath,
				eventHandler: eventHandler
		};
		if( 'undefined' == typeof(this._subscriptionsByPath[eventPath])){
			this._subscriptionsByPath[eventPath] = [];
		}
		if( this._subscriptionsByPath[eventPath].length == 0){
			// we are not yet subscribed to this path
			_sixnet_framework.bcSilent('async', 'subscribe', { eventName: eventPath }, dojo.hitch(this, function(response){
				if( response.data){
					// put a reference to this handle in the id list
					this._subscriptionsById[handle.id] = handle;
					this._subscriptionsByPath[eventPath].push(handle);
					this._activeSubscriptions++;
				}
			}));
		}else{
			this._subscriptionsById[handle.id] = handle;
			this._subscriptionsByPath[eventPath].push(handle);
			this._activeSubscriptions++;
		}
		return handle;
	},
	unsubscribe: function(handle){
		if( !handle || !handle.id || !this._subscriptionsById[handle.id]) return; // dead handle
		this._activeSubscriptions--;
		delete this._subscriptionsById[handle.id];
		// rebuild path list... this method is terrible.
		var newList = [];
		for(var aIdx = 0; aIdx < this._subscriptionsByPath[handle.path].length; aIdx++){
			if( this._subscriptionsByPath[handle.path][aIdx].id != handle.id){
				newList.push(this._subscriptionsByPath[handle.path][aIdx]);
			}
		}
		this._subscriptionsByPath[handle.path] = newList;
		if(this._subscriptionsByPath[handle.path].length==0){
			_sixnet_framework.bcSilent('async', 'unsubscribe', { eventName: handle.path });
		}
	},
	startPolling: function(){
		// Never have multiple pollers running.
		this.stopPolling();
		this._pollCanceled = false;
		this.rePoll();
	},
	stopPolling: function(){
		try{
			this._subscriptionsById = {};
			this._subscriptionsByPath = {};
			this._activeSubscriptions = 0;
			this._pollCanceled = true;
			if( this._pollDeferred && this._pollDeferred.cancel ){
				this._pollDeferred.cancel();
			}
		}catch(e){}
		this._pollDeferred = false;
	},
	rePoll: function(){
		if( !_sixnet_framework.polling) return;
		if(this._pollCanceled) return;
		//if there are active subscriptions then call to the server,
		//otherwise look again soon
		if( this._activeSubscriptions){
			this._pollDeferred = _sixnet_framework.bcSilent('async','pollEvents', {}, dojo.hitch(this, "handleEvent"), dojo.hitch(this, "handleError"));
		}else{
			setTimeout(dojo.hitch(this, "rePoll"),1000);
		}
	},
	handleEvent: function(response){
		this._pollDeferred = false;
		if( ! response.successful ){
			if(this._retrying){
				
				return;
			}
			this.stopPolling();
			_sixnet_framework.setSession('');
			_sixnet_framework.reloadDash();
			return;
		}
		if(dojo.isArray(response.data)){
			// Loop through all of the messages
			for( var aIdx = 0; aIdx < response.data.length; aIdx++){
				try{
					var aResponse = response.data[aIdx];
					console.log('Handling handeEvent', aResponse);
					// clone the array to walk.  Avoids issues with changing array while in event handler.
					if('undefined' == typeof(this._subscriptionsByPath[aResponse.subscribedEvent])){
						_sixnet_framework.log(3,"No listeners defined for ", aResponse.subscribedEvent);
						continue;
					}
					var listeners = dojo.clone(this._subscriptionsByPath[aResponse.subscribedEvent]);
					
					// for each response, dispatch the message to all listeners
					for( var hIdx = 0; hIdx < listeners.length; hIdx++){
						var handle = listeners[hIdx];
						handle.eventHandler( handle.path, aResponse.eventPayload);
					}
				}catch(e){
					_sixnet_framework.log(1, "Error handling ", handle.path, aResponse.eventPayload);
				}
			}
		}
		if( !this._pollCanceled) setTimeout(dojo.hitch(this, "rePoll"),500);
	},
	handleError: function(error){
		if( !this._pollCanceled){
			_sixnet_framework.log(1, "poll error:", error);
			setTimeout(dojo.hitch(this, "rePoll"),500);
		}
	}
});

}

if(!dojo._hasResource["dojox.data.ServiceStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.data.ServiceStore"] = true;
dojo.provide("dojox.data.ServiceStore");

// note that dojox.rpc.Service is not required, you can create your own services

// A ServiceStore is a readonly data store that provides a data.data interface to an RPC service.
// var myServices = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd"));
// var serviceStore = new dojox.data.ServiceStore({service:myServices.ServiceStore});
//
// The ServiceStore also supports lazy loading. References can be made to objects that have not been loaded.
//	For example if a service returned:
// {"name":"Example","lazyLoadedObject":{"$ref":"obj2"}}
//
// And this object has accessed using the dojo.data API:
// var obj = serviceStore.getValue(myObject,"lazyLoadedObject");
// The object would automatically be requested from the server (with an object id of "obj2").
//

dojo.declare("dojox.data.ServiceStore",
	// ClientFilter is intentionally not required, ServiceStore does not need it, and is more
	// lightweight without it, but if it is provided, the ServiceStore will use it.
	dojox.data.ClientFilter||null,{
		service: null,
		constructor: function(options){
			//summary:
			//		ServiceStore constructor, instantiate a new ServiceStore
			// 		A ServiceStore can be configured from a JSON Schema. Queries are just
			// 		passed through to the underlying services
			//
			// options:
			// 		Keyword arguments
			// The *schema* parameter
			//		This is a schema object for this store. This should be JSON Schema format.
			//
			// The *service* parameter
			// 		This is the service object that is used to retrieve lazy data and save results
			// 		The function should be directly callable with a single parameter of an object id to be loaded
			//
			// The *idAttribute* parameter
			//		Defaults to 'id'. The name of the attribute that holds an objects id.
			//		This can be a preexisting id provided by the server.
			//		If an ID isn't already provided when an object
			//		is fetched or added to the store, the autoIdentity system
			//		will generate an id for it and add it to the index.
			//
			// The *estimateCountFactor* parameter
			// 		This parameter is used by the ServiceStore to estimate the total count. When
			//		paging is indicated in a fetch and the response includes the full number of items
			//	 	requested by the fetch's count parameter, then the total count will be estimated
			//		to be estimateCountFactor multiplied by the provided count. If this is 1, then it is assumed that the server
			//		does not support paging, and the response is the full set of items, where the
			// 		total count is equal to the numer of items returned. If the server does support
			//		paging, an estimateCountFactor of 2 is a good value for estimating the total count
			//		It is also possible to override _processResults if the server can provide an exact
			// 		total count.
			//
			// The *syncMode* parameter
			//		Setting this to true will set the store to using synchronous calls by default.
			//		Sync calls return their data immediately from the calling function, so
			//		callbacks are unnecessary. This will only work with a synchronous capable service.
			//
			// description:
			//		ServiceStore can do client side caching and result set updating if
			// 		dojox.data.ClientFilter is loaded. Do this add:
			//	|	dojo.require("dojox.data.ClientFilter")
			//		prior to loading the ServiceStore (ClientFilter must be loaded before ServiceStore).
			//		To utilize client side filtering with a subclass, you can break queries into
			//		client side and server side components by putting client side actions in
			//		clientFilter property in fetch calls. For example you could override fetch:
			//	|	fetch: function(args){
				//	|		// do the sorting and paging on the client side
	 			//	|		args.clientFilter = {start:args.start, count: args.count, sort: args.sort};
	 			//	|		// args.query will be passed to the service object for the server side handling
	 			//	|		return this.inherited(arguments);
			//	|	}
			//		When extending this class, if you would like to create lazy objects, you can follow
			//		the example from dojox.data.tests.stores.ServiceStore:
			// |	var lazyItem = {
			// |		_loadObject: function(callback){
			// |			this.name="loaded";
			// |			delete this._loadObject;
			// |			callback(this);
			// |		}
			// |	};
			//setup a byId alias to the api call
			this.byId=this.fetchItemByIdentity;
			this._index = {};
			// if the advanced json parser is enabled, we can pass through object updates as onSet events
			if(options){
				dojo.mixin(this,options);
			}
			// We supply a default idAttribute for parser driven construction, but if no id attribute
			//	is supplied, it should be null so that auto identification takes place properly
			this.idAttribute = (options && options.idAttribute) || (this.schema && this.schema._idAttr);
		},
		schema: null,
		idAttribute: "id",
		labelAttribute: "label",
		syncMode: false,
		estimateCountFactor: 1,
		getSchema: function(){
			return this.schema;
		},

		loadLazyValues:true,

		getValue: function(/*Object*/ item, /*String*/property, /*value?*/defaultValue){
			// summary:
			//	Gets the value of an item's 'property'
			//
			//	item:
			//		The item to get the value from
			//	property:
			//		property to look up value for
			//	defaultValue:
			//		the default value

			var value = item[property];
			return value || // return the plain value since it was found;
						(property in item ? // a truthy value was not found, see if we actually have it
							value : // we do, so we can return it
							item._loadObject ? // property was not found, maybe because the item is not loaded, we will try to load it synchronously so we can get the property
								(dojox.rpc._sync = true) && arguments.callee.call(this,dojox.data.ServiceStore.prototype.loadItem({item:item}) || {}, property, defaultValue) : // load the item and run getValue again
								defaultValue);// not in item -> return default value
		},
		getValues: function(item, property){
			// summary:
			//		Gets the value of an item's 'property' and returns
			//		it.	If this value is an array it is just returned,
			//		if not, the value is added to an array and that is returned.
			//
			//	item: /* object */
			//	property: /* string */
			//		property to look up value for

			var val = this.getValue(item,property);
			if(val instanceof Array){
				return val;
			}
			if(!this.isItemLoaded(val)){
				dojox.rpc._sync = true;
				val = this.loadItem({item:val});
			}
			return val instanceof Array ? val : val === undefined ? [] : [val];
		},

		getAttributes: function(item){
			// summary:
			//	Gets the available attributes of an item's 'property' and returns
			//	it as an array.
			//
			//	item: /* object */

			var res = [];
			for(var i in item){
				if(item.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_')){
					res.push(i);
				}
			}
			return res;
		},

		hasAttribute: function(item,attribute){
			// summary:
			//		Checks to see if item has attribute
			//
			//	item: /* object */
			//	attribute: /* string */
			return attribute in item;
		},

		containsValue: function(item, attribute, value){
			// summary:
			//		Checks to see if 'item' has 'value' at 'attribute'
			//
			//	item: /* object */
			//	attribute: /* string */
			//	value: /* anything */
			return dojo.indexOf(this.getValues(item,attribute),value) > -1;
		},


		isItem: function(item){
			// summary:
			//		Checks to see if the argument is an item
			//
			//	item: /* object */
			//	attribute: /* string */

			// we have no way of determining if it belongs, we just have object returned from
			// 	service queries
			return (typeof item == 'object') && item && !(item instanceof Date);
		},

		isItemLoaded: function(item){
			// summary:
			//		Checks to see if the item is loaded.
			//
			//		item: /* object */

			return item && !item._loadObject;
		},

		loadItem: function(args){
			// summary:
			// 		Loads an item and calls the callback handler. Note, that this will call the callback
			// 		handler even if the item is loaded. Consequently, you can use loadItem to ensure
			// 		that an item is loaded is situations when the item may or may not be loaded yet.
			// 		If you access a value directly through property access, you can use this to load
			// 		a lazy value as well (doesn't need to be an item).
			//
			//	example:
			//		store.loadItem({
			//			item: item, // this item may or may not be loaded
			//			onItem: function(item){
			// 				// do something with the item
			//			}
			//		});

			var item;
			if(args.item._loadObject){
				args.item._loadObject(function(result){
					item = result; // in synchronous mode this can allow loadItem to return the value
					delete item._loadObject;
					var func = result instanceof Error ? args.onError : args.onItem;
					if(func){
						func.call(args.scope, result);
					}
				});
			}else if(args.onItem){
				// even if it is already loaded, we will use call the callback, this makes it easier to
				// use when it is not known if the item is loaded (you can always safely call loadItem).
				args.onItem.call(args.scope, args.item);
			}
			return item;
		},
		_currentId : 0,
		_processResults : function(results, deferred){
			// this should return an object with the items as an array and the total count of
			// items (maybe more than currently in the result set).
			// for example:
			//	| {totalCount:10, items: [{id:1},{id:2}]}

			// index the results, assigning ids as necessary

			if(results && typeof results == 'object'){
				var id = results.__id;
				if(!id){// if it hasn't been assigned yet
					if(this.idAttribute){
						// use the defined id if available
						id = results[this.idAttribute];
					}else{
						id = this._currentId++;
					}
					if(id !== undefined){
						var existingObj = this._index[id];
						if(existingObj){
							for(var j in existingObj){
								delete existingObj[j]; // clear it so we can mixin
							}
							results = dojo.mixin(existingObj,results);
						}
						results.__id = id;
						this._index[id] = results;
					}
				}
				for(var i in results){
					results[i] = this._processResults(results[i], deferred).items;
				}
				var count = results.length;
			}
			return {totalCount: deferred.request.count == count ? (deferred.request.start || 0) + count * this.estimateCountFactor : count, items: results};
		},
		close: function(request){
			return request && request.abort && request.abort();
		},
		fetch: function(args){
			// summary:
			//		See dojo.data.api.Read.fetch
			//
			// The *queryOptions.cache* parameter
			//		If true, indicates that the query result should be cached for future use. This is only available
			// 		if dojox.data.ClientFilter has been loaded before the ServiceStore
			//
			//	The *syncMode* parameter
			//		Indicates that the call should be fetch synchronously if possible (this is not always possible)
			//
			// The *clientFetch* parameter
			//		This is a fetch keyword argument for explicitly doing client side filtering, querying, and paging

			args = args || {};

			if("syncMode" in args ? args.syncMode : this.syncMode){
				dojox.rpc._sync = true;
			}
			var self = this;

			var scope = args.scope || self;
			var defResult = this.cachingFetch ? this.cachingFetch(args) : this._doQuery(args);
			defResult.request = args;
			defResult.addCallback(function(results){
				if(args.clientFetch){
					results = self.clientSideFetch({query:args.clientFetch,sort:args.sort,start:args.start,count:args.count},results);
				}
				var resultSet = self._processResults(results, defResult);
				results = args.results = resultSet.items;
				if(args.onBegin){
					args.onBegin.call(scope, resultSet.totalCount, args);
				}
				if(args.onItem){
					for(var i=0; i<results.length;i++){
						args.onItem.call(scope, results[i], args);
					}
				}
				if(args.onComplete){
					args.onComplete.call(scope, args.onItem ? null : results, args);
				}
				return results;
			});
			defResult.addErrback(args.onError && function(err){
				return args.onError.call(scope, err, args);
			});
			args.abort = function(){
				// abort the request
				defResult.cancel();
			};
			args.store = this;
			return args;
		},
		_doQuery: function(args){
			var query= typeof args.queryStr == 'string' ? args.queryStr : args.query;
			return this.service(query);
		},
		getFeatures: function(){
			// summary:
			// 		return the store feature set

			return {
				"dojo.data.api.Read": true,
				"dojo.data.api.Identity": true,
				"dojo.data.api.Schema": this.schema
			};
		},

		getLabel: function(item){
			// summary
			//		returns the label for an item. Just gets the "label" attribute.
			//
			return this.getValue(item,this.labelAttribute);
		},

		getLabelAttributes: function(item){
			// summary:
			//		returns an array of attributes that are used to create the label of an item
			return [this.labelAttribute];
		},

		//Identity API Support


		getIdentity: function(item){
			return item.__id;
		},

		getIdentityAttributes: function(item){
			// summary:
			//		returns the attributes which are used to make up the
			//		identity of an item.	Basically returns this.idAttribute

			return [this.idAttribute];
		},

		fetchItemByIdentity: function(args){
			// summary:
			//		fetch an item by its identity, by looking in our index of what we have loaded
			var item = this._index[(args._prefix || '') + args.identity];
			if(item){
				// the item exists in the index
				if(item._loadObject){
					// we have a handle on the item, but it isn't loaded yet, so we need to load it
					args.item = item;
					return this.loadItem(args);
				}else if(args.onItem){
					// it's already loaded, so we can immediately callback
					args.onItem.call(args.scope, item);
				}
			}else{
				// convert the different spellings
				return this.fetch({
						query: args.identity,
						onComplete: args.onItem,
						onError: args.onError,
						scope: args.scope
					}).results;
			}
			return item;
		}

	}
);

}

if(!dojo._hasResource["dojox.json.ref"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.json.ref"] = true;
dojo.provide("dojox.json.ref");



dojox.json.ref = {
	// summary:
	// 		Adds advanced JSON {de}serialization capabilities to the base json library.
	// 		This enhances the capabilities of dojo.toJson and dojo.fromJson,
	// 		adding referencing support, date handling, and other extra format handling.
	// 		On parsing, references are resolved. When references are made to
	// 		ids/objects that have been loaded yet, the loader function will be set to
	// 		_loadObject to denote a lazy loading (not loaded yet) object. 


	resolveJson: function(/*Object*/ root,/*Object?*/ args){
		// summary:
		// 		Indexes and resolves references in the JSON object.
		// description:
		// 		A JSON Schema object that can be used to advise the handling of the JSON (defining ids, date properties, urls, etc)
		//
		// root:
		//		The root object of the object graph to be processed
		// args:
		//		Object with additional arguments:
		//
		// The *index* parameter.
		//		This is the index object (map) to use to store an index of all the objects. 
		// 		If you are using inter-message referencing, you must provide the same object for each call.
		// The *defaultId* parameter.
		//		This is the default id to use for the root object (if it doesn't define it's own id)
		//	The *idPrefix* parameter.
		//		This the prefix to use for the ids as they enter the index. This allows multiple tables 
		// 		to use ids (that might otherwise collide) that enter the same global index. 
		// 		idPrefix should be in the form "/Service/".  For example,
		//		if the idPrefix is "/Table/", and object is encountered {id:"4",...}, this would go in the
		//		index as "/Table/4".
		//	The *idAttribute* parameter.
		//		This indicates what property is the identity property. This defaults to "id"
		//	The *assignAbsoluteIds* parameter.
		//		This indicates that the resolveJson should assign absolute ids (__id) as the objects are being parsed.
		//  
		// The *schemas* parameter
		//		This provides a map of schemas, from which prototypes can be retrieved
		// The *loader* parameter
		//		This is a function that is called added to the reference objects that can't be resolved (lazy objects)
		// return:
		//		An object, the result of the processing
		args = args || {};
		var idAttribute = args.idAttribute || 'id';
		var refAttribute = this.refAttribute;
		var idAsRef = args.idAsRef;
		var prefix = args.idPrefix || ''; 
		var assignAbsoluteIds = args.assignAbsoluteIds;
		var index = args.index || {}; // create an index if one doesn't exist
		var timeStamps = args.timeStamps;
		var ref,reWalk=[];
		var pathResolveRegex = /^(.*\/)?(\w+:\/\/)|[^\/\.]+\/\.\.\/|^.*\/(\/)/;
		var addProp = this._addProp;
		var F = function(){};
		function walk(it, stop, defaultId, needsPrefix, schema, defaultObject){
			// this walks the new graph, resolving references and making other changes
		 	var i, update, val, id = idAttribute in it ? it[idAttribute] : defaultId;
		 	if(idAttribute in it || ((id !== undefined) && needsPrefix)){
		 		id = (prefix + id).replace(pathResolveRegex,'$2$3');
		 	}
		 	var target = defaultObject || it;
			if(id !== undefined){ // if there is an id available...
				if(assignAbsoluteIds){
					it.__id = id;
				}
				if(args.schemas && (!(it instanceof Array)) && // won't try on arrays to do prototypes, plus it messes with queries 
		 					(val = id.match(/^(.+\/)[^\.\[]*$/))){ // if it has a direct table id (no paths)
		 			schema = args.schemas[val[1]];
				} 
				// if the id already exists in the system, we should use the existing object, and just 
				// update it... as long as the object is compatible
				if(index[id] && ((it instanceof Array) == (index[id] instanceof Array))){ 
					target = index[id];
					delete target.$ref; // remove this artifact
					delete target._loadObject;
					update = true;
				}else{
				 	var proto = schema && schema.prototype; // and if has a prototype
					if(proto){
						// if the schema defines a prototype, that needs to be the prototype of the object
						F.prototype = proto;
						target = new F();
					}
				}
				index[id] = target; // add the prefix, set _id, and index it
				if(timeStamps){
					timeStamps[id] = args.time;
				}
			}
			while(schema){
				var properties = schema.properties;
				if(properties){
					for(i in it){
						var propertyDefinition = properties[i];
						if(propertyDefinition && propertyDefinition.format == 'date-time' && typeof it[i] == 'string'){
							it[i] = dojo.date.stamp.fromISOString(it[i]);
						}
					}
				}
				schema = schema["extends"];
			}
			var length = it.length;
			for(i in it){
				if(i==length){
					break;		
				}
				if(it.hasOwnProperty(i)){
					val=it[i];
					if((typeof val =='object') && val && !(val instanceof Date) && i != '__parent'){
						ref=val[refAttribute] || (idAsRef && val[idAttribute]);
						if(!ref || !val.__parent){
							if(it != reWalk){
								val.__parent = target;
							}
						}
						if(ref){ // a reference was found
							// make sure it is a safe reference
							delete it[i];// remove the property so it doesn't resolve to itself in the case of id.propertyName lazy values
							var path = ref.toString().replace(/(#)([^\.\[])/,'$1.$2').match(/(^([^\[]*\/)?[^#\.\[]*)#?([\.\[].*)?/); // divide along the path
							if((ref = (path[1]=='$' || path[1]=='this' || path[1]=='') ? root : index[(prefix + path[1]).replace(pathResolveRegex,'$2$3')])){  // a $ indicates to start with the root, otherwise start with an id
								// if there is a path, we will iterate through the path references
								if(path[3]){
									path[3].replace(/(\[([^\]]+)\])|(\.?([^\.\[]+))/g,function(t,a,b,c,d){
										ref = ref && ref[b ? b.replace(/[\"\'\\]/,'') : d];
									});
								}
							}
							if(ref){
								val = ref;
							}else{
								// otherwise, no starting point was found (id not found), if stop is set, it does not exist, we have
								// unloaded reference, if stop is not set, it may be in a part of the graph not walked yet,
								// we will wait for the second loop
								if(!stop){
									var rewalking;
									if(!rewalking){
										reWalk.push(target); // we need to rewalk it to resolve references
									}
									rewalking = true; // we only want to add it once
									val = walk(val, false, val[refAttribute], true, propertyDefinition);
									// create a lazy loaded object
									val._loadObject = args.loader;
								}
							}
						}else{
							if(!stop){ // if we are in stop, that means we are in the second loop, and we only need to check this current one,
								// further walking may lead down circular loops
								val = walk(
									val,
									reWalk==it,
									id === undefined ? undefined : addProp(id, i), // the default id to use
									false,
									propertyDefinition, 
									// if we have an existing object child, we want to 
									// maintain it's identity, so we pass it as the default object
									target != it && typeof target[i] == 'object' && target[i] 
								);
							}
						}
					}
					it[i] = val;
					if(target!=it && !target.__isDirty){// do updates if we are updating an existing object and it's not dirty				
						var old = target[i];
						target[i] = val; // only update if it changed
						if(update && val !== old && // see if it is different 
								!target._loadObject && // no updates if we are just lazy loading
								!(i.charAt(0) == '_' && i.charAt(1) == '_') && i != "$ref" &&  
								!(val instanceof Date && old instanceof Date && val.getTime() == old.getTime()) && // make sure it isn't an identical date
								!(typeof val == 'function' && typeof old == 'function' && val.toString() == old.toString()) && // make sure it isn't an indentical function
								index.onUpdate){
							index.onUpdate(target,i,old,val); // call the listener for each update
						}
					}
				}
			}
	
			if(update && (idAttribute in it || target instanceof Array)){
				// this means we are updating with a full representation of the object, we need to remove deleted
				for(i in target){
					if(!target.__isDirty && target.hasOwnProperty(i) && !it.hasOwnProperty(i) && !(i.charAt(0) == '_' && i.charAt(1) == '_') && !(target instanceof Array && isNaN(i))){
						if(index.onUpdate && i != "_loadObject" && i != "_idAttr"){
							index.onUpdate(target,i,target[i],undefined); // call the listener for each update
						}
						delete target[i];
						while(target instanceof Array && target.length && target[target.length-1] === undefined){
							// shorten the target if necessary
							target.length--;
						}
					}
				}
			}else{
				if(index.onLoad){
					index.onLoad(target);
				}
			}
			return target;
		}
		if(root && typeof root == 'object'){
			root = walk(root,false,args.defaultId, true); // do the main walk through
			walk(reWalk,false); // re walk any parts that were not able to resolve references on the first round
		}
		return root;
	},


	fromJson: function(/*String*/ str,/*Object?*/ args){
	// summary:
	// 		evaluates the passed string-form of a JSON object.
	//
	// str:
	//		a string literal of a JSON item, for instance:
	//			'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'
	// args: See resolveJson
	//
	// return:
	//		An object, the result of the evaluation
		function ref(target){ // support call styles references as well
			var refObject = {};
			refObject[this.refAttribute] = target;
			return refObject;
		}
		try{
			var root = eval('(' + str + ')'); // do the eval
		}catch(e){
			throw new SyntaxError("Invalid JSON string: " + e.message + " parsing: "+ str);
		}		
		if(root){
			return this.resolveJson(root, args);
		}
		return root;
	},
	
	toJson: function(/*Object*/ it, /*Boolean?*/ prettyPrint, /*Object?*/ idPrefix, /*Object?*/ indexSubObjects){
		// summary:
		//		Create a JSON serialization of an object.
		//		This has support for referencing, including circular references, duplicate references, and out-of-message references
		// 		id and path-based referencing is supported as well and is based on http://www.json.com/2007/10/19/json-referencing-proposal-and-library/.
		//
		// it:
		//		an object to be serialized.
		//
		// prettyPrint:
		//		if true, we indent objects and arrays to make the output prettier.
		//		The variable dojo.toJsonIndentStr is used as the indent string
		//		-- to use something other than the default (tab),
		//		change that variable before calling dojo.toJson().
		//
		// idPrefix: The prefix that has been used for the absolute ids
		//
		// return:
		//		a String representing the serialized version of the passed object.
		var useRefs = this._useRefs;
		var addProp = this._addProp;
		var refAttribute = this.refAttribute;
		idPrefix = idPrefix || ''; // the id prefix for this context
		var paths={};
		var generated = {};
		function serialize(it,path,_indentStr){
			if(typeof it == 'object' && it){
				var value;
				if(it instanceof Date){ // properly serialize dates
					return '"' + dojo.date.stamp.toISOString(it,{zulu:true}) + '"';
				}
				var id = it.__id;
				if(id){ // we found an identifiable object, we will just serialize a reference to it... unless it is the root
					if(path != '#' && ((useRefs && !id.match(/#/)) || paths[id])){
						var ref = id;	
						if(id.charAt(0)!='#'){
							if(it.__clientId == id){
								ref = "cid:" + id;
							}else if(id.substring(0, idPrefix.length) == idPrefix){ // see if the reference is in the current context
								// a reference with a prefix matching the current context, the prefix should be removed
								ref = id.substring(idPrefix.length);
							}else{
								// a reference to a different context, assume relative url based referencing
								ref = id;
							}
						}
						var refObject = {};
						refObject[refAttribute] = ref;
						return serialize(refObject,'#');
					}
					path = id;
				}else{
					it.__id = path; // we will create path ids for other objects in case they are circular
					generated[path] = it;
				}
				paths[path] = it;// save it here so they can be deleted at the end
				_indentStr = _indentStr || "";
				var nextIndent = prettyPrint ? _indentStr + dojo.toJsonIndentStr : "";
				var newLine = prettyPrint ? "\n" : "";
				var sep = prettyPrint ? " " : "";
	
				if(it instanceof Array){
					var res = dojo.map(it, function(obj,i){
						var val = serialize(obj, addProp(path, i), nextIndent);
						if(typeof val != "string"){
							val = "undefined";
						}
						return newLine + nextIndent + val;
					});
					return "[" + res.join("," + sep) + newLine + _indentStr + "]";
				}
	
				var output = [];
				for(var i in it){
					if(it.hasOwnProperty(i)){
						var keyStr;
						if(typeof i == "number"){
							keyStr = '"' + i + '"';
						}else if(typeof i == "string" && (i.charAt(0) != '_' || i.charAt(1) != '_')){
							// we don't serialize our internal properties __id and __clientId
							keyStr = dojo._escapeString(i);
						}else{
							// skip non-string or number keys
							continue;
						}
						var val = serialize(it[i],addProp(path, i),nextIndent);
						if(typeof val != "string"){
							// skip non-serializable values
							continue;
						}
						output.push(newLine + nextIndent + keyStr + ":" + sep + val);
					}
				}
				return "{" + output.join("," + sep) + newLine + _indentStr + "}";
			}else if(typeof it == "function" && dojox.json.ref.serializeFunctions){
				return it.toString();
			}
	
			return dojo.toJson(it); // use the default serializer for primitives
		}
		var json = serialize(it,'#','');
		if(!indexSubObjects){
			for(var i in generated)  {// cleanup the temporary path-generated ids
				delete generated[i].__id;
			}
		}
		return json;
	},
	_addProp: function(id, prop){
		return id + (id.match(/#/) ? id.length == 1 ? '' : '.' : '#') + prop;
	},
	//	refAttribute: String
	//		This indicates what property is the reference property. This acts like the idAttribute
	// 		except that this is used to indicate the current object is a reference or only partially 
	// 		loaded. This defaults to "$ref". 
	refAttribute: "$ref",
	_useRefs: false,
	serializeFunctions: false
}

}

if(!dojo._hasResource["dojox.rpc.Rest"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.rpc.Rest"] = true;
dojo.provide("dojox.rpc.Rest"); 
// Note: This doesn't require dojox.rpc.Service, and if you want it you must require it 
// yourself, and you must load it prior to dojox.rpc.Rest.

// summary:
// 		This provides a HTTP REST service with full range REST verbs include PUT,POST, and DELETE.
// description:
// 		A normal GET query is done by using the service directly:
// 		| var restService = dojox.rpc.Rest("Project");
// 		| restService("4");
//		This will do a GET for the URL "/Project/4".
//		| restService.put("4","new content");
//		This will do a PUT to the URL "/Project/4" with the content of "new content".
//		You can also use the SMD service to generate a REST service:
// 		| var services = dojox.rpc.Service({services: {myRestService: {transport: "REST",...
// 		| services.myRestService("parameters");
//
// 		The modifying methods can be called as sub-methods of the rest service method like:
//  	| services.myRestService.put("parameters","data to put in resource");
//  	| services.myRestService.post("parameters","data to post to the resource");
//  	| services.myRestService['delete']("parameters");
(function(){
	if(dojox.rpc && dojox.rpc.transportRegistry){
		// register it as an RPC service if the registry is available
		dojox.rpc.transportRegistry.register(
			"REST",
			function(str){return str == "REST";},
			{
				getExecutor : function(func,method,svc){
					return new dojox.rpc.Rest(
						method.name,
						(method.contentType||svc._smd.contentType||"").match(/json|javascript/), // isJson
						null,
						function(id, args){
							var request = svc._getRequest(method,[id]);
							request.url= request.target + (request.data ? '?'+  request.data : '');
							return request;
						}
					);
				}
			}
		);
	}
	var drr;

	function index(deferred, service, range, id){
		deferred.addCallback(function(result){
			if(deferred.ioArgs.xhr && range){
					// try to record the total number of items from the range header
					range = deferred.ioArgs.xhr.getResponseHeader("Content-Range");
					deferred.fullLength = range && (range=range.match(/\/(.*)/)) && parseInt(range[1]);
			}
			return result;
		});
		return deferred;
	}
	drr = dojox.rpc.Rest = function(/*String*/path, /*Boolean?*/isJson, /*Object?*/schema, /*Function?*/getRequest){
		// summary:
		//		Creates a REST service using the provided path.
		var service;
		// it should be in the form /Table/
		service = function(id, args){
			return drr._get(service, id, args);
		};
		service.isJson = isJson;
		service._schema = schema;
		// cache:
		//		This is an object that provides indexing service
		// 		This can be overriden to take advantage of more complex referencing/indexing
		// 		schemes
		service.cache = {
			serialize: isJson ? ((dojox.json && dojox.json.ref) || dojo).toJson : function(result){
				return result;
			}
		};
		// the default XHR args creator:
		service._getRequest = getRequest || function(id, args){
			if(dojo.isObject(id)){
				id = dojo.objectToQuery(id);
				id = id ? "?" + id: "";
			}
			if(args && args.sort && !args.queryStr){
				id += (id ? "&" : "?") + "sort("
				for(var i = 0; i<args.sort.length; i++){
					var sort = args.sort[i];
					id += (i > 0 ? "," : "") + (sort.descending ? '-' : '+') + encodeURIComponent(sort.attribute); 
				}
				id += ")";
			}
			var request = {
				url: path + (id == null ? "" : id),
				handleAs: isJson ? 'json' : 'text', 
				contentType: isJson ? 'application/json' : 'text/plain',
				sync: dojox.rpc._sync,
				headers: {
					Accept: isJson ? 'application/json,application/javascript' : '*/*'
				}
			};
			if(args && (args.start >= 0 || args.count >= 0)){
				request.headers.Range = "items=" + (args.start || '0') + '-' + ((args.count && args.count != Infinity && (args.count + (args.start || 0) - 1)) || '');
			}
			dojox.rpc._sync = false;
			return request;
		};
		// each calls the event handler
		function makeRest(name){
			service[name] = function(id,content){
				return drr._change(name,service,id,content); // the last parameter is to let the OfflineRest know where to store the item
			};
		}
		makeRest('put');
		makeRest('post');
		makeRest('delete');
		// record the REST services for later lookup
		service.servicePath = path;
		return service;
	};

	drr._index={};// the map of all indexed objects that have gone through REST processing
	drr._timeStamps={};
	// these do the actual requests
	drr._change = function(method,service,id,content){
		// this is called to actually do the put, post, and delete
		var request = service._getRequest(id);
		request[method+"Data"] = content;
		return index(dojo.xhr(method.toUpperCase(),request,true),service);
	};

	drr._get= function(service,id, args){
		args = args || {};
		// this is called to actually do the get
		return index(dojo.xhrGet(service._getRequest(id, args)), service, (args.start >= 0 || args.count >= 0), id);
	};
})();

}

if(!dojo._hasResource["dojox.rpc.JsonRest"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.rpc.JsonRest"] = true;
dojo.provide("dojox.rpc.JsonRest");

 // this provides json indexing

// summary:
// 		Provides JSON/REST utility functions
(function(){
	var dirtyObjects = [];
	var Rest = dojox.rpc.Rest;
	var jr;
	function resolveJson(service, deferred, value, defaultId){
		var timeStamp = deferred.ioArgs && deferred.ioArgs.xhr && deferred.ioArgs.xhr.getResponseHeader("Last-Modified");
		if(timeStamp && Rest._timeStamps){
			Rest._timeStamps[defaultId] = timeStamp;
		}
		var hrefProperty = service._schema && service._schema.hrefProperty;
		if(hrefProperty){
			dojox.json.ref.refAttribute = hrefProperty;
		}
		value = value && dojox.json.ref.resolveJson(value, {
			defaultId: defaultId, 
			index: Rest._index,
			timeStamps: timeStamp && Rest._timeStamps,
			time: timeStamp,
			idPrefix: service.servicePath.replace(/[^\/]*$/,''),
			idAttribute: jr.getIdAttribute(service),
			schemas: jr.schemas,
			loader:	jr._loader,
			idAsRef: service.idAsRef, 
			assignAbsoluteIds: true
		});
		dojox.json.ref.refAttribute  = "$ref";
		return value;
	}
	jr = dojox.rpc.JsonRest={
		serviceClass: dojox.rpc.Rest,
		conflictDateHeader: "If-Unmodified-Since",
		commit: function(kwArgs){
			// summary:
			//		Saves the dirty data using REST Ajax methods

			kwArgs = kwArgs || {};
			var actions = [];
			var alreadyRecorded = {};
			var savingObjects = [];
			for(var i = 0; i < dirtyObjects.length; i++){
				var dirty = dirtyObjects[i];
				var object = dirty.object;
				var old = dirty.old;
				var append = false;
				if(!(kwArgs.service && (object || old) && 
						(object || old).__id.indexOf(kwArgs.service.servicePath)) && dirty.save){
					delete object.__isDirty;
					if(object){
						if(old){
							// changed object
							var pathParts;
							if((pathParts = object.__id.match(/(.*)#.*/))){ // it is a path reference
								// this means it is a sub object, we must go to the parent object and save it
								object = Rest._index[pathParts[1]];
							}
							if(!(object.__id in alreadyRecorded)){// if it has already been saved, we don't want to repeat it
								// record that we are saving
								alreadyRecorded[object.__id] = object;
								if(kwArgs.incrementalUpdates 
									&& !pathParts){ // I haven't figured out how we would do incremental updates on sub-objects yet
									// make an incremental update using a POST
									var incremental = (typeof kwArgs.incrementalUpdates == 'function' ?
										kwArgs.incrementalUpdates : function(){
											incremental = {};
											for(var j in object){
												if(object.hasOwnProperty(j)){
													if(object[j] !== old[j]){
														incremental[j] = object[j];
													}
												}else if(old.hasOwnProperty(j)){
													// we can't use incremental updates to remove properties
													return null;
												}
											}
											return incremental;
										})(object, old);
								}
								
								if(incremental){
									actions.push({method:"post",target:object, content: incremental});
								}
								else{
									actions.push({method:"put",target:object,content:object});
								}
							}
						}else{
							// new object
							var service = jr.getServiceAndId(object.__id).service;
							var idAttribute = jr.getIdAttribute(service);
							if((idAttribute in object) && !kwArgs.alwaysPostNewItems){
								// if the id attribute is specified, then we should know the location
								actions.push({method:"put",target:object, content:object});
							}else{
								actions.push({method:"post",target:{__id:service.servicePath},
														content:object});
							}
						}
					}else if(old){
						// deleted object
						actions.push({method:"delete",target:old});
					}//else{ this would happen if an object is created and then deleted, don't do anything
					savingObjects.push(dirty);
					dirtyObjects.splice(i--,1);
				}
			}
			dojo.connect(kwArgs,"onError",function(){
				if(kwArgs.revertOnError !== false){
					var postCommitDirtyObjects = dirtyObjects;
					dirtyObjects = savingObjects;
					var numDirty = 0; // make sure this does't do anything if it is called again
					jr.revert(); // revert if there was an error
					dirtyObjects = postCommitDirtyObjects;
				}
				else{
					dirtyObjects = dirtyObject.concat(savingObjects); 
				}
			});
			jr.sendToServer(actions, kwArgs);
			return actions;
		},
		sendToServer: function(actions, kwArgs){
			var xhrSendId;
			var plainXhr = dojo.xhr;
			var left = actions.length;// this is how many changes are remaining to be received from the server
			var i, contentLocation;
			var timeStamp;
			var conflictDateHeader = this.conflictDateHeader;
			// add headers for extra information
			dojo.xhr = function(method,args){
				// keep the transaction open as we send requests
				args.headers = args.headers || {};
				// the last one should commit the transaction
				args.headers['Transaction'] = actions.length - 1 == i ? "commit" : "open";
				if(conflictDateHeader && timeStamp){
					args.headers[conflictDateHeader] = timeStamp; 
				}
				if(contentLocation){
					args.headers['Content-ID'] = '<' + contentLocation + '>';
				}
				return plainXhr.apply(dojo,arguments);
			};			
			for(i =0; i < actions.length;i++){ // iterate through the actions to execute
				var action = actions[i];
				dojox.rpc.JsonRest._contentId = action.content && action.content.__id; // this is used by OfflineRest
				var isPost = action.method == 'post';
				timeStamp = action.method == 'put' && Rest._timeStamps[action.content.__id];
				if(timeStamp){
					// update it now
					Rest._timeStamps[action.content.__id] = (new Date()) + '';
				}
				// send the content location to the server
				contentLocation = isPost && dojox.rpc.JsonRest._contentId;
				var serviceAndId = jr.getServiceAndId(action.target.__id);
				var service = serviceAndId.service; 
				var dfd = action.deferred = service[action.method](
									serviceAndId.id.replace(/#/,''), // if we are using references, we need eliminate #
									dojox.json.ref.toJson(action.content, false, service.servicePath, true)
								);
				(function(object, dfd, service){
					dfd.addCallback(function(value){
						try{
							// Implements id assignment per the HTTP specification
							var newId = dfd.ioArgs.xhr && dfd.ioArgs.xhr.getResponseHeader("Location");
							//TODO: match URLs if the servicePath is relative...
							if(newId){
								// if the path starts in the middle of an absolute URL for Location, we will use the just the path part 
								var startIndex = newId.match(/(^\w+:\/\/)/) && newId.indexOf(service.servicePath);
								newId = startIndex > 0 ? newId.substring(startIndex) : (service.servicePath + newId).
										// now do simple relative URL resolution in case of a relative URL. 
										replace(/^(.*\/)?(\w+:\/\/)|[^\/\.]+\/\.\.\/|^.*\/(\/)/,'$2$3');
								object.__id = newId;
								Rest._index[newId] = object;
							}
							value = resolveJson(service, dfd, value, object && object.__id);
						}catch(e){}
						if(!(--left)){
							if(kwArgs.onComplete){
								kwArgs.onComplete.call(kwArgs.scope, actions);
							}
						}
						return value;
					});
				})(action.content, dfd, service);
								
				dfd.addErrback(function(value){
					
					// on an error we want to revert, first we want to separate any changes that were made since the commit
					left = -1; // first make sure that success isn't called
					kwArgs.onError.call(kwArgs.scope, value);
				});
			}
			// revert back to the normal XHR handler
			dojo.xhr = plainXhr;
			
		},
		getDirtyObjects: function(){
			return dirtyObjects;
		},
		revert: function(service){
			// summary:
			//		Reverts all the changes made to JSON/REST data
			for(var i = dirtyObjects.length; i > 0;){
				i--;
				var dirty = dirtyObjects[i];
				var object = dirty.object;
				var old = dirty.old;
				var store = dojox.data._getStoreForItem(object || old);
				
				if(!(service && (object || old) && 
					(object || old).__id.indexOf(service.servicePath))){
					// if we are in the specified store or if this is a global revert
					if(object && old){
						// changed
						for(var j in old){
							if(old.hasOwnProperty(j) && object[j] !== old[j]){
								if(store){
									store.onSet(object, j, object[j], old[j]);
								}
								object[j] = old[j];
							}
						}
						for(j in object){
							if(!old.hasOwnProperty(j)){
								if(store){
									store.onSet(object, j, object[j]);
								}
								delete object[j];
							}
						}
					}else if(!old){
						// was an addition, remove it
						if(store){
							store.onDelete(object);
						}
					}else{
						// was a deletion, we will add it back
						if(store){
							store.onNew(old);
						}
					}
					delete (object || old).__isDirty;
					dirtyObjects.splice(i, 1);
				}
			}
		},
		changing: function(object,_deleting){
			// summary:
			//		adds an object to the list of dirty objects.  This object
			//		contains a reference to the object itself as well as a
			//		cloned and trimmed version of old object for use with
			//		revert.
			if(!object.__id){
				return;
			}
			object.__isDirty = true;
			//if an object is already in the list of dirty objects, don't add it again
			//or it will overwrite the premodification data set.
			for(var i=0; i<dirtyObjects.length; i++){
				var dirty = dirtyObjects[i];
				if(object==dirty.object){
					if(_deleting){
						// we are deleting, no object is an indicator of deletiong
						dirty.object = false;
						if(!this._saveNotNeeded){
							dirty.save = true;
						}
					}
					return;
				}
			}
			var old = object instanceof Array ? [] : {};
			for(i in object){
				if(object.hasOwnProperty(i)){
					old[i] = object[i];
				}
			}
			dirtyObjects.push({object: !_deleting && object, old: old, save: !this._saveNotNeeded});
		},
		deleteObject: function(object){
			// summary:
			//		deletes an object 
			//	object:
			//  	object to delete
			this.changing(object,true);
		},
		getConstructor: function(/*Function|String*/service, schema){
			// summary:
			// 		Creates or gets a constructor for objects from this service
			if(typeof service == 'string'){
				var servicePath = service;
				service = new dojox.rpc.Rest(service,true);
				this.registerService(service, servicePath, schema);
			}
			if(service._constructor){
				return service._constructor;
			}
			service._constructor = function(data){
				// summary:
				//		creates a new object for this table
				//
				//	data:
				//		object to mixed in
				var self = this;
				var args = arguments;
				var properties;
				var initializeCalled;
				function addDefaults(schema){
					if(schema){
						addDefaults(schema['extends']);
						properties = schema.properties;
						for(var i in properties){
							var propDef = properties[i]; 
							if(propDef && (typeof propDef == 'object') && ("default" in propDef)){
								self[i] = propDef["default"];
							}
						}
					}
					if(schema && schema.prototype && schema.prototype.initialize){
						initializeCalled = true;
						schema.prototype.initialize.apply(self, args);
					}
				}
				addDefaults(service._schema);
				if(!initializeCalled && data && typeof data == 'object'){
					dojo.mixin(self,data);
				}
				var idAttribute = jr.getIdAttribute(service);
				Rest._index[this.__id = this.__clientId = 
						service.servicePath + (this[idAttribute] || 
							Math.random().toString(16).substring(2,14) + '@' + ((dojox.rpc.Client && dojox.rpc.Client.clientId) || "client"))] = this;
				if(dojox.json.schema && properties){
					dojox.json.schema.mustBeValid(dojox.json.schema.validate(this, service._schema));
				} 
				dirtyObjects.push({object:this, save: true});
			};
			return dojo.mixin(service._constructor, service._schema, {load:service});
		},
		fetch: function(absoluteId){
			// summary:
			//		Fetches a resource by an absolute path/id and returns a dojo.Deferred.
			var serviceAndId = jr.getServiceAndId(absoluteId);
			return this.byId(serviceAndId.service,serviceAndId.id);
		},
		getIdAttribute: function(service){
			// summary:
			//		Return the ids attribute used by this service (based on it's schema).
			//		Defaults to "id", if not other id is defined
			var schema = service._schema;
			var idAttr;
			if(schema){
				if(!(idAttr = schema._idAttr)){
					for(var i in schema.properties){
						if(schema.properties[i].identity || (schema.properties[i].link == "self")){
							schema._idAttr = idAttr = i;
						}
					}
				}
			}
			return idAttr || 'id';
		},
		getServiceAndId: function(/*String*/absoluteId){
			// summary:
			//		Returns the REST service and the local id for the given absolute id. The result 
			// 		is returned as an object with a service property and an id property
			//	absoluteId:
			//		This is the absolute id of the object
			var serviceName = '';
			
			for(var service in jr.services){
				if((absoluteId.substring(0, service.length) == service) && (service.length >= serviceName.length)){
					serviceName = service;
				}
			}
			if (serviceName){
				return {service: jr.services[serviceName], id:absoluteId.substring(serviceName.length)};
			}			
			var parts = absoluteId.match(/^(.*\/)([^\/]*)$/);
			return {service: new jr.serviceClass(parts[1], true), id:parts[2]};
		},
		services:{},
		schemas:{},
		registerService: function(/*Function*/ service, /*String*/ servicePath, /*Object?*/ schema){
			//	summary:
			//		Registers a service for as a JsonRest service, mapping it to a path and schema
			//	service:
			//		This is the service to register
			//	servicePath:
			//		This is the path that is used for all the ids for the objects returned by service
			//	schema:
			//		This is a JSON Schema object to associate with objects returned by this service
			servicePath = service.servicePath = servicePath || service.servicePath;
			service._schema = jr.schemas[servicePath] = schema || service._schema || {};
			jr.services[servicePath] = service;
		},
		byId: function(service, id){
			// if caching is allowed, we look in the cache for the result
			var deferred, result = Rest._index[(service.servicePath || '') + id];
			if(result && !result._loadObject){// cache hit
				deferred = new dojo.Deferred();
				deferred.callback(result);
				return deferred;
			}
			return this.query(service, id);
		},
		query: function(service, id, args){
			var deferred = service(id, args);
			
			deferred.addCallback(function(result){
				if(result.nodeType && result.cloneNode){
					// return immediately if it is an XML document
					return result;
				}				
				return resolveJson(service, deferred, result, typeof id != 'string' || (args && (args.start || args.count)) ? undefined: id);
			});
			return deferred;			
		},
		_loader: function(callback){
			// load a lazy object
			var serviceAndId = jr.getServiceAndId(this.__id);
			var self = this;
			jr.query(serviceAndId.service, serviceAndId.id).addBoth(function(result){
				// if they are the same this means an object was loaded, otherwise it 
				// might be a primitive that was loaded or maybe an error
				if(result == self){
					// we can clear the flag, so it is a loaded object
					delete result.$ref;
					delete result._loadObject;
				}else{
					// it is probably a primitive value, we can't change the identity of an object to
					//	the loaded value, so we will keep it lazy, but define the lazy loader to always
					//	return the loaded value
					self._loadObject = function(callback){
						callback(result);
					};
				}
				callback(result);
			});
		},
		isDirty: function(item){
			// summary
			//		returns true if the item is marked as dirty or true if there are any dirty items
			if(!item){
				return !!dirtyObjects.length;
			}
			return item.__isDirty;
		}
		
	};
})();



}

if(!dojo._hasResource["dojox.data.JsonRestStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.data.JsonRestStore"] = true;
dojo.provide("dojox.data.JsonRestStore");




dojo.declare("dojox.data.JsonRestStore",
	dojox.data.ServiceStore,
	{
		constructor: function(options){
			//summary:
			//		JsonRestStore is a Dojo Data store interface to JSON HTTP/REST web
			//		storage services that support read and write through GET, PUT, POST, and DELETE.
			// options:
			// 		Keyword arguments
			//
			// The *schema* parameter
			//		This is a schema object for this store. This should be JSON Schema format.
			//
			// The *service* parameter
			// 		This is the service object that is used to retrieve lazy data and save results
			// 		The function should be directly callable with a single parameter of an object id to be loaded
			// 		The function should also have the following methods:
			// 			put(id,value) - puts the value at the given id
			// 			post(id,value) - posts (appends) the value at the given id
			// 			delete(id) - deletes the value corresponding to the given id
			//		Note that it is critical that the service parses responses as JSON.
			//		If you are using dojox.rpc.Service, the easiest way to make sure this
			// 		happens is to make the responses have a content type of
			// 		application/json. If you are creating your own service, make sure you
			//		use handleAs: "json" with your XHR requests.
			//
			// The *target* parameter
			// 		This is the target URL for this Service store. This may be used in place
			// 		of a service parameter to connect directly to RESTful URL without
			// 		using a dojox.rpc.Service object.
			//
			// The *idAttribute* parameter
			//		Defaults to 'id'. The name of the attribute that holds an objects id.
			//		This can be a preexisting id provided by the server.
			//		If an ID isn't already provided when an object
			//		is fetched or added to the store, the autoIdentity system
			//		will generate an id for it and add it to the index.
			//
			// The *syncMode* parameter
			//		Setting this to true will set the store to using synchronous calls by default.
			//		Sync calls return their data immediately from the calling function, so
			//		callbacks are unnecessary
			//
			//	description:
			//		The JsonRestStore will cause all saved modifications to be sent to the server using Rest commands (PUT, POST, or DELETE).
			// 		When using a Rest store on a public network, it is important to implement proper security measures to
			//		control access to resources.
			//		On the server side implementing a REST interface means providing GET, PUT, POST, and DELETE handlers.
			//		GET - Retrieve an object or array/result set, this can be by id (like /table/1) or with a
			// 			query (like /table/?name=foo).
			//		PUT - This should modify a object, the URL will correspond to the id (like /table/1), and the body will
			// 			provide the modified object
			//		POST - This should create a new object. The URL will correspond to the target store (like /table/)
			// 			and the body should be the properties of the new object. The server's response should include a
			// 			Location header that indicates the id of the newly created object. This id will be used for subsequent
			// 			PUT and DELETE requests. JsonRestStore also includes a Content-Location header that indicates
			//			the temporary randomly generated id used by client, and this location is used for subsequent
			// 			PUT/DELETEs if no Location header is provided by the server or if a modification is sent prior
			// 			to receiving a response from the server.
			// 		DELETE - This should delete an object by id.
			// 		These articles include more detailed information on using the JsonRestStore:
			//		http://www.sitepen.com/blog/2008/06/13/restful-json-dojo-data/
			//		http://blog.medryx.org/2008/07/24/jsonreststore-overview/
			//
			//	example:
			// 		A JsonRestStore takes a REST service or a URL and uses it the remote communication for a
			// 		read/write dojo.data implementation. A JsonRestStore can be created with a simple URL like:
			// 	|	new JsonRestStore({target:"/MyData/"});
			//	example:
			// 		To use a JsonRestStore with a service, you should create a
			// 		service with a REST transport. This can be configured with an SMD:
			//	|	{
			//	|		services: {
			//	|			jsonRestStore: {
			//	|				transport: "REST",
			//	|				envelope: "URL",
			//	|				target: "store.php",
			//	|				contentType:"application/json",
			//	|				parameters: [
			//	|					{name: "location", type: "string", optional: true}
			//	|				]
			//	|			}
			//	|		}
			//	|	}
			// 		The SMD can then be used to create service, and the service can be passed to a JsonRestStore. For example:
			//	|	var myServices = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd"));
			//	|	var jsonStore = new dojox.data.JsonRestStore({service:myServices.jsonRestStore});
			//	example:
			//		The JsonRestStore also supports lazy loading. References can be made to objects that have not been loaded.
			//		For example if a service returned:
			//	|	{"name":"Example","lazyLoadedObject":{"$ref":"obj2"}}
			// 		And this object has accessed using the dojo.data API:
			//	|	var obj = jsonStore.getValue(myObject,"lazyLoadedObject");
			//		The object would automatically be requested from the server (with an object id of "obj2").
			//

			dojo.connect(dojox.rpc.Rest._index,"onUpdate",this,function(obj,attrName,oldValue,newValue){
				var prefix = this.service.servicePath;
				if(!obj.__id){
					console.log("no id on updated object ", obj);
				}else if(obj.__id.substring(0,prefix.length) == prefix){
					this.onSet(obj,attrName,oldValue,newValue);
				}
			});
			this.idAttribute = this.idAttribute || 'id';// no options about it, we have to have identity

			if(typeof options.target == 'string'){
				options.target = options.target.match(/\/$/) || this.allowNoTrailingSlash ? options.target : (options.target + '/');
				if(!this.service){
					this.service = dojox.rpc.JsonRest.services[options.target] ||
							dojox.rpc.Rest(options.target, true);
					// create a default Rest service
				}
			}

			dojox.rpc.JsonRest.registerService(this.service, options.target, this.schema);
			this.schema = this.service._schema = this.schema || this.service._schema || {};
			// wrap the service with so it goes through JsonRest manager
			this.service._store = this;
			this.service.idAsRef = this.idAsRef;
			this.schema._idAttr = this.idAttribute;
			var constructor = dojox.rpc.JsonRest.getConstructor(this.service);
			var self = this;
			this._constructor = function(data){
				constructor.call(this, data);
				self.onNew(this);
			}
			this._constructor.prototype = constructor.prototype;
			this._index = dojox.rpc.Rest._index;
		},
		
		// summary:
		//		Will load any schemas referenced content-type header or in Link headers
		loadReferencedSchema: true,
		// summary:
		//		Treat objects in queries as partially loaded objects
		idAsRef: false,
		referenceIntegrity: true,
		target:"",
		// summary:
		// 		Allow no trailing slash on target paths. This is generally discouraged since
		// 		it creates prevents simple scalar values from being used a relative URLs.
		// 		Disabled by default.
		allowNoTrailingSlash: false,
		//Write API Support
		newItem: function(data, parentInfo){
			// summary:
			//		adds a new item to the store at the specified point.
			//		Takes two parameters, data, and options.
			//
			//	data: /* object */
			//		The data to be added in as an item.
			data = new this._constructor(data);
			if(parentInfo){
				// get the previous value or any empty array
				var values = this.getValue(parentInfo.parent,parentInfo.attribute,[]);
				// set the new value
				values = values.concat([data]);
				data.__parent = values;
				this.setValue(parentInfo.parent, parentInfo.attribute, values);
			}
			return data;
		},
		deleteItem: function(item){
			// summary:
			//		deletes item and any references to that item from the store.
			//
			//	item:
			//		item to delete
			//

			//	If the desire is to delete only one reference, unsetAttribute or
			//	setValue is the way to go.
			var checked = [];
			var store = dojox.data._getStoreForItem(item) || this;
			if(this.referenceIntegrity){
				// cleanup all references
				dojox.rpc.JsonRest._saveNotNeeded = true;
				var index = dojox.rpc.Rest._index;
				var fixReferences = function(parent){
					var toSplice;
					// keep track of the checked ones
					checked.push(parent);
					// mark it checked so we don't run into circular loops when encountering cycles
					parent.__checked = 1;
					for(var i in parent){
						if(i.substring(0,2) != "__"){
							var value = parent[i];
							if(value == item){
								if(parent != index){ // make sure we are just operating on real objects
									if(parent instanceof Array){
										// mark it as needing to be spliced, don't do it now or it will mess up the index into the array
										(toSplice = toSplice || []).push(i);
									}else{
										// property, just delete it.
										(dojox.data._getStoreForItem(parent) || store).unsetAttribute(parent, i);
									}
								}
							}else{
								if((typeof value == 'object') && value){
									if(!value.__checked){
										// recursively search
										fixReferences(value);
									}
									if(typeof value.__checked == 'object' && parent != index){
										// if it is a modified array, we will replace it
										(dojox.data._getStoreForItem(parent) || store).setValue(parent, i, value.__checked);
									}
								}
							}
						}
					}
					if(toSplice){
						// we need to splice the deleted item out of these arrays
						i = toSplice.length;
						parent = parent.__checked = parent.concat(); // indicates that the array is modified
						while(i--){
							parent.splice(toSplice[i], 1);
						}
						return parent;
					}
					return null;
				};
				// start with the index
				fixReferences(index);
				dojox.rpc.JsonRest._saveNotNeeded = false;
				var i = 0;
				while(checked[i]){
					// remove the checked marker
					delete checked[i++].__checked;
				}
			}
			dojox.rpc.JsonRest.deleteObject(item);

			store.onDelete(item);
		},
		changing: function(item,_deleting){
			// summary:
			//		adds an item to the list of dirty items.	This item
			//		contains a reference to the item itself as well as a
			//		cloned and trimmed version of old item for use with
			//		revert.
			dojox.rpc.JsonRest.changing(item,_deleting);
		},

		setValue: function(item, attribute, value){
			// summary:
			//		sets 'attribute' on 'item' to 'value'

			var old = item[attribute];
			var store = item.__id ? dojox.data._getStoreForItem(item) : this;
			if(dojox.json.schema && store.schema && store.schema.properties){
				// if we have a schema and schema validator available we will validate the property change
				dojox.json.schema.mustBeValid(dojox.json.schema.checkPropertyChange(value,store.schema.properties[attribute]));
			}
			if(attribute == store.idAttribute){
				throw new Error("Can not change the identity attribute for an item");
			}
			store.changing(item);
			item[attribute]=value;
			if(value && !value.__parent){
				value.__parent = item;
			}
			store.onSet(item,attribute,old,value);
		},
		setValues: function(item, attribute, values){
			// summary:
			//	sets 'attribute' on 'item' to 'value' value
			//	must be an array.


			if(!dojo.isArray(values)){
				throw new Error("setValues expects to be passed an Array object as its value");
			}
			this.setValue(item,attribute,values);
		},

		unsetAttribute: function(item, attribute){
			// summary:
			//		unsets 'attribute' on 'item'

			this.changing(item);
			var old = item[attribute];
			delete item[attribute];
			this.onSet(item,attribute,old,undefined);
		},
		save: function(kwArgs){
			// summary:
			//		Saves the dirty data using REST Ajax methods. See dojo.data.api.Write for API.
			//
			//	kwArgs.global:
			//		This will cause the save to commit the dirty data for all
			// 		JsonRestStores as a single transaction.
			//
			//	kwArgs.revertOnError
			//		This will cause the changes to be reverted if there is an
			//		error on the save. By default a revert is executed unless
			//		a value of false is provide for this parameter.
			//
			//	kwArgs.incrementalUpdates
			//		For items that have been updated, if this is enabled, the server will be sent a POST request
			// 		with a JSON object containing the changed properties. By default this is
			// 		not enabled, and a PUT is used to deliver an update, and will include a full
			// 		serialization of all the properties of the item/object.
			//		If this is true, the POST request body will consist of a JSON object with
			// 		only the changed properties. The incrementalUpdates parameter may also
			//		be a function, in which case it will be called with the updated and previous objects
			//		and an object update representation can be returned.
			//
			//	kwArgs.alwaysPostNewItems
			//		If this is true, new items will always be sent with a POST request. By default
			//		this is not enabled, and the JsonRestStore will send a POST request if
			//		the item does not include its identifier (expecting server assigned location/
			//		identifier), and will send a PUT request if the item does include its identifier
			//		(the PUT will be sent to the URI corresponding to the provided identifier).

			if(!(kwArgs && kwArgs.global)){
				(kwArgs = kwArgs || {}).service = this.service;
			}
			if("syncMode" in kwArgs ? kwArgs.syncMode : this.syncMode){
				dojox.rpc._sync = true;
			}

			var actions = dojox.rpc.JsonRest.commit(kwArgs);
			this.serverVersion = this._updates && this._updates.length;
			return actions;
		},

		revert: function(kwArgs){
			// summary
			//		returns any modified data to its original state prior to a save();
			//
			//	kwArgs.global:
			//		This will cause the revert to undo all the changes for all
			// 		JsonRestStores in a single operation.
			dojox.rpc.JsonRest.revert(kwArgs && kwArgs.global && this.service);
		},

		isDirty: function(item){
			// summary
			//		returns true if the item is marked as dirty.
			return dojox.rpc.JsonRest.isDirty(item);
		},
		isItem: function(item, anyStore){
			//	summary:
			//		Checks to see if a passed 'item'
			//		really belongs to this JsonRestStore.
			//
			//	item: /* object */
			//		The value to test for being an item
			//	anyStore: /* boolean*/
			//		If true, this will return true if the value is an item for any JsonRestStore,
			//		not just this instance
			return item && item.__id && (anyStore || this.service == dojox.rpc.JsonRest.getServiceAndId(item.__id).service);
		},
		_doQuery: function(args){
			var query= typeof args.queryStr == 'string' ? args.queryStr : args.query;
			var deferred = dojox.rpc.JsonRest.query(this.service,query, args);
			var self = this;
			if(this.loadReferencedSchema){
				deferred.addCallback(function(result){
					var contentType = deferred.ioArgs && deferred.ioArgs.xhr && deferred.ioArgs.xhr.getResponseHeader("Content-Type");
					var schemaRef = contentType && contentType.match(/definedby\s*=\s*([^;]*)/);
					if(contentType && !schemaRef){
						schemaRef = deferred.ioArgs.xhr.getResponseHeader("Link");
						schemaRef = schemaRef && schemaRef.match(/<([^>]*)>;\s*rel="?definedby"?/);
					}
					schemaRef = schemaRef && schemaRef[1];
					if(schemaRef){
						var serviceAndId = dojox.rpc.JsonRest.getServiceAndId((self.target + schemaRef).replace(/^(.*\/)?(\w+:\/\/)|[^\/\.]+\/\.\.\/|^.*\/(\/)/,"$2$3"));
						var schemaDeferred = dojox.rpc.JsonRest.byId(serviceAndId.service, serviceAndId.id);
						schemaDeferred.addCallbacks(function(newSchema){
							dojo.mixin(self.schema, newSchema);
							return result;
						}, function(error){
							console.error(error); // log it, but don't let it cause the main request to fail
							return result;
						});
						return schemaDeferred;
					}
					return undefined;//don't change anything, and deal with the stupid post-commit lint complaints
				});
			}
			return deferred;
		},
		_processResults: function(results, deferred){
			// index the results
			var count = results.length;
			// if we don't know the length, and it is partial result, we will guess that it is twice as big, that will work for most widgets
			return {totalCount:deferred.fullLength || (deferred.request.count == count ? (deferred.request.start || 0) + count * 2 : count), items: results};
		},

		getConstructor: function(){
			// summary:
			// 		Gets the constructor for objects from this store
			return this._constructor;
		},
		getIdentity: function(item){
			var id = item.__clientId || item.__id;
			if(!id){
				return id;
			}
			var prefix = this.service.servicePath.replace(/[^\/]*$/,'');
			// support for relative or absolute referencing with ids
			return id.substring(0,prefix.length) != prefix ?	id : id.substring(prefix.length); // String
		},
		fetchItemByIdentity: function(args){
			var id = args.identity;
			var store = this;
			// if it is an absolute id, we want to find the right store to query
			if(id.toString().match(/^(\w*:)?\//)){
				var serviceAndId = dojox.rpc.JsonRest.getServiceAndId(id);
				store = serviceAndId.service._store;
				args.identity = serviceAndId.id;
			}
			args._prefix = store.service.servicePath.replace(/[^\/]*$/,'');
			return store.inherited(arguments);
		},
		//Notifcation Support

		onSet: function(){},
		onNew: function(){},
		onDelete: 	function(){},

		getFeatures: function(){
			// summary:
			// 		return the store feature set
			var features = this.inherited(arguments);
			features["dojo.data.api.Write"] = true;
			features["dojo.data.api.Notification"] = true;
			return features;
		},

		getParent: function(item){
			//	summary:
			//		Returns the parent item (or query) for the given item
			//	item:
			//		The item to find the parent of

			return item && item.__parent;
		}


	}
);
dojox.data.JsonRestStore.getStore = function(options, Class){
	//	summary:
	//		Will retrieve or create a store using the given options (the same options
	//		that are passed to JsonRestStore constructor. Returns a JsonRestStore instance
	//	options:
	//		See the JsonRestStore constructor
	//	Class:
	//		Constructor to use (for creating stores from JsonRestStore subclasses).
	// 		This is optional and defaults to JsonRestStore.
	if(typeof options.target == 'string'){
		options.target = options.target.match(/\/$/) || options.allowNoTrailingSlash ?
				options.target : (options.target + '/');
		var store = (dojox.rpc.JsonRest.services[options.target] || {})._store;
		if(store){
			return store;
		}
	}
	return new (Class || dojox.data.JsonRestStore)(options);
};
dojox.data._getStoreForItem = function(item){
	if(item.__id){
		var serviceAndId = dojox.rpc.JsonRest.getServiceAndId(item.__id);
		if(serviceAndId && serviceAndId.service._store){
			return serviceAndId.service._store;
		}else{
			var servicePath = item.__id.toString().match(/.*\//)[0];
			return new dojox.data.JsonRestStore({target:servicePath});
		}
	}
	return null;
};
dojox.json.ref._useRefs = true; // Use referencing when identifiable objects are referenced

}

if(!dojo._hasResource["dojox.fx._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.fx._base"] = true;
dojo.provide("dojox.fx._base");
// summary: Experimental and extended Animations beyond Dojo Core / Base functionality. 
//	Provides advanced Lines, Animations, and convenience aliases.
 

dojo.mixin(dojox.fx, {

	// anim: Function
	//	Alias of `dojo.anim` - the shorthand `dojo.animateProperty` with auto-play
	anim: dojo.anim,

	// animateProperty: Function
	//	Alias of `dojo.animateProperty` - animate any CSS property
	animateProperty: dojo.animateProperty,

	// fadeTo: Function 
	//		Fade an element from an opacity to an opacity.
	//		Omit `start:` property to detect. `end:` property is required.
	//		Ultimately an alias to `dojo._fade`
	fadeTo: dojo._fade,

	// fadeIn: Function
	//	Alias of `dojo.fadeIn` - Fade a node in.
	fadeIn: dojo.fadeIn,
	
	// fadeOut: Function
	//	Alias of `dojo.fadeOut` - Fades a node out.
	fadeOut: dojo.fadeOut,

	// combine: Function
	//	Alias of `dojo.fx.combine` - Run an array of animations in parallel
	combine: dojo.fx.combine,

	// chain: Function
	//	Alias of `dojo.fx.chain` - Run an array of animations in sequence
	chain: dojo.fx.chain,

	// slideTo: Function
	//	Alias of `dojo.fx.slideTo` - Slide a node to a defined top/left coordinate
	slideTo: dojo.fx.slideTo,

	// wipeIn: Function
	//	Alias of `dojo.fx.wipeIn` - Wipe a node to visible
	wipeIn: dojo.fx.wipeIn,

	// wipeOut: Function
	//	Alias of `dojo.fx.wipeOut` - Wipe a node to non-visible
	wipeOut: dojo.fx.wipeOut

});

dojox.fx.sizeTo = function(/* Object */args){
	// summary: 
	//		Creates an animation that will size a node
	//
	// description:
	//		Returns an animation that will size the target node
	//		defined in args Object about it's center to
	//		a width and height defined by (args.width, args.height), 
	//		supporting an optional method: chain||combine mixin
	//		(defaults to chain).	
	//
	//	- works best on absolutely or relatively positioned elements
	//	
	// example:
	//	|	// size #myNode to 400px x 200px over 1 second
	//	|	dojo.fx.sizeTo({
	//	|		node:'myNode',
	//	|		duration: 1000,
	//	|		width: 400,
	//	|		height: 200,
	//	|		method: "combine"
	//	|	}).play();
	//

	var node = args.node = dojo.byId(args.node),
		abs = "absolute";

	var method = args.method || "chain"; 
	if(!args.duration){ args.duration = 500; } // default duration needed
	if(method == "chain"){ args.duration = Math.floor(args.duration / 2); } 
	
	var top, newTop, left, newLeft, width, height = null;

	var init = (function(n){
		return function(){
			var cs = dojo.getComputedStyle(n),
				pos = cs.position,
				w = cs.width,
				h = cs.height
			;
			
			top = (pos == abs ? n.offsetTop : parseInt(cs.top) || 0);
			left = (pos == abs ? n.offsetLeft : parseInt(cs.left) || 0);
			width = (w == "auto" ? 0 : parseInt(w));
			height = (h == "auto" ? 0 : parseInt(h));
			
			newLeft = left - Math.floor((args.width - width) / 2); 
			newTop = top - Math.floor((args.height - height) / 2); 

			if(pos != abs && pos != 'relative'){
				var ret = dojo.coords(n, true);
				top = ret.y;
				left = ret.x;
				n.style.position = abs;
				n.style.top = top + "px";
				n.style.left = left + "px";
			}
		}
	})(node);

	var anim1 = dojo.animateProperty(dojo.mixin({
		properties: {
			height: function(){
				init();
				return { end: args.height || 0, start: height };
			},
			top: function(){
				return { start: top, end: newTop };
			}
		}
	}, args));
	var anim2 = dojo.animateProperty(dojo.mixin({
		properties: {
			width: function(){
				return { start: width, end: args.width || 0 }
			},
			left: function(){
				return { start: left, end: newLeft }
			}
		}
	}, args));

	var anim = dojo.fx[(args.method == "combine" ? "combine" : "chain")]([anim1, anim2]);
	return anim; // dojo.Animation

};

dojox.fx.slideBy = function(/* Object */args){
	// summary: 
	//		Returns an animation to slide a node by a defined offset.
	//
	// description:
	//		Returns an animation that will slide a node (args.node) from it's
	//		current position to it's current posision plus the numbers defined
	//		in args.top and args.left. standard dojo.fx mixin's apply. 
	//	
	// example:
	//	|	// slide domNode 50px down, and 22px left
	//	|	dojox.fx.slideBy({ 
	//	|		node: domNode, duration:400, 
	//	|		top: 50, left: -22 
	//	|	}).play();

	var node = args.node = dojo.byId(args.node),
		top, left;

	var init = (function(n){
		return function(){
			var cs = dojo.getComputedStyle(n);
			var pos = cs.position;
			top = (pos == 'absolute' ? n.offsetTop : parseInt(cs.top) || 0);
			left = (pos == 'absolute' ? n.offsetLeft : parseInt(cs.left) || 0);
			if(pos != 'absolute' && pos != 'relative'){
				var ret = dojo.coords(n, true);
				top = ret.y;
				left = ret.x;
				n.style.position = "absolute";
				n.style.top = top + "px";
				n.style.left = left + "px";
			}
		}
	})(node);
	init();
	
	var _anim = dojo.animateProperty(dojo.mixin({
		properties: {
			// FIXME: is there a way to update the _Line after creation?
			// null start values allow chaining to work, animateProperty will
			// determine them for us (except in ie6? -- ugh)
			top: top + (args.top || 0),
			left: left + (args.left || 0) 
		}
	}, args));
	dojo.connect(_anim, "beforeBegin", _anim, init);
	return _anim; // dojo.Animation
};

dojox.fx.crossFade = function(/* Object */args){
	// summary: 
	//		Returns an animation cross fading two element simultaneously
	// 
	// args:
	//	args.nodes: Array - two element array of domNodes, or id's
	//
	//	all other standard animation args mixins apply. args.node ignored.
	//

	// simple check for which node is visible, maybe too simple?
	var node1 = args.nodes[0] = dojo.byId(args.nodes[0]),
		op1 = dojo.style(node1,"opacity"),
		node2 = args.nodes[1] = dojo.byId(args.nodes[1]),
		op2 = dojo.style(node2, "opacity")
	;
	
	var _anim = dojo.fx.combine([
		dojo[(op1 == 0 ? "fadeIn" : "fadeOut")](dojo.mixin({
			node: node1
		},args)),
		dojo[(op1 == 0 ? "fadeOut" : "fadeIn")](dojo.mixin({
			node: node2
		},args))
	]);
	return _anim; // dojo.Animation
};

dojox.fx.highlight = function(/*Object*/ args){
	// summary: 
	//		Highlight a node
	//
	// description:
	//		Returns an animation that sets the node background to args.color
	//		then gradually fades back the original node background color
	//	
	// example:
	//	|	dojox.fx.highlight({ node:"foo" }).play(); 

	var node = args.node = dojo.byId(args.node);

	args.duration = args.duration || 400;
	
	// Assign default color light yellow
	var startColor = args.color || '#ffff99',
		endColor = dojo.style(node, "backgroundColor")
	;

	// safari "fix"
	// safari reports rgba(0, 0, 0, 0) (black) as transparent color, while
	// other browsers return "transparent", rendered as white by default by
	// dojo.Color; now dojo.Color maps "transparent" to
	// djConfig.transparentColor ([r, g, b]), if present; so we can use
	// the color behind the effect node
	if(endColor == "rgba(0, 0, 0, 0)"){
		endColor = "transparent";
	}

	var anim = dojo.animateProperty(dojo.mixin({
		properties: {
			backgroundColor: { start: startColor, end: endColor }
		}
	}, args));

	if(endColor == "transparent"){
		dojo.connect(anim, "onEnd", anim, function(){
			node.style.backgroundColor = endColor;
		});
	}

	return anim; // dojo.Animation
};

 
dojox.fx.wipeTo = function(/*Object*/ args){
	// summary:
	//		Animate a node wiping to a specific width or height
	//	
	// description:
	//		Returns an animation that will expand the
	//		node defined in 'args' object from it's current to
	//		the height or width value given by the args object.
	//
	//		default to height:, so leave height null and specify width:
	//		to wipeTo a width. note: this may be deprecated by a 
	//
	//		Note that the final value should not include
	//		units and should be an integer.  Thus a valid args object
	//		would look something like this:
	//
	//		|	dojox.fx.wipeTo({ node: "nodeId", height: 200 }).play();
	//
	//		Node must have no margin/border/padding, so put another
	//		node inside your target node for additional styling.

	args.node = dojo.byId(args.node);
	var node = args.node, s = node.style;

	var dir = (args.width ? "width" : "height"),
		endVal = args[dir],
		props = {}
	;

	props[dir] = {
		// wrapped in functions so we wait till the last second to query (in case value has changed)
		start: function(){
			// start at current [computed] height, but use 1px rather than 0
			// because 0 causes IE to display the whole panel
			s.overflow = "hidden";
			if(s.visibility == "hidden" || s.display == "none"){
				s[dir] = "1px";
				s.display = "";
				s.visibility = "";
				return 1;
			}else{
				var now = dojo.style(node,dir);
				return Math.max(now, 1);
			}
		},
		end: endVal
	};

	var anim = dojo.animateProperty(dojo.mixin({ properties: props }, args));
	return anim; // dojo.Animation
};

}

if(!dojo._hasResource["dojox.fx"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.fx"] = true;
dojo.provide("dojox.fx");

 

}

if(!dojo._hasResource['com.sixnet.services.widgets.sixnetLogger']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.sixnetLogger'] = true;
dojo.provide('com.sixnet.services.widgets.sixnetLogger');
//







/*
 * in this widget's template we have style for the <p> tags and 
 * one initial <p></p> that is used to addContent-before for each new 
 * event.
 * 
 */

dojo.declare('com.sixnet.services.widgets.sixnetLogger', [dijit._Widget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<style>\n\tloggerText p{\n\t\tfont-weight: bold;\n\t\tcolor: white;\n\t\tborder-bottom: 1px solid #999;\n\t\tbackground:transparent;\n\t}\n\t</style>\n\n\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"loggerMain\" style=\"position:fixed; bottom:22px; display:none; border:solid #000; border-width:thin; border-bottom: none; border-right:none; right:0; z-index:200; width:400px; height:0; background-image:url('dojo/com/sixnet/services/widgets/templates/images/logger.png');  opacity:0; filter:alpha(opacity=0);\">\n\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachEvent=\"onClick:onLoggerPinClick\" dojoAttachPoint=\"loggerPin\" style=\"position:relative; color:red; float:left; margin-left:2px; margin-top:2px; text-align: center; clear:none; height:15px; width:15px; \"><img src=\"dojo/com/sixnet/services/widgets/templates/images/thumbtack_up.png\" /></div>\n\t\t\n\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"loggerText\" style=\"padding:5px; padding-left:10px; font:'Verdana'; color:red; overflow-y:scroll; height:80px;\">\n\t\t\t\t\n\t\t<p style=\"border:none\"></p>\n\t\t</div>\n\t</div>\n</div>\n",
	edit: false,
	pinned: false,
	infoCount: 0,
	anims: [],
	haltAnimations: false,
	mouseEnter: false,
	mouseLeave: false,
	currentAnimation:{},
	ani:0,
	timer:0,
	postCreate: function(){
		this.inherited("postCreate", arguments);
//		this.connect(this.pinButton, "onclick", "pinLogger");
//		var theLogger = this;
		dojo.connect(this.loggerMain, "onMouseEnter", this,
				function(){
					//  if we do this once, don't repeat.
					_sixnet_framework.log(1, this);
					clearTimeout(this.timer);
					var currentOpacity = dojo.style(this.loggerMain.domNode, "opacity");
					if(currentOpacity > 0){
						dojo.style(this.loggerMain.domNode, "height", "90");
						dojo.style(this.loggerMain.domNode, "opacity", ".7");
					}
					//clearTimeout(this.ani);
				}
		);
		dojo.connect(this.loggerMain, "onMouseLeave", this,
				function(){
					//  if we do this once, don't repeat.
					var currentOpacity = dojo.style(this.loggerMain.domNode, "opacity");
					if(this.pinned == false && currentOpacity > 0){
						this.timer = setTimeout(dojo.hitch(this, "fadeAway"), 5000);
					}
				}
		);
	},

	/* ============== sixnetLogger functions [a-z] ================ */
	onLoggerPinClick: function(){
		if(this.pinned == false){
			clearTimeout(this.timer);
			clearTimeout(this.ani);
			this.pinned = true;
			dojo.attr(this.loggerPin, 'innerHTML','<img src="dojo/com/sixnet/services/widgets/templates/images/thumbtack_side.png" />');
			dojo.style(this.loggerMain.domNode, "height", "90");
			dojo.style(this.loggerMain.domNode, "opacity", ".7");
		}else{
			this.pinned = false;
			dojo.attr(this.loggerPin, 'innerHTML', '<img src="dojo/com/sixnet/services/widgets/templates/images/thumbtack_up.png" />');
			this.timer = setTimeout(dojo.hitch(this, "fadeAway"), 5000);
		}
	},
	
	checkPinned: function(){

	},

	event: function( eventWidget){
		//dojo.query("p:first-child", dojo.byId(this.loggerText).domNode).addContent('<p>I am new content!'.concat(this.infoCount).concat("</p>"), "before");
		eventWidget.placeAt(this.loggerText.domNode,"first");
		this.infoCount++;
		//  do animation/or not
		clearTimeout(this.timer);
		clearTimeout(this.ani);
		dojo.style(this.loggerMain.domNode, "display", "inline");
		dojo.style(this.loggerMain.domNode, "height", "90");
		dojo.style(this.loggerMain.domNode, "opacity", ".7");
		// replacing ani funky stuff with the below block (in if check)
		if(!this.pinned){
			// not pinned, set a timeout to go away
			this.timer = setTimeout(dojo.hitch(this, "fadeAway"), 5000);
		}
	},
	
	animateOpacity: function(){
		//var h = dojo.style(this.loggerMain.domNode, "height");
		var o = dojo.style(this.loggerMain.domNode, "opacity");
		if(o > 0){
			o -= 0.1;
			dojo.style(this.loggerMain.domNode, "opacity", o);
			this.ani = setTimeout(dojo.hitch(this,"animateOpacity"), 200);
		}else{
			dojo.style(this.loggerMain.domNode, "display", "none");
			_sixnet_framework.log(1, "ani eles", dojo.clone(this.ani));
			clearTimeout(this.ani);
		}
	},
	
	fadeAway: function(){
		_sixnet_framework.log(1, "fadeAway called", this);
		if(!this.pinned){
			this.animateOpacity();
		}
	},
	
	registerEvent: function(){
		
	}	
});

}

if(!dojo._hasResource['com.sixnet.services.widgets.sixnetLoggerPane']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.sixnetLoggerPane'] = true;
dojo.provide('com.sixnet.services.widgets.sixnetLoggerPane');




/*
 * in this widget's template we have style for the <p> tags and 
 * one initial <p></p> that is used to addContent-before for each new 
 * event.
 * 
 */

dojo.declare('com.sixnet.services.widgets.sixnetLoggerPane', [dijit._Widget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"contentPane\" >\n\t</div>\n</div>\n",
	content: '',
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.contentPane.setContent(this.content);
	}
	
	
});

}

if(!dojo._hasResource['com.sixnet.services.core.Framework']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.core.Framework'] = true;









dojo.provide('com.sixnet.services.core.Framework');
var _sixnet_framework_version = '2.0.0';

dojo.declare('com.sixnet.services.core.Framework', [dijit._Widget], {
	debug: false,
	polling: false,
	autoLogin: false,
	showLogger: false,
	bgColors: [],
	txtColors: [],
	sections: [],
	webEntry: 'services.php',
	_currentPermissions: {},
	_googleKey: '',
	_sessionToken: '',
	_super: false,
	_userId: '',
	_accountId: '',
	_loader: false,
	_logger: false,
	poller: false,	
	noCache: false,
	_workingCount: 0,
	_workingDialog: false,
	_sessionHandle: false,
	_heartbeatHandle: false,
	create:function(params){
		this.inherited("create", arguments);
		dojo.mixin(this, params);
		window._sixnet_framework = this;
	
		// REPLACE DOJO.REQUIRE if we are in noCache mode.  This allows us to RELOAD all widgets at run time even
		// if they are loaded once already.
		if( this.noCache){
			this._oldRequire = dojo['require'];
			var widgetCache = {};
			dojo['bumpCache'] = function(){
				var dateInfo = new Date();
				dojo.cacheBust = dateInfo.getTime();
				dojo.extend(); // call extend when empty to force the parser to reload stuff.
				widgetCache = {};
			};
			dojo['require'] = dojo.hitch(this, function(widgetName){
				try{
					if('undefined' == typeof(widgetCache[widgetName]) && widgetName.match(/com.sixnet.services/)){
						widgetCache[widgetName] = true;
						// busting only needed if the object is defined...
						var today = new Date();
						//dojo.config.cacheBust = today.getTime();
						var d = dojo;
						var classElements = widgetName.split('.');
						var moduleParentName = classElements.slice(0,classElements.length-1).join('.');
						var moduleParent = dojo.getObject(moduleParentName);
						delete moduleParent[classElements[classElements.length-1]];
						delete d._loadedModules[widgetName]; 
						var relpath = d._getModuleSymbols(widgetName).join("/") + '.js'; 
						var uri = ((relpath.charAt(0) == '/' || relpath.match(/^\w+:/)) ? "" : d.baseUrl) + relpath;
						delete d._loadedUrls[uri];
					}
				}catch(e){} // ok if there is an error.  Probably a class not previously loaded.
				this._oldRequire(widgetName);
			});
		}
		this._workingCount = 0;
		this._workingDialog = new com.sixnet.services.core.dashBoardDialog({duration: 1});
		this._workingDialog.setHref(dojo.moduleUrl('com.sixnet.services.core','templates/dashWorking.html'));
	
		this._loader = new com.sixnet.services.core.loader();	
		this._logger = new com.sixnet.services.widgets.sixnetLogger();
		this._logger.placeAt(dojo.body());
		this.poller = new com.sixnet.services.core.poller();
		this.connect( this._workingDialog, "onCancel", "onWorkingCancel");

	},
	getDash: function(){
		return this._loader.getDash();
	},
	resize: function(){
		//this._loader._dashBoard.resize();
	},
	onWorkingCancel: function(event){
		setTimeout(dojo.hitch(this, "showWorking"), 10);
	},
	startedWorking: function(){
		this._workingCount ++;
		this.showWorking();
	},
	stoppedWorking: function(){
		this._workingCount --;
		this.showWorking();
	},
	showWorking: function(){
		if( this._workingCount > 0){
			this._workingDialog.show();
		}else{
			this.log(1,"Hiding working when count is", this._workingCount);
			this._workingDialog.hide();
		}
	},
	
	alertColorCSS: function(){
		var bgColors = new Array();
		var txtColors = new Array();
		var sections = new Array();
		this.bc('access', 'getColorPreferences', {}, dojo.hitch(this, function(response){
			if( response.successful ){
				if(response.data.clrpref){
					//  if we have a clrpref, then apply it
					//  set this.update to true because we are going to update existing on Save
					this.update = true;
					var clrP = response.data.clrpref;
					for(var i=0; i<clrP.colors.length; i++){
						//  Here we fill color arrays w/ user specified colors
						bgColors.push(clrP.colors[i].background);
						txtColors.push(clrP.colors[i].color);
						sections.push(clrP.colors[i].section);
					}
					this.bgColors = bgColors;
					this.txtColors = txtColors;
					this.sections = sections;
					this.insertCSS();
				}else{
					//  we have a successful try, but no info - so, get default from sixnet_config
					this.bc('access', 'getSysConfigInfo', {name:'STATUS_COLORS', as_json:true}, dojo.hitch(this, function(response){
						if( response.successful ){
							if(response.data.value){
								//  we got STATUS_COLORS
								var clrP = response.data.value;
								for(var i=0; i<clrP.colors.length; i++){
									//  Here we fill color arrays w/ user specified colors
									bgColors.push(clrP.colors[i].background);
									txtColors.push(clrP.colors[i].color);
									sections.push(clrP.colors[i].section);
								}
								this.bgColors = bgColors;
								this.txtColors = txtColors;
								this.sections = sections;
								this.insertCSS();
							}
						}					
					}));
				}
			}else{
				this.log(1, response.error);
			}
		}));
	},
	
	insertCSS: function(){
		// build and insert CSS
		var style = '';
		for(var i=0; i<this.sections.length; i++){
//			style += '.'.concat(this.sections[i]).concat(' table{ background:').concat(this.bgColors[i]).concat('; color: ').concat(this.txtColors[i]).concat('; }');
			style += '.'.concat(this.sections[i]).concat('{ overflow:hidden; background:').concat(this.bgColors[i]).concat('; color: ').concat(this.txtColors[i]).concat('; width:100%; height:100%; }');
		}
		if( dojo.isIE){
			dojo.byId("alertColorCSS").styleSheet.cssText = style;
		}else{
			dojo.byId("alertColorCSS").innerHTML = style;
		}
	},
	
	getGoogleKey: function(){
		this.bc('access', 'getSysConfigInfo', {name: 'GOOGLE_KEYS', as_json:true}, dojo.hitch(this, function(response){
			if( response.successful ){
				//  we have the custom view, now setGridLayout
				//  find which has current ip as server
				if( null  == response.data.value){
					this.log(1,"No Map Keys Defined");
					return '';
				}
				var keys = response.data.value.keys;
				var currentHost = window.location.host;
				var currentKey = '';
				for(var i = 0; i < keys.length; i++){
					if(keys[i].server == currentHost){
						currentKey = keys[i].key;
					}
				}
				this._googleKey = currentKey;
			} else{
				this.log(1, response.error);
			}
		}));		
		
	},
	
	setSession: function(newSession){
		this._sessionToken = newSession;
	},
	
	setSuper: function(isSuper){
		this._super = isSuper;
	},
	
	setUserId: function(userId){
		this._userId = userId;
	},
	
	setAccount: function(accountId){
		this._accountId = accountId;
	},
	
	log: function(){
		var arglist = new Array();
		for(var i = 1; i < arguments.length; i++){
			arglist.push(arguments[i]);
		}
		var level = arguments[0];
		if(this.debug >= level){
			if(console.log.apply){
				console.log.apply(console, arglist);
			}
		}
	},
	
	alertError: function(){
		// on success == false
		
	},
	
	getUserRoles: function(){
		// ??? Roles ???
		this.bc('access', 'getUserRoles', {userId: this._userId }, dojo.hitch(this, function(response){
			if(response.successful){
				var obj = {};
				dojo.forEach(response.data, function(ur){
					if(!obj[ur.module]){
						obj[ur.module] = {};
					}
					obj[ur.module][ur.role] = ur;
				});
				this._currentPermissions = obj;
				this.log(1, "Current user ROLES:   ",dojo.toJson(obj, true));
			}
		})
		);
		
	},
	
	reloadDash: function(){
		// Load a new dash
		var widgetBase = new com.sixnet.services.core.dashWidgetBase({ dashBoard: null });
		widgetBase.resetWidgetCount();
		this.poller.unsubscribe(this._sessionHandle);
		this.poller.unsubscribe(this._sessionExpiredHandle);
		this.poller.unsubscribe(this._heartbeatHandle);
		// Decide if we are logged in, if we are enable polling.
		// If we are not, disable polling.
		this.bc('access', 'checkLogin', {}, dojo.hitch(this, function(response){
			if( response.data){
				// we are logged in start polling....
				this.poller.startPolling();
				this._sessionHandle = this.poller.subscribe('/system/session/warning', dojo.hitch(this, "sessionHandler"));
				this._sessionExpiredHandle = this.poller.subscribe('/system/session/expired', dojo.hitch(this, "sessionExpiredHandler"));
				this._heartbeatHandle = this.poller.subscribe('/system/heartbeat', dojo.hitch(this, "heartbeatHandler"));
			}else{
				// we are not logged in... end polling
				this.poller.stopPolling();
			}
		}));
		
		this._loader.discoverServices();
	},
	sessionHandler: function(eventName, payload){
		this._logger.event(new com.sixnet.services.widgets.sixnetLoggerPane({ content:'Your login will expire in : '.concat(payload.timeRemaining).concat(' seconds.')}));
	},
	sessionExpiredHandler: function(eventName, payload){
		this.log(1, 'Session expired.  Logging out.');
		this.setSession('');
		this.reloadDash();
	},
	heartbeatHandler: function(eventName, payload){
		this.log(1, '/system/heartbeat', payload);
	},
	bcSilent:function( moduleName, methodName, params, callback, errback, formNode, formHandler){
		return this.bc( moduleName, methodName, params, callback, errback, formNode, formHandler, true);
	},
	bc: function( moduleName, methodName, params, callback, errback, formNode, formHandler, silent){
		if('undefined' == typeof(silent)) silent = false;
		if( !silent) this.startedWorking();
		formNode = formNode?formNode:false;
		formHandler = dojo.isFunction(formHandler)?formHandler:false;
		params = dojo.isObject(params)?params:false;
		var postHandle = {}; // null post handle
		if( !formHandler){
			formHandler = dojo.hitch(this, function(response, ioArgs){
				if(response instanceof Error){
					this.log(1, "Request FAILED: ", response);
				}else{
					if(!response.successful){
							dojo.publish('/_sixnet_framework/close', [response.message]);
					}
				}
				ioResponse = response; // to get at afterwards in debugger.
			});
		}
		var buildCallStruct = {
			url: this.webEntry,
			handleAs:'json',
			sync: false
		};
		if( formNode){
			this.log(1, formNode.message);
			formNode.message.setAttribute("value", dojo.toJson({
				sessionToken: this._sessionToken,
				module: moduleName,
				method: methodName,
				parameters: params
			}));
			buildCallStruct.form = formNode;
			buildCallStruct.handle = formHandler;
			buildCallStruct.method = 'post';
			postHandle = dojo.io.iframe.send( buildCallStruct);
		}else{
			buildCallStruct.postData = dojo.toJson({
				sessionToken: this._sessionToken,
				module: moduleName,
				method: methodName,
				parameters: params
			});
			postHandle = dojo.rawXhrPost(buildCallStruct);
		}
		if(!formNode){
			postHandle.addCallback(dojo.hitch(this, function(response){
				if(!silent) this.stoppedWorking();
				return response;
			}));
			postHandle.addErrback(dojo.hitch(this, function(response){
				if(!silent) this.stoppedWorking();
				return response;
			}));
			if( !errback){
				postHandle.addErrback( dojo.hitch( this, function(error){
					if( error.message.match( /xhr cancelled/)) return;
					dojo.publish('/sixnet/shutdown', []); // shutdown all client operations.  return to login.
				}));
			}else{
				postHandle.addErrback(errback);
			}
			if( !callback){
				postHandle.addCallback( dojo.hitch( this, function(data){
					if( !data.successful){
						if( data.error.match( /You do not have permission to access/)){
							dojo.publish('/sixnet/errormessage', [data.error]);
							return ;
						}
					}
				}));
			}else{
				postHandle.addCallback(callback);
			}
		}
		
		return postHandle; 
	}
	
	
});


}

if(!dojo._hasResource["dijit._KeyNavContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._KeyNavContainer"] = true;
dojo.provide("dijit._KeyNavContainer");


dojo.declare("dijit._KeyNavContainer",
	dijit._Container,
	{

		// summary:
		//		A _Container with keyboard navigation of its children.
		// description:
		//		To use this mixin, call connectKeyNavHandlers() in
		//		postCreate() and call startupKeyNavChildren() in startup().
		//		It provides normalized keyboard and focusing code for Container
		//		widgets.
/*=====
		// focusedChild: [protected] Widget
		//		The currently focused child widget, or null if there isn't one
		focusedChild: null,
=====*/

		// tabIndex: Integer
		//		Tab index of the container; same as HTML tabIndex attribute.
		//		Note then when user tabs into the container, focus is immediately
		//		moved to the first item in the container.
		tabIndex: "0",

		_keyNavCodes: {},

		connectKeyNavHandlers: function(/*dojo.keys[]*/ prevKeyCodes, /*dojo.keys[]*/ nextKeyCodes){
			// summary:
			//		Call in postCreate() to attach the keyboard handlers
			//		to the container.
			// preKeyCodes: dojo.keys[]
			//		Key codes for navigating to the previous child.
			// nextKeyCodes: dojo.keys[]
			//		Key codes for navigating to the next child.
			// tags:
			//		protected

			var keyCodes = (this._keyNavCodes = {});
			var prev = dojo.hitch(this, this.focusPrev);
			var next = dojo.hitch(this, this.focusNext);
			dojo.forEach(prevKeyCodes, function(code){ keyCodes[code] = prev; });
			dojo.forEach(nextKeyCodes, function(code){ keyCodes[code] = next; });
			this.connect(this.domNode, "onkeypress", "_onContainerKeypress");
			this.connect(this.domNode, "onfocus", "_onContainerFocus");
		},

		startupKeyNavChildren: function(){
			// summary:
			//		Call in startup() to set child tabindexes to -1
			// tags:
			//		protected
			dojo.forEach(this.getChildren(), dojo.hitch(this, "_startupChild"));
		},

		addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){
			// summary:
			//		Add a child to our _Container
			dijit._KeyNavContainer.superclass.addChild.apply(this, arguments);
			this._startupChild(widget);
		},

		focus: function(){
			// summary:
			//		Default focus() implementation: focus the first child.
			this.focusFirstChild();
		},

		focusFirstChild: function(){
			// summary:
			//		Focus the first focusable child in the container.
			// tags:
			//		protected
			var child = this._getFirstFocusableChild();
			if(child){ // edge case: Menu could be empty or hidden
				this.focusChild(child);
			}
		},

		focusNext: function(){
			// summary:
			//		Focus the next widget
			// tags:
			//		protected
			var child = this._getNextFocusableChild(this.focusedChild, 1);
			this.focusChild(child);
		},

		focusPrev: function(){
			// summary:
			//		Focus the last focusable node in the previous widget
			//		(ex: go to the ComboButton icon section rather than button section)
			// tags:
			//		protected
			var child = this._getNextFocusableChild(this.focusedChild, -1);
			this.focusChild(child, true);
		},

		focusChild: function(/*dijit._Widget*/ widget, /*Boolean*/ last){
			// summary:
			//		Focus widget.
			// widget:
			//		Reference to container's child widget
			// last:
			//		If true and if widget has multiple focusable nodes, focus the
			//		last one instead of the first one
			// tags:
			//		protected
			
			if(this.focusedChild && widget !== this.focusedChild){
				this._onChildBlur(this.focusedChild);
			}
			widget.focus(last ? "end" : "start");
			this.focusedChild = widget;
		},

		_startupChild: function(/*dijit._Widget*/ widget){
			// summary:
			//		Setup for each child widget
			// description:
			//		Sets tabIndex=-1 on each child, so that the tab key will 
			//		leave the container rather than visiting each child.
			// tags:
			//		private
			
			widget.set("tabIndex", "-1");
			
			this.connect(widget, "_onFocus", function(){
				// Set valid tabIndex so tabbing away from widget goes to right place, see #10272
				widget.set("tabIndex", this.tabIndex);
			});
			this.connect(widget, "_onBlur", function(){
				widget.set("tabIndex", "-1");
			});
		},

		_onContainerFocus: function(evt){
			// summary:
			//		Handler for when the container gets focus
			// description:
			//		Initially the container itself has a tabIndex, but when it gets
			//		focus, switch focus to first child...
			// tags:
			//		private

			// Note that we can't use _onFocus() because switching focus from the
			// _onFocus() handler confuses the focus.js code
			// (because it causes _onFocusNode() to be called recursively)

			// focus bubbles on Firefox,
			// so just make sure that focus has really gone to the container
			if(evt.target !== this.domNode){ return; }

			this.focusFirstChild();

			// and then set the container's tabIndex to -1,
			// (don't remove as that breaks Safari 4)
			// so that tab or shift-tab will go to the fields after/before
			// the container, rather than the container itself
			dojo.attr(this.domNode, "tabIndex", "-1");
		},

		_onBlur: function(evt){
			// When focus is moved away the container, and its descendant (popup) widgets,
			// then restore the container's tabIndex so that user can tab to it again.
			// Note that using _onBlur() so that this doesn't happen when focus is shifted
			// to one of my child widgets (typically a popup)
			if(this.tabIndex){
				dojo.attr(this.domNode, "tabIndex", this.tabIndex);
			}
			this.inherited(arguments);
		},

		_onContainerKeypress: function(evt){
			// summary:
			//		When a key is pressed, if it's an arrow key etc. then
			//		it's handled here.
			// tags:
			//		private
			if(evt.ctrlKey || evt.altKey){ return; }
			var func = this._keyNavCodes[evt.charOrCode];
			if(func){
				func();
				dojo.stopEvent(evt);
			}
		},

		_onChildBlur: function(/*dijit._Widget*/ widget){
			// summary:
			//		Called when focus leaves a child widget to go
			//		to a sibling widget.
			// tags:
			//		protected
		},

		_getFirstFocusableChild: function(){
			// summary:
			//		Returns first child that can be focused
			return this._getNextFocusableChild(null, 1);	// dijit._Widget
		},

		_getNextFocusableChild: function(child, dir){
			// summary:
			//		Returns the next or previous focusable child, compared
			//		to "child"
			// child: Widget
			//		The current widget
			// dir: Integer
			//		* 1 = after
			//		* -1 = before
			if(child){
				child = this._getSiblingOfChild(child, dir);
			}
			var children = this.getChildren();
			for(var i=0; i < children.length; i++){
				if(!child){
					child = children[(dir>0) ? 0 : (children.length-1)];
				}
				if(child.isFocusable()){
					return child;	// dijit._Widget
				}
				child = this._getSiblingOfChild(child, dir);
			}
			// no focusable child found
			return null;	// dijit._Widget
		}
	}
);

}

if(!dojo._hasResource["dijit.MenuItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.MenuItem"] = true;
dojo.provide("dijit.MenuItem");






dojo.declare("dijit.MenuItem",
		[dijit._Widget, dijit._Templated, dijit._Contained, dijit._CssStateMixin],
		{
		// summary:
		//		A line item in a Menu Widget

		// Make 3 columns
		// icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
		templateString: dojo.cache("dijit", "templates/MenuItem.html", "<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" waiRole=\"menuitem\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" waiRole=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon dijitMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" waiRole=\"presentation\">\n\t\t<div dojoAttachPoint=\"arrowWrapper\" style=\"visibility: hidden\">\n\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuExpand\"/>\n\t\t\t<span class=\"dijitMenuExpandA11y\">+</span>\n\t\t</div>\n\t</td>\n</tr>\n"),

		attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
			label: { node: "containerNode", type: "innerHTML" },
			iconClass: { node: "iconNode", type: "class" }
		}),

		baseClass: "dijitMenuItem",

		// label: String
		//		Menu text
		label: '',

		// iconClass: String
		//		Class to apply to DOMNode to make it display an icon.
		iconClass: "",

		// accelKey: String
		//		Text for the accelerator (shortcut) key combination.
		//		Note that although Menu can display accelerator keys there
		//		is no infrastructure to actually catch and execute these
		//		accelerators.
		accelKey: "",

		// disabled: Boolean
		//		If true, the menu item is disabled.
		//		If false, the menu item is enabled.
		disabled: false,

		_fillContent: function(/*DomNode*/ source){
			// If button label is specified as srcNodeRef.innerHTML rather than
			// this.params.label, handle it here.
			if(source && !("label" in this.params)){
				this.set('label', source.innerHTML);
			}
		},

		postCreate: function(){
			this.inherited(arguments);
			dojo.setSelectable(this.domNode, false);
			var label = this.id+"_text";
			dojo.attr(this.containerNode, "id", label);
			if(this.accelKeyNode){
				dojo.attr(this.accelKeyNode, "id", this.id + "_accel");
				label += " " + this.id + "_accel";
			}
			dijit.setWaiState(this.domNode, "labelledby", label);
		},

		_onHover: function(){
			// summary:
			//		Handler when mouse is moved onto menu item
			// tags:
			//		protected
			this.getParent().onItemHover(this);
		},

		_onUnhover: function(){
			// summary:
			//		Handler when mouse is moved off of menu item,
			//		possibly to a child menu, or maybe to a sibling
			//		menuitem or somewhere else entirely.
			// tags:
			//		protected

			// if we are unhovering the currently selected item
			// then unselect it
			this.getParent().onItemUnhover(this);

			// _onUnhover() is called when the menu is hidden (collapsed), due to clicking
			// a MenuItem and having it execut.  When that happens, FF and IE don't generate
			// an onmouseout event for the MenuItem, so give _CssStateMixin some help
			this._hovering = false;
			this._setStateClass();
		},

		_onClick: function(evt){
			// summary:
			//		Internal handler for click events on MenuItem.
			// tags:
			//		private
			this.getParent().onItemClick(this, evt);
			dojo.stopEvent(evt);
		},

		onClick: function(/*Event*/ evt){
			// summary:
			//		User defined function to handle clicks
			// tags:
			//		callback
		},

		focus: function(){
			// summary:
			//		Focus on this MenuItem
			try{
				if(dojo.isIE == 8){
					// needed for IE8 which won't scroll TR tags into view on focus yet calling scrollIntoView creates flicker (#10275)
					this.containerNode.focus();
				}
				dijit.focus(this.focusNode);
			}catch(e){
				// this throws on IE (at least) in some scenarios
			}
		},

		_onFocus: function(){
			// summary:
			//		This is called by the focus manager when focus
			//		goes to this MenuItem or a child menu.
			// tags:
			//		protected
			this._setSelected(true);
			this.getParent()._onItemFocus(this);

			this.inherited(arguments);
		},

		_setSelected: function(selected){
			// summary:
			//		Indicate that this node is the currently selected one
			// tags:
			//		private

			/***
			 * TODO: remove this method and calls to it, when _onBlur() is working for MenuItem.
			 * Currently _onBlur() gets called when focus is moved from the MenuItem to a child menu.
			 * That's not supposed to happen, but the problem is:
			 * In order to allow dijit.popup's getTopPopup() to work,a sub menu's popupParent
			 * points to the parent Menu, bypassing the parent MenuItem... thus the
			 * MenuItem is not in the chain of active widgets and gets a premature call to
			 * _onBlur()
			 */

			dojo.toggleClass(this.domNode, "dijitMenuItemSelected", selected);
		},

		setLabel: function(/*String*/ content){
			// summary:
			//		Deprecated.   Use set('label', ...) instead.
			// tags:
			//		deprecated
			dojo.deprecated("dijit.MenuItem.setLabel() is deprecated.  Use set('label', ...) instead.", "", "2.0");
			this.set("label", content);
		},

		setDisabled: function(/*Boolean*/ disabled){
			// summary:
			//		Deprecated.   Use set('disabled', bool) instead.
			// tags:
			//		deprecated
			dojo.deprecated("dijit.Menu.setDisabled() is deprecated.  Use set('disabled', bool) instead.", "", "2.0");
			this.set('disabled', disabled);
		},
		_setDisabledAttr: function(/*Boolean*/ value){
			// summary:
			//		Hook for attr('disabled', ...) to work.
			//		Enable or disable this menu item.
			this.disabled = value;
			dijit.setWaiState(this.focusNode, 'disabled', value ? 'true' : 'false');
		},
		_setAccelKeyAttr: function(/*String*/ value){
			// summary:
			//		Hook for attr('accelKey', ...) to work.
			//		Set accelKey on this menu item.
			this.accelKey=value;

			this.accelKeyNode.style.display=value?"":"none";
			this.accelKeyNode.innerHTML=value;
			//have to use colSpan to make it work in IE
			dojo.attr(this.containerNode,'colSpan',value?"1":"2");
		}
	});

}

if(!dojo._hasResource["dijit.PopupMenuItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.PopupMenuItem"] = true;
dojo.provide("dijit.PopupMenuItem");



dojo.declare("dijit.PopupMenuItem",
		dijit.MenuItem,
		{
		_fillContent: function(){
			// summary:
			//		When Menu is declared in markup, this code gets the menu label and
			//		the popup widget from the srcNodeRef.
			// description:
			//		srcNodeRefinnerHTML contains both the menu item text and a popup widget
			//		The first part holds the menu item text and the second part is the popup
			// example:
			// |	<div dojoType="dijit.PopupMenuItem">
			// |		<span>pick me</span>
			// |		<popup> ... </popup>
			// |	</div>
			// tags:
			//		protected

			if(this.srcNodeRef){
				var nodes = dojo.query("*", this.srcNodeRef);
				dijit.PopupMenuItem.superclass._fillContent.call(this, nodes[0]);

				// save pointer to srcNode so we can grab the drop down widget after it's instantiated
				this.dropDownContainer = this.srcNodeRef;
			}
		},

		startup: function(){
			if(this._started){ return; }
			this.inherited(arguments);

			// we didn't copy the dropdown widget from the this.srcNodeRef, so it's in no-man's
			// land now.  move it to dojo.doc.body.
			if(!this.popup){
				var node = dojo.query("[widgetId]", this.dropDownContainer)[0];
				this.popup = dijit.byNode(node);
			}
			dojo.body().appendChild(this.popup.domNode);
			this.popup.startup();

			this.popup.domNode.style.display="none";
			if(this.arrowWrapper){
				dojo.style(this.arrowWrapper, "visibility", "");
			}
			dijit.setWaiState(this.focusNode, "haspopup", "true");
		},

		destroyDescendants: function(){
			if(this.popup){
				// Destroy the popup, unless it's already been destroyed.  This can happen because
				// the popup is a direct child of <body> even though it's logically my child.
				if(!this.popup._destroyed){
					this.popup.destroyRecursive();
				}
				delete this.popup;
			}
			this.inherited(arguments);
		}
	});


}

if(!dojo._hasResource["dijit.CheckedMenuItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.CheckedMenuItem"] = true;
dojo.provide("dijit.CheckedMenuItem");



dojo.declare("dijit.CheckedMenuItem",
		dijit.MenuItem,
		{
		// summary:
		//		A checkbox-like menu item for toggling on and off

		templateString: dojo.cache("dijit", "templates/CheckedMenuItem.html", "<tr class=\"dijitReset dijitMenuItem\" dojoAttachPoint=\"focusNode\" waiRole=\"menuitemcheckbox\" tabIndex=\"-1\"\n\t\tdojoAttachEvent=\"onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick\">\n\t<td class=\"dijitReset dijitMenuItemIconCell\" waiRole=\"presentation\">\n\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitMenuItemIcon dijitCheckedMenuItemIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t<span class=\"dijitCheckedMenuItemIconChar\">&#10003;</span>\n\t</td>\n\t<td class=\"dijitReset dijitMenuItemLabel\" colspan=\"2\" dojoAttachPoint=\"containerNode,labelNode\"></td>\n\t<td class=\"dijitReset dijitMenuItemAccelKey\" style=\"display: none\" dojoAttachPoint=\"accelKeyNode\"></td>\n\t<td class=\"dijitReset dijitMenuArrowCell\" waiRole=\"presentation\">&nbsp;</td>\n</tr>\n"),

		// checked: Boolean
		//		Our checked state
		checked: false,
		_setCheckedAttr: function(/*Boolean*/ checked){
			// summary:
			//		Hook so attr('checked', bool) works.
			//		Sets the class and state for the check box.
			dojo.toggleClass(this.domNode, "dijitCheckedMenuItemChecked", checked);
			dijit.setWaiState(this.domNode, "checked", checked);
			this.checked = checked;
		},

		onChange: function(/*Boolean*/ checked){
			// summary:
			//		User defined function to handle check/uncheck events
			// tags:
			//		callback
		},

		_onClick: function(/*Event*/ e){
			// summary:
			//		Clicking this item just toggles its state
			// tags:
			//		private
			if(!this.disabled){
				this.set("checked", !this.checked);
				this.onChange(this.checked);
			}
			this.inherited(arguments);
		}
	});

}

if(!dojo._hasResource["dijit.MenuSeparator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.MenuSeparator"] = true;
dojo.provide("dijit.MenuSeparator");





dojo.declare("dijit.MenuSeparator",
		[dijit._Widget, dijit._Templated, dijit._Contained],
		{
		// summary:
		//		A line between two menu items

		templateString: dojo.cache("dijit", "templates/MenuSeparator.html", "<tr class=\"dijitMenuSeparator\">\n\t<td class=\"dijitMenuSeparatorIconCell\">\n\t\t<div class=\"dijitMenuSeparatorTop\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n\t<td colspan=\"3\" class=\"dijitMenuSeparatorLabelCell\">\n\t\t<div class=\"dijitMenuSeparatorTop dijitMenuSeparatorLabel\"></div>\n\t\t<div class=\"dijitMenuSeparatorBottom\"></div>\n\t</td>\n</tr>\n"),

		postCreate: function(){
			dojo.setSelectable(this.domNode, false);
		},

		isFocusable: function(){
			// summary:
			//		Override to always return false
			// tags:
			//		protected

			return false; // Boolean
		}
	});


}

if(!dojo._hasResource["dijit.Menu"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Menu"] = true;
dojo.provide("dijit.Menu");







dojo.declare("dijit._MenuBase",
	[dijit._Widget, dijit._Templated, dijit._KeyNavContainer],
{
	// summary:
	//		Base class for Menu and MenuBar

	// parentMenu: [readonly] Widget
	//		pointer to menu that displayed me
	parentMenu: null,

	// popupDelay: Integer
	//		number of milliseconds before hovering (without clicking) causes the popup to automatically open.
	popupDelay: 500,

	startup: function(){
		if(this._started){ return; }

		dojo.forEach(this.getChildren(), function(child){ child.startup(); });
		this.startupKeyNavChildren();

		this.inherited(arguments);
	},

	onExecute: function(){
		// summary:
		//		Attach point for notification about when a menu item has been executed.
		//		This is an internal mechanism used for Menus to signal to their parent to
		//		close them, because they are about to execute the onClick handler.   In
		//		general developers should not attach to or override this method.
		// tags:
		//		protected
	},

	onCancel: function(/*Boolean*/ closeAll){
		// summary:
		//		Attach point for notification about when the user cancels the current menu
		//		This is an internal mechanism used for Menus to signal to their parent to
		//		close them.  In general developers should not attach to or override this method.
		// tags:
		//		protected
	},

	_moveToPopup: function(/*Event*/ evt){
		// summary:
		//		This handles the right arrow key (left arrow key on RTL systems),
		//		which will either open a submenu, or move to the next item in the
		//		ancestor MenuBar
		// tags:
		//		private

		if(this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled){
			this.focusedChild._onClick(evt);
		}else{
			var topMenu = this._getTopMenu();
			if(topMenu && topMenu._isMenuBar){
				topMenu.focusNext();
			}
		}
	},

	_onPopupHover: function(/*Event*/ evt){
		// summary:
		//		This handler is called when the mouse moves over the popup.
		// tags:
		//		private

		// if the mouse hovers over a menu popup that is in pending-close state,
		// then stop the close operation.
		// This can't be done in onItemHover since some popup targets don't have MenuItems (e.g. ColorPicker)
		if(this.currentPopup && this.currentPopup._pendingClose_timer){
			var parentMenu = this.currentPopup.parentMenu;
			// highlight the parent menu item pointing to this popup
			if(parentMenu.focusedChild){
				parentMenu.focusedChild._setSelected(false);
			}
			parentMenu.focusedChild = this.currentPopup.from_item;
			parentMenu.focusedChild._setSelected(true);
			// cancel the pending close
			this._stopPendingCloseTimer(this.currentPopup);
		}
	},

	onItemHover: function(/*MenuItem*/ item){
		// summary:
		//		Called when cursor is over a MenuItem.
		// tags:
		//		protected

		// Don't do anything unless user has "activated" the menu by:
		//		1) clicking it
		//		2) opening it from a parent menu (which automatically focuses it)
		if(this.isActive){
			this.focusChild(item);
			if(this.focusedChild.popup && !this.focusedChild.disabled && !this.hover_timer){
				this.hover_timer = setTimeout(dojo.hitch(this, "_openPopup"), this.popupDelay);
			}
		}
		// if the user is mixing mouse and keyboard navigation,
		// then the menu may not be active but a menu item has focus,
		// but it's not the item that the mouse just hovered over.
		// To avoid both keyboard and mouse selections, use the latest.
		if(this.focusedChild){
			this.focusChild(item);
		}
		this._hoveredChild = item;
	},

	_onChildBlur: function(item){
		// summary:
		//		Called when a child MenuItem becomes inactive because focus
		//		has been removed from the MenuItem *and* it's descendant menus.
		// tags:
		//		private
		this._stopPopupTimer();
		item._setSelected(false);
		// Close all popups that are open and descendants of this menu
		var itemPopup = item.popup;
		if(itemPopup){
			this._stopPendingCloseTimer(itemPopup);
			itemPopup._pendingClose_timer = setTimeout(function(){
				itemPopup._pendingClose_timer = null;
				if(itemPopup.parentMenu){
					itemPopup.parentMenu.currentPopup = null;
				}
				dijit.popup.close(itemPopup); // this calls onClose
			}, this.popupDelay);
		}
	},

	onItemUnhover: function(/*MenuItem*/ item){
		// summary:
		//		Callback fires when mouse exits a MenuItem
		// tags:
		//		protected

		if(this.isActive){
			this._stopPopupTimer();
		}
		if(this._hoveredChild == item){ this._hoveredChild = null; }
	},

	_stopPopupTimer: function(){
		// summary:
		//		Cancels the popup timer because the user has stop hovering
		//		on the MenuItem, etc.
		// tags:
		//		private
		if(this.hover_timer){
			clearTimeout(this.hover_timer);
			this.hover_timer = null;
		}
	},

	_stopPendingCloseTimer: function(/*dijit._Widget*/ popup){
		// summary:
		//		Cancels the pending-close timer because the close has been preempted
		// tags:
		//		private
		if(popup._pendingClose_timer){
			clearTimeout(popup._pendingClose_timer);
			popup._pendingClose_timer = null;
		}
	},

	_stopFocusTimer: function(){
		// summary:
		//		Cancels the pending-focus timer because the menu was closed before focus occured
		// tags:
		//		private
		if(this._focus_timer){
			clearTimeout(this._focus_timer);
			this._focus_timer = null;
		}
	},

	_getTopMenu: function(){
		// summary:
		//		Returns the top menu in this chain of Menus
		// tags:
		//		private
		for(var top=this; top.parentMenu; top=top.parentMenu);
		return top;
	},

	onItemClick: function(/*dijit._Widget*/ item, /*Event*/ evt){
		// summary:
		//		Handle clicks on an item.
		// tags:
		//		private

		// this can't be done in _onFocus since the _onFocus events occurs asynchronously
		if(typeof this.isShowingNow == 'undefined'){ // non-popup menu
			this._markActive();
		}

		this.focusChild(item);

		if(item.disabled){ return false; }

		if(item.popup){
			this._openPopup();
		}else{
			// before calling user defined handler, close hierarchy of menus
			// and restore focus to place it was when menu was opened
			this.onExecute();

			// user defined handler for click
			item.onClick(evt);
		}
	},

	_openPopup: function(){
		// summary:
		//		Open the popup to the side of/underneath the current menu item
		// tags:
		//		protected

		this._stopPopupTimer();
		var from_item = this.focusedChild;
		if(!from_item){ return; } // the focused child lost focus since the timer was started
		var popup = from_item.popup;
		if(popup.isShowingNow){ return; }
		if(this.currentPopup){
			this._stopPendingCloseTimer(this.currentPopup);
			dijit.popup.close(this.currentPopup);
		}
		popup.parentMenu = this;
		popup.from_item = from_item; // helps finding the parent item that should be focused for this popup
		var self = this;
		dijit.popup.open({
			parent: this,
			popup: popup,
			around: from_item.domNode,
			orient: this._orient || (this.isLeftToRight() ?
									{'TR': 'TL', 'TL': 'TR', 'BR': 'BL', 'BL': 'BR'} :
									{'TL': 'TR', 'TR': 'TL', 'BL': 'BR', 'BR': 'BL'}),
			onCancel: function(){ // called when the child menu is canceled
				// set isActive=false (_closeChild vs _cleanUp) so that subsequent hovering will NOT open child menus
				// which seems aligned with the UX of most applications (e.g. notepad, wordpad, paint shop pro)
				self.focusChild(from_item);	// put focus back on my node
				self._cleanUp();			// close the submenu (be sure this is done _after_ focus is moved)
				from_item._setSelected(true); // oops, _cleanUp() deselected the item
				self.focusedChild = from_item;	// and unset focusedChild
			},
			onExecute: dojo.hitch(this, "_cleanUp")
		});

		this.currentPopup = popup;
		// detect mouseovers to handle lazy mouse movements that temporarily focus other menu items
		popup.connect(popup.domNode, "onmouseenter", dojo.hitch(self, "_onPopupHover")); // cleaned up when the popped-up widget is destroyed on close

		if(popup.focus){
			// If user is opening the popup via keyboard (right arrow, or down arrow for MenuBar),
			// if the cursor happens to collide with the popup, it will generate an onmouseover event
			// even though the mouse wasn't moved.   Use a setTimeout() to call popup.focus so that
			// our focus() call overrides the onmouseover event, rather than vice-versa.  (#8742)
			popup._focus_timer = setTimeout(dojo.hitch(popup, function(){
				this._focus_timer = null;
				this.focus();
			}), 0);
		}
	},

	_markActive: function(){
		// summary:
		//              Mark this menu's state as active.
		//		Called when this Menu gets focus from:
		//			1) clicking it (mouse or via space/arrow key)
		//			2) being opened by a parent menu.
		//		This is not called just from mouse hover.
		//		Focusing a menu via TAB does NOT automatically set isActive
		//		since TAB is a navigation operation and not a selection one.
		//		For Windows apps, pressing the ALT key focuses the menubar
		//		menus (similar to TAB navigation) but the menu is not active
		//		(ie no dropdown) until an item is clicked.
		this.isActive = true;
		dojo.addClass(this.domNode, "dijitMenuActive");
		dojo.removeClass(this.domNode, "dijitMenuPassive");
	},

	onOpen: function(/*Event*/ e){
		// summary:
		//		Callback when this menu is opened.
		//		This is called by the popup manager as notification that the menu
		//		was opened.
		// tags:
		//		private

		this.isShowingNow = true;
		this._markActive();
	},

	_markInactive: function(){
		// summary:
		//		Mark this menu's state as inactive.
		this.isActive = false; // don't do this in _onBlur since the state is pending-close until we get here
		dojo.removeClass(this.domNode, "dijitMenuActive");
		dojo.addClass(this.domNode, "dijitMenuPassive");
	},

	onClose: function(){
		// summary:
		//		Callback when this menu is closed.
		//		This is called by the popup manager as notification that the menu
		//		was closed.
		// tags:
		//		private

		this._stopFocusTimer();
		this._markInactive();
		this.isShowingNow = false;
		this.parentMenu = null;
	},

	_closeChild: function(){
		// summary:
		//		Called when submenu is clicked or focus is lost.  Close hierarchy of menus.
		// tags:
		//		private
		this._stopPopupTimer();
		if(this.focusedChild){ // unhighlight the focused item
			this.focusedChild._setSelected(false);
			this.focusedChild._onUnhover();
			this.focusedChild = null;
		}
		if(this.currentPopup){
			// Close all popups that are open and descendants of this menu
			dijit.popup.close(this.currentPopup);
			this.currentPopup = null;
		}
	},

	_onItemFocus: function(/*MenuItem*/ item){
		// summary:
		//		Called when child of this Menu gets focus from:
		//			1) clicking it
		//			2) tabbing into it
		//			3) being opened by a parent menu.
		//		This is not called just from mouse hover.
		if(this._hoveredChild && this._hoveredChild != item){
			this._hoveredChild._onUnhover(); // any previous mouse movement is trumped by focus selection
		}
	},

	_onBlur: function(){
		// summary:
		//		Called when focus is moved away from this Menu and it's submenus.
		// tags:
		//		protected
		this._cleanUp();
		this.inherited(arguments);
	},

	_cleanUp: function(){
		// summary:
		//		Called when the user is done with this menu.  Closes hierarchy of menus.
		// tags:
		//		private

		this._closeChild(); // don't call this.onClose since that's incorrect for MenuBar's that never close
		if(typeof this.isShowingNow == 'undefined'){ // non-popup menu doesn't call onClose
			this._markInactive();
		}
	}
});

dojo.declare("dijit.Menu",
	dijit._MenuBase,
	{
	// summary
	//		A context menu you can assign to multiple elements

	// TODO: most of the code in here is just for context menu (right-click menu)
	// support.  In retrospect that should have been a separate class (dijit.ContextMenu).
	// Split them for 2.0

	constructor: function(){
		this._bindings = [];
	},

	templateString: dojo.cache("dijit", "templates/Menu.html", "<table class=\"dijit dijitMenu dijitMenuPassive dijitReset dijitMenuTable\" waiRole=\"menu\" tabIndex=\"${tabIndex}\" dojoAttachEvent=\"onkeypress:_onKeyPress\" cellspacing=0>\n\t<tbody class=\"dijitReset\" dojoAttachPoint=\"containerNode\"></tbody>\n</table>\n"),

	baseClass: "dijitMenu",

	// targetNodeIds: [const] String[]
	//		Array of dom node ids of nodes to attach to.
	//		Fill this with nodeIds upon widget creation and it becomes context menu for those nodes.
	targetNodeIds: [],

	// contextMenuForWindow: [const] Boolean
	//		If true, right clicking anywhere on the window will cause this context menu to open.
	//		If false, must specify targetNodeIds.
	contextMenuForWindow: false,

	// leftClickToOpen: [const] Boolean
	//		If true, menu will open on left click instead of right click, similiar to a file menu.
	leftClickToOpen: false,

	// refocus: Boolean
	// 		When this menu closes, re-focus the element which had focus before it was opened.
	refocus: true,

	postCreate: function(){
		if(this.contextMenuForWindow){
			this.bindDomNode(dojo.body());
		}else{
			// TODO: should have _setTargetNodeIds() method to handle initialization and a possible
			// later attr('targetNodeIds', ...) call.   There's also a problem that targetNodeIds[]
			// gets stale after calls to bindDomNode()/unBindDomNode() as it still is just the original list (see #9610)
			dojo.forEach(this.targetNodeIds, this.bindDomNode, this);
		}
		var k = dojo.keys, l = this.isLeftToRight();
		this._openSubMenuKey = l ? k.RIGHT_ARROW : k.LEFT_ARROW;
		this._closeSubMenuKey = l ? k.LEFT_ARROW : k.RIGHT_ARROW;
		this.connectKeyNavHandlers([k.UP_ARROW], [k.DOWN_ARROW]);
	},

	_onKeyPress: function(/*Event*/ evt){
		// summary:
		//		Handle keyboard based menu navigation.
		// tags:
		//		protected

		if(evt.ctrlKey || evt.altKey){ return; }

		switch(evt.charOrCode){
			case this._openSubMenuKey:
				this._moveToPopup(evt);
				dojo.stopEvent(evt);
				break;
			case this._closeSubMenuKey:
				if(this.parentMenu){
					if(this.parentMenu._isMenuBar){
						this.parentMenu.focusPrev();
					}else{
						this.onCancel(false);
					}
				}else{
					dojo.stopEvent(evt);
				}
				break;
		}
	},

	// thanks burstlib!
	_iframeContentWindow: function(/* HTMLIFrameElement */iframe_el){
		// summary:
		//		Returns the window reference of the passed iframe
		// tags:
		//		private
		var win = dojo.window.get(this._iframeContentDocument(iframe_el)) ||
			// Moz. TODO: is this available when defaultView isn't?
			this._iframeContentDocument(iframe_el)['__parent__'] ||
			(iframe_el.name && dojo.doc.frames[iframe_el.name]) || null;
		return win;	//	Window
	},

	_iframeContentDocument: function(/* HTMLIFrameElement */iframe_el){
		// summary:
		//		Returns a reference to the document object inside iframe_el
		// tags:
		//		protected
		var doc = iframe_el.contentDocument // W3
			|| (iframe_el.contentWindow && iframe_el.contentWindow.document) // IE
			|| (iframe_el.name && dojo.doc.frames[iframe_el.name] && dojo.doc.frames[iframe_el.name].document)
			|| null;
		return doc;	//	HTMLDocument
	},

	bindDomNode: function(/*String|DomNode*/ node){
		// summary:
		//		Attach menu to given node
		node = dojo.byId(node);

		var cn;	// Connect node

		// Support context menus on iframes.   Rather than binding to the iframe itself we need
		// to bind to the <body> node inside the iframe.
		if(node.tagName.toLowerCase() == "iframe"){
			var iframe = node,
				win = this._iframeContentWindow(iframe);
			cn = dojo.withGlobal(win, dojo.body);
		}else{
			
			// To capture these events at the top level, attach to <html>, not <body>.
			// Otherwise right-click context menu just doesn't work.
			cn = (node == dojo.body() ? dojo.doc.documentElement : node);
		}


		// "binding" is the object to track our connection to the node (ie, the parameter to bindDomNode())
		var binding = {
			node: node,
			iframe: iframe
		};

		// Save info about binding in _bindings[], and make node itself record index(+1) into
		// _bindings[] array.   Prefix w/_dijitMenu to avoid setting an attribute that may
		// start with a number, which fails on FF/safari.
		dojo.attr(node, "_dijitMenu" + this.id, this._bindings.push(binding));

		// Setup the connections to monitor click etc., unless we are connecting to an iframe which hasn't finished
		// loading yet, in which case we need to wait for the onload event first, and then connect
		// On linux Shift-F10 produces the oncontextmenu event, but on Windows it doesn't, so
		// we need to monitor keyboard events in addition to the oncontextmenu event.
		var doConnects = dojo.hitch(this, function(cn){
			return [
				// TODO: when leftClickToOpen is true then shouldn't space/enter key trigger the menu,
				// rather than shift-F10?
				dojo.connect(cn, this.leftClickToOpen ? "onclick" : "oncontextmenu", this, function(evt){
					// Schedule context menu to be opened unless it's already been scheduled from onkeydown handler
					dojo.stopEvent(evt);
					this._scheduleOpen(evt.target, iframe, {x: evt.pageX, y: evt.pageY});
				}),
				dojo.connect(cn, "onkeydown", this, function(evt){
					if(evt.shiftKey && evt.keyCode == dojo.keys.F10){
						dojo.stopEvent(evt);
						this._scheduleOpen(evt.target, iframe);	// no coords - open near target node
					}
				})
			];	
		});
		binding.connects = cn ? doConnects(cn) : [];

		if(iframe){
			// Setup handler to [re]bind to the iframe when the contents are initially loaded,
			// and every time the contents change.
			// Need to do this b/c we are actually binding to the iframe's <body> node.
			// Note: can't use dojo.connect(), see #9609.

			binding.onloadHandler = dojo.hitch(this, function(){
				// want to remove old connections, but IE throws exceptions when trying to
				// access the <body> node because it's already gone, or at least in a state of limbo

				var win = this._iframeContentWindow(iframe);
					cn = dojo.withGlobal(win, dojo.body);
				binding.connects = doConnects(cn);
			});
			if(iframe.addEventListener){
				iframe.addEventListener("load", binding.onloadHandler, false);
			}else{
				iframe.attachEvent("onload", binding.onloadHandler);
			}
		}
	},

	unBindDomNode: function(/*String|DomNode*/ nodeName){
		// summary:
		//		Detach menu from given node

		var node;
		try{
			node = dojo.byId(nodeName);
		}catch(e){
			// On IE the dojo.byId() call will get an exception if the attach point was
			// the <body> node of an <iframe> that has since been reloaded (and thus the
			// <body> node is in a limbo state of destruction.
			return;
		}

		// node["_dijitMenu" + this.id] contains index(+1) into my _bindings[] array
		var attrName = "_dijitMenu" + this.id;
		if(node && dojo.hasAttr(node, attrName)){
			var bid = dojo.attr(node, attrName)-1, b = this._bindings[bid];
			dojo.forEach(b.connects, dojo.disconnect);

			// Remove listener for iframe onload events
			var iframe = b.iframe;
			if(iframe){
				if(iframe.removeEventListener){
					iframe.removeEventListener("load", b.onloadHandler, false);
				}else{
					iframe.detachEvent("onload", b.onloadHandler);
				}
			}

			dojo.removeAttr(node, attrName);
			delete this._bindings[bid];
		}
	},

	_scheduleOpen: function(/*DomNode?*/ target, /*DomNode?*/ iframe, /*Object?*/ coords){
		// summary:
		//		Set timer to display myself.  Using a timer rather than displaying immediately solves
		//		two problems:
		//
		//		1. IE: without the delay, focus work in "open" causes the system
		//		context menu to appear in spite of stopEvent.
		//
		//		2. Avoid double-shows on linux, where shift-F10 generates an oncontextmenu event
		//		even after a dojo.stopEvent(e).  (Shift-F10 on windows doesn't generate the
		//		oncontextmenu event.)

		if(!this._openTimer){
			this._openTimer = setTimeout(dojo.hitch(this, function(){
				delete this._openTimer;
				this._openMyself({
					target: target,
					iframe: iframe,
					coords: coords
				});
			}), 1);
		}
	},

	_openMyself: function(args){
		// summary:
		//		Internal function for opening myself when the user does a right-click or something similar.
		// args:
		//		This is an Object containing:
		//		* target:
		//			The node that is being clicked
		//		* iframe:
		//			If an <iframe> is being clicked, iframe points to that iframe
		//		* coords:
		//			Put menu at specified x/y position in viewport, or if iframe is
		//			specified, then relative to iframe.
		//
		//		_openMyself() formerly took the event object, and since various code references
		//		evt.target (after connecting to _openMyself()), using an Object for parameters
		//		(so that old code still works).

		var target = args.target,
			iframe = args.iframe,
			coords = args.coords;

		// Get coordinates to open menu, either at specified (mouse) position or (if triggered via keyboard)
		// then near the node the menu is assigned to.
		if(coords){
			if(iframe){
				// Specified coordinates are on <body> node of an <iframe>, convert to match main document
				var od = target.ownerDocument,
					ifc = dojo.position(iframe, true),
					win = this._iframeContentWindow(iframe),
					scroll = dojo.withGlobal(win, "_docScroll", dojo);
	
				var cs = dojo.getComputedStyle(iframe),
					tp = dojo._toPixelValue,
					left = (dojo.isIE && dojo.isQuirks ? 0 : tp(iframe, cs.paddingLeft)) + (dojo.isIE && dojo.isQuirks ? tp(iframe, cs.borderLeftWidth) : 0),
					top = (dojo.isIE && dojo.isQuirks ? 0 : tp(iframe, cs.paddingTop)) + (dojo.isIE && dojo.isQuirks ? tp(iframe, cs.borderTopWidth) : 0);

				coords.x += ifc.x + left - scroll.x;
				coords.y += ifc.y + top - scroll.y;
			}
		}else{
			coords = dojo.position(target, true);
			coords.x += 10;
			coords.y += 10;
		}

		var self=this;
		var savedFocus = dijit.getFocus(this);
		function closeAndRestoreFocus(){
			// user has clicked on a menu or popup
			if(self.refocus){
				dijit.focus(savedFocus);
			}
			dijit.popup.close(self);
		}
		dijit.popup.open({
			popup: this,
			x: coords.x,
			y: coords.y,
			onExecute: closeAndRestoreFocus,
			onCancel: closeAndRestoreFocus,
			orient: this.isLeftToRight() ? 'L' : 'R'
		});
		this.focus();

		this._onBlur = function(){
			this.inherited('_onBlur', arguments);
			// Usually the parent closes the child widget but if this is a context
			// menu then there is no parent
			dijit.popup.close(this);
			// don't try to restore focus; user has clicked another part of the screen
			// and set focus there
		};
	},

	uninitialize: function(){
 		dojo.forEach(this._bindings, function(b){ if(b){ this.unBindDomNode(b.node); } }, this);
 		this.inherited(arguments);
	}
}
);

// Back-compat (TODO: remove in 2.0)






}

if(!dojo._hasResource["dojox.html.metrics"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.html.metrics"] = true;
dojo.provide("dojox.html.metrics");

(function(){
	var dhm = dojox.html.metrics;

	//	derived from Morris John's emResized measurer
	dhm.getFontMeasurements = function(){
		//	summary
		//	Returns an object that has pixel equivilents of standard font size values.
		var heights = {
			'1em':0, '1ex':0, '100%':0, '12pt':0, '16px':0, 'xx-small':0, 'x-small':0,
			'small':0, 'medium':0, 'large':0, 'x-large':0, 'xx-large':0
		};
	
		if(dojo.isIE){
			//	we do a font-size fix if and only if one isn't applied already.
			//	NOTE: If someone set the fontSize on the HTML Element, this will kill it.
			dojo.doc.documentElement.style.fontSize="100%";
		}
	
		//	set up the measuring node.
		var div=dojo.doc.createElement("div");
		var ds = div.style;
		ds.position="absolute";
		ds.left="-100px";
		ds.top="0";
		ds.width="30px";
		ds.height="1000em";
		ds.borderWidth="0";
		ds.margin="0";
		ds.padding="0";
		ds.outline="0";
		ds.lineHeight="1";
		ds.overflow="hidden";
		dojo.body().appendChild(div);
	
		//	do the measurements.
		for(var p in heights){
			ds.fontSize = p;
			heights[p] = Math.round(div.offsetHeight * 12/16) * 16/12 / 1000;
		}
		
		dojo.body().removeChild(div);
		div = null;
		return heights; 	//	object
	};

	var fontMeasurements = null;
	
	dhm.getCachedFontMeasurements = function(recalculate){
		if(recalculate || !fontMeasurements){
			fontMeasurements = dhm.getFontMeasurements();
		}
		return fontMeasurements;
	};

	var measuringNode = null, empty = {};
	dhm.getTextBox = function(/* String */ text, /* Object */ style, /* String? */ className){
		var m, s;
		if(!measuringNode){
			m = measuringNode = dojo.doc.createElement("div");
			// Container that we can set contraints on so that it doesn't
			// trigger a scrollbar.
			var c = dojo.doc.createElement("div"); 
			c.appendChild(m);
			s = c.style;
			s.overflow='scroll';
			s.position = "absolute";
			s.left = "0px";
			s.top = "-10000px";
			s.width = "1px";
			s.height = "1px";
			s.visibility = "hidden";
			s.borderWidth = "0";
			s.margin = "0";
			s.padding = "0";
			s.outline = "0";
			dojo.body().appendChild(c);
		}else{
			m = measuringNode;
		}
		// reset styles
		m.className = "";
		s = m.style;
		s.borderWidth = "0";
		s.margin = "0";
		s.padding = "0";
		s.outline = "0";
		// set new style
		if(arguments.length > 1 && style){
			for(var i in style){
				if(i in empty){ continue; }
				s[i] = style[i];
			}
		}
		// set classes
		if(arguments.length > 2 && className){
			m.className = className;
		}
		// take a measure
		m.innerHTML = text;
		var box = dojo.position(m);
		// position doesn't report right (reports 1, since parent is 1)
		// So we have to look at the scrollWidth to get the real width
		// Height is right.
		box.w = m.parentNode.scrollWidth;
		return box;
	};

	//	determine the scrollbar sizes on load.
	var scroll={ w:16, h:16 };
	dhm.getScrollbar=function(){ return { w:scroll.w, h:scroll.h }; };

	dhm._fontResizeNode = null;

	dhm.initOnFontResize = function(interval){
		var f = dhm._fontResizeNode = dojo.doc.createElement("iframe");
		var fs = f.style;
		fs.position = "absolute";
		fs.width = "5em";
		fs.height = "10em";
		fs.top = "-10000px";
		if(dojo.isIE){
			f.onreadystatechange = function(){
				if(f.contentWindow.document.readyState == "complete"){
					f.onresize = f.contentWindow.parent[dojox._scopeName].html.metrics._fontresize;
				}
			};
		}else{
			f.onload = function(){
				f.contentWindow.onresize = f.contentWindow.parent[dojox._scopeName].html.metrics._fontresize;
			};
		}
		//The script tag is to work around a known firebug race condition.  See comments in bug #9046
		f.setAttribute("src", "javascript:'<html><head><script>if(\"loadFirebugConsole\" in window){window.loadFirebugConsole();}</script></head><body></body></html>'");
		dojo.body().appendChild(f);
		dhm.initOnFontResize = function(){};
	};

	dhm.onFontResize = function(){};
	dhm._fontresize = function(){
		dhm.onFontResize();
	}

	dojo.addOnUnload(function(){
		// destroy our font resize iframe if we have one
		var f = dhm._fontResizeNode;
		if(f){
			if(dojo.isIE && f.onresize){
				f.onresize = null;
			}else if(f.contentWindow && f.contentWindow.onresize){
				f.contentWindow.onresize = null;
			}
			dhm._fontResizeNode = null;
		}
	});

	dojo.addOnLoad(function(){
		// getScrollbar metrics node
		try{
			var n=dojo.doc.createElement("div");
			n.style.cssText = "top:0;left:0;width:100px;height:100px;overflow:scroll;position:absolute;visibility:hidden;";
			dojo.body().appendChild(n);
			scroll.w = n.offsetWidth - n.clientWidth;
			scroll.h = n.offsetHeight - n.clientHeight;
			dojo.body().removeChild(n);
			//console.log("Scroll bar dimensions: ", scroll);
			delete n;
		}catch(e){}

		// text size poll setup
		if("fontSizeWatch" in dojo.config && !!dojo.config.fontSizeWatch){
			dhm.initOnFontResize();
		}
	});
})();

}

if(!dojo._hasResource["dojox.grid.util"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid.util"] = true;
dojo.provide("dojox.grid.util");

// summary: grid utility library
(function(){
	var dgu = dojox.grid.util;

	dgu.na = '...';
	dgu.rowIndexTag = "gridRowIndex";
	dgu.gridViewTag = "gridView";


	dgu.fire = function(ob, ev, args){
		var fn = ob && ev && ob[ev];
		return fn && (args ? fn.apply(ob, args) : ob[ev]());
	};
	
	dgu.setStyleHeightPx = function(inElement, inHeight){
		if(inHeight >= 0){
			var s = inElement.style;
			var v = inHeight + 'px';
			if(inElement && s['height'] != v){
				s['height'] = v;
			}
		}
	};
	
	dgu.mouseEvents = [ 'mouseover', 'mouseout', /*'mousemove',*/ 'mousedown', 'mouseup', 'click', 'dblclick', 'contextmenu' ];

	dgu.keyEvents = [ 'keyup', 'keydown', 'keypress' ];

	dgu.funnelEvents = function(inNode, inObject, inMethod, inEvents){
		var evts = (inEvents ? inEvents : dgu.mouseEvents.concat(dgu.keyEvents));
		for (var i=0, l=evts.length; i<l; i++){
			inObject.connect(inNode, 'on' + evts[i], inMethod);
		}
	};

	dgu.removeNode = function(inNode){
		inNode = dojo.byId(inNode);
		inNode && inNode.parentNode && inNode.parentNode.removeChild(inNode);
		return inNode;
	};
	
	dgu.arrayCompare = function(inA, inB){
		for(var i=0,l=inA.length; i<l; i++){
			if(inA[i] != inB[i]){return false;}
		}
		return (inA.length == inB.length);
	};
	
	dgu.arrayInsert = function(inArray, inIndex, inValue){
		if(inArray.length <= inIndex){
			inArray[inIndex] = inValue;
		}else{
			inArray.splice(inIndex, 0, inValue);
		}
	};
	
	dgu.arrayRemove = function(inArray, inIndex){
		inArray.splice(inIndex, 1);
	};
	
	dgu.arraySwap = function(inArray, inI, inJ){
		var cache = inArray[inI];
		inArray[inI] = inArray[inJ];
		inArray[inJ] = cache;
	};
})();

}

if(!dojo._hasResource["dojox.grid._Scroller"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid._Scroller"] = true;
dojo.provide("dojox.grid._Scroller");

(function(){
	var indexInParent = function(inNode){
		var i=0, n, p=inNode.parentNode;
		while((n = p.childNodes[i++])){
			if(n == inNode){
				return i - 1;
			}
		}
		return -1;
	};
	
	var cleanNode = function(inNode){
		if(!inNode){
			return;
		}
		var filter = function(inW){
			return inW.domNode && dojo.isDescendant(inW.domNode, inNode, true);
		};
		var ws = dijit.registry.filter(filter);
		for(var i=0, w; (w=ws[i]); i++){
			w.destroy();
		}
		delete ws;
	};

	var getTagName = function(inNodeOrId){
		var node = dojo.byId(inNodeOrId);
		return (node && node.tagName ? node.tagName.toLowerCase() : '');
	};
	
	var nodeKids = function(inNode, inTag){
		var result = [];
		var i=0, n;
		while((n = inNode.childNodes[i])){
			i++;
			if(getTagName(n) == inTag){
				result.push(n);
			}
		}
		return result;
	};
	
	var divkids = function(inNode){
		return nodeKids(inNode, 'div');
	};

	dojo.declare("dojox.grid._Scroller", null, {
		constructor: function(inContentNodes){
			this.setContentNodes(inContentNodes);
			this.pageHeights = [];
			this.pageNodes = [];
			this.stack = [];
		},
		// specified
		rowCount: 0, // total number of rows to manage
		defaultRowHeight: 32, // default height of a row
		keepRows: 100, // maximum number of rows that should exist at one time
		contentNode: null, // node to contain pages
		scrollboxNode: null, // node that controls scrolling
		// calculated
		defaultPageHeight: 0, // default height of a page
		keepPages: 10, // maximum number of pages that should exists at one time
		pageCount: 0,
		windowHeight: 0,
		firstVisibleRow: 0,
		lastVisibleRow: 0,
		averageRowHeight: 0, // the average height of a row
		// private
		page: 0,
		pageTop: 0,
		// init
		init: function(inRowCount, inKeepRows, inRowsPerPage){
			switch(arguments.length){
				case 3: this.rowsPerPage = inRowsPerPage;
				case 2: this.keepRows = inKeepRows;
				case 1: this.rowCount = inRowCount;
				default: break;
			}
			this.defaultPageHeight = this.defaultRowHeight * this.rowsPerPage;
			this.pageCount = this._getPageCount(this.rowCount, this.rowsPerPage);
			this.setKeepInfo(this.keepRows);
			this.invalidate();
			if(this.scrollboxNode){
				this.scrollboxNode.scrollTop = 0;
				this.scroll(0);
				this.scrollboxNode.onscroll = dojo.hitch(this, 'onscroll');
			}
		},
		_getPageCount: function(rowCount, rowsPerPage){
			return rowCount ? (Math.ceil(rowCount / rowsPerPage) || 1) : 0;
		},
		destroy: function(){
			this.invalidateNodes();
			delete this.contentNodes;
			delete this.contentNode;
			delete this.scrollboxNode;
		},
		setKeepInfo: function(inKeepRows){
			this.keepRows = inKeepRows;
			this.keepPages = !this.keepRows ? this.keepPages : Math.max(Math.ceil(this.keepRows / this.rowsPerPage), 2);
		},
		// nodes
		setContentNodes: function(inNodes){
			this.contentNodes = inNodes;
			this.colCount = (this.contentNodes ? this.contentNodes.length : 0);
			this.pageNodes = [];
			for(var i=0; i<this.colCount; i++){
				this.pageNodes[i] = [];
			}
		},
		getDefaultNodes: function(){
			return this.pageNodes[0] || [];
		},
		// updating
		invalidate: function(){
			this._invalidating = true;
			this.invalidateNodes();
			this.pageHeights = [];
			this.height = (this.pageCount ? (this.pageCount - 1)* this.defaultPageHeight + this.calcLastPageHeight() : 0);
			this.resize();
			this._invalidating = false;
		},
		updateRowCount: function(inRowCount){
			this.invalidateNodes();
			this.rowCount = inRowCount;
			// update page count, adjust document height
			var oldPageCount = this.pageCount;
			if(oldPageCount === 0){
				//We want to have at least 1px in height to keep scroller.  Otherwise with an
				//empty grid you can't scroll to see the header.
				this.height = 1;
			}
			this.pageCount = this._getPageCount(this.rowCount, this.rowsPerPage);
			if(this.pageCount < oldPageCount){
				for(var i=oldPageCount-1; i>=this.pageCount; i--){
					this.height -= this.getPageHeight(i);
					delete this.pageHeights[i];
				}
			}else if(this.pageCount > oldPageCount){
				this.height += this.defaultPageHeight * (this.pageCount - oldPageCount - 1) + this.calcLastPageHeight();
			}
			this.resize();
		},
		// implementation for page manager
		pageExists: function(inPageIndex){
			return Boolean(this.getDefaultPageNode(inPageIndex));
		},
		measurePage: function(inPageIndex){
			if(this.grid.rowHeight){
				var height = this.grid.rowHeight + 1;
				return ((inPageIndex + 1) * this.rowsPerPage > this.rowCount ?
					this.rowCount - inPageIndex * this.rowsPerPage :
					this.rowsPerPage) * height;
					 
			}
			var n = this.getDefaultPageNode(inPageIndex);
			return (n && n.innerHTML) ? n.offsetHeight : undefined;
		},
		positionPage: function(inPageIndex, inPos){
			for(var i=0; i<this.colCount; i++){
				this.pageNodes[i][inPageIndex].style.top = inPos + 'px';
			}
		},
		repositionPages: function(inPageIndex){
			var nodes = this.getDefaultNodes();
			var last = 0;

			for(var i=0; i<this.stack.length; i++){
				last = Math.max(this.stack[i], last);
			}
			//
			var n = nodes[inPageIndex];
			var y = (n ? this.getPageNodePosition(n) + this.getPageHeight(inPageIndex) : 0);
			for(var p=inPageIndex+1; p<=last; p++){
				n = nodes[p];
				if(n){
					if(this.getPageNodePosition(n) == y){
						return;
					}
					this.positionPage(p, y);
				}
				y += this.getPageHeight(p);
			}
		},
		installPage: function(inPageIndex){
			for(var i=0; i<this.colCount; i++){
				this.contentNodes[i].appendChild(this.pageNodes[i][inPageIndex]);
			}
		},
		preparePage: function(inPageIndex, inReuseNode){
			var p = (inReuseNode ? this.popPage() : null);
			for(var i=0; i<this.colCount; i++){
				var nodes = this.pageNodes[i];
				var new_p = (p === null ? this.createPageNode() : this.invalidatePageNode(p, nodes));
				new_p.pageIndex = inPageIndex;
				nodes[inPageIndex] = new_p;
			}
		},
		// rendering implementation
		renderPage: function(inPageIndex){
			var nodes = [];
			var i, j;
			for(i=0; i<this.colCount; i++){
				nodes[i] = this.pageNodes[i][inPageIndex];
			}
			for(i=0, j=inPageIndex*this.rowsPerPage; (i<this.rowsPerPage)&&(j<this.rowCount); i++, j++){
				this.renderRow(j, nodes);
			}
		},
		removePage: function(inPageIndex){
			for(var i=0, j=inPageIndex*this.rowsPerPage; i<this.rowsPerPage; i++, j++){
				this.removeRow(j);
			}
		},
		destroyPage: function(inPageIndex){
			for(var i=0; i<this.colCount; i++){
				var n = this.invalidatePageNode(inPageIndex, this.pageNodes[i]);
				if(n){
					dojo.destroy(n);
				}
			}
		},
		pacify: function(inShouldPacify){
		},
		// pacification
		pacifying: false,
		pacifyTicks: 200,
		setPacifying: function(inPacifying){
			if(this.pacifying != inPacifying){
				this.pacifying = inPacifying;
				this.pacify(this.pacifying);
			}
		},
		startPacify: function(){
			this.startPacifyTicks = new Date().getTime();
		},
		doPacify: function(){
			var result = (new Date().getTime() - this.startPacifyTicks) > this.pacifyTicks;
			this.setPacifying(true);
			this.startPacify();
			return result;
		},
		endPacify: function(){
			this.setPacifying(false);
		},
		// default sizing implementation
		resize: function(){
			if(this.scrollboxNode){
				this.windowHeight = this.scrollboxNode.clientHeight;
			}
			for(var i=0; i<this.colCount; i++){
				//We want to have 1px in height min to keep scroller.  Otherwise can't scroll
				//and see header in empty grid.
				dojox.grid.util.setStyleHeightPx(this.contentNodes[i], Math.max(1,this.height));
			}
			
			// Calculate the average row height and update the defaults (row and page).
			var needPage = (!this._invalidating);
			if(!needPage){
				var ah = this.grid.attr("autoHeight");
				if(typeof ah == "number" && ah <= Math.min(this.rowsPerPage, this.rowCount)){
					needPage = true;
				}
			}
			if(needPage){
				this.needPage(this.page, this.pageTop);
			}
			var rowsOnPage = (this.page < this.pageCount - 1) ? this.rowsPerPage : ((this.rowCount % this.rowsPerPage) || this.rowsPerPage);
			var pageHeight = this.getPageHeight(this.page);
			this.averageRowHeight = (pageHeight > 0 && rowsOnPage > 0) ? (pageHeight / rowsOnPage) : 0;
		},
		calcLastPageHeight: function(){
			if(!this.pageCount){
				return 0;
			}
			var lastPage = this.pageCount - 1;
			var lastPageHeight = ((this.rowCount % this.rowsPerPage)||(this.rowsPerPage)) * this.defaultRowHeight;
			this.pageHeights[lastPage] = lastPageHeight;
			return lastPageHeight;
		},
		updateContentHeight: function(inDh){
			this.height += inDh;
			this.resize();
		},
		updatePageHeight: function(inPageIndex, fromBuild){
			if(this.pageExists(inPageIndex)){
				var oh = this.getPageHeight(inPageIndex);
				var h = (this.measurePage(inPageIndex));
				if(h === undefined){
					h = oh;
				}
				this.pageHeights[inPageIndex] = h;
				if(oh != h){
					this.updateContentHeight(h - oh);
					var ah = this.grid.attr("autoHeight");
					if((typeof ah == "number" && ah > this.rowCount)||(ah === true && !fromBuild)){
						this.grid.sizeChange();
					}else{
						this.repositionPages(inPageIndex);
					}
				}
				return h;
			}
			return 0;
		},
		rowHeightChanged: function(inRowIndex){
			this.updatePageHeight(Math.floor(inRowIndex / this.rowsPerPage), false);
		},
		// scroller core
		invalidateNodes: function(){
			while(this.stack.length){
				this.destroyPage(this.popPage());
			}
		},
		createPageNode: function(){
			var p = document.createElement('div');
			dojo.attr(p,"role","presentation");
			p.style.position = 'absolute';
			//p.style.width = '100%';
			p.style[dojo._isBodyLtr() ? "left" : "right"] = '0';
			return p;
		},
		getPageHeight: function(inPageIndex){
			var ph = this.pageHeights[inPageIndex];
			return (ph !== undefined ? ph : this.defaultPageHeight);
		},
		// FIXME: this is not a stack, it's a FIFO list
		pushPage: function(inPageIndex){
			return this.stack.push(inPageIndex);
		},
		popPage: function(){
			return this.stack.shift();
		},
		findPage: function(inTop){
			var i = 0, h = 0;
			for(var ph = 0; i<this.pageCount; i++, h += ph){
				ph = this.getPageHeight(i);
				if(h + ph >= inTop){
					break;
				}
			}
			this.page = i;
			this.pageTop = h;
		},
		buildPage: function(inPageIndex, inReuseNode, inPos){
			this.preparePage(inPageIndex, inReuseNode);
			this.positionPage(inPageIndex, inPos);
			// order of operations is key below
			this.installPage(inPageIndex);
			this.renderPage(inPageIndex);
			// order of operations is key above
			this.pushPage(inPageIndex);
		},
		needPage: function(inPageIndex, inPos){
			var h = this.getPageHeight(inPageIndex), oh = h;
			if(!this.pageExists(inPageIndex)){
				this.buildPage(inPageIndex, this.keepPages&&(this.stack.length >= this.keepPages), inPos);
				h = this.updatePageHeight(inPageIndex, true);
			}else{
				this.positionPage(inPageIndex, inPos);
			}
			return h;
		},
		onscroll: function(){
			this.scroll(this.scrollboxNode.scrollTop);
		},
		scroll: function(inTop){
			this.grid.scrollTop = inTop;
			if(this.colCount){
				this.startPacify();
				this.findPage(inTop);
				var h = this.height;
				var b = this.getScrollBottom(inTop);
				for(var p=this.page, y=this.pageTop; (p<this.pageCount)&&((b<0)||(y<b)); p++){
					y += this.needPage(p, y);
				}
				this.firstVisibleRow = this.getFirstVisibleRow(this.page, this.pageTop, inTop);
				this.lastVisibleRow = this.getLastVisibleRow(p - 1, y, b);
				// indicates some page size has been updated
				if(h != this.height){
					this.repositionPages(p-1);
				}
				this.endPacify();
			}
		},
		getScrollBottom: function(inTop){
			return (this.windowHeight >= 0 ? inTop + this.windowHeight : -1);
		},
		// events
		processNodeEvent: function(e, inNode){
			var t = e.target;
			while(t && (t != inNode) && t.parentNode && (t.parentNode.parentNode != inNode)){
				t = t.parentNode;
			}
			if(!t || !t.parentNode || (t.parentNode.parentNode != inNode)){
				return false;
			}
			var page = t.parentNode;
			e.topRowIndex = page.pageIndex * this.rowsPerPage;
			e.rowIndex = e.topRowIndex + indexInParent(t);
			e.rowTarget = t;
			return true;
		},
		processEvent: function(e){
			return this.processNodeEvent(e, this.contentNode);
		},
		// virtual rendering interface
		renderRow: function(inRowIndex, inPageNode){
		},
		removeRow: function(inRowIndex){
		},
		// page node operations
		getDefaultPageNode: function(inPageIndex){
			return this.getDefaultNodes()[inPageIndex];
		},
		positionPageNode: function(inNode, inPos){
		},
		getPageNodePosition: function(inNode){
			return inNode.offsetTop;
		},
		invalidatePageNode: function(inPageIndex, inNodes){
			var p = inNodes[inPageIndex];
			if(p){
				delete inNodes[inPageIndex];
				this.removePage(inPageIndex, p);
				cleanNode(p);
				p.innerHTML = '';
			}
			return p;
		},
		// scroll control
		getPageRow: function(inPage){
			return inPage * this.rowsPerPage;
		},
		getLastPageRow: function(inPage){
			return Math.min(this.rowCount, this.getPageRow(inPage + 1)) - 1;
		},
		getFirstVisibleRow: function(inPage, inPageTop, inScrollTop){
			if(!this.pageExists(inPage)){
				return 0;
			}
			var row = this.getPageRow(inPage);
			var nodes = this.getDefaultNodes();
			var rows = divkids(nodes[inPage]);
			for(var i=0,l=rows.length; i<l && inPageTop<inScrollTop; i++, row++){
				inPageTop += rows[i].offsetHeight;
			}
			return (row ? row - 1 : row);
		},
		getLastVisibleRow: function(inPage, inBottom, inScrollBottom){
			if(!this.pageExists(inPage)){
				return 0;
			}
			var nodes = this.getDefaultNodes();
			var row = this.getLastPageRow(inPage);
			var rows = divkids(nodes[inPage]);
			for(var i=rows.length-1; i>=0 && inBottom>inScrollBottom; i--, row--){
				inBottom -= rows[i].offsetHeight;
			}
			return row + 1;
		},
		findTopRow: function(inScrollTop){
			var nodes = this.getDefaultNodes();
			var rows = divkids(nodes[this.page]);
			for(var i=0,l=rows.length,t=this.pageTop,h; i<l; i++){
				h = rows[i].offsetHeight;
				t += h;
				if(t >= inScrollTop){
					this.offset = h - (t - inScrollTop);
					return i + this.page * this.rowsPerPage;
				}
			}
			return -1;
		},
		findScrollTop: function(inRow){
			var rowPage = Math.floor(inRow / this.rowsPerPage);
			var t = 0;
			var i, l;
			for(i=0; i<rowPage; i++){
				t += this.getPageHeight(i);
			}
			this.pageTop = t;
			this.needPage(rowPage, this.pageTop);

			var nodes = this.getDefaultNodes();
			var rows = divkids(nodes[rowPage]);
			var r = inRow - this.rowsPerPage * rowPage;
			for(i=0,l=rows.length; i<l && i<r; i++){
				t += rows[i].offsetHeight;
			}
			return t;
		},
		dummy: 0
	});
})();

}

if(!dojo._hasResource["dojox.grid.cells._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid.cells._base"] = true;
dojo.provide("dojox.grid.cells._base");




dojo.declare("dojox.grid._DeferredTextWidget", dijit._Widget, {
	deferred: null,
	_destroyOnRemove: true,
	postCreate: function(){
		if(this.deferred){
			this.deferred.addBoth(dojo.hitch(this, function(text){
				if(this.domNode){
					this.domNode.innerHTML = text;
				}
			}));
		}
	}
});

(function(){
	var focusSelectNode = function(inNode){
		try{
			dojox.grid.util.fire(inNode, "focus");
			dojox.grid.util.fire(inNode, "select");
		}catch(e){// IE sux bad
		}
	};
	
	var whenIdle = function(/*inContext, inMethod, args ...*/){
		setTimeout(dojo.hitch.apply(dojo, arguments), 0);
	};

	var dgc = dojox.grid.cells;

	dojo.declare("dojox.grid.cells._Base", null, {
		// summary:
		//	Respresents a grid cell and contains information about column options and methods
		//	for retrieving cell related information.
		//	Each column in a grid layout has a cell object and most events and many methods
		//	provide access to these objects.
		styles: '',
		classes: '',
		editable: false,
		alwaysEditing: false,
		formatter: null,
		defaultValue: '...',
		value: null,
		hidden: false,
		noresize: false,
		draggable: true,
		//private
		_valueProp: "value",
		_formatPending: false,

		constructor: function(inProps){
			this._props = inProps || {};
			dojo.mixin(this, inProps);
			if(this.draggable === undefined){
				this.draggable = true;
			}
		},

		_defaultFormat: function(inValue, callArgs){
			var s = this.grid.formatterScope || this;
			var f = this.formatter;
			if(f && s && typeof f == "string"){
				f = this.formatter = s[f];
			}
			var v = (inValue != this.defaultValue && f) ? f.apply(s, callArgs) : inValue;
			if(typeof v == "undefined"){
				return this.defaultValue;
			}
			if(v && v.addBoth){
				// Check if it's a deferred
				v = new dojox.grid._DeferredTextWidget({deferred: v},
									dojo.create("span", {innerHTML: this.defaultValue}));
			}
			if(v && v.declaredClass && v.startup){
				return "<div class='dojoxGridStubNode' linkWidget='" +
						v.id +
						"' cellIdx='" +
						this.index +
						"'>" +
						this.defaultValue +
						"</div>";
			}
			return v;
		},
		
		// data source
		format: function(inRowIndex, inItem){
			// summary:
			//	provides the html for a given grid cell.
			// inRowIndex: int
			// grid row index
			// returns: html for a given grid cell
			var f, i=this.grid.edit.info, d=this.get ? this.get(inRowIndex, inItem) : (this.value || this.defaultValue);
			d = (d && d.replace && this.grid.escapeHTMLInData) ? d.replace(/&/g, '&amp;').replace(/</g, '&lt;') : d;
			if(this.editable && (this.alwaysEditing || (i.rowIndex==inRowIndex && i.cell==this))){
				return this.formatEditing(d, inRowIndex);
			}else{
				return this._defaultFormat(d, [d, inRowIndex, this]);
			}
		},
		formatEditing: function(inDatum, inRowIndex){
			// summary:
			//	formats the cell for editing
			// inDatum: anything
			//	cell data to edit
			// inRowIndex: int
			//	grid row index
			// returns: string of html to place in grid cell
		},
		// utility
		getNode: function(inRowIndex){
			// summary:
			//	gets the dom node for a given grid cell.
			// inRowIndex: int
			// grid row index
			// returns: dom node for a given grid cell
			return this.view.getCellNode(inRowIndex, this.index);
		},
		getHeaderNode: function(){
			return this.view.getHeaderCellNode(this.index);
		},
		getEditNode: function(inRowIndex){
			return (this.getNode(inRowIndex) || 0).firstChild || 0;
		},
		canResize: function(){
			var uw = this.unitWidth;
			return uw && (uw!=='auto');
		},
		isFlex: function(){
			var uw = this.unitWidth;
			return uw && dojo.isString(uw) && (uw=='auto' || uw.slice(-1)=='%');
		},
		// edit support
		applyEdit: function(inValue, inRowIndex){
			this.grid.edit.applyCellEdit(inValue, this, inRowIndex);
		},
		cancelEdit: function(inRowIndex){
			this.grid.doCancelEdit(inRowIndex);
		},
		_onEditBlur: function(inRowIndex){
			if(this.grid.edit.isEditCell(inRowIndex, this.index)){
				//console.log('editor onblur', e);
				this.grid.edit.apply();
			}
		},
		registerOnBlur: function(inNode, inRowIndex){
			if(this.commitOnBlur){
				dojo.connect(inNode, "onblur", function(e){
					// hack: if editor still thinks this editor is current some ms after it blurs, assume we've focused away from grid
					setTimeout(dojo.hitch(this, "_onEditBlur", inRowIndex), 250);
				});
			}
		},
		//protected
		needFormatNode: function(inDatum, inRowIndex){
			this._formatPending = true;
			whenIdle(this, "_formatNode", inDatum, inRowIndex);
		},
		cancelFormatNode: function(){
			this._formatPending = false;
		},
		//private
		_formatNode: function(inDatum, inRowIndex){
			if(this._formatPending){
				this._formatPending = false;
				// make cell selectable
				dojo.setSelectable(this.grid.domNode, true);
				this.formatNode(this.getEditNode(inRowIndex), inDatum, inRowIndex);
			}
		},
		//protected
		formatNode: function(inNode, inDatum, inRowIndex){
			// summary:
			//	format the editing dom node. Use when editor is a widget.
			// inNode: dom node
			// dom node for the editor
			// inDatum: anything
			//	cell data to edit
			// inRowIndex: int
			//	grid row index
			if(dojo.isIE){
				// IE sux bad
				whenIdle(this, "focus", inRowIndex, inNode);
			}else{
				this.focus(inRowIndex, inNode);
			}
		},
		dispatchEvent: function(m, e){
			if(m in this){
				return this[m](e);
			}
		},
		//public
		getValue: function(inRowIndex){
			// summary:
			//	returns value entered into editor
			// inRowIndex: int
			// grid row index
			// returns:
			//	value of editor
			return this.getEditNode(inRowIndex)[this._valueProp];
		},
		setValue: function(inRowIndex, inValue){
			// summary:
			//	set the value of the grid editor
			// inRowIndex: int
			// grid row index
			// inValue: anything
			//	value of editor
			var n = this.getEditNode(inRowIndex);
			if(n){
				n[this._valueProp] = inValue;
			}
		},
		focus: function(inRowIndex, inNode){
			// summary:
			//	focus the grid editor
			// inRowIndex: int
			// grid row index
			// inNode: dom node
			//	editor node
			focusSelectNode(inNode || this.getEditNode(inRowIndex));
		},
		save: function(inRowIndex){
			// summary:
			//	save editor state
			// inRowIndex: int
			// grid row index
			this.value = this.value || this.getValue(inRowIndex);
			//console.log("save", this.value, inCell.index, inRowIndex);
		},
		restore: function(inRowIndex){
			// summary:
			//	restore editor state
			// inRowIndex: int
			// grid row index
			this.setValue(inRowIndex, this.value);
			//console.log("restore", this.value, inCell.index, inRowIndex);
		},
		//protected
		_finish: function(inRowIndex){
			// summary:
			//	called when editing is completed to clean up editor
			// inRowIndex: int
			// grid row index
			dojo.setSelectable(this.grid.domNode, false);
			this.cancelFormatNode();
		},
		//public
		apply: function(inRowIndex){
			// summary:
			//	apply edit from cell editor
			// inRowIndex: int
			// grid row index
			this.applyEdit(this.getValue(inRowIndex), inRowIndex);
			this._finish(inRowIndex);
		},
		cancel: function(inRowIndex){
			// summary:
			//	cancel cell edit
			// inRowIndex: int
			// grid row index
			this.cancelEdit(inRowIndex);
			this._finish(inRowIndex);
		}
	});
	dgc._Base.markupFactory = function(node, cellDef){
		var d = dojo;
		var formatter = d.trim(d.attr(node, "formatter")||"");
		if(formatter){
			cellDef.formatter = dojo.getObject(formatter)||formatter;
		}
		var get = d.trim(d.attr(node, "get")||"");
		if(get){
			cellDef.get = dojo.getObject(get);
		}
		var getBoolAttr = function(attr, cell, cellAttr){
			var value = d.trim(d.attr(node, attr)||"");
			if(value){ cell[cellAttr||attr] = !(value.toLowerCase()=="false"); }
		};
		getBoolAttr("sortDesc", cellDef);
		getBoolAttr("editable", cellDef);
		getBoolAttr("alwaysEditing", cellDef);
		getBoolAttr("noresize", cellDef);
		getBoolAttr("draggable", cellDef);

		var value = d.trim(d.attr(node, "loadingText")||d.attr(node, "defaultValue")||"");
		if(value){
			cellDef.defaultValue = value;
		}

		var getStrAttr = function(attr, cell, cellAttr){
			var value = d.trim(d.attr(node, attr)||"")||undefined;
			if(value){ cell[cellAttr||attr] = value; }
		};
		getStrAttr("styles", cellDef);
		getStrAttr("headerStyles", cellDef);
		getStrAttr("cellStyles", cellDef);
		getStrAttr("classes", cellDef);
		getStrAttr("headerClasses", cellDef);
		getStrAttr("cellClasses", cellDef);
	};

	dojo.declare("dojox.grid.cells.Cell", dgc._Base, {
		// summary
		// grid cell that provides a standard text input box upon editing
		constructor: function(){
			this.keyFilter = this.keyFilter;
		},
		// keyFilter: RegExp
		//		optional regex for disallowing keypresses
		keyFilter: null,
		formatEditing: function(inDatum, inRowIndex){
			this.needFormatNode(inDatum, inRowIndex);
			return '<input class="dojoxGridInput" type="text" value="' + inDatum + '">';
		},
		formatNode: function(inNode, inDatum, inRowIndex){
			this.inherited(arguments);
			// FIXME: feels too specific for this interface
			this.registerOnBlur(inNode, inRowIndex);
		},
		doKey: function(e){
			if(this.keyFilter){
				var key = String.fromCharCode(e.charCode);
				if(key.search(this.keyFilter) == -1){
					dojo.stopEvent(e);
				}
			}
		},
		_finish: function(inRowIndex){
			this.inherited(arguments);
			var n = this.getEditNode(inRowIndex);
			try{
				dojox.grid.util.fire(n, "blur");
			}catch(e){}
		}
	});
	dgc.Cell.markupFactory = function(node, cellDef){
		dgc._Base.markupFactory(node, cellDef);
		var d = dojo;
		var keyFilter = d.trim(d.attr(node, "keyFilter")||"");
		if(keyFilter){
			cellDef.keyFilter = new RegExp(keyFilter);
		}
	};

	dojo.declare("dojox.grid.cells.RowIndex", dgc.Cell, {
		name: 'Row',

		postscript: function(){
			this.editable = false;
		},
		get: function(inRowIndex){
			return inRowIndex + 1;
		}
	});
	dgc.RowIndex.markupFactory = function(node, cellDef){
		dgc.Cell.markupFactory(node, cellDef);
	};

	dojo.declare("dojox.grid.cells.Select", dgc.Cell, {
		// summary:
		// grid cell that provides a standard select for editing

		// options: Array
		// 		text of each item
		options: null,

		// values: Array
		//		value for each item
		values: null,

		// returnIndex: Integer
		// 		editor returns only the index of the selected option and not the value
		returnIndex: -1,

		constructor: function(inCell){
			this.values = this.values || this.options;
		},
		formatEditing: function(inDatum, inRowIndex){
			this.needFormatNode(inDatum, inRowIndex);
			var h = [ '<select class="dojoxGridSelect">' ];
			for (var i=0, o, v; ((o=this.options[i]) !== undefined)&&((v=this.values[i]) !== undefined); i++){
				h.push("<option", (inDatum==v ? ' selected' : ''), ' value="' + v + '"', ">", o, "</option>");
			}
			h.push('</select>');
			return h.join('');
		},
		getValue: function(inRowIndex){
			var n = this.getEditNode(inRowIndex);
			if(n){
				var i = n.selectedIndex, o = n.options[i];
				return this.returnIndex > -1 ? i : o.value || o.innerHTML;
			}
		}
	});
	dgc.Select.markupFactory = function(node, cell){
		dgc.Cell.markupFactory(node, cell);
		var d=dojo;
		var options = d.trim(d.attr(node, "options")||"");
		if(options){
			var o = options.split(',');
			if(o[0] != options){
				cell.options = o;
			}
		}
		var values = d.trim(d.attr(node, "values")||"");
		if(values){
			var v = values.split(',');
			if(v[0] != values){
				cell.values = v;
			}
		}
	};

	dojo.declare("dojox.grid.cells.AlwaysEdit", dgc.Cell, {
		// summary:
		// grid cell that is always in an editable state, regardless of grid editing state
		alwaysEditing: true,
		_formatNode: function(inDatum, inRowIndex){
			this.formatNode(this.getEditNode(inRowIndex), inDatum, inRowIndex);
		},
		applyStaticValue: function(inRowIndex){
			var e = this.grid.edit;
			e.applyCellEdit(this.getValue(inRowIndex), this, inRowIndex);
			e.start(this, inRowIndex, true);
		}
	});
	dgc.AlwaysEdit.markupFactory = function(node, cell){
		dgc.Cell.markupFactory(node, cell);
	};

	dojo.declare("dojox.grid.cells.Bool", dgc.AlwaysEdit, {
		// summary:
		// grid cell that provides a standard checkbox that is always on for editing
		_valueProp: "checked",
		formatEditing: function(inDatum, inRowIndex){
			return '<input class="dojoxGridInput" type="checkbox"' + (inDatum ? ' checked="checked"' : '') + ' style="width: auto" />';
		},
		doclick: function(e){
			if(e.target.tagName == 'INPUT'){
				this.applyStaticValue(e.rowIndex);
			}
		}
	});
	dgc.Bool.markupFactory = function(node, cell){
		dgc.AlwaysEdit.markupFactory(node, cell);
	};
})();

}

if(!dojo._hasResource["dojox.grid.cells"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid.cells"] = true;
dojo.provide("dojox.grid.cells");


}

if(!dojo._hasResource["dojox.grid._Builder"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid._Builder"] = true;
dojo.provide("dojox.grid._Builder");




(function(){
	var dg = dojox.grid;

	var getTdIndex = function(td){
		return td.cellIndex >=0 ? td.cellIndex : dojo.indexOf(td.parentNode.cells, td);
	};
	
	var getTrIndex = function(tr){
		return tr.rowIndex >=0 ? tr.rowIndex : dojo.indexOf(tr.parentNode.childNodes, tr);
	};
	
	var getTr = function(rowOwner, index){
		return rowOwner && ((rowOwner.rows||0)[index] || rowOwner.childNodes[index]);
	};

	var findTable = function(node){
		for(var n=node; n && n.tagName!='TABLE'; n=n.parentNode){}
		return n;
	};
	
	var ascendDom = function(inNode, inWhile){
		for(var n=inNode; n && inWhile(n); n=n.parentNode){}
		return n;
	};
	
	var makeNotTagName = function(inTagName){
		var name = inTagName.toUpperCase();
		return function(node){ return node.tagName != name; };
	};

	var rowIndexTag = dojox.grid.util.rowIndexTag;
	var gridViewTag = dojox.grid.util.gridViewTag;

	// base class for generating markup for the views
	dg._Builder = dojo.extend(function(view){
		if(view){
			this.view = view;
			this.grid = view.grid;
		}
	},{
		view: null,
		// boilerplate HTML
		_table: '<table class="dojoxGridRowTable" border="0" cellspacing="0" cellpadding="0" role="presentation"',

		// Returns the table variable as an array - and with the view width, if specified
		getTableArray: function(){
			var html = [this._table];
			if(this.view.viewWidth){
				html.push([' style="width:', this.view.viewWidth, ';"'].join(''));
			}
			html.push('>');
			return html;
		},
		
		// generate starting tags for a cell
		generateCellMarkup: function(inCell, inMoreStyles, inMoreClasses, isHeader){
			var result = [], html;
			if(isHeader){
				var sortInfo = inCell.index != inCell.grid.getSortIndex() ? "" : inCell.grid.sortInfo > 0 ? 'aria-sort="ascending"' : 'aria-sort="descending"';
				if (!inCell.id){
					inCell.id = this.grid.id + "Hdr" + inCell.index;
				}
				// column headers are not editable, mark as aria-readonly=true
				html = ['<th tabIndex="-1" aria-readonly="true" role="columnheader"', sortInfo, 'id="', inCell.id, '"'];
			}else{
				// cells inherit grid aria-readonly property; default value for aria-readonly is false(grid is editable)
				// if grid is editable (had any editable cells), mark non editable cells as aria-readonly=true
				// if no editable cells, grid's aria-readonly value will have been set to true and cells will inherit
				var editInfo = this.grid.editable && !inCell.editable ? 'aria-readonly="true"' : "";
				html = ['<td tabIndex="-1" role="gridcell"', editInfo];
			}
			if(inCell.colSpan){
				html.push(' colspan="', inCell.colSpan, '"');
			}
			if(inCell.rowSpan){
				html.push(' rowspan="', inCell.rowSpan, '"');
			}
			html.push(' class="dojoxGridCell ');
			if(inCell.classes){
				html.push(inCell.classes, ' ');
			}
			if(inMoreClasses){
				html.push(inMoreClasses, ' ');
			}
			// result[0] => td opener, style
			result.push(html.join(''));
			// SLOT: result[1] => td classes 
			result.push('');
			html = ['" idx="', inCell.index, '" style="'];
			if(inMoreStyles && inMoreStyles[inMoreStyles.length-1] != ';'){
				inMoreStyles += ';';
			}
			html.push(inCell.styles, inMoreStyles||'', inCell.hidden?'display:none;':'');
			if(inCell.unitWidth){
				html.push('width:', inCell.unitWidth, ';');
			}
			// result[2] => markup
			result.push(html.join(''));
			// SLOT: result[3] => td style 
			result.push('');
			html = [ '"' ];
			if(inCell.attrs){
				html.push(" ", inCell.attrs);
			}
			html.push('>');
			// result[4] => td postfix
			result.push(html.join(''));
			// SLOT: result[5] => content
			result.push('');
			// result[6] => td closes
			result.push(isHeader?'</th>':'</td>');
			return result; // Array
		},

		// cell finding
		isCellNode: function(inNode){
			return Boolean(inNode && inNode!=dojo.doc && dojo.attr(inNode, "idx"));
		},
		
		getCellNodeIndex: function(inCellNode){
			return inCellNode ? Number(dojo.attr(inCellNode, "idx")) : -1;
		},
		
		getCellNode: function(inRowNode, inCellIndex){
			for(var i=0, row; (row=getTr(inRowNode.firstChild, i)); i++){
				for(var j=0, cell; (cell=row.cells[j]); j++){
					if(this.getCellNodeIndex(cell) == inCellIndex){
						return cell;
					}
				}
			}
			return null;
		},
		
		findCellTarget: function(inSourceNode, inTopNode){
			var n = inSourceNode;
			while(n && (!this.isCellNode(n) || (n.offsetParent && gridViewTag in n.offsetParent.parentNode && n.offsetParent.parentNode[gridViewTag] != this.view.id)) && (n!=inTopNode)){
				n = n.parentNode;
			}
			return n!=inTopNode ? n : null;
		},
		
		// event decoration
		baseDecorateEvent: function(e){
			e.dispatch = 'do' + e.type;
			e.grid = this.grid;
			e.sourceView = this.view;
			e.cellNode = this.findCellTarget(e.target, e.rowNode);
			e.cellIndex = this.getCellNodeIndex(e.cellNode);
			e.cell = (e.cellIndex >= 0 ? this.grid.getCell(e.cellIndex) : null);
		},
		
		// event dispatch
		findTarget: function(inSource, inTag){
			var n = inSource;
			while(n && (n!=this.domNode) && (!(inTag in n) || (gridViewTag in n && n[gridViewTag] != this.view.id))){
				n = n.parentNode;
			}
			return (n != this.domNode) ? n : null; 
		},

		findRowTarget: function(inSource){
			return this.findTarget(inSource, rowIndexTag);
		},

		isIntraNodeEvent: function(e){
			try{
				return (e.cellNode && e.relatedTarget && dojo.isDescendant(e.relatedTarget, e.cellNode));
			}catch(x){
				// e.relatedTarget has permission problem in FF if it's an input: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
				return false;
			}
		},

		isIntraRowEvent: function(e){
			try{
				var row = e.relatedTarget && this.findRowTarget(e.relatedTarget);
				return !row && (e.rowIndex==-1) || row && (e.rowIndex==row.gridRowIndex);			
			}catch(x){
				// e.relatedTarget on INPUT has permission problem in FF: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
				return false;
			}
		},

		dispatchEvent: function(e){
			if(e.dispatch in this){
				return this[e.dispatch](e);
			}
			return false;
		},

		// dispatched event handlers
		domouseover: function(e){
			if(e.cellNode && (e.cellNode!=this.lastOverCellNode)){
				this.lastOverCellNode = e.cellNode;
				this.grid.onMouseOver(e);
			}
			this.grid.onMouseOverRow(e);
		},

		domouseout: function(e){
			if(e.cellNode && (e.cellNode==this.lastOverCellNode) && !this.isIntraNodeEvent(e, this.lastOverCellNode)){
				this.lastOverCellNode = null;
				this.grid.onMouseOut(e);
				if(!this.isIntraRowEvent(e)){
					this.grid.onMouseOutRow(e);
				}
			}
		},
		
		domousedown: function(e){
			if (e.cellNode)
				this.grid.onMouseDown(e);
			this.grid.onMouseDownRow(e);
		}
	});

	// Produces html for grid data content. Owned by grid and used internally 
	// for rendering data. Override to implement custom rendering.
	dg._ContentBuilder = dojo.extend(function(view){
		dg._Builder.call(this, view);
	},dg._Builder.prototype,{
		update: function(){
			this.prepareHtml();
		},

		// cache html for rendering data rows
		prepareHtml: function(){
			var defaultGet=this.grid.get, cells=this.view.structure.cells;
			for(var j=0, row; (row=cells[j]); j++){
				for(var i=0, cell; (cell=row[i]); i++){
					cell.get = cell.get || (cell.value == undefined) && defaultGet;
					cell.markup = this.generateCellMarkup(cell, cell.cellStyles, cell.cellClasses, false);
					if (!this.grid.editable && cell.editable){
						this.grid.editable = true;
					}
				}
			}
		},

		// time critical: generate html using cache and data source
		generateHtml: function(inDataIndex, inRowIndex){
			var
				html = this.getTableArray(),
				v = this.view,
				cells = v.structure.cells,
				item = this.grid.getItem(inRowIndex);

			dojox.grid.util.fire(this.view, "onBeforeRow", [inRowIndex, cells]);
			for(var j=0, row; (row=cells[j]); j++){
				if(row.hidden || row.header){
					continue;
				}
				html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
				for(var i=0, cell, m, cc, cs; (cell=row[i]); i++){
					m = cell.markup; cc = cell.customClasses = []; cs = cell.customStyles = [];
					// content (format can fill in cc and cs as side-effects)
					m[5] = cell.format(inRowIndex, item);
					// classes
					m[1] = cc.join(' ');
					// styles
					m[3] = cs.join(';');
					// in-place concat
					html.push.apply(html, m);
				}
				html.push('</tr>');
			}
			html.push('</table>');
			return html.join(''); // String
		},

		decorateEvent: function(e){
			e.rowNode = this.findRowTarget(e.target);
			if(!e.rowNode){return false;}
			e.rowIndex = e.rowNode[rowIndexTag];
			this.baseDecorateEvent(e);
			e.cell = this.grid.getCell(e.cellIndex);
			return true; // Boolean
		}
	});

	// Produces html for grid header content. Owned by grid and used internally 
	// for rendering data. Override to implement custom rendering.
	dg._HeaderBuilder = dojo.extend(function(view){
		this.moveable = null;
		dg._Builder.call(this, view);
	},dg._Builder.prototype,{
		_skipBogusClicks: false,
		overResizeWidth: 4,
		minColWidth: 1,
		
		update: function(){
			if(this.tableMap){
				this.tableMap.mapRows(this.view.structure.cells);
			}else{
				this.tableMap = new dg._TableMap(this.view.structure.cells);
			}
		},

		generateHtml: function(inGetValue, inValue){
			var html = this.getTableArray(), cells = this.view.structure.cells;
			
			dojox.grid.util.fire(this.view, "onBeforeRow", [-1, cells]);
			for(var j=0, row; (row=cells[j]); j++){
				if(row.hidden){
					continue;
				}
				html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGridInvisible">');
				for(var i=0, cell, markup; (cell=row[i]); i++){
					cell.customClasses = [];
					cell.customStyles = [];
					if(this.view.simpleStructure){
						if(cell.draggable){
							if(cell.headerClasses){
								if(cell.headerClasses.indexOf('dojoDndItem') == -1){
									cell.headerClasses += ' dojoDndItem';
								}
							}else{
								cell.headerClasses = 'dojoDndItem';
							}
						}
						if(cell.attrs){
							if(cell.attrs.indexOf("dndType='gridColumn_") == -1){
								cell.attrs += " dndType='gridColumn_" + this.grid.id + "'";
							}
						}else{
							cell.attrs = "dndType='gridColumn_" + this.grid.id + "'";
						}
					}
					markup = this.generateCellMarkup(cell, cell.headerStyles, cell.headerClasses, true);
					// content
					markup[5] = (inValue != undefined ? inValue : inGetValue(cell));
					// styles
					markup[3] = cell.customStyles.join(';');
					// classes
					markup[1] = cell.customClasses.join(' '); //(cell.customClasses ? ' ' + cell.customClasses : '');
					html.push(markup.join(''));
				}
				html.push('</tr>');
			}
			html.push('</table>');
			return html.join('');
		},

		// event helpers
		getCellX: function(e){
			var n, x = e.layerX;
			if(dojo.isMoz){
				n = ascendDom(e.target, makeNotTagName("th"));
				x -= (n && n.offsetLeft) || 0;
				var t = e.sourceView.getScrollbarWidth();
				if(!dojo._isBodyLtr()/*&& e.sourceView.headerNode.scrollLeft < t*/){
					//fix #11253
					table = ascendDom(n,makeNotTagName("table"));
					x -= (table && table.offsetLeft) || 0;
				}
				//x -= getProp(ascendDom(e.target, mkNotTagName("td")), "offsetLeft") || 0;
			}
			n = ascendDom(e.target, function(){
				if(!n || n == e.cellNode){
					return false;
				}
				// Mozilla 1.8 (FF 1.5) has a bug that makes offsetLeft = -parent border width
				// when parent has border, overflow: hidden, and is positioned
				// handle this problem here ... not a general solution!
				x += (n.offsetLeft < 0 ? 0 : n.offsetLeft);
				return true;
			});
			return x;
		},

		// event decoration
		decorateEvent: function(e){
			this.baseDecorateEvent(e);
			e.rowIndex = -1;
			e.cellX = this.getCellX(e);
			return true;
		},

		// event handlers
		// resizing
		prepareResize: function(e, mod){
			do{
				var i = getTdIndex(e.cellNode);
				e.cellNode = (i ? e.cellNode.parentNode.cells[i+mod] : null);
				e.cellIndex = (e.cellNode ? this.getCellNodeIndex(e.cellNode) : -1);
			}while(e.cellNode && e.cellNode.style.display == "none");
			return Boolean(e.cellNode);
		},

		canResize: function(e){
			if(!e.cellNode || e.cellNode.colSpan > 1){
				return false;
			}
			var cell = this.grid.getCell(e.cellIndex); 
			return !cell.noresize && cell.canResize();
		},

		overLeftResizeArea: function(e){
			// We are never over a resize area if we are in the process of moving
			if(dojo.hasClass(dojo.body(), "dojoDndMove")){
				return false;
			}
			//Bugfix for crazy IE problem (#8807).  IE returns position information for the icon and text arrow divs
			//as if they were still on the left instead of returning the position they were 'float: right' to.
			//So, the resize check ends up checking the wrong adjacent cell.  This checks to see if the hover was over 
			//the image or text nodes, then just ignored them/treat them not in scale range.
			if(dojo.isIE){
				var tN = e.target;
				if(dojo.hasClass(tN, "dojoxGridArrowButtonNode") || 
					dojo.hasClass(tN, "dojoxGridArrowButtonChar")){
					return false;
				}
			}

			if(dojo._isBodyLtr()){
				return (e.cellIndex>0) && (e.cellX < this.overResizeWidth) && this.prepareResize(e, -1);
			}
			var t = e.cellNode && (e.cellX < this.overResizeWidth);
			return t;
		},

		overRightResizeArea: function(e){
			// We are never over a resize area if we are in the process of moving
			if(dojo.hasClass(dojo.body(), "dojoDndMove")){
				return false;
			}
			//Bugfix for crazy IE problem (#8807).  IE returns position information for the icon and text arrow divs
			//as if they were still on the left instead of returning the position they were 'float: right' to.
			//So, the resize check ends up checking the wrong adjacent cell.  This checks to see if the hover was over 
			//the image or text nodes, then just ignored them/treat them not in scale range.
			if(dojo.isIE){
				var tN = e.target;
				if(dojo.hasClass(tN, "dojoxGridArrowButtonNode") || 
					dojo.hasClass(tN, "dojoxGridArrowButtonChar")){
					return false;
				}
			}

			if(dojo._isBodyLtr()){
				return e.cellNode && (e.cellX >= e.cellNode.offsetWidth - this.overResizeWidth);
			}
			return (e.cellIndex>0) && (e.cellX >= e.cellNode.offsetWidth - this.overResizeWidth) && this.prepareResize(e, -1);
		},

		domousemove: function(e){
			//console.log(e.cellIndex, e.cellX, e.cellNode.offsetWidth);
			if(!this.moveable){
				var c = (this.overRightResizeArea(e) ? 'dojoxGridColResize' : (this.overLeftResizeArea(e) ? 'dojoxGridColResize' : ''));
				if(c && !this.canResize(e)){
					c = 'dojoxGridColNoResize';
				}
				dojo.toggleClass(e.sourceView.headerNode, "dojoxGridColNoResize", (c == "dojoxGridColNoResize"));
				dojo.toggleClass(e.sourceView.headerNode, "dojoxGridColResize", (c == "dojoxGridColResize"));
				if(dojo.isIE){
					var t = e.sourceView.headerNode.scrollLeft;
					e.sourceView.headerNode.scrollLeft = t;
				}
				if(c){
					dojo.stopEvent(e);
				}
			}
		},

		domousedown: function(e){
			if(!this.moveable){
				if((this.overRightResizeArea(e) || this.overLeftResizeArea(e)) && this.canResize(e)){
					this.beginColumnResize(e);
				}else{
					this.grid.onMouseDown(e);
					this.grid.onMouseOverRow(e);
				}
				//else{
				//	this.beginMoveColumn(e);
				//}
			}
		},

		doclick: function(e) {
			if(this._skipBogusClicks){
				dojo.stopEvent(e);
				return true;
			}
			return false;
		},

		// column resizing
		colResizeSetup: function(/*Event Object*/e, /*boolean*/ isMouse ){
			//Set up the drag object for column resizing
			// Called with mouse event in case of drag and drop,
			// Also called from keyboard shift-arrow event when focus is on a header
			var headContentBox = dojo.contentBox(e.sourceView.headerNode);
			
			if(isMouse){  //IE draws line even with no mouse down so separate from keyboard 
				this.lineDiv = document.createElement('div');

				// NOTE: this is for backwards compatibility with Dojo 1.3
				var vw = (dojo.position||dojo._abs)(e.sourceView.headerNode, true);
				var bodyContentBox = dojo.contentBox(e.sourceView.domNode);
				//fix #11340
				var l = e.clientX;
				if(!dojo._isBodyLtr() && dojo.isIE < 8){
					l -= dojox.html.metrics.getScrollbar().w;
				}				
				dojo.style(this.lineDiv, {
					top: vw.y + "px",
					left: l + "px",
					height: (bodyContentBox.h + headContentBox.h) + "px"
				});
				dojo.addClass(this.lineDiv, "dojoxGridResizeColLine");
				this.lineDiv._origLeft = l;
				dojo.body().appendChild(this.lineDiv);
			}
			var spanners = [], nodes = this.tableMap.findOverlappingNodes(e.cellNode);
			for(var i=0, cell; (cell=nodes[i]); i++){
				spanners.push({ node: cell, index: this.getCellNodeIndex(cell), width: cell.offsetWidth });
				//console.log("spanner: " + this.getCellNodeIndex(cell));
			}

			var view = e.sourceView;
			var adj = dojo._isBodyLtr() ? 1 : -1;
			var views = e.grid.views.views;
			var followers = [];
			for(var j=view.idx+adj, cView; (cView=views[j]); j=j+adj){
				followers.push({ node: cView.headerNode, left: window.parseInt(cView.headerNode.style.left) });
			}
			var table = view.headerContentNode.firstChild;
			var drag = {
				scrollLeft: e.sourceView.headerNode.scrollLeft,
				view: view,
				node: e.cellNode,
				index: e.cellIndex,
				w: dojo.contentBox(e.cellNode).w,
				vw: headContentBox.w,
				table: table,
				tw: dojo.contentBox(table).w,
				spanners: spanners,
				followers: followers
			};
			return drag;
		},
		beginColumnResize: function(e){
			this.moverDiv = document.createElement("div");
			dojo.style(this.moverDiv,{position: "absolute", left:0}); // to make DnD work with dir=rtl
			dojo.body().appendChild(this.moverDiv);
			dojo.addClass(this.grid.domNode, "dojoxGridColumnResizing");
			var m = (this.moveable = new dojo.dnd.Moveable(this.moverDiv));

			var drag = this.colResizeSetup(e,true);

			m.onMove = dojo.hitch(this, "doResizeColumn", drag);

			dojo.connect(m, "onMoveStop", dojo.hitch(this, function(){
				this.endResizeColumn(drag);
				if(drag.node.releaseCapture){
					drag.node.releaseCapture();
				}
				this.moveable.destroy();
				delete this.moveable;
				this.moveable = null;
				dojo.removeClass(this.grid.domNode, "dojoxGridColumnResizing");
			}));

			if(e.cellNode.setCapture){
				e.cellNode.setCapture();
			}
			m.onMouseDown(e);
		},

		doResizeColumn: function(inDrag, mover, leftTop){
			var changeX = leftTop.l;
			var data = {
				deltaX: changeX,
				w: inDrag.w + (dojo._isBodyLtr() ? changeX : -changeX),//fix #11341
				vw: inDrag.vw + changeX,
				tw: inDrag.tw + changeX
			};
			
			this.dragRecord = {inDrag: inDrag, mover: mover, leftTop:leftTop};
			
			if(data.w >= this.minColWidth){
				if (!mover) { // we are using keyboard do immediate resize
					this.doResizeNow(inDrag, data);
				}
				else{
					dojo.style(this.lineDiv, "left", (this.lineDiv._origLeft + data.deltaX) + "px");
				}
			}
		},

		endResizeColumn: function(inDrag){
			if(this.dragRecord){
				var leftTop = this.dragRecord.leftTop;
				var changeX = dojo._isBodyLtr() ? leftTop.l : -leftTop.l;
				// Make sure we are not under our minimum
				// http://bugs.dojotoolkit.org/ticket/9390
				changeX += Math.max(inDrag.w + changeX, this.minColWidth) - (inDrag.w + changeX);
				if(dojo.isWebKit && inDrag.spanners.length){
					// Webkit needs the pad border extents back in
					changeX += dojo._getPadBorderExtents(inDrag.spanners[0].node).w;
				}
				var data = {
					deltaX: changeX,
					w: inDrag.w + changeX,
					vw: inDrag.vw + changeX,
					tw: inDrag.tw + changeX
				};
				// Only resize the columns when the drag has finished
				this.doResizeNow(inDrag, data);
			}
			
			dojo.destroy(this.lineDiv);
 			dojo.destroy(this.moverDiv);
			dojo.destroy(this.moverDiv);
			delete this.moverDiv;
			this._skipBogusClicks = true;
			inDrag.view.update();
			this._skipBogusClicks = false;
			this.grid.onResizeColumn(inDrag.index);
		},
		doResizeNow: function(inDrag, data){
			inDrag.view.convertColPctToFixed();
			if(inDrag.view.flexCells && !inDrag.view.testFlexCells()){
				var t = findTable(inDrag.node);
				if(t){
					(t.style.width = '');
				}
			}
			var i, s, sw, f, fl;
			for(i=0; (s=inDrag.spanners[i]); i++){
				sw = s.width + data.deltaX;
				s.node.style.width = sw + 'px';
				inDrag.view.setColWidth(s.index, sw);
			}
			if(dojo._isBodyLtr() || !dojo.isIE){//fix #11339			
				for(i=0; (f=inDrag.followers[i]); i++){
					fl = f.left + data.deltaX;
					f.node.style.left = fl + 'px';
				}
			}
			inDrag.node.style.width = data.w + 'px';
			inDrag.view.setColWidth(inDrag.index, data.w);
			inDrag.view.headerNode.style.width = data.vw + 'px';
			inDrag.view.setColumnsWidth(data.tw);
			if(!dojo._isBodyLtr()){
				inDrag.view.headerNode.scrollLeft = inDrag.scrollLeft + data.deltaX;
			}
		}
	});

	// Maps an html table into a structure parsable for information about cell row and col spanning.
	// Used by HeaderBuilder.
	dg._TableMap = dojo.extend(function(rows){
		this.mapRows(rows);
	},{
		map: null,

		mapRows: function(inRows){
			// summary: Map table topography

			//console.log('mapRows');
			// # of rows
			var rowCount = inRows.length;
			if(!rowCount){
				return;
			}
			// map which columns and rows fill which cells
			this.map = [];
			var row;
			for(var k=0; (row=inRows[k]); k++){
				this.map[k] = [];
			}
			for(var j=0; (row=inRows[j]); j++){
				for(var i=0, x=0, cell, colSpan, rowSpan; (cell=row[i]); i++){
					while(this.map[j][x]){x++;}
					this.map[j][x] = { c: i, r: j };
					rowSpan = cell.rowSpan || 1;
					colSpan = cell.colSpan || 1;
					for(var y=0; y<rowSpan; y++){
						for(var s=0; s<colSpan; s++){
							this.map[j+y][x+s] = this.map[j][x];
						}
					}
					x += colSpan;
				}
			}
			//this.dumMap();
		},

		dumpMap: function(){
			for(var j=0, row, h=''; (row=this.map[j]); j++,h=''){
				for(var i=0, cell; (cell=row[i]); i++){
					h += cell.r + ',' + cell.c + '   ';
				}
			}
		},

		getMapCoords: function(inRow, inCol){
			// summary: Find node's map coords by it's structure coords
			for(var j=0, row; (row=this.map[j]); j++){
				for(var i=0, cell; (cell=row[i]); i++){
					if(cell.c==inCol && cell.r == inRow){
						return { j: j, i: i };
					}
					//else{console.log(inRow, inCol, ' : ', i, j, " : ", cell.r, cell.c); };
				}
			}
			return { j: -1, i: -1 };
		},
		
		getNode: function(inTable, inRow, inCol){
			// summary: Find a node in inNode's table with the given structure coords
			var row = inTable && inTable.rows[inRow];
			return row && row.cells[inCol];
		},
		
		_findOverlappingNodes: function(inTable, inRow, inCol){
			var nodes = [];
			var m = this.getMapCoords(inRow, inCol);
			//console.log("node j: %d, i: %d", m.j, m.i);
			for(var j=0, row; (row=this.map[j]); j++){
				if(j == m.j){ continue; }
				var rw = row[m.i];
				//console.log("overlaps: r: %d, c: %d", rw.r, rw.c);
				var n = (rw?this.getNode(inTable, rw.r, rw.c):null);
				if(n){ nodes.push(n); }
			}
			//console.log(nodes);
			return nodes;
		},
		
		findOverlappingNodes: function(inNode){
			return this._findOverlappingNodes(findTable(inNode), getTrIndex(inNode.parentNode), getTdIndex(inNode));
		}
	});
})();

}

if(!dojo._hasResource["dojox.grid._View"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid._View"] = true;
dojo.provide("dojox.grid._View");










(function(){
	// private
	var getStyleText = function(inNode, inStyleText){
		return inNode.style.cssText == undefined ? inNode.getAttribute("style") : inNode.style.cssText;
	};

	// public
	dojo.declare('dojox.grid._View', [dijit._Widget, dijit._Templated], {
		// summary:
		//		A collection of grid columns. A grid is comprised of a set of views that stack horizontally.
		//		Grid creates views automatically based on grid's layout structure.
		//		Users should typically not need to access individual views directly.
		//
		// defaultWidth: String
		//		Default width of the view
		defaultWidth: "18em",

		// viewWidth: String
		// 		Width for the view, in valid css unit
		viewWidth: "",

		templateString:"<div class=\"dojoxGridView\" wairole=\"presentation\">\n\t<div class=\"dojoxGridHeader\" dojoAttachPoint=\"headerNode\" wairole=\"presentation\">\n\t\t<div dojoAttachPoint=\"headerNodeContainer\" style=\"width:9000em\" wairole=\"presentation\">\n\t\t\t<div dojoAttachPoint=\"headerContentNode\" wairole=\"row\"></div>\n\t\t</div>\n\t</div>\n\t<input type=\"checkbox\" class=\"dojoxGridHiddenFocus\" dojoAttachPoint=\"hiddenFocusNode\" wairole=\"presentation\" />\n\t<input type=\"checkbox\" class=\"dojoxGridHiddenFocus\" wairole=\"presentation\" />\n\t<div class=\"dojoxGridScrollbox\" dojoAttachPoint=\"scrollboxNode\" wairole=\"presentation\">\n\t\t<div class=\"dojoxGridContent\" dojoAttachPoint=\"contentNode\" hidefocus=\"hidefocus\" wairole=\"presentation\"></div>\n\t</div>\n</div>\n",
		
		themeable: false,
		classTag: 'dojoxGrid',
		marginBottom: 0,
		rowPad: 2,

		// _togglingColumn: int
		//		Width of the column being toggled (-1 for none)
		_togglingColumn: -1,
		
		// _headerBuilderClass: Object
		//		The class to use for our header builder
		_headerBuilderClass: dojox.grid._HeaderBuilder,
		
		// _contentBuilderClass: Object
		//		The class to use for our content builder
		_contentBuilderClass: dojox.grid._ContentBuilder,
		
		postMixInProperties: function(){
			this.rowNodes = {};
		},

		postCreate: function(){
			this.connect(this.scrollboxNode,"onscroll","doscroll");
			dojox.grid.util.funnelEvents(this.contentNode, this, "doContentEvent", [ 'mouseover', 'mouseout', 'click', 'dblclick', 'contextmenu', 'mousedown' ]);
			dojox.grid.util.funnelEvents(this.headerNode, this, "doHeaderEvent", [ 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'click', 'contextmenu' ]);
			this.content = new this._contentBuilderClass(this);
			this.header = new this._headerBuilderClass(this);
			//BiDi: in RTL case, style width='9000em' causes scrolling problem in head node
			if(!dojo._isBodyLtr()){
				this.headerNodeContainer.style.width = "";
			}
		},

		destroy: function(){
			dojo.destroy(this.headerNode);
			delete this.headerNode;
			for(var i in this.rowNodes){
				dojo.destroy(this.rowNodes[i]);
			}
			this.rowNodes = {};
			if(this.source){
				this.source.destroy();
			}
			this.inherited(arguments);
		},

		// focus 
		focus: function(){
			if(dojo.isIE || dojo.isWebKit || dojo.isOpera){
				this.hiddenFocusNode.focus();
			}else{
				this.scrollboxNode.focus();
			}
		},

		setStructure: function(inStructure){
			var vs = (this.structure = inStructure);
			// FIXME: similar logic is duplicated in layout
			if(vs.width && !isNaN(vs.width)){
				this.viewWidth = vs.width + 'em';
			}else{
				this.viewWidth = vs.width || (vs.noscroll ? 'auto' : this.viewWidth); //|| this.defaultWidth;
			}
			this._onBeforeRow = vs.onBeforeRow||function(){};
			this._onAfterRow = vs.onAfterRow||function(){};
			this.noscroll = vs.noscroll;
			if(this.noscroll){
				this.scrollboxNode.style.overflow = "hidden";
			}
			this.simpleStructure = Boolean(vs.cells.length == 1);
			// bookkeeping
			this.testFlexCells();
			// accomodate new structure
			this.updateStructure();
		},
		
		_cleanupRowWidgets: function(inRowNode){
			// Summary:
			//		Cleans up the widgets for the given row node so that
			//		we can reattach them if needed
			if(inRowNode){
				dojo.forEach(dojo.query("[widgetId]", inRowNode).map(dijit.byNode), function(w){
					if(w._destroyOnRemove){
						w.destroy();
						delete w;
					}else if(w.domNode && w.domNode.parentNode){
						w.domNode.parentNode.removeChild(w.domNode);
					}
				});
			}
		},
		
		onBeforeRow: function(inRowIndex, cells){
			this._onBeforeRow(inRowIndex, cells);
			if(inRowIndex >= 0){
				this._cleanupRowWidgets(this.getRowNode(inRowIndex));
			}
		},
		
		onAfterRow: function(inRowIndex, cells, inRowNode){
			this._onAfterRow(inRowIndex, cells, inRowNode);
			var g = this.grid;
			dojo.forEach(dojo.query(".dojoxGridStubNode", inRowNode), function(n){
				if(n && n.parentNode){
					var lw = n.getAttribute("linkWidget");
					var cellIdx = window.parseInt(dojo.attr(n, "cellIdx"), 10);
					var cellDef = g.getCell(cellIdx);
					var w = dijit.byId(lw);
					if(w){
						n.parentNode.replaceChild(w.domNode, n);
						if(!w._started){
							w.startup();
						}
					}else{
						n.innerHTML = "";
					}
				}
			}, this);
		},

		testFlexCells: function(){
			// FIXME: cheater, this function does double duty as initializer and tester
			this.flexCells = false;
			for(var j=0, row; (row=this.structure.cells[j]); j++){
				for(var i=0, cell; (cell=row[i]); i++){
					cell.view = this;
					this.flexCells = this.flexCells || cell.isFlex();
				}
			}
			return this.flexCells;
		},

		updateStructure: function(){
			// header builder needs to update table map
			this.header.update();
			// content builder needs to update markup cache
			this.content.update();
		},

		getScrollbarWidth: function(){
			var hasScrollSpace = this.hasVScrollbar();
			var overflow = dojo.style(this.scrollboxNode, "overflow");
			if(this.noscroll || !overflow || overflow == "hidden"){
				hasScrollSpace = false;
			}else if(overflow == "scroll"){
				hasScrollSpace = true;
			}
			return (hasScrollSpace ? dojox.html.metrics.getScrollbar().w : 0); // Integer
		},

		getColumnsWidth: function(){
			var h = this.headerContentNode;
			return h && h.firstChild ? h.firstChild.offsetWidth : 0; // Integer
		},

		setColumnsWidth: function(width){
			this.headerContentNode.firstChild.style.width = width + 'px';
			if(this.viewWidth){
				this.viewWidth = width + 'px';
			}
		},

		getWidth: function(){
			return this.viewWidth || (this.getColumnsWidth()+this.getScrollbarWidth()) +'px'; // String
		},

		getContentWidth: function(){
			return Math.max(0, dojo._getContentBox(this.domNode).w - this.getScrollbarWidth()) + 'px'; // String
		},

		render: function(){
			this.scrollboxNode.style.height = '';
			this.renderHeader();
			if(this._togglingColumn >= 0){
				this.setColumnsWidth(this.getColumnsWidth() - this._togglingColumn);
				this._togglingColumn = -1;
			}
			var cells = this.grid.layout.cells;
			var getSibling = dojo.hitch(this, function(node, before){
				!dojo._isBodyLtr() && (before = !before);
				var inc = before?-1:1;
				var idx = this.header.getCellNodeIndex(node) + inc;
				var cell = cells[idx];
				while(cell && cell.getHeaderNode() && cell.getHeaderNode().style.display == "none"){
					idx += inc;
					cell = cells[idx];
				}
				if(cell){
					return cell.getHeaderNode();
				}
				return null;
			});
			if(this.grid.columnReordering && this.simpleStructure){
				if(this.source){
					this.source.destroy();
				}
				
				// Create the top and bottom markers
				var bottomMarkerId = "dojoxGrid_bottomMarker";
				var topMarkerId = "dojoxGrid_topMarker";
				if(this.bottomMarker){
					dojo.destroy(this.bottomMarker);
				}
				this.bottomMarker = dojo.byId(bottomMarkerId);
				if(this.topMarker){
					dojo.destroy(this.topMarker);
				}
				this.topMarker = dojo.byId(topMarkerId);
				if (!this.bottomMarker) {
					this.bottomMarker = dojo.create("div", {
						"id": bottomMarkerId,
						"class": "dojoxGridColPlaceBottom"
					}, dojo.body());
					this._hide(this.bottomMarker);

					
					this.topMarker = dojo.create("div", {
						"id": topMarkerId,
						"class": "dojoxGridColPlaceTop"
					}, dojo.body());
					this._hide(this.topMarker);
				}
				this.arrowDim = dojo.contentBox(this.bottomMarker);

				var headerHeight = dojo.contentBox(this.headerContentNode.firstChild.rows[0]).h;
				
				this.source = new dojo.dnd.Source(this.headerContentNode.firstChild.rows[0], {
					horizontal: true,
					accept: [ "gridColumn_" + this.grid.id ],
					viewIndex: this.index,
					generateText: false,
					onMouseDown: dojo.hitch(this, function(e){
						this.header.decorateEvent(e);
						if((this.header.overRightResizeArea(e) || this.header.overLeftResizeArea(e)) &&
							this.header.canResize(e) && !this.header.moveable){
							this.header.beginColumnResize(e);
						}else{
							if(this.grid.headerMenu){
								this.grid.headerMenu.onCancel(true);
							}
							// IE reports a left click as 1, where everything else reports 0
							if(e.button === (dojo.isIE ? 1 : 0)){
								dojo.dnd.Source.prototype.onMouseDown.call(this.source, e);
							}
						}
					}),
					onMouseOver: dojo.hitch(this, function(e){
						var src = this.source;
						if(src._getChildByEvent(e)){
							dojo.dnd.Source.prototype.onMouseOver.apply(src, arguments);
						}
					}),
					_markTargetAnchor: dojo.hitch(this, function(before){
						var src = this.source;
						if(src.current == src.targetAnchor && src.before == before){ return; }
						if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
							src._removeItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
						}
						dojo.dnd.Source.prototype._markTargetAnchor.call(src, before);
						
						var target = before ? src.targetAnchor : getSibling(src.targetAnchor, src.before);
						var endAdd = 0;

						if (!target) {
							target = src.targetAnchor;
							endAdd = dojo.contentBox(target).w + this.arrowDim.w/2 + 2;
						}

						// NOTE: this is for backwards compatibility with Dojo 1.3
						var pos = (dojo.position||dojo._abs)(target, true);
						var left = Math.floor(pos.x - this.arrowDim.w/2 + endAdd);

						dojo.style(this.bottomMarker, "visibility", "visible");
						dojo.style(this.topMarker, "visibility", "visible");
						dojo.style(this.bottomMarker, {
							"left": left + "px",
							"top" : (headerHeight + pos.y) + "px"
						});

						dojo.style(this.topMarker, {
							"left": left + "px",
							"top" : (pos.y - this.arrowDim.h) + "px"
						});

						if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
							src._addItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
						}
					}),
					_unmarkTargetAnchor: dojo.hitch(this, function(){
						var src = this.source;
						if(!src.targetAnchor){ return; }
						if(src.targetAnchor && getSibling(src.targetAnchor, src.before)){
							src._removeItemClass(getSibling(src.targetAnchor, src.before), src.before ? "After" : "Before");
						}
						this._hide(this.bottomMarker);
						this._hide(this.topMarker);
						dojo.dnd.Source.prototype._unmarkTargetAnchor.call(src);
					}),
					destroy: dojo.hitch(this, function(){
						dojo.disconnect(this._source_conn);
						dojo.unsubscribe(this._source_sub);
						dojo.dnd.Source.prototype.destroy.call(this.source);
						if(this.bottomMarker){
							dojo.destroy(this.bottomMarker);
							delete this.bottomMarker;
						}
						if(this.topMarker){
							dojo.destroy(this.topMarker);
							delete this.topMarker;
						}
					}),
					onDndCancel: dojo.hitch(this, function(){
						dojo.dnd.Source.prototype.onDndCancel.call(this.source);
						this._hide(this.bottomMarker);
						this._hide(this.topMarker);
					})
				});

				this._source_conn = dojo.connect(this.source, "onDndDrop", this, "_onDndDrop");
				this._source_sub = dojo.subscribe("/dnd/drop/before", this, "_onDndDropBefore");
				this.source.startup();
			}
		},
		
		_hide: function(node){
			dojo.style(node, {
				left: "-10000px",
				top: "-10000px",
				"visibility": "hidden"
			});
		},

		_onDndDropBefore: function(source, nodes, copy){
			if(dojo.dnd.manager().target !== this.source){
				return;
			}
			this.source._targetNode = this.source.targetAnchor;
			this.source._beforeTarget = this.source.before;
			var views = this.grid.views.views;
			var srcView = views[source.viewIndex];
			var tgtView = views[this.index];
			if(tgtView != srcView){
				srcView.convertColPctToFixed();
				tgtView.convertColPctToFixed();
			}
		},

		_onDndDrop: function(source, nodes, copy){
			if(dojo.dnd.manager().target !== this.source){
				if(dojo.dnd.manager().source === this.source){
					this._removingColumn = true;
				}
				return;
			}
			this._hide(this.bottomMarker);
			this._hide(this.topMarker);

			var getIdx = function(n){
				return n ? dojo.attr(n, "idx") : null;
			};
			var w = dojo.marginBox(nodes[0]).w;
			if(source.viewIndex !== this.index){
				var views = this.grid.views.views;
				var srcView = views[source.viewIndex];
				var tgtView = views[this.index];
				if(srcView.viewWidth && srcView.viewWidth != "auto"){
					srcView.setColumnsWidth(srcView.getColumnsWidth() - w);
				}
				if(tgtView.viewWidth && tgtView.viewWidth != "auto"){
					tgtView.setColumnsWidth(tgtView.getColumnsWidth());
				}
			}
			var stn = this.source._targetNode;
			var stb = this.source._beforeTarget;
			!dojo._isBodyLtr() && (stb = !stb);
			var layout = this.grid.layout;
			var idx = this.index;
			delete this.source._targetNode;
			delete this.source._beforeTarget;
			
			layout.moveColumn(
				source.viewIndex,
				idx,
				getIdx(nodes[0]),
				getIdx(stn),
				stb);
		},

		renderHeader: function(){
			this.headerContentNode.innerHTML = this.header.generateHtml(this._getHeaderContent);
			if(this.flexCells){
				this.contentWidth = this.getContentWidth();
				this.headerContentNode.firstChild.style.width = this.contentWidth;
			}
			dojox.grid.util.fire(this, "onAfterRow", [-1, this.structure.cells, this.headerContentNode]);
		},

		// note: not called in 'view' context
		_getHeaderContent: function(inCell){
			var n = inCell.name || inCell.grid.getCellName(inCell);
			var ret = [ '<div class="dojoxGridSortNode' ];
			
			if(inCell.index != inCell.grid.getSortIndex()){
				ret.push('">');
			}else{
				ret = ret.concat([ ' ',
							inCell.grid.sortInfo > 0 ? 'dojoxGridSortUp' : 'dojoxGridSortDown',
							'"><div class="dojoxGridArrowButtonChar">',
							inCell.grid.sortInfo > 0 ? '&#9650;' : '&#9660;',
							'</div><div class="dojoxGridArrowButtonNode" role="presentation"></div>',
							'<div class="dojoxGridColCaption">']);
			}
			ret = ret.concat([n, '</div></div>']);
			return ret.join('');
		},

		resize: function(){
			this.adaptHeight();
			this.adaptWidth();
		},

		hasHScrollbar: function(reset){
			var hadScroll = this._hasHScroll||false;
			if(this._hasHScroll == undefined || reset){
				if(this.noscroll){
					this._hasHScroll = false;
				}else{
					var style = dojo.style(this.scrollboxNode, "overflow");
					if(style == "hidden"){
						this._hasHScroll = false;
					}else if(style == "scroll"){
						this._hasHScroll = true;
					}else{
						this._hasHScroll = (this.scrollboxNode.offsetWidth - this.getScrollbarWidth() < this.contentNode.offsetWidth );
					}
				}
			}
			if(hadScroll !== this._hasHScroll){
				this.grid.update();
			}
			return this._hasHScroll; // Boolean
		},

		hasVScrollbar: function(reset){
			var hadScroll = this._hasVScroll||false;
			if(this._hasVScroll == undefined || reset){
				if(this.noscroll){
					this._hasVScroll = false;
				}else{
					var style = dojo.style(this.scrollboxNode, "overflow");
					if(style == "hidden"){
						this._hasVScroll = false;
					}else if(style == "scroll"){
						this._hasVScroll = true;
					}else{
						this._hasVScroll = (this.scrollboxNode.scrollHeight > this.scrollboxNode.clientHeight);
					}
				}
			}
			if(hadScroll !== this._hasVScroll){
				this.grid.update();
			}
			return this._hasVScroll; // Boolean
		},
		
		convertColPctToFixed: function(){
			// Fix any percentage widths to be pixel values
			var hasPct = false;
			this.grid.initialWidth = "";
			var cellNodes = dojo.query("th", this.headerContentNode);
			var fixedWidths = dojo.map(cellNodes, function(c, vIdx){
				var w = c.style.width;
				dojo.attr(c, "vIdx", vIdx);
				if(w && w.slice(-1) == "%"){
					hasPct = true;
				}else if(w && w.slice(-2) == "px"){
					return window.parseInt(w, 10);
				}
				return dojo.contentBox(c).w;
			});
			if(hasPct){
				dojo.forEach(this.grid.layout.cells, function(cell, idx){
					if(cell.view == this){
						var cellNode = cell.view.getHeaderCellNode(cell.index);
						if(cellNode && dojo.hasAttr(cellNode, "vIdx")){
							var vIdx = window.parseInt(dojo.attr(cellNode, "vIdx"));
							this.setColWidth(idx, fixedWidths[vIdx]);
							dojo.removeAttr(cellNode, "vIdx");
						}
					}
				}, this);
				return true;
			}
			return false;
		},

		adaptHeight: function(minusScroll){
			if(!this.grid._autoHeight){
				var h = (this.domNode.style.height && parseInt(this.domNode.style.height.replace(/px/,''), 10)) || this.domNode.clientHeight;
				var self = this;
				var checkOtherViewScrollers = function(){
					var v;
					for(var i in self.grid.views.views){
						v = self.grid.views.views[i];
						if(v !== self && v.hasHScrollbar()){
							return true;
						}
					}
					return false;
				};
				if(minusScroll || (this.noscroll && checkOtherViewScrollers())){
					h -= dojox.html.metrics.getScrollbar().h;
				}
				dojox.grid.util.setStyleHeightPx(this.scrollboxNode, h);
			}
			this.hasVScrollbar(true);
		},

		adaptWidth: function(){
			if(this.flexCells){
				// the view content width
				this.contentWidth = this.getContentWidth();
				this.headerContentNode.firstChild.style.width = this.contentWidth;
			}
			// FIXME: it should be easier to get w from this.scrollboxNode.clientWidth, 
			// but clientWidth seemingly does not include scrollbar width in some cases
			var w = this.scrollboxNode.offsetWidth - this.getScrollbarWidth();
			if(!this._removingColumn){
				w = Math.max(w, this.getColumnsWidth()) + 'px';
			}else{
				w = Math.min(w, this.getColumnsWidth()) + 'px';
				this._removingColumn = false;
			}
			var cn = this.contentNode;
			cn.style.width = w;
			this.hasHScrollbar(true);
		},

		setSize: function(w, h){
			var ds = this.domNode.style;
			var hs = this.headerNode.style;

			if(w){
				ds.width = w;
				hs.width = w;
			}
			ds.height = (h >= 0 ? h + 'px' : '');
		},

		renderRow: function(inRowIndex){
			var rowNode = this.createRowNode(inRowIndex);
			this.buildRow(inRowIndex, rowNode);
			this.grid.edit.restore(this, inRowIndex);
			return rowNode;
		},

		createRowNode: function(inRowIndex){
			var node = document.createElement("div");
			node.className = this.classTag + 'Row';
			if (this instanceof dojox.grid._RowSelector){
				dojo.attr(node,"role","presentation");
			}else{
				dojo.attr(node,"role","row");
				if (this.grid.selectionMode != "none") {
					dojo.attr(node, "aria-selected", "false"); //rows can be selected so add aria-selected prop
				}
			}
			node[dojox.grid.util.gridViewTag] = this.id;
			node[dojox.grid.util.rowIndexTag] = inRowIndex;
			this.rowNodes[inRowIndex] = node;
			return node;
		},

		buildRow: function(inRowIndex, inRowNode){
			
			this.buildRowContent(inRowIndex, inRowNode);
		  	
			this.styleRow(inRowIndex, inRowNode);
		  
		 
		},

		buildRowContent: function(inRowIndex, inRowNode){
			inRowNode.innerHTML = this.content.generateHtml(inRowIndex, inRowIndex); 
			if(this.flexCells && this.contentWidth){
				// FIXME: accessing firstChild here breaks encapsulation
				inRowNode.firstChild.style.width = this.contentWidth;
			}
			dojox.grid.util.fire(this, "onAfterRow", [inRowIndex, this.structure.cells, inRowNode]);
		},

		rowRemoved:function(inRowIndex){
			if(inRowIndex >= 0){
				this._cleanupRowWidgets(this.getRowNode(inRowIndex));
			}
			this.grid.edit.save(this, inRowIndex);
			delete this.rowNodes[inRowIndex];
		},

		getRowNode: function(inRowIndex){
			return this.rowNodes[inRowIndex];
		},

		getCellNode: function(inRowIndex, inCellIndex){
			var row = this.getRowNode(inRowIndex);
			if(row){
				return this.content.getCellNode(row, inCellIndex);
			}
		},

		getHeaderCellNode: function(inCellIndex){
			if(this.headerContentNode){
				return this.header.getCellNode(this.headerContentNode, inCellIndex);
			}
		},

		// styling
		styleRow: function(inRowIndex, inRowNode){
			inRowNode._style = getStyleText(inRowNode);
			this.styleRowNode(inRowIndex, inRowNode);
		},

		styleRowNode: function(inRowIndex, inRowNode){
			if(inRowNode){
				this.doStyleRowNode(inRowIndex, inRowNode);
			}
		},

		doStyleRowNode: function(inRowIndex, inRowNode){
			this.grid.styleRowNode(inRowIndex, inRowNode);
		},

		// updating
		updateRow: function(inRowIndex){
			var rowNode = this.getRowNode(inRowIndex);
			if(rowNode){
				rowNode.style.height = '';
				this.buildRow(inRowIndex, rowNode);
			}
			return rowNode;
		},

		updateRowStyles: function(inRowIndex){
			this.styleRowNode(inRowIndex, this.getRowNode(inRowIndex));
		},

		// scrolling
		lastTop: 0,
		firstScroll:0,

		doscroll: function(inEvent){
			//var s = dojo.marginBox(this.headerContentNode.firstChild);
			var isLtr = dojo._isBodyLtr();
			if(this.firstScroll < 2){
				if((!isLtr && this.firstScroll == 1) || (isLtr && this.firstScroll === 0)){
					var s = dojo.marginBox(this.headerNodeContainer);
					if(dojo.isIE){
						this.headerNodeContainer.style.width = s.w + this.getScrollbarWidth() + 'px';
					}else if(dojo.isMoz){
						//TODO currently only for FF, not sure for safari and opera
						this.headerNodeContainer.style.width = s.w - this.getScrollbarWidth() + 'px';
						//this.headerNodeContainer.style.width = s.w + 'px';
						//set scroll to right in FF
						this.scrollboxNode.scrollLeft = isLtr ?
							this.scrollboxNode.clientWidth - this.scrollboxNode.scrollWidth :
							this.scrollboxNode.scrollWidth - this.scrollboxNode.clientWidth;
					}
				}
				this.firstScroll++;
			}
			this.headerNode.scrollLeft = this.scrollboxNode.scrollLeft;
			// 'lastTop' is a semaphore to prevent feedback-loop with setScrollTop below
			var top = this.scrollboxNode.scrollTop;
			if(top !== this.lastTop){
				this.grid.scrollTo(top);
			}
		},

		setScrollTop: function(inTop){
			// 'lastTop' is a semaphore to prevent feedback-loop with doScroll above
			this.lastTop = inTop;
			this.scrollboxNode.scrollTop = inTop;
			return this.scrollboxNode.scrollTop;
		},

		// event handlers (direct from DOM)
		doContentEvent: function(e){
			if(this.content.decorateEvent(e)){
				this.grid.onContentEvent(e);
			}
		},

		doHeaderEvent: function(e){
			if(this.header.decorateEvent(e)){
				this.grid.onHeaderEvent(e);
			}
		},

		// event dispatch(from Grid)
		dispatchContentEvent: function(e){
			return this.content.dispatchEvent(e);
		},

		dispatchHeaderEvent: function(e){
			return this.header.dispatchEvent(e);
		},

		// column resizing
		setColWidth: function(inIndex, inWidth){
			this.grid.setCellWidth(inIndex, inWidth + 'px');
		},

		update: function(){
			if(!this.domNode){
				return;
			}
			this.content.update();
			this.grid.update();
			//get scroll after update or scroll left setting goes wrong on IE.
			//See trac: #8040
			var left = this.scrollboxNode.scrollLeft;
			this.scrollboxNode.scrollLeft = left;
			this.headerNode.scrollLeft = left;
		}
	});

	dojo.declare("dojox.grid._GridAvatar", dojo.dnd.Avatar, {
		construct: function(){
			var dd = dojo.doc;

			var a = dd.createElement("table");
			a.cellPadding = a.cellSpacing = "0";
			a.className = "dojoxGridDndAvatar";
			a.style.position = "absolute";
			a.style.zIndex = 1999;
			a.style.margin = "0px"; // to avoid dojo.marginBox() problems with table's margins
			var b = dd.createElement("tbody");
			var tr = dd.createElement("tr");
			var td = dd.createElement("td");
			var img = dd.createElement("td");
			tr.className = "dojoxGridDndAvatarItem";
			img.className = "dojoxGridDndAvatarItemImage";
			img.style.width = "16px";
			var source = this.manager.source, node;
			if(source.creator){
				// create an avatar representation of the node
				node = source._normalizedCreator(source.getItem(this.manager.nodes[0].id).data, "avatar").node;
			}else{
				// or just clone the node and hope it works
				node = this.manager.nodes[0].cloneNode(true);
				var table, tbody;
				if(node.tagName.toLowerCase() == "tr"){
					// insert extra table nodes
					table = dd.createElement("table");
					tbody = dd.createElement("tbody");
					tbody.appendChild(node);
					table.appendChild(tbody);
					node = table;
				}else if(node.tagName.toLowerCase() == "th"){
					// insert extra table nodes
					table = dd.createElement("table");
					tbody = dd.createElement("tbody");
					var r = dd.createElement("tr");
					table.cellPadding = table.cellSpacing = "0";
					r.appendChild(node);
					tbody.appendChild(r);
					table.appendChild(tbody);
					node = table;
				}
			}
			node.id = "";
			td.appendChild(node);
			tr.appendChild(img);
			tr.appendChild(td);
			dojo.style(tr, "opacity", 0.9);
			b.appendChild(tr);

			a.appendChild(b);
			this.node = a;

			var m = dojo.dnd.manager();
			this.oldOffsetY = m.OFFSET_Y;
			m.OFFSET_Y = 1;
		},
		destroy: function(){
			dojo.dnd.manager().OFFSET_Y = this.oldOffsetY;
			this.inherited(arguments);
		}
	});

	var oldMakeAvatar = dojo.dnd.manager().makeAvatar;
	dojo.dnd.manager().makeAvatar = function(){
		var src = this.source;
		if(src.viewIndex !== undefined && !dojo.hasClass(dojo.body(),"dijit_a11y")){
			return new dojox.grid._GridAvatar(this);
		}
		return oldMakeAvatar.call(dojo.dnd.manager());
	};
})();

}

if(!dojo._hasResource["dojox.grid._RowSelector"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid._RowSelector"] = true;
dojo.provide("dojox.grid._RowSelector");


dojo.declare('dojox.grid._RowSelector', dojox.grid._View, {
	// summary:
	//	Custom grid view. If used in a grid structure, provides a small selectable region for grid rows.
	defaultWidth: "2em",
	noscroll: true,
	padBorderWidth: 2,
	buildRendering: function(){
		this.inherited('buildRendering', arguments);
		this.scrollboxNode.style.overflow = "hidden";
		this.headerNode.style.visibility = "hidden";
	},	
	getWidth: function(){
		return this.viewWidth || this.defaultWidth;
	},
	buildRowContent: function(inRowIndex, inRowNode){
		var w = this.contentWidth || 0;
		inRowNode.innerHTML = '<table class="dojoxGridRowbarTable" style="width:' + w + 'px;height:1px;" border="0" cellspacing="0" cellpadding="0" role="presentation"><tr><td class="dojoxGridRowbarInner">&nbsp;</td></tr></table>';
	},
	renderHeader: function(){
	},
	updateRow: function(){
	},
	resize: function(){
		this.adaptHeight();
	},
	adaptWidth: function(){
		// Only calculate this here - rather than every call to buildRowContent
		if(!("contentWidth" in this) && this.contentNode){
			this.contentWidth = this.contentNode.offsetWidth - this.padBorderWidth;
		}
	},
	// styling
	doStyleRowNode: function(inRowIndex, inRowNode){
		var n = [ "dojoxGridRowbar dojoxGridNonNormalizedCell" ];
		if(this.grid.rows.isOver(inRowIndex)){
			n.push("dojoxGridRowbarOver");
		}
		if(this.grid.selection.isSelected(inRowIndex)){
			n.push("dojoxGridRowbarSelected");
		}
		inRowNode.className = n.join(" ");
	},
	// event handlers
	domouseover: function(e){
		this.grid.onMouseOverRow(e);
	},
	domouseout: function(e){
		if(!this.isIntraRowEvent(e)){
			this.grid.onMouseOutRow(e);
		}
	}
});

}

if(!dojo._hasResource["dojox.grid._Layout"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid._Layout"] = true;
dojo.provide("dojox.grid._Layout");



dojo.declare("dojox.grid._Layout", null, {
	// summary:
	//	Controls grid cell layout. Owned by grid and used internally.
	constructor: function(inGrid){
		this.grid = inGrid;
	},
	// flat array of grid cells
	cells: [],
	// structured array of grid cells
	structure: null,
	// default cell width
	defaultWidth: '6em',

	// methods
	moveColumn: function(sourceViewIndex, destViewIndex, cellIndex, targetIndex, before){
		var source_cells = this.structure[sourceViewIndex].cells[0];
		var dest_cells = this.structure[destViewIndex].cells[0];

		var cell = null;
		var cell_ri = 0;
		var target_ri = 0;

		for(var i=0, c; c=source_cells[i]; i++){
			if(c.index == cellIndex){
				cell_ri = i;
				break;
			}
		}
		cell = source_cells.splice(cell_ri, 1)[0];
		cell.view = this.grid.views.views[destViewIndex];

		for(i=0, c=null; c=dest_cells[i]; i++){
			if(c.index == targetIndex){
				target_ri = i;
				break;
			}
		}
		if(!before){
			target_ri += 1;
		}
		dest_cells.splice(target_ri, 0, cell);

		var sortedCell = this.grid.getCell(this.grid.getSortIndex());
		if(sortedCell){
			sortedCell._currentlySorted = this.grid.getSortAsc();
		}

		this.cells = [];
		cellIndex = 0;
		var v;
		for(i=0; v=this.structure[i]; i++){
			for(var j=0, cs; cs=v.cells[j]; j++){
				for(var k=0; c=cs[k]; k++){
					c.index = cellIndex;
					this.cells.push(c);
					if("_currentlySorted" in c){
						var si = cellIndex + 1;
						si *= c._currentlySorted ? 1 : -1;
						this.grid.sortInfo = si;
						delete c._currentlySorted;
					}
					cellIndex++;
				}
			}
		}
		this.grid.setupHeaderMenu();
		//this.grid.renderOnIdle();
	},

	setColumnVisibility: function(columnIndex, visible){
		var cell = this.cells[columnIndex];
		if(cell.hidden == visible){
			cell.hidden = !visible;
			var v = cell.view, w = v.viewWidth;
			if(w && w != "auto"){
				v._togglingColumn = dojo.marginBox(cell.getHeaderNode()).w || 0;
			}
			v.update();
			return true;
		}else{
			return false;
		}
	},
	
	addCellDef: function(inRowIndex, inCellIndex, inDef){
		var self = this;
		var getCellWidth = function(inDef){
			var w = 0;
			if(inDef.colSpan > 1){
				w = 0;
			}else{
				w = inDef.width || self._defaultCellProps.width || self.defaultWidth;

				if(!isNaN(w)){
					w = w + "em";
				}
			}
			return w;
		};

		var props = {
			grid: this.grid,
			subrow: inRowIndex,
			layoutIndex: inCellIndex,
			index: this.cells.length
		};

		if(inDef && inDef instanceof dojox.grid.cells._Base){
			var new_cell = dojo.clone(inDef);
			props.unitWidth = getCellWidth(new_cell._props);
			new_cell = dojo.mixin(new_cell, this._defaultCellProps, inDef._props, props);
			return new_cell;
		}

		var cell_type = inDef.type || this._defaultCellProps.type || dojox.grid.cells.Cell;

		props.unitWidth = getCellWidth(inDef);
		return new cell_type(dojo.mixin({}, this._defaultCellProps, inDef, props));	
	},
	
	addRowDef: function(inRowIndex, inDef){
		var result = [];
		var relSum = 0, pctSum = 0, doRel = true;
		for(var i=0, def, cell; (def=inDef[i]); i++){
			cell = this.addCellDef(inRowIndex, i, def);
			result.push(cell);
			this.cells.push(cell);
			// Check and calculate the sum of all relative widths
			if(doRel && cell.relWidth){
				relSum += cell.relWidth;
			}else if(cell.width){
				var w = cell.width;
				if(typeof w == "string" && w.slice(-1) == "%"){
					pctSum += window.parseInt(w, 10);
				}else if(w == "auto"){
					// relative widths doesn't play nice with auto - since we
					// don't have a way of knowing how much space the auto is 
					// supposed to take up.
					doRel = false;
				}
			}
		}
		if(relSum && doRel){
			// We have some kind of relWidths specified - so change them to %
			dojo.forEach(result, function(cell){
				if(cell.relWidth){
					cell.width = cell.unitWidth = ((cell.relWidth / relSum) * (100 - pctSum)) + "%";
				}
			});
		}
		return result;
	
	},

	addRowsDef: function(inDef){
		var result = [];
		if(dojo.isArray(inDef)){
			if(dojo.isArray(inDef[0])){
				for(var i=0, row; inDef && (row=inDef[i]); i++){
					result.push(this.addRowDef(i, row));
				}
			}else{
				result.push(this.addRowDef(0, inDef));
			}
		}
		return result;	
	},
	
	addViewDef: function(inDef){
		this._defaultCellProps = inDef.defaultCell || {};
		if(inDef.width && inDef.width == "auto"){
			delete inDef.width;
		}
		return dojo.mixin({}, inDef, {cells: this.addRowsDef(inDef.rows || inDef.cells)});
	},
	
	setStructure: function(inStructure){
		this.fieldIndex = 0;
		this.cells = [];
		var s = this.structure = [];

		if(this.grid.rowSelector){
			var sel = { type: dojox._scopeName + ".grid._RowSelector" };

			if(dojo.isString(this.grid.rowSelector)){
				var width = this.grid.rowSelector;

				if(width == "false"){
					sel = null;
				}else if(width != "true"){
					sel['width'] = width;
				}
			}else{
				if(!this.grid.rowSelector){
					sel = null;
				}
			}

			if(sel){
				s.push(this.addViewDef(sel));
			}
		}

		var isCell = function(def){
			return ("name" in def || "field" in def || "get" in def);
		};

		var isRowDef = function(def){
			if(dojo.isArray(def)){
				if(dojo.isArray(def[0]) || isCell(def[0])){
					return true;
				}
			}
			return false;
		};

		var isView = function(def){
			return (def !== null && dojo.isObject(def) &&
					("cells" in def || "rows" in def || ("type" in def && !isCell(def))));
		};

		if(dojo.isArray(inStructure)){
			var hasViews = false;
			for(var i=0, st; (st=inStructure[i]); i++){
				if(isView(st)){
					hasViews = true;
					break;
				}
			}
			if(!hasViews){
				s.push(this.addViewDef({ cells: inStructure }));
			}else{
				for(i=0; (st=inStructure[i]); i++){
					if(isRowDef(st)){
						s.push(this.addViewDef({ cells: st }));
					}else if(isView(st)){
						s.push(this.addViewDef(st));
					}
				}
			}
		}else if(isView(inStructure)){
			// it's a view object
			s.push(this.addViewDef(inStructure));
		}

		this.cellCount = this.cells.length;
		this.grid.setupHeaderMenu();
	}
});

}

if(!dojo._hasResource["dojox.grid._ViewManager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid._ViewManager"] = true;
dojo.provide("dojox.grid._ViewManager");

dojo.declare('dojox.grid._ViewManager', null, {
	// summary:
	//		A collection of grid views. Owned by grid and used internally for managing grid views.
	// description:
	//		Grid creates views automatically based on grid's layout structure.
	//		Users should typically not need to access individual views or the views collection directly.
	constructor: function(inGrid){
		this.grid = inGrid;
	},

	defaultWidth: 200,

	views: [],

	// operations
	resize: function(){
		this.onEach("resize");
	},

	render: function(){
		this.onEach("render");
	},

	// views
	addView: function(inView){
		inView.idx = this.views.length;
		this.views.push(inView);
	},

	destroyViews: function(){
		for(var i=0, v; v=this.views[i]; i++){
			v.destroy();
		}
		this.views = [];
	},

	getContentNodes: function(){
		var nodes = [];
		for(var i=0, v; v=this.views[i]; i++){
			nodes.push(v.contentNode);
		}
		return nodes;
	},

	forEach: function(inCallback){
		for(var i=0, v; v=this.views[i]; i++){
			inCallback(v, i);
		}
	},

	onEach: function(inMethod, inArgs){
		inArgs = inArgs || [];
		for(var i=0, v; v=this.views[i]; i++){
			if(inMethod in v){
				v[inMethod].apply(v, inArgs);
			}
		}
	},

	// layout
	normalizeHeaderNodeHeight: function(){
		var rowNodes = [];
		for(var i=0, v; (v=this.views[i]); i++){
			if(v.headerContentNode.firstChild){
				rowNodes.push(v.headerContentNode);
			}
		}
		this.normalizeRowNodeHeights(rowNodes);
	},

	normalizeRowNodeHeights: function(inRowNodes){
		var h = 0;
		var currHeights = [];
		if(this.grid.rowHeight){
			h = this.grid.rowHeight;
		}else{
			if(inRowNodes.length <= 1){ 
				// no need to normalize if we are the only one...
				return; 
			}
			for(var i=0, n; (n=inRowNodes[i]); i++){
				// We only care about the height - so don't use marginBox.  This
				// depends on the container not having any margin (which it shouldn't)
				// Also - we only look up the height if the cell doesn't have the
				// dojoxGridNonNormalizedCell class (like for row selectors)
				if(!dojo.hasClass(n, "dojoxGridNonNormalizedCell")){
					currHeights[i] = n.firstChild.offsetHeight;
					h =  Math.max(h, currHeights[i]);
				}
			}
			h = (h >= 0 ? h : 0);
	
			//Work around odd FF3 rendering bug: #8864.
			//A one px increase fixes FireFox 3's rounding bug for fractional font sizes.
			if(dojo.isMoz && h){h++;}
		}
		for(i=0; (n=inRowNodes[i]); i++){
			if(currHeights[i] != h){
				n.firstChild.style.height = h + "px";
			}
		}
	},
	
	resetHeaderNodeHeight: function(){
		for(var i=0, v, n; (v=this.views[i]); i++){
			n = v.headerContentNode.firstChild;
			if(n){
				n.style.height = "";
			}
		}
	},

	renormalizeRow: function(inRowIndex){
		var rowNodes = [];
		for(var i=0, v, n; (v=this.views[i])&&(n=v.getRowNode(inRowIndex)); i++){
			n.firstChild.style.height = '';
			rowNodes.push(n);
		}
		this.normalizeRowNodeHeights(rowNodes);
	},

	getViewWidth: function(inIndex){
		return this.views[inIndex].getWidth() || this.defaultWidth;
	},

	// must be called after view widths are properly set or height can be miscalculated
	// if there are flex columns
	measureHeader: function(){
		// need to reset view header heights so they are properly measured.
		this.resetHeaderNodeHeight();
		this.forEach(function(inView){
			inView.headerContentNode.style.height = '';
		});
		var h = 0;
		// calculate maximum view header height
		this.forEach(function(inView){
			h = Math.max(inView.headerNode.offsetHeight, h);
		});
		return h;
	},

	measureContent: function(){
		var h = 0;
		this.forEach(function(inView){
			h = Math.max(inView.domNode.offsetHeight, h);
		});
		return h;
	},

	findClient: function(inAutoWidth){
		// try to use user defined client
		var c = this.grid.elasticView || -1;
		// attempt to find implicit client
		if(c < 0){
			for(var i=1, v; (v=this.views[i]); i++){
				if(v.viewWidth){
					for(i=1; (v=this.views[i]); i++){
						if(!v.viewWidth){
							c = i;
							break;
						}
					}
					break;
				}
			}
		}
		// client is in the middle by default
		if(c < 0){
			c = Math.floor(this.views.length / 2);
		}
		return c;
	},

	arrange: function(l, w){
		var i, v, vw, len = this.views.length;
		// find the client
		var c = (w <= 0 ? len : this.findClient());
		// layout views
		var setPosition = function(v, l){
			var ds = v.domNode.style;
			var hs = v.headerNode.style;

			if(!dojo._isBodyLtr()){
				ds.right = l + 'px';
				// fixed rtl, the scrollbar is on the right side in FF
				if (dojo.isMoz) {
					hs.right = l + v.getScrollbarWidth() + 'px';
					hs.width = parseInt(hs.width, 10) - v.getScrollbarWidth() + 'px';
				}else{
					hs.right = l + 'px';					
				}
			}else{
				ds.left = l + 'px';
				hs.left = l + 'px';
			}
			ds.top = 0 + 'px';
			hs.top = 0;
		};
		// for views left of the client
		//BiDi TODO: The left and right should not appear in BIDI environment. Should be replaced with 
		//leading and tailing concept.
		for(i=0; (v=this.views[i])&&(i<c); i++){
			// get width
			vw = this.getViewWidth(i);
			// process boxes
			v.setSize(vw, 0);
			setPosition(v, l);
			if(v.headerContentNode && v.headerContentNode.firstChild){
				vw = v.getColumnsWidth()+v.getScrollbarWidth();
			}else{
				vw = v.domNode.offsetWidth;
			}
			// update position
			l += vw;
		}
		// next view (is the client, i++ == c) 
		i++;
		// start from the right edge
		var r = w;
		// for views right of the client (iterated from the right)
		for(var j=len-1; (v=this.views[j])&&(i<=j); j--){
			// get width
			vw = this.getViewWidth(j);
			// set size
			v.setSize(vw, 0);
			// measure in pixels
			vw = v.domNode.offsetWidth;
			// update position
			r -= vw;
			// set position
			setPosition(v, r);
		}
		if(c<len){
			v = this.views[c];
			// position the client box between left and right boxes	
			vw = Math.max(1, r-l);
			// set size
			v.setSize(vw + 'px', 0);
			setPosition(v, l);
		}
		return l;
	},

	// rendering
	renderRow: function(inRowIndex, inNodes, skipRenorm){
		var rowNodes = [];
		for(var i=0, v, n, rowNode; (v=this.views[i])&&(n=inNodes[i]); i++){
			rowNode = v.renderRow(inRowIndex);
			n.appendChild(rowNode);
			rowNodes.push(rowNode);
		}
		if(!skipRenorm){
			this.normalizeRowNodeHeights(rowNodes);
		}
	},
	
	rowRemoved: function(inRowIndex){
		this.onEach("rowRemoved", [ inRowIndex ]);
	},
	
	// updating
	updateRow: function(inRowIndex, skipRenorm){
		for(var i=0, v; v=this.views[i]; i++){
			v.updateRow(inRowIndex);
		}
		if(!skipRenorm){
			this.renormalizeRow(inRowIndex);
		}
	},
	
	updateRowStyles: function(inRowIndex){
		this.onEach("updateRowStyles", [ inRowIndex ]);
	},
	
	// scrolling
	setScrollTop: function(inTop){
		var top = inTop;
		for(var i=0, v; v=this.views[i]; i++){
			top = v.setScrollTop(inTop);
			// Work around IE not firing scroll events that cause header offset
			// issues to occur.
			if(dojo.isIE && v.headerNode && v.scrollboxNode){
				v.headerNode.scrollLeft = v.scrollboxNode.scrollLeft;
			}
		}
		return top;
		//this.onEach("setScrollTop", [ inTop ]);
	},
	
	getFirstScrollingView: function(){
		// summary: Returns the first grid view with a scroll bar 
		for(var i=0, v; (v=this.views[i]); i++){
			if(v.hasHScrollbar() || v.hasVScrollbar()){
				return v;
			}
		}
		return null;
	}
	
});

}

if(!dojo._hasResource["dojox.grid._RowManager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid._RowManager"] = true;
dojo.provide("dojox.grid._RowManager");

(function(){
	var setStyleText = function(inNode, inStyleText){
		if(inNode.style.cssText == undefined){
			inNode.setAttribute("style", inStyleText);
		}else{
			inNode.style.cssText = inStyleText;
		}
	};

	dojo.declare("dojox.grid._RowManager", null, {
		//	Stores information about grid rows. Owned by grid and used internally.
		constructor: function(inGrid){
			this.grid = inGrid;
		},
		linesToEms: 2,
		overRow: -2,
		// styles
		prepareStylingRow: function(inRowIndex, inRowNode){
			return {
				index: inRowIndex, 
				node: inRowNode,
				odd: Boolean(inRowIndex&1),
				selected: !!this.grid.selection.isSelected(inRowIndex),
				over: this.isOver(inRowIndex),
				customStyles: "",
				customClasses: "dojoxGridRow"
			};
		},
		styleRowNode: function(inRowIndex, inRowNode){
			var row = this.prepareStylingRow(inRowIndex, inRowNode);
			this.grid.onStyleRow(row);
			this.applyStyles(row);
		},
		applyStyles: function(inRow){
			var i = inRow;

			i.node.className = i.customClasses;
			var h = i.node.style.height;
			setStyleText(i.node, i.customStyles + ';' + (i.node._style||''));
			i.node.style.height = h;
		},
		updateStyles: function(inRowIndex){
			this.grid.updateRowStyles(inRowIndex);
		},
		// states and events
		setOverRow: function(inRowIndex){
			var last = this.overRow;
			this.overRow = inRowIndex;
			if((last!=this.overRow)&&(dojo.isString(last) || last >= 0)){
				this.updateStyles(last);
			}
			this.updateStyles(this.overRow);
		},
		isOver: function(inRowIndex){
			return (this.overRow == inRowIndex && !dojo.hasClass(this.grid.domNode, "dojoxGridColumnResizing"));
		}
	});
})();

}

if(!dojo._hasResource["dojox.grid._FocusManager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid._FocusManager"] = true;
dojo.provide("dojox.grid._FocusManager");



// focus management
dojo.declare("dojox.grid._FocusManager", null, {
	// summary:
	//	Controls grid cell focus. Owned by grid and used internally for focusing.
	//	Note: grid cell actually receives keyboard input only when cell is being edited.
	constructor: function(inGrid){
		this.grid = inGrid;
		this.cell = null;
		this.rowIndex = -1;
		this._connects = [];
		this.headerMenu = this.grid.headerMenu;
		this._connects.push(dojo.connect(this.grid.domNode, "onfocus", this, "doFocus"));
		this._connects.push(dojo.connect(this.grid.domNode, "onblur", this, "doBlur"));
		this._connects.push(dojo.connect(this.grid.domNode, "oncontextmenu", this, "doContextMenu"));
		this._connects.push(dojo.connect(this.grid.lastFocusNode, "onfocus", this, "doLastNodeFocus"));
		this._connects.push(dojo.connect(this.grid.lastFocusNode, "onblur", this, "doLastNodeBlur"));
		this._connects.push(dojo.connect(this.grid,"_onFetchComplete", this, "_delayedCellFocus"));
		this._connects.push(dojo.connect(this.grid,"postrender", this, "_delayedHeaderFocus"));
	},
	destroy: function(){
		dojo.forEach(this._connects, dojo.disconnect);
		delete this.grid;
		delete this.cell;
	},
	_colHeadNode: null,
	_colHeadFocusIdx: null,
	_contextMenuBindNode: null,
	tabbingOut: false,
	focusClass: "dojoxGridCellFocus",
	focusView: null,
	initFocusView: function(){
		this.focusView = this.grid.views.getFirstScrollingView() || this.focusView;
		this._initColumnHeaders();
	},
	isFocusCell: function(inCell, inRowIndex){
		// summary:
		//	states if the given cell is focused
		// inCell: object
		//	grid cell object
		// inRowIndex: int
		//	grid row index
		// returns:
		//	true of the given grid cell is focused
		return (this.cell == inCell) && (this.rowIndex == inRowIndex);
	},
	isLastFocusCell: function(){
		if(this.cell){
			return (this.rowIndex == this.grid.rowCount-1) && (this.cell.index == this.grid.layout.cellCount-1);
		}
		return false;
	},
	isFirstFocusCell: function(){
		if(this.cell){
			return (this.rowIndex === 0) && (this.cell.index === 0);
		}
		return false;
	},
	isNoFocusCell: function(){
		return (this.rowIndex < 0) || !this.cell;
	},
	isNavHeader: function(){
		// summary:
		//	states whether currently navigating among column headers.
		// returns:
		//	true if focus is on a column header; false otherwise. 
		return (!!this._colHeadNode);
	},
	getHeaderIndex: function(){
		// summary:
		//	if one of the column headers currently has focus, return its index.
		// returns:
		//	index of the focused column header, or -1 if none have focus.
		if(this._colHeadNode){
			return dojo.indexOf(this._findHeaderCells(), this._colHeadNode);
		}else{
			return -1;
		}
	},
	_focusifyCellNode: function(inBork){
		var n = this.cell && this.cell.getNode(this.rowIndex);
		if(n){
			dojo.toggleClass(n, this.focusClass, inBork);
			if(inBork){
				var sl = this.scrollIntoView();
				try{
					if(!this.grid.edit.isEditing()){
						dojox.grid.util.fire(n, "focus");
						if(sl){ this.cell.view.scrollboxNode.scrollLeft = sl; }
					}
				}catch(e){}
			}
		}
	},
	_delayedCellFocus: function(){
		if(this.isNavHeader()||!this.grid._focused){
				return;
		}
		var n = this.cell && this.cell.getNode(this.rowIndex);
		if(n){ 
			try{
				if(!this.grid.edit.isEditing()){
					dojo.toggleClass(n, this.focusClass, true);
					this.blurHeader();
					dojox.grid.util.fire(n, "focus");
				}
			} 
			catch(e){}
		}
	},
	_delayedHeaderFocus: function(){
		if(this.isNavHeader()){
			this.focusHeader();
			this.grid.domNode.focus();
		}
	},
	_initColumnHeaders: function(){
		var headers = this._findHeaderCells();
		for(var i = 0; i < headers.length; i++){
			this._connects.push(dojo.connect(headers[i], "onfocus", this, "doColHeaderFocus"));
			this._connects.push(dojo.connect(headers[i], "onblur", this, "doColHeaderBlur"));
		}
	},
	_findHeaderCells: function(){
		// This should be a one liner:
		//	dojo.query("th[tabindex=-1]", this.grid.viewsHeaderNode);
		// But there is a bug in dojo.query() for IE -- see trac #7037.
		var allHeads = dojo.query("th", this.grid.viewsHeaderNode);
		var headers = [];
		for (var i = 0; i < allHeads.length; i++){
			var aHead = allHeads[i];
			var hasTabIdx = dojo.hasAttr(aHead, "tabIndex");
			var tabindex = dojo.attr(aHead, "tabIndex");
			if (hasTabIdx && tabindex < 0) {
				headers.push(aHead);
			}
		}
		return headers;
	},
	_setActiveColHeader: function(/*Node*/colHeaderNode, /*Integer*/colFocusIdx, /*Integer*/ prevColFocusIdx){
		//console.log("setActiveColHeader() - colHeaderNode:colFocusIdx:prevColFocusIdx = " + colHeaderNode + ":" + colFocusIdx + ":" + prevColFocusIdx);
		dojo.attr(this.grid.domNode, "aria-activedescendant",colHeaderNode.id);
		if (prevColFocusIdx != null && prevColFocusIdx >= 0 && prevColFocusIdx != colFocusIdx){
			dojo.toggleClass(this._findHeaderCells()[prevColFocusIdx],this.focusClass,false);
		}
		dojo.toggleClass(colHeaderNode,this.focusClass, true);
		this._colHeadNode = colHeaderNode;
		this._colHeadFocusIdx = colFocusIdx;
		this._scrollHeader(this._colHeadFocusIdx);
	},
	scrollIntoView: function(){
		var info = (this.cell ? this._scrollInfo(this.cell) : null);
		if(!info || !info.s){
			return null;
		}
		var rt = this.grid.scroller.findScrollTop(this.rowIndex);
		// place cell within horizontal view
		if(info.n && info.sr){
			if(info.n.offsetLeft + info.n.offsetWidth > info.sr.l + info.sr.w){
				info.s.scrollLeft = info.n.offsetLeft + info.n.offsetWidth - info.sr.w;
			}else if(info.n.offsetLeft < info.sr.l){
				info.s.scrollLeft = info.n.offsetLeft;
			}
		}
		// place cell within vertical view
		if(info.r && info.sr){
			if(rt + info.r.offsetHeight > info.sr.t + info.sr.h){
				this.grid.setScrollTop(rt + info.r.offsetHeight - info.sr.h);
			}else if(rt < info.sr.t){
				this.grid.setScrollTop(rt);
			}
		}

		return info.s.scrollLeft;
	},
	_scrollInfo: function(cell, domNode){
		if(cell){
			var cl = cell,
				sbn = cl.view.scrollboxNode,
				sbnr = {
					w: sbn.clientWidth,
					l: sbn.scrollLeft,
					t: sbn.scrollTop,
					h: sbn.clientHeight
				},
				rn = cl.view.getRowNode(this.rowIndex);
			return {
				c: cl,
				s: sbn,
				sr: sbnr,
				n: (domNode ? domNode : cell.getNode(this.rowIndex)),
				r: rn
			};
		}
		return null;
	},
	_scrollHeader: function(currentIdx){
		var info = null;
		if(this._colHeadNode){
			var cell = this.grid.getCell(currentIdx);
			info = this._scrollInfo(cell, cell.getNode(0));
		}
		if(info && info.s && info.sr && info.n){
			// scroll horizontally as needed.
			var scroll = info.sr.l + info.sr.w;
			if(info.n.offsetLeft + info.n.offsetWidth > scroll){
				info.s.scrollLeft = info.n.offsetLeft + info.n.offsetWidth - info.sr.w;
			}else if(info.n.offsetLeft < info.sr.l){
				info.s.scrollLeft = info.n.offsetLeft;
			}else if(dojo.isIE <= 7 && cell && cell.view.headerNode){
				// Trac 7158: scroll dojoxGridHeader for IE7 and lower
				cell.view.headerNode.scrollLeft = info.s.scrollLeft;
			}
		}
	},
	_isHeaderHidden: function(){
		// summary:
		//		determine if the grid headers are hidden
		//		relies on documented technique of setting .dojoxGridHeader { display:none; } 
		// returns: Boolean
		//		true if headers are hidden
		//		false if headers are not hidden
		
		var curView = this.focusView;
		if (!curView){
			// find one so we can determine if headers are hidden
			// there is no focusView after adding items to empty grid (test_data_grid_empty.html)
			for (var i = 0, cView; (cView = this.grid.views.views[i]); i++) {
				if(cView.headerNode ){
					curView=cView;
					break;		
				}	
			}
		}
		return (curView && dojo.getComputedStyle(curView.headerNode).display == "none");
	},
	colSizeAdjust: function (e, colIdx, delta){ // adjust the column specified by colIdx by the specified delta px
		var headers = this._findHeaderCells();
		var view = this.focusView;
		if (!view) {
			for (var i = 0, cView; (cView = this.grid.views.views[i]); i++) {
				// find first view with a tableMap in order to work with empty grid
				if(cView.header.tableMap.map ){
					view=cView;
					break;		
				}
			}
		}
		var curHeader = headers[colIdx];
		if (!view || (colIdx == headers.length-1 && colIdx === 0)){
			return; // can't adjust single col. grid
		}	
		view.content.baseDecorateEvent(e);
		// need to adjust event with header cell info since focus is no longer on header cell
		e.cellNode = curHeader; //this.findCellTarget(e.target, e.rowNode);
		e.cellIndex = view.content.getCellNodeIndex(e.cellNode);
		e.cell = (e.cellIndex >= 0 ? this.grid.getCell(e.cellIndex) : null);
		if (view.header.canResize(e)){ 
			var deltaObj = {
				l: delta
			};
			var drag = view.header.colResizeSetup(e,false);
			view.header.doResizeColumn(drag, null, deltaObj);
			view.update();
		}
	},
	styleRow: function(inRow){
		return;
	},
	setFocusIndex: function(inRowIndex, inCellIndex){
		// summary:
		//	focuses the given grid cell
		// inRowIndex: int
		//	grid row index
		// inCellIndex: int
		//	grid cell index
		this.setFocusCell(this.grid.getCell(inCellIndex), inRowIndex);
	},
	setFocusCell: function(inCell, inRowIndex){
		// summary:
		//	focuses the given grid cell
		// inCell: object
		//	grid cell object
		// inRowIndex: int
		//	grid row index
		if(inCell && !this.isFocusCell(inCell, inRowIndex)){
			this.tabbingOut = false;
			if (this._colHeadNode){
				this.blurHeader();
			}
			this._colHeadNode = this._colHeadFocusIdx = null;
			this.focusGridView();
			this._focusifyCellNode(false);
			this.cell = inCell;
			this.rowIndex = inRowIndex;
			this._focusifyCellNode(true);
		}
		// even if this cell isFocusCell, the document focus may need to be rejiggered
		// call opera on delay to prevent keypress from altering focus
		if(dojo.isOpera){
			setTimeout(dojo.hitch(this.grid, 'onCellFocus', this.cell, this.rowIndex), 1);
		}else{
			this.grid.onCellFocus(this.cell, this.rowIndex);
		}
	},
	next: function(){
		// summary:
		//	focus next grid cell
		if(this.cell){
			var row=this.rowIndex, col=this.cell.index+1, cc=this.grid.layout.cellCount-1, rc=this.grid.rowCount-1;
			if(col > cc){
				col = 0;
				row++;
			}
			if(row > rc){
				col = cc;
				row = rc;
			}
			if(this.grid.edit.isEditing()){ //when editing, only navigate to editable cells
				var nextCell = this.grid.getCell(col);
				if (!this.isLastFocusCell() && !nextCell.editable){
					this.cell=nextCell;
					this.rowIndex=row;
					this.next();
					return;
				}
			}
			this.setFocusIndex(row, col);
		}
	},
	previous: function(){
		// summary:
		//	focus previous grid cell
		if(this.cell){
			var row=(this.rowIndex || 0), col=(this.cell.index || 0) - 1;
			if(col < 0){
				col = this.grid.layout.cellCount-1;
				row--;
			}
			if(row < 0){
				row = 0;
				col = 0;
			}
			if(this.grid.edit.isEditing()){ //when editing, only navigate to editable cells
				var prevCell = this.grid.getCell(col);
				if (!this.isFirstFocusCell() && !prevCell.editable){
					this.cell=prevCell;
					this.rowIndex=row;
					this.previous();
					return;
				}
			}
			this.setFocusIndex(row, col);
		}
	},
	move: function(inRowDelta, inColDelta) {
		// summary:
		//	focus grid cell or  simulate focus to column header based on position relative to current focus
		// inRowDelta: int
		// vertical distance from current focus
		// inColDelta: int
		// horizontal distance from current focus

		var colDir = inColDelta < 0 ? -1 : 1;
		// Handle column headers.
		if(this.isNavHeader()){
			var headers = this._findHeaderCells();
			var savedIdx = currentIdx = dojo.indexOf(headers, this._colHeadNode);
			currentIdx += inColDelta;
			while(currentIdx >=0 && currentIdx < headers.length && headers[currentIdx].style.display == "none"){
				// skip over hidden column headers
				currentIdx += colDir;
			}
			if((currentIdx >= 0) && (currentIdx < headers.length)){
				this._setActiveColHeader(headers[currentIdx],currentIdx, savedIdx);
			}
		}else{
			if(this.cell){
				// Handle grid proper.
				var sc = this.grid.scroller,
					r = this.rowIndex,
					rc = this.grid.rowCount-1,
					row = Math.min(rc, Math.max(0, r+inRowDelta));
				if(inRowDelta){
					if(inRowDelta>0){
						if(row > sc.getLastPageRow(sc.page)){
							//need to load additional data, let scroller do that
							this.grid.setScrollTop(this.grid.scrollTop+sc.findScrollTop(row)-sc.findScrollTop(r));
						}
					}else if(inRowDelta<0){
						if(row <= sc.getPageRow(sc.page)){
							//need to load additional data, let scroller do that
							this.grid.setScrollTop(this.grid.scrollTop-sc.findScrollTop(r)-sc.findScrollTop(row));
						}
					}
				}
				var cc = this.grid.layout.cellCount-1,
				i = this.cell.index,
				col = Math.min(cc, Math.max(0, i+inColDelta));
				var cell = this.grid.getCell(col);
				while(col>=0 && col < cc && cell && cell.hidden === true){
					// skip hidden cells
					col += colDir;
					cell = this.grid.getCell(col);
				}
				if (!cell || cell.hidden === true){
					// don't change col if would move to hidden
					col = i;
				}
				this.setFocusIndex(row, col);
				if(inRowDelta){
					this.grid.updateRow(r);
				}
			}
		}
	},
	previousKey: function(e){
		if(this.grid.edit.isEditing()){
			dojo.stopEvent(e);
			this.previous();
		}else if(!this.isNavHeader() && !this._isHeaderHidden()) {
			this.grid.domNode.focus(); // will call doFocus and set focus into header.
			dojo.stopEvent(e);
		}else{
			this.tabOut(this.grid.domNode);
			if (this._colHeadFocusIdx != null) { // clear grid header focus
				dojo.toggleClass(this._findHeaderCells()[this._colHeadFocusIdx], this.focusClass, false);
				this._colHeadFocusIdx = null;
			}
			this._focusifyCellNode(false);
		}
	},
	nextKey: function(e) {
		var isEmpty = (this.grid.rowCount === 0);
		if(e.target === this.grid.domNode && this._colHeadFocusIdx == null){
			this.focusHeader();
			dojo.stopEvent(e);
		}else if(this.isNavHeader()){
			// if tabbing from col header, then go to grid proper. 
			this.blurHeader();
			if(!this.findAndFocusGridCell()){
				this.tabOut(this.grid.lastFocusNode);
			}
			this._colHeadNode = this._colHeadFocusIdx= null;
		}else if(this.grid.edit.isEditing()){
			dojo.stopEvent(e);
			this.next();
		}else{
			this.tabOut(this.grid.lastFocusNode);
		}
	},
	tabOut: function(inFocusNode){
		this.tabbingOut = true;
		inFocusNode.focus();
	},
	focusGridView: function(){
		dojox.grid.util.fire(this.focusView, "focus");
	},
	focusGrid: function(inSkipFocusCell){
		this.focusGridView();
		this._focusifyCellNode(true);
	},
	findAndFocusGridCell: function(){
		// summary:
		//		find the first focusable grid cell 
		// returns: Boolean
		//		true if focus was set to a cell
		//		false if no cell found to set focus onto
		
		var didFocus = true;
		var isEmpty = (this.grid.rowCount === 0); // If grid is empty this.grid.rowCount == 0
		if (this.isNoFocusCell() && !isEmpty){
			var cellIdx = 0;
			var cell = this.grid.getCell(cellIdx);
			if (cell.hidden) {
				// if first cell isn't visible, use _colHeadFocusIdx 
				// could also use a while loop to find first visible cell - not sure that is worth it
				cellIdx = this.isNavHeader() ? this._colHeadFocusIdx : 0;
			}
			this.setFocusIndex(0, cellIdx);
		}
		else if (this.cell && !isEmpty){
			if (this.focusView && !this.focusView.rowNodes[this.rowIndex]){
				// if rowNode for current index is undefined (likely as a result of a sort and because of #7304) 
				// scroll to that row
				this.grid.scrollToRow(this.rowIndex);
			}
			this.focusGrid();
		}else {
			didFocus = false;
		}
		this._colHeadNode = this._colHeadFocusIdx= null;
		return didFocus;
	},
	focusHeader: function(){
		var headerNodes = this._findHeaderCells();
		var saveColHeadFocusIdx = this._colHeadFocusIdx;
		if (this._isHeaderHidden()){
			// grid header is hidden, focus a cell
			this.findAndFocusGridCell();
		}
		else if (!this._colHeadFocusIdx) {
			if (this.isNoFocusCell()) {
				this._colHeadFocusIdx = 0;
			}
			else {
				this._colHeadFocusIdx = this.cell.index;
			}
		}
		this._colHeadNode = headerNodes[this._colHeadFocusIdx];
		while(this._colHeadNode && this._colHeadFocusIdx >=0 && this._colHeadFocusIdx < headerNodes.length &&
				this._colHeadNode.style.display == "none"){
			// skip over hidden column headers
			this._colHeadFocusIdx++;
			this._colHeadNode = headerNodes[this._colHeadFocusIdx];
		}
		if(this._colHeadNode && this._colHeadNode.style.display != "none"){
			// Column header cells know longer receive actual focus.  So, for keyboard invocation of
			// contextMenu to work, the contextMenu must be bound to the grid.domNode rather than the viewsHeaderNode.
			// unbind the contextmenu from the viewsHeaderNode and to the grid when header cells are active.  Reset
			// the binding back to the viewsHeaderNode when header cells are no longer acive (in blurHeader) #10483
			if (this.headerMenu && this._contextMenuBindNode != this.grid.domNode){
				this.headerMenu.unBindDomNode(this.grid.viewsHeaderNode);
				this.headerMenu.bindDomNode(this.grid.domNode);
				this._contextMenuBindNode = this.grid.domNode;
			}
			this._setActiveColHeader(this._colHeadNode, this._colHeadFocusIdx, saveColHeadFocusIdx);
			this._scrollHeader(this._colHeadFocusIdx);
			this._focusifyCellNode(false);
		}else {
			// all col head nodes are hidden - focus the grid
			this.findAndFocusGridCell();
		}
	},
	blurHeader: function(){
		dojo.removeClass(this._colHeadNode, this.focusClass);
		dojo.removeAttr(this.grid.domNode,"aria-activedescendant");
		// reset contextMenu onto viewsHeaderNode so right mouse on header will invoke (see focusHeader)
		if (this.headerMenu && this._contextMenuBindNode == this.grid.domNode) {
			var viewsHeader = this.grid.viewsHeaderNode;
			this.headerMenu.unBindDomNode(this.grid.domNode);
			this.headerMenu.bindDomNode(viewsHeader);
			this._contextMenuBindNode = viewsHeader;
		}
	},
	doFocus: function(e){
		// trap focus only for grid dom node
		if(e && e.target != e.currentTarget){
			dojo.stopEvent(e);
			return;
		}
		// do not focus for scrolling if grid is about to blur
		if(!this.tabbingOut){
			this.focusHeader();
		}
		this.tabbingOut = false;
		dojo.stopEvent(e);
	},
	doBlur: function(e){
		dojo.stopEvent(e);	// FF2
	},
	doContextMenu: function(e){
	//stop contextMenu event if no header Menu to prevent default/browser contextMenu
		if (!this.headerMenu){
			dojo.stopEvent(e); 
		}
	},
	doLastNodeFocus: function(e){
		if (this.tabbingOut){
			this._focusifyCellNode(false);
		}else if(this.grid.rowCount >0){
			if (this.isNoFocusCell()){
				this.setFocusIndex(0,0);
			}
			this._focusifyCellNode(true);
		}else {
			this.focusHeader();
		}
		this.tabbingOut = false;
		dojo.stopEvent(e);	 // FF2
	},
	doLastNodeBlur: function(e){
		dojo.stopEvent(e);	 // FF2
	},
	doColHeaderFocus: function(e){
		this._setActiveColHeader(e.target,dojo.attr(e.target, "idx"),this._colHeadFocusIdx);
		this._scrollHeader(this.getHeaderIndex());
		dojo.stopEvent(e);
	},
	doColHeaderBlur: function(e){
		dojo.toggleClass(e.target, this.focusClass, false);
	}		
});

}

if(!dojo._hasResource["dojox.grid._EditManager"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid._EditManager"] = true;
dojo.provide("dojox.grid._EditManager");



dojo.declare("dojox.grid._EditManager", null, {
	// summary:
	//		Controls grid cell editing process. Owned by grid and used internally for editing.
	constructor: function(inGrid){
		// inGrid: dojox.Grid
		//		The dojox.Grid this editor should be attached to
		this.grid = inGrid;
		this.connections = [];
		if(dojo.isIE){
			this.connections.push(dojo.connect(document.body, "onfocus", dojo.hitch(this, "_boomerangFocus")));
		}
	},
	
	info: {},

	destroy: function(){
		dojo.forEach(this.connections,dojo.disconnect);
	},

	cellFocus: function(inCell, inRowIndex){
		// summary:
		//		Invoke editing when cell is focused
		// inCell: cell object
		//		Grid cell object
		// inRowIndex: Integer
		//		Grid row index
		if(this.grid.singleClickEdit || this.isEditRow(inRowIndex)){
			// if same row or quick editing, edit
			this.setEditCell(inCell, inRowIndex);
		}else{
			// otherwise, apply any pending row edits
			this.apply();
		}
		// if dynamic or static editing...
		if(this.isEditing() || (inCell && inCell.editable && inCell.alwaysEditing)){
			// let the editor focus itself as needed
			this._focusEditor(inCell, inRowIndex);
		}
	},

	rowClick: function(e){
		if(this.isEditing() && !this.isEditRow(e.rowIndex)){
			this.apply();
		}
	},

	styleRow: function(inRow){
		if(inRow.index == this.info.rowIndex){
			inRow.customClasses += ' dojoxGridRowEditing';
		}
	},

	dispatchEvent: function(e){
		var c = e.cell, ed = (c && c["editable"]) ? c : 0;
		return ed && ed.dispatchEvent(e.dispatch, e);
	},

	// Editing
	isEditing: function(){
		// summary:
		//		Indicates editing state of the grid.
		// returns: Boolean
		//	 	True if grid is actively editing
		return this.info.rowIndex !== undefined;
	},

	isEditCell: function(inRowIndex, inCellIndex){
		// summary:
		//		Indicates if the given cell is being edited.
		// inRowIndex: Integer
		//		Grid row index
		// inCellIndex: Integer
		//		Grid cell index
		// returns: Boolean
		//	 	True if given cell is being edited
		return (this.info.rowIndex === inRowIndex) && (this.info.cell.index == inCellIndex);
	},

	isEditRow: function(inRowIndex){
		// summary:
		//		Indicates if the given row is being edited.
		// inRowIndex: Integer
		//		Grid row index
		// returns: Boolean
		//	 	True if given row is being edited
		return this.info.rowIndex === inRowIndex;
	},

	setEditCell: function(inCell, inRowIndex){
		// summary:
		//		Set the given cell to be edited
		// inRowIndex: Integer
		//		Grid row index
		// inCell: Object
		//		Grid cell object
		if(!this.isEditCell(inRowIndex, inCell.index) && this.grid.canEdit && this.grid.canEdit(inCell, inRowIndex)){
			this.start(inCell, inRowIndex, this.isEditRow(inRowIndex) || inCell.editable);
		}
	},

	_focusEditor: function(inCell, inRowIndex){
		dojox.grid.util.fire(inCell, "focus", [inRowIndex]);
	},

	focusEditor: function(){
		if(this.isEditing()){
			this._focusEditor(this.info.cell, this.info.rowIndex);
		}
	},

	// implement fix for focus boomerang effect on IE
	_boomerangWindow: 500,
	_shouldCatchBoomerang: function(){
		return this._catchBoomerang > new Date().getTime();
	},
	_boomerangFocus: function(){
		//console.log("_boomerangFocus");
		if(this._shouldCatchBoomerang()){
			// make sure we don't utterly lose focus
			this.grid.focus.focusGrid();
			// let the editor focus itself as needed
			this.focusEditor();
			// only catch once
			this._catchBoomerang = 0;
		}
	},
	_doCatchBoomerang: function(){
		// give ourselves a few ms to boomerang IE focus effects
		if(dojo.isIE){this._catchBoomerang = new Date().getTime() + this._boomerangWindow;}
	},
	// end boomerang fix API

	start: function(inCell, inRowIndex, inEditing){
		this.grid.beginUpdate();
		this.editorApply();
		if(this.isEditing() && !this.isEditRow(inRowIndex)){
			this.applyRowEdit();
			this.grid.updateRow(inRowIndex);
		}
		if(inEditing){
			this.info = { cell: inCell, rowIndex: inRowIndex };
			this.grid.doStartEdit(inCell, inRowIndex); 
			this.grid.updateRow(inRowIndex);
		}else{
			this.info = {};
		}
		this.grid.endUpdate();
		// make sure we don't utterly lose focus
		this.grid.focus.focusGrid();
		// let the editor focus itself as needed
		this._focusEditor(inCell, inRowIndex);
		// give ourselves a few ms to boomerang IE focus effects
		this._doCatchBoomerang();
	},

	_editorDo: function(inMethod){
		var c = this.info.cell;
		//c && c.editor && c.editor[inMethod](c, this.info.rowIndex);
		if(c && c.editable){
			c[inMethod](this.info.rowIndex);
		}
	},

	editorApply: function(){
		this._editorDo("apply");
	},

	editorCancel: function(){
		this._editorDo("cancel");
	},

	applyCellEdit: function(inValue, inCell, inRowIndex){
		if(this.grid.canEdit(inCell, inRowIndex)){
			this.grid.doApplyCellEdit(inValue, inRowIndex, inCell.field);
		}
	},

	applyRowEdit: function(){
		this.grid.doApplyEdit(this.info.rowIndex, this.info.cell.field);
	},

	apply: function(){
		// summary:
		//		Apply a grid edit
		if(this.isEditing()){
			this.grid.beginUpdate();
			this.editorApply();
			this.applyRowEdit();
			this.info = {};
			this.grid.endUpdate();
			this.grid.focus.focusGrid();
			this._doCatchBoomerang();
		}
	},

	cancel: function(){
		// summary:
		//		Cancel a grid edit
		if(this.isEditing()){
			this.grid.beginUpdate();
			this.editorCancel();
			this.info = {};
			this.grid.endUpdate();
			this.grid.focus.focusGrid();
			this._doCatchBoomerang();
		}
	},

	save: function(inRowIndex, inView){
		// summary:
		//		Save the grid editing state
		// inRowIndex: Integer
		//		Grid row index
		// inView: Object
		//		Grid view
		var c = this.info.cell;
		if(this.isEditRow(inRowIndex) && (!inView || c.view==inView) && c.editable){
			c.save(c, this.info.rowIndex);
		}
	},

	restore: function(inView, inRowIndex){
		// summary:
		//		Restores the grid editing state
		// inRowIndex: Integer
		//		Grid row index
		// inView: Object
		//		Grid view
		var c = this.info.cell;
		if(this.isEditRow(inRowIndex) && c.view == inView && c.editable){
			c.restore(c, this.info.rowIndex);
		}
	}
});

}

if(!dojo._hasResource['dojox.grid.Selection']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['dojox.grid.Selection'] = true;
dojo.provide('dojox.grid.Selection');

dojo.declare("dojox.grid.Selection", null, {
	// summary:
	//		Manages row selection for grid. Owned by grid and used internally
	//		for selection. Override to implement custom selection.

	constructor: function(inGrid){
		this.grid = inGrid;
		this.selected = [];

		this.setMode(inGrid.selectionMode);
	},

	mode: 'extended',

	selected: null,
	updating: 0,
	selectedIndex: -1,

	setMode: function(mode){
		if(this.selected.length){
			this.deselectAll();
		}
		if(mode != 'extended' && mode != 'multiple' && mode != 'single' && mode != 'none'){
			this.mode = 'extended';
		}else{
			this.mode = mode;
		}
	},

	onCanSelect: function(inIndex){
		return this.grid.onCanSelect(inIndex);
	},

	onCanDeselect: function(inIndex){
		return this.grid.onCanDeselect(inIndex);
	},

	onSelected: function(inIndex){
	},

	onDeselected: function(inIndex){
	},

	//onSetSelected: function(inIndex, inSelect) { };
	onChanging: function(){
	},

	onChanged: function(){
	},

	isSelected: function(inIndex){
		if(this.mode == 'none'){
			return false;
		}
		return this.selected[inIndex];
	},

	getFirstSelected: function(){
		if(!this.selected.length||this.mode == 'none'){ return -1; }
		for(var i=0, l=this.selected.length; i<l; i++){
			if(this.selected[i]){
				return i;
			}
		}
		return -1;
	},

	getNextSelected: function(inPrev){
		if(this.mode == 'none'){ return -1; }
		for(var i=inPrev+1, l=this.selected.length; i<l; i++){
			if(this.selected[i]){
				return i;
			}
		}
		return -1;
	},

	getSelected: function(){
		var result = [];
		for(var i=0, l=this.selected.length; i<l; i++){
			if(this.selected[i]){
				result.push(i);
			}
		}
		return result;
	},

	getSelectedCount: function(){
		var c = 0;
		for(var i=0; i<this.selected.length; i++){
			if(this.selected[i]){
				c++;
			}
		}
		return c;
	},

	_beginUpdate: function(){
		if(this.updating === 0){
			this.onChanging();
		}
		this.updating++;
	},

	_endUpdate: function(){
		this.updating--;
		if(this.updating === 0){
			this.onChanged();
		}
	},

	select: function(inIndex){
		if(this.mode == 'none'){ return; }
		if(this.mode != 'multiple'){
			this.deselectAll(inIndex);
			this.addToSelection(inIndex);
		}else{
			this.toggleSelect(inIndex);
		}
	},

	addToSelection: function(inIndex){
		if(this.mode == 'none'){ return; }
		if(dojo.isArray(inIndex)){
			dojo.forEach(inIndex, this.addToSelection, this);
			return;
		}
		inIndex = Number(inIndex);
		if(this.selected[inIndex]){
			this.selectedIndex = inIndex;
		}else{
			if(this.onCanSelect(inIndex) !== false){
				this.selectedIndex = inIndex;
				var rowNode = this.grid.getRowNode(inIndex);
				if(rowNode){
					dojo.attr(rowNode,"aria-selected","true");
				}
				this._beginUpdate();
				this.selected[inIndex] = true;
				//this.grid.onSelected(inIndex);
				this.onSelected(inIndex);
				//this.onSetSelected(inIndex, true);
				this._endUpdate();
			}
		}
	},

	deselect: function(inIndex){
		if(this.mode == 'none'){ return; }
		if(dojo.isArray(inIndex)){
			dojo.forEach(inIndex, this.deselect, this);
			return;
		}
		inIndex = Number(inIndex);
		if(this.selectedIndex == inIndex){
			this.selectedIndex = -1;
		}
		if(this.selected[inIndex]){
			if(this.onCanDeselect(inIndex) === false){
				return;
			}
			var rowNode = this.grid.getRowNode(inIndex);
			if(rowNode){
				dojo.attr(rowNode,"aria-selected","false");
			}
			this._beginUpdate();
			delete this.selected[inIndex];
			//this.grid.onDeselected(inIndex);
			this.onDeselected(inIndex);
			//this.onSetSelected(inIndex, false);
			this._endUpdate();
		}
	},

	setSelected: function(inIndex, inSelect){
		this[(inSelect ? 'addToSelection' : 'deselect')](inIndex);
	},

	toggleSelect: function(inIndex){
		if(dojo.isArray(inIndex)){
			dojo.forEach(inIndex, this.toggleSelect, this);
			return;
		}
		this.setSelected(inIndex, !this.selected[inIndex]);
	},

	_range: function(inFrom, inTo, func){
		var s = (inFrom >= 0 ? inFrom : inTo), e = inTo;
		if(s > e){
			e = s;
			s = inTo;
		}
		for(var i=s; i<=e; i++){
			func(i);
		}
	},

	selectRange: function(inFrom, inTo){
		this._range(inFrom, inTo, dojo.hitch(this, "addToSelection"));
	},

	deselectRange: function(inFrom, inTo){
		this._range(inFrom, inTo, dojo.hitch(this, "deselect"));
	},

	insert: function(inIndex){
		this.selected.splice(inIndex, 0, false);
		if(this.selectedIndex >= inIndex){
			this.selectedIndex++;
		}
	},

	remove: function(inIndex){
		this.selected.splice(inIndex, 1);
		if(this.selectedIndex >= inIndex){
			this.selectedIndex--;
		}
	},

	deselectAll: function(inExcept){
		for(var i in this.selected){
			if((i!=inExcept)&&(this.selected[i]===true)){
				this.deselect(i);
			}
		}
	},

	clickSelect: function(inIndex, inCtrlKey, inShiftKey){
		if(this.mode == 'none'){ return; }
		this._beginUpdate();
		if(this.mode != 'extended'){
			this.select(inIndex);
		}else{
			var lastSelected = this.selectedIndex;
			if(!inCtrlKey){
				this.deselectAll(inIndex);
			}
			if(inShiftKey){
				this.selectRange(lastSelected, inIndex);
			}else if(inCtrlKey){
				this.toggleSelect(inIndex);
			}else{
				this.addToSelection(inIndex);
			}
		}
		this._endUpdate();
	},

	clickSelectEvent: function(e){
		this.clickSelect(e.rowIndex, dojo.isCopyKey(e), e.shiftKey);
	},

	clear: function(){
		this._beginUpdate();
		this.deselectAll();
		this._endUpdate();
	}
});

}

if(!dojo._hasResource["dojox.grid._Events"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid._Events"] = true;
dojo.provide("dojox.grid._Events");

dojo.declare("dojox.grid._Events", null, {
	// summary:
	//		_Grid mixin that provides default implementations for grid events.
	// description: 
	//		Default synthetic events dispatched for _Grid. dojo.connect to events to
	//		retain default implementation or override them for custom handling.
	
	// cellOverClass: String
	// 		css class to apply to grid cells over which the cursor is placed.
	cellOverClass: "dojoxGridCellOver",
	
	onKeyEvent: function(e){
		// summary: top level handler for Key Events
		this.dispatchKeyEvent(e);
	},

	onContentEvent: function(e){
		// summary: Top level handler for Content events
		this.dispatchContentEvent(e);
	},

	onHeaderEvent: function(e){
		// summary: Top level handler for header events
		this.dispatchHeaderEvent(e);
	},

	onStyleRow: function(inRow){
		// summary:
		//		Perform row styling on a given row. Called whenever row styling is updated.
		//
		// inRow: Object
		// 		Object containing row state information: selected, true if the row is selcted; over:
		// 		true of the mouse is over the row; odd: true if the row is odd. Use customClasses and
		// 		customStyles to control row css classes and styles; both properties are strings.
		//
		// example: onStyleRow({ selected: true, over:true, odd:false })
		var i = inRow;
		i.customClasses += (i.odd?" dojoxGridRowOdd":"") + (i.selected?" dojoxGridRowSelected":"") + (i.over?" dojoxGridRowOver":"");
		this.focus.styleRow(inRow);
		this.edit.styleRow(inRow);
	},
	
	onKeyDown: function(e){
		// summary:
		// 		Grid key event handler. By default enter begins editing and applies edits, escape cancels an edit,
		// 		tab, shift-tab, and arrow keys move grid cell focus.
		if(e.altKey || e.metaKey){
			return;
		}
		var dk = dojo.keys;
		var colIdx;
		switch(e.keyCode){
			case dk.ESCAPE:
				this.edit.cancel();
				break;
			case dk.ENTER:
				if(!this.edit.isEditing()){
					colIdx = this.focus.getHeaderIndex();
					if(colIdx >= 0) {
						this.setSortIndex(colIdx);
						break;
					}else {
						this.selection.clickSelect(this.focus.rowIndex, dojo.isCopyKey(e), e.shiftKey);
					}
					dojo.stopEvent(e);
				}
				if(!e.shiftKey){
					var isEditing = this.edit.isEditing();
					this.edit.apply();
					if(!isEditing){
						this.edit.setEditCell(this.focus.cell, this.focus.rowIndex);
					}
				}
				if (!this.edit.isEditing()){
					var curView = this.focus.focusView || this.views.views[0];  //if no focusView than only one view
					curView.content.decorateEvent(e);
					this.onRowClick(e);
				}
				break;
			case dk.SPACE:
				if(!this.edit.isEditing()){
					colIdx = this.focus.getHeaderIndex();
					if(colIdx >= 0) {
						this.setSortIndex(colIdx);
						break;
					}else {
						this.selection.clickSelect(this.focus.rowIndex, dojo.isCopyKey(e), e.shiftKey);
					}
					dojo.stopEvent(e);
				}
				break;
			case dk.TAB:
				this.focus[e.shiftKey ? 'previousKey' : 'nextKey'](e);
				break;
			case dk.LEFT_ARROW:
			case dk.RIGHT_ARROW:
				if(!this.edit.isEditing()){
					var keyCode = e.keyCode;  // IE seems to lose after stopEvent when modifier keys
					dojo.stopEvent(e);
					colIdx = this.focus.getHeaderIndex();
					if (colIdx >= 0 && (e.shiftKey && e.ctrlKey)){
						this.focus.colSizeAdjust(e, colIdx, (keyCode == dk.LEFT_ARROW ? -1 : 1)*5);
					}
					else{
						var offset = (keyCode == dk.LEFT_ARROW) ? 1 : -1;
						if(dojo._isBodyLtr()){ offset *= -1; }
						this.focus.move(0, offset);
					}
				}
				break;
			case dk.UP_ARROW:
				if(!this.edit.isEditing() && this.focus.rowIndex !== 0){
					dojo.stopEvent(e);
					this.focus.move(-1, 0);
				}
				break;
			case dk.DOWN_ARROW:
				if(!this.edit.isEditing() && this.focus.rowIndex+1 != this.rowCount){
					dojo.stopEvent(e);
					this.focus.move(1, 0);
				}
				break;
			case dk.PAGE_UP:
				if(!this.edit.isEditing() && this.focus.rowIndex !== 0){
					dojo.stopEvent(e);
					if(this.focus.rowIndex != this.scroller.firstVisibleRow+1){
						this.focus.move(this.scroller.firstVisibleRow-this.focus.rowIndex, 0);
					}else{
						this.setScrollTop(this.scroller.findScrollTop(this.focus.rowIndex-1));
						this.focus.move(this.scroller.firstVisibleRow-this.scroller.lastVisibleRow+1, 0);
					}
				}
				break;
			case dk.PAGE_DOWN:
				if(!this.edit.isEditing() && this.focus.rowIndex+1 != this.rowCount){
					dojo.stopEvent(e);
					if(this.focus.rowIndex != this.scroller.lastVisibleRow-1){
						this.focus.move(this.scroller.lastVisibleRow-this.focus.rowIndex-1, 0);
					}else{
						this.setScrollTop(this.scroller.findScrollTop(this.focus.rowIndex+1));
						this.focus.move(this.scroller.lastVisibleRow-this.scroller.firstVisibleRow-1, 0);
					}
				}
				break;
			default:
				break;
		}
	},
	
	onMouseOver: function(e){
		// summary:
		//		Event fired when mouse is over the grid.
		// e: Event
		//		Decorated event object contains reference to grid, cell, and rowIndex
		e.rowIndex == -1 ? this.onHeaderCellMouseOver(e) : this.onCellMouseOver(e);
	},
	
	onMouseOut: function(e){
		// summary:
		//		Event fired when mouse moves out of the grid.
		// e: Event
		//		Decorated event object that contains reference to grid, cell, and rowIndex
		e.rowIndex == -1 ? this.onHeaderCellMouseOut(e) : this.onCellMouseOut(e);
	},
	
	onMouseDown: function(e){
		// summary:
		//		Event fired when mouse is down inside grid.
		// e: Event
		//		Decorated event object that contains reference to grid, cell, and rowIndex
		e.rowIndex == -1 ? this.onHeaderCellMouseDown(e) : this.onCellMouseDown(e);
	},
	
	onMouseOverRow: function(e){
		// summary:
		//		Event fired when mouse is over any row (data or header).
		// e: Event
		//		Decorated event object contains reference to grid, cell, and rowIndex
		if(!this.rows.isOver(e.rowIndex)){
			this.rows.setOverRow(e.rowIndex);
			e.rowIndex == -1 ? this.onHeaderMouseOver(e) : this.onRowMouseOver(e);
		}
	},
	onMouseOutRow: function(e){
		// summary:
		//		Event fired when mouse moves out of any row (data or header).
		// e: Event
		//		Decorated event object contains reference to grid, cell, and rowIndex
		if(this.rows.isOver(-1)){
			this.onHeaderMouseOut(e);
		}else if(!this.rows.isOver(-2)){
			this.rows.setOverRow(-2);
			this.onRowMouseOut(e);
		}
	},
	
	onMouseDownRow: function(e){
		// summary:
		//		Event fired when mouse is down inside grid row
		// e: Event
		//		Decorated event object that contains reference to grid, cell, and rowIndex
		if(e.rowIndex != -1)
			this.onRowMouseDown(e);
	},

	// cell events
	onCellMouseOver: function(e){
		// summary:
		//		Event fired when mouse is over a cell.
		// e: Event
		//		Decorated event object contains reference to grid, cell, and rowIndex
		if(e.cellNode){
			dojo.addClass(e.cellNode, this.cellOverClass);
		}
	},
	
	onCellMouseOut: function(e){
		// summary:
		//		Event fired when mouse moves out of a cell.
		// e: Event
		//		Decorated event object which contains reference to grid, cell, and rowIndex
		if(e.cellNode){
			dojo.removeClass(e.cellNode, this.cellOverClass);
		}
	},
	
	onCellMouseDown: function(e){
		// summary:
		//		Event fired when mouse is down in a header cell.
		// e: Event
		// 		Decorated event object which contains reference to grid, cell, and rowIndex
	},

	onCellClick: function(e){
		// summary:
		//		Event fired when a cell is clicked.
		// e: Event
		//		Decorated event object which contains reference to grid, cell, and rowIndex
		this._click[0] = this._click[1];
		this._click[1] = e;
		if(!this.edit.isEditCell(e.rowIndex, e.cellIndex)){
			this.focus.setFocusCell(e.cell, e.rowIndex);
		}
		this.onRowClick(e);
	},

	onCellDblClick: function(e){
		// summary:
		//		Event fired when a cell is double-clicked.
		// e: Event
		//		Decorated event object contains reference to grid, cell, and rowIndex
		if(this._click.length > 1 && dojo.isIE){
			this.edit.setEditCell(this._click[1].cell, this._click[1].rowIndex);
		}else if(this._click.length > 1 && this._click[0].rowIndex != this._click[1].rowIndex){
			this.edit.setEditCell(this._click[0].cell, this._click[0].rowIndex);
		}else{
			this.edit.setEditCell(e.cell, e.rowIndex);
		}
		this.onRowDblClick(e);
	},

	onCellContextMenu: function(e){
		// summary:
		//		Event fired when a cell context menu is accessed via mouse right click.
		// e: Event
		//		Decorated event object which contains reference to grid, cell, and rowIndex
		this.onRowContextMenu(e);
	},

	onCellFocus: function(inCell, inRowIndex){
		// summary:
		//		Event fired when a cell receives focus.
		// inCell: Object
		//		Cell object containing properties of the grid column.
		// inRowIndex: Integer
		//		Index of the grid row
		this.edit.cellFocus(inCell, inRowIndex);
	},

	// row events
	onRowClick: function(e){
		// summary:
		//		Event fired when a row is clicked.
		// e: Event
		//		Decorated event object which contains reference to grid, cell, and rowIndex
		this.edit.rowClick(e);
		this.selection.clickSelectEvent(e);
	},

	onRowDblClick: function(e){
		// summary:
		//		Event fired when a row is double clicked.
		// e: Event
		//		decorated event object which contains reference to grid, cell, and rowIndex
	},

	onRowMouseOver: function(e){
		// summary:
		//		Event fired when mouse moves over a data row.
		// e: Event
		//		Decorated event object which contains reference to grid, cell, and rowIndex
	},

	onRowMouseOut: function(e){
		// summary:
		//		Event fired when mouse moves out of a data row.
		// e: Event
		// 		Decorated event object contains reference to grid, cell, and rowIndex
	},
	
	onRowMouseDown: function(e){
		// summary:
		//		Event fired when mouse is down in a row.
		// e: Event
		// 		Decorated event object which contains reference to grid, cell, and rowIndex
	},

	onRowContextMenu: function(e){
		// summary:
		//		Event fired when a row context menu is accessed via mouse right click.
		// e: Event
		// 		Decorated event object which contains reference to grid, cell, and rowIndex
		dojo.stopEvent(e);
	},

	// header events
	onHeaderMouseOver: function(e){
		// summary:
		//		Event fired when mouse moves over the grid header.
		// e: Event
		// 		Decorated event object contains reference to grid, cell, and rowIndex
	},

	onHeaderMouseOut: function(e){
		// summary:
		//		Event fired when mouse moves out of the grid header.
		// e: Event
		// 		Decorated event object which contains reference to grid, cell, and rowIndex
	},

	onHeaderCellMouseOver: function(e){
		// summary:
		//		Event fired when mouse moves over a header cell.
		// e: Event
		// 		Decorated event object which contains reference to grid, cell, and rowIndex
		if(e.cellNode){
			dojo.addClass(e.cellNode, this.cellOverClass);
		}
	},

	onHeaderCellMouseOut: function(e){
		// summary:
		//		Event fired when mouse moves out of a header cell.
		// e: Event
		// 		Decorated event object which contains reference to grid, cell, and rowIndex
		if(e.cellNode){
			dojo.removeClass(e.cellNode, this.cellOverClass);
		}
	},
	
	onHeaderCellMouseDown: function(e) {
		// summary:
		//		Event fired when mouse is down in a header cell.
		// e: Event
		// 		Decorated event object which contains reference to grid, cell, and rowIndex
	},

	onHeaderClick: function(e){
		// summary:
		//		Event fired when the grid header is clicked.
		// e: Event
		// Decorated event object which contains reference to grid, cell, and rowIndex
	},

	onHeaderCellClick: function(e){
		// summary:
		//		Event fired when a header cell is clicked.
		// e: Event
		//		Decorated event object which contains reference to grid, cell, and rowIndex
		this.setSortIndex(e.cell.index);
		this.onHeaderClick(e);
	},

	onHeaderDblClick: function(e){
		// summary:
		//		Event fired when the grid header is double clicked.
		// e: Event
		//		Decorated event object which contains reference to grid, cell, and rowIndex
	},

	onHeaderCellDblClick: function(e){
		// summary:
		//		Event fired when a header cell is double clicked.
		// e: Event
		//		Decorated event object which contains reference to grid, cell, and rowIndex
		this.onHeaderDblClick(e);
	},

	onHeaderCellContextMenu: function(e){
		// summary:
		//		Event fired when a header cell context menu is accessed via mouse right click.
		// e: Event
		//		Decorated event object which contains reference to grid, cell, and rowIndex
		this.onHeaderContextMenu(e);
	},

	onHeaderContextMenu: function(e){
		// summary:
		//		Event fired when the grid header context menu is accessed via mouse right click.
		// e: Event
		//		Decorated event object which contains reference to grid, cell, and rowIndex
		if(!this.headerMenu){
			dojo.stopEvent(e);
		}
	},

	// editing
	onStartEdit: function(inCell, inRowIndex){
		// summary:
		//		Event fired when editing is started for a given grid cell
		// inCell: Object
		//		Cell object containing properties of the grid column.
		// inRowIndex: Integer
		//		Index of the grid row
	},

	onApplyCellEdit: function(inValue, inRowIndex, inFieldIndex){
		// summary:
		//		Event fired when editing is applied for a given grid cell
		// inValue: String
		//		Value from cell editor
		// inRowIndex: Integer
		//		Index of the grid row
		// inFieldIndex: Integer
		//		Index in the grid's data store
	},

	onCancelEdit: function(inRowIndex){
		// summary:
		//		Event fired when editing is cancelled for a given grid cell
		// inRowIndex: Integer
		//		Index of the grid row
	},

	onApplyEdit: function(inRowIndex){
		// summary:
		//		Event fired when editing is applied for a given grid row
		// inRowIndex: Integer
		//		Index of the grid row
	},

	onCanSelect: function(inRowIndex){
		// summary:
		//		Event to determine if a grid row may be selected
		// inRowIndex: Integer
		//		Index of the grid row
		// returns: Boolean
		//		true if the row can be selected
		return true;
	},

	onCanDeselect: function(inRowIndex){
		// summary:
		//		Event to determine if a grid row may be deselected
		// inRowIndex: Integer
		//		Index of the grid row
		// returns: Boolean
		//		true if the row can be deselected
		return true;
	},

	onSelected: function(inRowIndex){
		// summary:
		//		Event fired when a grid row is selected
		// inRowIndex: Integer
		//		Index of the grid row
		this.updateRowStyles(inRowIndex);
	},

	onDeselected: function(inRowIndex){
		// summary:
		//		Event fired when a grid row is deselected
		// inRowIndex: Integer
		//		Index of the grid row
		this.updateRowStyles(inRowIndex);
	},

	onSelectionChanged: function(){
	}
});

}

if(!dojo._hasResource["dojox.grid._Grid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid._Grid"] = true;
dojo.provide("dojox.grid._Grid");




















(function(){
	// NOTE: this is for backwards compatibility with Dojo 1.3
	if(!dojo.isCopyKey){
		dojo.isCopyKey = dojo.dnd.getCopyKeyState;
	}
	/*=====
	dojox.grid.__CellDef = function(){
		//	name: String?
		//		The text to use in the header of the grid for this cell.
		//	get: Function?
		//		function(rowIndex){} rowIndex is of type Integer.  This
		//		function will be called when a cell	requests data.  Returns the
		//		unformatted data for the cell.
		//	value: String?
		//		If "get" is not specified, this is used as the data for the cell.
		//	defaultValue: String?
		//		If "get" and "value" aren't specified or if "get" returns an undefined
		//		value, this is used as the data for the cell.  "formatter" is not run
		//		on this if "get" returns an undefined value.
		//	formatter: Function?
		//		function(data, rowIndex){} data is of type anything, rowIndex
		//		is of type Integer.  This function will be called after the cell
		//		has its data but before it passes it back to the grid to render.
		//		Returns the formatted version of the cell's data.
		//	type: dojox.grid.cells._Base|Function?
		//		TODO
		//	editable: Boolean?
		//		Whether this cell should be editable or not.
		//	hidden: Boolean?
		//		If true, the cell will not be displayed.
		//	noresize: Boolean?
		//		If true, the cell will not be able to be resized.
		//	width: Integer|String?
		//		A CSS size.  If it's an Integer, the width will be in em's.
		//	colSpan: Integer?
		//		How many columns to span this cell.  Will not work in the first
		//		sub-row of cells.
		//	rowSpan: Integer?
		//		How many sub-rows to span this cell.
		//	styles: String?
		//		A string of styles to apply to both the header cell and main
		//		grid cells.  Must end in a ';'.
		//	headerStyles: String?
		//		A string of styles to apply to just the header cell.  Must end
		//		in a ';'
		//	cellStyles: String?
		//		A string of styles to apply to just the main grid cells.  Must
		//		end in a ';'
		//	classes: String?
		//		A space separated list of classes to apply to both the header
		//		cell and the main grid cells.
		//	headerClasses: String?
		//		A space separated list of classes to apply to just the header
		//		cell.
		//	cellClasses: String?
		//		A space separated list of classes to apply to just the main
		//		grid cells.
		//	attrs: String?
		//		A space separated string of attribute='value' pairs to add to
		//		the header cell element and main grid cell elements.
		this.name = name;
		this.value = value;
		this.get = get;
		this.formatter = formatter;
		this.type = type;
		this.editable = editable;
		this.hidden = hidden;
		this.width = width;
		this.colSpan = colSpan;
		this.rowSpan = rowSpan;
		this.styles = styles;
		this.headerStyles = headerStyles;
		this.cellStyles = cellStyles;
		this.classes = classes;
		this.headerClasses = headerClasses;
		this.cellClasses = cellClasses;
		this.attrs = attrs;
	}
	=====*/

	/*=====
	dojox.grid.__ViewDef = function(){
		//	noscroll: Boolean?
		//		If true, no scrollbars will be rendered without scrollbars.
		//	width: Integer|String?
		//		A CSS size.  If it's an Integer, the width will be in em's. If
		//		"noscroll" is true, this value is ignored.
		//	cells: dojox.grid.__CellDef[]|Array[dojox.grid.__CellDef[]]?
		//		The structure of the cells within this grid.
		//	type: String?
		//		A string containing the constructor of a subclass of
		//		dojox.grid._View.  If this is not specified, dojox.grid._View
		//		is used.
		//	defaultCell: dojox.grid.__CellDef?
		//		A cell definition with default values for all cells in this view.  If
		//		a property is defined in a cell definition in the "cells" array and
		//		this property, the cell definition's property will override this
		//		property's property.
		//	onBeforeRow: Function?
		//		function(rowIndex, cells){} rowIndex is of type Integer, cells
		//		is of type Array[dojox.grid.__CellDef[]].  This function is called
		//		before each row of data is rendered.  Before the header is
		//		rendered, rowIndex will be -1.  "cells" is a reference to the
		//		internal structure of this view's cells so any changes you make to
		//		it will persist between calls.
		//	onAfterRow: Function?
		//		function(rowIndex, cells, rowNode){} rowIndex is of type Integer, cells
		//		is of type Array[dojox.grid.__CellDef[]], rowNode is of type DOMNode.
		//		This function is called	after each row of data is rendered.  After the
		//		header is rendered, rowIndex will be -1.  "cells" is a reference to the
		//		internal structure of this view's cells so any changes you make to
		//		it will persist between calls.
		this.noscroll = noscroll;
		this.width = width;
		this.cells = cells;
		this.type = type;
		this.defaultCell = defaultCell;
		this.onBeforeRow = onBeforeRow;
		this.onAfterRow = onAfterRow;
	}
	=====*/

	dojo.declare('dojox.grid._Grid',
		[ dijit._Widget, dijit._Templated, dojox.grid._Events ],
		{
		// summary:
		// 		A grid widget with virtual scrolling, cell editing, complex rows,
		// 		sorting, fixed columns, sizeable columns, etc.
		//
		//	description:
		//		_Grid provides the full set of grid features without any
		//		direct connection to a data store.
		//
		//		The grid exposes a get function for the grid, or optionally
		//		individual columns, to populate cell contents.
		//
		//		The grid is rendered based on its structure, an object describing
		//		column and cell layout.
		//
		//	example:
		//		A quick sample:
		//
		//		define a get function
		//	|	function get(inRowIndex){ // called in cell context
		//	|		return [this.index, inRowIndex].join(', ');
		//	|	}
		//
		//		define the grid structure:
		//	|	var structure = [ // array of view objects
		//	|		{ cells: [// array of rows, a row is an array of cells
		//	|			[
		//	|				{ name: "Alpha", width: 6 },
		//	|				{ name: "Beta" },
		//	|				{ name: "Gamma", get: get }]
		//	|		]}
		//	|	];
		//
		//	|	<div id="grid"
		//	|		rowCount="100" get="get"
		//	|		structure="structure"
		//	|		dojoType="dojox.grid._Grid"></div>

		templateString:"<div hidefocus=\"hidefocus\" wairole=\"grid\" dojoAttachEvent=\"onmouseout:_mouseOut\">\n\t<div class=\"dojoxGridMasterHeader\" dojoAttachPoint=\"viewsHeaderNode\" wairole=\"presentation\"></div>\n\t<div class=\"dojoxGridMasterView\" dojoAttachPoint=\"viewsNode\" wairole=\"presentation\"></div>\n\t<div class=\"dojoxGridMasterMessages\" style=\"display: none;\" dojoAttachPoint=\"messagesNode\"></div>\n\t<span dojoAttachPoint=\"lastFocusNode\" tabindex=\"0\"></span>\n</div>\n",

		// classTag: String
		// 		CSS class applied to the grid's domNode
		classTag: 'dojoxGrid',

		// settings
		// rowCount: Integer
		//		Number of rows to display.
		rowCount: 5,

		// keepRows: Integer
		//		Number of rows to keep in the rendering cache.
		keepRows: 75,

		// rowsPerPage: Integer
		//		Number of rows to render at a time.
		rowsPerPage: 25,

		// autoWidth: Boolean
		//		If autoWidth is true, grid width is automatically set to fit the data.
		autoWidth: false,
		
		// initialWidth: String
		//		A css string to use to set our initial width (only used if autoWidth
		//		is true).  The first rendering of the grid will be this width, any
		//		resizing of columns, etc will result in the grid switching to 
		//		autoWidth mode.  Note, this width will override any styling in a
		//		stylesheet or directly on the node.
		initialWidth: "",

		// autoHeight: Boolean|Integer
		//		If autoHeight is true, grid height is automatically set to fit the data.
		//		If it is an integer, the height will be automatically set to fit the data
		//		if there are fewer than that many rows - and the height will be set to show
		//		that many rows if there are more
		autoHeight: '',

		// rowHeight: Integer
		//		If rowHeight is set to a positive number, it will define the height of the rows
		//		in pixels. This can provide a significant performance advantage, since it
		//		eliminates the need to measure row sizes during rendering, which is one
		// 		the primary bottlenecks in the DataGrid's performance. 
		rowHeight: 0,
		
		// autoRender: Boolean
		//		If autoRender is true, grid will render itself after initialization.
		autoRender: true,

		// defaultHeight: String
		//		default height of the grid, measured in any valid css unit.
		defaultHeight: '15em',
		
		// height: String
		//		explicit height of the grid, measured in any valid css unit.  This will be populated (and overridden)
		//		if the height: css attribute exists on the source node.
		height: '',

		// structure: dojox.grid.__ViewDef|dojox.grid.__ViewDef[]|dojox.grid.__CellDef[]|Array[dojox.grid.__CellDef[]]
		//		View layout defintion.
		structure: null,

		// elasticView: Integer
		//	Override defaults and make the indexed grid view elastic, thus filling available horizontal space.
		elasticView: -1,

		// singleClickEdit: boolean
		//		Single-click starts editing. Default is double-click
		singleClickEdit: false,

		// selectionMode: String
		//		Set the selection mode of grid's Selection.  Value must be 'single', 'multiple',
		//		or 'extended'.  Default is 'extended'.
		selectionMode: 'extended',

		// rowSelector: Boolean|String
		// 		If set to true, will add a row selector view to this grid.  If set to a CSS width, will add
		// 		a row selector of that width to this grid.
		rowSelector: '',

		// columnReordering: Boolean
		// 		If set to true, will add drag and drop reordering to views with one row of columns.
		columnReordering: false,

		// headerMenu: dijit.Menu
		// 		If set to a dijit.Menu, will use this as a context menu for the grid headers.
		headerMenu: null,

		// placeholderLabel: String
		// 		Label of placeholders to search for in the header menu to replace with column toggling
		// 		menu items.
		placeholderLabel: "GridColumns",
		
		// selectable: Boolean
		//		Set to true if you want to be able to select the text within the grid.
		selectable: false,
		
		// Used to store the last two clicks, to ensure double-clicking occurs based on the intended row
		_click: null,
		
		// loadingMessage: String
		//  Message that shows while the grid is loading
		loadingMessage: "<span class='dojoxGridLoading'>${loadingState}</span>",

		// errorMessage: String
		//  Message that shows when the grid encounters an error loading
		errorMessage: "<span class='dojoxGridError'>${errorState}</span>",

		// noDataMessage: String
		//  Message that shows if the grid has no data - wrap it in a 
		//  span with class 'dojoxGridNoData' if you want it to be
		//  styled similar to the loading and error messages
		noDataMessage: "",
		
		// escapeHTMLInData: Boolean
		//		This will escape HTML brackets from the data to prevent HTML from 
		// 		user-inputted data being rendered with may contain JavaScript and result in 
		// 		XSS attacks. This is true by default, and it is recommended that it remain 
		// 		true. Setting this to false will allow data to be displayed in the grid without 
		// 		filtering, and should be only used if it is known that the data won't contain 
		// 		malicious scripts. If HTML is needed in grid cells, it is recommended that 
		// 		you use the formatter function to generate the HTML (the output of 
		// 		formatter functions is not filtered, even with escapeHTMLInData set to true).
		escapeHTMLInData: true,	
		
		// formatterScope: Object
		//		An object to execute format functions within.  If not set, the
		//		format functions will execute within the scope of the cell that
		//		has a format function.
		formatterScope: null,
		
		// editable: boolean
		// indicates if the grid contains editable cells, default is false
		// set to true if editable cell encountered during rendering 
		editable: false,
		
		// private
		sortInfo: 0,
		themeable: true,
		_placeholders: null,

		// _layoutClass: Object
		//	The class to use for our layout - can be overridden by grid subclasses
		_layoutClass: dojox.grid._Layout,

		// initialization
		buildRendering: function(){
			this.inherited(arguments);
			if(!this.domNode.getAttribute('tabIndex')){
				this.domNode.tabIndex = "0";
			}
			this.createScroller();
			this.createLayout();
			this.createViews();
			this.createManagers();

			this.createSelection();

			this.connect(this.selection, "onSelected", "onSelected");
			this.connect(this.selection, "onDeselected", "onDeselected");
			this.connect(this.selection, "onChanged", "onSelectionChanged");

			dojox.html.metrics.initOnFontResize();
			this.connect(dojox.html.metrics, "onFontResize", "textSizeChanged");
			dojox.grid.util.funnelEvents(this.domNode, this, 'doKeyEvent', dojox.grid.util.keyEvents);
			if (this.selectionMode != "none") {
				dojo.attr(this.domNode, "aria-multiselectable", this.selectionMode == "single" ? "false" : "true");
			}

			dojo.addClass(this.domNode, this.classTag);
			if(!this.isLeftToRight()){
				dojo.addClass(this.domNode, this.classTag+"Rtl");
			}
		},
		
		postMixInProperties: function(){
			this.inherited(arguments);
			var messages = dojo.i18n.getLocalization("dijit", "loading", this.lang);
			this.loadingMessage = dojo.string.substitute(this.loadingMessage, messages);
			this.errorMessage = dojo.string.substitute(this.errorMessage, messages);
			if(this.srcNodeRef && this.srcNodeRef.style.height){
				this.height = this.srcNodeRef.style.height;
			}
			// Call this to update our autoheight to start out
			this._setAutoHeightAttr(this.autoHeight, true);
			this.lastScrollTop = this.scrollTop = 0;
		},
		
		postCreate: function(){
			this._placeholders = [];
			this._setHeaderMenuAttr(this.headerMenu);
			this._setStructureAttr(this.structure);
			this._click = [];
			this.inherited(arguments);
			if(this.domNode && this.autoWidth && this.initialWidth){
				this.domNode.style.width = this.initialWidth;
			}
			if (this.domNode && !this.editable){
				// default value for aria-readonly is false, set to true if grid is not editable
				dojo.attr(this.domNode,"aria-readonly", "true");
			}
		},

		destroy: function(){
			this.domNode.onReveal = null;
			this.domNode.onSizeChange = null;

			// Fixes IE domNode leak
			delete this._click;

			this.edit.destroy();
			delete this.edit;

			this.views.destroyViews();
			if(this.scroller){
				this.scroller.destroy();
				delete this.scroller;
			}
			if(this.focus){
				this.focus.destroy();
				delete this.focus;
			}
			if(this.headerMenu&&this._placeholders.length){
				dojo.forEach(this._placeholders, function(p){ p.unReplace(true); });
				this.headerMenu.unBindDomNode(this.viewsHeaderNode);
			}
			this.inherited(arguments);
		},

		_setAutoHeightAttr: function(ah, skipRender){
			// Calculate our autoheight - turn it into a boolean or an integer
			if(typeof ah == "string"){
				if(!ah || ah == "false"){
					ah = false;
				}else if (ah == "true"){
					ah = true;
				}else{
					ah = window.parseInt(ah, 10);
				}
			}
			if(typeof ah == "number"){
				if(isNaN(ah)){
					ah = false;
				}
				// Autoheight must be at least 1, if it's a number.  If it's
				// less than 0, we'll take that to mean "all" rows (same as 
				// autoHeight=true - if it is equal to zero, we'll take that
				// to mean autoHeight=false
				if(ah < 0){
					ah = true;
				}else if (ah === 0){
					ah = false;
				}
			}
			this.autoHeight = ah;
			if(typeof ah == "boolean"){
				this._autoHeight = ah;
			}else if(typeof ah == "number"){
				this._autoHeight = (ah >= this.get('rowCount'));
			}else{
				this._autoHeight = false;
			}
			if(this._started && !skipRender){
				this.render();
			}
		},

		_getRowCountAttr: function(){
			return this.updating && this.invalidated && this.invalidated.rowCount != undefined ?
				this.invalidated.rowCount : this.rowCount;
		},
		
		textSizeChanged: function(){
			this.render();
		},

		sizeChange: function(){
			this.update();
		},

		createManagers: function(){
			// summary:
			//		create grid managers for various tasks including rows, focus, selection, editing

			// row manager
			this.rows = new dojox.grid._RowManager(this);
			// focus manager
			this.focus = new dojox.grid._FocusManager(this);
			// edit manager
			this.edit = new dojox.grid._EditManager(this);
		},

		createSelection: function(){
			// summary:	Creates a new Grid selection manager.

			// selection manager
			this.selection = new dojox.grid.Selection(this);
		},

		createScroller: function(){
			// summary: Creates a new virtual scroller
			this.scroller = new dojox.grid._Scroller();
			this.scroller.grid = this;
			this.scroller.renderRow = dojo.hitch(this, "renderRow");
			this.scroller.removeRow = dojo.hitch(this, "rowRemoved");
		},

		createLayout: function(){
			// summary: Creates a new Grid layout
			this.layout = new this._layoutClass(this);
			this.connect(this.layout, "moveColumn", "onMoveColumn");
		},

		onMoveColumn: function(){
			this.render();
		},
		
		onResizeColumn: function(/*int*/ cellIdx){
			// Called when a column is resized.
		},

		// views
		createViews: function(){
			this.views = new dojox.grid._ViewManager(this);
			this.views.createView = dojo.hitch(this, "createView");
		},

		createView: function(inClass, idx){
			var c = dojo.getObject(inClass);
			var view = new c({ grid: this, index: idx });
			this.viewsNode.appendChild(view.domNode);
			this.viewsHeaderNode.appendChild(view.headerNode);
			this.views.addView(view);
			return view;
		},

		buildViews: function(){
			for(var i=0, vs; (vs=this.layout.structure[i]); i++){
				this.createView(vs.type || dojox._scopeName + ".grid._View", i).setStructure(vs);
			}
			this.scroller.setContentNodes(this.views.getContentNodes());
		},

		_setStructureAttr: function(structure){
			var s = structure;
			if(s && dojo.isString(s)){
				dojo.deprecated("dojox.grid._Grid.attr('structure', 'objVar')", "use dojox.grid._Grid.attr('structure', objVar) instead", "2.0");
				s=dojo.getObject(s);
			}
			this.structure = s;
			if(!s){
				if(this.layout.structure){
					s = this.layout.structure;
				}else{
					return;
				}
			}
			this.views.destroyViews();
			if(s !== this.layout.structure){
				this.layout.setStructure(s);
			}
			this._structureChanged();
		},

		setStructure: function(/* dojox.grid.__ViewDef|dojox.grid.__ViewDef[]|dojox.grid.__CellDef[]|Array[dojox.grid.__CellDef[]] */ inStructure){
			// summary:
			//		Install a new structure and rebuild the grid.
			dojo.deprecated("dojox.grid._Grid.setStructure(obj)", "use dojox.grid._Grid.attr('structure', obj) instead.", "2.0");
			this._setStructureAttr(inStructure);
		},
		
		getColumnTogglingItems: function(){
			// Summary: returns an array of dijit.CheckedMenuItem widgets that can be
			//		added to a menu for toggling columns on and off.
			return dojo.map(this.layout.cells, function(cell){
				if(!cell.menuItems){ cell.menuItems = []; }

				var self = this;
				var item = new dijit.CheckedMenuItem({
					label: cell.name,
					checked: !cell.hidden,
					_gridCell: cell,
					onChange: function(checked){
						if(self.layout.setColumnVisibility(this._gridCell.index, checked)){
							var items = this._gridCell.menuItems;
							if(items.length > 1){
								dojo.forEach(items, function(item){
									if(item !== this){
										item.setAttribute("checked", checked);
									}
								}, this);
							}
							checked = dojo.filter(self.layout.cells, function(c){
								if(c.menuItems.length > 1){
									dojo.forEach(c.menuItems, "item.attr('disabled', false);");
								}else{
									c.menuItems[0].attr('disabled', false);
								}
								return !c.hidden;
							});
							if(checked.length == 1){
								dojo.forEach(checked[0].menuItems, "item.attr('disabled', true);");
							}
						}
					},
					destroy: function(){
						var index = dojo.indexOf(this._gridCell.menuItems, this);
						this._gridCell.menuItems.splice(index, 1);
						delete this._gridCell;
						dijit.CheckedMenuItem.prototype.destroy.apply(this, arguments);
					}
				});
				cell.menuItems.push(item);
				return item;
			}, this); // dijit.CheckedMenuItem[]
		},

		_setHeaderMenuAttr: function(menu){
			if(this._placeholders && this._placeholders.length){
				dojo.forEach(this._placeholders, function(p){
					p.unReplace(true);
				});
				this._placeholders = [];
			}
			if(this.headerMenu){
				this.headerMenu.unBindDomNode(this.viewsHeaderNode);
			}
			this.headerMenu = menu;
			if(!menu){ return; }

			this.headerMenu.bindDomNode(this.viewsHeaderNode);
			if(this.headerMenu.getPlaceholders){
				this._placeholders = this.headerMenu.getPlaceholders(this.placeholderLabel);
			}
		},

		setHeaderMenu: function(/* dijit.Menu */ menu){
			dojo.deprecated("dojox.grid._Grid.setHeaderMenu(obj)", "use dojox.grid._Grid.attr('headerMenu', obj) instead.", "2.0");
			this._setHeaderMenuAttr(menu);
		},
		
		setupHeaderMenu: function(){
			if(this._placeholders && this._placeholders.length){
				dojo.forEach(this._placeholders, function(p){
					if(p._replaced){
						p.unReplace(true);
					}
					p.replace(this.getColumnTogglingItems());
				}, this);
			}
		},

		_fetch: function(start){
			this.setScrollTop(0);
		},

		getItem: function(inRowIndex){
			return null;
		},
		
		showMessage: function(message){
			if(message){
				this.messagesNode.innerHTML = message;
				this.messagesNode.style.display = "";
			}else{
				this.messagesNode.innerHTML = "";
				this.messagesNode.style.display = "none";
			}
		},

		_structureChanged: function() {
			this.buildViews();
			if(this.autoRender && this._started){
				this.render();
			}
		},

		hasLayout: function() {
			return this.layout.cells.length;
		},

		// sizing
		resize: function(changeSize, resultSize){
			// summary:
			//		Update the grid's rendering dimensions and resize it
			
			// Calling sizeChange calls update() which calls _resize...so let's
			// save our input values, if any, and use them there when it gets 
			// called.  This saves us an extra call to _resize(), which can
			// get kind of heavy.
			this._pendingChangeSize = changeSize;
			this._pendingResultSize = resultSize;
			this.sizeChange();
		},

		_getPadBorder: function() {
			this._padBorder = this._padBorder || dojo._getPadBorderExtents(this.domNode);
			return this._padBorder;
		},

		_getHeaderHeight: function(){
			var vns = this.viewsHeaderNode.style, t = vns.display == "none" ? 0 : this.views.measureHeader();
			vns.height = t + 'px';
			// header heights are reset during measuring so must be normalized after measuring.
			this.views.normalizeHeaderNodeHeight();
			return t;
		},
		
		_resize: function(changeSize, resultSize){
			// Restore our pending values, if any
			changeSize = changeSize || this._pendingChangeSize;
			resultSize = resultSize || this._pendingResultSize;
			delete this._pendingChangeSize;
			delete this._pendingResultSize;
			// if we have set up everything except the DOM, we cannot resize
			if(!this.domNode){ return; }
			var pn = this.domNode.parentNode;
			if(!pn || pn.nodeType != 1 || !this.hasLayout() || pn.style.visibility == "hidden" || pn.style.display == "none"){
				return;
			}
			// useful measurement
			var padBorder = this._getPadBorder();
			var hh = undefined;
			var h;
			// grid height
			if(this._autoHeight){
				this.domNode.style.height = 'auto';
				this.viewsNode.style.height = '';
			}else if(typeof this.autoHeight == "number"){
				h = hh = this._getHeaderHeight();
				h += (this.scroller.averageRowHeight * this.autoHeight);
				this.domNode.style.height = h + "px";
			}else if(this.domNode.clientHeight <= padBorder.h){
				if(pn == document.body){
					this.domNode.style.height = this.defaultHeight;
				}else if(this.height){
					this.domNode.style.height = this.height;
				}else{
					this.fitTo = "parent";
				}
			}
			// if we are given dimensions, size the grid's domNode to those dimensions
			if(resultSize){
				changeSize = resultSize;
			}
			if(changeSize){
				dojo.marginBox(this.domNode, changeSize);
				this.height = this.domNode.style.height;
				delete this.fitTo;
			}else if(this.fitTo == "parent"){
				h = this._parentContentBoxHeight = this._parentContentBoxHeight || dojo._getContentBox(pn).h;
				this.domNode.style.height = Math.max(0, h) + "px";
			}
			
			var hasFlex = dojo.some(this.views.views, function(v){ return v.flexCells; });

			if(!this._autoHeight && (h || dojo._getContentBox(this.domNode).h) === 0){
				// We need to hide the header, since the Grid is essentially hidden.
				this.viewsHeaderNode.style.display = "none";
			}else{
				// Otherwise, show the header and give it an appropriate height.
				this.viewsHeaderNode.style.display = "block";
				if(!hasFlex && hh === undefined){
					hh = this._getHeaderHeight();
				}
			}
			if(hasFlex){
				hh = undefined;
			}

			// NOTE: it is essential that width be applied before height
			// Header height can only be calculated properly after view widths have been set.
			// This is because flex column width is naturally 0 in Firefox.
			// Therefore prior to width sizing flex columns with spaces are maximally wrapped
			// and calculated to be too tall.
			this.adaptWidth();
			this.adaptHeight(hh);

			this.postresize();
		},

		adaptWidth: function() {
			// private: sets width and position for views and update grid width if necessary
			var doAutoWidth = (!this.initialWidth && this.autoWidth);
			var w = doAutoWidth ? 0 : this.domNode.clientWidth || (this.domNode.offsetWidth - this._getPadBorder().w),
				vw = this.views.arrange(1, w);
			this.views.onEach("adaptWidth");
			if(doAutoWidth){
				this.domNode.style.width = vw + "px";
			}
		},

		adaptHeight: function(inHeaderHeight){
			// private: measures and normalizes header height, then sets view heights, and then updates scroller
			// content extent
			var t = inHeaderHeight === undefined ? this._getHeaderHeight() : inHeaderHeight;
			var h = (this._autoHeight ? -1 : Math.max(this.domNode.clientHeight - t, 0) || 0);
			this.views.onEach('setSize', [0, h]);
			this.views.onEach('adaptHeight');
			if(!this._autoHeight){
				var numScroll = 0, numNoScroll = 0;
				var noScrolls = dojo.filter(this.views.views, function(v){
					var has = v.hasHScrollbar();
					if(has){ numScroll++; }else{ numNoScroll++; }
					return (!has);
				});
				if(numScroll > 0 && numNoScroll > 0){
					dojo.forEach(noScrolls, function(v){
						v.adaptHeight(true);
					});
				}
			}
			if(this.autoHeight === true || h != -1 || (typeof this.autoHeight == "number" && this.autoHeight >= this.get('rowCount'))){
				this.scroller.windowHeight = h;
			}else{
				this.scroller.windowHeight = Math.max(this.domNode.clientHeight - t, 0);
			}
		},

		// startup
		startup: function(){
			if(this._started){return;}
			this.inherited(arguments);
			if(this.autoRender){
				this.render();
			}
		},

		// render
		render: function(){
			// summary:
			//	Render the grid, headers, and views. Edit and scrolling states are reset. To retain edit and
			// scrolling states, see Update.

			if(!this.domNode){return;}
			if(!this._started){return;}

			if(!this.hasLayout()) {
				this.scroller.init(0, this.keepRows, this.rowsPerPage);
				return;
			}
			//
			this.update = this.defaultUpdate;
			this._render();
		},

		_render: function(){
			this.scroller.init(this.get('rowCount'), this.keepRows, this.rowsPerPage);
			this.prerender();
			this.setScrollTop(0);
			this.postrender();
		},

		prerender: function(){
			// if autoHeight, make sure scroller knows not to virtualize; everything must be rendered.
			this.keepRows = this._autoHeight ? 0 : this.keepRows;
			this.scroller.setKeepInfo(this.keepRows);
			this.views.render();
			this._resize();
		},

		postrender: function(){
			this.postresize();
			this.focus.initFocusView();
			// make rows unselectable
			dojo.setSelectable(this.domNode, this.selectable);
		},

		postresize: function(){
			// views are position absolute, so they do not inflate the parent
			if(this._autoHeight){
				var size = Math.max(this.views.measureContent()) + 'px';
				
				this.viewsNode.style.height = size;
			}
		},

		renderRow: function(inRowIndex, inNodes){
			// summary: private, used internally to render rows
			this.views.renderRow(inRowIndex, inNodes, this._skipRowRenormalize);
		},

		rowRemoved: function(inRowIndex){
			// summary: private, used internally to remove rows
			this.views.rowRemoved(inRowIndex);
		},

		invalidated: null,

		updating: false,

		beginUpdate: function(){
			// summary:
			//		Use to make multiple changes to rows while queueing row updating.
			// NOTE: not currently supporting nested begin/endUpdate calls
			this.invalidated = [];
			this.updating = true;
		},

		endUpdate: function(){
			// summary:
			//		Use after calling beginUpdate to render any changes made to rows.
			this.updating = false;
			var i = this.invalidated, r;
			if(i.all){
				this.update();
			}else if(i.rowCount != undefined){
				this.updateRowCount(i.rowCount);
			}else{
				for(r in i){
					this.updateRow(Number(r));
				}
			}
			this.invalidated = [];
		},

		// update
		defaultUpdate: function(){
			// note: initial update calls render and subsequently this function.
			if(!this.domNode){return;}
			if(this.updating){
				this.invalidated.all = true;
				return;
			}
			//this.edit.saveState(inRowIndex);
			this.lastScrollTop = this.scrollTop;
			this.prerender();
			this.scroller.invalidateNodes();
			this.setScrollTop(this.lastScrollTop);
			this.postrender();
			//this.edit.restoreState(inRowIndex);
		},

		update: function(){
			// summary:
			//		Update the grid, retaining edit and scrolling states.
			this.render();
		},

		updateRow: function(inRowIndex){
			// summary:
			//		Render a single row.
			// inRowIndex: Integer
			//		Index of the row to render
			inRowIndex = Number(inRowIndex);
			if(this.updating){
				this.invalidated[inRowIndex]=true;
			}else{
				this.views.updateRow(inRowIndex);
				this.scroller.rowHeightChanged(inRowIndex);
			}
		},

		updateRows: function(startIndex, howMany){
			// summary:
			//		Render consecutive rows at once.
			// startIndex: Integer
			//		Index of the starting row to render
			// howMany: Integer
			//		How many rows to update.
			startIndex = Number(startIndex);
			howMany = Number(howMany);
			var i;
			if(this.updating){
				for(i=0; i<howMany; i++){
					this.invalidated[i+startIndex]=true;
				}
			}else{
				for(i=0; i<howMany; i++){
					this.views.updateRow(i+startIndex, this._skipRowRenormalize);
				}
				this.scroller.rowHeightChanged(startIndex);
			}
		},

		updateRowCount: function(inRowCount){
			//summary:
			//	Change the number of rows.
			// inRowCount: int
			//	Number of rows in the grid.
			if(this.updating){
				this.invalidated.rowCount = inRowCount;
			}else{
				this.rowCount = inRowCount;
				this._setAutoHeightAttr(this.autoHeight, true);
				if(this.layout.cells.length){
					this.scroller.updateRowCount(inRowCount);
				}
				this._resize();				
				if(this.layout.cells.length){
					this.setScrollTop(this.scrollTop);
				}
			}
		},

		updateRowStyles: function(inRowIndex){
			// summary:
			//		Update the styles for a row after it's state has changed.
			this.views.updateRowStyles(inRowIndex);
		},
		getRowNode: function(inRowIndex){
			// summary:
			//		find the rowNode that is not a rowSelector
			if (this.focus.focusView && !(this.focus.focusView instanceof dojox.grid._RowSelector)){
					return this.focus.focusView.rowNodes[inRowIndex];
			}else{ // search through views
				for (var i = 0, cView; (cView = this.views.views[i]); i++) {
					if (!(cView instanceof dojox.grid._RowSelector)) {
						return cView.rowNodes[inRowIndex];
					}
				}
			}
			return null;
		},
		rowHeightChanged: function(inRowIndex){
			// summary:
			//		Update grid when the height of a row has changed. Row height is handled automatically as rows
			//		are rendered. Use this function only to update a row's height outside the normal rendering process.
			// inRowIndex: Integer
			// 		index of the row that has changed height

			this.views.renormalizeRow(inRowIndex);
			this.scroller.rowHeightChanged(inRowIndex);
		},

		// fastScroll: Boolean
		//		flag modifies vertical scrolling behavior. Defaults to true but set to false for slower
		//		scroll performance but more immediate scrolling feedback
		fastScroll: true,

		delayScroll: false,

		// scrollRedrawThreshold: int
		//	pixel distance a user must scroll vertically to trigger grid scrolling.
		scrollRedrawThreshold: (dojo.isIE ? 100 : 50),

		// scroll methods
		scrollTo: function(inTop){
			// summary:
			//		Vertically scroll the grid to a given pixel position
			// inTop: Integer
			//		vertical position of the grid in pixels
			if(!this.fastScroll){
				this.setScrollTop(inTop);
				return;
			}
			var delta = Math.abs(this.lastScrollTop - inTop);
			this.lastScrollTop = inTop;
			if(delta > this.scrollRedrawThreshold || this.delayScroll){
				this.delayScroll = true;
				this.scrollTop = inTop;
				this.views.setScrollTop(inTop);
				if(this._pendingScroll){
					window.clearTimeout(this._pendingScroll);
				}
				var _this = this;
				this._pendingScroll = window.setTimeout(function(){
					delete _this._pendingScroll;
					_this.finishScrollJob();
				}, 200);
			}else{
				this.setScrollTop(inTop);
			}
		},

		finishScrollJob: function(){
			this.delayScroll = false;
			this.setScrollTop(this.scrollTop);
		},

		setScrollTop: function(inTop){
			this.scroller.scroll(this.views.setScrollTop(inTop));
		},

		scrollToRow: function(inRowIndex){
			// summary:
			//		Scroll the grid to a specific row.
			// inRowIndex: Integer
			// 		grid row index
			this.setScrollTop(this.scroller.findScrollTop(inRowIndex) + 1);
		},

		// styling (private, used internally to style individual parts of a row)
		styleRowNode: function(inRowIndex, inRowNode){
			if(inRowNode){
				this.rows.styleRowNode(inRowIndex, inRowNode);
			}
		},
		
		// called when the mouse leaves the grid so we can deselect all hover rows
		_mouseOut: function(e){
			this.rows.setOverRow(-2);
		},
	
		// cells
		getCell: function(inIndex){
			// summary:
			//		Retrieves the cell object for a given grid column.
			// inIndex: Integer
			// 		Grid column index of cell to retrieve
			// returns:
			//		a grid cell
			return this.layout.cells[inIndex];
		},

		setCellWidth: function(inIndex, inUnitWidth){
			this.getCell(inIndex).unitWidth = inUnitWidth;
		},

		getCellName: function(inCell){
			// summary: Returns the cell name of a passed cell
			return "Cell " + inCell.index; // String
		},

		// sorting
		canSort: function(inSortInfo){
			// summary:
			//		Determines if the grid can be sorted
			// inSortInfo: Integer
			//		Sort information, 1-based index of column on which to sort, positive for an ascending sort
			// 		and negative for a descending sort
			// returns: Boolean
			//		True if grid can be sorted on the given column in the given direction
		},

		sort: function(){
		},

		getSortAsc: function(inSortInfo){
			// summary:
			//		Returns true if grid is sorted in an ascending direction.
			inSortInfo = inSortInfo == undefined ? this.sortInfo : inSortInfo;
			return Boolean(inSortInfo > 0); // Boolean
		},

		getSortIndex: function(inSortInfo){
			// summary:
			//		Returns the index of the column on which the grid is sorted
			inSortInfo = inSortInfo == undefined ? this.sortInfo : inSortInfo;
			return Math.abs(inSortInfo) - 1; // Integer
		},

		setSortIndex: function(inIndex, inAsc){
			// summary:
			// 		Sort the grid on a column in a specified direction
			// inIndex: Integer
			// 		Column index on which to sort.
			// inAsc: Boolean
			// 		If true, sort the grid in ascending order, otherwise in descending order
			var si = inIndex +1;
			if(inAsc != undefined){
				si *= (inAsc ? 1 : -1);
			} else if(this.getSortIndex() == inIndex){
				si = -this.sortInfo;
			}
			this.setSortInfo(si);
		},

		setSortInfo: function(inSortInfo){
			if(this.canSort(inSortInfo)){
				this.sortInfo = inSortInfo;
				this.sort();
				this.update();
			}
		},

		// DOM event handler
		doKeyEvent: function(e){
			e.dispatch = 'do' + e.type;
			this.onKeyEvent(e);
		},

		// event dispatch
		//: protected
		_dispatch: function(m, e){
			if(m in this){
				return this[m](e);
			}
			return false;
		},

		dispatchKeyEvent: function(e){
			this._dispatch(e.dispatch, e);
		},

		dispatchContentEvent: function(e){
			this.edit.dispatchEvent(e) || e.sourceView.dispatchContentEvent(e) || this._dispatch(e.dispatch, e);
		},

		dispatchHeaderEvent: function(e){
			e.sourceView.dispatchHeaderEvent(e) || this._dispatch('doheader' + e.type, e);
		},

		dokeydown: function(e){
			this.onKeyDown(e);
		},

		doclick: function(e){
			if(e.cellNode){
				this.onCellClick(e);
			}else{
				this.onRowClick(e);
			}
		},

		dodblclick: function(e){
			if(e.cellNode){
				this.onCellDblClick(e);
			}else{
				this.onRowDblClick(e);
			}
		},

		docontextmenu: function(e){
			if(e.cellNode){
				this.onCellContextMenu(e);
			}else{
				this.onRowContextMenu(e);
			}
		},

		doheaderclick: function(e){
			if(e.cellNode){
				this.onHeaderCellClick(e);
			}else{
				this.onHeaderClick(e);
			}
		},

		doheaderdblclick: function(e){
			if(e.cellNode){
				this.onHeaderCellDblClick(e);
			}else{
				this.onHeaderDblClick(e);
			}
		},

		doheadercontextmenu: function(e){
			if(e.cellNode){
				this.onHeaderCellContextMenu(e);
			}else{
				this.onHeaderContextMenu(e);
			}
		},

		// override to modify editing process
		doStartEdit: function(inCell, inRowIndex){
			this.onStartEdit(inCell, inRowIndex);
		},

		doApplyCellEdit: function(inValue, inRowIndex, inFieldIndex){
			this.onApplyCellEdit(inValue, inRowIndex, inFieldIndex);
		},

		doCancelEdit: function(inRowIndex){
			this.onCancelEdit(inRowIndex);
		},

		doApplyEdit: function(inRowIndex){
			this.onApplyEdit(inRowIndex);
		},

		// row editing
		addRow: function(){
			// summary:
			//		Add a row to the grid.
			this.updateRowCount(this.get('rowCount')+1);
		},

		removeSelectedRows: function(){
			// summary:
			//		Remove the selected rows from the grid.
			if(this.allItemsSelected){
				this.updateRowCount(0);
			}else{
				this.updateRowCount(Math.max(0, this.get('rowCount') - this.selection.getSelected().length));
			}
			this.selection.clear();
		}

	});

	dojox.grid._Grid.markupFactory = function(props, node, ctor, cellFunc){
		var d = dojo;
		var widthFromAttr = function(n){
			var w = d.attr(n, "width")||"auto";
			if((w != "auto")&&(w.slice(-2) != "em")&&(w.slice(-1) != "%")){
				w = parseInt(w, 10)+"px";
			}
			return w;
		};
		// if(!props.store){ console.debug("no store!"); }
		// if a structure isn't referenced, do we have enough
		// data to try to build one automatically?
		if(	!props.structure &&
			node.nodeName.toLowerCase() == "table"){

			// try to discover a structure
			props.structure = d.query("> colgroup", node).map(function(cg){
				var sv = d.attr(cg, "span");
				var v = {
					noscroll: (d.attr(cg, "noscroll") == "true") ? true : false,
					__span: (!!sv ? parseInt(sv, 10) : 1),
					cells: []
				};
				if(d.hasAttr(cg, "width")){
					v.width = widthFromAttr(cg);
				}
				return v; // for vendetta
			});
			if(!props.structure.length){
				props.structure.push({
					__span: Infinity,
					cells: [] // catch-all view
				});
			}
			// check to see if we're gonna have more than one view

			// for each tr in our th, create a row of cells
			d.query("thead > tr", node).forEach(function(tr, tr_idx){
				var cellCount = 0;
				var viewIdx = 0;
				var lastViewIdx;
				var cView = null;
				d.query("> th", tr).map(function(th){
					// what view will this cell go into?

					// NOTE:
					//		to prevent extraneous iteration, we start counters over
					//		for each row, incrementing over the surface area of the
					//		structure that colgroup processing generates and
					//		creating cell objects for each <th> to place into those
					//		cell groups.  There's a lot of state-keepking logic
					//		here, but it is what it has to be.
					if(!cView){ // current view book keeping
						lastViewIdx = 0;
						cView = props.structure[0];
					}else if(cellCount >= (lastViewIdx+cView.__span)){
						viewIdx++;
						// move to allocating things into the next view
						lastViewIdx += cView.__span;
						var lastView = cView;
						cView = props.structure[viewIdx];
					}

					// actually define the cell from what markup hands us
					var cell = {
						name: d.trim(d.attr(th, "name")||th.innerHTML),
						colSpan: parseInt(d.attr(th, "colspan")||1, 10),
						type: d.trim(d.attr(th, "cellType")||""),
						id: d.trim(d.attr(th,"id")||"")
					};
					cellCount += cell.colSpan;
					var rowSpan = d.attr(th, "rowspan");
					if(rowSpan){
						cell.rowSpan = rowSpan;
					}
					if(d.hasAttr(th, "width")){
						cell.width = widthFromAttr(th);
					}
					if(d.hasAttr(th, "relWidth")){
						cell.relWidth = window.parseInt(dojo.attr(th, "relWidth"), 10);
					}
					if(d.hasAttr(th, "hidden")){
						cell.hidden = d.attr(th, "hidden") == "true";
					}

					if(cellFunc){
						cellFunc(th, cell);
					}

					cell.type = cell.type ? dojo.getObject(cell.type) : dojox.grid.cells.Cell;

					if(cell.type && cell.type.markupFactory){
						cell.type.markupFactory(th, cell);
					}

					if(!cView.cells[tr_idx]){
						cView.cells[tr_idx] = [];
					}
					cView.cells[tr_idx].push(cell);
				});
			});
		}

		return new ctor(props, node);
	};
})();

}

if(!dojo._hasResource["dojox.grid.DataSelection"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid.DataSelection"] = true;
dojo.provide("dojox.grid.DataSelection");


dojo.declare("dojox.grid.DataSelection", dojox.grid.Selection, {
	getFirstSelected: function(){
		var idx = dojox.grid.Selection.prototype.getFirstSelected.call(this);

		if(idx == -1){ return null; }
		return this.grid.getItem(idx);
	},

	getNextSelected: function(inPrev){
		var old_idx = this.grid.getItemIndex(inPrev);
		var idx = dojox.grid.Selection.prototype.getNextSelected.call(this, old_idx);

		if(idx == -1){ return null; }
		return this.grid.getItem(idx);
	},

	getSelected: function(){
		var result = [];
		for(var i=0, l=this.selected.length; i<l; i++){
			if(this.selected[i]){
				result.push(this.grid.getItem(i));
			}
		}
		return result;
	},

	addToSelection: function(inItemOrIndex){
		if(this.mode == 'none'){ return; }
		var idx = null;
		if(typeof inItemOrIndex == "number" || typeof inItemOrIndex == "string"){
			idx = inItemOrIndex;
		}else{
			idx = this.grid.getItemIndex(inItemOrIndex);
		}
		dojox.grid.Selection.prototype.addToSelection.call(this, idx);
	},

	deselect: function(inItemOrIndex){
		if(this.mode == 'none'){ return; }
		var idx = null;
		if(typeof inItemOrIndex == "number" || typeof inItemOrIndex == "string"){
			idx = inItemOrIndex;
		}else{
			idx = this.grid.getItemIndex(inItemOrIndex);
		}
		dojox.grid.Selection.prototype.deselect.call(this, idx);
	},

	deselectAll: function(inItemOrIndex){
		var idx = null;
		if(inItemOrIndex || typeof inItemOrIndex == "number"){
			if(typeof inItemOrIndex == "number" || typeof inItemOrIndex == "string"){
				idx = inItemOrIndex;
			}else{
				idx = this.grid.getItemIndex(inItemOrIndex);
			}
			dojox.grid.Selection.prototype.deselectAll.call(this, idx);
		}else{
			this.inherited(arguments);
		}
	}
});

}

if(!dojo._hasResource["dojox.grid.DataGrid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid.DataGrid"] = true;
dojo.provide("dojox.grid.DataGrid");




/*=====
dojo.declare("dojox.grid.__DataCellDef", dojox.grid.__CellDef, {
	constructor: function(){
		//	field: String?
		//		The attribute to read from the dojo.data item for the row.
		//  fields: String[]?
		//		An array of fields to grab the values of and pass as an array to the grid
		//	get: Function?
		//		function(rowIndex, item?){} rowIndex is of type Integer, item is of type
		//		Object.  This function will be called when a cell requests data.  Returns
		//		the unformatted data for the cell.
	}
});
=====*/

/*=====
dojo.declare("dojox.grid.__DataViewDef", dojox.grid.__ViewDef, {
	constructor: function(){
		//	cells: dojox.grid.__DataCellDef[]|Array[dojox.grid.__DataCellDef[]]?
		//		The structure of the cells within this grid.
		//	defaultCell: dojox.grid.__DataCellDef?
		//		A cell definition with default values for all cells in this view.  If
		//		a property is defined in a cell definition in the "cells" array and
		//		this property, the cell definition's property will override this
		//		property's property.
	}
});
=====*/

dojo.declare("dojox.grid.DataGrid", dojox.grid._Grid, {
	store: null,
	query: null,
	queryOptions: null,
	fetchText: '...',
	sortFields: null,
	
	// updateDelay: int
	//		Time, in milliseconds, to delay updates automatically so that multiple
	//		calls to onSet/onNew/onDelete don't keep rerendering the grid.  Set
	//		to 0 to immediately cause updates.  A higher value will result in
	//		better performance at the expense of responsiveness of the grid.
	updateDelay: 1,

/*=====
	// structure: dojox.grid.__DataViewDef|dojox.grid.__DataViewDef[]|dojox.grid.__DataCellDef[]|Array[dojox.grid.__DataCellDef[]]
	//		View layout defintion.
	structure: '',
=====*/

	// You can specify items instead of a query, if you like.  They do not need
	// to be loaded - but the must be items in the store
	items: null,
	
	_store_connects: null,
	_by_idty: null,
	_by_idx: null,
	_cache: null,
	_pages: null,
	_pending_requests: null,
	_bop: -1,
	_eop: -1,
	_requests: 0,
	rowCount: 0,

	_isLoaded: false,
	_isLoading: false,
	
	postCreate: function(){
		this._pages = [];
		this._store_connects = [];
		this._by_idty = {};
		this._by_idx = [];
		this._cache = [];
		this._pending_requests = {};

		this._setStore(this.store);
		this.inherited(arguments);
	},

	createSelection: function(){
		this.selection = new dojox.grid.DataSelection(this);
	},

	get: function(inRowIndex, inItem){
		// summary: Default data getter.
		// description:
		//		Provides data to display in a grid cell. Called in grid cell context.
		//		So this.cell.index is the column index.
		// inRowIndex: Integer
		//		Row for which to provide data
		// returns:
		//		Data to display for a given grid cell.
		
		if(inItem && this.field == "_item" && !this.fields){
			return inItem;
		}else if(inItem && this.fields){
			var ret = [];
			var s = this.grid.store;
			dojo.forEach(this.fields, function(f){
				ret = ret.concat(s.getValues(inItem, f));
			});
			return ret;
		}else if(!inItem && typeof inRowIndex === "string"){
			return this.inherited(arguments);
		}
		return (!inItem ? this.defaultValue : (!this.field ? this.value : (this.field == "_item" ? inItem : this.grid.store.getValue(inItem, this.field))));
	},

	_checkUpdateStatus: function(){
		if(this.updateDelay > 0){
			var iStarted = false;
			if(this._endUpdateDelay){
				clearTimeout(this._endUpdateDelay);
				delete this._endUpdateDelay;
				iStarted = true;
			}
			if(!this.updating){
				this.beginUpdate();
				iStarted = true;
			}
			if(iStarted){
				var _this = this;
				this._endUpdateDelay = setTimeout(function(){
					delete _this._endUpdateDelay;
					_this.endUpdate();
				}, this.updateDelay);
			}
		}
	},
	
	_onSet: function(item, attribute, oldValue, newValue){
		this._checkUpdateStatus();
		var idx = this.getItemIndex(item);
		if(idx>-1){
			this.updateRow(idx);
		}
	},
	
	_createItem: function(item, index){
		var idty = this._hasIdentity ? this.store.getIdentity(item) : dojo.toJson(this.query) + ":idx:" + index + ":sort:" + dojo.toJson(this.getSortProps());
		var o = this._by_idty[idty] = { idty: idty, item: item };
		return o;
	},

	_addItem: function(item, index, noUpdate){
		this._by_idx[index] = this._createItem(item, index);
		if(!noUpdate){
			this.updateRow(index);
		}
	},

	_onNew: function(item, parentInfo){
		this._checkUpdateStatus();
		var rowCount = this.get('rowCount');
		this._addingItem = true;
		this.updateRowCount(rowCount+1);
		this._addingItem = false;
		this._addItem(item, rowCount);
		this.showMessage();
	},

	_onDelete: function(item){
		this._checkUpdateStatus();
		var idx = this._getItemIndex(item, true);

		if(idx >= 0){
			// When a row is deleted, all rest rows are shifted down,
			// and migrate from page to page. If some page is not 
			// loaded yet empty rows can migrate to initialized pages
			// without refreshing. It causes empty rows in some pages, see:
			// http://bugs.dojotoolkit.org/ticket/6818
			// this code fix this problem by reseting loaded page info
			this._pages = [];
			this._bop = -1;
			this._eop = -1;

			var o = this._by_idx[idx];
			this._by_idx.splice(idx, 1);
			delete this._by_idty[o.idty];
			this.updateRowCount(this.get('rowCount')-1);
			if(this.get('rowCount') === 0){
				this.showMessage(this.noDataMessage);
			}
		}
	},

	_onRevert: function(){
		this._refresh();
	},

	setStore: function(store, query, queryOptions){
		this._setQuery(query, queryOptions);
		this._setStore(store);
		this._refresh(true);
	},
	
	setQuery: function(query, queryOptions){
		this._setQuery(query, queryOptions);
		this._refresh(true);
	},
	
	setItems: function(items){
		this.items = items;
		this._setStore(this.store);
		this._refresh(true);
	},
	
	_setQuery: function(query, queryOptions){
		this.query = query;
		this.queryOptions = queryOptions || this.queryOptions;		
	},

	_setStore: function(store){
		if(this.store&&this._store_connects){
			dojo.forEach(this._store_connects,function(arr){
				dojo.forEach(arr, dojo.disconnect);
			});
		}
		this.store = store;

		if(this.store){
			var f = this.store.getFeatures();
			var h = [];

			this._canEdit = !!f["dojo.data.api.Write"] && !!f["dojo.data.api.Identity"];
			this._hasIdentity = !!f["dojo.data.api.Identity"];

			if(!!f["dojo.data.api.Notification"] && !this.items){
				h.push(this.connect(this.store, "onSet", "_onSet"));
				h.push(this.connect(this.store, "onNew", "_onNew"));
				h.push(this.connect(this.store, "onDelete", "_onDelete"));
			}
			if(this._canEdit){
				h.push(this.connect(this.store, "revert", "_onRevert"));
			}

			this._store_connects = h;
		}
	},

	_onFetchBegin: function(size, req){
		if(!this.scroller){ return; }
		if(this.rowCount != size){
			if(req.isRender){
				this.scroller.init(size, this.keepRows, this.rowsPerPage);
				this.rowCount = size;
				this._setAutoHeightAttr(this.autoHeight, true);
				this._skipRowRenormalize = true;
				this.prerender();
				this._skipRowRenormalize = false;
			}else{
				this.updateRowCount(size);
			}
		}
		if(!size){
			this.views.render();
			this._resize();
			this.showMessage(this.noDataMessage);
			this.focus.initFocusView();
		}else{
			this.showMessage();
		}
	},

	_onFetchComplete: function(items, req){
		if(!this.scroller){ return; }
		if(items && items.length > 0){
			//console.log(items);
			dojo.forEach(items, function(item, idx){
				this._addItem(item, req.start+idx, true);
			}, this);
			if(this._autoHeight){
				this._skipRowRenormalize = true;
			}
			this.updateRows(req.start, items.length);
			if(this._autoHeight){
				this._skipRowRenormalize = false;
			}			
			if(req.isRender){
				this.setScrollTop(0);
				this.postrender();
			}else if(this._lastScrollTop){
				this.setScrollTop(this._lastScrollTop);
			}
		}
		delete this._lastScrollTop;
		if(!this._isLoaded){
			this._isLoading = false;
			this._isLoaded = true;
		}
		this._pending_requests[req.start] = false;
	},

	_onFetchError: function(err, req){
		console.log(err);
		delete this._lastScrollTop;
		if(!this._isLoaded){
			this._isLoading = false;
			this._isLoaded = true;
			this.showMessage(this.errorMessage);
		}
		this._pending_requests[req.start] = false;
		this.onFetchError(err, req);
	},

	onFetchError: function(err, req){
	},

	_fetch: function(start, isRender){
		start = start || 0;
		if(this.store && !this._pending_requests[start]){
			if(!this._isLoaded && !this._isLoading){
				this._isLoading = true;
				this.showMessage(this.loadingMessage);
			}
			this._pending_requests[start] = true;
			//console.log("fetch: ", start);
			try{
				if(this.items){
					var items = this.items;
					var store = this.store;
					this.rowsPerPage = items.length;
					var req = {
						start: start,
						count: this.rowsPerPage,
						isRender: isRender
					};
					this._onFetchBegin(items.length, req);
					
					// Load them if we need to
					var waitCount = 0;
					dojo.forEach(items, function(i){
						if(!store.isItemLoaded(i)){ waitCount++; }
					});
					if(waitCount === 0){
						this._onFetchComplete(items, req);
					}else{
						var onItem = function(item){
							waitCount--;
							if(waitCount === 0){
								this._onFetchComplete(items, req);
							}
						};
						dojo.forEach(items, function(i){
							if(!store.isItemLoaded(i)){
								store.loadItem({item: i, onItem: onItem, scope: this});
							}
						}, this);
					}
				}else{
					this.store.fetch({
						start: start,
						count: this.rowsPerPage,
						query: this.query,
						sort: this.getSortProps(),
						queryOptions: this.queryOptions,
						isRender: isRender,
						onBegin: dojo.hitch(this, "_onFetchBegin"),
						onComplete: dojo.hitch(this, "_onFetchComplete"),
						onError: dojo.hitch(this, "_onFetchError")
					});
				}
			}catch(e){
				this._onFetchError(e, {start: start, count: this.rowsPerPage});
			}
		}
	},

	_clearData: function(){
		this.updateRowCount(0);
		this._by_idty = {};
		this._by_idx = [];
		this._pages = [];
		this._bop = this._eop = -1;
		this._isLoaded = false;
		this._isLoading = false;
	},

	getItem: function(idx){
		var data = this._by_idx[idx];
		if(!data||(data&&!data.item)){
			this._preparePage(idx);
			return null;
		}
		return data.item;
	},

	getItemIndex: function(item){
		return this._getItemIndex(item, false);
	},
	
	_getItemIndex: function(item, isDeleted){
		if(!isDeleted && !this.store.isItem(item)){
			return -1;
		}

		var idty = this._hasIdentity ? this.store.getIdentity(item) : null;

		for(var i=0, l=this._by_idx.length; i<l; i++){
			var d = this._by_idx[i];
			if(d && ((idty && d.idty == idty) || (d.item === item))){
				return i;
			}
		}
		return -1;
	},

	filter: function(query, reRender){
		this.query = query;
		if(reRender){
			this._clearData();
		}
		this._fetch();
	},

	_getItemAttr: function(idx, attr){
		var item = this.getItem(idx);
		return (!item ? this.fetchText : this.store.getValue(item, attr));
	},

	// rendering
	_render: function(){
		if(this.domNode.parentNode){
			this.scroller.init(this.get('rowCount'), this.keepRows, this.rowsPerPage);
			this.prerender();
			this._fetch(0, true);
		}
	},

	// paging
	_requestsPending: function(inRowIndex){
		return this._pending_requests[inRowIndex];
	},

	_rowToPage: function(inRowIndex){
		return (this.rowsPerPage ? Math.floor(inRowIndex / this.rowsPerPage) : inRowIndex);
	},

	_pageToRow: function(inPageIndex){
		return (this.rowsPerPage ? this.rowsPerPage * inPageIndex : inPageIndex);
	},

	_preparePage: function(inRowIndex){
		if((inRowIndex < this._bop || inRowIndex >= this._eop) && !this._addingItem){
			var pageIndex = this._rowToPage(inRowIndex);
			this._needPage(pageIndex);
			this._bop = pageIndex * this.rowsPerPage;
			this._eop = this._bop + (this.rowsPerPage || this.get('rowCount'));
		}
	},

	_needPage: function(inPageIndex){
		if(!this._pages[inPageIndex]){
			this._pages[inPageIndex] = true;
			this._requestPage(inPageIndex);
		}
	},

	_requestPage: function(inPageIndex){
		var row = this._pageToRow(inPageIndex);
		var count = Math.min(this.rowsPerPage, this.get('rowCount') - row);
		if(count > 0){
			this._requests++;
			if(!this._requestsPending(row)){
				setTimeout(dojo.hitch(this, "_fetch", row, false), 1);
				//this.requestRows(row, count);
			}
		}
	},

	getCellName: function(inCell){
		return inCell.field;
		//console.log(inCell);
	},

	_refresh: function(isRender){
		this._clearData();
		this._fetch(0, isRender);
	},

	sort: function(){
		this._lastScrollTop = this.scrollTop;
		this._refresh();
	},

	canSort: function(){
		return (!this._isLoading);
	},

	getSortProps: function(){
		var c = this.getCell(this.getSortIndex());
		if(!c){
			if(this.sortFields){
				return this.sortFields;
			}
			return null;
		}else{
			var desc = c["sortDesc"];
			var si = !(this.sortInfo>0);
			if(typeof desc == "undefined"){
				desc = si;
			}else{
				desc = si ? !desc : desc;
			}
			return [{ attribute: c.field, descending: desc }];
		}
	},

	styleRowState: function(inRow){
		// summary: Perform row styling
		if(this.store && this.store.getState){
			var states=this.store.getState(inRow.index), c='';
			for(var i=0, ss=["inflight", "error", "inserting"], s; s=ss[i]; i++){
				if(states[s]){
					c = ' dojoxGridRow-' + s;
					break;
				}
			}
			inRow.customClasses += c;
		}
	},

	onStyleRow: function(inRow){
		this.styleRowState(inRow);
		this.inherited(arguments);
	},

	// editing
	canEdit: function(inCell, inRowIndex){
		return this._canEdit;
	},

	_copyAttr: function(idx, attr){
		var row = {};
		var backstop = {};
		var src = this.getItem(idx);
		return this.store.getValue(src, attr);
	},

	doStartEdit: function(inCell, inRowIndex){
		if(!this._cache[inRowIndex]){
			this._cache[inRowIndex] = this._copyAttr(inRowIndex, inCell.field);
		}
		this.onStartEdit(inCell, inRowIndex);
	},

	doApplyCellEdit: function(inValue, inRowIndex, inAttrName){
		this.store.fetchItemByIdentity({
			identity: this._by_idx[inRowIndex].idty,
			onItem: dojo.hitch(this, function(item){
				var oldValue = this.store.getValue(item, inAttrName);
				if(typeof oldValue == 'number'){
					inValue = isNaN(inValue) ? inValue : parseFloat(inValue);
				}else if(typeof oldValue == 'boolean'){
					inValue = inValue == 'true' ? true : inValue == 'false' ? false : inValue;
				}else if(oldValue instanceof Date){
					var asDate = new Date(inValue);
					inValue = isNaN(asDate.getTime()) ? inValue : asDate;
				}
				this.store.setValue(item, inAttrName, inValue);
				this.onApplyCellEdit(inValue, inRowIndex, inAttrName);
			})
		});
	},

	doCancelEdit: function(inRowIndex){
		var cache = this._cache[inRowIndex];
		if(cache){
			this.updateRow(inRowIndex);
			delete this._cache[inRowIndex];
		}
		this.onCancelEdit.apply(this, arguments);
	},

	doApplyEdit: function(inRowIndex, inDataAttr){
		var cache = this._cache[inRowIndex];
		/*if(cache){
			var data = this.getItem(inRowIndex);
			if(this.store.getValue(data, inDataAttr) != cache){
				this.update(cache, data, inRowIndex);
			}
			delete this._cache[inRowIndex];
		}*/
		this.onApplyEdit(inRowIndex);
	},

	removeSelectedRows: function(){
		// summary:
		//		Remove the selected rows from the grid.
		if(this._canEdit){
			this.edit.apply();
			var fx = dojo.hitch(this, function(items){
				if(items.length){
					dojo.forEach(items, this.store.deleteItem, this.store);
					this.selection.clear();
				}			
			});
			if(this.allItemsSelected){
				this.store.fetch({
							query: this.query, 
							queryOptions: this.queryOptions,
							onComplete: fx});
			}else{
				fx(this.selection.getSelected());
			}
		}
	}
});

dojox.grid.DataGrid.cell_markupFactory = function(cellFunc, node, cellDef){
	var field = dojo.trim(dojo.attr(node, "field")||"");
	if(field){
		cellDef.field = field;
	}
	cellDef.field = cellDef.field||cellDef.name;
	var fields = dojo.trim(dojo.attr(node, "fields")||"");
	if(fields){
		cellDef.fields = fields.split(",");
	}
	if(cellFunc){
		cellFunc(node, cellDef);
	}
};

dojox.grid.DataGrid.markupFactory = function(props, node, ctor, cellFunc){
	return dojox.grid._Grid.markupFactory(props, node, ctor, 
					dojo.partial(dojox.grid.DataGrid.cell_markupFactory, cellFunc));
};

}

if(!dojo._hasResource["dijit.ToolbarSeparator"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.ToolbarSeparator"] = true;
dojo.provide("dijit.ToolbarSeparator");




dojo.declare("dijit.ToolbarSeparator",
		[ dijit._Widget, dijit._Templated ],
		{
		// summary:
		//		A spacer between two `dijit.Toolbar` items
		templateString: '<div class="dijitToolbarSeparator dijitInline" waiRole="presentation"></div>',
		postCreate: function(){ dojo.setSelectable(this.domNode, false); },
		isFocusable: function(){
			// summary:
			//		This widget isn't focusable, so pass along that fact.
			// tags:
			//		protected
			return false;
		}

	});



}

if(!dojo._hasResource["dijit.Toolbar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Toolbar"] = true;
dojo.provide("dijit.Toolbar");





dojo.declare("dijit.Toolbar",
	[dijit._Widget, dijit._Templated, dijit._KeyNavContainer],
	{
	// summary:
	//		A Toolbar widget, used to hold things like `dijit.Editor` buttons

	templateString:
		'<div class="dijit" waiRole="toolbar" tabIndex="${tabIndex}" dojoAttachPoint="containerNode">' +
		//	'<table style="table-layout: fixed" class="dijitReset dijitToolbarTable">' + // factor out style
		//		'<tr class="dijitReset" dojoAttachPoint="containerNode"></tr>'+
		//	'</table>' +
		'</div>',

	baseClass: "dijitToolbar",

	postCreate: function(){
		this.connectKeyNavHandlers(
			this.isLeftToRight() ? [dojo.keys.LEFT_ARROW] : [dojo.keys.RIGHT_ARROW],
			this.isLeftToRight() ? [dojo.keys.RIGHT_ARROW] : [dojo.keys.LEFT_ARROW]
		);
		this.inherited(arguments);
	},

	startup: function(){
		if(this._started){ return; }

		this.startupKeyNavChildren();

		this.inherited(arguments);
	}
}
);

// For back-compat, remove for 2.0


}

if(!dojo._hasResource["com.sixnet.services.core.data.query"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.core.data.query"] = true;
dojo.provide("com.sixnet.services.core.data.query");

dojo.declare("com.sixnet.services.core.data.query",[],{
	// This class manages a single query with arbitrary nesting.
	// The actual query that is sent to the grid (not the one specified in the template
	_query: null,
	// _queryHandles:  This object stores the query handles that have been requested.
	_queryHandles: null,
	_queryHandleCount: 0,
	conjunction: 'AND',
	_queryLock: 0,
	constructor: function(props){
		dojo.mixin(this, props);
	
		// INITIALIZATION
		// Initialize the query if it was not set in the attributes
		
		this._queryHandles = {};
		this._query = {};
	},
	onQueryChange: function(newQuery){
	},
	_onQueryChange: function(){
		this.buildQuery();
	},
	getQuery: function(){
		if(this._queryLock){
			console.log("Get Query called while locked");
		}
		return dojo.clone(this._query);
	},
	queryLock: function(lockedCallback, postLockCallback){
		// the query lock function prevents the grid from attempting to update untill 
		// all query actions in the lockedCallback complete.
		var queryHandles = dojo.clone(this._queryHandles);
		this._queryLock ++;
		console.log("QueryLocked",this._queryLock);
		try{
			// prevent other code from permanently locking the query builder
			lockedCallback();
		}catch(e){
			_sixnet_framework.log(0, "Error in queryLock callback", e);
			// reset query to previous value in case of callback error.
			this._queryHandles = queryHandles;
		}
		this._queryLock --;
		console.log("QueryUnLocked",this._queryLock);
		this._onQueryChange();
		try{
			if('undefined' != typeof(postLockCallback)) postLockCallback();
		}catch(e){
			_sixnet_framework.log(0, "Error in queryLock callback", e);
			
		}
	},
	makeQueryHandle: function(){
		var helperObject = { 
				queryHandle: "handle" + this._queryHandleCount++,
				setQuery: dojo.hitch(this, function(query){
					if(this.getMode(query) == 'empty'){
						console.trace();
					}
					helperObject.query = dojo.clone(query);
					// put this queryHandleObject in the list
					// but only if we set a query in it
					this._queryHandles[helperObject.queryHandle] = helperObject;
					this._onQueryChange();
				}),
				releaseQuery: dojo.hitch(this, function(){
					if(!this._queryHandles[helperObject.queryHandle]) return;
					delete this._queryHandles[helperObject.queryHandle];
					this._onQueryChange();
				})
		};
		return helperObject;  
	},
	buildQuery: function(){
		// default conjunction to AND
		var index;
		this._query = {}; // reset to no query then build from handles...
		for(index in this._queryHandles){
			if(!this._queryHandles.hasOwnProperty(index)) continue;
			this.extendSearchQuery(this._queryHandles[index]);
		}
		_sixnet_framework.log(0, "Query", this._query);
		if(this._queryLock == 0){
			this.onQueryChange(this._query);
		}
	},
	getMode:function(queryHandle){
		function emptyLeft(){ return ( 'undefined' == typeof(queryHandle.left_expression) && 'undefined' == typeof(queryHandle.left_field) && 'undefined' == typeof(queryHandle.left_value)); } ;
		function emptyRight(){ return ( 'undefined' == typeof(queryHandle.right_expression) && 'undefined' == typeof(queryHandle.right_field) && 'undefined' == typeof(queryHandle.right_value)); } ;
		if(emptyLeft() && emptyRight()) return 'empty';
		if(emptyLeft()) return 'emptyLeft';
		if(emptyRight()) return 'emptyRight';
		return 'full';
	},
	extendSearchQuery: function(queryHandle){
		// modes = 'empty', 'emptyLeft', 'emptyRight', 'full';
		console.log('extending', queryHandle);
		switch(this.getMode(this._query)){
		case 'empty':
			this._query = queryHandle.query;
			break;
		case 'emptyLeft':
			this._query.left_expression = queryHandle.query;
			break;
		case 'emptyRight':
			this._query.right_expression = queryHandle.query;
			this._query.operator = this.conjunction;
			break;
		case 'full':
			var newQuery = {} ;
			newQuery.left_expression = queryHandle.query;
			newQuery.operator = this.conjunction;
			newQuery.right_expression = this._query;
			this._query = newQuery;			
			break;
		}
	}	
	
});

}

if(!dojo._hasResource['com.sixnet.services.widgets.sixnetGrid']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.sixnetGrid'] = true;








dojo.provide('com.sixnet.services.widgets.sixnetGrid');


/**
 * sixnetGrid provides a data display widget that understands the Sixnet "getViewData" and "updateViewData" paradigm
 * Remember... In general ONLY call methods of a class from outside.  Never use properties of a class directly.
 * Note: In some cases when dealing with dojo classes it is necessary to handle properties that do not have setters and getters
 * 			Avoid this whereever possible.
 */


dojo.declare('com.sixnet.services.widgets.sixnetGrid', [com.sixnet.services.core.dashWidgetBase, dijit._Templated, com.sixnet.services.core.data.query], {
	// ******** dojo properties *******
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\" >\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"top\" dojoAttachPoint=\"_toolbar\"  style=\"overflow:hidden; height:28px\">\n\t\t</div>\n\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" >\n\t\t\t<div dojoType=\"dojox.grid.DataGrid\" renderDelay=\"20\" rowHeight=\"70\" rowsPerPage=\"10\" escapeHTMLInData=\"false\" loadingMessage=\"...data loading\"  dojoAttachPoint=\"_displayGrid\"></div> \n\t</div>\t\n</div>\n",
	// ******** attributes (template setable) ***********
	// store is the data provider for this grid.  It must be specified in attributes  *REQUIRED
	store: null,
	// viewName is sent in getViewData and updateViewData *REQUIRED 
	viewName: '',
	// module is the name of the server side module that contains the view in viewName *REQUIRED
	module:'',
	// formatterClass is an optional override of the class containing formatter functions used to render custom fields
	formatterClass: 'com.sixnet.services.core.data.formatter',
	// columnReordering .. allow the template to set this so we can use the grid with and without it.
	columnReordering: true,
	// query is the minimum query sent by this grid.  It defaults to null and must be set in the postCreate to {} if still null
	query: null,
	_holdOff: false,
	// Drop in toolbar widgets (array in order of appearance
	toolbarWidgets: null,
	// **********  Private Properties of sixnetGrid ********* //
	_holdOffQuery: false,
	// instance of the formatter class, set in postCreate 
	_formatter: null,
	// DataGrid that is the main visual component of this widget 
	_displayGrid: null,
	// _viewChanged: the view (order, sort and visible fields) of the grid changed since last save
	_viewChanged: false,
	// _viewDescriptor: the descriptor for how to layout the fields and data (global generic)
	_viewDescriptor: null,
	// _fullDescriptor: the full return from server
	_fullDescriptor: null,
	// _freshLoad: track first load so when using holdOff until done, in the views case, onViewChanged isn't called a bunch, resulting in multi-builds of the search
	_freshLoad: true,
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this._freshLoad = true;
		this._displayGrid.scroller.measurePage = dojo.hitch(this._displayGrid.scroller, function(inPageIndex){
			if(this.grid.rowHeight){
				var height = this.grid.rowHeight ;//+ 1;
				return ((inPageIndex + 1) * this.rowsPerPage > this.rowCount ?
					(this.rowCount - inPageIndex  ) * this.rowsPerPage :
					this.rowsPerPage) * height;
					 
			}
			var n = this.getDefaultPageNode(inPageIndex);
			return (n && n.innerHTML) ? n.offsetHeight : undefined;
		});
		// VALIDATION
		if(!this.store){
			throw new Error("No store set for sixnetGrid.");
		}
		if(this.viewName.length == 0){
			throw new Error("No viewName set for sixnetGrid.");
		}
		if(this.module.length == 0){
			throw new Error("No module set for sixnetGrid.");
		}
		
		// CONNECTIONS
		this.connect(this._displayGrid, "_onFetchBegin", "onFetchBegin");
		_sixnet_framework.log(0, "onStartUp", this);
		this.connect(this, "onViewDescriptorLoaded", "buildGrid");
		this.connect(this._displayGrid, "onResizeColumn", "markViewChanged");
		this.connect(this._displayGrid, "onMoveColumn", "markViewChanged");
		
		
		// Setup toolbar
		if( null == this.toolbarWidgets) this.toolbarWidgets = [];
		dojo.forEach(this.toolbarWidgets, dojo.hitch(this, function(toolbarWidget){
			_sixnet_framework.log(1, "Toolbar widget:", toolbarWidget);
		}));
		// setup the queryHandle structure and build the internal (minimal) query
		if( null == this.query) this.query = {};
		this._internalQueryHandle = this.makeQueryHandle();
		// this.query is the one that is coded into the template or passed in props
		if(this.getMode(this.query) != 'empty')
			this._internalQueryHandle.setQuery(this.query);
		// Build an instance of the formatter if one is specified, otherwise use the default.
		try{
			var clazz = dojo.getObject(this.formatterClass);
			this._formatter = new clazz({ grid:this._displayGrid, store:this.store});
		}catch(e){
			// Failed to set formatter 
			_sixnet_framework.log(3, e.message);
		}
		this.getViewDescriptor();
	},
	setHoldOff: function(newValue){
		if(!this._holdOff){
			// if we are NOT in hold off mode. We can go directly to any value without other efforts.
			this._holdOff = newValue;
			return;
		}
		// If we are IN hold off mode, we have to check to see if the grid has been started.
		if(this._freshLoad){
			// start the grid for the first time.
			this._freshLoad = false;
			this._startGrid();
		}
		this._holdOff = (newValue?true:false);
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce thumbnail in "Running Apps" pane on side of dashboard
		return false;
	},
	// EVENTS
	onQueryChange: function(newQuery){
		// query generated by com.sixnet.services.core.data.query
		console.log('onQueryChange', newQuery, this._queryLock, this._holdOff);
		this._holdOffQuery = newQuery;
		if(this._holdOff) return;
		this._displayGrid.setQuery(newQuery);
	},
	onFetchBegin: function(size, keywordArgs){
		this.resultSize = size;
		try{
			this.onResultSizeChange(size);
		}catch(e){
			console.log("Error firing onResultSizeChange", e);
		}
	},
	onResultSizeChange: function(size){
	},
	onViewDescriptorLoaded: function(){
	},
	onViewChanged: function(){
	},
	
	// METHODS
	reloadGrid: function(){
		this._displayGrid.setQuery(this.getQuery());
	},
	_startGrid:function(){
		console.log('starting grid', this);
		this._displayGrid.attr({
			formatterScope:this._formatter,
			columnReordering: this.columnReordering
		});
		this._displayGrid._setStore(this.store);
		
		// Calls to onQueryChange must originate from query.  This false event mucks stuff up
		//this.onQueryChange(this._holdOffQuery?this._holdOffQuery:this.getQuery());
		this.reloadGrid();
//		//
//		if(this._freshLoad){
//			this._freshLoad = false;
			this.onViewChanged();
//		}
	},
	addToToolbar: function(toolbarWidget, side){
		setTimeout(dojo.hitch(this, function(toolbarWidget,side){
			this._toolbar.addChild(toolbarWidget);
			//toolbarWidget.placeAt(this._toolbar.domNode);
			toolbarWidget.domNode.style.height = '100%';
			
			if(side == 'left'){
				try{
					toolbarWidget.domNode.style.cssFloat = 'left';
					toolbarWidget.domNode.style.styleFloat = 'left';
				}catch(e){
					console.log(e);
				}
			}
			if(side == 'right'){
				try{
					toolbarWidget.domNode.style.cssFloat = 'right';
					toolbarWidget.domNode.style.styleFloat = 'right';
				}catch(e){
					console.log(e);
				}
			}
		}, toolbarWidget,side),10);
	},
	
	getFormatter: function(){
		// return formatter so that the parent can attach events on it.
		return this._formatter;
	},
	buildGrid: function(){
		var descriptorClone = dojo.clone(this._viewDescriptor);
		console.log("buildGrid of sixnetGrid:", this._viewDescriptor);
		this.buildGridStructure(descriptorClone);
		if(!this._holdOff){
			this._freshLoad = false;
			this._startGrid();
		}
	},
	getDescriptor: function(){
		return dojo.clone(this._viewDescriptor);
	},
	buildGridStructure: function(descriptor){
		// walk the descriptor... apply filters (like views)
		var filteredDescriptor = descriptor;
		this._displayGrid.setStructure(filteredDescriptor);
	},
	applyNewDescriptor: function(descriptor){
		this._displayGrid.setStructure(descriptor);
//		if(!this._freshLoad){
			this.onViewChanged();
//		}
	},
	markViewChanged: function(){
		this._viewChanged = true;
		this.onViewChanged();
	},
	getFullDescriptor: function(){
		return dojo.clone(this._viewDescriptor);
	},
	getGridStructure: function(){
		console.log('this._displayGrid.layout:  ', this._displayGrid.layout);
		console.log('this._displayGrid.layout.cells:  ', this._displayGrid.layout.cells);
		return this._displayGrid.layout.cells;
	},
	getViewDescriptor: function(){
		_sixnet_framework.bc(this.module, 'getViewDescriptor', { viewName: this.viewName}, dojo.hitch(this, function(response){
			if(response.successful){
				try{
					var viewDescriptor = { cells: [], all_cells: [] };
					dojo.forEach(response.data.cells, dojo.hitch(this, function(cell){
						// translate cell types into formatter calls.
						try{
							if(cell.field){
//								if(cell.hidden) return; // do not want to waste time processing hidden fields.
								// CHANGE: Grab all_cells here for column menu and views
								// cell .toString is overriden for sort (on field)
								cell.toString = dojo.hitch(cell, function(){ return this.name?this.name:this.field ;});
								viewDescriptor.all_cells.push(cell);
								if(!cell.hidden){
									viewDescriptor.cells.push(cell);
								}else{
									cell.hidden = false;
								}
								var cellType = cell.type ;
								cell.fieldType = cell.type;
								delete cell.type;
								switch( cellType){
								case 'jobtarget':
									cell.formatter = 'jobtarget';
									break;
								case 'jobname':
									cell.formatter = 'jobname';
									break;
								case 'jobimplementation':
									cell.formatter = 'jobimplementation';
									break;
								case 'interfaces':
									cell.formatter = 'interfaces';
									break;
								case 'client_config':
									cell.formatter = 'client_config';
									break;
								case 'epocseconds':
									cell.formatter = "timeToDate";
									break;
								case 'serial':
									cell.formatter = "serial";
									break;
//								case 'enum':
//									cell.type = dojox.grid.cells.ComboBox;
//									break;
								case 'lightbar':
									cell.formatter = "cellLightbarSignal";
									break;
								case 'alert':
									cell.formatter = "alertColor";
									break;
								case 'checkbox':
									cell.formatter = "booleanCheck";
									break;
								case 'username':
									cell.formatter = "username";
									break;
								case 'accountname':
									cell.formatter = "accountname";
								}
							}
						}catch(e){
							console.log("Error in getViewDescriptor",e);
						}
					}));
					this._viewDescriptor = viewDescriptor;
					_sixnet_framework.log(0, 'viewDescriptor', this._viewDescriptor);
					this.onViewDescriptorLoaded();
				}catch(e){
					console.log("FME", e);
				}
			}else{
				if(response.error){
					var alertError = response.error.split("::");
					// and do log out process
					alert(alertError);
					
				}
			}
		}));
		
	}
	
});

}

if(!dojo._hasResource["dojox.data.QueryReadStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.data.QueryReadStore"] = true;
dojo.provide("dojox.data.QueryReadStore");




dojo.declare("dojox.data.QueryReadStore",
	null,
	{
		//	summary:
		//		This class provides a store that is mainly intended to be used
		//		for loading data dynamically from the server, used i.e. for
		//		retreiving chunks of data from huge data stores on the server (by server-side filtering!).
		//		Upon calling the fetch() method of this store the data are requested from
		//		the server if they are not yet loaded for paging (or cached).
		//
		//		For example used for a combobox which works on lots of data. It
		//		can be used to retreive the data partially upon entering the
		//		letters "ac" it returns only items like "action", "acting", etc.
		//
		// note:
		//		The field name "id" in a query is reserved for looking up data
		//		by id. This is necessary as before the first fetch, the store
		//		has no way of knowing which field the server will declare as
		//		identifier.
		//
		//	example:
		// |	// The parameter "query" contains the data that are sent to the server.
		// |	var store = new dojox.data.QueryReadStore({url:'/search.php'});
		// |	store.fetch({query:{name:'a'}, queryOptions:{ignoreCase:false}});
		//
		// |	// Since "serverQuery" is given, it overrules and those data are
		// |	// sent to the server.
		// |	var store = new dojox.data.QueryReadStore({url:'/search.php'});
		// |	store.fetch({serverQuery:{name:'a'}, queryOptions:{ignoreCase:false}});
		//
		// |	<div dojoType="dojox.data.QueryReadStore"
		// |		jsId="store2"
		// |		url="../tests/stores/QueryReadStore.php"
		// |		requestMethod="post"></div>
		// |	<div dojoType="dojox.grid.data.DojoData"
		// |		jsId="model2"
		// |		store="store2"
		// |		sortFields="[{attribute: 'name', descending: true}]"
		// |		rowsPerPage="30"></div>
		// |	<div dojoType="dojox.Grid" id="grid2"
		// |		model="model2"
		// |		structure="gridLayout"
		// |		style="height:300px; width:800px;"></div>
	
		//
		//	todo:
		//		- there is a bug in the paging, when i set start:2, count:5 after an initial fetch() and doClientPaging:true
		//		  it returns 6 elemetns, though count=5, try it in QueryReadStore.html
		//		- add optional caching
		//		- when the first query searched for "a" and the next for a subset of
		//		  the first, i.e. "ab" then we actually dont need a server request, if
		//		  we have client paging, we just need to filter the items we already have
		//		  that might also be tooo much logic
		
		url:"",
		requestMethod:"get",
		//useCache:false,
		
		// We use the name in the errors, once the name is fixed hardcode it, may be.
		_className:"dojox.data.QueryReadStore",
		
		// This will contain the items we have loaded from the server.
		// The contents of this array is optimized to satisfy all read-api requirements
		// and for using lesser storage, so the keys and their content need some explaination:
		// 		this._items[0].i - the item itself 
		//		this._items[0].r - a reference to the store, so we can identify the item
		//			securly. We set this reference right after receiving the item from the
		//			server.
		_items:[],
		
		// Store the last query that triggered xhr request to the server.
		// So we can compare if the request changed and if we shall reload 
		// (this also depends on other factors, such as is caching used, etc).
		_lastServerQuery:null,
		
		// Store how many rows we have so that we can pass it to a clientPaging handler
		_numRows:-1,
		
		// Store a hash of the last server request. Actually I introduced this
		// for testing, so I can check if no unnecessary requests were issued for
		// client-side-paging.
		lastRequestHash:null,
		
		// summary:
		//		By default every request for paging is sent to the server.
		doClientPaging:false,
	
		// summary:
		//		By default all the sorting is done serverside before the data is returned
		//		which is the proper place to be doing it for really large datasets.
		doClientSorting:false,
	
		// Items by identify for Identify API
		_itemsByIdentity:null,
		
		// Identifier used
		_identifier:null,
	
		_features: {'dojo.data.api.Read':true, 'dojo.data.api.Identity':true},
	
		_labelAttr: "label",
		
		constructor: function(/* Object */ params){
			dojo.mixin(this,params);
		},
		
		getValue: function(/* item */ item, /* attribute-name-string */ attribute, /* value? */ defaultValue){
			//	According to the Read API comments in getValue() and exception is
			//	thrown when an item is not an item or the attribute not a string!
			this._assertIsItem(item);
			if(!dojo.isString(attribute)){
				throw new Error(this._className+".getValue(): Invalid attribute, string expected!");
			}
			if(!this.hasAttribute(item, attribute)){
				// read api says: return defaultValue "only if *item* does not have a value for *attribute*." 
				// Is this the case here? The attribute doesn't exist, but a defaultValue, sounds reasonable.
				if(defaultValue){
					return defaultValue;
				}
				console.log(this._className+".getValue(): Item does not have the attribute '"+attribute+"'.");
			}
			return item.i[attribute];
		},
		
		getValues: function(/* item */ item, /* attribute-name-string */ attribute){
			this._assertIsItem(item);
			var ret = [];
			if(this.hasAttribute(item, attribute)){
				ret.push(item.i[attribute]);
			}
			return ret;
		},
		
		getAttributes: function(/* item */ item){
			this._assertIsItem(item);
			var ret = [];
			for(var i in item.i){
				ret.push(i);
			}
			return ret;
		},
	
		hasAttribute: function(/* item */ item,	/* attribute-name-string */ attribute){
			//	summary: 
			//		See dojo.data.api.Read.hasAttribute()
			return this.isItem(item) && typeof item.i[attribute]!="undefined";
		},
		
		containsValue: function(/* item */ item, /* attribute-name-string */ attribute, /* anything */ value){
			var values = this.getValues(item, attribute);
			var len = values.length;
			for(var i=0; i<len; i++){
				if(values[i] == value){
					return true;
				}
			}
			return false;
		},
		
		isItem: function(/* anything */ something){
			// Some basic tests, that are quick and easy to do here.
			// >>> var store = new dojox.data.QueryReadStore({});
			// >>> store.isItem("");
			// false
			//
			// >>> var store = new dojox.data.QueryReadStore({});
			// >>> store.isItem({});
			// false
			//
			// >>> var store = new dojox.data.QueryReadStore({});
			// >>> store.isItem(0);
			// false
			//
			// >>> var store = new dojox.data.QueryReadStore({});
			// >>> store.isItem({name:"me", label:"me too"});
			// false
			//
			if(something){
				return typeof something.r != "undefined" && something.r == this;
			}
			return false;
		},
		
		isItemLoaded: function(/* anything */ something){
			// Currently we dont have any state that tells if an item is loaded or not
			// if the item exists its also loaded.
			// This might change when we start working with refs inside items ...
			return this.isItem(something);
		},
	
		loadItem: function(/* object */ args){
			if(this.isItemLoaded(args.item)){
				return;
			}
			// Actually we have nothing to do here, or at least I dont know what to do here ...
		},
	
		fetch:function(/* Object? */ request){
			//	summary:
			//		See dojo.data.util.simpleFetch.fetch() this is just a copy and I adjusted
			//		only the paging, since it happens on the server if doClientPaging is
			//		false, thx to http://trac.dojotoolkit.org/ticket/4761 reporting this.
			//		Would be nice to be able to use simpleFetch() to reduce copied code,
			//		but i dont know how yet. Ideas please!
			request = request || {};
			if(!request.store){
				request.store = this;
			}
			var self = this;
		
			var _errorHandler = function(errorData, requestObject){
				if(requestObject.onError){
					var scope = requestObject.scope || dojo.global;
					requestObject.onError.call(scope, errorData, requestObject);
				}
			};
		
			var _fetchHandler = function(items, requestObject, numRows){
				var oldAbortFunction = requestObject.abort || null;
				var aborted = false;
				
				var startIndex = requestObject.start?requestObject.start:0;
				if(self.doClientPaging == false){
					// For client paging we dont need no slicing of the result.
					startIndex = 0;
				}
				var endIndex = requestObject.count?(startIndex + requestObject.count):items.length;
		
				requestObject.abort = function(){
					aborted = true;
					if(oldAbortFunction){
						oldAbortFunction.call(requestObject);
					}
				};
		
				var scope = requestObject.scope || dojo.global;
				if(!requestObject.store){
					requestObject.store = self;
				}
				if(requestObject.onBegin){
					requestObject.onBegin.call(scope, numRows, requestObject);
				}
				if(requestObject.sort && self.doClientSorting){
					items.sort(dojo.data.util.sorter.createSortFunction(requestObject.sort, self));
				}
				if(requestObject.onItem){
					for(var i = startIndex; (i < items.length) && (i < endIndex); ++i){
						var item = items[i];
						if(!aborted){
							requestObject.onItem.call(scope, item, requestObject);
						}
					}
				}
				if(requestObject.onComplete && !aborted){
					var subset = null;
					if(!requestObject.onItem){
						subset = items.slice(startIndex, endIndex);
					}
					requestObject.onComplete.call(scope, subset, requestObject);
				}
			};
			this._fetchItems(request, _fetchHandler, _errorHandler);
			return request;	// Object
		},
	
		getFeatures: function(){
			return this._features;
		},
	
		close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
			// I have no idea if this is really needed ... 
		},
	
		getLabel: function(/* item */ item){
			//	summary:
			//		See dojo.data.api.Read.getLabel()
			if(this._labelAttr && this.isItem(item)){
				return this.getValue(item, this._labelAttr); //String
			}
			return undefined; //undefined
		},
	
		getLabelAttributes: function(/* item */ item){
			//	summary:
			//		See dojo.data.api.Read.getLabelAttributes()
			if(this._labelAttr){
				return [this._labelAttr]; //array
			}
			return null; //null
		},
		
		_xhrFetchHandler: function(data, request, fetchHandler, errorHandler){
			data = this._filterResponse(data);
			if(data.label){
				this._labelAttr = data.label;
			}
			var numRows = data.numRows || -1;

			this._items = [];
			// Store a ref to "this" in each item, so we can simply check if an item
			// really origins form here (idea is from ItemFileReadStore, I just don't know
			// how efficient the real storage use, garbage collection effort, etc. is).
			dojo.forEach(data.items,function(e){ 
				this._items.push({i:e, r:this}); 
			},this); 
			
			var identifier = data.identifier;
			this._itemsByIdentity = {};
			if(identifier){
				this._identifier = identifier;
				var i;
				for(i = 0; i < this._items.length; ++i){
					var item = this._items[i].i;
					var identity = item[identifier];
					if(!this._itemsByIdentity[identity]){
						this._itemsByIdentity[identity] = item;
					}else{
						throw new Error(this._className+":  The json data as specified by: [" + this.url + "] is malformed.  Items within the list have identifier: [" + identifier + "].  Value collided: [" + identity + "]");
					}
				}
			}else{
				this._identifier = Number;
				for(i = 0; i < this._items.length; ++i){
					this._items[i].n = i;
				}
			}
			
			// TODO actually we should do the same as dojo.data.ItemFileReadStore._getItemsFromLoadedData() to sanitize
			// (does it really sanititze them) and store the data optimal. should we? for security reasons???
			numRows = this._numRows = (numRows === -1) ? this._items.length : numRows;
			fetchHandler(this._items, request, numRows);
			this._numRows = numRows;		
		},
		
		_fetchItems: function(request, fetchHandler, errorHandler){
			//	summary:
			// 		The request contains the data as defined in the Read-API.
			// 		Additionally there is following keyword "serverQuery".
			//
			//	The *serverQuery* parameter, optional.
			//		This parameter contains the data that will be sent to the server.
			//		If this parameter is not given the parameter "query"'s
			//		data are sent to the server. This is done for some reasons:
			//		- to specify explicitly which data are sent to the server, they
			//		  might also be a mix of what is contained in "query", "queryOptions"
			//		  and the paging parameters "start" and "count" or may be even
			//		  completely different things.
			//		- don't modify the request.query data, so the interface using this
			//		  store can rely on unmodified data, as the combobox dijit currently
			//		  does it, it compares if the query has changed
			//		- request.query is required by the Read-API
			//
			// 		I.e. the following examples might be sent via GET:
			//		  fetch({query:{name:"abc"}, queryOptions:{ignoreCase:true}})
			//		  the URL will become:   /url.php?name=abc
			//
			//		  fetch({serverQuery:{q:"abc", c:true}, query:{name:"abc"}, queryOptions:{ignoreCase:true}})
			//		  the URL will become:   /url.php?q=abc&c=true
			//		  // The serverQuery-parameter has overruled the query-parameter
			//		  // but the query parameter stays untouched, but is not sent to the server!
			//		  // The serverQuery contains more data than the query, so they might differ!
			//
	
			var serverQuery = request.serverQuery || request.query || {};
			//Need to add start and count
			if(!this.doClientPaging){
				serverQuery.start = request.start || 0;
				// Count might not be sent if not given.
				if(request.count){
					serverQuery.count = request.count;
				}
			}
			if(!this.doClientSorting && request.sort){
				var sortInfo = [];
				dojo.forEach(request.sort, function(sort){
					if(sort && sort.attribute){
						sortInfo.push((sort.descending ? "-" : "") + sort.attribute);
					}
				});
				serverQuery.sort = sortInfo.join(',');
			}
			// Compare the last query and the current query by simply json-encoding them,
			// so we dont have to do any deep object compare ... is there some dojo.areObjectsEqual()???
			if(this.doClientPaging && this._lastServerQuery !== null &&
				dojo.toJson(serverQuery) == dojo.toJson(this._lastServerQuery)
				){
				this._numRows = (this._numRows === -1) ? this._items.length : this._numRows;
				fetchHandler(this._items, request, this._numRows);
			}else{
				var xhrFunc = this.requestMethod.toLowerCase() == "post" ? dojo.xhrPost : dojo.xhrGet;
				var xhrHandler = xhrFunc({url:this.url, handleAs:"json-comment-optional", content:serverQuery});
				xhrHandler.addCallback(dojo.hitch(this, function(data){
					this._xhrFetchHandler(data, request, fetchHandler, errorHandler);
				}));
				xhrHandler.addErrback(function(error){
					errorHandler(error, request);
				});
				// Generate the hash using the time in milliseconds and a randon number.
				// Since Math.randon() returns something like: 0.23453463, we just remove the "0."
				// probably just for esthetic reasons :-).
				this.lastRequestHash = new Date().getTime()+"-"+String(Math.random()).substring(2);
				this._lastServerQuery = dojo.mixin({}, serverQuery);
			}
		},
		
		_filterResponse: function(data){
			//	summary:
			//		If the data from servers needs to be processed before it can be processed by this
			//		store, then this function should be re-implemented in subclass. This default 
			//		implementation just return the data unchanged.
			//	data:
			//		The data received from server
			return data;
		},
	
		_assertIsItem: function(/* item */ item){
			//	summary:
			//		It throws an error if item is not valid, so you can call it in every method that needs to
			//		throw an error when item is invalid.
			//	item: 
			//		The item to test for being contained by the store.
			if(!this.isItem(item)){
				throw new Error(this._className+": Invalid item argument.");
			}
		},
	
		_assertIsAttribute: function(/* attribute-name-string */ attribute){
			//	summary:
			//		This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
			//	attribute: 
			//		The attribute to test for being contained by the store.
			if(typeof attribute !== "string"){ 
				throw new Error(this._className+": Invalid attribute argument ('"+attribute+"').");
			}
		},
	
		fetchItemByIdentity: function(/* Object */ keywordArgs){
			//	summary: 
			//		See dojo.data.api.Identity.fetchItemByIdentity()
	
			// See if we have already loaded the item with that id
			// In case there hasn't been a fetch yet, _itemsByIdentity is null
			// and thus a fetch will be triggered below.
			if(this._itemsByIdentity){
				var item = this._itemsByIdentity[keywordArgs.identity];
				if(!(item === undefined)){
					if(keywordArgs.onItem){
						var scope = keywordArgs.scope ? keywordArgs.scope : dojo.global;
						keywordArgs.onItem.call(scope, {i:item, r:this});
					}
					return;
				}
			}
	
			// Otherwise we need to go remote
			// Set up error handler
			var _errorHandler = function(errorData, requestObject){
				var scope = keywordArgs.scope ? keywordArgs.scope : dojo.global;
				if(keywordArgs.onError){
					keywordArgs.onError.call(scope, errorData);
				}
			};
			
			// Set up fetch handler
			var _fetchHandler = function(items, requestObject){
				var scope = keywordArgs.scope ? keywordArgs.scope : dojo.global;
				try{
					// There is supposed to be only one result
					var item = null;
					if(items && items.length == 1){
						item = items[0];
					}
					
					// If no item was found, item is still null and we'll
					// fire the onItem event with the null here
					if(keywordArgs.onItem){
						keywordArgs.onItem.call(scope, item);
					}
				}catch(error){
					if(keywordArgs.onError){
						keywordArgs.onError.call(scope, error);
					}
				}
			};
			
			// Construct query
			var request = {serverQuery:{id:keywordArgs.identity}};
			
			// Dispatch query
			this._fetchItems(request, _fetchHandler, _errorHandler);
		},
		
		getIdentity: function(/* item */ item){
			//	summary: 
			//		See dojo.data.api.Identity.getIdentity()
			var identifier = null;
			if(this._identifier === Number){
				identifier = item.n; // Number
			}else{
				identifier = item.i[this._identifier];
			}
			return identifier;
		},
		
		getIdentityAttributes: function(/* item */ item){
			//	summary:
			//		See dojo.data.api.Identity.getIdentityAttributes()
			return [this._identifier];
		}
	}
);

}

if(!dojo._hasResource['com.sixnet.services.widgets.debugger']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.debugger'] = true;
dojo.provide('com.sixnet.services.widgets.debugger');







///  ????????? where is this?
//dojo.require('com.sixnet.services.core.Bespin');

dojo.declare('com.sixnet.services.widgets.debugger', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div dojoAttachPoint=\"DEBUGGER\" style=\"background:lightgray;\">\n\t<div dojoType=\"dijit.layout.BorderContainer\" style=\"background:lightgray; width:100%; height:100%; margin-right:15px; border:none\" gutters=\"false\">\n\t\t<div dojoType=\"dijit.layout.BorderContainer\" region=\"center\" gutters=\"false\" style=\"padding:0\">  \n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"top\" style=\"clear:both; padding:5px; height:50px; float: left; background:#ffffff\">\n\t\t\t\t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"module\" value=\"providers\">\n\t\t\t\t</div>\n\t\t\t\t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"method\" value=\"getInstalled\">\n\t\t\t\t</div>\n\t\t\t\t<div dojoType=\"dijit.form.Button\" label=\"Call\" dojoAttachEvent=\"onClick:frameworkCall\">\n\t\t\t\t</div>\n\t\t\t</div>\n \t\t\t<div dojoType=\"dijit.layout.BorderContainer\" region=\"center\" >\n\t\t\t\t<div dojoAttachPoint=\"pitcher\" dojoType=\"dijit.layout.ContentPane\" region=\"left\" style=\"width:45%; margin-right:14px; background:blue\">\n\t\t\t\t\t<iframe class=\"debugLeft\" src=\"debug_left.html\" style=\"width:100%; height:100%;\" ></iframe>\n\t\t\t\t</div>\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" dojoAttachPoint=\"catcher\" style=\"background:blue\">\n\t\t\t\t\t<iframe class=\"debugRight\" src=\"debug_left.html\" style=\"width:100%; height:100%\" ></iframe>\n\t\t\t\t</div>\n\t\t\t</div> \n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"catcher\" style=\"width: 45%; height:100%; float: left; background:lightgray\">\n\t\t\t\t<iframe class=\"debugRight\" src=\"debug_left.html\" style=\"width:100%; height:500px\" ></iframe>\n\t\t\t</div>\n\t\t</div>\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"background:lightgray; height:25px\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; font-weight:bold\">\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	values:{count:0},
	rightFrame: false,
	leftFrame: false,
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.connect( this.dashBoard, "onHideWidget", "onHide");
		
		var leftList = dojo.query(".debugLeft", this.domNode);
		leftList[0].onload = dojo.hitch(this, function(){
			this.debugLeft = leftList[0].contentWindow.bespin;
			this.debugLeft.setContent("{}");
		});
		this.leftFrame = leftList[0];
		var rightList = dojo.query(".debugRight", this.domNode);
		rightList[0].onload = dojo.hitch(this, function(){
			this.debugRight = rightList[0].contentWindow.bespin;
			this.debugRight.setContent("");
		});
		this.rightFrame = rightList[0];
		this._subscribes.push( dojo.subscribe( '/status/hint', dojo.hitch(this.statusLine, "setContent")));
		
		// wait for the tiki to load
	
	},
	onHide: function(widget){
		// when this widget hides, it has to clear the besbin iframes.
		if( widget != this) return;
		this.pitcher.domNode.removeChild(this.leftFrame);
		this.catcher.domNode.removeChild(this.rightFrame);
	},
//	=====================================  //
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce thumbnail in "Running Apps" pane on side of dashboard
		return new dijit.layout.ContentPane({content:'DEBUGGER<br />'+this.incrementWidgetCount()});
	},
	
	frameworkCall: function(){
		//  module, method, params
		_sixnet_framework.bc(this.module.getValue(), this.method.getValue(), dojo.fromJson(this.debugLeft.getContent()), dojo.hitch(this, function(response){
			if( response.successful ){
				_sixnet_framework.log(1, this.debugRight);
				var info = dojo.toJson(response.data, true);
				this.debugRight.setContent(info);//computeFrameWithParentFrame();
			}else{
				alert(response.error);
			}
		}));
	}
});

}

if(!dojo._hasResource['com.sixnet.services.widgets.debugDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.debugDash'] = true;
dojo.provide('com.sixnet.services.widgets.debugDash');
// tell package managerthat a specific package has been loaded
// load dojo dashWidgetBash

// _Templated == mix-in Widget HTML




// simulate Class system like Java with dojo.declare 
// 3 arguments (optional_global_name,
//		null or base class or array of objects (multiple inheritance),
//			object hash of properties to be mixed in after all other inheritance has been solved)
// dojo.moduleUrl is used to return a dojo._Url object relative to a module.
dojo.declare('com.sixnet.services.widgets.debugDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('ccom.sixnet.services.widgets',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown,onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashImage\" src=\"${moduleUrl}templates/images/debug.png\"></img>\n\t<div class=\"dashLabel\">Dbooger</div>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onClick: function(){
		this.dashBoard.runApp( 'com.sixnet.services.widgets.debugger');
	}
		
});

}

if(!dojo._hasResource["com.sixnet.services.widgets.sixnetGridCheckSearch"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.sixnetGridCheckSearch"] = true;
dojo.provide("com.sixnet.services.widgets.sixnetGridCheckSearch");






dojo.declare("com.sixnet.services.widgets.sixnetGridCheckSearch",[dijit._Widget, dijit._Templated],{
	widgetsInTemplate: true,
	templateString: dojo.cache("com.sixnet.services.widgets", "templates/sixnetGridCheckSearch.html", "<div>\n\t<div dojoType=\"dijit.layout.ContentPane\" style=\"float:left; margin-left:.25em\">\t\n\t\t<div style=\"float:left; font-family:Myriad,Helvetica,Tahoma,Arial,clean,sans-serif; margin-top:.5em;\" dojoType=\"dijit.form.TextBox\" placeHolder=\"...search\" dojoAttachEvent=\"onKeyUp: _onSearchValueChange, onChange: _onSearchValueChange\" dojoAttachPoint=\"searchValue\"></div>\n\t\t<div style=\"float:left; margin-top:.5em;\" dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"searchMenu\"></div>\n\t\t<div style=\"float:left; margin-top:.5em;\" dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"searchButtons\"></div>\n\t</div>\n</div>\n"),
	grid: null,
	gridQueryHandle: null,
	compositeQuery: null,
	searchFields: null,
	alteredSearchFields: null,
	searchText: '',
	dirtyText: false,
	dirtyChecks: false,
	buttonsShown: false,
	ddButton: null,
	_queryHandles: null,
	postCreate: function(){
		// move this widget to the toolbar
		this.compositeQuery = new com.sixnet.services.core.data.query({ conjunction:'OR'});
		this.gridQueryHandle = this.grid.makeQueryHandle();
		this._queryHandles = [];
		this.alteredSearchFields = {};
		this.connect(this.grid, "onViewDescriptorLoaded", "_initializeSearchMenu");
		this.connect(this.grid, "onViewChanged", "_buildSearchMenu");
		this.connect(this.compositeQuery, "onQueryChange", "_compositeQueryChange");
		this.connect(this, "_onSearchChanged", "showApplyCancel");
		this.connect(this, "_onSearchValueChange", "showApplyCancel");
        this.grid.addToToolbar(this, 'left');
		if(dojo.isIE){
			dojo.style(this.searchValue.domNode, 'margin-top', '.23em');
		}
	},
	_compositeQueryChange: function(newQuery){
		this.gridQueryHandle.setQuery(newQuery);
	},
	_onSearchValueChange: function(event){
		this.dirtyText  = (this.searchText != this.searchValue.getValue());
//		if( this.dirtyText && !dojo.isObject(event)){
//			this.applyChanges(false);
//		}
		if( dojo.isObject(event) && ( event.keyCode == 13)){
			this.applyChanges(false);
//			this.grid.holdOff = false;
//			this.grid.startGrid();
		}
		console.log('searchValueChange', arguments);
	},
	_onChange: function(searchFields, value){
		// use query lock to prevent corruption of the query list.
		this.compositeQuery.queryLock(dojo.hitch(this, function(){
			
			for(var i = 0; i < this._queryHandles.length; i++){
				this._queryHandles[i].releaseQuery();
			}
			this._queryHandles = [];
			// build queries with OR ...
			for( var index in searchFields){
				// prevent prototype corruption
				if(!searchFields.hasOwnProperty(index)) continue;
				var queryHandle = this.compositeQuery.makeQueryHandle();
				queryHandle.setQuery({ left_field:index, operator:'LIKE', right_value:'%'+value+'%'});
				this._queryHandles.push(queryHandle);
			}
			
		}));	
		this.grid.setHoldOff(false);
	},
	applyChanges: function(applyChecks){
		this.dirtyText = false;
		if(applyChecks && this.dirtyChecks){
			this.searchFields = dojo.clone(this.alteredSearchFields);
			this.dirtyChecks = false;
		}
		this.searchText = this.searchValue.getValue();
		setTimeout(dojo.hitch(this, function(){
			// on some browsers, onChange will fire again causing the ApplyCancel buttons to re-appear.
			// hide them AFTER that.
			this.hideApplyCancel();
		},0));
		this._onChange(this.searchFields, this.searchText);
	},
	setSearchText: function(newSearchText){
		this.searchValue.setValue(newSearchText);
	},
	showApplyCancel: function(){
		if(!this.dirtyText && !this.dirtyChecks){
			this.hideApplyCancel();
			return;
		}
		if(this.buttonsShown){
			return;
		}
		var cancelButton = new dijit.form.Button({ label:"Cancel", onClick: dojo.hitch(this, function(){
			this.dirtyChecks = false;
			this.alteredSearchFields = dojo.clone(this.searchFields);
			this.searchValue.setValue(this.searchText);
			setTimeout(dojo.hitch(this, function(){
				// on some browsers, onChange will fire again causing the ApplyCancel buttons to re-appear.
				// hide them AFTER that.
				this.hideApplyCancel();
			},0));
			
		})});
		cancelButton.placeAt( this.searchButtons.domNode);
		var applyButton = new dijit.form.Button({ label:"Apply", onClick: dojo.hitch(this, "onApplyButtonClick")});
		applyButton.placeAt( this.searchButtons.domNode);
		this.buttonsShown = true;
	},
	
	onApplyButtonClick: function(){
		this.dirtyChecks = true;
		this.applyChanges(true); // apply by click results in applying checkboxes.  Apply by enter does not.
//		this.grid.holdOff = false;
//		this.grid.startGrid();
	},
	
	hideApplyCancel: function(){
		this.searchButtons.setContent('');
		if(this.dirtyChecks){
			this.dirtyChecks = false;
			this.alteredSearchFields = dojo.clone(this.searchFields);
		}
		this.searchMenu.setContent('');
		this._buildSearchMenu();
		this.buttonsShown = false;
	},
	_onSearchChanged: function(){
		this.dirty = true;
	},
	_initializeSearchMenu: function(){
		try{
//			this._buildSearchMenu();
			setTimeout(dojo.hitch(this,"_buildSearchMenu"), 10);
	        setTimeout(dojo.hitch(this,"onSearchMenuInitialized"), 10);
		}catch(e){
			console.log("error in _initializeSearchMenu",e);
		}

	},
	_buildSearchMenu: function(){
		try{
			//var dataSet = this.grid.getDescriptor();
//			var dataSet = this.grid.getGridStructure();
			if(this.ddButton && this.ddButton.domNode){
				this.ddButton.destroyRecursive();
			}
			var dataCells = [];
			var tmpCells = this.grid.getGridStructure();//dataSet['cells'];
			for(var i=0; i< tmpCells.length;i++){
				tmpCells[i].toString = dojo.hitch(tmpCells[i], function(){ return this.name?this.name:this.field ;});
				dataCells.push(tmpCells[i]);
			}
			console.log("_buildSearchMenu structure:  ", dataCells);
//			var  = dojo.clone(dataSet);
			// only initialize searchFields on first pass.
			if(!this.searchFields){
				this.searchFields = {};
				this.alteredSearchFields = {};
				for(var h=0; h<dataCells.length; h++){
					if(dataCells[h].search){
						this.searchFields[dataCells[h].field] = true;
						this.alteredSearchFields[dataCells[h].field] = true;
					}
				}
			}
			var dataSetLength = dataCells.length;
	        //  set up holder now that we have the correct length to apply to dimensions
	        var divideOn = 10;
			var holderN_width = 178;
			if(dataSetLength > divideOn){
				holderN_width = Math.round(((dataSetLength/divideOn)*170)+8);
			}
		    var holderN = new dijit.layout.ContentPane({style: "width:".concat(holderN_width).concat("; background:#fff; padding:4px; border:1px solid #7eabcd;")});
		    dojo.addClass(dojo.byId(holderN.domNode), '.dijitMenuItem');
		    dojo.addClass(dojo.byId(holderN.domNode), '.dijitReset');
			///////////////////////  ADD DROP DOWN BUTTON HERE  ///////////////////////////
			//  add dropdown button DropDownButton  dropDown: this.columnsMenu
		    this.ddButton = new dijit.form.DropDownButton({
	            label: "Search In:",
	            dropDown: holderN
	        });
		    dojo.style(this.ddButton.domNode, "float", "left");
		    this.ddButton.placeAt(this.searchMenu.domNode);
	        // The cells implement toString by returning the field name.  We can sort cells now.
	        var pCells = dataCells;
        	pCells.sort();
	        ///////////////////////////////////////////////////////
	        //  Add check boxes, connect to show/hide columns
	        var makeNewContentPane = true;
	        var columnCP = {};
	        //
	        
	        for(var i = 0; i < pCells.length; i++){
		       //////////// _sixnet_framework.log(1, " this.cellByFieldName: ", this.cellByFieldName);
	        	//  add column to holder
	        
	        	if(makeNewContentPane == true){
	    	        columnCP = new dijit.layout.ContentPane({style:"float:left; width:160px"}).placeAt(dojo.byId(holderN.domNode), "last");
	    	        makeNewContentPane = false;
	        	}
	        	//  add checkbox row to colummn
	        	var checkboxCP = new dijit.layout.ContentPane({style:"float:left; clear:both; height:20px; width:160px"}).placeAt(dojo.byId(columnCP.domNode), "last");
				var checkState = false;
				var checkField = pCells[i].field;
				var visualLabel = pCells[i].name;
				var cnm = checkField;
				var color = "#000000";
				
	        	
				if(typeof(this.searchFields[checkField]) != 'undefined' && this.searchFields[checkField]){
					checkState = true;
				}
				///////////////////////////////////////////////////////////////////////////////////
				//////////////////////  SETUP CHECKBOX OBJ, ATTACH TO _checkBoxCP  ////////////////
				var cb = new com.sixnet.services.widgets.LabeledCheckBox({
					name:cnm, 
					value: cnm, 
					checked: (checkState?true:false), 
					onChange: dojo.hitch(this, function(field, v){
						if(typeof(v) == 'undefined') return;
						this.setSearchField(field, v);
						this._onSearchChanged();
					}, checkField)
				});
				dojo.addClass(cb, "gridCheckSearch");
				// add CheckBox to cp (content pane)
				cb.placeAt(checkboxCP.domNode);
		       	dojo.query(dojo.byId(checkboxCP.domNode)).addContent("<div style='float:left; clear:right; margin-left:5px;'>"+visualLabel+"</div>");
		       	if(i%divideOn == 0 && i != 0){
					makeNewContentPane = true;
				}
				
			} // for(var i = 0; i < pCells.length; i++)
	        // Wait till we are actually in the dom and let other widgets know...
		}catch(e){
			console.log("error in _buildSearchMenu", e);
		}
	},
	
//	setChecksToField: function(field, fireQuery){
//		console.log("QUERY:  ", dojo.query(".gridCheckSearch", this.searchMenu.domNode), "  SET TO: ", field);
//		if(fireQuery == true){
//			this.onApplyButtonClick();
//		}
//	},
	
	setSearchField: function(field, v){
		
		var fieldIsOn = ( 'undefined' != typeof(this.alteredSearchFields[field])) && this.alteredSearchFields[field];
		
		if(v == true){
			this.alteredSearchFields[field] = true;
			this.dirtyChecks = !fieldIsOn;
		}else{
			delete this.alteredSearchFields[field];
			this.dirtyChecks = fieldIsOn;
		}
	},
	onSearchMenuInitialized: function(){}
});

}

if(!dojo._hasResource['com.sixnet.services.widgets.toolbarWidget']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.toolbarWidget'] = true;







dojo.provide('com.sixnet.services.widgets.toolbarWidget');

/**
 * sixnetGrid provides a data display widget that understands the Sixnet "getViewData" and "updateViewData" paradigm
 * Remember... In general ONLY call methods of a class from outside.  Never use properties of a class directly.
 * Note: In some cases when dealing with dojo classes it is necessary to handle properties that do not have setters and getters
 * 			Avoid this whereever possible.
 */


dojo.declare('com.sixnet.services.widgets.toolbarWidget', [dijit._Widget, dijit._Templated], {
	// ******** dojo properties *******
	widgetsInTemplate: true,
	templateString:"<div>\n\tDice!\n</div>\n",
	// ******** attributes (template setable) ***********
	// **********  Private Properties of sixnetGrid ********* //

	// ********** Methods *************** //
	constructor: function(){
		_sixnet_framework.log(1, "construct toolbarwidget", arguments);
	},
	postCreate: function(){
	this.inherited("postCreate", arguments);
	}
});

}

if(!dojo._hasResource["com.sixnet.services.widgets.sixnetGridRadioSearch"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.sixnetGridRadioSearch"] = true;
dojo.provide("com.sixnet.services.widgets.sixnetGridRadioSearch");






dojo.declare("com.sixnet.services.widgets.sixnetGridRadioSearch",[dijit._Widget, dijit._Templated],{
	widgetsInTemplate: true,
	templateString: dojo.cache("com.sixnet.services.widgets", "templates/sixnetGridRadioSearch.html", "<div>\n\t<div dojoType=\"dijit.layout.ContentPane\">\t\n\t\t<div dojoType=\"dijit.form.Form\" onSubmit=\"return false;\">\n\t\t\t<div style=\"float:left\" dojoType=\"dijit.form.TextBox\" dojoAttachEvent=\"onKeyUp: _onSearchValueChange, onChange: _onSearchValueChange\" dojoAttachPoint=\"searchValue\"></div>\n\t\t\t<div style=\"float:left\" dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"searchMenu\"></div>\n\t\t\t<div style=\"float:left\" dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"searchButtons\"></div>\n\t\t</div>\n\t</div>\n</div>\n"),
	grid: null,
	gridQueryHandle: null,
	compositeQuery: null,
	searchField: '',
	alteredSearchFields: null,
	searchText: '',
	dirtyText: false,
	dirtyChecks: false,
	buttonsShown: false,
	ddButton: null,
	_queryHandles: null,
	postCreate: function(){
		// move this widget to the toolbar
		this.compositeQuery = new com.sixnet.services.core.data.query({ conjunction:'OR'});
		this.gridQueryHandle = this.grid.makeQueryHandle();
		this._queryHandles = [];
		this.grid.addToToolbar(this,'left');
		this.alteredSearchField = {};
		this.connect(this.grid, "onViewDescriptorLoaded", "_buildSearchMenu");
		this.connect(this.compositeQuery, "onQueryChange", "_compositeQueryChange");
		this.connect(this, "_onSearchChanged", "showApplyCancel");
		this.connect(this, "_onSearchValueChange", "showApplyCancel");
	},
	_compositeQueryChange: function(newQuery){
		this.gridQueryHandle.setQuery(newQuery);
	},
	_onSearchValueChange: function(event){
		this.dirtyText  = (this.searchText != this.searchValue.getValue());
		if( this.dirtyText && !dojo.isObject(event)){
			this.applyChanges();
		}
		if( this.dirtyText && dojo.isObject(event) && ( event.keyCode == 13)){
			this.applyChanges();
		}
		console.log('searchValueChange', arguments);
	},
	_onChange: function(searchField, value){
		// use query lock to prevent corruption of the query list.
		this.compositeQuery.queryLock(dojo.hitch(this, function(){
			console.log("entering gridcheck query lock");
			for(var i = 0; i < this._queryHandles.length; i++){
				this._queryHandles[i].releaseQuery();
			}
			this._queryHandles = [];
			// build queries with OR ...
			var queryHandle = this.compositeQuery.makeQueryHandle();
			queryHandle.setQuery({ left_field:this.searchField, operator:'LIKE', right_value:'%'+value+'%'});
			this._queryHandles.push(queryHandle);
			console.log("exiting gridcheck query lock");
		}));	
	},
	applyChanges: function(applyChecks){
		this.dirtyText = false;
		if(applyChecks){
			this.searchField = this.alteredSearchField;
			this.dirtyChecks = false;
		}
		this.searchText = this.searchValue.getValue();
		setTimeout(dojo.hitch(this, function(){
			// on some browsers, onChange will fire again causing the ApplyCancel buttons to re-appear.
			// hide them AFTER that.
			this.hideApplyCancel();
		},0));
		this._onChange(this.searchField, this.searchText);
	},
	showApplyCancel: function(){
		if(!this.dirtyText && !this.dirtyChecks){
			this.hideApplyCancel();
			return;
		}
		if(this.buttonsShown){
			return;
		}
		var cancelButton = new dijit.form.Button({ label:"Cancel", onClick: dojo.hitch(this, function(){
			this.dirtyChecks = false;
			this.alteredSearchField = this.searchField;
			this.searchValue.setValue(this.searchText);
			setTimeout(dojo.hitch(this, function(){
				// on some browsers, onChange will fire again causing the ApplyCancel buttons to re-appear.
				// hide them AFTER that.
				this.hideApplyCancel();
			},0));
			
		})});
		cancelButton.placeAt( this.searchButtons.domNode);
		var applyButton = new dijit.form.Button({ label:"Apply", onClick: dojo.hitch(this, function(){
			this.dirtyChecks = true;
			this.applyChanges(true); // apply by click results in applying checkboxes.  Apply by enter does not.
		})});
		applyButton.placeAt( this.searchButtons.domNode);
		this.buttonsShown = true;
	},
	hideApplyCancel: function(){
		this.searchButtons.setContent('');
		this.searchMenu.setContent('');
		this._buildSearchMenu();
		this.buttonsShown = false;
	},
	_onSearchChanged: function(){
		this.dirty = true;
	},
	_buildSearchMenu: function(){
		var dataSet = this.grid.getDescriptor();
		var dataCells = dataSet['cells'];
		// only initialize searchFields on first pass.
		if(!this.searchField){
			this.searchField = '';
			for(var h=0; h<dataCells.length; h++){
				if(dataCells[h].search){
					this.searchField = dataCells[h].field;
				}
			}
		}
		var dataSetLength = dataSet['cells'].length;
        //  set up holder now that we have the correct length to apply to dimensions
        var divideOn = 10;
		var holder0_width = 178;
		if(dataSetLength > divideOn){
			holder0_width = Math.round(((dataSetLength/divideOn)*170)+8);
		}
	    var holder0 = new dijit.layout.ContentPane({style: "width:".concat(holder0_width).concat("; background:#fff; padding:4px; border:1px solid #7eabcd;")});
	    dojo.addClass(dojo.byId(holder0.domNode), '.dijitMenuItem');
	    dojo.addClass(dojo.byId(holder0.domNode), '.dijitReset');
		///////////////////////  ADD DROP DOWN BUTTON HERE  ///////////////////////////
		//  add dropdown button DropDownButton  dropDown: this.columnsMenu
	    this.ddButton = new dijit.form.DropDownButton({
            label: "Search In:",
            dropDown: holder0
        });
	    dojo.style(this.ddButton.domNode, "float", "left");
	    this.ddButton.placeAt(this.searchMenu.domNode);
        // The cells implement toString by returning the field name.  We can sort cells now.
        var pCells = dataSet['cells'];
        pCells.sort();
        ///////////////////////////////////////////////////////
        //  Add check boxes, connect to show/hide columns
        var makeNewContentPane = true;
        var columnCP = {};
        //
        
        for(var i = 0; i < pCells.length; i++){
	       //////////// _sixnet_framework.log(1, " this.cellByFieldName: ", this.cellByFieldName);
        	//  add column to holder
        	if(makeNewContentPane == true){
    	        columnCP = new dijit.layout.ContentPane({style:"float:left; width:160px"}).placeAt(dojo.byId(holder0.domNode), "last");
    	        makeNewContentPane = false;
        	}
        	//  add checkbox row to colummn
        	var checkboxCP = new dijit.layout.ContentPane({style:"float:left; clear:both; height:20px; width:160px"}).placeAt(dojo.byId(columnCP.domNode), "last");
			var checkState = false;
			var checkField = pCells[i].field;
			var visualLabel = pCells[i].name;
			var cnm = checkField;
			var color = "#000000";
			
		
			///////////////////////////////////////////////////////////////////////////////////
			//////////////////////  SETUP CHECKBOX OBJ, ATTACH TO _checkBoxCP  ////////////////
			var cb = new com.sixnet.services.widgets.LabeledRadioButton({
				name:this.searchField, 
				value: cnm, 
				checked: (this.searchField == cnm), 
				onChange: dojo.hitch(this, function(field, v){
					if(typeof(v) == 'undefined') return;
					this.dirtyChecks = true;
					if(v == true){
						this.alteredSearchField = field;
					}
					this._onSearchChanged();
				}, checkField)
			});
			// add CheckBox to cp (content pane)
			cb.placeAt(checkboxCP.domNode);
			dojo.query(dojo.byId(checkboxCP.domNode)).addContent("<div style='float:left; clear:right; margin-left:5px;'>"+visualLabel+"</div>");
			if(i%divideOn == 0 && i != 0){
				makeNewContentPane = true;
			}
		} // for(var i = 0; i < pCells.length; i++)
        
	}
});

}

if(!dojo._hasResource["dojox.widget.PlaceholderMenuItem"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.widget.PlaceholderMenuItem"] = true;
dojo.provide("dojox.widget.PlaceholderMenuItem");



dojo.declare("dojox.widget.PlaceholderMenuItem", dijit.MenuItem, {
	// summary:
	//		A menu item that can be used as a placeholder.  Set the label
	//		of this item to a unique key and you can then use it to add new
	//		items at that location.  This item is not displayed.
	
	_replaced: false, 
	_replacedWith: null, 
	_isPlaceholder: true, 

	postCreate: function(){ 
		this.domNode.style.display = "none"; 
		this._replacedWith = []; 
		if(!this.label){
			this.label = this.containerNode.innerHTML;
		}
		this.inherited(arguments); 
	}, 
	
	replace: function(/*dijit.MenuItem[]*/ menuItems){ 
		// summary:
		//		replaces this menu item with the given menuItems.  The original
		//		menu item is not actually removed from the menu - so if you want
		//		it removed, you must do that explicitly.
		// returns:
		//		true if the replace happened, false if not
		if(this._replaced){ return false; } 

		var index = this.getIndexInParent(); 
		if(index < 0){ return false; } 

		var p = this.getParent(); 

		dojo.forEach(menuItems, function(item){ 
			p.addChild(item, index++); 
		}); 
		this._replacedWith = menuItems; 

		this._replaced = true; 
		return true;
	}, 
	
	unReplace: function(/*Boolean?*/ destroy){ 
		// summary:
		//		Removes menu items added by calling replace().  It returns the
		//		array of items that were actually removed (in case you want to
		//		clean them up later)
		// destroy:
		//		Also call destroy on any removed items.
		// returns:
		//		The array of items that were actually removed
		
		if(!this._replaced){ return []; } 

		var p = this.getParent(); 
		if(!p){ return []; } 

		var r = this._replacedWith; 
		dojo.forEach(this._replacedWith, function(item){ 
			p.removeChild(item); 
			if(destroy){ 
				item.destroy(); 
			} 
		}); 
		this._replacedWith = []; 
		this._replaced = false; 

		return r; // dijit.MenuItem[] 
	} 
}); 

// Se need to extend dijit.Menu so that we have a getPlaceholders function.
dojo.extend(dijit.Menu, { 
	getPlaceholders: function(/*String?*/ label){ 
		// summary:
		//		returns an array of placeholders with the given label.  There
		//		can be multiples.
		// label:
		//		Label to search for - if not specified, then all placeholders
		//		are returned
		// returns:
		//		An array of placeholders that match the given label
		var r = []; 

		var children = this.getChildren(); 
		children.forEach(function(child){ 
			if(child._isPlaceholder && (!label || child.label == label)){
				r.push(child); 
			}else if(child._started && child.popup && child.popup.getPlaceholders){
				r = r.concat(child.popup.getPlaceholders(label));
			}else if(!child._started && child.dropDownContainer){
				var node = dojo.query("[widgetId]", child.dropDownContainer)[0];
				var menu = dijit.byNode(node);
				if(menu.getPlaceholders){
					r = r.concat(menu.getPlaceholders(label));
				}
			}
		}, this); 
		return r; // dojox.widget.PlaceholderMenuItem[]
	}
}); 

}

if(!dojo._hasResource["dojo.data.api.Request"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.data.api.Request"] = true;
dojo.provide("dojo.data.api.Request");

dojo.declare("dojo.data.api.Request", null, {
	//	summary:
	//		This class defines out the semantics of what a 'Request' object looks like
	//		when returned from a fetch() method.  In general, a request object is
	//		nothing more than the original keywordArgs from fetch with an abort function 
	//		attached to it to allow users to abort a particular request if they so choose. 
	//		No other functions are required on a general Request object return.  That does not
	//		inhibit other store implementations from adding extentions to it, of course.
	//
	//		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 details on fetch, see dojo.data.api.Read.fetch().

	abort: function(){
		//	summary:
		//		This function is a hook point for stores to provide as a way for 
		//		a fetch to be halted mid-processing.
		//	description:
		//		This function is a hook point for stores to provide as a way for 
		//		a fetch to be halted mid-processing.  For more details on the fetch() api,
		//		please see dojo.data.api.Read.fetch().
		throw new Error('Unimplemented API: dojo.data.api.Request.abort');
	}
});

}

if(!dojo._hasResource["dojo.data.api.Read"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.data.api.Read"] = true;
dojo.provide("dojo.data.api.Read");


dojo.declare("dojo.data.api.Read", 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.data APIs, 
	//		please visit: http://www.dojotoolkit.org/node/98

	getValue: function(	/* item */ item, 
						/* attribute-name-string */ attribute, 
						/* value? */ defaultValue){
		//	summary:
		//		Returns a single attribute value.
		//		Returns defaultValue if and only if *item* does not have a value for *attribute*.
		//		Returns null if and only if null was explicitly set as the attribute value.
		//		Returns undefined if and only if the item does not have a value for the
		//		given attribute (which is the same as saying the item does not have the attribute). 
		// description:
		//		Saying that an "item x does not have a value for an attribute y"
		//		is identical to saying that an "item x does not have attribute y". 
		//		It is an oxymoron to say "that attribute is present but has no values" 
		//		or "the item has that attribute but does not have any attribute values".
		//		If store.hasAttribute(item, attribute) returns false, then
		//		store.getValue(item, attribute) will return undefined.
		//
		//	item:
		//		The item to access values on.
		//	attribute:
		//		The attribute to access represented as a string.
		//	defaultValue:
		//		Optional.  A default value to use for the getValue return in the attribute does not exist or has no value.
		//
		//	exceptions:
		//		Throws an exception if *item* is not an item, or *attribute* is not a string
		//	example:
		//	|	var darthVader = store.getValue(lukeSkywalker, "father");
		var attributeValue = null;
		throw new Error('Unimplemented API: dojo.data.api.Read.getValue');
		return attributeValue; // a literal, an item, null, or undefined (never an array)
	},

	getValues: function(/* item */ item,
						/* attribute-name-string */ attribute){
		//	summary:
		// 		This getValues() method works just like the getValue() method, but getValues()
		//		always returns an array rather than a single attribute value.  The array
		//		may be empty, may contain a single attribute value, or may contain
		//		many attribute values.
		//		If the item does not have a value for the given attribute, then getValues()
		//		will return an empty array: [].  (So, if store.hasAttribute(item, attribute)
		//		has a return of false, then store.getValues(item, attribute) will return [].)
		//
		//	item:
		//		The item to access values on.
		//	attribute:
		//		The attribute to access represented as a string.
		//
		//	exceptions:
		//		Throws an exception if *item* is not an item, or *attribute* is not a string
		//	example:
		//	|	var friendsOfLuke = store.getValues(lukeSkywalker, "friends");
		var array = [];
		throw new Error('Unimplemented API: dojo.data.api.Read.getValues');
		return array; // an array that may contain literals and items
	},

	getAttributes: function(/* item */ item){
		//	summary:
		//		Returns an array with all the attributes that this item has.  This
		//		method will always return an array; if the item has no attributes
		//		at all, getAttributes() will return an empty array: [].
		//
		//	item:
		//		The item to access attributes on.
		//
		//	exceptions:
		//		Throws an exception if *item* is not an item, or *attribute* is not a string
		//	example:
		//	|	var array = store.getAttributes(kermit);
		var array = [];
		throw new Error('Unimplemented API: dojo.data.api.Read.getAttributes');
		return array; // array
	},

	hasAttribute: function(	/* item */ item,
							/* attribute-name-string */ attribute){
		//	summary:
		//		Returns true if the given *item* has a value for the given *attribute*.
		//
		//	item:
		//		The item to access attributes on.
		//	attribute:
		//		The attribute to access represented as a string.
		//
		//	exceptions:
		//		Throws an exception if *item* is not an item, or *attribute* is not a string
		//	example:
		//	|	var trueOrFalse = store.hasAttribute(kermit, "color");
		throw new Error('Unimplemented API: dojo.data.api.Read.hasAttribute');
		return false; // boolean
	},

	containsValue: function(/* item */ item,
							/* attribute-name-string */ attribute, 
							/* anything */ value){
		//	summary:
		//		Returns true if the given *value* is one of the values that getValues()
		//		would return.
		//
		//	item:
		//		The item to access values on.
		//	attribute:
		//		The attribute to access represented as a string.
		//	value:
		//		The value to match as a value for the attribute.
		//
		//	exceptions:
		//		Throws an exception if *item* is not an item, or *attribute* is not a string
		//	example:
		//	|	var trueOrFalse = store.containsValue(kermit, "color", "green");
		throw new Error('Unimplemented API: dojo.data.api.Read.containsValue');
		return false; // boolean
	},

	isItem: function(/* anything */ something){
		//	summary:
		//		Returns true if *something* is an item and came from the store instance.  
		//		Returns false if *something* is a literal, an item from another store instance, 
		//		or is any object other than an item.
		//
		//	something:
		//		Can be anything.
		//
		//	example:
		//	|	var yes = store.isItem(store.newItem());
		//	|	var no  = store.isItem("green");
		throw new Error('Unimplemented API: dojo.data.api.Read.isItem');
		return false; // boolean
	},

	isItemLoaded: function(/* anything */ something){
		//	summary:
		//		Returns false if isItem(something) is false.  Returns false if
		//		if isItem(something) is true but the the item is not yet loaded
		//		in local memory (for example, if the item has not yet been read
		//		from the server).
		//
		//	something:
		//		Can be anything.
		//
		//	example:
		//	|	var yes = store.isItemLoaded(store.newItem());
		//	|	var no  = store.isItemLoaded("green");
		throw new Error('Unimplemented API: dojo.data.api.Read.isItemLoaded');
		return false; // boolean
	},

	loadItem: function(/* object */ keywordArgs){
		//	summary:
		//		Given an item, this method loads the item so that a subsequent call
		//		to store.isItemLoaded(item) will return true.  If a call to
		//		isItemLoaded() returns true before loadItem() is even called,
		//		then loadItem() need not do any work at all and will not even invoke
		//		the callback handlers.  So, before invoking this method, check that
		//		the item has not already been loaded.  
		// 	keywordArgs:
		//		An anonymous object that defines the item to load and callbacks to invoke when the 
		//		load has completed.  The format of the object is as follows:
		//		{
		//			item: object,
		//			onItem: Function,
		//			onError: Function,
		//			scope: object
		//		}
		//	The *item* parameter.
		//		The item parameter is an object that represents the item in question that should be
		//		contained by the store.  This attribute is required.
		
		//	The *onItem* parameter.
		//		Function(item)
		//		The onItem parameter is the callback to invoke when the item has been loaded.  It takes only one
		//		parameter, the fully loaded item.
		//
		//	The *onError* parameter.
		//		Function(error)
		//		The onError parameter is the callback to invoke when the item load encountered an error.  It takes only one
		//		parameter, the error object
		//
		//	The *scope* parameter.
		//		If a scope object is provided, all of the callback functions (onItem, 
		//		onError, etc) will be invoked in the context of the scope object.
		//		In the body of the callback function, the value of the "this"
		//		keyword will be the scope object.   If no scope object is provided,
		//		the callback functions will be called in the context of dojo.global().
		//		For example, onItem.call(scope, item, request) vs. 
		//		onItem.call(dojo.global(), item, request)
		if(!this.isItemLoaded(keywordArgs.item)){
			throw new Error('Unimplemented API: dojo.data.api.Read.loadItem');
		}
	},

	fetch: function(/* Object */ keywordArgs){
		//	summary:
		//		Given a query and set of defined options, such as a start and count of items to return,
		//		this method executes the query and makes the results available as data items.
		//		The format and expectations of stores is that they operate in a generally asynchronous 
		//		manner, therefore callbacks are always used to return items located by the fetch parameters.
		//
		//	description:
		//		A Request object will always be returned and is returned immediately.
		//		The basic request is nothing more than the keyword args passed to fetch and 
		//		an additional function attached, abort().  The returned request object may then be used 
		//		to cancel a fetch.  All data items returns are passed through the callbacks defined in the 
		//		fetch parameters and are not present on the 'request' object.
		//
		//		This does not mean that custom stores can not add methods and properties to the request object
		//		returned, only that the API does not require it.  For more info about the Request API, 
		//		see dojo.data.api.Request
		//
		//	keywordArgs:
		//		The keywordArgs parameter may either be an instance of 
		//		conforming to dojo.data.api.Request or may be a simple anonymous object
		//		that may contain any of the following:
		//		{ 
		//			query: query-object or query-string,
		//			queryOptions: object,
		//			onBegin: Function,
		//			onItem: Function,
		//			onComplete: Function,
		//			onError: Function,
		//			scope: object,
		//			start: int
		//			count: int
		//			sort: array
		//		}
		//		All implementations should accept keywordArgs objects with any of
		//		the 9 standard properties: query, onBegin, onItem, onComplete, onError 
		//		scope, sort, start, and count.  Some implementations may accept additional 
		//		properties in the keywordArgs object as valid parameters, such as 
		//		{includeOutliers:true}.         
		//
		//	The *query* parameter.
		//		The query may be optional in some data store implementations.
		//		The dojo.data.api.Read API does not specify the syntax or semantics
		//		of the query itself -- each different data store implementation
		//		may have its own notion of what a query should look like.
		//		However, as of dojo 0.9, 1.0, and 1.1, all the provided datastores in dojo.data
		//		and dojox.data support an object structure query, where the object is a set of 
		//		name/value parameters such as { attrFoo: valueBar, attrFoo1: valueBar1}.  Most of the
		//		dijit widgets, such as ComboBox assume this to be the case when working with a datastore 
		//		when they dynamically update the query.  Therefore, for maximum compatibility with dijit 
		//		widgets the recommended query parameter is a key/value object.  That does not mean that the
		//		the datastore may not take alternative query forms, such as a simple string, a Date, a number, 
		//		or a mix of such.  Ultimately, The dojo.data.api.Read API is agnostic about what the query 
		//		format.  
		//		Further note:  In general for query objects that accept strings as attribute 
		//		value matches, the store should also support basic filtering capability, such as * 
		//		(match any character) and ? (match single character).  An example query that is a query object
		//		would be like: { attrFoo: "value*"}.  Which generally means match all items where they have 
		//		an attribute named attrFoo, with a value that starts with 'value'.
		//
		//	The *queryOptions* parameter
		//		The queryOptions parameter is an optional parameter used to specify optiosn that may modify
		//		the query in some fashion, such as doing a case insensitive search, or doing a deep search
		//		where all items in a hierarchical representation of data are scanned instead of just the root 
		//		items.  It currently defines two options that all datastores should attempt to honor if possible:
		//		{
		//			ignoreCase: boolean, //Whether or not the query should match case sensitively or not.  Default behaviour is false.
		//			deep: boolean 	//Whether or not a fetch should do a deep search of items and all child 
		//							//items instead of just root-level items in a datastore.  Default is false.
		//		}
		//
		//	The *onBegin* parameter.
		//		function(size, request);
		//		If an onBegin callback function is provided, the callback function
		//		will be called just once, before the first onItem callback is called.
		//		The onBegin callback function will be passed two arguments, the
		//		the total number of items identified and the Request object.  If the total number is
		//		unknown, then size will be -1.  Note that size is not necessarily the size of the 
		//		collection of items returned from the query, as the request may have specified to return only a 
		//		subset of the total set of items through the use of the start and count parameters.
		//
		//	The *onItem* parameter.
		//		function(item, request);
		//		If an onItem callback function is provided, the callback function
		//		will be called as each item in the result is received. The callback 
		//		function will be passed two arguments: the item itself, and the
		//		Request object.
		//
		//	The *onComplete* parameter.
		//		function(items, request);
		//
		//		If an onComplete callback function is provided, the callback function
		//		will be called just once, after the last onItem callback is called.
		//		Note that if the onItem callback is not present, then onComplete will be passed
		//		an array containing all items which matched the query and the request object.  
		//		If the onItem callback is present, then onComplete is called as: 
		//		onComplete(null, request).
		//
		//	The *onError* parameter.
		//		function(errorData, request); 
		//		If an onError callback function is provided, the callback function
		//		will be called if there is any sort of error while attempting to
		//		execute the query.
		//		The onError callback function will be passed two arguments:
		//		an Error object and the Request object.
		//
		//	The *scope* parameter.
		//		If a scope object is provided, all of the callback functions (onItem, 
		//		onComplete, onError, etc) will be invoked in the context of the scope
		//		object.  In the body of the callback function, the value of the "this"
		//		keyword will be the scope object.   If no scope object is provided,
		//		the callback functions will be called in the context of dojo.global().  
		//		For example, onItem.call(scope, item, request) vs. 
		//		onItem.call(dojo.global(), item, request)
		//
		//	The *start* parameter.
		//		If a start parameter is specified, this is a indication to the datastore to 
		//		only start returning items once the start number of items have been located and
		//		skipped.  When this parameter is paired withh 'count', the store should be able
		//		to page across queries with millions of hits by only returning subsets of the 
		//		hits for each query
		//
		//	The *count* parameter.
		//		If a count parameter is specified, this is a indication to the datastore to 
		//		only return up to that many items.  This allows a fetch call that may have 
		//		millions of item matches to be paired down to something reasonable.  
		//
		//	The *sort* parameter.
		//		If a sort parameter is specified, this is a indication to the datastore to 
		//		sort the items in some manner before returning the items.  The array is an array of 
		//		javascript objects that must conform to the following format to be applied to the
		//		fetching of items:
		//		{
		//			attribute: attribute || attribute-name-string,
		//			descending: true|false;   // Optional.  Default is false.
		//		}
		//		Note that when comparing attributes, if an item contains no value for the attribute
		//		(undefined), then it the default ascending sort logic should push it to the bottom 
		//		of the list.  In the descending order case, it such items should appear at the top of the list.
		// 
		//	returns:
		//		The fetch() method will return a javascript object conforming to the API
		//		defined in dojo.data.api.Request.  In general, it will be the keywordArgs
		//		object returned with the required functions in Request.js attached.
		//		Its general purpose is to provide a convenient way for a caller to abort an
		//		ongoing fetch.  
		// 
		//		The Request object may also have additional properties when it is returned
		//		such as request.store property, which is a pointer to the datastore object that 
		//		fetch() is a method of.
		//
		//	exceptions:
		//		Throws an exception if the query is not valid, or if the query
		//		is required but was not supplied.
		//
		//	example:
		//		Fetch all books identified by the query and call 'showBooks' when complete
		//		|	var request = store.fetch({query:"all books", onComplete: showBooks});
		//	example:
		//		Fetch all items in the story and call 'showEverything' when complete.
		//		|	var request = store.fetch(onComplete: showEverything);
		//	example:
		//		Fetch only 10 books that match the query 'all books', starting at the fifth book found during the search.
		//		This demonstrates how paging can be done for specific queries.  
		//		|	var request = store.fetch({query:"all books", start: 4, count: 10, onComplete: showBooks});
		//	example:
		//		Fetch all items that match the query, calling 'callback' each time an item is located.
		//		|	var request = store.fetch({query:"foo/bar", onItem:callback});
		//	example:
		//		Fetch the first 100 books by author King, call showKing when up to 100 items have been located.
		//		|	var request = store.fetch({query:{author:"King"}, start: 0, count:100, onComplete: showKing});
		//	example:
		//		Locate the books written by Author King, sort it on title and publisher, then return the first 100 items from the sorted items.
		//		|	var request = store.fetch({query:{author:"King"}, sort: [{ attribute: "title", descending: true}, {attribute: "publisher"}], ,start: 0, count:100, onComplete: 'showKing'});
		//	example:
		//		Fetch the first 100 books by authors starting with the name King, then call showKing when up to 100 items have been located.
		//		|	var request = store.fetch({query:{author:"King*"}, start: 0, count:100, onComplete: showKing});
		//	example:
		//		Fetch the first 100 books by authors ending with 'ing', but only have one character before it (King, Bing, Ling, Sing, etc.), then call showBooks when up to 100 items have been located.
		//		|	var request = store.fetch({query:{author:"?ing"}, start: 0, count:100, onComplete: showBooks});
		//	example:
		//		Fetch the first 100 books by author King, where the name may appear as King, king, KING, kInG, and so on, then call showKing when up to 100 items have been located.
		//		|	var request = store.fetch({query:{author:"King"}, queryOptions:(ignoreCase: true}, start: 0, count:100, onComplete: showKing});
		//	example:
		//		Paging
		//		|	var store = new dojo.data.LargeRdbmsStore({url:"jdbc:odbc:foobar"});
		//		|	var fetchArgs = {
		//		|		query: {type:"employees", name:"Hillary *"}, // string matching
		//		|		sort: [{attribute:"department", descending:true}],
		//		|		start: 0,
		//		|		count: 20,
		//		|		scope: displayer,
		//		|		onBegin: showThrobber,
		//		|		onItem: displayItem,
		//		|		onComplete: stopThrobber,
		//		|		onError: handleFetchError,
		//		|	};
		//		|	store.fetch(fetchArgs);
		//		|	...
		//		and then when the user presses the "Next Page" button...
		//		|	fetchArgs.start += 20;
		//		|	store.fetch(fetchArgs);  // get the next 20 items
		var request = null; 
		throw new Error('Unimplemented API: dojo.data.api.Read.fetch');
		return request; // an object conforming to the dojo.data.api.Request API
	},

	getFeatures: function(){
		//	summary:
		//		The getFeatures() method returns an simple keyword values object 
		//		that specifies what interface features the datastore implements.  
		//		A simple CsvStore may be read-only, and the only feature it 
		//		implements will be the 'dojo.data.api.Read' interface, so the
		//		getFeatures() method will return an object like this one:
		//		{'dojo.data.api.Read': true}.
		//		A more sophisticated datastore might implement a variety of
		//		interface features, like 'dojo.data.api.Read', 'dojo.data.api.Write', 
		//		'dojo.data.api.Identity', and 'dojo.data.api.Attribution'.
		return {
			'dojo.data.api.Read': true
		};
	},

	close: function(/*dojo.data.api.Request || keywordArgs || null */ request){
		//	summary:
		//		The close() method is intended for instructing the store to 'close' out 
		//		any information associated with a particular request.
		//
		//	description:
		//		The close() method is intended for instructing the store to 'close' out 
		//		any information associated with a particular request.  In general, this API
		//		expects to recieve as a parameter a request object returned from a fetch.  
		//		It will then close out anything associated with that request, such as 
		//		clearing any internal datastore caches and closing any 'open' connections.
		//		For some store implementations, this call may be a no-op.
		//
		//	request:
		//		An instance of a request for the store to use to identify what to close out.
		//		If no request is passed, then the store should clear all internal caches (if any)
		//		and close out all 'open' connections.  It does not render the store unusable from
		//		there on, it merely cleans out any current data and resets the store to initial 
		//		state.
		//
		//	example:
		//	|	var request = store.fetch({onComplete: doSomething});
		//	|	...
		//	|	store.close(request);
		throw new Error('Unimplemented API: dojo.data.api.Read.close');
	},

	getLabel: function(/* item */ item){
		//	summary:
		//		Method to inspect the item and return a user-readable 'label' for the item
		//		that provides a general/adequate description of what the item is. 
		//
		//	description:
		//		Method to inspect the item and return a user-readable 'label' for the item
		//		that provides a general/adequate description of what the item is.  In general
		//		most labels will be a specific attribute value or collection of the attribute
		//		values that combine to label the item in some manner.  For example for an item
		//		that represents a person it may return the label as:  "firstname lastlame" where
		//		the firstname and lastname are attributes on the item.  If the store is unable 
		//		to determine an adequate human readable label, it should return undefined.  Users that wish
		//		to customize how a store instance labels items should replace the getLabel() function on 
		//		their instance of the store, or extend the store and replace the function in 
		//		the extension class.
		//
		//	item:
		//		The item to return the label for.
		//
		//	returns: 
		//		A user-readable string representing the item or undefined if no user-readable label can 
		//		be generated.
		throw new Error('Unimplemented API: dojo.data.api.Read.getLabel');
		return undefined;
	},

	getLabelAttributes: function(/* item */ item){
		//	summary:
		//		Method to inspect the item and return an array of what attributes of the item were used 
		//		to generate its label, if any.
		//
		//	description:
		//		Method to inspect the item and return an array of what attributes of the item were used 
		//		to generate its label, if any.  This function is to assist UI developers in knowing what
		//		attributes can be ignored out of the attributes an item has when displaying it, in cases
		//		where the UI is using the label as an overall identifer should they wish to hide 
		//		redundant information.
		//
		//	item:
		//		The item to return the list of label attributes for.
		//
		//	returns: 
		//		An array of attribute names that were used to generate the label, or null if public attributes 
		//		were not used to generate the label.
		throw new Error('Unimplemented API: dojo.data.api.Read.getLabelAttributes');
		return null;
	}
});

}

if(!dojo._hasResource["dojox.uuid._base"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.uuid._base"] = true;
dojo.provide("dojox.uuid._base");

// Public constants:
dojox.uuid.NIL_UUID = "00000000-0000-0000-0000-000000000000";
dojox.uuid.version = {
	//	Enumeration for the different UUID versions.
	UNKNOWN: 0,
	TIME_BASED: 1,
	DCE_SECURITY: 2,
	NAME_BASED_MD5: 3,
	RANDOM: 4,
	NAME_BASED_SHA1: 5 };
dojox.uuid.variant = {
	//	Enumeration for the different UUID variants.
	NCS: "0",
	DCE: "10",
	MICROSOFT: "110",
	UNKNOWN: "111" };

dojox.uuid.assert = function(/*Boolean*/ booleanValue, /*String?*/ message){
	// summary: 
	//		Throws an exception if the assertion fails.
	// description: 
	//		If the asserted condition is true, this method does nothing. If the
	//		condition is false, we throw an error with a error message. 
	// booleanValue: Must be true for the assertion to succeed.
	// message: A string describing the assertion.
	// throws: Throws an Error if 'booleanValue' is false.
	if(!booleanValue){
		if(!message){
			message = "An assert statement failed.\n" +
			"The method dojox.uuid.assert() was called with a 'false' value.\n";
		}
		throw new Error(message);
	}
};

dojox.uuid.generateNilUuid = function(){
	// summary: 
	//		This function returns the Nil UUID: "00000000-0000-0000-0000-000000000000".
	// description: 
	//		The Nil UUID is described in section 4.1.7 of
	//		RFC 4122: http://tools.ietf.org/html/rfc4122#section-4.1.7
	// examples: 
	//		var string = dojox.uuid.generateNilUuid();
	return dojox.uuid.NIL_UUID; // String
};

dojox.uuid.isValid = function(/*String*/ uuidString){
	// summary: 
	//		Returns true if the UUID was initialized with a valid value.
	uuidString = uuidString.toString();
	var valid = (dojo.isString(uuidString) &&
		(uuidString.length == 36) &&
		(uuidString == uuidString.toLowerCase()));
	if(valid){
		var arrayOfParts = uuidString.split("-");
		valid = ((arrayOfParts.length == 5) &&
			(arrayOfParts[0].length == 8) &&
			(arrayOfParts[1].length == 4) &&
			(arrayOfParts[2].length == 4) &&
			(arrayOfParts[3].length == 4) &&
			(arrayOfParts[4].length == 12));
		var HEX_RADIX = 16;
		for (var i in arrayOfParts) {
			var part = arrayOfParts[i];
			var integer = parseInt(part, HEX_RADIX);
			valid = valid && isFinite(integer);
		}
	}
	return valid; // boolean
};

dojox.uuid.getVariant = function(/*String*/ uuidString){
	// summary: 
	//		Returns a variant code that indicates what type of UUID this is.
	//		Returns one of the enumerated dojox.uuid.variant values.
	// example: 
	//		var variant = dojox.uuid.getVariant("3b12f1df-5232-4804-897e-917bf397618a");
	//		dojox.uuid.assert(variant == dojox.uuid.variant.DCE);
	// example: 
	// "3b12f1df-5232-4804-897e-917bf397618a"
	//                     ^
	//                     |
	//         (variant "10__" == DCE)
	if(!dojox.uuid._ourVariantLookupTable){
		var variant = dojox.uuid.variant;
		var lookupTable = [];

		lookupTable[0x0] = variant.NCS;       // 0000
		lookupTable[0x1] = variant.NCS;       // 0001
		lookupTable[0x2] = variant.NCS;       // 0010
		lookupTable[0x3] = variant.NCS;       // 0011

		lookupTable[0x4] = variant.NCS;       // 0100
		lookupTable[0x5] = variant.NCS;       // 0101
		lookupTable[0x6] = variant.NCS;       // 0110
		lookupTable[0x7] = variant.NCS;       // 0111

		lookupTable[0x8] = variant.DCE;       // 1000
		lookupTable[0x9] = variant.DCE;       // 1001
		lookupTable[0xA] = variant.DCE;       // 1010
		lookupTable[0xB] = variant.DCE;       // 1011

		lookupTable[0xC] = variant.MICROSOFT; // 1100
		lookupTable[0xD] = variant.MICROSOFT; // 1101
		lookupTable[0xE] = variant.UNKNOWN;   // 1110
		lookupTable[0xF] = variant.UNKNOWN;   // 1111
		
		dojox.uuid._ourVariantLookupTable = lookupTable;
	}

	uuidString = uuidString.toString();
	var variantCharacter = uuidString.charAt(19);
	var HEX_RADIX = 16;
	var variantNumber = parseInt(variantCharacter, HEX_RADIX);
	dojox.uuid.assert((variantNumber >= 0) && (variantNumber <= 16));
	return dojox.uuid._ourVariantLookupTable[variantNumber]; // dojox.uuid.variant
};

dojox.uuid.getVersion = function(/*String*/ uuidString){
	// summary: 
	//		Returns a version number that indicates what type of UUID this is.
	//		Returns one of the enumerated dojox.uuid.version values.
	// example: 
	//		var version = dojox.uuid.getVersion("b4308fb0-86cd-11da-a72b-0800200c9a66");
	//		dojox.uuid.assert(version == dojox.uuid.version.TIME_BASED);
	// exceptions: 
	//		Throws an Error if this is not a DCE Variant UUID.
	var errorMessage = "dojox.uuid.getVersion() was not passed a DCE Variant UUID.";
	dojox.uuid.assert(dojox.uuid.getVariant(uuidString) == dojox.uuid.variant.DCE, errorMessage);
	uuidString = uuidString.toString();
	
		// "b4308fb0-86cd-11da-a72b-0800200c9a66"
		//                ^
		//                |
		//       (version 1 == TIME_BASED)
	var versionCharacter = uuidString.charAt(14);
	var HEX_RADIX = 16;
	var versionNumber = parseInt(versionCharacter, HEX_RADIX);
	return versionNumber; // dojox.uuid.version
};

dojox.uuid.getNode = function(/*String*/ uuidString){
	// summary: 
	//		If this is a version 1 UUID (a time-based UUID), getNode() returns a 
	//		12-character string with the "node" or "pseudonode" portion of the UUID, 
	//		which is the rightmost 12 characters. 
	// exceptions: 
	//		Throws an Error if this is not a version 1 UUID.
	var errorMessage = "dojox.uuid.getNode() was not passed a TIME_BASED UUID.";
	dojox.uuid.assert(dojox.uuid.getVersion(uuidString) == dojox.uuid.version.TIME_BASED, errorMessage);

	uuidString = uuidString.toString();
	var arrayOfStrings = uuidString.split('-');
	var nodeString = arrayOfStrings[4];
	return nodeString; // String (a 12-character string, which will look something like "917bf397618a")
};

dojox.uuid.getTimestamp = function(/*String*/ uuidString, /*String?*/ returnType){
	// summary: 
	//		If this is a version 1 UUID (a time-based UUID), this method returns
	//		the timestamp value encoded in the UUID.  The caller can ask for the
	//		timestamp to be returned either as a JavaScript Date object or as a 
	//		15-character string of hex digits.
	// returnType: Any of these five values: "string", String, "hex", "date", Date
	// returns: 
	//		Returns the timestamp value as a JavaScript Date object or a 15-character string of hex digits.
	// examples: 
	//		var uuidString = "b4308fb0-86cd-11da-a72b-0800200c9a66";
	//		var date, string, hexString;
	//		date   = dojox.uuid.getTimestamp(uuidString);         // returns a JavaScript Date
	//		date   = dojox.uuid.getTimestamp(uuidString, Date);     // 
	//		string = dojox.uuid.getTimestamp(uuidString, String);   // "Mon, 16 Jan 2006 20:21:41 GMT"
	//		hexString = dojox.uuid.getTimestamp(uuidString, "hex"); // "1da86cdb4308fb0"
	// exceptions: 
	//		Throws an Error if this is not a version 1 UUID.
	var errorMessage = "dojox.uuid.getTimestamp() was not passed a TIME_BASED UUID.";
	dojox.uuid.assert(dojox.uuid.getVersion(uuidString) == dojox.uuid.version.TIME_BASED, errorMessage);
	
	uuidString = uuidString.toString();
	if(!returnType){returnType = null};
	switch(returnType){
		case "string":
		case String:
			return dojox.uuid.getTimestamp(uuidString, Date).toUTCString(); // String (e.g. "Mon, 16 Jan 2006 20:21:41 GMT")
			break;
		case "hex":
			// Return a 15-character string of hex digits containing the 
			// timestamp for this UUID, with the high-order bits first.
			var arrayOfStrings = uuidString.split('-');
			var hexTimeLow = arrayOfStrings[0];
			var hexTimeMid = arrayOfStrings[1];
			var hexTimeHigh = arrayOfStrings[2];
		
			// Chop off the leading "1" character, which is the UUID 
			// version number for time-based UUIDs.
			hexTimeHigh = hexTimeHigh.slice(1);
		
			var timestampAsHexString = hexTimeHigh + hexTimeMid + hexTimeLow;
			dojox.uuid.assert(timestampAsHexString.length == 15);
			return timestampAsHexString; // String (e.g. "1da86cdb4308fb0")
			break;
		case null: // no returnType was specified, so default to Date
		case "date":
		case Date:
			// Return a JavaScript Date object. 
			var GREGORIAN_CHANGE_OFFSET_IN_HOURS = 3394248;
			var HEX_RADIX = 16;
		
			var arrayOfParts = uuidString.split('-');
			var timeLow = parseInt(arrayOfParts[0], HEX_RADIX);
			var timeMid = parseInt(arrayOfParts[1], HEX_RADIX);
			var timeHigh = parseInt(arrayOfParts[2], HEX_RADIX);
			var hundredNanosecondIntervalsSince1582 = timeHigh & 0x0FFF;
			hundredNanosecondIntervalsSince1582 <<= 16;
			hundredNanosecondIntervalsSince1582 += timeMid;
			// What we really want to do next is shift left 32 bits, but the 
			// result will be too big to fit in an int, so we'll multiply by 2^32,
			// and the result will be a floating point approximation.
			hundredNanosecondIntervalsSince1582 *= 0x100000000;
			hundredNanosecondIntervalsSince1582 += timeLow;
			var millisecondsSince1582 = hundredNanosecondIntervalsSince1582 / 10000;
		
			// Again, this will be a floating point approximation.
			// We can make things exact later if we need to.
			var secondsPerHour = 60 * 60;
			var hoursBetween1582and1970 = GREGORIAN_CHANGE_OFFSET_IN_HOURS;
			var secondsBetween1582and1970 = hoursBetween1582and1970 * secondsPerHour;
			var millisecondsBetween1582and1970 = secondsBetween1582and1970 * 1000;
			var millisecondsSince1970 = millisecondsSince1582 - millisecondsBetween1582and1970;
		
			var timestampAsDate = new Date(millisecondsSince1970);
			return timestampAsDate; // Date
			break;
		default:
			// we got passed something other than a valid returnType
			dojox.uuid.assert(false, "dojox.uuid.getTimestamp was not passed a valid returnType: " + returnType);
			break;
	}
};

}

if(!dojo._hasResource["dojox.uuid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.uuid"] = true;
dojo.provide("dojox.uuid");


}

if(!dojo._hasResource["dojox.uuid.Uuid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.uuid.Uuid"] = true;
dojo.provide("dojox.uuid.Uuid");


dojox.uuid.Uuid = function(/*String?*/ input){
	// summary: 
	//		This is the constructor for the Uuid class.  The Uuid class offers 
	//		methods for inspecting existing UUIDs.
	// input: A 36-character string that conforms to the UUID spec.
	// examples:
	//		var uuid;
	//		uuid = new dojox.uuid.Uuid("3b12f1df-5232-4804-897e-917bf397618a");
	//		uuid = new dojox.uuid.Uuid(); // "00000000-0000-0000-0000-000000000000"
	//		uuid = new dojox.uuid.Uuid(dojox.uuid.generateRandomUuid());
	//		uuid = new dojox.uuid.Uuid(dojox.uuid.generateTimeBasedUuid());
	//		dojox.uuid.Uuid.setGenerator(dojox.uuid.generateRandomUuid);
	//		uuid = new dojox.uuid.Uuid();
	//		dojox.uuid.assert(!uuid.isEqual(dojox.uuid.NIL_UUID));
	this._uuidString = dojox.uuid.NIL_UUID;
	if(input){
		dojox.uuid.assert(dojo.isString(input));
		this._uuidString = input.toLowerCase();
		dojox.uuid.assert(this.isValid());
	}else{
		var ourGenerator = dojox.uuid.Uuid.getGenerator();
		if(ourGenerator){
			this._uuidString = ourGenerator();
			dojox.uuid.assert(this.isValid());
		}
	}
};

dojox.uuid.Uuid.compare = function(/*dojox.uuid.Uuid*/ uuidOne, /*dojox.uuid.Uuid*/ uuidTwo){
	// summary: 
	//		Given two UUIDs to compare, this method returns 0, 1, or -1.
	// description:
	//		This method is designed to be used by sorting routines, like the
	//		JavaScript built-in Array sort() method. This implementation is 
	//		intended to match the sample implementation in IETF RFC 4122:
	//		http://www.ietf.org/rfc/rfc4122.txt
	// uuidOne: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	// uuidTwo: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.

	// examples:
	//		var uuid;
	//		var generator = dojox.uuid.TimeBasedGenerator;
	//		var a = new dojox.uuid.Uuid(generator);
	//		var b = new dojox.uuid.Uuid(generator);
	//		var c = new dojox.uuid.Uuid(generator);
	//		var array = new Array(a, b, c);
	//		array.sort(dojox.uuid.Uuid.compare);
	var uuidStringOne = uuidOne.toString();
	var uuidStringTwo = uuidTwo.toString();
	if (uuidStringOne > uuidStringTwo) return 1;   // integer
	if (uuidStringOne < uuidStringTwo) return -1;  // integer
	return 0; // integer (either 0, 1, or -1)
};

dojox.uuid.Uuid.setGenerator = function(/*Function?*/ generator){
	// summary: 
	//		Sets the default generator, which will be used by the 
	//		"new dojox.uuid.Uuid()" constructor if no parameters
	//		are passed in.
	// generator: A UUID generator function, such as dojox.uuid.generateTimeBasedUuid.
	dojox.uuid.assert(!generator || dojo.isFunction(generator));
	dojox.uuid.Uuid._ourGenerator = generator;
};

dojox.uuid.Uuid.getGenerator = function(){
	// summary: 
	//		Returns the default generator.  See setGenerator().
	return dojox.uuid.Uuid._ourGenerator; // generator (A UUID generator, such as dojox.uuid.TimeBasedGenerator).
};

dojox.uuid.Uuid.prototype.toString = function(){
	// summary: 
	//		This method returns a standard 36-character string representing 
	//		the UUID, such as "3b12f1df-5232-4804-897e-917bf397618a".
	return this._uuidString; // string
};

dojox.uuid.Uuid.prototype.compare = function(/*dojox.uuid.Uuid*/ otherUuid){
	// summary: 
	//		Compares this UUID to another UUID, and returns 0, 1, or -1.
	// description:
	//		This implementation is intended to match the sample implementation
	//		in IETF RFC 4122: http://www.ietf.org/rfc/rfc4122.txt
	// otherUuid: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	return dojox.uuid.Uuid.compare(this, otherUuid); // integer (either 0, 1, or -1)
};

dojox.uuid.Uuid.prototype.isEqual = function(/*dojox.uuid.Uuid*/ otherUuid){
	// summary: 
	//		Returns true if this UUID is equal to the otherUuid, or false otherwise.
	// otherUuid: Any object that has toString() method that returns a 36-character string that conforms to the UUID spec.
	return (this.compare(otherUuid) == 0); // boolean
};

dojox.uuid.Uuid.prototype.isValid = function(){
	// summary: 
	//		Returns true if the UUID was initialized with a valid value.
	return dojox.uuid.isValid(this);
};

dojox.uuid.Uuid.prototype.getVariant = function(){
	// summary: 
	//		Returns a variant code that indicates what type of UUID this is.
	//		Returns one of the enumerated dojox.uuid.variant values.

	// example: 
	//		var uuid = new dojox.uuid.Uuid("3b12f1df-5232-4804-897e-917bf397618a");
	//		var variant = uuid.getVariant();
	//		dojox.uuid.assert(variant == dojox.uuid.variant.DCE);
	// example: 
	// "3b12f1df-5232-4804-897e-917bf397618a"
	//                     ^
	//                     |
	//         (variant "10__" == DCE)
	return dojox.uuid.getVariant(this);
};

dojox.uuid.Uuid.prototype.getVersion = function(){
	// summary: 
	//		Returns a version number that indicates what type of UUID this is.
	//		Returns one of the enumerated dojox.uuid.version values.
	// example: 
	//		var uuid = new dojox.uuid.Uuid("b4308fb0-86cd-11da-a72b-0800200c9a66");
	//		var version = uuid.getVersion();
	//		dojox.uuid.assert(version == dojox.uuid.version.TIME_BASED);
	// exceptions: 
	//		Throws an Error if this is not a DCE Variant UUID.
	if(!this._versionNumber){
		this._versionNumber = dojox.uuid.getVersion(this);
	}
	return this._versionNumber; // dojox.uuid.version
};

dojox.uuid.Uuid.prototype.getNode = function(){
	// summary: 
	//		If this is a version 1 UUID (a time-based UUID), getNode() returns a 
	//		12-character string with the "node" or "pseudonode" portion of the UUID, 
	//		which is the rightmost 12 characters.  
	// exceptions: 
	//		Throws an Error if this is not a version 1 UUID.
	if (!this._nodeString) {
		this._nodeString = dojox.uuid.getNode(this);
	}
	return this._nodeString; // String (a 12-character string, which will look something like "917bf397618a")
};

dojox.uuid.Uuid.prototype.getTimestamp = function(/*String?*/ returnType){
	// summary: 
	//		If this is a version 1 UUID (a time-based UUID), this method returns
	//		the timestamp value encoded in the UUID.  The caller can ask for the
	//		timestamp to be returned either as a JavaScript Date object or as a 
	//		15-character string of hex digits.
	// returnType: Any of these five values: "string", String, "hex", "date", Date
	// returns: 
	//		Returns the timestamp value as a JavaScript Date object or a 15-character string of hex digits.
	// examples: 
	//		var uuid = new dojox.uuid.Uuid("b4308fb0-86cd-11da-a72b-0800200c9a66");
	//		var date, string, hexString;
	//		date   = uuid.getTimestamp();         // returns a JavaScript Date
	//		date   = uuid.getTimestamp(Date);     // 
	//		string = uuid.getTimestamp(String);   // "Mon, 16 Jan 2006 20:21:41 GMT"
	//		hexString = uuid.getTimestamp("hex"); // "1da86cdb4308fb0"
	// exceptions: 
	//		Throws an Error if this is not a version 1 UUID.
	if(!returnType){returnType = null};
	switch(returnType){
		case "string":
		case String:
			return this.getTimestamp(Date).toUTCString(); // String (e.g. "Mon, 16 Jan 2006 20:21:41 GMT")
			break;
		case "hex":
			// Return a 15-character string of hex digits containing the 
			// timestamp for this UUID, with the high-order bits first.
			if (!this._timestampAsHexString) {
				this._timestampAsHexString = dojox.uuid.getTimestamp(this, "hex");
			}
			return this._timestampAsHexString; // String (e.g. "1da86cdb4308fb0")
			break;
		case null: // no returnType was specified, so default to Date
		case "date":
		case Date:
			// Return a JavaScript Date object. 
			if (!this._timestampAsDate) {
				this._timestampAsDate = dojox.uuid.getTimestamp(this, Date);
			}
			return this._timestampAsDate; // Date
			break;
		default:
			// we got passed something other than a valid returnType
			dojox.uuid.assert(false, "The getTimestamp() method dojox.uuid.Uuid was passed a bogus returnType: " + returnType);
			break;
	}
};

}

if(!dojo._hasResource['com.sixnet.services.core.data.store']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.core.data.store'] = true;
dojo.provide('com.sixnet.services.core.data.store');




dojo.declare('com.sixnet.services.core.data.store', [dijit._Widget], {
	filteringSelectMode: false,
	itemsByIdentity: false,
	identifier: '',
	module: '',
	viewName:'',
	mode: 'LIKE',
	argsCount: 0,
	constructor : function(params) { 
		this.itemsByIdentity = {}; 
		dojo.mixin(this, params);
		if( !this.identifier) throw new Error("Required mixin 'identifier' missing in store");
	},
	fetch: function(keywordArgs){
		// allow us to save the callbacks without saving a reference to the object itself.
		// this is due to an apparent bug in grid that causes cross contamination of the keywordArgs object
		try{
			this.argsCount++;
			var newArgs = { start:0 };
			var index;
			for(index in keywordArgs){
				if(!keywordArgs[index]) continue;
				if(typeof(keywordArgs[index].declaredClass) != 'undefined') continue;
				newArgs[index] = dojo.clone(keywordArgs[index]);
			} 
			
		
			var tmpQuery = newArgs.query;
			if( this.filteringSelectMode && ! keywordArgs.extendedQuery){
				if( typeof(newArgs.start) == 'undefined') newArgs.start = 0;
				newArgs.query = {};
				for( var queryIdx in tmpQuery){
					if( tmpQuery[queryIdx].length == 0) continue;
					if( tmpQuery[queryIdx].match(/^\*$/) ){
						tmpQuery[queryIdx] = '';//tmpQuery[queryIdx].replace(/\*/g, "");
						//newArgs.query.push({ field: queryIdx, operator:'LIKE', value: '%'.concat(tmpQuery[queryIdx]).concat('%')});
					}else{
						tmpQuery[queryIdx] = tmpQuery[queryIdx].replace(/\*/g, "");
						newArgs.query = { left_field: queryIdx, operator:'LIKE', right_value: tmpQuery[queryIdx].concat('%')};
					
						//newArgs.query.push({ field: queryIdx, operator:'EQUAL', value: tmpQuery[queryIdx]});
					}
				}
			}
			if( keywordArgs.extendedQuery){
				newArgs.query = keywordArgs.extendedQuery;
			}
			var newSort = [];
			if( dojo.isArray(newArgs.sort)){
				dojo.forEach( newArgs.sort, function(sort){
					if( typeof(sort.attribute) == 'undefined') return;
					newSort.push(sort);
				});
			}else{
				if( newArgs.sort && (typeof(newArgs.sort.attribute) != 'undefined')){
					newSort.push(newArgs.sort);
				}
			}
			newArgs.sort = newSort;
			var bc = 'bcSilent';
			if( this.argsCount > 0){
				bc = 'bc';
			}
			return _sixnet_framework[bc](this.module, 'getViewData', {
			//return _sixnet_framework.bcSilent(this.module, 'getViewData', {
				viewName: this.viewName,
				mode: this.mode,
				startingOffset :newArgs.start,
				query :newArgs.query?newArgs.query:{},
				sort : newArgs.sort,
				descriptor: '',
				maxCount : isFinite(newArgs.count)?newArgs.count:-1
			}, dojo.hitch(this, "onEvent", keywordArgs), dojo.hitch(this, "onServerError"));
			//return keywordArgs;
		}catch(e){
			this.argsCount--;
			_sixnet_framework.log(0, 'error in execute query', e);
		}
	},
	onServerError: function(){
		this.argsCount--;
	},
	destroyRecursive : function() {
		this.inherited("destroyRecursive", arguments);
	},
	onEvent : function(keywordArgs, data) {
		try{
			
			this.argsCount--;
			var updatedItems = data.data ;
			// store items by identity
			dojo.forEach(updatedItems.items, dojo.hitch(this, function(item){
				if( this.filteringSelectMode){
					for( index in item){
						if( !item.hasOwnProperty(index)) continue;
						item[index] = [ item[index]];
					}
				}
				this.itemsByIdentity[this.getIdentity(item)] = item;
			}));
			
				if(keywordArgs.extendedError && ( updatedItems.items.length == 0)){
				keywordArgs.extendedError("No Items Found");
			}
			if( keywordArgs.onBegin)
				keywordArgs.onBegin(updatedItems.totalItemCount, keywordArgs);
			if( keywordArgs.onComplete)
				keywordArgs.onComplete(updatedItems.items, keywordArgs);
			
		}catch(e){
			_sixnet_framework.log(3, 'error in onEvent', e);
		}
	},
	isItemLoaded: function(item){
		return ( this.identifier && this.itemsByIdentity[this.getIdentity(item)]);
	},
	getValue : function( /* item */item,
	/* attribute-name-string */attribute,
	/* value? */defaultValue) {
		if (typeof (item[attribute]) == 'undefined')
			return undefined;
		if(this.filteringSelectMode) return item[attribute][0];
		return item[attribute];
	},
	getFeatures : function() {
		return {
			'dojo.data.api.Read' :true,
			'dojo.data.api.Identity' :true,
			'dojo.data.api.Notification': true
		};
	},
	isItem: function(proposedItem){
		if( typeof(proposedItem) == 'undefined') return false;
		var idList = this.identifier.split(',');
		var hasAttributes = true;
		dojo.forEach(idList, function(idName){
			if( typeof(proposedItem[idName]) == 'undefined') hasAttributes = false;
		});
		return hasAttributes;
	},
	fetchItemByIdentity: function(keywordArgs){
		//		item has been located and load has completed.  The format of the object is as follows:
		//		{
		//			identity: string|object,
		//			onItem: Function,
		//			onError: Function,
		//			scope: object
		//		}
		var error = false;
		var item = false;
		if( this.identifier){
			if( !keywordArgs.identity){
				error = new Error('No identity specified in keywordArgs for fetchItemByIdentity');
			}else{
				item = this.itemsByIdentity[keywordArgs.identity];
				if( typeof(item) == 'undefined'){
					_sixnet_framework.log(3, 'No Item with that identifier was found', keywordArgs, this.itemsByIdentity);
				}
			}
		}else{
			error = new Error('No identifer specified for this store.');
		}
		if(error && keywordArgs.onError){
			callback = (keywordArgs.scope)?dojo.hitch(keywordArgs.scope, keywordArgs.onError):keywordArgs.onError;
			callback(error);
		}
		if( keywordArgs.onItem){
			callback = (keywordArgs.scope)?dojo.hitch(keywordArgs.scope, keywordArgs.onItem):keywordArgs.onItem;
			callback(item);
		}
		return item;
	},
	getIdentity: function(/* item */ item){
		//	summary:
		//		Returns a unique identifier for an item.  The return value will be
		//		either a string or something that has a toString() method (such as,
		//		for example, a dojox.uuid.Uuid object).
		//	item:
		//		The item from the store from which to obtain its identifier.
		//	exceptions:
		//		Conforming implementations may throw an exception or return null if
		//		item is not an item.
		//	example:
		//	|	var itemId = store.getIdentity(kermit);
		//	|	assert(kermit === store.findByIdentity(store.getIdentity(kermit)));
		var idList = this.identifier.split(',');
		var identity = '';
		var item = item; // shift scope so we can see this item in the function below.
		dojo.forEach(idList, function(idName){
			identity = identity.concat(idName).concat(':').concat(item[idName]).concat(':');
		});
		return identity;
	},

	getIdentityAttributes: function(/* item */ item){
		//	summary:
		//		Returns an array of attribute names that are used to generate the identity. 
		//		For most stores, this is a single attribute, but for some complex stores
		//		such as RDB backed stores that use compound (multi-attribute) identifiers
		//		it can be more than one.  If the identity is not composed of attributes
		//		on the item, it will return null.  This function is intended to identify
		//		the attributes that comprise the identity so that so that during a render
		//		of all attributes, the UI can hide the the identity information if it 
		//		chooses.( var queryIdx in tmpQuery){
		//	item:
		//		The item from the store from which to obtain the array of public attributes that 
		//		compose the identifier, if any.
		//	example:
		//	|	var itemId = store.getIdentity(kermit);
		//	|	var identifiers = store.getIdentityAttributes(itemId);
		//	|	assert(typeof identifiers === "array" || identifiers === null);
		
		return this.identifier.split(','); // string
	}

	
	
});

}

if(!dojo._hasResource["dojo.data.api.Write"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.data.api.Write"] = true;
dojo.provide("dojo.data.api.Write");


dojo.declare("dojo.data.api.Write", dojo.data.api.Read, {
	//	summary:
	//		This is an abstract API that data provider implementations conform to.  
	//		This file defines function signatures and intentionally leaves all the
	//		functionss unimplemented.

	getFeatures: function(){
		//	summary: 
		//		See dojo.data.api.Read.getFeatures()
		return {
			'dojo.data.api.Read': true,
			'dojo.data.api.Write': true
		};
	},

	newItem: function(/* Object? */ keywordArgs, /*Object?*/ parentInfo){
		//	summary:
		//		Returns a newly created item.  Sets the attributes of the new
		//		item based on the *keywordArgs* provided.  In general, the attribute
		//		names in the keywords become the attributes in the new item and as for
		//		the attribute values in keywordArgs, they become the values of the attributes
		//		in the new item.  In addition, for stores that support hierarchical item 
		//		creation, an optional second parameter is accepted that defines what item is the parent
		//		of the new item and what attribute of that item should the new item be assigned to.
		//		In general, this will assume that the attribute targetted is multi-valued and a new item
		//		is appended onto the list of values for that attribute.  
		//
		//	keywordArgs:
		//		A javascript object defining the initial content of the item as a set of JavaScript 'property name: value' pairs.
		//	parentInfo:
		//		An optional javascript object defining what item is the parent of this item (in a hierarchical store.  Not all stores do hierarchical items), 
		//		and what attribute of that parent to assign the new item to.  If this is present, and the attribute specified
		//		is a multi-valued attribute, it will append this item into the array of values for that attribute.  The structure
		//		of the object is as follows:
		//		{
		//			parent: someItem,
		//			attribute: "attribute-name-string"
		//		}
		//
		//	exceptions:
		//		Throws an exception if *keywordArgs* is a string or a number or
		//		anything other than a simple anonymous object.  
		//		Throws an exception if the item in parentInfo is not an item from the store
		//		or if the attribute isn't an attribute name string.
		//	example:
		//	|	var kermit = store.newItem({name: "Kermit", color:[blue, green]});

		var newItem;
		throw new Error('Unimplemented API: dojo.data.api.Write.newItem');
		return newItem; // item
	},

	deleteItem: function(/* item */ item){
		//	summary:
		//		Deletes an item from the store.
		//
		//	item: 
		//		The item to delete.
		//
		//	exceptions:
		//		Throws an exception if the argument *item* is not an item 
		//		(if store.isItem(item) returns false).
		//	example:
		//	|	var success = store.deleteItem(kermit);
		throw new Error('Unimplemented API: dojo.data.api.Write.deleteItem');
		return false; // boolean
	},

	setValue: function(	/* item */ item, 
						/* string */ attribute,
						/* almost anything */ value){
		//	summary:
		//		Sets the value of an attribute on an item.
		//		Replaces any previous value or values.
		//
		//	item:
		//		The item to modify.
		//	attribute:
		//		The attribute of the item to change represented as a string name.
		//	value:
		//		The value to assign to the item.
		//
		//	exceptions:
		//		Throws an exception if *item* is not an item, or if *attribute*
		//		is neither an attribute object or a string.
		//		Throws an exception if *value* is undefined.
		//	example:
		//	|	var success = store.set(kermit, "color", "green");
		throw new Error('Unimplemented API: dojo.data.api.Write.setValue');
		return false; // boolean
	},

	setValues: function(/* item */ item,
						/* string */ attribute, 
						/* array */ values){
		//	summary:
		//		Adds each value in the *values* array as a value of the given
		//		attribute on the given item.
		//		Replaces any previous value or values.
		//		Calling store.setValues(x, y, []) (with *values* as an empty array) has
		//		the same effect as calling store.unsetAttribute(x, y).
		//
		//	item:
		//		The item to modify.
		//	attribute:
		//		The attribute of the item to change represented as a string name.
		//	values:
		//		An array of values to assign to the attribute..
		//
		//	exceptions:
		//		Throws an exception if *values* is not an array, if *item* is not an
		//		item, or if *attribute* is neither an attribute object or a string.
		//	example:
		//	|	var success = store.setValues(kermit, "color", ["green", "aqua"]);
		//	|	success = store.setValues(kermit, "color", []);
		//	|	if (success) {assert(!store.hasAttribute(kermit, "color"));}
		throw new Error('Unimplemented API: dojo.data.api.Write.setValues');
		return false; // boolean
	},

	unsetAttribute: function(	/* item */ item, 
								/* string */ attribute){
		//	summary:
		//		Deletes all the values of an attribute on an item.
		//
		//	item:
		//		The item to modify.
		//	attribute:
		//		The attribute of the item to unset represented as a string.
		//
		//	exceptions:
		//		Throws an exception if *item* is not an item, or if *attribute*
		//		is neither an attribute object or a string.
		//	example:
		//	|	var success = store.unsetAttribute(kermit, "color");
		//	|	if (success) {assert(!store.hasAttribute(kermit, "color"));}
		throw new Error('Unimplemented API: dojo.data.api.Write.clear');
		return false; // boolean
	},

	save: function(/* object */ keywordArgs){
		//	summary:
		//		Saves to the server all the changes that have been made locally.
		//		The save operation may take some time and is generally performed
		//		in an asynchronous fashion.  The outcome of the save action is 
		//		is passed into the set of supported callbacks for the save.
		//   
		//	keywordArgs:
		//		{
		//			onComplete: function
		//			onError: function
		//			scope: object
		//		}
		//
		//	The *onComplete* parameter.
		//		function();
		//
		//		If an onComplete callback function is provided, the callback function
		//		will be called just once, after the save has completed.  No parameters
		//		are generally passed to the onComplete.
		//
		//	The *onError* parameter.
		//		function(errorData); 
		//
		//		If an onError callback function is provided, the callback function
		//		will be called if there is any sort of error while attempting to
		//		execute the save.  The onError function will be based one parameter, the
		//		error.
		//
		//	The *scope* parameter.
		//		If a scope object is provided, all of the callback function (
		//		onComplete, onError, etc) will be invoked in the context of the scope
		//		object.  In the body of the callback function, the value of the "this"
		//		keyword will be the scope object.   If no scope object is provided,
		//		the callback functions will be called in the context of dojo.global.  
		//		For example, onComplete.call(scope) vs. 
		//		onComplete.call(dojo.global)
		//
		//	returns:
		//		Nothing.  Since the saves are generally asynchronous, there is 
		//		no need to return anything.  All results are passed via callbacks.
		//	example:
		//	|	store.save({onComplete: onSave});
		//	|	store.save({scope: fooObj, onComplete: onSave, onError: saveFailed});
		throw new Error('Unimplemented API: dojo.data.api.Write.save');
	},

	revert: function(){
		//	summary:
		//		Discards any unsaved changes.
		//	description:
		//		Discards any unsaved changes.
		//
		//	example:
		//	|	var success = store.revert();
		throw new Error('Unimplemented API: dojo.data.api.Write.revert');
		return false; // boolean
	},

	isDirty: function(/* item? */ item){
		//	summary:
		//		Given an item, isDirty() returns true if the item has been modified 
		//		since the last save().  If isDirty() is called with no *item* argument,  
		//		then this function returns true if any item has been modified since
		//		the last save().
		//
		//	item:
		//		The item to check.
		//
		//	exceptions:
		//		Throws an exception if isDirty() is passed an argument and the
		//		argument is not an item.
		//	example:
		//	|	var trueOrFalse = store.isDirty(kermit); // true if kermit is dirty
		//	|	var trueOrFalse = store.isDirty();       // true if any item is dirty
		throw new Error('Unimplemented API: dojo.data.api.Write.isDirty');
		return false; // boolean
	}
});

}

if(!dojo._hasResource['com.sixnet.services.core.data.writeStore']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.core.data.writeStore'] = true;
dojo.provide('com.sixnet.services.core.data.writeStore');





dojo.declare('com.sixnet.services.core.data.writeStore', [com.sixnet.services.core.data.store], {
	_isDirty: false,
	_newiesById: false,
	_dirtiesById: false,
	_deletedById: false,
	constructor: function(params){
		this._dirtiesById = {};
		this._deletedById = {};
		this._newiesById = {};
	},
	getFeatures: function(){
		var features = this.inherited(arguments);
		return dojo.mixin( features, {
			'dojo.data.api.Read': true
			//,
			//'dojo.data.api.Write': true
		});
	},
	onEvent : function(keywordArgs, data) {
		this.argsCount --;
		var updatedItems = data.data ;
		var returnData = [];
		// store items by identity
		
		for( id in this._newiesById){
			this.itemsByIdentity[id] = this._newiesById[id];
			returnData.push(this.itemsByIdentity[id]);
		}
		
		if(typeof(updatedItems) == 'undefined'){
			_sixnet_framework.log(1, "Unable to access view.", data.error);
			if( keywordArgs.onBegin)
				keywordArgs.onBegin(0, keywordArgs);
			if( keywordArgs.onComplete)
				keywordArgs.onComplete([], keywordArgs);
			return;			
		}
		if( this.filteringSelectMode){
			dojo.forEach(updatedItems.items, dojo.hitch(this, function(item){
				var id = this.getIdentity(item);
				if(this._dirtiesById[id]) this.itemsByIdentity[id] = this._dirtiesById[id];
				else this.itemsByIdentity[id] = item;
				var item = this.itemsByIdentity[id];
				for( index in item){
					if( !item.hasOwnProperty(index)) continue;
					item[index] = [ item[index]];
				}
				returnData.push(item);
			}));
		}else{
			dojo.forEach(updatedItems.items, dojo.hitch(this, function(item){
				var id = this.getIdentity(item);
				if(this._dirtiesById[id]) this.itemsByIdentity[id] = this._dirtiesById[id];
				else this.itemsByIdentity[id] = item;
				returnData.push(this.itemsByIdentity[id]);
			}));
		}
	
		if( typeof(keywordArgs.sort) !='undefined' && keywordArgs.sort && keywordArgs.sort.length > 0){
			returnData.sort(function(item1,item2){
				var result = 0;
				if( item1[keywordArgs.sort[0]['attribute']] > item2[keywordArgs.sort[0]['attribute']]) result = 1;
				if( item1[keywordArgs.sort[0]['attribute']] < item2[keywordArgs.sort[0]['attribute']]) result = -1;
				return (keywordArgs.sort[0]['descending']?-1:1) * result;
			});
		}
		try{
			if(keywordArgs.extendedError && ( updatedItems.items.length == 0)){
				keywordArgs.extendedError("No Items Found");
			}
			if( keywordArgs.onBegin)
				keywordArgs.onBegin(updatedItems.totalItemCount, keywordArgs);
			if( keywordArgs.onComplete)
				keywordArgs.onComplete(returnData, keywordArgs);
			
		}catch(e){
			_sixnet_framework.log(3, 'errir in onEvent', e);
		}
		
	},
	newItem: function(/* Object? */ keywordArgs, /*Object?*/ parentInfo){
		if( typeof(keywordArgs) == 'undefined') throw new Error('New item called without keywordArgs object');
		if( !this.isItem(keywordArgs)) throw new Error('Error creating item, no identifier found in keywordArgs object');
		
		var newItem = dojo.clone(keywordArgs);
		this._newiesById[this.getIdentity(newItem)] = newItem;
		this.onNew(newItem, parentInfo);
		this.onDirty();
		return newItem; // item
	},

	deleteItem: function(/* item */ item){
		if( !this.isItem(item)) throw new Error('Attempt to delete an item that does not belong to this store');
		this._deletedById[this.getIdentity(item)] = item; 
		this.onDelete(item);
		return false; // boolean
	},

	setValue: function(	/* item */ item, 
						/* string */ attribute,
						/* almost anything */ value){
		if( !this.isItem(item)) throw new Error('Attempt to set an attribute on an item that this store does not own');
		var oldValue = item[attribute];
		item[attribute] = value ;
		if( value != oldValue){
			this._dirtiesById[this.getIdentity(item)] = item;
			this.onDirty();
		}
		this.onSet(item, attribute, oldValue, value);
		return true; // boolean
	},

	setValues: function(/* item */ item,
						/* string */ attribute, 
						/* array */ values){
		//	summary:
		//		Adds each value in the *values* array as a value of the given
		//		attribute on the given item.
		//		Replaces any previous value or values.
		//		Calling store.setValues(x, y, []) (with *values* as an empty array) has
		//		the same effect as calling store.unsetAttribute(x, y).
		//
		//	item:
		//		The item to modify.
		//	attribute:
		//		The attribute of the item to change represented as a string name.
		//	values:
		//		An array of values to assign to the attribute..
		//
		//	exceptions:
		//		Throws an exception if *values* is not an array, if *item* is not an
		//		item, or if *attribute* is neither an attribute object or a string.
		//	example:
		//	|	var success = store.setValues(kermit, "color", ["green", "aqua"]);
		//	|	success = store.setValues(kermit, "color", []);
		//	|	if (success) {assert(!store.hasAttribute(kermit, "color"));}
		throw new Error('Unimplemented API: dojo.data.api.Write.setValues');
		return false; // boolean
	},

	unsetAttribute: function(	/* item */ item, 
								/* string */ attribute){
		//	summary:
		//		Deletes all the values of an attribute on an item.
		//
		//	item:
		//		The item to modify.
		//	attribute:
		//		The attribute of the item to unset represented as a string.
		//
		//	exceptions:
		//		Throws an exception if *item* is not an item, or if *attribute*
		//		is neither an attribute object or a string.
		//	example:
		//	|	var success = store.unsetAttribute(kermit, "color");
		//	|	if (success) {assert(!store.hasAttribute(kermit, "color"));}
		throw new Error('Unimplemented API: dojo.data.api.Write.clear');
		return false; // boolean
	},

	save: function(/* object */ keywordArgs){
		//	summary:
		//		Saves to the server all the changes that have been made locally.
		//		The save operation may take some time and is generally performed
		//		in an asynchronous fashion.  The outcome of the save action is 
		//		is passed into the set of supported callbacks for the save.
		//   
		//	keywordArgs:
		//		{
		//			onComplete: function
		//			onError: function
		//			scope: object
		//		}
		//
		//	The *onComplete* parameter.
		//		function();
		//
		//		If an onComplete callback function is provided, the callback function
		//		will be called just once, after the save has completed.  No parameters
		//		are generally passed to the onComplete.
		//
		//	The *onError* parameter.
		//		function(errorData); 
		//
		//		If an onError callback function is provided, the callback function
		//		will be called if there is any sort of error while attempting to
		//		execute the save.  The onError function will be based one parameter, the
		//		error.
		//
		//	The *scope* parameter.
		//		If a scope object is provided, all of the callback function (
		//		onComplete, onError, etc) will be invoked in the context of the scope
		//		object.  In the body of the callback function, the value of the "this"
		//		keyword will be the scope object.   If no scope object is provided,
		//		the callback functions will be called in the context of dojo.global.  
		//		For example, onComplete.call(scope) vs. 
		//		onComplete.call(dojo.global)
		//
		//	returns:
		//		Nothing.  Since the saves are generally asynchronous, there is 
		//		no need to return anything.  All results are passed via callbacks.
		//	example:
		//	|	store.save({onComplete: onSave});
		//	|	store.save({scope: fooObj, onComplete: onSave, onError: saveFailed});
		var items = [];
		for(var dirtyIndex in this._dirtiesById){
			items.push( this._dirtiesById[dirtyIndex]);
		}
		_sixnet_framework.log(3, 'saving...not', this);
		return _sixnet_framework.bc(this.module, 'updateViewData', {
				viewName: this.viewName,
				items: items
			}, dojo.hitch(this, "onSaveEvent", keywordArgs));
	},
	onSaveEvent: function(keywordArgs, response){
		this.revert();
		this.onSave();
		_sixnet_framework.log(3, 'onSaveEvent', arguments);
	},
	revert: function(){
		//	summary:
		//		Discards any unsaved changes.
		//	description:
		//		Discards any unsaved changes.
		//
		//	example:
		//	|	var success = store.revert();
		this._newiesById = {};
		this._dirtiesById = {};
		return true; // boolean
	},

	isDirty: function(/* item? */ item){
		if( typeof(item) == 'undefined') return this._dirty ;
		if( typeof(this._newiesById[this.getIdentity(item)]) != 'undefined') return true;
		if( typeof(this._dirtiesById[this.getIdentity(item)]) != 'undefined') return true;
		return false; // boolean
	},
	onNew: function(){},
	onSet:function(item, attribute, oldValue, newValue){},
	onDelete: function(){},
	onDirty: function(){},
	onSave: function(){}
});

}

if(!dojo._hasResource['com.sixnet.services.widgets.sixnetGMap']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.sixnetGMap'] = true;
dojo.provide('com.sixnet.services.widgets.sixnetGMap');
//










/* new grid layout..... c;on e b4 set structure
 * sav all fields to view
 * sixnetGMap: Look up key and Plot devices on a google map.
 * 
 * 
 * params:
 * {
	store: assumed in template where this is in template
	grid: Obj
	viewName: Used for custom view look-up, String
	formatter: Obj
	module: Related Module, String
	*pDescriptor: [cells] Section of pDescriptor, JSON formatted Obj. Acts as default layout
	userId: Current user, String
	toolbarDD: Select view, upon show save, <select>
	originalLoad: Used to check for 
	currentView: Holds currnet view info, String
	toolbarAttachPoint: domNode to attach to, Obj
	showSaveView: Indicates to show buttons Save/Manage views, Boolean
	*query: Store query, JSON formatted Obj
 * 	}
 */
dojo.declare('com.sixnet.services.widgets.sixnetGMap', [com.sixnet.services.core.dashWidgetEmbedded, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"mapHolder\" style=\"width:100%; height:100%\"></div>\n</div>\n",
	longitude: -122.1419,
	latitude: 37.4419,
	map: false,
	googleKey: false,
	script: false,
	id: false,
	isReady: false,
	
	constructor: function(){
		_sixnet_framework.log(1, "constructor sixnetGMap args: ", arguments);
		this.googleKey = _sixnet_framework._googleKey;
	},
	postCreate: function(){
		this.inherited("postCreate", arguments);
//		   _sixnet_framework.log(1, "before click event", event);
//		this.googleMe();
	},
	
	postMixInProperties: function() {
		/*
		 * 
		 *  TODO:
		 *  There is a disconnect here. The script tag uses _this.id_ SO 
		 *  we work the first time around...
		 *  When attempting a second map-load... no go.
		 */
		_sixnet_framework.log(1, "postMixInProperties");
		this.id = dijit.getUniqueId('map');
		_sixnet_framework.log(1, "if route");
		// create the callback handler script to redirect the callback to this widget
		script = document.createElement("script");
		script.type = "text/javascript";
		script.text = "function googleCallback(data){ dijit.byId('"+this.id+"').googleCallback(data)}";
		dojo.doc.getElementsByTagName("head")[0].appendChild(script);
		// create the script to load the google maps api
		script = document.createElement("script");
		script.type = "text/javascript";
		// ensure script tag has a unique id
		script.id= "api"+this.id;
		script.src = "http://maps.google.com/maps?file=api&v=2.x&sensor=false&key="+this.googleKey+"&async=2&callback=googleCallback";
		dojo.doc.getElementsByTagName("head")[0].appendChild(script);
	},
	
	googleCallback: function(){
		_sixnet_framework.log(1, "key in googleCallback:  ", dojo.clone(this.googleKey), this.mapHolder);
		this.map = new GMap2(this.mapHolder.domNode);
		this.map.setMapType(G_HYBRID_MAP);
		this.map.addControl(new GLargeMapControl3D());
	    this.map.addControl(new GMapTypeControl());
		this.map.setCenter(new GLatLng(this.latitude, this.longitude), 3);
		this.isReady = true;
	},
	
	setMarkers: function(data){
		// {"gps":[{"gps_lat":"26.105397783"},{"gps_long":"-80.257980967"},{"gps_alt":"-32"},{"gps_time":"205956"},{"gps_sat":"5"},{"gps_type":"1"},{"gps_feet":"6"},{"gps_cp_lat":""},{"gps_cp_long":""},{"gps_cp_rad":"0"}]}
		for(var i = 0; i < data.length; i++){
			var position = dojo.fromJson(data[i].gps_position);
//			_sixnet_framework.log(1, "<<position json", position.gps);
			var gps_lat = 0;
			var gps_long = 0;
			for(var j = 0; j < position.gps.length; j++){
				if(position.gps[j].gps_lat){
					gps_lat = position.gps[j].gps_lat;
				}
				if(position.gps[j].gps_long){
					gps_long = position.gps[j].gps_long;
				}
			}
		    var latlng = new GLatLng(gps_lat, gps_long);
		    this.map.addOverlay(new GMarker(latlng));
		}
	}
});

}

if(!dojo._hasResource["com.sixnet.services.widgets.dndParens"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.dndParens"] = true;



//dojo.require("dojo.dnd");
dojo.provide("com.sixnet.services.widgets.dndParens");

dojo.declare('com.sixnet.services.widgets.dndParens',[com.sixnet.services.widgets.dndSource], {
	dropMarkup: function(){
		var dropParen = new com.sixnet.services.widgets.dropParens({});
		return dropParen.domNode;
	}
//	onChildDrop: function(){
//		_sixnet_framework.log(1, arguments, " << dndParen-> onChildDrop");
//	}
});

}

if(!dojo._hasResource['com.sixnet.services.widgets.HintButton']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.HintButton'] = true;
dojo.provide('com.sixnet.services.widgets.HintButton');


dojo.declare('com.sixnet.services.widgets.HintButton', [dijit.form.Button],{
	hint:'',
	_limitUserMode:false,
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.connect(this, "onMouseOver", dojo.hitch( this, function(hint, event){
			dojo.publish('/status/hint', [hint]);
		}, this.hint));
		this.connect(this, "onMouseLeave", dojo.hitch( this, function(){
			dojo.publish('/status/hint', ['']);
		}));
	}
});

}

if(!dojo._hasResource["dojo.cldr.supplemental"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.cldr.supplemental"] = true;
dojo.provide("dojo.cldr.supplemental");



dojo.cldr.supplemental.getFirstDayOfWeek = function(/*String?*/locale){
// summary: Returns a zero-based index for first day of the week
// description:
//		Returns a zero-based index for first day of the week, as used by the local (Gregorian) calendar.
//		e.g. Sunday (returns 0), or Monday (returns 1)

	// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/firstDay
	var firstDay = {/*default is 1=Monday*/
		mv:5,
		af:6,bh:6,dj:6,dz:6,eg:6,er:6,et:6,iq:6,ir:6,jo:6,ke:6,kw:6,
		ly:6,ma:6,om:6,qa:6,sa:6,sd:6,so:6,tn:6,ye:6,
		ar:0,as:0,az:0,bw:0,ca:0,cn:0,fo:0,ge:0,gl:0,gu:0,hk:0,ie:0,
		il:0,'in':0,is:0,jm:0,jp:0,kg:0,kr:0,la:0,mh:0,mn:0,mo:0,mp:0,
		mt:0,nz:0,ph:0,pk:0,sg:0,sy:0,th:0,tt:0,tw:0,um:0,us:0,uz:0,
		vi:0,zw:0
// variant. do not use?		gb:0,
	};

	var country = dojo.cldr.supplemental._region(locale);
	var dow = firstDay[country];
	return (dow === undefined) ? 1 : dow; /*Number*/
};

dojo.cldr.supplemental._region = function(/*String?*/locale){
	locale = dojo.i18n.normalizeLocale(locale);
	var tags = locale.split('-');
	var region = tags[1];
	if(!region){
		// IE often gives language only (#2269)
		// Arbitrary mappings of language-only locales to a country:
		region = {de:"de", en:"us", es:"es", fi:"fi", fr:"fr", he:"il", hu:"hu", it:"it",
			ja:"jp", ko:"kr", nl:"nl", pt:"br", sv:"se", zh:"cn"}[tags[0]];
	}else if(region.length == 4){
		// The ISO 3166 country code is usually in the second position, unless a
		// 4-letter script is given. See http://www.ietf.org/rfc/rfc4646.txt
		region = tags[2];
	}
	return region;
}

dojo.cldr.supplemental.getWeekend = function(/*String?*/locale){
// summary: Returns a hash containing the start and end days of the weekend
// description:
//		Returns a hash containing the start and end days of the weekend according to local custom using locale,
//		or by default in the user's locale.
//		e.g. {start:6, end:0}

	// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/weekData/weekend{Start,End}
	var weekendStart = {/*default is 6=Saturday*/
		'in':0,
		af:4,dz:4,ir:4,om:4,sa:4,ye:4,
		ae:5,bh:5,eg:5,il:5,iq:5,jo:5,kw:5,ly:5,ma:5,qa:5,sd:5,sy:5,tn:5
	};

	var weekendEnd = {/*default is 0=Sunday*/
		af:5,dz:5,ir:5,om:5,sa:5,ye:5,
		ae:6,bh:5,eg:6,il:6,iq:6,jo:6,kw:6,ly:6,ma:6,qa:6,sd:6,sy:6,tn:6
	};

	var country = dojo.cldr.supplemental._region(locale);
	var start = weekendStart[country];
	var end = weekendEnd[country];
	if(start === undefined){start=6;}
	if(end === undefined){end=0;}
	return {start:start, end:end}; /*Object {start,end}*/
};

}

if(!dojo._hasResource["dojo.date"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.date"] = true;
dojo.provide("dojo.date");

/*=====
dojo.date = {
	// summary: Date manipulation utilities
}
=====*/

dojo.date.getDaysInMonth = function(/*Date*/dateObject){
	//	summary:
	//		Returns the number of days in the month used by dateObject
	var month = dateObject.getMonth();
	var days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
	if(month == 1 && dojo.date.isLeapYear(dateObject)){ return 29; } // Number
	return days[month]; // Number
}

dojo.date.isLeapYear = function(/*Date*/dateObject){
	//	summary:
	//		Determines if the year of the dateObject is a leap year
	//	description:
	//		Leap years are years with an additional day YYYY-02-29, where the
	//		year number is a multiple of four with the following exception: If
	//		a year is a multiple of 100, then it is only a leap year if it is
	//		also a multiple of 400. For example, 1900 was not a leap year, but
	//		2000 is one.

	var year = dateObject.getFullYear();
	return !(year%400) || (!(year%4) && !!(year%100)); // Boolean
}

// FIXME: This is not localized
dojo.date.getTimezoneName = function(/*Date*/dateObject){
	//	summary:
	//		Get the user's time zone as provided by the browser
	// dateObject:
	//		Needed because the timezone may vary with time (daylight savings)
	//	description:
	//		Try to get time zone info from toString or toLocaleString method of
	//		the Date object -- UTC offset is not a time zone.  See
	//		http://www.twinsun.com/tz/tz-link.htm Note: results may be
	//		inconsistent across browsers.

	var str = dateObject.toString(); // Start looking in toString
	var tz = ''; // The result -- return empty string if nothing found
	var match;

	// First look for something in parentheses -- fast lookup, no regex
	var pos = str.indexOf('(');
	if(pos > -1){
		tz = str.substring(++pos, str.indexOf(')'));
	}else{
		// If at first you don't succeed ...
		// If IE knows about the TZ, it appears before the year
		// Capital letters or slash before a 4-digit year 
		// at the end of string
		var pat = /([A-Z\/]+) \d{4}$/;
		if((match = str.match(pat))){
			tz = match[1];
		}else{
		// Some browsers (e.g. Safari) glue the TZ on the end
		// of toLocaleString instead of putting it in toString
			str = dateObject.toLocaleString();
			// Capital letters or slash -- end of string, 
			// after space
			pat = / ([A-Z\/]+)$/;
			if((match = str.match(pat))){
				tz = match[1];
			}
		}
	}

	// Make sure it doesn't somehow end up return AM or PM
	return (tz == 'AM' || tz == 'PM') ? '' : tz; // String
}

// Utility methods to do arithmetic calculations with Dates

dojo.date.compare = function(/*Date*/date1, /*Date?*/date2, /*String?*/portion){
	//	summary:
	//		Compare two date objects by date, time, or both.
	//	description:
	//  	Returns 0 if equal, positive if a > b, else negative.
	//	date1:
	//		Date object
	//	date2:
	//		Date object.  If not specified, the current Date is used.
	//	portion:
	//		A string indicating the "date" or "time" portion of a Date object.
	//		Compares both "date" and "time" by default.  One of the following:
	//		"date", "time", "datetime"

	// Extra step required in copy for IE - see #3112
	date1 = new Date(+date1);
	date2 = new Date(+(date2 || new Date()));

	if(portion == "date"){
		// Ignore times and compare dates.
		date1.setHours(0, 0, 0, 0);
		date2.setHours(0, 0, 0, 0);
	}else if(portion == "time"){
		// Ignore dates and compare times.
		date1.setFullYear(0, 0, 0);
		date2.setFullYear(0, 0, 0);
	}
	
	if(date1 > date2){ return 1; } // int
	if(date1 < date2){ return -1; } // int
	return 0; // int
};

dojo.date.add = function(/*Date*/date, /*String*/interval, /*int*/amount){
	//	summary:
	//		Add to a Date in intervals of different size, from milliseconds to years
	//	date: Date
	//		Date object to start with
	//	interval:
	//		A string representing the interval.  One of the following:
	//			"year", "month", "day", "hour", "minute", "second",
	//			"millisecond", "quarter", "week", "weekday"
	//	amount:
	//		How much to add to the date.

	var sum = new Date(+date); // convert to Number before copying to accomodate IE (#3112)
	var fixOvershoot = false;
	var property = "Date";

	switch(interval){
		case "day":
			break;
		case "weekday":
			//i18n FIXME: assumes Saturday/Sunday weekend, but this is not always true.  see dojo.cldr.supplemental

			// Divide the increment time span into weekspans plus leftover days
			// e.g., 8 days is one 5-day weekspan / and two leftover days
			// Can't have zero leftover days, so numbers divisible by 5 get
			// a days value of 5, and the remaining days make up the number of weeks
			var days, weeks;
			var mod = amount % 5;
			if(!mod){
				days = (amount > 0) ? 5 : -5;
				weeks = (amount > 0) ? ((amount-5)/5) : ((amount+5)/5);
			}else{
				days = mod;
				weeks = parseInt(amount/5);
			}
			// Get weekday value for orig date param
			var strt = date.getDay();
			// Orig date is Sat / positive incrementer
			// Jump over Sun
			var adj = 0;
			if(strt == 6 && amount > 0){
				adj = 1;
			}else if(strt == 0 && amount < 0){
			// Orig date is Sun / negative incrementer
			// Jump back over Sat
				adj = -1;
			}
			// Get weekday val for the new date
			var trgt = strt + days;
			// New date is on Sat or Sun
			if(trgt == 0 || trgt == 6){
				adj = (amount > 0) ? 2 : -2;
			}
			// Increment by number of weeks plus leftover days plus
			// weekend adjustments
			amount = (7 * weeks) + days + adj;
			break;
		case "year":
			property = "FullYear";
			// Keep increment/decrement from 2/29 out of March
			fixOvershoot = true;
			break;
		case "week":
			amount *= 7;
			break;
		case "quarter":
			// Naive quarter is just three months
			amount *= 3;
			// fallthrough...
		case "month":
			// Reset to last day of month if you overshoot
			fixOvershoot = true;
			property = "Month";
			break;
//		case "hour":
//		case "minute":
//		case "second":
//		case "millisecond":
		default:
			property = "UTC"+interval.charAt(0).toUpperCase() + interval.substring(1) + "s";
	}

	if(property){
		sum["set"+property](sum["get"+property]()+amount);
	}

	if(fixOvershoot && (sum.getDate() < date.getDate())){
		sum.setDate(0);
	}

	return sum; // Date
};

dojo.date.difference = function(/*Date*/date1, /*Date?*/date2, /*String?*/interval){
	//	summary:
	//		Get the difference in a specific unit of time (e.g., number of
	//		months, weeks, days, etc.) between two dates, rounded to the
	//		nearest integer.
	//	date1:
	//		Date object
	//	date2:
	//		Date object.  If not specified, the current Date is used.
	//	interval:
	//		A string representing the interval.  One of the following:
	//			"year", "month", "day", "hour", "minute", "second",
	//			"millisecond", "quarter", "week", "weekday"
	//		Defaults to "day".

	date2 = date2 || new Date();
	interval = interval || "day";
	var yearDiff = date2.getFullYear() - date1.getFullYear();
	var delta = 1; // Integer return value

	switch(interval){
		case "quarter":
			var m1 = date1.getMonth();
			var m2 = date2.getMonth();
			// Figure out which quarter the months are in
			var q1 = Math.floor(m1/3) + 1;
			var q2 = Math.floor(m2/3) + 1;
			// Add quarters for any year difference between the dates
			q2 += (yearDiff * 4);
			delta = q2 - q1;
			break;
		case "weekday":
			var days = Math.round(dojo.date.difference(date1, date2, "day"));
			var weeks = parseInt(dojo.date.difference(date1, date2, "week"));
			var mod = days % 7;

			// Even number of weeks
			if(mod == 0){
				days = weeks*5;
			}else{
				// Weeks plus spare change (< 7 days)
				var adj = 0;
				var aDay = date1.getDay();
				var bDay = date2.getDay();

				weeks = parseInt(days/7);
				mod = days % 7;
				// Mark the date advanced by the number of
				// round weeks (may be zero)
				var dtMark = new Date(date1);
				dtMark.setDate(dtMark.getDate()+(weeks*7));
				var dayMark = dtMark.getDay();

				// Spare change days -- 6 or less
				if(days > 0){
					switch(true){
						// Range starts on Sat
						case aDay == 6:
							adj = -1;
							break;
						// Range starts on Sun
						case aDay == 0:
							adj = 0;
							break;
						// Range ends on Sat
						case bDay == 6:
							adj = -1;
							break;
						// Range ends on Sun
						case bDay == 0:
							adj = -2;
							break;
						// Range contains weekend
						case (dayMark + mod) > 5:
							adj = -2;
					}
				}else if(days < 0){
					switch(true){
						// Range starts on Sat
						case aDay == 6:
							adj = 0;
							break;
						// Range starts on Sun
						case aDay == 0:
							adj = 1;
							break;
						// Range ends on Sat
						case bDay == 6:
							adj = 2;
							break;
						// Range ends on Sun
						case bDay == 0:
							adj = 1;
							break;
						// Range contains weekend
						case (dayMark + mod) < 0:
							adj = 2;
					}
				}
				days += adj;
				days -= (weeks*2);
			}
			delta = days;
			break;
		case "year":
			delta = yearDiff;
			break;
		case "month":
			delta = (date2.getMonth() - date1.getMonth()) + (yearDiff * 12);
			break;
		case "week":
			// Truncate instead of rounding
			// Don't use Math.floor -- value may be negative
			delta = parseInt(dojo.date.difference(date1, date2, "day")/7);
			break;
		case "day":
			delta /= 24;
			// fallthrough
		case "hour":
			delta /= 60;
			// fallthrough
		case "minute":
			delta /= 60;
			// fallthrough
		case "second":
			delta /= 1000;
			// fallthrough
		case "millisecond":
			delta *= date2.getTime() - date1.getTime();
	}

	// Round for fractional values and DST leaps
	return Math.round(delta); // Number (integer)
};

}

if(!dojo._hasResource["dojo.date.locale"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.date.locale"] = true;
dojo.provide("dojo.date.locale");

// Localization methods for Date.   Honor local customs using locale-dependent dojo.cldr data.







// Load the bundles containing localization information for
// names and formats


//NOTE: Everything in this module assumes Gregorian calendars.
// Other calendars will be implemented in separate modules.

(function(){
	// Format a pattern without literals
	function formatPattern(dateObject, bundle, options, pattern){
		return pattern.replace(/([a-z])\1*/ig, function(match){
			var s, pad,
				c = match.charAt(0),
				l = match.length,
				widthList = ["abbr", "wide", "narrow"];
			switch(c){
				case 'G':
					s = bundle[(l < 4) ? "eraAbbr" : "eraNames"][dateObject.getFullYear() < 0 ? 0 : 1];
					break;
				case 'y':
					s = dateObject.getFullYear();
					switch(l){
						case 1:
							break;
						case 2:
							if(!options.fullYear){
								s = String(s); s = s.substr(s.length - 2);
								break;
							}
							// fallthrough
						default:
							pad = true;
					}
					break;
				case 'Q':
				case 'q':
					s = Math.ceil((dateObject.getMonth()+1)/3);
//					switch(l){
//						case 1: case 2:
							pad = true;
//							break;
//						case 3: case 4: // unimplemented
//					}
					break;
				case 'M':
					var m = dateObject.getMonth();
					if(l<3){
						s = m+1; pad = true;
					}else{
						var propM = ["months", "format", widthList[l-3]].join("-");
						s = bundle[propM][m];
					}
					break;
				case 'w':
					var firstDay = 0;
					s = dojo.date.locale._getWeekOfYear(dateObject, firstDay); pad = true;
					break;
				case 'd':
					s = dateObject.getDate(); pad = true;
					break;
				case 'D':
					s = dojo.date.locale._getDayOfYear(dateObject); pad = true;
					break;
				case 'E':
					var d = dateObject.getDay();
					if(l<3){
						s = d+1; pad = true;
					}else{
						var propD = ["days", "format", widthList[l-3]].join("-");
						s = bundle[propD][d];
					}
					break;
				case 'a':
					var timePeriod = (dateObject.getHours() < 12) ? 'am' : 'pm';
					s = bundle['dayPeriods-format-wide-' + timePeriod];
					break;
				case 'h':
				case 'H':
				case 'K':
				case 'k':
					var h = dateObject.getHours();
					// strange choices in the date format make it impossible to write this succinctly
					switch (c){
						case 'h': // 1-12
							s = (h % 12) || 12;
							break;
						case 'H': // 0-23
							s = h;
							break;
						case 'K': // 0-11
							s = (h % 12);
							break;
						case 'k': // 1-24
							s = h || 24;
							break;
					}
					pad = true;
					break;
				case 'm':
					s = dateObject.getMinutes(); pad = true;
					break;
				case 's':
					s = dateObject.getSeconds(); pad = true;
					break;
				case 'S':
					s = Math.round(dateObject.getMilliseconds() * Math.pow(10, l-3)); pad = true;
					break;
				case 'v': // FIXME: don't know what this is. seems to be same as z?
				case 'z':
					// We only have one timezone to offer; the one from the browser
					s = dojo.date.locale._getZone(dateObject, true, options);
					if(s){break;}
					l=4;
					// fallthrough... use GMT if tz not available
				case 'Z':
					var offset = dojo.date.locale._getZone(dateObject, false, options);
					var tz = [
						(offset<=0 ? "+" : "-"),
						dojo.string.pad(Math.floor(Math.abs(offset)/60), 2),
						dojo.string.pad(Math.abs(offset)% 60, 2)
					];
					if(l==4){
						tz.splice(0, 0, "GMT");
						tz.splice(3, 0, ":");
					}
					s = tz.join("");
					break;
//				case 'Y': case 'u': case 'W': case 'F': case 'g': case 'A': case 'e':
//					console.log(match+" modifier unimplemented");
				default:
					throw new Error("dojo.date.locale.format: invalid pattern char: "+pattern);
			}
			if(pad){ s = dojo.string.pad(s, l); }
			return s;
		});
	}

/*=====
	dojo.date.locale.__FormatOptions = function(){
	//	selector: String
	//		choice of 'time','date' (default: date and time)
	//	formatLength: String
	//		choice of long, short, medium or full (plus any custom additions).  Defaults to 'short'
	//	datePattern:String
	//		override pattern with this string
	//	timePattern:String
	//		override pattern with this string
	//	am: String
	//		override strings for am in times
	//	pm: String
	//		override strings for pm in times
	//	locale: String
	//		override the locale used to determine formatting rules
	//	fullYear: Boolean
	//		(format only) use 4 digit years whenever 2 digit years are called for
	//	strict: Boolean
	//		(parse only) strict parsing, off by default
		this.selector = selector;
		this.formatLength = formatLength;
		this.datePattern = datePattern;
		this.timePattern = timePattern;
		this.am = am;
		this.pm = pm;
		this.locale = locale;
		this.fullYear = fullYear;
		this.strict = strict;
	}
=====*/

dojo.date.locale._getZone = function(/*Date*/dateObject, /*boolean*/getName, /*dojo.date.locale.__FormatOptions?*/options){
	// summary:
	//		Returns the zone (or offset) for the given date and options.  This
	//		is broken out into a separate function so that it can be overridden
	//		by timezone-aware code.
	//
	// dateObject:
	//		the date and/or time being formatted.
	//
	// getName:
	//		Whether to return the timezone string (if true), or the offset (if false)
	//
	// options:
	//		The options being used for formatting
	if(getName){
		return dojo.date.getTimezoneName(dateObject);
	}else{
		return dateObject.getTimezoneOffset();
	}
};


dojo.date.locale.format = function(/*Date*/dateObject, /*dojo.date.locale.__FormatOptions?*/options){
	// summary:
	//		Format a Date object as a String, using locale-specific settings.
	//
	// description:
	//		Create a string from a Date object using a known localized pattern.
	//		By default, this method formats both date and time from dateObject.
	//		Formatting patterns are chosen appropriate to the locale.  Different
	//		formatting lengths may be chosen, with "full" used by default.
	//		Custom patterns may be used or registered with translations using
	//		the dojo.date.locale.addCustomFormats method.
	//		Formatting patterns are implemented using [the syntax described at
	//		unicode.org](http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns)
	//
	// dateObject:
	//		the date and/or time to be formatted.  If a time only is formatted,
	//		the values in the year, month, and day fields are irrelevant.  The
	//		opposite is true when formatting only dates.

	options = options || {};

	var locale = dojo.i18n.normalizeLocale(options.locale),
		formatLength = options.formatLength || 'short',
		bundle = dojo.date.locale._getGregorianBundle(locale),
		str = [],
		sauce = dojo.hitch(this, formatPattern, dateObject, bundle, options);
	if(options.selector == "year"){
		return _processPattern(bundle["dateFormatItem-yyyy"] || "yyyy", sauce);
	}
	var pattern;
	if(options.selector != "date"){
		pattern = options.timePattern || bundle["timeFormat-"+formatLength];
		if(pattern){str.push(_processPattern(pattern, sauce));}
	}
	if(options.selector != "time"){
		pattern = options.datePattern || bundle["dateFormat-"+formatLength];
		if(pattern){str.push(_processPattern(pattern, sauce));}
	}

	return str.length == 1 ? str[0] : bundle["dateTimeFormat-"+formatLength].replace(/\{(\d+)\}/g,
		function(match, key){ return str[key]; }); // String
};

dojo.date.locale.regexp = function(/*dojo.date.locale.__FormatOptions?*/options){
	// summary:
	//		Builds the regular needed to parse a localized date

	return dojo.date.locale._parseInfo(options).regexp; // String
};

dojo.date.locale._parseInfo = function(/*dojo.date.locale.__FormatOptions?*/options){
	options = options || {};
	var locale = dojo.i18n.normalizeLocale(options.locale),
		bundle = dojo.date.locale._getGregorianBundle(locale),
		formatLength = options.formatLength || 'short',
		datePattern = options.datePattern || bundle["dateFormat-" + formatLength],
		timePattern = options.timePattern || bundle["timeFormat-" + formatLength],
		pattern;
	if(options.selector == 'date'){
		pattern = datePattern;
	}else if(options.selector == 'time'){
		pattern = timePattern;
	}else{
		pattern = bundle["dateTimeFormat-"+formatLength].replace(/\{(\d+)\}/g,
			function(match, key){ return [timePattern, datePattern][key]; });
	}

	var tokens = [],
		re = _processPattern(pattern, dojo.hitch(this, _buildDateTimeRE, tokens, bundle, options));
	return {regexp: re, tokens: tokens, bundle: bundle};
};

dojo.date.locale.parse = function(/*String*/value, /*dojo.date.locale.__FormatOptions?*/options){
	// summary:
	//		Convert a properly formatted string to a primitive Date object,
	//		using locale-specific settings.
	//
	// description:
	//		Create a Date object from a string using a known localized pattern.
	//		By default, this method parses looking for both date and time in the string.
	//		Formatting patterns are chosen appropriate to the locale.  Different
	//		formatting lengths may be chosen, with "full" used by default.
	//		Custom patterns may be used or registered with translations using
	//		the dojo.date.locale.addCustomFormats method.
	//	
	//		Formatting patterns are implemented using [the syntax described at
	//		unicode.org](http://www.unicode.org/reports/tr35/tr35-4.html#Date_Format_Patterns)
	//		When two digit years are used, a century is chosen according to a sliding 
	//		window of 80 years before and 20 years after present year, for both `yy` and `yyyy` patterns.
	//		year < 100CE requires strict mode.
	//
	// value:
	//		A string representation of a date

	var info = dojo.date.locale._parseInfo(options),
		tokens = info.tokens, bundle = info.bundle,
		re = new RegExp("^" + info.regexp + "$", info.strict ? "" : "i"),
		match = re.exec(value);

	if(!match){ return null; } // null

	var widthList = ['abbr', 'wide', 'narrow'],
		result = [1970,0,1,0,0,0,0], // will get converted to a Date at the end
		amPm = "",
		valid = dojo.every(match, function(v, i){
		if(!i){return true;}
		var token=tokens[i-1];
		var l=token.length;
		switch(token.charAt(0)){
			case 'y':
				if(l != 2 && options.strict){
					//interpret year literally, so '5' would be 5 A.D.
					result[0] = v;
				}else{
					if(v<100){
						v = Number(v);
						//choose century to apply, according to a sliding window
						//of 80 years before and 20 years after present year
						var year = '' + new Date().getFullYear(),
							century = year.substring(0, 2) * 100,
							cutoff = Math.min(Number(year.substring(2, 4)) + 20, 99),
							num = (v < cutoff) ? century + v : century - 100 + v;
						result[0] = num;
					}else{
						//we expected 2 digits and got more...
						if(options.strict){
							return false;
						}
						//interpret literally, so '150' would be 150 A.D.
						//also tolerate '1950', if 'yyyy' input passed to 'yy' format
						result[0] = v;
					}
				}
				break;
			case 'M':
				if(l>2){
					var months = bundle['months-format-' + widthList[l-3]].concat();
					if(!options.strict){
						//Tolerate abbreviating period in month part
						//Case-insensitive comparison
						v = v.replace(".","").toLowerCase();
						months = dojo.map(months, function(s){ return s.replace(".","").toLowerCase(); } );
					}
					v = dojo.indexOf(months, v);
					if(v == -1){
//						console.log("dojo.date.locale.parse: Could not parse month name: '" + v + "'.");
						return false;
					}
				}else{
					v--;
				}
				result[1] = v;
				break;
			case 'E':
			case 'e':
				var days = bundle['days-format-' + widthList[l-3]].concat();
				if(!options.strict){
					//Case-insensitive comparison
					v = v.toLowerCase();
					days = dojo.map(days, function(d){return d.toLowerCase();});
				}
				v = dojo.indexOf(days, v);
				if(v == -1){
//					console.log("dojo.date.locale.parse: Could not parse weekday name: '" + v + "'.");
					return false;
				}

				//TODO: not sure what to actually do with this input,
				//in terms of setting something on the Date obj...?
				//without more context, can't affect the actual date
				//TODO: just validate?
				break;
			case 'D':
				result[1] = 0;
				// fallthrough...
			case 'd':
				result[2] = v;
				break;
			case 'a': //am/pm
				var am = options.am || bundle['dayPeriods-format-wide-am'],
					pm = options.pm || bundle['dayPeriods-format-wide-pm'];
				if(!options.strict){
					var period = /\./g;
					v = v.replace(period,'').toLowerCase();
					am = am.replace(period,'').toLowerCase();
					pm = pm.replace(period,'').toLowerCase();
				}
				if(options.strict && v != am && v != pm){
//					console.log("dojo.date.locale.parse: Could not parse am/pm part.");
					return false;
				}

				// we might not have seen the hours field yet, so store the state and apply hour change later
				amPm = (v == pm) ? 'p' : (v == am) ? 'a' : '';
				break;
			case 'K': //hour (1-24)
				if(v == 24){ v = 0; }
				// fallthrough...
			case 'h': //hour (1-12)
			case 'H': //hour (0-23)
			case 'k': //hour (0-11)
				//TODO: strict bounds checking, padding
				if(v > 23){
//					console.log("dojo.date.locale.parse: Illegal hours value");
					return false;
				}

				//in the 12-hour case, adjusting for am/pm requires the 'a' part
				//which could come before or after the hour, so we will adjust later
				result[3] = v;
				break;
			case 'm': //minutes
				result[4] = v;
				break;
			case 's': //seconds
				result[5] = v;
				break;
			case 'S': //milliseconds
				result[6] = v;
//				break;
//			case 'w':
//TODO				var firstDay = 0;
//			default:
//TODO: throw?
//				console.log("dojo.date.locale.parse: unsupported pattern char=" + token.charAt(0));
		}
		return true;
	});

	var hours = +result[3];
	if(amPm === 'p' && hours < 12){
		result[3] = hours + 12; //e.g., 3pm -> 15
	}else if(amPm === 'a' && hours == 12){
		result[3] = 0; //12am -> 0
	}

	//TODO: implement a getWeekday() method in order to test 
	//validity of input strings containing 'EEE' or 'EEEE'...

	var dateObject = new Date(result[0], result[1], result[2], result[3], result[4], result[5], result[6]); // Date
	if(options.strict){
		dateObject.setFullYear(result[0]);
	}

	// Check for overflow.  The Date() constructor normalizes things like April 32nd...
	//TODO: why isn't this done for times as well?
	var allTokens = tokens.join(""),
		dateToken = allTokens.indexOf('d') != -1,
		monthToken = allTokens.indexOf('M') != -1;

	if(!valid ||
		(monthToken && dateObject.getMonth() > result[1]) ||
		(dateToken && dateObject.getDate() > result[2])){
		return null;
	}

	// Check for underflow, due to DST shifts.  See #9366
	// This assumes a 1 hour dst shift correction at midnight
	// We could compare the timezone offset after the shift and add the difference instead.
	if((monthToken && dateObject.getMonth() < result[1]) ||
		(dateToken && dateObject.getDate() < result[2])){
		dateObject = dojo.date.add(dateObject, "hour", 1);
	}

	return dateObject; // Date
};

function _processPattern(pattern, applyPattern, applyLiteral, applyAll){
	//summary: Process a pattern with literals in it

	// Break up on single quotes, treat every other one as a literal, except '' which becomes '
	var identity = function(x){return x;};
	applyPattern = applyPattern || identity;
	applyLiteral = applyLiteral || identity;
	applyAll = applyAll || identity;

	//split on single quotes (which escape literals in date format strings) 
	//but preserve escaped single quotes (e.g., o''clock)
	var chunks = pattern.match(/(''|[^'])+/g),
		literal = pattern.charAt(0) == "'";

	dojo.forEach(chunks, function(chunk, i){
		if(!chunk){
			chunks[i]='';
		}else{
			chunks[i]=(literal ? applyLiteral : applyPattern)(chunk.replace(/''/g, "'"));
			literal = !literal;
		}
	});
	return applyAll(chunks.join(''));
}

function _buildDateTimeRE(tokens, bundle, options, pattern){
	pattern = dojo.regexp.escapeString(pattern);
	if(!options.strict){ pattern = pattern.replace(" a", " ?a"); } // kludge to tolerate no space before am/pm
	return pattern.replace(/([a-z])\1*/ig, function(match){
		// Build a simple regexp.  Avoid captures, which would ruin the tokens list
		var s,
			c = match.charAt(0),
			l = match.length,
			p2 = '', p3 = '';
		if(options.strict){
			if(l > 1){ p2 = '0' + '{'+(l-1)+'}'; }
			if(l > 2){ p3 = '0' + '{'+(l-2)+'}'; }
		}else{
			p2 = '0?'; p3 = '0{0,2}';
		}
		switch(c){
			case 'y':
				s = '\\d{2,4}';
				break;
			case 'M':
				s = (l>2) ? '\\S+?' : p2+'[1-9]|1[0-2]';
				break;
			case 'D':
				s = p2+'[1-9]|'+p3+'[1-9][0-9]|[12][0-9][0-9]|3[0-5][0-9]|36[0-6]';
				break;
			case 'd':
				s = '3[01]|[12]\\d|'+p2+'[1-9]';
				break;
			case 'w':
				s = p2+'[1-9]|[1-4][0-9]|5[0-3]';
				break;
			case 'E':
				s = '\\S+';
				break;
			case 'h': //hour (1-12)
				s = p2+'[1-9]|1[0-2]';
				break;
			case 'k': //hour (0-11)
				s = p2+'\\d|1[01]';
				break;
			case 'H': //hour (0-23)
				s = p2+'\\d|1\\d|2[0-3]';
				break;
			case 'K': //hour (1-24)
				s = p2+'[1-9]|1\\d|2[0-4]';
				break;
			case 'm':
			case 's':
				s = '[0-5]\\d';
				break;
			case 'S':
				s = '\\d{'+l+'}';
				break;
			case 'a':
				var am = options.am || bundle['dayPeriods-format-wide-am'],
					pm = options.pm || bundle['dayPeriods-format-wide-pm'];
				if(options.strict){
					s = am + '|' + pm;
				}else{
					s = am + '|' + pm;
					if(am != am.toLowerCase()){ s += '|' + am.toLowerCase(); }
					if(pm != pm.toLowerCase()){ s += '|' + pm.toLowerCase(); }
					if(s.indexOf('.') != -1){ s += '|' + s.replace(/\./g, ""); }
				}
				s = s.replace(/\./g, "\\.");
				break;
			default:
			// case 'v':
			// case 'z':
			// case 'Z':
				s = ".*";
//				console.log("parse of date format, pattern=" + pattern);
		}

		if(tokens){ tokens.push(match); }

		return "(" + s + ")"; // add capture
	}).replace(/[\xa0 ]/g, "[\\s\\xa0]"); // normalize whitespace.  Need explicit handling of \xa0 for IE.
}
})();

(function(){
var _customFormats = [];
dojo.date.locale.addCustomFormats = function(/*String*/packageName, /*String*/bundleName){
	// summary:
	//		Add a reference to a bundle containing localized custom formats to be
	//		used by date/time formatting and parsing routines.
	//
	// description:
	//		The user may add custom localized formats where the bundle has properties following the
	//		same naming convention used by dojo.cldr: `dateFormat-xxxx` / `timeFormat-xxxx`
	//		The pattern string should match the format used by the CLDR.
	//		See dojo.date.locale.format() for details.
	//		The resources must be loaded by dojo.requireLocalization() prior to use

	_customFormats.push({pkg:packageName,name:bundleName});
};

dojo.date.locale._getGregorianBundle = function(/*String*/locale){
	var gregorian = {};
	dojo.forEach(_customFormats, function(desc){
		var bundle = dojo.i18n.getLocalization(desc.pkg, desc.name, locale);
		gregorian = dojo.mixin(gregorian, bundle);
	}, this);
	return gregorian; /*Object*/
};
})();

dojo.date.locale.addCustomFormats("dojo.cldr","gregorian");

dojo.date.locale.getNames = function(/*String*/item, /*String*/type, /*String?*/context, /*String?*/locale){
	// summary:
	//		Used to get localized strings from dojo.cldr for day or month names.
	//
	// item:
	//	'months' || 'days'
	// type:
	//	'wide' || 'narrow' || 'abbr' (e.g. "Monday", "Mon", or "M" respectively, in English)
	// context:
	//	'standAlone' || 'format' (default)
	// locale:
	//	override locale used to find the names

	var label,
		lookup = dojo.date.locale._getGregorianBundle(locale),
		props = [item, context, type];
	if(context == 'standAlone'){
		var key = props.join('-');
		label = lookup[key];
		// Fall back to 'format' flavor of name
		if(label[0] == 1){ label = undefined; } // kludge, in the absence of real aliasing support in dojo.cldr
	}
	props[1] = 'format';

	// return by copy so changes won't be made accidentally to the in-memory model
	return (label || lookup[props.join('-')]).concat(); /*Array*/
};

dojo.date.locale.isWeekend = function(/*Date?*/dateObject, /*String?*/locale){
	// summary:
	//	Determines if the date falls on a weekend, according to local custom.

	var weekend = dojo.cldr.supplemental.getWeekend(locale),
		day = (dateObject || new Date()).getDay();
	if(weekend.end < weekend.start){
		weekend.end += 7;
		if(day < weekend.start){ day += 7; }
	}
	return day >= weekend.start && day <= weekend.end; // Boolean
};

// These are used only by format and strftime.  Do they need to be public?  Which module should they go in?

dojo.date.locale._getDayOfYear = function(/*Date*/dateObject){
	// summary: gets the day of the year as represented by dateObject
	return dojo.date.difference(new Date(dateObject.getFullYear(), 0, 1, dateObject.getHours()), dateObject) + 1; // Number
};

dojo.date.locale._getWeekOfYear = function(/*Date*/dateObject, /*Number*/firstDayOfWeek){
	if(arguments.length == 1){ firstDayOfWeek = 0; } // Sunday

	var firstDayOfYear = new Date(dateObject.getFullYear(), 0, 1).getDay(),
		adj = (firstDayOfYear - firstDayOfWeek + 7) % 7,
		week = Math.floor((dojo.date.locale._getDayOfYear(dateObject) + adj - 1) / 7);

	// if year starts on the specified day, start counting weeks at 1
	if(firstDayOfYear == firstDayOfWeek){ week++; }

	return week; // Number
};

}

if(!dojo._hasResource["dijit.Calendar"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Calendar"] = true;
dojo.provide("dijit.Calendar");









dojo.declare(
	"dijit.Calendar",
	[dijit._Widget, dijit._Templated, dijit._CssStateMixin],
	{
		// summary:
		//		A simple GUI for choosing a date in the context of a monthly calendar.
		//
		// description:
		//		A simple GUI for choosing a date in the context of a monthly calendar.
		//		This widget can't be used in a form because it doesn't serialize the date to an
		//		`<input>` field.  For a form element, use dijit.form.DateTextBox instead.
		//
		//		Note that the parser takes all dates attributes passed in the
		//		[RFC 3339 format](http://www.faqs.org/rfcs/rfc3339.html), e.g. `2005-06-30T08:05:00-07:00`
		//		so that they are serializable and locale-independent.
		//
		// example:
		//	|	var calendar = new dijit.Calendar({}, dojo.byId("calendarNode"));
		//
		// example:
		//	|	<div dojoType="dijit.Calendar"></div>

		templateString: dojo.cache("dijit", "templates/Calendar.html", "<table cellspacing=\"0\" cellpadding=\"0\" class=\"dijitCalendarContainer\" role=\"grid\" dojoAttachEvent=\"onkeypress: _onKeyPress\">\n\t<thead>\n\t\t<tr class=\"dijitReset dijitCalendarMonthContainer\" valign=\"top\">\n\t\t\t<th class='dijitReset dijitCalendarArrow' dojoAttachPoint=\"decrementMonth\">\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarDecrease\" waiRole=\"presentation\"/>\n\t\t\t\t<span dojoAttachPoint=\"decreaseArrowNode\" class=\"dijitA11ySideArrow\">-</span>\n\t\t\t</th>\n\t\t\t<th class='dijitReset' colspan=\"5\">\n\t\t\t\t<div class=\"dijitVisible\">\n\t\t\t\t\t<div class=\"dijitPopup dijitMenu dijitMenuPassive dijitHidden\" dojoAttachPoint=\"monthDropDown\" dojoAttachEvent=\"onmouseup: _onMonthSelect, onmouseover: _onMenuHover, onmouseout: _onMenuHover\">\n\t\t\t\t\t\t<div class=\"dijitCalendarMonthLabelTemplate dijitCalendarMonthLabel\"></div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div dojoAttachPoint=\"monthLabelSpacer\" class=\"dijitSpacer\"></div>\n\t\t\t\t<div dojoAttachPoint=\"monthLabelNode\" class=\"dijitCalendarMonthLabel dijitInline dijitVisible\" dojoAttachEvent=\"onmousedown: _onMonthToggle\"></div>\n\t\t\t</th>\n\t\t\t<th class='dijitReset dijitCalendarArrow' dojoAttachPoint=\"incrementMonth\">\n\t\t\t\t<img src=\"${_blankGif}\" alt=\"\" class=\"dijitCalendarIncrementControl dijitCalendarIncrease\" waiRole=\"presentation\"/>\n\t\t\t\t<span dojoAttachPoint=\"increaseArrowNode\" class=\"dijitA11ySideArrow\">+</span>\n\t\t\t</th>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<th class=\"dijitReset dijitCalendarDayLabelTemplate\" role=\"columnheader\"><span class=\"dijitCalendarDayLabel\"></span></th>\n\t\t</tr>\n\t</thead>\n\t<tbody dojoAttachEvent=\"onclick: _onDayClick, onmouseover: _onDayMouseOver, onmouseout: _onDayMouseOut, onmousedown: _onDayMouseDown, onmouseup: _onDayMouseUp\" class=\"dijitReset dijitCalendarBodyContainer\">\n\t\t<tr class=\"dijitReset dijitCalendarWeekTemplate\" role=\"row\">\n\t\t\t<td class=\"dijitReset dijitCalendarDateTemplate\" role=\"gridcell\"><span class=\"dijitCalendarDateLabel\"></span></td>\n\t\t</tr>\n\t</tbody>\n\t<tfoot class=\"dijitReset dijitCalendarYearContainer\">\n\t\t<tr>\n\t\t\t<td class='dijitReset' valign=\"top\" colspan=\"7\">\n\t\t\t\t<h3 class=\"dijitCalendarYearLabel\">\n\t\t\t\t\t<span dojoAttachPoint=\"previousYearLabelNode\" class=\"dijitInline dijitCalendarPreviousYear\"></span>\n\t\t\t\t\t<span dojoAttachPoint=\"currentYearLabelNode\" class=\"dijitInline dijitCalendarSelectedYear\"></span>\n\t\t\t\t\t<span dojoAttachPoint=\"nextYearLabelNode\" class=\"dijitInline dijitCalendarNextYear\"></span>\n\t\t\t\t</h3>\n\t\t\t</td>\n\t\t</tr>\n\t</tfoot>\n</table>\n"),

		// value: Date
		//		The currently selected Date
		value: new Date(),

		// datePackage: String
		//		JavaScript namespace to find Calendar routines.  Uses Gregorian Calendar routines
		//		at dojo.date by default.
		datePackage: "dojo.date",

		// dayWidth: String
		//		How to represent the days of the week in the calendar header. See dojo.date.locale
		dayWidth: "narrow",

		// tabIndex: Integer
		//		Order fields are traversed when user hits the tab key
		tabIndex: "0",
		
		baseClass:"dijitCalendar",

		// Set node classes for various mouse events, see dijit._CssStateMixin for more details 
		cssStateNodes: {
			"decrementMonth": "dijitCalendarArrow",
			"incrementMonth": "dijitCalendarArrow",
			"previousYearLabelNode": "dijitCalendarPreviousYear",
			"nextYearLabelNode": "dijitCalendarNextYear"			
		},

		attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
			tabIndex: "domNode"
 		}),

		setValue: function(/*Date*/ value){
			// summary:
			//      Deprecated.   Used attr('value', ...) instead.
			// tags:
			//      deprecated
			dojo.deprecated("dijit.Calendar:setValue() is deprecated.  Use set('value', ...) instead.", "", "2.0");
			this.set('value', value);
		},

		_getValueAttr: function(){
			// summary:
			//		Support getter attr('value')
			var value = new this.dateClassObj(this.value);
			value.setHours(0, 0, 0, 0); // return midnight, local time for back-compat

			// If daylight savings pushes midnight to the previous date, fix the Date
			// object to point at 1am so it will represent the correct day. See #9366
			if(value.getDate() < this.value.getDate()){
				value = this.dateFuncObj.add(value, "hour", 1);
			}
			return value;
		},

		_setValueAttr: function(/*Date*/ value){
			// summary:
			//		Support setter attr("value", ...)
			// description:
			// 		Set the current date and update the UI.  If the date is disabled, the value will
			//		not change, but the display will change to the corresponding month.
			// tags:
			//      protected
			if(!this.value || this.dateFuncObj.compare(value, this.value)){
				value = new this.dateClassObj(value);
				value.setHours(1); // to avoid issues when DST shift occurs at midnight, see #8521, #9366
				this.displayMonth = new this.dateClassObj(value);
				if(!this.isDisabledDate(value, this.lang)){
					this.value = value;
					this.onChange(this.get('value'));
				}
				dojo.attr(this.domNode, "aria-label",
					this.dateLocaleModule.format(value,
						{selector:"date", formatLength:"full"}));
				this._populateGrid();
			}
		},

		_setText: function(node, text){
			// summary:
			//		This just sets the content of node to the specified text.
			//		Can't do "node.innerHTML=text" because of an IE bug w/tables, see #3434.
			// tags:
			//      private
			while(node.firstChild){
				node.removeChild(node.firstChild);
			}
			node.appendChild(dojo.doc.createTextNode(text));
		},

		_populateGrid: function(){
			// summary:
			//      Fills in the calendar grid with each day (1-31)
			// tags:
			//      private
			var month = this.displayMonth;
			month.setDate(1);
			var firstDay = month.getDay(),
				daysInMonth = this.dateFuncObj.getDaysInMonth(month),
				daysInPreviousMonth = this.dateFuncObj.getDaysInMonth(this.dateFuncObj.add(month, "month", -1)),
				today = new this.dateClassObj(),
				dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.lang);
			if(dayOffset > firstDay){ dayOffset -= 7; }

			// Iterate through dates in the calendar and fill in date numbers and style info
			dojo.query(".dijitCalendarDateTemplate", this.domNode).forEach(function(template, i){
				i += dayOffset;
				var date = new this.dateClassObj(month),
					number, clazz = "dijitCalendar", adj = 0;

				if(i < firstDay){
					number = daysInPreviousMonth - firstDay + i + 1;
					adj = -1;
					clazz += "Previous";
				}else if(i >= (firstDay + daysInMonth)){
					number = i - firstDay - daysInMonth + 1;
					adj = 1;
					clazz += "Next";
				}else{
					number = i - firstDay + 1;
					clazz += "Current";
				}

				if(adj){
					date = this.dateFuncObj.add(date, "month", adj);
				}
				date.setDate(number);

				if(!this.dateFuncObj.compare(date, today, "date")){
					clazz = "dijitCalendarCurrentDate " + clazz;
				}

				if(this._isSelectedDate(date, this.lang)){
					clazz = "dijitCalendarSelectedDate " + clazz;
				}

				if(this.isDisabledDate(date, this.lang)){
					clazz = "dijitCalendarDisabledDate " + clazz;
				}

				var clazz2 = this.getClassForDate(date, this.lang);
				if(clazz2){
					clazz = clazz2 + " " + clazz;
				}

				template.className = clazz + "Month dijitCalendarDateTemplate";
				template.dijitDateValue = date.valueOf();
				var label = dojo.query(".dijitCalendarDateLabel", template)[0],
					text = date.getDateLocalized ? date.getDateLocalized(this.lang) : date.getDate();
				this._setText(label, text);
			}, this);

			// Fill in localized month name
			var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, month);
			this._setText(this.monthLabelNode, monthNames[month.getMonth()]);
			// Repopulate month list based on current year (Hebrew calendar)
			dojo.query(".dijitCalendarMonthLabelTemplate", this.domNode).forEach(function(node, i){
				dojo.toggleClass(node, "dijitHidden", !(i in monthNames)); // hide leap months (Hebrew)
				this._setText(node, monthNames[i]);
			}, this);

			// Fill in localized prev/current/next years
			var y = month.getFullYear() - 1;
			var d = new this.dateClassObj();
			dojo.forEach(["previous", "current", "next"], function(name){
				d.setFullYear(y++);
				this._setText(this[name+"YearLabelNode"],
					this.dateLocaleModule.format(d, {selector:'year', locale:this.lang}));
			}, this);

			// Set up repeating mouse behavior
			var _this = this;
			var typematic = function(nodeProp, dateProp, adj){
//FIXME: leaks (collects) listeners if populateGrid is called multiple times.  Do this once?
				_this._connects.push(
					dijit.typematic.addMouseListener(_this[nodeProp], _this, function(count){
						if(count >= 0){ _this._adjustDisplay(dateProp, adj); }
					}, 0.8, 500)
				);
			};
			typematic("incrementMonth", "month", 1);
			typematic("decrementMonth", "month", -1);
			typematic("nextYearLabelNode", "year", 1);
			typematic("previousYearLabelNode", "year", -1);
		},

		goToToday: function(){
			// summary:
			//      Sets calendar's value to today's date
			this.set('value', new this.dateClassObj());
		},

		constructor: function(/*Object*/args){
			var dateClass = (args.datePackage && (args.datePackage != "dojo.date"))? args.datePackage + ".Date" : "Date";
			this.dateClassObj = dojo.getObject(dateClass, false);
			this.datePackage = args.datePackage || this.datePackage;
			this.dateFuncObj = dojo.getObject(this.datePackage, false);
			this.dateLocaleModule = dojo.getObject(this.datePackage + ".locale", false);
		},

		postMixInProperties: function(){
			// parser.instantiate sometimes passes in NaN for IE.  Use default value in prototype instead.
			if(isNaN(this.value)){ delete this.value; }
			this.inherited(arguments);
		},

		postCreate: function(){
			this.inherited(arguments);
			dojo.setSelectable(this.domNode, false);

			var cloneClass = dojo.hitch(this, function(clazz, n){
				var template = dojo.query(clazz, this.domNode)[0];
	 			for(var i=0; i<n; i++){
					template.parentNode.appendChild(template.cloneNode(true));
				}
			});

			// clone the day label and calendar day templates 6 times to make 7 columns
			cloneClass(".dijitCalendarDayLabelTemplate", 6);
			cloneClass(".dijitCalendarDateTemplate", 6);

			// now make 6 week rows
			cloneClass(".dijitCalendarWeekTemplate", 5);

			// insert localized day names in the header
			var dayNames = this.dateLocaleModule.getNames('days', this.dayWidth, 'standAlone', this.lang);
			var dayOffset = dojo.cldr.supplemental.getFirstDayOfWeek(this.lang);
			dojo.query(".dijitCalendarDayLabel", this.domNode).forEach(function(label, i){
				this._setText(label, dayNames[(i + dayOffset) % 7]);
			}, this);

			var dateObj = new this.dateClassObj(this.value);
			// Fill in spacer/month dropdown element with all the month names (invisible) so that the maximum width will affect layout
			var monthNames = this.dateLocaleModule.getNames('months', 'wide', 'standAlone', this.lang, dateObj);
			cloneClass(".dijitCalendarMonthLabelTemplate", monthNames.length-1);
			dojo.query(".dijitCalendarMonthLabelTemplate", this.domNode).forEach(function(node, i){
				dojo.attr(node, "month", i);
				if(i in monthNames){ this._setText(node, monthNames[i]); }
				dojo.place(node.cloneNode(true), this.monthLabelSpacer);
			}, this);

			this.value = null;
			this.set('value', dateObj);
		},

		_onMenuHover: function(e){
			dojo.stopEvent(e);
			dojo.toggleClass(e.target, "dijitMenuItemHover");
		},

		_adjustDisplay: function(/*String*/ part, /*int*/ amount){
			// summary:
			//      Moves calendar forwards or backwards by months or years
			// part:
			//      "month" or "year"
			// amount:
			//      Number of months or years
			// tags:
			//      private
			this.displayMonth = this.dateFuncObj.add(this.displayMonth, part, amount);
			this._populateGrid();
		},

		_onMonthToggle: function(/*Event*/ evt){
			// summary:
			//      Handler for when user triggers or dismisses the month list
			// tags:
			//      protected
			dojo.stopEvent(evt);

			if(evt.type == "mousedown"){
				var coords = dojo.position(this.monthLabelNode);
//				coords.y -= dojo.position(this.domNode, true).y;
				// Size the dropdown's width to match the label in the widget
				// so that they are horizontally aligned
				var dim = {
					width: coords.w + "px",
					top: -this.displayMonth.getMonth() * coords.h + "px"
				};
				if((dojo.isIE && dojo.isQuirks) || dojo.isIE < 7){
					dim.left = -coords.w/2 + "px";
				}
				dojo.style(this.monthDropDown, dim);
				this._popupHandler = this.connect(document, "onmouseup", "_onMonthToggle");
			}else{
				this.disconnect(this._popupHandler);
				delete this._popupHandler;
			}

			dojo.toggleClass(this.monthDropDown, "dijitHidden");
			dojo.toggleClass(this.monthLabelNode, "dijitVisible");
		},

		_onMonthSelect: function(/*Event*/ evt){
			// summary:
			//      Handler for when user selects a month from a list
			// tags:
			//      protected
			this._onMonthToggle(evt);
			this.displayMonth.setMonth(dojo.attr(evt.target, "month"));
			this._populateGrid();
		},

		_onDayClick: function(/*Event*/ evt){
			// summary:
			//      Handler for day clicks, selects the date if appropriate
			// tags:
			//      protected
			dojo.stopEvent(evt);
			for(var node = evt.target; node && !node.dijitDateValue; node = node.parentNode);
			if(node && !dojo.hasClass(node, "dijitCalendarDisabledDate")){
				this.set('value', node.dijitDateValue);
				this.onValueSelected(this.get('value'));
			}
		},

		_onDayMouseOver: function(/*Event*/ evt){
			// summary:
			//      Handler for mouse over events on days, sets hovered style
			// tags:
			//      protected

			// event can occur on <td> or the <span> inside the td,
			// set node to the <td>.
			var node =
				dojo.hasClass(evt.target, "dijitCalendarDateLabel") ?
				evt.target.parentNode :
				evt.target;

			if(node && (node.dijitDateValue || node == this.previousYearLabelNode || node == this.nextYearLabelNode) ){
				dojo.addClass(node, "dijitCalendarHoveredDate");
				this._currentNode = node;
			}
		},

		_onDayMouseOut: function(/*Event*/ evt){
			// summary:
			//      Handler for mouse out events on days, clears hovered style
			// tags:
			//      protected
	
			if(!this._currentNode){ return; }
			
			// if mouse out occurs moving from <td> to <span> inside <td>, ignore it
			if(evt.relatedTarget && evt.relatedTarget.parentNode == this._currentNode){ return; }

			dojo.removeClass(this._currentNode, "dijitCalendarHoveredDate");
			if(dojo.hasClass(this._currentNode, "dijitCalendarActiveDate")) {
				dojo.removeClass(this._currentNode, "dijitCalendarActiveDate");
			}
			this._currentNode = null;
		},
		
		_onDayMouseDown: function(/*Event*/ evt){
			var node = evt.target.parentNode;
			if(node && node.dijitDateValue){
				dojo.addClass(node, "dijitCalendarActiveDate");
				this._currentNode = node;
			}
		},
		
		_onDayMouseUp: function(/*Event*/ evt){
			var node = evt.target.parentNode;
			if(node && node.dijitDateValue){
				dojo.removeClass(node, "dijitCalendarActiveDate");
			}
		},

//TODO: use typematic
//TODO: skip disabled dates without ending up in a loop
//TODO: could optimize by avoiding populate grid when month does not change
		_onKeyPress: function(/*Event*/evt){
			// summary:
			//		Provides keyboard navigation of calendar
			// tags:
			//		protected
			var dk = dojo.keys,
				increment = -1,
				interval,
				newValue = this.value;
			switch(evt.keyCode){
				case dk.RIGHT_ARROW:
					increment = 1;
					//fallthrough...
				case dk.LEFT_ARROW:
					interval = "day";
					if(!this.isLeftToRight()){ increment *= -1; }
					break;
				case dk.DOWN_ARROW:
					increment = 1;
					//fallthrough...
				case dk.UP_ARROW:
					interval = "week";
					break;
				case dk.PAGE_DOWN:
					increment = 1;
					//fallthrough...
				case dk.PAGE_UP:
					interval = evt.ctrlKey ? "year" : "month";
					break;
				case dk.END:
					// go to the next month
					newValue = this.dateFuncObj.add(newValue, "month", 1);
					// subtract a day from the result when we're done
					interval = "day";
					//fallthrough...
				case dk.HOME:
					newValue = new Date(newValue).setDate(1);
					break;
				case dk.ENTER:
					this.onValueSelected(this.get('value'));
					break;
				case dk.ESCAPE:
					//TODO
				default:
					return;
			}
			dojo.stopEvent(evt);

			if(interval){
				newValue = this.dateFuncObj.add(newValue, interval, increment);
			}

			this.set("value", newValue);
		},

		onValueSelected: function(/*Date*/ date){
			// summary:
			//		Notification that a date cell was selected.  It may be the same as the previous value.
			// description:
			//      Used by `dijit.form._DateTimeTextBox` (and thus `dijit.form.DateTextBox`)
			//      to get notification when the user has clicked a date.
			// tags:
			//      protected
		},

		onChange: function(/*Date*/ date){
			// summary:
			//		Called only when the selected date has changed
		},

		_isSelectedDate: function(/*Date*/ dateObject, /*String?*/ locale){
			// summary:
			//		Extension point so developers can subclass Calendar to
			//		support multiple (concurrently) selected dates
			// tags:
			//		protected extension
			return !this.dateFuncObj.compare(dateObject, this.value, "date")
		},

		isDisabledDate: function(/*Date*/ dateObject, /*String?*/ locale){
			// summary:
			//		May be overridden to disable certain dates in the calendar e.g. `isDisabledDate=dojo.date.locale.isWeekend`
			// tags:
			//      extension
/*=====
			return false; // Boolean
=====*/
		},

		getClassForDate: function(/*Date*/ dateObject, /*String?*/ locale){
			// summary:
			//		May be overridden to return CSS classes to associate with the date entry for the given dateObject,
			//		for example to indicate a holiday in specified locale.
			// tags:
			//      extension

/*=====
			return ""; // String
=====*/
		}
	}
);

}

if(!dojo._hasResource["dijit.Tooltip"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Tooltip"] = true;
dojo.provide("dijit.Tooltip");




dojo.declare(
	"dijit._MasterTooltip",
	[dijit._Widget, dijit._Templated],
	{
		// summary:
		//		Internal widget that holds the actual tooltip markup,
		//		which occurs once per page.
		//		Called by Tooltip widgets which are just containers to hold
		//		the markup
		// tags:
		//		protected

		// duration: Integer
		//		Milliseconds to fade in/fade out
		duration: dijit.defaultDuration,

		templateString: dojo.cache("dijit", "templates/Tooltip.html", "<div class=\"dijitTooltip dijitTooltipLeft\" id=\"dojoTooltip\">\n\t<div class=\"dijitTooltipContainer dijitTooltipContents\" dojoAttachPoint=\"containerNode\" waiRole='alert'></div>\n\t<div class=\"dijitTooltipConnector\"></div>\n</div>\n"),

		postCreate: function(){
			dojo.body().appendChild(this.domNode);

			this.bgIframe = new dijit.BackgroundIframe(this.domNode);

			// Setup fade-in and fade-out functions.
			this.fadeIn = dojo.fadeIn({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onShow") });
			this.fadeOut = dojo.fadeOut({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onHide") });

		},

		show: function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position, /*Boolean*/ rtl){
			// summary:
			//		Display tooltip w/specified contents to right of specified node
			//		(To left if there's no space on the right, or if rtl == true)

			if(this.aroundNode && this.aroundNode === aroundNode){
				return;
			}

			if(this.fadeOut.status() == "playing"){
				// previous tooltip is being hidden; wait until the hide completes then show new one
				this._onDeck=arguments;
				return;
			}
			this.containerNode.innerHTML=innerHTML;

			var pos = dijit.placeOnScreenAroundElement(this.domNode, aroundNode, dijit.getPopupAroundAlignment((position && position.length) ? position : dijit.Tooltip.defaultPosition, !rtl), dojo.hitch(this, "orient"));

			// show it
			dojo.style(this.domNode, "opacity", 0);
			this.fadeIn.play();
			this.isShowingNow = true;
			this.aroundNode = aroundNode;
		},

		orient: function(/* DomNode */ node, /* String */ aroundCorner, /* String */ tooltipCorner){
			// summary:
			//		Private function to set CSS for tooltip node based on which position it's in.
			//		This is called by the dijit popup code.
			// tags:
			//		protected

			node.className = "dijitTooltip " +
				{
					"BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
					"TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
					"BR-TR": "dijitTooltipBelow dijitTooltipABRight",
					"TR-BR": "dijitTooltipAbove dijitTooltipABRight",
					"BR-BL": "dijitTooltipRight",
					"BL-BR": "dijitTooltipLeft"
				}[aroundCorner + "-" + tooltipCorner];
		},

		_onShow: function(){
			// summary:
			//		Called at end of fade-in operation
			// tags:
			//		protected
			if(dojo.isIE){
				// the arrow won't show up on a node w/an opacity filter
				this.domNode.style.filter="";
			}
		},

		hide: function(aroundNode){
			// summary:
			//		Hide the tooltip
			if(this._onDeck && this._onDeck[1] == aroundNode){
				// this hide request is for a show() that hasn't even started yet;
				// just cancel the pending show()
				this._onDeck=null;
			}else if(this.aroundNode === aroundNode){
				// this hide request is for the currently displayed tooltip
				this.fadeIn.stop();
				this.isShowingNow = false;
				this.aroundNode = null;
				this.fadeOut.play();
			}else{
				// just ignore the call, it's for a tooltip that has already been erased
			}
		},

		_onHide: function(){
			// summary:
			//		Called at end of fade-out operation
			// tags:
			//		protected

			this.domNode.style.cssText="";	// to position offscreen again
			this.containerNode.innerHTML="";
			if(this._onDeck){
				// a show request has been queued up; do it now
				this.show.apply(this, this._onDeck);
				this._onDeck=null;
			}
		}

	}
);

dijit.showTooltip = function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position, /*Boolean*/ rtl){
	// summary:
	//		Display tooltip w/specified contents in specified position.
	//		See description of dijit.Tooltip.defaultPosition for details on position parameter.
	//		If position is not specified then dijit.Tooltip.defaultPosition is used.
	if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
	return dijit._masterTT.show(innerHTML, aroundNode, position, rtl);
};

dijit.hideTooltip = function(aroundNode){
	// summary:
	//		Hide the tooltip
	if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
	return dijit._masterTT.hide(aroundNode);
};

dojo.declare(
	"dijit.Tooltip",
	dijit._Widget,
	{
		// summary:
		//		Pops up a tooltip (a help message) when you hover over a node.

		// label: String
		//		Text to display in the tooltip.
		//		Specified as innerHTML when creating the widget from markup.
		label: "",

		// showDelay: Integer
		//		Number of milliseconds to wait after hovering over/focusing on the object, before
		//		the tooltip is displayed.
		showDelay: 400,

		// connectId: [const] String[]
		//		Id's of domNodes to attach the tooltip to.
		//		When user hovers over any of the specified dom nodes, the tooltip will appear.
		//
		//		Note: Currently connectId can only be specified on initialization, it cannot
		//		be changed via attr('connectId', ...)
		//
		//		Note: in 2.0 this will be renamed to connectIds for less confusion.
		connectId: [],

		// position: String[]
		//		See description of `dijit.Tooltip.defaultPosition` for details on position parameter.
		position: [],

		constructor: function(){
			// Map id's of nodes I'm connected to to a list of the this.connect() handles
			this._nodeConnectionsById = {};
		},

		_setConnectIdAttr: function(newIds){
			for(var oldId in this._nodeConnectionsById){
				this.removeTarget(oldId);
			}
			dojo.forEach(dojo.isArrayLike(newIds) ? newIds : [newIds], this.addTarget, this);
		},

		_getConnectIdAttr: function(){
			var ary = [];
			for(var id in this._nodeConnectionsById){
				ary.push(id);
			}
			return ary;
		},

		addTarget: function(/*DOMNODE || String*/ id){
			// summary:
			//		Attach tooltip to specified node, if it's not already connected
			var node = dojo.byId(id);
			if(!node){ return; }
			if(node.id in this._nodeConnectionsById){ return; }//Already connected

			this._nodeConnectionsById[node.id] = [
				this.connect(node, "onmouseenter", "_onTargetMouseEnter"),
				this.connect(node, "onmouseleave", "_onTargetMouseLeave"),
				this.connect(node, "onfocus", "_onTargetFocus"),
				this.connect(node, "onblur", "_onTargetBlur")
			];
		},

		removeTarget: function(/*DOMNODE || String*/ node){
			// summary:
			//		Detach tooltip from specified node

			// map from DOMNode back to plain id string
			var id = node.id || node;

			if(id in this._nodeConnectionsById){
				dojo.forEach(this._nodeConnectionsById[id], this.disconnect, this);
				delete this._nodeConnectionsById[id];
			}
		},

		postCreate: function(){
			dojo.addClass(this.domNode,"dijitTooltipData");
		},

		startup: function(){
			this.inherited(arguments);

			// If this tooltip was created in a template, or for some other reason the specified connectId[s]
			// didn't exist during the widget's initialization, then connect now.
			var ids = this.connectId;
			dojo.forEach(dojo.isArrayLike(ids) ? ids : [ids], this.addTarget, this);
		},

		_onTargetMouseEnter: function(/*Event*/ e){
			// summary:
			//		Handler for mouseenter event on the target node
			// tags:
			//		private
			this._onHover(e);
		},

		_onTargetMouseLeave: function(/*Event*/ e){
			// summary:
			//		Handler for mouseleave event on the target node
			// tags:
			//		private
			this._onUnHover(e);
		},

		_onTargetFocus: function(/*Event*/ e){
			// summary:
			//		Handler for focus event on the target node
			// tags:
			//		private

			this._focus = true;
			this._onHover(e);
		},

		_onTargetBlur: function(/*Event*/ e){
			// summary:
			//		Handler for blur event on the target node
			// tags:
			//		private

			this._focus = false;
			this._onUnHover(e);
		},

		_onHover: function(/*Event*/ e){
			// summary:
			//		Despite the name of this method, it actually handles both hover and focus
			//		events on the target node, setting a timer to show the tooltip.
			// tags:
			//		private
			if(!this._showTimer){
				var target = e.target;
				this._showTimer = setTimeout(dojo.hitch(this, function(){this.open(target)}), this.showDelay);
			}
		},

		_onUnHover: function(/*Event*/ e){
			// summary:
			//		Despite the name of this method, it actually handles both mouseleave and blur
			//		events on the target node, hiding the tooltip.
			// tags:
			//		private

			// keep a tooltip open if the associated element still has focus (even though the
			// mouse moved away)
			if(this._focus){ return; }

			if(this._showTimer){
				clearTimeout(this._showTimer);
				delete this._showTimer;
			}
			this.close();
		},

		open: function(/*DomNode*/ target){
 			// summary:
			//		Display the tooltip; usually not called directly.
			// tags:
			//		private

			if(this._showTimer){
				clearTimeout(this._showTimer);
				delete this._showTimer;
			}
			dijit.showTooltip(this.label || this.domNode.innerHTML, target, this.position, !this.isLeftToRight());

			this._connectNode = target;
			this.onShow(target, this.position);
		},

		close: function(){
			// summary:
			//		Hide the tooltip or cancel timer for show of tooltip
			// tags:
			//		private

			if(this._connectNode){
				// if tooltip is currently shown
				dijit.hideTooltip(this._connectNode);
				delete this._connectNode;
				this.onHide();
			}
			if(this._showTimer){
				// if tooltip is scheduled to be shown (after a brief delay)
				clearTimeout(this._showTimer);
				delete this._showTimer;
			}
		},

		onShow: function(target, position){
			// summary:
			//		Called when the tooltip is shown
			// tags:
			//		callback
		},

		onHide: function(){
			// summary:
			//		Called when the tooltip is hidden
			// tags:
			//		callback
		},

		uninitialize: function(){
			this.close();
			this.inherited(arguments);
		}
	}
);

// dijit.Tooltip.defaultPosition: String[]
//		This variable controls the position of tooltips, if the position is not specified to
//		the Tooltip widget or *TextBox widget itself.  It's an array of strings with the following values:
//
//			* before: places tooltip to the left of the target node/widget, or to the right in
//			  the case of RTL scripts like Hebrew and Arabic
//			* after: places tooltip to the right of the target node/widget, or to the left in
//			  the case of RTL scripts like Hebrew and Arabic
//			* above: tooltip goes above target node
//			* below: tooltip goes below target node
//
//		The list is positions is tried, in order, until a position is found where the tooltip fits
//		within the viewport.
//
//		Be careful setting this parameter.  A value of "above" may work fine until the user scrolls
//		the screen so that there's no room above the target node.   Nodes with drop downs, like
//		DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure
//		that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there
//		is only room below (or above) the target node, but not both.
dijit.Tooltip.defaultPosition = ["after", "before"];

}

if(!dojo._hasResource["dijit.form.ValidationTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.ValidationTextBox"] = true;
dojo.provide("dijit.form.ValidationTextBox");








/*=====
	dijit.form.ValidationTextBox.__Constraints = function(){
		// locale: String
		//		locale used for validation, picks up value from this widget's lang attribute
		// _flags_: anything
		//		various flags passed to regExpGen function
		this.locale = "";
		this._flags_ = "";
	}
=====*/

dojo.declare(
	"dijit.form.ValidationTextBox",
	dijit.form.TextBox,
	{
		// summary:
		//		Base class for textbox widgets with the ability to validate content of various types and provide user feedback.
		// tags:
		//		protected

		templateString: dojo.cache("dijit.form", "templates/ValidationTextBox.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class=\"dijitReset dijitInputInner\" dojoAttachPoint='textbox,focusNode' autocomplete=\"off\"\n\t\t\t${!nameAttrSetting} type='${type}'\n\t/></div\n></div>\n"),
		baseClass: "dijitTextBox dijitValidationTextBox",

		// required: Boolean
		//		User is required to enter data into this field.
		required: false,

		// promptMessage: String
		//		If defined, display this hint string immediately on focus to the textbox, if empty.
		//		Think of this like a tooltip that tells the user what to do, not an error message
		//		that tells the user what they've done wrong.
		//
		//		Message disappears when user starts typing.
		promptMessage: "",

		// invalidMessage: String
		// 		The message to display if value is invalid.
		//		The translated string value is read from the message file by default.
		// 		Set to "" to use the promptMessage instead.
		invalidMessage: "$_unset_$",

		// missingMessage: String
		// 		The message to display if value is empty and the field is required.
		//		The translated string value is read from the message file by default.
		// 		Set to "" to use the invalidMessage instead.
		missingMessage: "$_unset_$",

		// constraints: dijit.form.ValidationTextBox.__Constraints
		//		user-defined object needed to pass parameters to the validator functions
		constraints: {},

		// regExp: [extension protected] String
		//		regular expression string used to validate the input
		//		Do not specify both regExp and regExpGen
		regExp: ".*",

		regExpGen: function(/*dijit.form.ValidationTextBox.__Constraints*/constraints){
			// summary:
			//		Overridable function used to generate regExp when dependent on constraints.
			//		Do not specify both regExp and regExpGen.
			// tags:
			//		extension protected
			return this.regExp; // String
		},

		// state: [readonly] String
		//		Shows current state (ie, validation result) of input (Normal, Warning, or Error)
		state: "",

		// tooltipPosition: String[]
		//		See description of `dijit.Tooltip.defaultPosition` for details on this parameter.
		tooltipPosition: [],

		_setValueAttr: function(){
			// summary:
			//		Hook so attr('value', ...) works.
			this.inherited(arguments);
			this.validate(this._focused);
		},

		validator: function(/*anything*/value, /*dijit.form.ValidationTextBox.__Constraints*/constraints){
			// summary:
			//		Overridable function used to validate the text input against the regular expression.
			// tags:
			//		protected
			return (new RegExp("^(?:" + this.regExpGen(constraints) + ")"+(this.required?"":"?")+"$")).test(value) &&
				(!this.required || !this._isEmpty(value)) &&
				(this._isEmpty(value) || this.parse(value, constraints) !== undefined); // Boolean
		},

		_isValidSubset: function(){
			// summary:
			//		Returns true if the value is either already valid or could be made valid by appending characters.
			//		This is used for validation while the user [may be] still typing.
			return this.textbox.value.search(this._partialre) == 0;
		},

		isValid: function(/*Boolean*/ isFocused){
			// summary:
			//		Tests if value is valid.
			//		Can override with your own routine in a subclass.
			// tags:
			//		protected
			return this.validator(this.textbox.value, this.constraints);
		},

		_isEmpty: function(value){
			// summary:
			//		Checks for whitespace
			return /^\s*$/.test(value); // Boolean
		},

		getErrorMessage: function(/*Boolean*/ isFocused){
			// summary:
			//		Return an error message to show if appropriate
			// tags:
			//		protected
			return (this.required && this._isEmpty(this.textbox.value)) ? this.missingMessage : this.invalidMessage; // String
		},

		getPromptMessage: function(/*Boolean*/ isFocused){
			// summary:
			//		Return a hint message to show when widget is first focused
			// tags:
			//		protected
			return this.promptMessage; // String
		},

		_maskValidSubsetError: true,
		validate: function(/*Boolean*/ isFocused){
			// summary:
			//		Called by oninit, onblur, and onkeypress.
			// description:
			//		Show missing or invalid messages if appropriate, and highlight textbox field.
			// tags:
			//		protected
			var message = "";
			var isValid = this.disabled || this.isValid(isFocused);
			if(isValid){ this._maskValidSubsetError = true; }
			var isEmpty = this._isEmpty(this.textbox.value);
			var isValidSubset = !isValid && !isEmpty && isFocused && this._isValidSubset();
			this.state = ((isValid || ((!this._hasBeenBlurred || isFocused) && isEmpty) || isValidSubset) && this._maskValidSubsetError) ? "" : "Error";
			if(this.state == "Error"){ this._maskValidSubsetError = isFocused; } // we want the error to show up afer a blur and refocus
			this._setStateClass();
			dijit.setWaiState(this.focusNode, "invalid", isValid ? "false" : "true");
			if(isFocused){
				if(this.state == "Error"){
					message = this.getErrorMessage(true);
				}else{
					message = this.getPromptMessage(true); // show the prompt whever there's no error
				}
				this._maskValidSubsetError = true; // since we're focused, always mask warnings
			}
			this.displayMessage(message);
			return isValid;
		},

		// _message: String
		//		Currently displayed message
		_message: "",

		displayMessage: function(/*String*/ message){
			// summary:
			//		Overridable method to display validation errors/hints.
			//		By default uses a tooltip.
			// tags:
			//		extension
			if(this._message == message){ return; }
			this._message = message;
			dijit.hideTooltip(this.domNode);
			if(message){
				dijit.showTooltip(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
			}
		},

		_refreshState: function(){
			// Overrides TextBox._refreshState()
			this.validate(this._focused);
			this.inherited(arguments);
		},

		//////////// INITIALIZATION METHODS ///////////////////////////////////////

		constructor: function(){
			this.constraints = {};
		},

		_setConstraintsAttr: function(/* Object */ constraints){
			if(!constraints.locale && this.lang){
				constraints.locale = this.lang;
			}
			this.constraints = constraints;
			this._computePartialRE();
		},

		_computePartialRE: function(){
			var p = this.regExpGen(this.constraints);
			this.regExp = p;
			var partialre = "";
			// parse the regexp and produce a new regexp that matches valid subsets
			// if the regexp is .* then there's no use in matching subsets since everything is valid
			if(p != ".*"){ this.regExp.replace(/\\.|\[\]|\[.*?[^\\]{1}\]|\{.*?\}|\(\?[=:!]|./g,
				function (re){
					switch(re.charAt(0)){
						case '{':
						case '+':
						case '?':
						case '*':
						case '^':
						case '$':
						case '|':
						case '(':
							partialre += re;
							break;
						case ")":
							partialre += "|$)";
							break;
						 default:
							partialre += "(?:"+re+"|$)";
							break;
					}
				}
			);}
			try{ // this is needed for now since the above regexp parsing needs more test verification
				"".search(partialre);
			}catch(e){ // should never be here unless the original RE is bad or the parsing is bad
				partialre = this.regExp;
				console.warn('RegExp error in ' + this.declaredClass + ': ' + this.regExp);
			} // should never be here unless the original RE is bad or the parsing is bad
			this._partialre = "^(?:" + partialre + ")$";
		},

		postMixInProperties: function(){
			this.inherited(arguments);
			this.messages = dojo.i18n.getLocalization("dijit.form", "validate", this.lang);
			if(this.invalidMessage == "$_unset_$"){ this.invalidMessage = this.messages.invalidMessage; }
			if(!this.invalidMessage){ this.invalidMessage = this.promptMessage; }
			if(this.missingMessage == "$_unset_$"){ this.missingMessage = this.messages.missingMessage; }
			if(!this.missingMessage){ this.missingMessage = this.invalidMessage; }
			this._setConstraintsAttr(this.constraints); // this needs to happen now (and later) due to codependency on _set*Attr calls attachPoints
		},

		_setDisabledAttr: function(/*Boolean*/ value){
			this.inherited(arguments);	// call FormValueWidget._setDisabledAttr()
			this._refreshState();
		},

		_setRequiredAttr: function(/*Boolean*/ value){
			this.required = value;
			dijit.setWaiState(this.focusNode, "required", value);
			this._refreshState();
		},

		reset:function(){
			// Overrides dijit.form.TextBox.reset() by also
			// hiding errors about partial matches
			this._maskValidSubsetError = true;
			this.inherited(arguments);
		},

		_onBlur: function(){
			this.displayMessage('');
			this.inherited(arguments);
		}
	}
);

dojo.declare(
	"dijit.form.MappedTextBox",
	dijit.form.ValidationTextBox,
	{
		// summary:
		//		A dijit.form.ValidationTextBox subclass which provides a base class for widgets that have
		//		a visible formatted display value, and a serializable
		//		value in a hidden input field which is actually sent to the server.
		// description:
		//		The visible display may
		//		be locale-dependent and interactive.  The value sent to the server is stored in a hidden
		//		input field which uses the `name` attribute declared by the original widget.  That value sent
		//		to the server is defined by the dijit.form.MappedTextBox.serialize method and is typically
		//		locale-neutral.
		// tags:
		//		protected

		postMixInProperties: function(){
			this.inherited(arguments);

			// we want the name attribute to go to the hidden <input>, not the displayed <input>,
			// so override _FormWidget.postMixInProperties() setting of nameAttrSetting
			this.nameAttrSetting = "";
		},

		serialize: function(/*anything*/val, /*Object?*/options){
			// summary:
			//		Overridable function used to convert the attr('value') result to a canonical
			//		(non-localized) string.  For example, will print dates in ISO format, and
			//		numbers the same way as they are represented in javascript.
			// tags:
			//		protected extension
			return val.toString ? val.toString() : ""; // String
		},

		toString: function(){
			// summary:
			//		Returns widget as a printable string using the widget's value
			// tags:
			//		protected
			var val = this.filter(this.get('value')); // call filter in case value is nonstring and filter has been customized
			return val != null ? (typeof val == "string" ? val : this.serialize(val, this.constraints)) : ""; // String
		},

		validate: function(){
			// Overrides `dijit.form.TextBox.validate`
			this.valueNode.value = this.toString();
			return this.inherited(arguments);
		},

		buildRendering: function(){
			// Overrides `dijit._Templated.buildRendering`

			this.inherited(arguments);

			// Create a hidden <input> node with the serialized value used for submit
			// (as opposed to the displayed value).
			// Passing in name as markup rather than calling dojo.create() with an attrs argument
			// to make dojo.query(input[name=...]) work on IE. (see #8660)
			this.valueNode = dojo.place("<input type='hidden'" + (this.name ? " name='" + this.name + "'" : "") + ">", this.textbox, "after");
		},

		reset:function(){
			// Overrides `dijit.form.ValidationTextBox.reset` to
			// reset the hidden textbox value to ''
			this.valueNode.value = '';
			this.inherited(arguments);
		}
	}
);

/*=====
	dijit.form.RangeBoundTextBox.__Constraints = function(){
		// min: Number
		//		Minimum signed value.  Default is -Infinity
		// max: Number
		//		Maximum signed value.  Default is +Infinity
		this.min = min;
		this.max = max;
	}
=====*/

dojo.declare(
	"dijit.form.RangeBoundTextBox",
	dijit.form.MappedTextBox,
	{
		// summary:
		//		Base class for textbox form widgets which defines a range of valid values.

		// rangeMessage: String
		//		The message to display if value is out-of-range
		rangeMessage: "",

		/*=====
		// constraints: dijit.form.RangeBoundTextBox.__Constraints
		constraints: {},
		======*/

		rangeCheck: function(/*Number*/ primitive, /*dijit.form.RangeBoundTextBox.__Constraints*/ constraints){
			// summary:
			//		Overridable function used to validate the range of the numeric input value.
			// tags:
			//		protected
			return	("min" in constraints? (this.compare(primitive,constraints.min) >= 0) : true) &&
				("max" in constraints? (this.compare(primitive,constraints.max) <= 0) : true); // Boolean
		},

		isInRange: function(/*Boolean*/ isFocused){
			// summary:
			//		Tests if the value is in the min/max range specified in constraints
			// tags:
			//		protected
			return this.rangeCheck(this.get('value'), this.constraints);
		},

		_isDefinitelyOutOfRange: function(){
			// summary:
			//		Returns true if the value is out of range and will remain
			//		out of range even if the user types more characters
			var val = this.get('value');
			var isTooLittle = false;
			var isTooMuch = false;
			if("min" in this.constraints){
				var min = this.constraints.min;
				min = this.compare(val, ((typeof min == "number") && min >= 0 && val !=0) ? 0 : min);
				isTooLittle = (typeof min == "number") && min < 0;
			}
			if("max" in this.constraints){
				var max = this.constraints.max;
				max = this.compare(val, ((typeof max != "number") || max > 0) ? max : 0);
				isTooMuch = (typeof max == "number") && max > 0;
			}
			return isTooLittle || isTooMuch;
		},

		_isValidSubset: function(){
			// summary:
			//		Overrides `dijit.form.ValidationTextBox._isValidSubset`.
			//		Returns true if the input is syntactically valid, and either within
			//		range or could be made in range by more typing.
			return this.inherited(arguments) && !this._isDefinitelyOutOfRange();
		},

		isValid: function(/*Boolean*/ isFocused){
			// Overrides dijit.form.ValidationTextBox.isValid to check that the value is also in range.
			return this.inherited(arguments) &&
				((this._isEmpty(this.textbox.value) && !this.required) || this.isInRange(isFocused)); // Boolean
		},

		getErrorMessage: function(/*Boolean*/ isFocused){
			// Overrides dijit.form.ValidationTextBox.getErrorMessage to print "out of range" message if appropriate
			var v = this.get('value');
			if(v !== null && v !== '' && v !== undefined && (typeof v != "number" || !isNaN(v)) && !this.isInRange(isFocused)){ // don't check isInRange w/o a real value
				return this.rangeMessage; // String
			}
			return this.inherited(arguments);
		},

		postMixInProperties: function(){
			this.inherited(arguments);
			if(!this.rangeMessage){
				this.messages = dojo.i18n.getLocalization("dijit.form", "validate", this.lang);
				this.rangeMessage = this.messages.rangeMessage;
			}
		},

		_setConstraintsAttr: function(/* Object */ constraints){
			this.inherited(arguments);
			if(this.focusNode){ // not set when called from postMixInProperties
				if(this.constraints.min !== undefined){
					dijit.setWaiState(this.focusNode, "valuemin", this.constraints.min);
				}else{
					dijit.removeWaiState(this.focusNode, "valuemin");
				}
				if(this.constraints.max !== undefined){
					dijit.setWaiState(this.focusNode, "valuemax", this.constraints.max);
				}else{
					dijit.removeWaiState(this.focusNode, "valuemax");
				}
			}
		},

		_setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange){
			// summary:
			//		Hook so attr('value', ...) works.

			dijit.setWaiState(this.focusNode, "valuenow", value);
			this.inherited(arguments);
		}
	}
);

}

if(!dojo._hasResource["dijit.form._DateTimeTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form._DateTimeTextBox"] = true;
dojo.provide("dijit.form._DateTimeTextBox");






new Date("X"); // workaround for #11279, new Date("") == NaN

/*=====
dojo.declare(
	"dijit.form._DateTimeTextBox.__Constraints",
	[dijit.form.RangeBoundTextBox.__Constraints, dojo.date.locale.__FormatOptions], {
	// summary:
	//		Specifies both the rules on valid/invalid values (first/last date/time allowed),
	//		and also formatting options for how the date/time is displayed.
	// example:
	//		To restrict to dates within 2004, displayed in a long format like "December 25, 2005":
	//	|		{min:'2004-01-01',max:'2004-12-31', formatLength:'long'}
});
=====*/

dojo.declare(
	"dijit.form._DateTimeTextBox",
	dijit.form.RangeBoundTextBox,
	{
		// summary:
		//		Base class for validating, serializable, range-bound date or time text box.

		// constraints: dijit.form._DateTimeTextBox.__Constraints
		//		Despite the name, this parameter specifies both constraints on the input
		//		(including starting/ending dates/times allowed) as well as
		//		formatting options like whether the date is displayed in long (ex: December 25, 2005)
		//		or short (ex: 12/25/2005) format.   See `dijit.form._DateTimeTextBox.__Constraints` for details.
		/*=====
		constraints: {},
		======*/

		// Override ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
		// than a straight regexp to deal with locale  (plus formatting options too?)
		regExpGen: dojo.date.locale.regexp,

		// datePackage: String
		//	JavaScript namespace to find calendar routines.  Uses Gregorian calendar routines
		//	at dojo.date, by default.
		datePackage: "dojo.date",

		// Override _FormWidget.compare() to work for dates/times
		compare: dojo.date.compare,

		format: function(/*Date*/ value, /*dojo.date.locale.__FormatOptions*/ constraints){
			// summary:
			//		Formats the value as a Date, according to specified locale (second argument)
			// tags:
			//		protected
			if(!value){ return ''; }
			return this.dateLocaleModule.format(value, constraints);
		},

		parse: function(/*String*/ value, /*dojo.date.locale.__FormatOptions*/ constraints){
			// summary:
			//		Parses as string as a Date, according to constraints
			// tags:
			//		protected

			return this.dateLocaleModule.parse(value, constraints) || (this._isEmpty(value) ? null : undefined);	 // Date
		},

		// Overrides ValidationTextBox.serialize() to serialize a date in canonical ISO format.
		serialize: function(/*anything*/val, /*Object?*/options){
			if(val.toGregorian){
				val = val.toGregorian();
			}
			return dojo.date.stamp.toISOString(val, options);
		},

		// value: Date
		//		The value of this widget as a JavaScript Date object.  Use get("value") / set("value", val) to manipulate.
		//		When passed to the parser in markup, must be specified according to `dojo.date.stamp.fromISOString`
		value: new Date(""),	// value.toString()="NaN"
		_blankValue: null,	// used by filter() when the textbox is blank

		//	popupClass: [protected extension] String
		//		Name of the popup widget class used to select a date/time.
		//		Subclasses should specify this.
		popupClass: "", // default is no popup = text only


		// _selector: [protected extension] String
		//		Specifies constraints.selector passed to dojo.date functions, should be either
		//		"date" or "time".
		//		Subclass must specify this.
		_selector: "",

		constructor: function(/*Object*/args){
			var dateClass = args.datePackage ? args.datePackage + ".Date" : "Date";
			this.dateClassObj = dojo.getObject(dateClass, false);
			this.value = new this.dateClassObj("");

			this.datePackage = args.datePackage || this.datePackage;
			this.dateLocaleModule = dojo.getObject(this.datePackage + ".locale", false);
			this.regExpGen = this.dateLocaleModule.regexp;
		},

		_setConstraintsAttr: function(/* Object */ constraints){
			constraints.selector = this._selector;
			constraints.fullYear = true; // see #5465 - always format with 4-digit years
			var fromISO = dojo.date.stamp.fromISOString;
			if(typeof constraints.min == "string"){ constraints.min = fromISO(constraints.min); }
 			if(typeof constraints.max == "string"){ constraints.max = fromISO(constraints.max); }
			this.inherited(arguments, [constraints]);
		},

		_onFocus: function(/*Event*/ evt){
			// summary:
			//		open the popup
			this._open();
			this.inherited(arguments);
		},

		_setValueAttr: function(/*Date*/ value, /*Boolean?*/ priorityChange, /*String?*/ formattedValue){
			// summary:
			//		Sets the date on this textbox.  Note that `value` must be like a Javascript Date object.
			if(value !== undefined){
				if(!value || value.toString() == dijit.form._DateTimeTextBox.prototype.value.toString()){
					value = null;
				}
				if(value instanceof Date && !(this.dateClassObj instanceof Date)){
					value = new this.dateClassObj(value);
				}
			}
			this.inherited(arguments, [value, priorityChange, formattedValue]);
			if(this._picker){
				// #3948: fix blank date on popup only
				if(!value){value = new this.dateClassObj();}
				this._picker.set('value', value);
			}
		},

		_open: function(){
			// summary:
			//		opens the TimePicker, and sets the onValueSelected value

			if(this.disabled || this.readOnly || !this.popupClass){return;}

			var textBox = this;

			if(!this._picker){
				var PopupProto = dojo.getObject(this.popupClass, false);
				this._picker = new PopupProto({
					onValueSelected: function(value){
						if(textBox._tabbingAway){
							delete textBox._tabbingAway;
						}else{
							textBox.focus(); // focus the textbox before the popup closes to avoid reopening the popup
						}
						setTimeout(dojo.hitch(textBox, "_close"), 1); // allow focus time to take

						// this will cause InlineEditBox and other handlers to do stuff so make sure it's last
						dijit.form._DateTimeTextBox.superclass._setValueAttr.call(textBox, value, true);
					},
					id: this.id + "_popup",
					dir: textBox.dir,
					lang: textBox.lang,
					value: this.get('value') || new this.dateClassObj(),
					constraints: textBox.constraints,

					datePackage: textBox.datePackage,

					isDisabledDate: function(/*Date*/ date){
						// summary:
						// 	disables dates outside of the min/max of the _DateTimeTextBox
						var compare = dojo.date.compare;
						var constraints = textBox.constraints;
						return constraints && (
							(constraints.min && compare(constraints.min, date, textBox._selector) > 0) ||
							(constraints.max && compare(constraints.max, date, textBox._selector) < 0)
						);
					}
				});
			}
			if(!this._opened){
				// Open drop down.  Align left sides of input box and drop down, even in RTL mode,
				// otherwise positioning thrown off when the drop down width is changed in marginBox call below (#10676)
				dijit.popup.open({
					parent: this,
					popup: this._picker,
					orient: {'BL':'TL', 'TL':'BL'},
					around: this.domNode,
					onCancel: dojo.hitch(this, this._close),
					onClose: function(){ textBox._opened=false; }
				});
				this._opened=true;
			}

			dojo.marginBox(this._picker.domNode,{ w:this.domNode.offsetWidth });
		},

		_close: function(){
			if(this._opened){
				dijit.popup.close(this._picker);
				this._opened=false;
			}
		},

		_onBlur: function(){
			// summary:
			//		Called magically when focus has shifted away from this widget and it's dropdown
			this._close();
			if(this._picker){
				// teardown so that constraints will be rebuilt next time (redundant reference: #6002)
				this._picker.destroy();
				delete this._picker;
			}
			this.inherited(arguments);
			// don't focus on <input>.  the user has explicitly focused on something else.
		},

		_getDisplayedValueAttr: function(){
			return this.textbox.value;
		},

		_setDisplayedValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange){
			this._setValueAttr(this.parse(value, this.constraints), priorityChange, value);
		},

		destroy: function(){
			if(this._picker){
				this._picker.destroy();
				delete this._picker;
			}
			this.inherited(arguments);
		},

		postCreate: function(){
			this.inherited(arguments);
			this.connect(this.focusNode, 'onkeypress', this._onKeyPress);
			this.connect(this.focusNode, 'onclick', this._open);
		},

		_onKeyPress: function(/*Event*/ e){
			// summary:
			//		Handler for keypress events

			var p = this._picker, dk = dojo.keys;
			// Handle the key in the picker, if it has a handler.  If the handler
			// returns false, then don't handle any other keys.
			if(p && this._opened && p.handleKey){
				if(p.handleKey(e) === false){ return; }
			}
			if(this._opened && e.charOrCode == dk.ESCAPE && !(e.shiftKey || e.ctrlKey || e.altKey || e.metaKey)){
				this._close();
				dojo.stopEvent(e);
			}else if(!this._opened && e.charOrCode == dk.DOWN_ARROW){
				this._open();
				dojo.stopEvent(e);
			}else if(e.charOrCode === dk.TAB){
				this._tabbingAway = true;
			}else if(this._opened && (e.keyChar || e.charOrCode === dk.BACKSPACE || e.charOrCode == dk.DELETE)){
				// Replace the element - but do it after a delay to allow for
				// filtering to occur
				setTimeout(dojo.hitch(this, function(){
					if(this._picker && this._opened){
						dijit.placeOnScreenAroundElement(p.domNode.parentNode, this.domNode, {'BL':'TL', 'TL':'BL'}, p.orient ? dojo.hitch(p, "orient") : null);
					}
				}), 1);
			}
		}
	}
);

}

if(!dojo._hasResource["dijit.form.DateTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.DateTextBox"] = true;
dojo.provide("dijit.form.DateTextBox");




dojo.declare(
	"dijit.form.DateTextBox",
	dijit.form._DateTimeTextBox,
	{
		// summary:
		//		A validating, serializable, range-bound date text box with a drop down calendar
		//
		//		Example:
		// |	new dijit.form.DateTextBox({value: new Date(2009, 0, 20)})
		//
		//		Example:
		// |	<input dojotype='dijit.form.DateTextBox' value='2009-01-20'>

		baseClass: "dijitTextBox dijitDateTextBox",
		popupClass: "dijit.Calendar",
		_selector: "date",

		// value: Date
		//		The value of this widget as a JavaScript Date object, with only year/month/day specified.
		//		If specified in markup, use the format specified in `dojo.date.stamp.fromISOString`
		value: new Date("")	// value.toString()="NaN"
	}
);

}

if(!dojo._hasResource["dijit._TimePicker"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._TimePicker"] = true;
dojo.provide("dijit._TimePicker");




/*=====
dojo.declare(
	"dijit._TimePicker.__Constraints",
	dojo.date.locale.__FormatOptions,
	{
		// clickableIncrement: String
		//		See `dijit._TimePicker.clickableIncrement`
		clickableIncrement: "T00:15:00",

		// visibleIncrement: String
		//		See `dijit._TimePicker.visibleIncrement`
		visibleIncrement: "T01:00:00",

		// visibleRange: String
		//		See `dijit._TimePicker.visibleRange`
		visibleRange: "T05:00:00"
	}
);
=====*/

dojo.declare("dijit._TimePicker",
	[dijit._Widget, dijit._Templated],
	{
		// summary:
		//		A graphical time picker.
		//		This widget is used internally by other widgets and is not available
		//		as a standalone widget due to lack of accessibility support.

		templateString: dojo.cache("dijit", "templates/TimePicker.html", "<div id=\"widget_${id}\" class=\"dijitMenu\"\n    ><div dojoAttachPoint=\"upArrow\" class=\"dijitButtonNode dijitUpArrowButton\" dojoAttachEvent=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" wairole=\"presentation\" role=\"presentation\">&nbsp;</div\n\t\t><div class=\"dijitArrowButtonChar\">&#9650;</div></div\n    ><div dojoAttachPoint=\"timeMenu,focusNode\" dojoAttachEvent=\"onclick:_onOptionSelected,onmouseover,onmouseout\"></div\n    ><div dojoAttachPoint=\"downArrow\" class=\"dijitButtonNode dijitDownArrowButton\" dojoAttachEvent=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" wairole=\"presentation\" role=\"presentation\">&nbsp;</div\n\t\t><div class=\"dijitArrowButtonChar\">&#9660;</div></div\n></div>\n"),

		// baseClass: [protected] String
		//		The root className to use for the various states of this widget
		baseClass: "dijitTimePicker",

		// clickableIncrement: String
		//		ISO-8601 string representing the amount by which
		//		every clickable element in the time picker increases.
		//		Set in local time, without a time zone.
		//		Example: `T00:15:00` creates 15 minute increments
		//		Must divide dijit._TimePicker.visibleIncrement evenly
		clickableIncrement: "T00:15:00",

		// visibleIncrement: String
		//		ISO-8601 string representing the amount by which
		//		every element with a visible time in the time picker increases.
		//		Set in local time, without a time zone.
		//		Example: `T01:00:00` creates text in every 1 hour increment
		visibleIncrement: "T01:00:00",

		// visibleRange: String
		//		ISO-8601 string representing the range of this TimePicker.
		//		The TimePicker will only display times in this range.
		//		Example: `T05:00:00` displays 5 hours of options
		visibleRange: "T05:00:00",

		// value: String
		//		Date to display.
		//		Defaults to current time and date.
		//		Can be a Date object or an ISO-8601 string.
		//		If you specify the GMT time zone (`-01:00`),
		//		the time will be converted to the local time in the local time zone.
		//		Otherwise, the time is considered to be in the local time zone.
		//		If you specify the date and isDate is true, the date is used.
		//		Example: if your local time zone is `GMT -05:00`,
		//		`T10:00:00` becomes `T10:00:00-05:00` (considered to be local time),
		//		`T10:00:00-01:00` becomes `T06:00:00-05:00` (4 hour difference),
		//		`T10:00:00Z` becomes `T05:00:00-05:00` (5 hour difference between Zulu and local time)
		//		`yyyy-mm-ddThh:mm:ss` is the format to set the date and time
		//		Example: `2007-06-01T09:00:00`
		value: new Date(),

		_visibleIncrement:2,
		_clickableIncrement:1,
		_totalIncrements:10,

		// constraints: dijit._TimePicker.__Constraints
		//		Specifies valid range of times (start time, end time)
		constraints:{},

/*=====
		serialize: function(val, options){
			// summary:
			//		User overridable function used to convert the attr('value') result to a String
			// val: Date
			//		The current value
			// options: Object?
			// tags:
			//		protected
		},
=====*/
		serialize: dojo.date.stamp.toISOString,

		// _filterString: string
		//		The string to filter by
		_filterString: "",

		setValue: function(/*Date*/ value){
			// summary:
			//		Deprecated.  Used attr('value') instead.
			// tags:
			//		deprecated
			dojo.deprecated("dijit._TimePicker:setValue() is deprecated.  Use set('value', ...) instead.", "", "2.0");
			this.set('value', value);
		},
		_setValueAttr: function(/*Date*/ date){
			// summary:
			//		Hook so attr('value', ...) works.
			// description:
			//		Set the value of the TimePicker.
			//		Redraws the TimePicker around the new date.
			// tags:
			//		protected
			this.value = date;
			this._showText();
		},

		onOpen: function(best){
			// summary:
			//		This is called by the popup manager when a TimeTextBox is displayed on the screen
			// best:
			//		Whether it is being displayed above or below the `dijit.form.TimeTextBox`
			// tags:
			//		protected
			if(this._beenOpened && this.domNode.parentNode){
				// We've been opened before - so set our filter to to the
				// currently-displayed value (or empty string if it's already
				// valid)
				var p = dijit.byId(this.domNode.parentNode.dijitPopupParent);
				if(p){
					var val = p.get('displayedValue');
					if(val && !p.parse(val, p.constraints)){
						this._filterString = val;
					}else{
						this._filterString = "";
					}
					this._showText();
				}
			}
			this._beenOpened = true;
		},

		isDisabledDate: function(/*Date*/ dateObject, /*String?*/ locale){
			// summary:
			//		May be overridden to disable certain dates in the TimePicker e.g. `isDisabledDate=dojo.date.locale.isWeekend`
			// type:
			//		extension
			return false; // Boolean
		},

		_getFilteredNodes: function(/*number*/ start, /*number*/ maxNum, /*Boolean*/ before){
			// summary:
			//		Returns an array of nodes with the filter applied.  At most maxNum nodes
			//		will be returned - but fewer may be returned as well.  If the
			//		before parameter is set to true, then it will return the elements
			//		before the given index
			// tags:
			//		private
			var nodes = [], n, i = start, max = this._maxIncrement + Math.abs(i),
				chk = before?-1:1, dec = before?1:0, inc = before?0:1;
			do{
				i = i - dec;
				n = this._createOption(i);
				if(n){nodes.push(n);}
				i = i + inc;
			}while(nodes.length < maxNum && (i*chk) < max);
			if(before){ nodes.reverse(); }
			return nodes;
		},

		_showText: function(){
			// summary:
			//		Displays the relevant choices in the drop down list
			// tags:
			//		private
			this.timeMenu.innerHTML = "";
			var fromIso = dojo.date.stamp.fromISOString;
			this._clickableIncrementDate=fromIso(this.clickableIncrement);
			this._visibleIncrementDate=fromIso(this.visibleIncrement);
			this._visibleRangeDate=fromIso(this.visibleRange);
			// get the value of the increments and the range in seconds (since 00:00:00) to find out how many divs to create
			var sinceMidnight = function(/*Date*/ date){
				return date.getHours() * 60 * 60 + date.getMinutes() * 60 + date.getSeconds();
			};

			var clickableIncrementSeconds = sinceMidnight(this._clickableIncrementDate);
			var visibleIncrementSeconds = sinceMidnight(this._visibleIncrementDate);
			var visibleRangeSeconds = sinceMidnight(this._visibleRangeDate);

			// round reference date to previous visible increment
			var time = this.value.getTime();
			this._refDate = new Date(time - time % (visibleIncrementSeconds*1000));
			this._refDate.setFullYear(1970,0,1); // match parse defaults

			// assume clickable increment is the smallest unit
			this._clickableIncrement = 1;
			// divide the visible range by the clickable increment to get the number of divs to create
			// example: 10:00:00/00:15:00 -> display 40 divs
			this._totalIncrements = visibleRangeSeconds / clickableIncrementSeconds;
			// divide the visible increments by the clickable increments to get how often to display the time inline
			// example: 01:00:00/00:15:00 -> display the time every 4 divs
			this._visibleIncrement = visibleIncrementSeconds / clickableIncrementSeconds;
			// divide the number of seconds in a day by the clickable increment in seconds to get the
			// absolute max number of increments.
			this._maxIncrement = (60 * 60 * 24) / clickableIncrementSeconds;

			// find the nodes we should display based on our filter
			var before = this._getFilteredNodes(0, this._totalIncrements >> 1, true);
			var after = this._getFilteredNodes(0, this._totalIncrements >> 1, false);
			if(before.length < this._totalIncrements >> 1){
				before = before.slice(before.length / 2);
				after = after.slice(0, after.length / 2);
			}
			dojo.forEach(before.concat(after), function(n){this.timeMenu.appendChild(n);}, this);

			// TODO:
			// I commented this out because it
			// causes problems for a TimeTextBox in a Dialog, or as the editor of an InlineEditBox,
			// because the timeMenu node isn't visible yet. -- Bill (Bug #????)
			// dijit.focus(this.timeMenu);
		},

		postCreate: function(){
			// instantiate constraints
			if(this.constraints === dijit._TimePicker.prototype.constraints){
				this.constraints={};
			}

			// brings in visibleRange, increments, etc.
			dojo.mixin(this, this.constraints);

			// dojo.date.locale needs the lang in the constraints as locale
			if(!this.constraints.locale){
				this.constraints.locale=this.lang;
			}

			// assign typematic mouse listeners to the arrow buttons
			this.connect(this.timeMenu, dojo.isIE ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
			var _this = this;
			var typematic = function(){
				_this._connects.push(
					dijit.typematic.addMouseListener.apply(null, arguments)
				);
			};
			typematic(this.upArrow,this,this._onArrowUp, 1.0, 50);
			typematic(this.downArrow,this,this._onArrowDown, 1.0, 50);

			// Connect some callback functions to the hover event of the arrows
			var triggerFx = function(cb){
				return function(cnt){
					// don't run on the first firing
					if(cnt > 0){cb.call(this, arguments);}
				};
			};
			var hoverFx = function(node, cb){
				return function(e){
					dojo.stopEvent(e);
					dijit.typematic.trigger(e, this, node, triggerFx(cb), node, 1.0, 50);
				};
			};
			this.connect(this.upArrow, "onmouseover", hoverFx(this.upArrow, this._onArrowUp));
			this.connect(this.downArrow, "onmouseover", hoverFx(this.downArrow, this._onArrowDown));

			this.inherited(arguments);
		},

		_buttonMouse: function(/*Event*/ e){
			// summary:
			//		Handler for hover (and unhover) on up/down arrows
			// tags:
			//		private

			// in non-IE browser the "mouseenter" event will become "mouseover", 
			// but in IE it's still "mouseenter"
			dojo.toggleClass(e.currentTarget, e.currentTarget == this.upArrow ? "dijitUpArrowHover" : "dijitDownArrowHover", 
				e.type == "mouseenter" || e.type == "mouseover");
		},

		_createOption: function(/*Number*/ index){
			// summary:
			//		Creates a clickable time option
			// tags:
			//		private
			var date = new Date(this._refDate);
			var incrementDate = this._clickableIncrementDate;
			date.setHours(date.getHours() + incrementDate.getHours() * index,
				date.getMinutes() + incrementDate.getMinutes() * index,
				date.getSeconds() + incrementDate.getSeconds() * index);
			if(this.constraints.selector == "time"){
				date.setFullYear(1970,0,1); // make sure each time is for the same date
			}
			var dateString = dojo.date.locale.format(date, this.constraints);
			if(this._filterString && dateString.toLowerCase().indexOf(this._filterString) !== 0){
				// Doesn't match the filter - return null
				return null;
			}

			var div = dojo.create("div", {"class": this.baseClass+"Item"});
			div.date = date;
			div.index = index;
			dojo.create('div',{
				"class": this.baseClass + "ItemInner",
				innerHTML: dateString
			}, div);

			if(index%this._visibleIncrement<1 && index%this._visibleIncrement>-1){
				dojo.addClass(div, this.baseClass+"Marker");
			}else if(!(index%this._clickableIncrement)){
				dojo.addClass(div, this.baseClass+"Tick");
			}

			if(this.isDisabledDate(date)){
				// set disabled
				dojo.addClass(div, this.baseClass+"ItemDisabled");
			}
			if(!dojo.date.compare(this.value, date, this.constraints.selector)){
				div.selected = true;
				dojo.addClass(div, this.baseClass+"ItemSelected");
				if(dojo.hasClass(div, this.baseClass+"Marker")){
					dojo.addClass(div, this.baseClass+"MarkerSelected");
				}else{
					dojo.addClass(div, this.baseClass+"TickSelected");
				}
			}
			return div;
		},

		_onOptionSelected: function(/*Object*/ tgt){
			// summary:
			//		Called when user clicks an option in the drop down list
			// tags:
			//		private
			var tdate = tgt.target.date || tgt.target.parentNode.date;
			if(!tdate || this.isDisabledDate(tdate)){ return; }
			this._highlighted_option = null;
			this.set('value', tdate);
			this.onValueSelected(tdate);
		},

		onValueSelected: function(/*Date*/ time){
			// summary:
			//		Notification that a time was selected.  It may be the same as the previous value.
			// description:
			//      Used by `dijit.form._DateTimeTextBox` (and thus `dijit.form.TimeTextBox`)
			//      to get notification when the user has clicked a time.
			// tags:
			//      protected
		},


		_highlightOption: function(/*node*/ node, /*Boolean*/ highlight){
			// summary:
			//		Turns on/off hover effect on a node based on mouse out/over event
			// tags:
			//		private
			if(!node){return;}
			if(highlight){
				if(this._highlighted_option){
					this._highlightOption(this._highlighted_option, false);
				}
				this._highlighted_option = node;
			}else if(this._highlighted_option !== node){
				return;
			}else{
				this._highlighted_option = null;
			}
			dojo.toggleClass(node, this.baseClass+"ItemHover", highlight);
			if(dojo.hasClass(node, this.baseClass+"Marker")){
				dojo.toggleClass(node, this.baseClass+"MarkerHover", highlight);
			}else{
				dojo.toggleClass(node, this.baseClass+"TickHover", highlight);
			}
		},

		onmouseover: function(/*Event*/ e){
			// summary:
			//		Handler for onmouseover event
			// tags:
			//		private
			this._keyboardSelected = null;
			var tgr = (e.target.parentNode === this.timeMenu) ? e.target : e.target.parentNode;
			// if we aren't targeting an item, then we return
			if(!dojo.hasClass(tgr, this.baseClass+"Item")){return;}
			this._highlightOption(tgr, true);
		},

		onmouseout: function(/*Event*/ e){
			// summary:
			//		Handler for onmouseout event
			// tags:
			//		private
			this._keyboardSelected = null;
			var tgr = (e.target.parentNode === this.timeMenu) ? e.target : e.target.parentNode;
			this._highlightOption(tgr, false);
		},

		_mouseWheeled: function(/*Event*/ e){
			// summary:
			//		Handle the mouse wheel events
			// tags:
			//		private
			this._keyboardSelected = null;
			dojo.stopEvent(e);
			// we're not _measuring_ the scroll amount, just direction
			var scrollAmount = (dojo.isIE ? e.wheelDelta : -e.detail);
			this[(scrollAmount>0 ? "_onArrowUp" : "_onArrowDown")](); // yes, we're making a new dom node every time you mousewheel, or click
		},

		_onArrowUp: function(count){
			// summary:
			//		Handler for up arrow key.
			// description:
			//		Removes the bottom time and add one to the top
			// tags:
			//		private
			if(typeof count == "number" && count == -1){ return; } // typematic end
			if(!this.timeMenu.childNodes.length){ return; }
			var index = this.timeMenu.childNodes[0].index;
			var divs = this._getFilteredNodes(index, 1, true);
			if(divs.length){
				this.timeMenu.removeChild(this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1]);
				this.timeMenu.insertBefore(divs[0], this.timeMenu.childNodes[0]);
			}
		},

		_onArrowDown: function(count){
			// summary:
			//		Handler for up arrow key.
			// description:
			//		Remove the top time and add one to the bottom
			// tags:
			//		private
			if(typeof count == "number" && count == -1){ return; } // typematic end
			if(!this.timeMenu.childNodes.length){ return; }
			var index = this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1].index + 1;
			var divs = this._getFilteredNodes(index, 1, false);
			if(divs.length){
				this.timeMenu.removeChild(this.timeMenu.childNodes[0]);
				this.timeMenu.appendChild(divs[0]);
			}
		},

		handleKey: function(/*Event*/ e){
			// summary:
			//		Called from `dijit.form._DateTimeTextBox` to pass a keypress event
			//		from the `dijit.form.TimeTextBox` to be handled in this widget
			// tags:
			//		protected
			var dk = dojo.keys;
			if(e.keyChar || e.charOrCode === dk.BACKSPACE || e.charOrCode == dk.DELETE){
				// Set a timeout to kick off our filter
				setTimeout(dojo.hitch(this, function(){
					this._filterString = e.target.value.toLowerCase();
					this._showText();
				}),1);
			}else if(e.charOrCode == dk.DOWN_ARROW || e.charOrCode == dk.UP_ARROW){
				dojo.stopEvent(e);
				// Figure out which option to highlight now and then highlight it
				if(this._highlighted_option && !this._highlighted_option.parentNode){
					this._highlighted_option = null;
				}
				var timeMenu = this.timeMenu,
					tgt = this._highlighted_option || dojo.query("." + this.baseClass + "ItemSelected", timeMenu)[0];
				if(!tgt){
					tgt = timeMenu.childNodes[0];
				}else if(timeMenu.childNodes.length){
					if(e.charOrCode == dk.DOWN_ARROW && !tgt.nextSibling){
						this._onArrowDown();
					}else if(e.charOrCode == dk.UP_ARROW && !tgt.previousSibling){
						this._onArrowUp();
					}
					if(e.charOrCode == dk.DOWN_ARROW){
						tgt = tgt.nextSibling;
					}else{
						tgt = tgt.previousSibling;
					}
				}
				this._highlightOption(tgt, true);
				this._keyboardSelected = tgt;
			}else if(this._highlighted_option && (e.charOrCode == dk.ENTER || e.charOrCode === dk.TAB)){
				// Accept the currently-highlighted option as the value
				if(!this._keyboardSelected && e.charOrCode === dk.TAB){ return; } // mouse hover followed by TAB is NO selection
				if(e.charOrCode == dk.ENTER){dojo.stopEvent(e);}
				this._onOptionSelected({target: this._highlighted_option});
			}
		}
	}
);


}

if(!dojo._hasResource["dijit.form.TimeTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.TimeTextBox"] = true;
dojo.provide("dijit.form.TimeTextBox");




/*=====
dojo.declare(
	"dijit.form.TimeTextBox.__Constraints",
	[dijit.form._DateTimeTextBox.__Constraints, dijit._TimePicker.__Constraints]
);
=====*/

dojo.declare(
	"dijit.form.TimeTextBox",
	dijit.form._DateTimeTextBox,
	{
		// summary:
		//		A validating, serializable, range-bound time text box with a drop down time picker

		baseClass: "dijitTextBox dijitTimeTextBox",
		popupClass: "dijit._TimePicker",
		_selector: "time",

/*=====
		// constraints: dijit.form.TimeTextBox.__Constraints
		constraints:{},
=====*/

		// value: Date
		//		The value of this widget as a JavaScript Date object.  Note that the date portion implies time zone and daylight savings rules.
		//
		//		Example:
		// |	new dijit.form.TimeTextBox({value: dojo.date.stamp.fromISOString("T12:59:59", new Date())})
		//
		//		When passed to the parser in markup, must be specified according to locale-independent
		//		`dojo.date.stamp.fromISOString` format.
		//
		//		Example:
		// |	<input dojotype='dijit.form.TimeTextBox' value='T12:34:00'>
		value: new Date("")		// value.toString()="NaN"
		//FIXME: in markup, you have no control over daylight savings
	}
);

}

if(!dojo._hasResource["com.sixnet.services.widgets.dateTime"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.dateTime"] = true;
dojo.provide("com.sixnet.services.widgets.dateTime");






//
/*
 * Idea is no data inside...
 * parent: container of sorts, i.e. dialog, contentPane...
 */
dojo.declare('com.sixnet.services.widgets.dateTime',[dijit.form._FormValueWidget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div class=\"dijit dijitInline dijitLeft dateTimeWidget\">\n\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"focusNode,dateHolder\" style=\"float:left; width:16em;\"></div>   \n\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"timeHolder\" style=\"float:left;\"></div>\n\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"AMPM\" style=\"width:30px; float:left; font-weight:bold; margin-left:5px; color:#999\"></div>\n</div>\n",
	allValues:false,
	actualValues:false,
	addValue:false,
	disabled:false,
	removeValue:false,
	parent:false,
	epoch:null,
    storedDate:false,
    storedTime:false,
    _lastValue: null,
    
    postCreate: function(){
    	this.inherited("postCreate", arguments);
        this.epoch = 0;
        this._lastValue = this.epoch;
    	this.makeCalendar(dojo.hitch(this, "makeTimeTextBox"));
        this.setEpoch();
    },
    
	makeCalendar: function(onComplete){
		var parent = this;
		this.timeSettingsDate = new dijit.form.DateTextBox({
			promptMessage:"mm/dd/yyyy",
			constraints:{datePattern:'MM/dd/yyyy', strict:true},
			invalidMessage:"Invalid date. Use mm/dd/yyyy format.",
			onChange:function(){
				parent.setEpoch();	
			}
		}).placeAt(dojo.byId(this.dateHolder.domNode, "last"));
		this.timeSettingsDate.startup();
		var date = new Date();
		if(this.storedDate > 0){
			date = new Date(this.storedDate);
		}
		this.timeSettingsDate.attr("value", date);
		onComplete();
	},
	
	makeTimeTextBox: function(){
		var parent = this;
		this.timeSettingsTime = new dijit.form.TimeTextBox({
			constraints:{timePattern:'HH:mm:ss', clickableIncrement:'T00:15:00', visibleIncrement:'T00:15:00', visibleRange:'T01:00:00'},
			required:"true",
			onChange:function(){
				var date = new Date(arguments[0]);
				parent.setAMPM(date.getHours());
				parent.setEpoch();
			},
			invalidMessage:"Invalid time. Use HH:MM:SS where HH is 00 - 23 hours."
		}).placeAt(dojo.byId(this.timeHolder.domNode, "last"));
		this.timeSettingsTime.startup();
		var date = new Date();
		if(this.storedTime > 0){
			date = new Date(this.storedTime);
		}
		this.timeSettingsTime.attr("value", date);
		this.setAMPM(this.timeSettingsTime.value.getHours());
		//_sixnet_framework.log(1, this.timeSettingsTime, this.timeSettingsTime.value, "  << timeSettingsTime");
	},
	
	setAMPM: function(hour){
		var ampm = "";
		if(hour < 12){
			ampm = "am";
		}else{
			ampm = "pm";
		}
		this.AMPM.attr("content", ampm);
	},
	getValue: function(){
		return this._lastValue;
	},
	setEpoch: function(){
		var tsDate = ''.concat(this.timeSettingsDate.value).split(" ");
		var tsTime = ''.concat(this.timeSettingsTime.value).split(" ");
		var formattedTimestamp = ''.concat(tsDate[1]+" ").concat(tsDate[2]+", ").concat(tsDate[3]+" ").concat(tsTime[4]);
		var jsDate = new Date(formattedTimestamp);
		_sixnet_framework.log(1, "formattedTimestamp: ", formattedTimestamp, "   jsDate:  ", typeof(jsDate), "  getTime/1000:  ", typeof(jsDate.getTime()/1000));
		this.epoch = Math.round(jsDate.getTime()/1000); // round added just to see if
		// IE will register as number.
		this._lastValue = this.epoch;
		_sixnet_framework.log(1, "Epoch: ", Number(this.epoch), "  typeof:  ", typeof(this.epoch));
	}
});

}

if(!dojo._hasResource["dijit.form.DropDownButton"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.DropDownButton"] = true;
dojo.provide("dijit.form.DropDownButton");



}

if(!dojo._hasResource['com.sixnet.services.widgets.sixnetToolbar']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.sixnetToolbar'] = true;
dojo.provide('com.sixnet.services.widgets.sixnetToolbar');
//










/*
 * sixnetToolbar: serves a a generalized toolbar for
 * use in conjunction with sixnetGrid.
 * 
 * expects:
 * grid == DataGrid or sixnetGrid.grid
 * store
 * 
 * dojoAttachPoint connects:
 * addButton
 * removeButton
 *  * ----viewDD (for toolbarDD attachPoint)
 *  
 * built-in handling of:
 * discardChangesButton (this.grid.store.revert())
 * saveChangesButton (this.grid.store.save())
 * searchBox
 * searchButton
 * cancelSearchButton
 * 
 * args:
 * {
	grid: Obj
	store: Obj
 * }
 */
dojo.declare('com.sixnet.services.widgets.sixnetToolbar', [dijit._Widget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\t\n\t<div dojoTyp=\"dijit.layout.ContentPane\" style=\"height:28px; width:100%\">\n\t\t<div dojoType=\"dijit.Toolbar\" style=\"height:28px; width:100%\" dojoAttachPoint=\"toolbar\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"margin-top:3px;height:23px; float:left; overflow:hidden; clear:none\" dojoAttachPoint=\"searchColumns\" >\n\t\t\t\t<div style=\"float:left; font-size:1.1em; width:10em; margin-top:3px;margin-left:5px;\" dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"searchBox\"></div>\n\t\t\t</div>\n\t\t\t<div style=\"float:left\" dojoType=\"com.sixnet.services.widgets.HintButton\" hint=\"Search\" dojoAttachPoint=\"searchButton\" dojoAttachEvent=\"onClick:onSearchClick\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"dojo/com/sixnet/services/widgets/templates/images/find.png\"></div>\n\t\t\t<div class=\"notMini\" style=\"float:left\" dojoType=\"com.sixnet.services.widgets.HintButton\" hint=\"Clear Search\" dojoAttachPoint=\"cancelSearchButton\" dojoAttachEvent=\"onClick:onCancelSearchClick\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"dojo/com/sixnet/services/widgets/templates/images/cancelFind.png\"></div>\n\t\t\t\n\t\t\t<div style=\"margin-top:3px;height:23px; float:left; overflow:hidden; clear:none\" dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"viewDD\"></div>\n\t\t\t<div style=\"margin-top:3px;height:23px; float:left; overflow:hidden; clear:none\" dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"extras\"></div>\n\t\t\t  \n\t\t\t<div style=\"float:right; margin-right:15px; height:23px; width:90px; background:url(/dojo/com/sixnet/services/widgets/templates/images/toAdvanced.png) no-repeat; cursor:pointer\" dojoType=\"com.sixnet.services.widgets.HintButton\" dojoAttachPoint=\"basicToAdvancedButton\"></div>\n\t\t\t\t\t\t\n\t\t\t<div style=\"float:right; margin-right:15px\" class=\"editButtons notMini\" dojoType=\"com.sixnet.services.widgets.HintButton\" hint=\"Discard changes\" dojoAttachEvent=\"onClick:onCancelChangesClick\"  dojoAttachPoint=\"discardChangesButton\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"dojo/com/sixnet/services/widgets/templates/images/delete.png\"></div>\n\t\t\t<div style=\"float:right\" class=\"editButtons notMini\" dojoType=\"com.sixnet.services.widgets.HintButton\" hint=\"Save changes\" dojoAttachEvent=\"onClick:onSaveChangesClick\" dojoAttachPoint=\"saveChangesButton\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"dojo/com/sixnet/services/widgets/templates/images/filesave.png\"></div>\n\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t<div style=\"float:right; margin-right:15px\" class=\"editButtons notMini\" dojoType=\"com.sixnet.services.widgets.HintButton\" hint=\"Add\" dojoAttachPoint=\"addButton\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"dojo/com/sixnet/services/widgets/templates/images/insrow.png\"></div>\n\t\t\t<div style=\"float:right\" class=\"editButtons notMini\" dojoType=\"com.sixnet.services.widgets.HintButton\" hint=\"Remove the selected row\" dojoAttachPoint=\"removeButton\" ><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"dojo/com/sixnet/services/widgets/templates/images/remrow.png\"></div>\n\t\t</div>\n\t</div>\n</div>\n",
	edit: false,
	editRole: [],
	grid: {},
	module: '',
	mini: false,
	store: {},
	needsSaved: false,
	searchField: '',
	view: false,
	viewRole: '',
	currentPermissions: {},
	anims:[],
	currentAnimation:false,
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		_sixnet_framework.log(3, "SIXNET SUPER: ", _sixnet_framework._super);
		if(!_sixnet_framework._super){
			// user is not super, filter necessary
			this.restrictToolbar();
		}else{
			this.dimEditButtons();
		}
		if(this.mini){
			var miniList = dojo.query(".notMini", this.domNode);
			dojo.forEach(miniList, function(node){
				node.style.display = 'none';
			});
		}
		this.connect(this.searchBox, "onKeyUp", "onSearchKeyUp");
		this.connect(this.searchBox, "onChange", "onSearchKeyUp");
//		this.connect(this.toolbarLarge, "onClick", "expandToolbar");
//		this.connect(this.toolbarSmall, "onClick", "shrinkToolbar");
//
//		this.domNode.style.display = 'none';
//		this.advancedToolbar.domNode.style.display = "block";
//		this.stackContainer.startup();
//		this.stackContainer.selectChild(this.toolbarHolder.domNode);
	},

	/* ============== sixnetToolbar functions [a-z] ================ */
	
	expandToolbar: function(){
//		_sixnet_framework.log(1, this.stackContainer);
//		this.stackContainer.forward();
//		dojo.query(dojo.byId('stackContainer')).forward();
//	    &lt;
//	</button>
//	<span dojoType="dijit.layout.StackController" containerId="stackContainer">
//	</span>
//	<button id="next" onClick="dijit.byId('stackContainer').forward()" dojoType="dijit.form.Button">
//	    &gt;
//	</button>
//		this.domNode.style.height = "90";
////		dojo.removeClass(this.toolbar.domNode, "dijitToolbar");
////		dojo.addClass(this.toolbar.domNode, "dijitToolbarExpanded");
//		
//		// tundra dijitToolbar - add repeat y;
////		dojo.attr(this.toolbarContainer, {style:'height:58px'});
////		dojo.attr(this.toolbar, {style:'height:58px'});
//		dojo.style(this.toolbarHolder, "height", "90");
//		dojo.style(this.toolbar.domNode, "backgroundRepeat", "repeat");
//		_sixnet_framework.log(1, dojo.style(this.toolbar.domNode, "backgroundImage"), dojo.style(this.toolbar.domNode, "backgroundRepeat"));
//		dojo.style(this.toolbar.domNode, "height", "90");
//		dojo.attr(this.toolbar, {style:"height:90px"});
//		this.toolbar.params.style = "height:90px";
////		dojo.style(this.domNode.parentNode, "height", "90");
////		dojo.style(this.domNode.parentNode.parentNode.parentNode, "height", "90");
////		_sixnet_framework.log(1, "in expand", dojo.query(this.domNode.parentNode.parentNode), _sixnet_framework);
//		_sixnet_framework.log(1, this.toolbarHolder, this.toolbar);
//		this.dashBoard.resize();
//		this.toolbar.domNode.resize();
//		this.grid.domNode.resize();
//		var gridHeight = this.grid.height.split("px");
//		_sixnet_framework.log(1, gridHeight);
//		var newGridHeight = (gridHeight[0] - 90);
//		this.grid.style = "height:".concat(newGridHeight).concat("px");
//		dojo.style(this.grid, "height", newGridHeight);
//		this.anims.push(
//			dojox.fx.wipeTo(dojo.mixin({ node:this.toolbarHolder.domNode, delay:(delay+=200)}, {height: 90}))
//		);
//		this.currentAnimation = dojo.fx.combine(this.anims);
//		this.currentAnimation.play();

	},
	
	shrinkToolbar: function(){
//		dojo.attr(this.toolbarContainer, {style:'height:28px'});
//		dojo.attr(this.toolbar, {height:'28px'});
		this.myStackContainer.forward();
	},
	
	restrictToolbar: function(){
		/*  TESTING THIS AND NOT SEEING RESULTS??? MAKE SURE YOU AREN'T SUPER! */
		var currentPermissions = dojo.clone(_sixnet_framework._currentPermissions);
//		var rolesArray = new Array();
		currentPermissions = {
				ROLES:[
				       dojo.clone(_sixnet_framework._currentPermissions)
		]};
//		currentPermissions["ROLES"][0][this.module]
		//  here we just need the roles for said module
		for(var j=0; j<currentPermissions["ROLES"].length; j++){
			_sixnet_framework.log(3, currentPermissions["ROLES"][j][this.module], currentPermissions["ROLES"][j][this.module], " roles dude");
			//  access module
			for(role in currentPermissions["ROLES"][j][this.module]){
				_sixnet_framework.log(3, "role:  ", role, "length: ", this.editRole.length);
				//  build an indicator and/or call functions from switch per role

				//  editRole is Array, so we have to loop thru to compare to all of it
				for(var i = 0; i < this.editRole.length; i++){
					_sixnet_framework.log(3, this.editRole[i], " <<<  >>> ", role);
					if(this.editRole[i] == role){
						//  has toolbar edit role
						this.edit = true;
					}
//					if(this.viewRole == role){
//						//  has toolbar view role
//						this.view = true;
//					}
				}
			}
			if(!this.edit/* && this.view*/){
				_sixnet_framework.log(3, "edit: false");
				//  hide edit controls: +/- save/revert
				dojo.addClass( this.addButton.focusNode, "hidden");
				dojo.addClass( this.removeButton.focusNode, "hidden");
				dojo.addClass( this.saveChangesButton.focusNode, "hidden");
				dojo.addClass( this.discardChangesButton.focusNode, "hidden");
			}else if(this.edit){
				_sixnet_framework.log(3, "edit: true");
				this.dimEditButtons();
			}
		}
	},
	
	dimEditButtons: function(){
		//  dim/deactive for now the remove, save, and revert buttons
		dojo.addClass( this.removeButton.focusNode, "disabledButton");
		dojo.addClass( this.saveChangesButton.focusNode, "disabledButton");
		dojo.addClass( this.discardChangesButton.focusNode, "disabledButton");
	},
	
	hideSaveRevertButton: function(){
		dojo.addClass( this.saveChangesButton.focusNode, "disabledButton");
		dojo.addClass( this.discardChangesButton.focusNode, "disabledButton");
		this.needsSaved = false;	
	},
	
	onSaveChangesClick: function(){
		//  saves store.
		this.store.save();
		this.hideSaveRevertButton();
	},
	
	onCancelChangesClick: function(){
		//  reverts any unsaved changes on store.
		this.store.revert();
		this.hideSaveRevertButton();
	},
	
	onSearchKeyUp: function(event){
		// emulate a click on the search button when the user hits enter in the search box.
		if( event.keyCode == 13){
			this.onSearchClick();
		}
	},
	
	onCancelSearchClick: function(){
		this.searchBox.setValue('');
		this.grid.setQuery({});
	},
	
	onSearchClick: function(){
		
	},
	
	unhideSaveRevertButton: function(){
		if( dojo.hasClass( this.saveChangesButton.focusNode, "disabledButton")){
			dojo.removeClass( this.saveChangesButton.focusNode, "disabledButton");
		}
		if( dojo.hasClass( this.discardChangesButton.focusNode, "disabledButton")){
			dojo.removeClass( this.discardChangesButton.focusNode, "disabledButton");
		}
		this.needsSaved = true;
		return;
	}
});

}

if(!dojo._hasResource["dijit.form._FormSelectWidget"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form._FormSelectWidget"] = true;
dojo.provide("dijit.form._FormSelectWidget");




/*=====
dijit.form.__SelectOption = function(){
	// value: String
	//		The value of the option.  Setting to empty (or missing) will
	//		place a separator at that location
	// label: String
	//		The label for our option.  It can contain html tags.
	//  selected: Boolean
	//		Whether or not we are a selected option
	// disabled: Boolean
	//		Whether or not this specific option is disabled
	this.value = value;
	this.label = label;
	this.selected = selected;
	this.disabled = disabled;
}
=====*/

dojo.declare("dijit.form._FormSelectWidget", dijit.form._FormValueWidget, {
	// summary:
	//		Extends _FormValueWidget in order to provide "select-specific"
	//		values - i.e., those values that are unique to <select> elements.
	//		This also provides the mechanism for reading the elements from
	//		a store, if desired.

	// multiple: Boolean
	//		Whether or not we are multi-valued
	multiple: false,

	// options: dijit.form.__SelectOption[]
	//		The set of options for our select item.  Roughly corresponds to
	//      the html <option> tag.
	options: null,

	// store: dojo.data.api.Identity
	//		A store which, at the very least impelements dojo.data.api.Identity
	//		to use for getting our list of options - rather than reading them
	//		from the <option> html tags.
	store: null,

	// query: object
	//		A query to use when fetching items from our store
	query: null,

	// queryOptions: object
	//		Query options to use when fetching from the store
	queryOptions: null,

	// onFetch: Function
	//		A callback to do with an onFetch - but before any items are actually
	//		iterated over (i.e. to filter even futher what you want to add)
	onFetch: null,

	// sortByLabel: boolean
	//		Flag to sort the options returned from a store by the label of
	//		the store.
	sortByLabel: true,


	// loadChildrenOnOpen: boolean
	//		By default loadChildren is called when the items are fetched from the
	//		store.  This property allows delaying loadChildren (and the creation
	//		of the options/menuitems) until the user opens the click the button.
	//		dropdown
	loadChildrenOnOpen: false,

	getOptions: function(/* anything */ valueOrIdx){
		// summary:
		//		Returns a given option (or options).
		// valueOrIdx:
		//		If passed in as a string, that string is used to look up the option
		//		in the array of options - based on the value property.
		//		(See dijit.form.__SelectOption).
		//
		//		If passed in a number, then the option with the given index (0-based)
		//		within this select will be returned.
		//
		//		If passed in a dijit.form.__SelectOption, the same option will be
		//		returned if and only if it exists within this select.
		//
		//		If passed an array, then an array will be returned with each element
		//		in the array being looked up.
		//
		//		If not passed a value, then all options will be returned
		//
		// returns:
		//		The option corresponding with the given value or index.  null
		//		is returned if any of the following are true:
		//			- A string value is passed in which doesn't exist
		//			- An index is passed in which is outside the bounds of the array of options
		//			- A dijit.form.__SelectOption is passed in which is not a part of the select

		// NOTE: the compare for passing in a dijit.form.__SelectOption checks
		//		if the value property matches - NOT if the exact option exists
		// NOTE: if passing in an array, null elements will be placed in the returned
		//		array when a value is not found.
		var lookupValue = valueOrIdx, opts = this.options || [], l = opts.length;

		if(lookupValue === undefined){
			return opts; // dijit.form.__SelectOption[]
		}
		if(dojo.isArray(lookupValue)){
			return dojo.map(lookupValue, "return this.getOptions(item);", this); // dijit.form.__SelectOption[]
		}
		if(dojo.isObject(valueOrIdx)){
			// We were passed an option - so see if it's in our array (directly),
			// and if it's not, try and find it by value.
			if(!dojo.some(this.options, function(o, idx){
				if(o === lookupValue ||
					(o.value && o.value === lookupValue.value)){
					lookupValue = idx;
					return true;
				}
				return false;
			})){
				lookupValue = -1;
			}
		}
		if(typeof lookupValue == "string"){
			for(var i=0; i<l; i++){
				if(opts[i].value === lookupValue){
					lookupValue = i;
					break;
				}
			}
		}
		if(typeof lookupValue == "number" && lookupValue >= 0 && lookupValue < l){
			return this.options[lookupValue] // dijit.form.__SelectOption
		}
		return null; // null
	},

	addOption: function(/* dijit.form.__SelectOption, dijit.form.__SelectOption[] */ option){
		// summary:
		//		Adds an option or options to the end of the select.  If value
		//		of the option is empty or missing, a separator is created instead.
		//		Passing in an array of options will yield slightly better performance
		//		since the children are only loaded once.
		if(!dojo.isArray(option)){ option = [option]; }
		dojo.forEach(option, function(i){
			if(i && dojo.isObject(i)){
				this.options.push(i);
			}
		}, this);
		this._loadChildren();
	},

	removeOption: function(/* string, dijit.form.__SelectOption, number, or array */ valueOrIdx){
		// summary:
		//		Removes the given option or options.  You can remove by string
		//		(in which case the value is removed), number (in which case the
		//		index in the options array is removed), or select option (in
		//		which case, the select option with a matching value is removed).
		//		You can also pass in an array of those values for a slightly
		//		better performance since the children are only loaded once.
		if(!dojo.isArray(valueOrIdx)){ valueOrIdx = [valueOrIdx]; }
		var oldOpts = this.getOptions(valueOrIdx);
		dojo.forEach(oldOpts, function(i){
			// We can get null back in our array - if our option was not found.  In
			// that case, we don't want to blow up...
			if(i){
				this.options = dojo.filter(this.options, function(node, idx){
					return (node.value !== i.value);
				});
				this._removeOptionItem(i);
			}
		}, this);
		this._loadChildren();
	},

	updateOption: function(/* dijit.form.__SelectOption, dijit.form.__SelectOption[] */ newOption){
		// summary:
		//		Updates the values of the given option.  The option to update
		//		is matched based on the value of the entered option.  Passing
		//		in an array of new options will yeild better performance since
		//		the children will only be loaded once.
		if(!dojo.isArray(newOption)){ newOption = [newOption]; }
		dojo.forEach(newOption, function(i){
			var oldOpt = this.getOptions(i), k;
			if(oldOpt){
				for(k in i){ oldOpt[k] = i[k]; }
			}
		}, this);
		this._loadChildren();
	},

	setStore: function(/* dojo.data.api.Identity */ store,
						/* anything? */ selectedValue,
						/* Object? */ fetchArgs){
		// summary:
		//		Sets the store you would like to use with this select widget.
		//		The selected value is the value of the new store to set.  This
		//		function returns the original store, in case you want to reuse
		//		it or something.
		// store: dojo.data.api.Identity
		//		The store you would like to use - it MUST implement Identity,
		//		and MAY implement Notification.
		// selectedValue: anything?
		//		The value that this widget should set itself to *after* the store
		//		has been loaded
		// fetchArgs: Object?
		//		The arguments that will be passed to the store's fetch() function
		var oStore = this.store;
		fetchArgs = fetchArgs || {};
		if(oStore !== store){
			// Our store has changed, so update our notifications
			dojo.forEach(this._notifyConnections || [], dojo.disconnect);
			delete this._notifyConnections;
			if(store && store.getFeatures()["dojo.data.api.Notification"]){
				this._notifyConnections = [
					dojo.connect(store, "onNew", this, "_onNewItem"),
					dojo.connect(store, "onDelete", this, "_onDeleteItem"),
					dojo.connect(store, "onSet", this, "_onSetItem")
				];
			}
			this.store = store;
		}

		// Turn off change notifications while we make all these changes
		this._onChangeActive = false;

		// Remove existing options (if there are any)
		if(this.options && this.options.length){
			this.removeOption(this.options);
		}

		// Add our new options
		if(store){
			var cb = function(items){
				if(this.sortByLabel && !fetchArgs.sort && items.length){
					items.sort(dojo.data.util.sorter.createSortFunction([{
						attribute: store.getLabelAttributes(items[0])[0]
					}], store));
				}

				if(fetchArgs.onFetch){
					items = fetchArgs.onFetch(items);
				}
				// TODO: Add these guys as a batch, instead of separately
				dojo.forEach(items, function(i){
					this._addOptionForItem(i);
				}, this);

				// Set our value (which might be undefined), and then tweak
				// it to send a change event with the real value
				this._loadingStore = false;
				this.set("value", (("_pendingValue" in this) ? this._pendingValue : selectedValue));
				delete this._pendingValue;

				if(!this.loadChildrenOnOpen){
					this._loadChildren();
				}else{
					this._pseudoLoadChildren(items);
				}
				this._fetchedWith = opts;
				this._lastValueReported = this.multiple ? [] : null;
				this._onChangeActive = true;
				this.onSetStore();
				this._handleOnChange(this.value);
			};
			var opts = dojo.mixin({onComplete:cb, scope: this}, fetchArgs);
			this._loadingStore = true;
			store.fetch(opts);
		}else{
			delete this._fetchedWith;
		}
		return oStore;	// dojo.data.api.Identity
	},

	_setValueAttr: function(/*anything*/ newValue, /*Boolean, optional*/ priorityChange){
		// summary:
		//		set the value of the widget.
		//		If a string is passed, then we set our value from looking it up.
		if(this._loadingStore){
			// Our store is loading - so save our value, and we'll set it when
			// we're done
			this._pendingValue = newValue;
			return;
		}
		var opts = this.getOptions() || [];
		if(!dojo.isArray(newValue)){
			newValue = [newValue];
		}
		dojo.forEach(newValue, function(i, idx){
			if(!dojo.isObject(i)){
				i = i + "";
			}
			if(typeof i === "string"){
				newValue[idx] = dojo.filter(opts, function(node){
					return node.value === i;
				})[0] || {value: "", label: ""};
			}
		}, this);

		// Make sure some sane default is set
		newValue = dojo.filter(newValue, function(i){ return i && i.value; });
		if(!this.multiple && (!newValue[0] || !newValue[0].value) && opts.length){
			newValue[0] = opts[0];
		}
		dojo.forEach(opts, function(i){
			i.selected = dojo.some(newValue, function(v){ return v.value === i.value; });
		});
		var val = dojo.map(newValue, function(i){ return i.value; }),
			disp = dojo.map(newValue, function(i){ return i.label; });

		this.value = this.multiple ? val : val[0];
		this._setDisplay(this.multiple ? disp : disp[0]);
		this._updateSelection();
		this._handleOnChange(this.value, priorityChange);
	},

	_getDisplayedValueAttr: function(){
		// summary:
		//		returns the displayed value of the widget
		var val = this.get("value");
		if(!dojo.isArray(val)){
			val = [val];
		}
		var ret = dojo.map(this.getOptions(val), function(v){
			if(v && "label" in v){
				return v.label;
			}else if(v){
				return v.value;
			}
			return null;
		}, this);
		return this.multiple ? ret : ret[0];
	},

	_getValueDeprecated: false, // remove when _FormWidget:getValue is removed
	getValue: function(){
		// summary:
		//		get the value of the widget.
		return this._lastValue;
	},

	undo: function(){
		// summary:
		//		restore the value to the last value passed to onChange
		this._setValueAttr(this._lastValueReported, false);
	},

	_loadChildren: function(){
		// summary:
		//		Loads the children represented by this widget's options.
		//		reset the menu to make it "populatable on the next click
		if(this._loadingStore){ return; }
		dojo.forEach(this._getChildren(), function(child){
			child.destroyRecursive();
		});
		// Add each menu item
		dojo.forEach(this.options, this._addOptionItem, this);

		// Update states
		this._updateSelection();
	},

	_updateSelection: function(){
		// summary:
		//		Sets the "selected" class on the item for styling purposes
		this.value = this._getValueFromOpts();
		var val = this.value;
		if(!dojo.isArray(val)){
			val = [val];
		}
		if(val && val[0]){
			dojo.forEach(this._getChildren(), function(child){
				var isSelected = dojo.some(val, function(v){
					return child.option && (v === child.option.value);
				});
				dojo.toggleClass(child.domNode, this.baseClass + "SelectedOption", isSelected);
				dijit.setWaiState(child.domNode, "selected", isSelected);
			}, this);
		}
		this._handleOnChange(this.value);
	},

	_getValueFromOpts: function(){
		// summary:
		//		Returns the value of the widget by reading the options for
		//		the selected flag
		var opts = this.getOptions() || [];
		if(!this.multiple && opts.length){
			// Mirror what a select does - choose the first one
			var opt = dojo.filter(opts, function(i){
				return i.selected;
			})[0];
			if(opt && opt.value){
				return opt.value
			}else{
				opts[0].selected = true;
				return opts[0].value;
			}
		}else if(this.multiple){
			// Set value to be the sum of all selected
			return dojo.map(dojo.filter(opts, function(i){
				return i.selected;
			}), function(i){
				return i.value;
			}) || [];
		}
		return "";
	},

	// Internal functions to call when we have store notifications come in
	_onNewItem: function(/* item */ item, /* Object? */ parentInfo){
		if(!parentInfo || !parentInfo.parent){
			// Only add it if we are top-level
			this._addOptionForItem(item);
		}
	},
	_onDeleteItem: function(/* item */ item){
		var store = this.store;
		this.removeOption(store.getIdentity(item));
	},
	_onSetItem: function(/* item */ item){
		this.updateOption(this._getOptionObjForItem(item));
	},

	_getOptionObjForItem: function(item){
		// summary:
		//		Returns an option object based off the given item.  The "value"
		//		of the option item will be the identity of the item, the "label"
		//		of the option will be the label of the item.  If the item contains
		//		children, the children value of the item will be set
		var store = this.store, label = store.getLabel(item),
			value = (label ? store.getIdentity(item) : null);
		return {value: value, label: label, item:item}; // dijit.form.__SelectOption
	},

	_addOptionForItem: function(/* item */ item){
		// summary:
		//		Creates (and adds) the option for the given item
		var store = this.store;
		if(!store.isItemLoaded(item)){
			// We are not loaded - so let's load it and add later
			store.loadItem({item: item, onComplete: function(i){
				this._addOptionForItem(item);
			},
			scope: this});
			return;
		}
		var newOpt = this._getOptionObjForItem(item);
		this.addOption(newOpt);
	},

	constructor: function(/* Object */ keywordArgs){
		// summary:
		//		Saves off our value, if we have an initial one set so we
		//		can use it if we have a store as well (see startup())
		this._oValue = (keywordArgs || {}).value || null;
	},

	_fillContent: function(){
		// summary:
		//		Loads our options and sets up our dropdown correctly.  We
		//		don't want any content, so we don't call any inherit chain
		//		function.
		var opts = this.options;
		if(!opts){
			opts = this.options = this.srcNodeRef ? dojo.query(">",
						this.srcNodeRef).map(function(node){
							if(node.getAttribute("type") === "separator"){
								return { value: "", label: "", selected: false, disabled: false };
							}
							return { value: node.getAttribute("value"),
										label: String(node.innerHTML),
										selected: node.getAttribute("selected") || false,
										disabled: node.getAttribute("disabled") || false };
						}, this) : [];
		}
		if(!this.value){
			this.value = this._getValueFromOpts();
		}else if(this.multiple && typeof this.value == "string"){
			this.value = this.value.split(",");
		}
	},

	postCreate: function(){
		// summary:
		//		sets up our event handling that we need for functioning
		//		as a select
		dojo.setSelectable(this.focusNode, false);
		this.inherited(arguments);

		// Make our event connections for updating state
		this.connect(this, "onChange", "_updateSelection");
		this.connect(this, "startup", "_loadChildren");

		this._setValueAttr(this.value, null);
	},

	startup: function(){
		// summary:
		//		Connects in our store, if we have one defined
		this.inherited(arguments);
		var store = this.store, fetchArgs = {};
		dojo.forEach(["query", "queryOptions", "onFetch"], function(i){
			if(this[i]){
				fetchArgs[i] = this[i];
			}
			delete this[i];
		}, this);
		if(store && store.getFeatures()["dojo.data.api.Identity"]){
			// Temporarily set our store to null so that it will get set
			// and connected appropriately
			this.store = null;
			this.setStore(store, this._oValue, fetchArgs);
		}
	},

	destroy: function(){
		// summary:
		//		Clean up our connections
		dojo.forEach(this._notifyConnections || [], dojo.disconnect);
		this.inherited(arguments);
	},

	_addOptionItem: function(/* dijit.form.__SelectOption */ option){
		// summary:
		//		User-overridable function which, for the given option, adds an
		//		item to the select.  If the option doesn't have a value, then a
		//		separator is added in that place.  Make sure to store the option
		//		in the created option widget.
	},

	_removeOptionItem: function(/* dijit.form.__SelectOption */ option){
		// summary:
		//		User-overridable function which, for the given option, removes
		//		its item from the select.
	},

	_setDisplay: function(/*String or String[]*/ newDisplay){
		// summary:
		//		Overridable function which will set the display for the
		//		widget.  newDisplay is either a string (in the case of
		//		single selects) or array of strings (in the case of multi-selects)
	},

	_getChildren: function(){
		// summary:
		//		Overridable function to return the children that this widget contains.
		return [];
	},

	_getSelectedOptionsAttr: function(){
		// summary:
		//		hooks into this.attr to provide a mechanism for getting the
		//		option items for the current value of the widget.
		return this.getOptions(this.get("value"));
	},

	_pseudoLoadChildren: function(/* item[] */ items){
		// summary:
		//		a function that will "fake" loading children, if needed, and
		//		if we have set to not load children until the widget opens.
		// items:
		//		An array of items that will be loaded, when needed
	},

	onSetStore: function(){
		// summary:
		//		a function that can be connected to in order to receive a
		//		notification that the store has finished loading and all options
		//		from that store are available
	}
});

}

if(!dojo._hasResource["dijit.form.Select"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.Select"] = true;
dojo.provide("dijit.form.Select");








dojo.declare("dijit.form._SelectMenu", dijit.Menu, {
	// summary:
	//		An internally-used menu for dropdown that allows us a vertical scrollbar
	buildRendering: function(){
		// summary:
		//		Stub in our own changes, so that our domNode is not a table
		//		otherwise, we won't respond correctly to heights/overflows
		this.inherited(arguments);
		var o = (this.menuTableNode = this.domNode);
		var n = (this.domNode = dojo.create("div", {style: {overflowX: "hidden", overflowY: "scroll"}}));
		if(o.parentNode){
			o.parentNode.replaceChild(n, o);
		}
		dojo.removeClass(o, "dijitMenuTable");
		n.className = o.className + " dijitSelectMenu";
		o.className = "dijitReset dijitMenuTable";
		dijit.setWaiRole(o,"listbox");
		dijit.setWaiRole(n,"presentation");
		n.appendChild(o);
	},
	resize: function(/*Object*/ mb){
		// summary:
		//		Overridden so that we are able to handle resizing our
		//		internal widget.  Note that this is not a "full" resize
		//		implementation - it only works correctly if you pass it a
		//		marginBox.
		//
		// mb: Object
		//		The margin box to set this dropdown to.
		if(mb){
			dojo.marginBox(this.domNode, mb);
			if("w" in mb){
				// We've explicitly set the wrapper <div>'s width, so set <table> width to match.
				// 100% is safer than a pixel value because there may be a scroll bar with
				// browser/OS specific width.
				this.menuTableNode.style.width = "100%";
			}
		}
	}
});

dojo.declare("dijit.form.Select", [dijit.form._FormSelectWidget, dijit._HasDropDown], {
	// summary:
	//		This is a "styleable" select box - it is basically a DropDownButton which
	//		can take a <select> as its input.

	baseClass: "dijitSelect",

	templateString: dojo.cache("dijit.form", "templates/Select.html", "<table class=\"dijit dijitReset dijitInline dijitLeft\"\n\tdojoAttachPoint=\"_buttonNode,tableNode,focusNode\" cellspacing='0' cellpadding='0'\n\twaiRole=\"combobox\" waiState=\"haspopup-true\"\n\t><tbody waiRole=\"presentation\"><tr waiRole=\"presentation\"\n\t\t><td class=\"dijitReset dijitStretch dijitButtonContents dijitButtonNode\" waiRole=\"presentation\"\n\t\t\t><span class=\"dijitReset dijitInline dijitButtonText\"  dojoAttachPoint=\"containerNode,_popupStateNode\"></span\n\t\t\t><input type=\"hidden\" ${!nameAttrSetting} dojoAttachPoint=\"valueNode\" value=\"${value}\" waiState=\"hidden-true\"\n\t\t/></td><td class=\"dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\t\tdojoAttachPoint=\"titleNode\" waiRole=\"presentation\"\n\t\t\t><div class=\"dijitReset dijitArrowButtonInner\" waiRole=\"presentation\"></div\n\t\t\t><div class=\"dijitReset dijitArrowButtonChar\" waiRole=\"presentation\">&#9660;</div\n\t\t></td\n\t></tr></tbody\n></table>\n"),

	// attributeMap: Object
	//		Add in our style to be applied to the focus node
	attributeMap: dojo.mixin(dojo.clone(dijit.form._FormSelectWidget.prototype.attributeMap),{style:"tableNode"}),

	// required: Boolean
	//		Can be true or false, default is false.
	required: false,

	// state: String
	//		Shows current state (ie, validation result) of input (Normal, Warning, or Error)
	state: "",

	//	tooltipPosition: String[]
	//		See description of dijit.Tooltip.defaultPosition for details on this parameter.
	tooltipPosition: [],

	// emptyLabel: string
	//		What to display in an "empty" dropdown
	emptyLabel: "",

	// _isLoaded: Boolean
	//		Whether or not we have been loaded
	_isLoaded: false,

	// _childrenLoaded: Boolean
	//		Whether or not our children have been loaded
	_childrenLoaded: false,

	_fillContent: function(){
		// summary:
		//		Set the value to be the first, or the selected index
		this.inherited(arguments);
		if(this.options.length && !this.value && this.srcNodeRef){
			var si = this.srcNodeRef.selectedIndex;
			this.value = this.options[si != -1 ? si : 0].value;
		}

		// Create the dropDown widget
		this.dropDown = new dijit.form._SelectMenu({id: this.id + "_menu"});
		dojo.addClass(this.dropDown.domNode, this.baseClass + "Menu");
	},

	_getMenuItemForOption: function(/*dijit.form.__SelectOption*/ option){
		// summary:
		//		For the given option, return the menu item that should be
		//		used to display it.  This can be overridden as needed
		if(!option.value){
			// We are a separator (no label set for it)
			return new dijit.MenuSeparator();
		}else{
			// Just a regular menu option
			var click = dojo.hitch(this, "_setValueAttr", option);
			var item = new dijit.MenuItem({
				option: option,
				label: option.label,
				onClick: click,
				disabled: option.disabled || false
			});
			dijit.setWaiRole(item.focusNode, "listitem");
			return item;
		}
	},

	_addOptionItem: function(/*dijit.form.__SelectOption*/ option){
		// summary:
		//		For the given option, add an option to our dropdown.
		//		If the option doesn't have a value, then a separator is added
		//		in that place.
		if(this.dropDown){
			this.dropDown.addChild(this._getMenuItemForOption(option));
		}
	},

	_getChildren: function(){
		if(!this.dropDown){
			return [];
		}
		return this.dropDown.getChildren();
	},

	_loadChildren: function(/*Boolean*/ loadMenuItems){
		// summary:
		//		Resets the menu and the length attribute of the button - and
		//		ensures that the label is appropriately set.
		//	loadMenuItems: Boolean
		//		actually loads the child menu items - we only do this when we are
		//		populating for showing the dropdown.

		if(loadMenuItems === true){
			// this.inherited destroys this.dropDown's child widgets (MenuItems).
			// Avoid this.dropDown (Menu widget) having a pointer to a destroyed widget (which will cause
			// issues later in _setSelected). (see #10296)
			if(this.dropDown){
				delete this.dropDown.focusedChild;
			}
			if(this.options.length){
				this.inherited(arguments);
			}else{
				// Drop down menu is blank but add one blank entry just so something appears on the screen
				// to let users know that they are no choices (mimicing native select behavior)
				dojo.forEach(this._getChildren(), function(child){ child.destroyRecursive(); });
				var item = new dijit.MenuItem({label: "&nbsp;"});
				this.dropDown.addChild(item);
			}
		}else{
			this._updateSelection();
		}

		var len = this.options.length;
		this._isLoaded = false;
		this._childrenLoaded = true;

		if(!this._loadingStore){
			// Don't call this if we are loading - since we will handle it later
			this._setValueAttr(this.value);
		}
	},

	_setValueAttr: function(value){
		this.inherited(arguments);
		dojo.attr(this.valueNode, "value", this.get("value"));
	},

	_setDisplay: function(/*String*/ newDisplay){
		// summary:
		//		sets the display for the given value (or values)
		this.containerNode.innerHTML = '<span class="dijitReset dijitInline ' + this.baseClass + 'Label">' +
					(newDisplay || this.emptyLabel || "&nbsp;") +
					'</span>';
		dijit.setWaiState(this.focusNode, "valuetext", (newDisplay || this.emptyLabel || "&nbsp;") );
	},

	validate: function(/*Boolean*/ isFocused){
		// summary:
		//		Called by oninit, onblur, and onkeypress.
		// description:
		//		Show missing or invalid messages if appropriate, and highlight textbox field.
		//		Used when a select is initially set to no value and the user is required to
		//		set the value.
		
		var isValid = this.isValid(isFocused);
		this.state = isValid ? "" : "Error";
		this._setStateClass();
		dijit.setWaiState(this.focusNode, "invalid", isValid ? "false" : "true");
		var message = isValid ? "" : this._missingMsg;
		if(this._message !== message){
			this._message = message;
			dijit.hideTooltip(this.domNode);
			if(message){
				dijit.showTooltip(message, this.domNode, this.tooltipPosition, !this.isLeftToRight());
			}
		}
		return isValid;
	},

	isValid: function(/*Boolean*/ isFocused){
		// summary:
		//		Whether or not this is a valid value.   The only way a Select
		//		can be invalid is when it's required but nothing is selected.
		return (!this.required || !(/^\s*$/.test(this.value)));
	},

	reset: function(){
		// summary:
		//		Overridden so that the state will be cleared.
		this.inherited(arguments);
		dijit.hideTooltip(this.domNode);
		this.state = "";
		this._setStateClass();
		delete this._message;
	},

	postMixInProperties: function(){
		// summary:
		//		set the missing message
		this.inherited(arguments);
		this._missingMsg = dojo.i18n.getLocalization("dijit.form", "validate",
									this.lang).missingMessage;
	},

	postCreate: function(){
		this.inherited(arguments);
		if(this.tableNode.style.width){
			dojo.addClass(this.domNode, this.baseClass + "FixedWidth");
		}
	},

	isLoaded: function(){
		return this._isLoaded;
	},

	loadDropDown: function(/*Function*/ loadCallback){
		// summary:
		//		populates the menu
		this._loadChildren(true);
		this._isLoaded = true;
		loadCallback();
	},

	closeDropDown: function(){
		// overriding _HasDropDown.closeDropDown()
		this.inherited(arguments);

		if(this.dropDown && this.dropDown.menuTableNode){
			// Erase possible width: 100% setting from _SelectMenu.resize().
			// Leaving it would interfere with the next openDropDown() call, which
			// queries the natural size of the drop down.
			this.dropDown.menuTableNode.style.width = "";
		}
	},

	uninitialize: function(preserveDom){
		if(this.dropDown && !this.dropDown._destroyed){
			this.dropDown.destroyRecursive(preserveDom);
			delete this.dropDown;
		}
		this.inherited(arguments);
	}
});

}

if(!dojo._hasResource["dijit.form.ComboBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.ComboBox"] = true;
dojo.provide("dijit.form.ComboBox");












dojo.declare(
	"dijit.form.ComboBoxMixin",
	null,
	{
		// summary:
		//		Implements the base functionality for `dijit.form.ComboBox`/`dijit.form.FilteringSelect`
		// description:
		//		All widgets that mix in dijit.form.ComboBoxMixin must extend `dijit.form._FormValueWidget`.
		// tags:
		//		protected

		// item: Object
		//		This is the item returned by the dojo.data.store implementation that
		//		provides the data for this ComboBox, it's the currently selected item.
		item: null,

		// pageSize: Integer
		//		Argument to data provider.
		//		Specifies number of search results per page (before hitting "next" button)
		pageSize: Infinity,

		// store: Object
		//		Reference to data provider object used by this ComboBox
		store: null,

		// fetchProperties: Object
		//		Mixin to the dojo.data store's fetch.
		//		For example, to set the sort order of the ComboBox menu, pass:
		//	|	{ sort: {attribute:"name",descending: true} }
		//		To override the default queryOptions so that deep=false, do:
		//	|	{ queryOptions: {ignoreCase: true, deep: false} }
		fetchProperties:{},

		// query: Object
		//		A query that can be passed to 'store' to initially filter the items,
		//		before doing further filtering based on `searchAttr` and the key.
		//		Any reference to the `searchAttr` is ignored.
		query: {},

		// autoComplete: Boolean
		//		If user types in a partial string, and then tab out of the `<input>` box,
		//		automatically copy the first entry displayed in the drop down list to
		//		the `<input>` field
		autoComplete: true,

		// highlightMatch: String
		// 		One of: "first", "all" or "none".
		//
		//		If the ComboBox/FilteringSelect opens with the search results and the searched
		//		string can be found, it will be highlighted.  If set to "all"
		//		then will probably want to change `queryExpr` parameter to '*${0}*'
		//
		//		Highlighting is only performed when `labelType` is "text", so as to not
		//		interfere with any HTML markup an HTML label might contain.
		highlightMatch: "first",

		// searchDelay: Integer
		//		Delay in milliseconds between when user types something and we start
		//		searching based on that value
		searchDelay: 100,

		// searchAttr: String
		//		Search for items in the data store where this attribute (in the item)
		//		matches what the user typed
		searchAttr: "name",

		// labelAttr: String?
		//		The entries in the drop down list come from this attribute in the
		//		dojo.data items.
		//		If not specified, the searchAttr attribute is used instead.
		labelAttr: "",

		// labelType: String
		//		Specifies how to interpret the labelAttr in the data store items.
		//		Can be "html" or "text".
		labelType: "text",

		// queryExpr: String
		//		This specifies what query ComboBox/FilteringSelect sends to the data store,
		//		based on what the user has typed.  Changing this expression will modify
		//		whether the drop down shows only exact matches, a "starting with" match,
		//		etc.   Use it in conjunction with highlightMatch.
		//		dojo.data query expression pattern.
		//		`${0}` will be substituted for the user text.
		//		`*` is used for wildcards.
		//		`${0}*` means "starts with", `*${0}*` means "contains", `${0}` means "is"
		queryExpr: "${0}*",

		// ignoreCase: Boolean
		//		Set true if the ComboBox/FilteringSelect should ignore case when matching possible items
		ignoreCase: true,

		// hasDownArrow: [const] Boolean
		//		Set this textbox to have a down arrow button, to display the drop down list.
		//		Defaults to true.
		hasDownArrow: true,

		templateString: dojo.cache("dijit.form", "templates/ComboBox.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\"\n\tdojoAttachPoint=\"comboNode\" waiRole=\"combobox\"\n\t><div class='dijitReset dijitRight dijitButtonNode dijitArrowButton dijitDownArrowButton dijitArrowButtonContainer'\n\t\tdojoAttachPoint=\"downArrowNode\" waiRole=\"presentation\"\n\t\tdojoAttachEvent=\"onmousedown:_onArrowMouseDown\"\n\t\t><input class=\"dijitReset dijitInputField dijitArrowButtonInner\" value=\"&#9660; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t\t\t${_buttonInputDisabled}\n\t/></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' ${!nameAttrSetting} type=\"text\" autocomplete=\"off\"\n\t\t\tdojoAttachEvent=\"onkeypress:_onKeyPress,compositionend\"\n\t\t\tdojoAttachPoint=\"textbox,focusNode\" waiRole=\"textbox\" waiState=\"haspopup-true,autocomplete-list\"\n\t/></div\n></div>\n"),

		baseClass: "dijitTextBox dijitComboBox",

		// Set classes like dijitDownArrowButtonHover depending on
		// mouse action over button node
		cssStateNodes: {
			"downArrowNode": "dijitDownArrowButton"
		},

		_getCaretPos: function(/*DomNode*/ element){
			// khtml 3.5.2 has selection* methods as does webkit nightlies from 2005-06-22
			var pos = 0;
			if(typeof(element.selectionStart) == "number"){
				// FIXME: this is totally borked on Moz < 1.3. Any recourse?
				pos = element.selectionStart;
			}else if(dojo.isIE){
				// in the case of a mouse click in a popup being handled,
				// then the dojo.doc.selection is not the textarea, but the popup
				// var r = dojo.doc.selection.createRange();
				// hack to get IE 6 to play nice. What a POS browser.
				var tr = dojo.doc.selection.createRange().duplicate();
				var ntr = element.createTextRange();
				tr.move("character",0);
				ntr.move("character",0);
				try{
					// If control doesnt have focus, you get an exception.
					// Seems to happen on reverse-tab, but can also happen on tab (seems to be a race condition - only happens sometimes).
					// There appears to be no workaround for this - googled for quite a while.
					ntr.setEndPoint("EndToEnd", tr);
					pos = String(ntr.text).replace(/\r/g,"").length;
				}catch(e){
					// If focus has shifted, 0 is fine for caret pos.
				}
			}
			return pos;
		},

		_setCaretPos: function(/*DomNode*/ element, /*Number*/ location){
			location = parseInt(location);
			dijit.selectInputText(element, location, location);
		},

		_setDisabledAttr: function(/*Boolean*/ value){
			// Additional code to set disabled state of ComboBox node.
			// Overrides _FormValueWidget._setDisabledAttr() or ValidationTextBox._setDisabledAttr().
			this.inherited(arguments);
			dijit.setWaiState(this.comboNode, "disabled", value);
		},

		_abortQuery: function(){
			// stop in-progress query
			if(this.searchTimer){
				clearTimeout(this.searchTimer);
				this.searchTimer = null;
			}
			if(this._fetchHandle){
				if(this._fetchHandle.abort){ this._fetchHandle.abort(); }
				this._fetchHandle = null;
			}
		},

		_onInput: function(/*Event*/ evt){
			// summary:
			//		Handles paste events
			if(!this.searchTimer && (evt.type == 'paste'/*IE|WebKit*/ || evt.type == 'input'/*Firefox*/) && this._lastInput != this.textbox.value){
				this.searchTimer = setTimeout(dojo.hitch(this, function(){
					this._onKeyPress({charOrCode: 229}); // fake IME key to cause a search
				}), 100); // long delay that will probably be preempted by keyboard input
			}
			this.inherited(arguments);
		},

		_onKeyPress: function(/*Event*/ evt){
			// summary:
			//		Handles keyboard events
			var key = evt.charOrCode;
			// except for cutting/pasting case - ctrl + x/v
			if(evt.altKey || ((evt.ctrlKey || evt.metaKey) && (key != 'x' && key != 'v')) || key == dojo.keys.SHIFT){
				return; // throw out weird key combinations and spurious events
			}
			var doSearch = false;
			var searchFunction = "_startSearchFromInput";
			var pw = this._popupWidget;
			var dk = dojo.keys;
			var highlighted = null;
			this._prev_key_backspace = false;
			this._abortQuery();
			if(this._isShowingNow){
				pw.handleKey(key);
				highlighted = pw.getHighlightedOption();
			}
			switch(key){
				case dk.PAGE_DOWN:
				case dk.DOWN_ARROW:
				case dk.PAGE_UP:
				case dk.UP_ARROW:
					if(!this._isShowingNow){
						doSearch = true;
						searchFunction = "_startSearchAll";
					}else{
						this._announceOption(highlighted);
					}
					dojo.stopEvent(evt);
					break;

				case dk.ENTER:
					// prevent submitting form if user presses enter. Also
					// prevent accepting the value if either Next or Previous
					// are selected
					if(highlighted){
						// only stop event on prev/next
						if(highlighted == pw.nextButton){
							this._nextSearch(1);
							dojo.stopEvent(evt);
							break;
						}else if(highlighted == pw.previousButton){
							this._nextSearch(-1);
							dojo.stopEvent(evt);
							break;
						}
					}else{
						// Update 'value' (ex: KY) according to currently displayed text
						this._setBlurValue(); // set value if needed
						this._setCaretPos(this.focusNode, this.focusNode.value.length); // move cursor to end and cancel highlighting
					}
					// default case:
					// prevent submit, but allow event to bubble
					evt.preventDefault();
					// fall through

				case dk.TAB:
					var newvalue = this.get('displayedValue');
					//	if the user had More Choices selected fall into the
					//	_onBlur handler
					if(pw && (
						newvalue == pw._messages["previousMessage"] ||
						newvalue == pw._messages["nextMessage"])
					){
						break;
					}
					if(highlighted){
						this._selectOption();
					}
					if(this._isShowingNow){
						this._lastQuery = null; // in case results come back later
						this._hideResultList();
					}
					break;

				case ' ':
					if(highlighted){
						dojo.stopEvent(evt);
						this._selectOption();
						this._hideResultList();
					}else{
						doSearch = true;
					}
					break;

				case dk.ESCAPE:
					if(this._isShowingNow){
						dojo.stopEvent(evt);
						this._hideResultList();
					}
					break;

				case dk.DELETE:
				case dk.BACKSPACE:
					this._prev_key_backspace = true;
					doSearch = true;
					break;

				default:
					// Non char keys (F1-F12 etc..)  shouldn't open list.
					// Ascii characters and IME input (Chinese, Japanese etc.) should.
					// On IE and safari, IME input produces keycode == 229, and we simulate
					// it on firefox by attaching to compositionend event (see compositionend method)
					doSearch = typeof key == 'string' || key == 229;
			}
			if(doSearch){
				// need to wait a tad before start search so that the event
				// bubbles through DOM and we have value visible
				this.item = undefined; // undefined means item needs to be set
				this.searchTimer = setTimeout(dojo.hitch(this, searchFunction),1);
			}
		},

		_autoCompleteText: function(/*String*/ text){
			// summary:
			// 		Fill in the textbox with the first item from the drop down
			// 		list, and highlight the characters that were
			// 		auto-completed. For example, if user typed "CA" and the
			// 		drop down list appeared, the textbox would be changed to
			// 		"California" and "ifornia" would be highlighted.

			var fn = this.focusNode;

			// IE7: clear selection so next highlight works all the time
			dijit.selectInputText(fn, fn.value.length);
			// does text autoComplete the value in the textbox?
			var caseFilter = this.ignoreCase? 'toLowerCase' : 'substr';
			if(text[caseFilter](0).indexOf(this.focusNode.value[caseFilter](0)) == 0){
				var cpos = this._getCaretPos(fn);
				// only try to extend if we added the last character at the end of the input
				if((cpos+1) > fn.value.length){
					// only add to input node as we would overwrite Capitalisation of chars
					// actually, that is ok
					fn.value = text;//.substr(cpos);
					// visually highlight the autocompleted characters
					dijit.selectInputText(fn, cpos);
				}
			}else{
				// text does not autoComplete; replace the whole value and highlight
				fn.value = text;
				dijit.selectInputText(fn);
			}
		},

		_openResultList: function(/*Object*/ results, /*Object*/ dataObject){
			this._fetchHandle = null;
			if(	this.disabled ||
				this.readOnly ||
				(dataObject.query[this.searchAttr] != this._lastQuery)
			){
				return;
			}
			this._popupWidget.clearResultList();
			if(!results.length && !this._maxOptions){ // this condition needs to match !this._isvalid set in FilteringSelect::_openResultList
				this._hideResultList();
				return;
			}


			// Fill in the textbox with the first item from the drop down list,
			// and highlight the characters that were auto-completed. For
			// example, if user typed "CA" and the drop down list appeared, the
			// textbox would be changed to "California" and "ifornia" would be
			// highlighted.

			dataObject._maxOptions = this._maxOptions;
			var nodes = this._popupWidget.createOptions(
				results,
				dataObject,
				dojo.hitch(this, "_getMenuLabelFromItem")
			);

			// show our list (only if we have content, else nothing)
			this._showResultList();

			// #4091:
			//		tell the screen reader that the paging callback finished by
			//		shouting the next choice
			if(dataObject.direction){
				if(1 == dataObject.direction){
					this._popupWidget.highlightFirstOption();
				}else if(-1 == dataObject.direction){
					this._popupWidget.highlightLastOption();
				}
				this._announceOption(this._popupWidget.getHighlightedOption());
			}else if(this.autoComplete && !this._prev_key_backspace /*&& !dataObject.direction*/
				// when the user clicks the arrow button to show the full list,
				// startSearch looks for "*".
				// it does not make sense to autocomplete
				// if they are just previewing the options available.
				&& !/^[*]+$/.test(dataObject.query[this.searchAttr])){
					this._announceOption(nodes[1]); // 1st real item
			}
		},

		_showResultList: function(){
			this._hideResultList();
			// hide the tooltip
			this.displayMessage("");

			// Position the list and if it's too big to fit on the screen then
			// size it to the maximum possible height
			// Our dear friend IE doesnt take max-height so we need to
			// calculate that on our own every time

			// TODO: want to redo this, see
			//		http://trac.dojotoolkit.org/ticket/3272
			//	and
			//		http://trac.dojotoolkit.org/ticket/4108


			// natural size of the list has changed, so erase old
			// width/height settings, which were hardcoded in a previous
			// call to this function (via dojo.marginBox() call)
			dojo.style(this._popupWidget.domNode, {width: "", height: ""});

			var best = this.open();
			// #3212:
			//		only set auto scroll bars if necessary prevents issues with
			//		scroll bars appearing when they shouldn't when node is made
			//		wider (fractional pixels cause this)
			var popupbox = dojo.marginBox(this._popupWidget.domNode);
			this._popupWidget.domNode.style.overflow =
				((best.h == popupbox.h) && (best.w == popupbox.w)) ? "hidden" : "auto";
			// #4134:
			//		borrow TextArea scrollbar test so content isn't covered by
			//		scrollbar and horizontal scrollbar doesn't appear
			var newwidth = best.w;
			if(best.h < this._popupWidget.domNode.scrollHeight){
				newwidth += 16;
			}
			dojo.marginBox(this._popupWidget.domNode, {
				h: best.h,
				w: Math.max(newwidth, this.domNode.offsetWidth)
			});
			
			// If we increased the width of drop down to match the width of ComboBox.domNode,
			// then need to reposition the drop down (wrapper) so (all of) the drop down still
			// appears underneath the ComboBox.domNode
			if(newwidth < this.domNode.offsetWidth){
				this._popupWidget.domNode.parentNode.style.left = dojo.position(this.domNode, true).x + "px";
			}

			dijit.setWaiState(this.comboNode, "expanded", "true");
		},

		_hideResultList: function(){
			this._abortQuery();
			if(this._isShowingNow){
				dijit.popup.close(this._popupWidget);
				this._isShowingNow=false;
				dijit.setWaiState(this.comboNode, "expanded", "false");
				dijit.removeWaiState(this.focusNode,"activedescendant");
			}
		},

		_setBlurValue: function(){
			// if the user clicks away from the textbox OR tabs away, set the
			// value to the textbox value
			// #4617:
			//		if value is now more choices or previous choices, revert
			//		the value
			var newvalue = this.get('displayedValue');
			var pw = this._popupWidget;
			if(pw && (
				newvalue == pw._messages["previousMessage"] ||
				newvalue == pw._messages["nextMessage"]
				)
			){
				this._setValueAttr(this._lastValueReported, true);
			}else if(typeof this.item == "undefined"){
				// Update 'value' (ex: KY) according to currently displayed text
				this.item = null;
				this.set('displayedValue', newvalue);
			}else{
				if(this.value != this._lastValueReported){
					dijit.form._FormValueWidget.prototype._setValueAttr.call(this, this.value, true);
				}
				this._refreshState();
			}
		},

		_onBlur: function(){
			// summary:
			//		Called magically when focus has shifted away from this widget and it's drop down
			this._hideResultList();
			this.inherited(arguments);
		},

		_setItemAttr: function(/*item*/ item, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
			// summary:
			//              Set the displayed valued in the input box, and the hidden value
			//              that gets submitted, based on a dojo.data store item.
			// description:
			//              Users shouldn't call this function; they should be calling
			//              attr('item', value)
			// tags:
			//              private
			if(!displayedValue){ displayedValue = this.labelFunc(item, this.store); }
			this.value = this._getValueField() != this.searchAttr? this.store.getIdentity(item) : displayedValue;
			this.item = item;
			dijit.form.ComboBox.superclass._setValueAttr.call(this, this.value, priorityChange, displayedValue);
		},

		_announceOption: function(/*Node*/ node){
			// summary:
			//		a11y code that puts the highlighted option in the textbox.
			//		This way screen readers will know what is happening in the
			//		menu.

			if(!node){
				return;
			}
			// pull the text value from the item attached to the DOM node
			var newValue;
			if(node == this._popupWidget.nextButton ||
				node == this._popupWidget.previousButton){
				newValue = node.innerHTML;
				this.item = undefined;
				this.value = '';
			}else{
				newValue = this.labelFunc(node.item, this.store);
				this.set('item', node.item, false, newValue);
			}
			// get the text that the user manually entered (cut off autocompleted text)
			this.focusNode.value = this.focusNode.value.substring(0, this._lastInput.length);
			// set up ARIA activedescendant
			dijit.setWaiState(this.focusNode, "activedescendant", dojo.attr(node, "id"));
			// autocomplete the rest of the option to announce change
			this._autoCompleteText(newValue);
		},

		_selectOption: function(/*Event*/ evt){
			// summary:
			//		Menu callback function, called when an item in the menu is selected.
			if(evt){
				this._announceOption(evt.target);
			}
			this._hideResultList();
			this._setCaretPos(this.focusNode, this.focusNode.value.length);
			dijit.form._FormValueWidget.prototype._setValueAttr.call(this, this.value, true); // set this.value and fire onChange
		},

		_onArrowMouseDown: function(evt){
			// summary:
			//		Callback when arrow is clicked
			if(this.disabled || this.readOnly){
				return;
			}
			dojo.stopEvent(evt);
			this.focus();
			if(this._isShowingNow){
				this._hideResultList();
			}else{
				// forces full population of results, if they click
				// on the arrow it means they want to see more options
				this._startSearchAll();
			}
		},

		_startSearchAll: function(){
			this._startSearch('');
		},

		_startSearchFromInput: function(){
			this._startSearch(this.focusNode.value.replace(/([\\\*\?])/g, "\\$1"));
		},

		_getQueryString: function(/*String*/ text){
			return dojo.string.substitute(this.queryExpr, [text]);
		},

		_startSearch: function(/*String*/ key){
			if(!this._popupWidget){
				var popupId = this.id + "_popup";
				this._popupWidget = new dijit.form._ComboBoxMenu({
					onChange: dojo.hitch(this, this._selectOption),
					id: popupId,
					dir: this.dir
				});
				dijit.removeWaiState(this.focusNode,"activedescendant");
				dijit.setWaiState(this.textbox,"owns",popupId); // associate popup with textbox
			}
			// create a new query to prevent accidentally querying for a hidden
			// value from FilteringSelect's keyField
			var query = dojo.clone(this.query); // #5970
			this._lastInput = key; // Store exactly what was entered by the user.
			this._lastQuery = query[this.searchAttr] = this._getQueryString(key);
			// #5970: set _lastQuery, *then* start the timeout
			// otherwise, if the user types and the last query returns before the timeout,
			// _lastQuery won't be set and their input gets rewritten
			this.searchTimer=setTimeout(dojo.hitch(this, function(query, _this){
				this.searchTimer = null;
				var fetch = {
					queryOptions: {
						ignoreCase: this.ignoreCase,
						deep: true
					},
					query: query,
					onBegin: dojo.hitch(this, "_setMaxOptions"),
					onComplete: dojo.hitch(this, "_openResultList"),
					onError: function(errText){
						_this._fetchHandle = null;
						console.error('dijit.form.ComboBox: ' + errText);
						dojo.hitch(_this, "_hideResultList")();
					},
					start: 0,
					count: this.pageSize
				};
				dojo.mixin(fetch, _this.fetchProperties);
				this._fetchHandle = _this.store.fetch(fetch);

				var nextSearch = function(dataObject, direction){
					dataObject.start += dataObject.count*direction;
					// #4091:
					//		tell callback the direction of the paging so the screen
					//		reader knows which menu option to shout
					dataObject.direction = direction;
					this._fetchHandle = this.store.fetch(dataObject);
				};
				this._nextSearch = this._popupWidget.onPage = dojo.hitch(this, nextSearch, this._fetchHandle);
			}, query, this), this.searchDelay);
		},

		_setMaxOptions: function(size, request){
			 this._maxOptions = size;
		},

		_getValueField: function(){
			// summmary:
			//		Helper for postMixInProperties() to set this.value based on data inlined into the markup.
			//		Returns the attribute name in the item (in dijit.form._ComboBoxDataStore) to use as the value.
			return this.searchAttr;
		},

		/////////////// Event handlers /////////////////////

		// FIXME: For 2.0, rename to "_compositionEnd"
		compositionend: function(/*Event*/ evt){
			// summary:
			//		When inputting characters using an input method, such as
			//		Asian languages, it will generate this event instead of
			//		onKeyDown event.
			//		Note: this event is only triggered in FF (not in IE/safari)
			// tags:
			//		private

			// 229 is the code produced by IE and safari while pressing keys during
			// IME input mode
			this._onKeyPress({charOrCode: 229});
		},

		//////////// INITIALIZATION METHODS ///////////////////////////////////////

		constructor: function(){
			this.query={};
			this.fetchProperties={};
		},

		postMixInProperties: function(){
			if(!this.store){
				var srcNodeRef = this.srcNodeRef;

				// if user didn't specify store, then assume there are option tags
				this.store = new dijit.form._ComboBoxDataStore(srcNodeRef);

				// if there is no value set and there is an option list, set
				// the value to the first value to be consistent with native
				// Select

				// Firefox and Safari set value
				// IE6 and Opera set selectedIndex, which is automatically set
				// by the selected attribute of an option tag
				// IE6 does not set value, Opera sets value = selectedIndex
				if(!("value" in this.params)){
					var item = this.store.fetchSelectedItem();
					if(item){
						var valueField = this._getValueField();
						this.value = valueField != this.searchAttr? this.store.getValue(item, valueField) : this.labelFunc(item, this.store);
					}
				}
			}
			this.inherited(arguments);
		},

		postCreate: function(){
			// summary:
			//		Subclasses must call this method from their postCreate() methods
			// tags:
			//		protected

			if(!this.hasDownArrow){
				this.downArrowNode.style.display = "none";
			}

			// find any associated label element and add to ComboBox node.
			var label=dojo.query('label[for="'+this.id+'"]');
			if(label.length){
				label[0].id = (this.id+"_label");
				var cn=this.comboNode;
				dijit.setWaiState(cn, "labelledby", label[0].id);

			}
			this.inherited(arguments);
		},

		uninitialize: function(){
			if(this._popupWidget && !this._popupWidget._destroyed){
				this._hideResultList();
				this._popupWidget.destroy();
			}
			this.inherited(arguments);
		},

		_getMenuLabelFromItem: function(/*Item*/ item){
			var label = this.labelAttr? this.store.getValue(item, this.labelAttr) : this.labelFunc(item, this.store);
			var labelType = this.labelType;
			// If labelType is not "text" we don't want to screw any markup ot whatever.
			if(this.highlightMatch != "none" && this.labelType == "text" && this._lastInput){
				label = this.doHighlight(label, this._escapeHtml(this._lastInput));
				labelType = "html";
			}
			return {html: labelType == "html", label: label};
		},

		doHighlight: function(/*String*/label, /*String*/find){
			// summary:
			//		Highlights the string entered by the user in the menu.  By default this
			//		highlights the first occurence found. Override this method
			//		to implement your custom highlighing.
			// tags:
			//		protected

			// Add greedy when this.highlightMatch == "all"
			var modifiers = "i"+(this.highlightMatch == "all"?"g":"");
			var escapedLabel = this._escapeHtml(label);
			find = dojo.regexp.escapeString(find); // escape regexp special chars
			var ret = escapedLabel.replace(new RegExp("(^|\\s)("+ find +")", modifiers),
					'$1<span class="dijitComboBoxHighlightMatch">$2</span>');
			return ret;// returns String, (almost) valid HTML (entities encoded)
		},

		_escapeHtml: function(/*string*/str){
			// TODO Should become dojo.html.entities(), when exists use instead
			// summary:
			//		Adds escape sequences for special characters in XML: &<>"'
			str = String(str).replace(/&/gm, "&amp;").replace(/</gm, "&lt;")
				.replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
			return str; // string
		},

		open: function(){
			// summary:
			//		Opens the drop down menu.  TODO: rename to _open.
			// tags:
			//		private
			this._isShowingNow=true;
			return dijit.popup.open({
				popup: this._popupWidget,
				around: this.domNode,
				parent: this
			});
		},

		reset: function(){
			// Overrides the _FormWidget.reset().
			// Additionally reset the .item (to clean up).
			this.item = null;
			this.inherited(arguments);
		},

		labelFunc: function(/*item*/ item, /*dojo.data.store*/ store){
			// summary:
			//              Computes the label to display based on the dojo.data store item.
			// returns:
			//              The label that the ComboBox should display
			// tags:
			//              private

			// Use toString() because XMLStore returns an XMLItem whereas this
			// method is expected to return a String (#9354)
			return store.getValue(item, this.searchAttr).toString(); // String
		}
	}
);

dojo.declare(
	"dijit.form._ComboBoxMenu",
	[dijit._Widget, dijit._Templated, dijit._CssStateMixin],
	{
		// summary:
		//		Focus-less menu for internal use in `dijit.form.ComboBox`
		// tags:
		//		private

		templateString: "<ul class='dijitReset dijitMenu' dojoAttachEvent='onmousedown:_onMouseDown,onmouseup:_onMouseUp,onmouseover:_onMouseOver,onmouseout:_onMouseOut' tabIndex='-1' style='overflow: \"auto\"; overflow-x: \"hidden\";'>"
				+"<li class='dijitMenuItem dijitMenuPreviousButton' dojoAttachPoint='previousButton' waiRole='option'></li>"
				+"<li class='dijitMenuItem dijitMenuNextButton' dojoAttachPoint='nextButton' waiRole='option'></li>"
			+"</ul>",

		// _messages: Object
		//		Holds "next" and "previous" text for paging buttons on drop down
		_messages: null,
		
		baseClass: "dijitComboBoxMenu",

		postMixInProperties: function(){
			this._messages = dojo.i18n.getLocalization("dijit.form", "ComboBox", this.lang);
			this.inherited(arguments);
		},

		_setValueAttr: function(/*Object*/ value){
			this.value = value;
			this.onChange(value);
		},

		// stubs
		onChange: function(/*Object*/ value){
			// summary:
			//		Notifies ComboBox/FilteringSelect that user clicked an option in the drop down menu.
			//		Probably should be called onSelect.
			// tags:
			//		callback
		},
		onPage: function(/*Number*/ direction){
			// summary:
			//		Notifies ComboBox/FilteringSelect that user clicked to advance to next/previous page.
			// tags:
			//		callback
		},

		postCreate: function(){
			// fill in template with i18n messages
			this.previousButton.innerHTML = this._messages["previousMessage"];
			this.nextButton.innerHTML = this._messages["nextMessage"];
			this.inherited(arguments);
		},

		onClose: function(){
			// summary:
			//		Callback from dijit.popup code to this widget, notifying it that it closed
			// tags:
			//		private
			this._blurOptionNode();
		},

		_createOption: function(/*Object*/ item, labelFunc){
			// summary:
			//		Creates an option to appear on the popup menu subclassed by
			//		`dijit.form.FilteringSelect`.

			var labelObject = labelFunc(item);
			var menuitem = dojo.doc.createElement("li");
			dijit.setWaiRole(menuitem, "option");
			if(labelObject.html){
				menuitem.innerHTML = labelObject.label;
			}else{
				menuitem.appendChild(
					dojo.doc.createTextNode(labelObject.label)
				);
			}
			// #3250: in blank options, assign a normal height
			if(menuitem.innerHTML == ""){
				menuitem.innerHTML = "&nbsp;";
			}
			menuitem.item=item;
			return menuitem;
		},

		createOptions: function(results, dataObject, labelFunc){
			// summary:
			//		Fills in the items in the drop down list
			// results:
			//		Array of dojo.data items
			// dataObject:
			//		dojo.data store
			// labelFunc:
			//		Function to produce a label in the drop down list from a dojo.data item

			//this._dataObject=dataObject;
			//this._dataObject.onComplete=dojo.hitch(comboBox, comboBox._openResultList);
			// display "Previous . . ." button
			this.previousButton.style.display = (dataObject.start == 0) ? "none" : "";
			dojo.attr(this.previousButton, "id", this.id + "_prev");
			// create options using _createOption function defined by parent
			// ComboBox (or FilteringSelect) class
			// #2309:
			//		iterate over cache nondestructively
			dojo.forEach(results, function(item, i){
				var menuitem = this._createOption(item, labelFunc);
				menuitem.className = "dijitReset dijitMenuItem" +
					(this.isLeftToRight() ? "" : " dijitMenuItemRtl");
				dojo.attr(menuitem, "id", this.id + i);
				this.domNode.insertBefore(menuitem, this.nextButton);
			}, this);
			// display "Next . . ." button
			var displayMore = false;
			//Try to determine if we should show 'more'...
			if(dataObject._maxOptions && dataObject._maxOptions != -1){
				if((dataObject.start + dataObject.count) < dataObject._maxOptions){
					displayMore = true;
				}else if((dataObject.start + dataObject.count) > dataObject._maxOptions && dataObject.count == results.length){
					//Weird return from a datastore, where a start + count > maxOptions
					// implies maxOptions isn't really valid and we have to go into faking it.
					//And more or less assume more if count == results.length
					displayMore = true;
				}
			}else if(dataObject.count == results.length){
				//Don't know the size, so we do the best we can based off count alone.
				//So, if we have an exact match to count, assume more.
				displayMore = true;
			}

			this.nextButton.style.display = displayMore ? "" : "none";
			dojo.attr(this.nextButton,"id", this.id + "_next");
			return this.domNode.childNodes;
		},

		clearResultList: function(){
			// summary:
			//		Clears the entries in the drop down list, but of course keeps the previous and next buttons.
			while(this.domNode.childNodes.length>2){
				this.domNode.removeChild(this.domNode.childNodes[this.domNode.childNodes.length-2]);
			}
		},

		_onMouseDown: function(/*Event*/ evt){
			dojo.stopEvent(evt);
		},

		_onMouseUp: function(/*Event*/ evt){
			if(evt.target === this.domNode || !this._highlighted_option){
				return;
			}else if(evt.target == this.previousButton){
				this.onPage(-1);
			}else if(evt.target == this.nextButton){
				this.onPage(1);
			}else{
				var tgt = evt.target;
				// while the clicked node is inside the div
				while(!tgt.item){
					// recurse to the top
					tgt = tgt.parentNode;
				}
				this._setValueAttr({ target: tgt }, true);
			}
		},

		_onMouseOver: function(/*Event*/ evt){
			if(evt.target === this.domNode){ return; }
			var tgt = evt.target;
			if(!(tgt == this.previousButton || tgt == this.nextButton)){
				// while the clicked node is inside the div
				while(!tgt.item){
					// recurse to the top
					tgt = tgt.parentNode;
				}
			}
			this._focusOptionNode(tgt);
		},

		_onMouseOut: function(/*Event*/ evt){
			if(evt.target === this.domNode){ return; }
			this._blurOptionNode();
		},

		_focusOptionNode: function(/*DomNode*/ node){
			// summary:
			//		Does the actual highlight.
			if(this._highlighted_option != node){
				this._blurOptionNode();
				this._highlighted_option = node;
				dojo.addClass(this._highlighted_option, "dijitMenuItemSelected");
			}
		},

		_blurOptionNode: function(){
			// summary:
			//		Removes highlight on highlighted option.
			if(this._highlighted_option){
				dojo.removeClass(this._highlighted_option, "dijitMenuItemSelected");
				this._highlighted_option = null;
			}
		},

		_highlightNextOption: function(){
			// summary:
			// 		Highlight the item just below the current selection.
			// 		If nothing selected, highlight first option.

			// because each press of a button clears the menu,
			// the highlighted option sometimes becomes detached from the menu!
			// test to see if the option has a parent to see if this is the case.
			if(!this.getHighlightedOption()){
				var fc = this.domNode.firstChild;
				this._focusOptionNode(fc.style.display == "none" ? fc.nextSibling : fc);
			}else{
				var ns = this._highlighted_option.nextSibling;
				if(ns && ns.style.display != "none"){
					this._focusOptionNode(ns);
				}else{
					this.highlightFirstOption();
				}
			}
			// scrollIntoView is called outside of _focusOptionNode because in IE putting it inside causes the menu to scroll up on mouseover
			dojo.window.scrollIntoView(this._highlighted_option);
		},

		highlightFirstOption: function(){
			// summary:
			// 		Highlight the first real item in the list (not Previous Choices).
			var first = this.domNode.firstChild;
			var second = first.nextSibling;
			this._focusOptionNode(second.style.display == "none" ? first : second); // remotely possible that Previous Choices is the only thing in the list
			dojo.window.scrollIntoView(this._highlighted_option);
		},

		highlightLastOption: function(){
			// summary:
			// 		Highlight the last real item in the list (not More Choices).
			this._focusOptionNode(this.domNode.lastChild.previousSibling);
			dojo.window.scrollIntoView(this._highlighted_option);
		},

		_highlightPrevOption: function(){
			// summary:
			// 		Highlight the item just above the current selection.
			// 		If nothing selected, highlight last option (if
			// 		you select Previous and try to keep scrolling up the list).
			if(!this.getHighlightedOption()){
				var lc = this.domNode.lastChild;
				this._focusOptionNode(lc.style.display == "none" ? lc.previousSibling : lc);
			}else{
				var ps = this._highlighted_option.previousSibling;
				if(ps && ps.style.display != "none"){
					this._focusOptionNode(ps);
				}else{
					this.highlightLastOption();
				}
			}
			dojo.window.scrollIntoView(this._highlighted_option);
		},

		_page: function(/*Boolean*/ up){
			// summary:
			//		Handles page-up and page-down keypresses

			var scrollamount = 0;
			var oldscroll = this.domNode.scrollTop;
			var height = dojo.style(this.domNode, "height");
			// if no item is highlighted, highlight the first option
			if(!this.getHighlightedOption()){
				this._highlightNextOption();
			}
			while(scrollamount<height){
				if(up){
					// stop at option 1
					if(!this.getHighlightedOption().previousSibling ||
						this._highlighted_option.previousSibling.style.display == "none"){
						break;
					}
					this._highlightPrevOption();
				}else{
					// stop at last option
					if(!this.getHighlightedOption().nextSibling ||
						this._highlighted_option.nextSibling.style.display == "none"){
						break;
					}
					this._highlightNextOption();
				}
				// going backwards
				var newscroll=this.domNode.scrollTop;
				scrollamount+=(newscroll-oldscroll)*(up ? -1:1);
				oldscroll=newscroll;
			}
		},

		pageUp: function(){
			// summary:
			//		Handles pageup keypress.
			//		TODO: just call _page directly from handleKey().
			// tags:
			//		private
			this._page(true);
		},

		pageDown: function(){
			// summary:
			//		Handles pagedown keypress.
			//		TODO: just call _page directly from handleKey().
			// tags:
			//		private
			this._page(false);
		},

		getHighlightedOption: function(){
			// summary:
			//		Returns the highlighted option.
			var ho = this._highlighted_option;
			return (ho && ho.parentNode) ? ho : null;
		},

		handleKey: function(key){
			switch(key){
				case dojo.keys.DOWN_ARROW:
					this._highlightNextOption();
					break;
				case dojo.keys.PAGE_DOWN:
					this.pageDown();
					break;
				case dojo.keys.UP_ARROW:
					this._highlightPrevOption();
					break;
				case dojo.keys.PAGE_UP:
					this.pageUp();
					break;
			}
		}
	}
);

dojo.declare(
	"dijit.form.ComboBox",
	[dijit.form.ValidationTextBox, dijit.form.ComboBoxMixin],
	{
		// summary:
		//		Auto-completing text box, and base class for dijit.form.FilteringSelect.
		//
		// description:
		//		The drop down box's values are populated from an class called
		//		a data provider, which returns a list of values based on the characters
		//		that the user has typed into the input box.
		//		If OPTION tags are used as the data provider via markup,
		//		then the OPTION tag's child text node is used as the widget value
		//		when selected.  The OPTION tag's value attribute is ignored.
		//		To set the default value when using OPTION tags, specify the selected
		//		attribute on 1 of the child OPTION tags.
		//
		//		Some of the options to the ComboBox are actually arguments to the data
		//		provider.

		_setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
			// summary:
			//		Hook so attr('value', value) works.
			// description:
			//		Sets the value of the select.
			this.item = null; // value not looked up in store
			if(!value){ value = ''; } // null translates to blank
			dijit.form.ValidationTextBox.prototype._setValueAttr.call(this, value, priorityChange, displayedValue);
		}
	}
);

dojo.declare("dijit.form._ComboBoxDataStore", null, {
	// summary:
	//		Inefficient but small data store specialized for inlined `dijit.form.ComboBox` data
	//
	// description:
	//		Provides a store for inlined data like:
	//
	//	|	<select>
	//	|		<option value="AL">Alabama</option>
	//	|		...
	//
	//		Actually. just implements the subset of dojo.data.Read/Notification
	//		needed for ComboBox and FilteringSelect to work.
	//
	//		Note that an item is just a pointer to the <option> DomNode.

	constructor: function( /*DomNode*/ root){
		this.root = root;
		if(root.tagName != "SELECT" && root.firstChild){
			root = dojo.query("select", root);
			if(root.length > 0){ // SELECT is a child of srcNodeRef
				root = root[0];
			}else{ // no select, so create 1 to parent the option tags to define selectedIndex
				this.root.innerHTML = "<SELECT>"+this.root.innerHTML+"</SELECT>";
				root = this.root.firstChild;
			}
			this.root = root;
		}
		dojo.query("> option", root).forEach(function(node){
			//	TODO: this was added in #3858 but unclear why/if it's needed;  doesn't seem to be.
			//	If it is needed then can we just hide the select itself instead?
			//node.style.display="none";
			node.innerHTML = dojo.trim(node.innerHTML);
		});

	},

	getValue: function(	/* item */ item,
						/* attribute-name-string */ attribute,
						/* value? */ defaultValue){
		return (attribute == "value") ? item.value : (item.innerText || item.textContent || '');
	},

	isItemLoaded: function(/* anything */ something){
		return true;
	},

	getFeatures: function(){
		return {"dojo.data.api.Read": true, "dojo.data.api.Identity": true};
	},

	_fetchItems: function(	/* Object */ args,
							/* Function */ findCallback,
							/* Function */ errorCallback){
		// summary:
		//		See dojo.data.util.simpleFetch.fetch()
		if(!args.query){ args.query = {}; }
		if(!args.query.name){ args.query.name = ""; }
		if(!args.queryOptions){ args.queryOptions = {}; }
		var matcher = dojo.data.util.filter.patternToRegExp(args.query.name, args.queryOptions.ignoreCase),
			items = dojo.query("> option", this.root).filter(function(option){
				return (option.innerText || option.textContent || '').match(matcher);
			} );
		if(args.sort){
			items.sort(dojo.data.util.sorter.createSortFunction(args.sort, this));
		}
		findCallback(items, args);
	},

	close: function(/*dojo.data.api.Request || args || null */ request){
		return;
	},

	getLabel: function(/* item */ item){
		return item.innerHTML;
	},

	getIdentity: function(/* item */ item){
		return dojo.attr(item, "value");
	},

	fetchItemByIdentity: function(/* Object */ args){
		// summary:
		//		Given the identity of an item, this method returns the item that has
		//		that identity through the onItem callback.
		//		Refer to dojo.data.api.Identity.fetchItemByIdentity() for more details.
		//
		// description:
		//		Given arguments like:
		//
		//	|		{identity: "CA", onItem: function(item){...}
		//
		//		Call `onItem()` with the DOM node `<option value="CA">California</option>`
		var item = dojo.query("> option[value='" + args.identity + "']", this.root)[0];
		args.onItem(item);
	},

	fetchSelectedItem: function(){
		// summary:
		//		Get the option marked as selected, like `<option selected>`.
		//		Not part of dojo.data API.
		var root = this.root,
			si = root.selectedIndex;
		return typeof si == "number"
			? dojo.query("> option:nth-child(" + (si != -1 ? si+1 : 1) + ")", root)[0]
			: null;	// dojo.data.Item
	}
});
//Mix in the simple fetch implementation to this class.
dojo.extend(dijit.form._ComboBoxDataStore,dojo.data.util.simpleFetch);

}

if(!dojo._hasResource["dijit.form.FilteringSelect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.FilteringSelect"] = true;
dojo.provide("dijit.form.FilteringSelect");



dojo.declare(
	"dijit.form.FilteringSelect",
	[dijit.form.MappedTextBox, dijit.form.ComboBoxMixin],
	{
		// summary:
		//		An enhanced version of the HTML SELECT tag, populated dynamically
		//
		// description:
		//		An enhanced version of the HTML SELECT tag, populated dynamically. It works
		//		very nicely with very large data sets because it can load and page data as needed.
		//		It also resembles ComboBox, but does not allow values outside of the provided ones.
		//		If OPTION tags are used as the data provider via markup, then the
		//		OPTION tag's child text node is used as the displayed value when selected
		//		while the OPTION tag's value attribute is used as the widget value on form submit.
		//		To set the default value when using OPTION tags, specify the selected
		//		attribute on 1 of the child OPTION tags.
		//
		//		Similar features:
		//			- There is a drop down list of possible values.
		//			- You can only enter a value from the drop down list.  (You can't
		//				enter an arbitrary value.)
		//			- The value submitted with the form is the hidden value (ex: CA),
		//				not the displayed value a.k.a. label (ex: California)
		//
		//		Enhancements over plain HTML version:
		//			- If you type in some text then it will filter down the list of
		//				possible values in the drop down list.
		//			- List can be specified either as a static list or via a javascript
		//				function (that can get the list from a server)

		_isvalid: true,

		// required: Boolean
		//		True (default) if user is required to enter a value into this field.
		required: true,

		_lastDisplayedValue: "",

		isValid: function(){
			// Overrides ValidationTextBox.isValid()
			return this._isvalid || (!this.required && this.get('displayedValue') == ""); // #5974
		},

		_refreshState: function(){
			if(!this.searchTimer){ // state will be refreshed after results are returned
				this.inherited(arguments);
			}
		},

		_callbackSetLabel: function(	/*Array*/ result,
						/*Object*/ dataObject,
						/*Boolean?*/ priorityChange){
			// summary:
			//		Callback function that dynamically sets the label of the
			//		ComboBox

			// setValue does a synchronous lookup,
			// so it calls _callbackSetLabel directly,
			// and so does not pass dataObject
			// still need to test against _lastQuery in case it came too late
			if((dataObject && dataObject.query[this.searchAttr] != this._lastQuery) || (!dataObject && result.length && this.store.getIdentity(result[0]) != this._lastQuery)){
				return;
			}
			if(!result.length){
				//#3268: do nothing on bad input
				//#3285: change CSS to indicate error
				this.valueNode.value = "";
				dijit.form.TextBox.superclass._setValueAttr.call(this, "", priorityChange || (priorityChange === undefined && !this._focused));
				this._isvalid = false;
				this.validate(this._focused);
				this.item = null;
			}else{
				this.set('item', result[0], priorityChange);
			}
		},

		_openResultList: function(/*Object*/ results, /*Object*/ dataObject){
			// Overrides ComboBox._openResultList()

			// #3285: tap into search callback to see if user's query resembles a match
			if(dataObject.query[this.searchAttr] != this._lastQuery){
				return;
			}
			if(this.item === undefined){ // item == undefined for keyboard search
				this._isvalid = results.length != 0 || this._maxOptions != 0; // result.length==0 && maxOptions != 0 implies the nextChoices item selected but then the datastore returned 0 more entries
				this.validate(true);
			}
			dijit.form.ComboBoxMixin.prototype._openResultList.apply(this, arguments);
		},

		_getValueAttr: function(){
			// summary:
			//		Hook for attr('value') to work.

			// don't get the textbox value but rather the previously set hidden value.
			// Use this.valueNode.value which isn't always set for other MappedTextBox widgets until blur
			return this.valueNode.value;
		},

		_getValueField: function(){
			// Overrides ComboBox._getValueField()
			return "value";
		},

		_setValueAttr: function(/*String*/ value, /*Boolean?*/ priorityChange){
			// summary:
			//		Hook so attr('value', value) works.
			// description:
			//		Sets the value of the select.
			//		Also sets the label to the corresponding value by reverse lookup.
			if(!this._onChangeActive){ priorityChange = null; }
			this._lastQuery = value;

			if(value === null || value === ''){
				this._setDisplayedValueAttr('', priorityChange);
				return;
			}

			//#3347: fetchItemByIdentity if no keyAttr specified
			var self = this;
			this.store.fetchItemByIdentity({
				identity: value,
				onItem: function(item){
					self._callbackSetLabel(item? [item] : [], undefined, priorityChange);
				}
			});
		},

		_setItemAttr: function(/*item*/ item, /*Boolean?*/ priorityChange, /*String?*/ displayedValue){
			// summary:
			//		Set the displayed valued in the input box, and the hidden value
			//		that gets submitted, based on a dojo.data store item.
			// description:
			//		Users shouldn't call this function; they should be calling
			//		attr('item', value)
			// tags:
			//		private
			this._isvalid = true;
			this.inherited(arguments);
			this.valueNode.value = this.value;
			this._lastDisplayedValue = this.textbox.value;
		},

		_getDisplayQueryString: function(/*String*/ text){
			return text.replace(/([\\\*\?])/g, "\\$1");
		},

		_setDisplayedValueAttr: function(/*String*/ label, /*Boolean?*/ priorityChange){
			// summary:
			//		Hook so attr('displayedValue', label) works.
			// description:
			//		Sets textbox to display label. Also performs reverse lookup
			//		to set the hidden value.

			// When this is called during initialization it'll ping the datastore
			// for reverse lookup, and when that completes (after an XHR request)
			// will call setValueAttr()... but that shouldn't trigger an onChange()
			// event, even when it happens after creation has finished
			if(!this._created){
				priorityChange = false;
			}

			if(this.store){
				this._hideResultList();
				var query = dojo.clone(this.query); // #6196: populate query with user-specifics
				// escape meta characters of dojo.data.util.filter.patternToRegExp().
				this._lastQuery = query[this.searchAttr] = this._getDisplayQueryString(label);
				// if the label is not valid, the callback will never set it,
				// so the last valid value will get the warning textbox set the
				// textbox value now so that the impending warning will make
				// sense to the user
				this.textbox.value = label;
				this._lastDisplayedValue = label;
				var _this = this;
				var fetch = {
					query: query,
					queryOptions: {
						ignoreCase: this.ignoreCase,
						deep: true
					},
					onComplete: function(result, dataObject){
						_this._fetchHandle = null;
						dojo.hitch(_this, "_callbackSetLabel")(result, dataObject, priorityChange);
					},
					onError: function(errText){
						_this._fetchHandle = null;
						console.error('dijit.form.FilteringSelect: ' + errText);
						dojo.hitch(_this, "_callbackSetLabel")([], undefined, false);
					}
				};
				dojo.mixin(fetch, this.fetchProperties);
				this._fetchHandle = this.store.fetch(fetch);
			}
		},

		postMixInProperties: function(){
			this.inherited(arguments);
			this._isvalid = !this.required;
		},

		undo: function(){
			this.set('displayedValue', this._lastDisplayedValue);
		}
	}
);

}

if(!dojo._hasResource["com.sixnet.services.widgets.dropComparison"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.dropComparison"] = true;











dojo.provide("com.sixnet.services.widgets.dropComparison");

dojo.declare('com.sixnet.services.widgets.dropComparison',[dijit._Widget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div class=\"dijit dijitInline dijitLeft\">\n\t\t<span class=\"dojoDndHandle\"><span style=\"font-size:.6em; font-weight:bold; top:0\">\\_</span></span>\n\t\t<div dojoAttachPoint=\"field\" class=\"dijit dijitInline dijitLeft\"></div>\n\t\t<div dojoAttachPoint=\"operator\" class=\"dijit dijitInline dijitLeft\"></div>\n\t\t<div dojoAttachPoint=\"value\" class=\"dijit dijitInline dijitLeft\"></div>\n</div>\n",
	fields:{},
	fieldTypes:[],
	currentField:null,
	mostRecentFieldType:'',
	inputNode:null,
	
	clear: function(){
		// remove all children
		// add a single dndDropZoneSource
	},
	
	setFields: function(data){
		_sixnet_framework.log(1, "dropComp setFields", data);
		this.fields = data;
		this.field.appendChild(this.fieldSource());
		this.operator.appendChild(this.operatorSource());
//		this.value.appendChild(this.valueSource());
		dojo.connect(this, "onDrop", this, "onChildDrop");
	},
	
	postCreate: function(){
		// populate template nodes
//		switch(option){
//			case 'close':
//				break;
//			default:
//				this.addNodeHandle(node);
//		}
//		this.field.appendChild(this.fieldSource());
//		this.operator.appendChild(this.operatorSource());
//		this.value.appendChild(this.valueSource());
//		dojo.connect(this, "onDrop", this, "onChildDrop");
	},
	
	onChildDrop: function(node){
		// build any dndDropZoneSources needed according to psuedo code.
		_sixnet_framework.log(1, "Drop comparison detects child drop event NOW WE GOT ACTION");
	},
	
	valueSource: function(){
		var node = dojo.create('span');
		var input = new dijit.form.TextBox({});
		node.appendChild(input.domNode);
		return node;
	},
	
	operatorSource: function(){
		var node = dojo.create('span');
		var select = dojo.create('select');
		dojo.forEach(["=","<",">"], function(value){
			var option = dojo.create('option');
			option.innerHTML = value;
			option.setAttribute("value", value);
			select.appendChild( option);	
		});
		var filteringSelect = new dijit.form.Select({store:null, style:"width:50px; text-align:center"}, select);
		node.appendChild(filteringSelect.domNode);
		return node;
	},
	
	fieldSource: function(){
		_sixnet_framework.log(1, this.fields, " << buildFieldsDD");
		var fieldDD = dojo.create("select", {}, null);
		var fieldOptions = [];
		var hasDefault = false;
        for(var i = 0; i < this.fields.length; i++){
			var option = this.fields[i].field;
			var fieldType = this.fields[i].fieldType;
			if(i == 0){
				this.currentFieldType = fieldType;
				this.currentField = option;
			}
			if(this.fields[i].regexp){
				this.fieldTypes.push({field:option, type:fieldType, regex:this.fields[i].regexp});
			}else if(this.fields[i].options && fieldType == "enum"){
				this.fieldTypes.push({field:option, type:fieldType, options:this.fields[i].options});
			}else{
				this.fieldTypes.push({field:option, type:fieldType});
			}
			var opt = dojo.create("option", {value:option, innerHTML:option, name:option}, fieldDD);
		}
        var fieldFilteringSelect = new dijit.form.FilteringSelect({
        }, fieldDD);
        dojo.addClass(fieldFilteringSelect.domNode, "fieldFilteringSelect");
		var parent = this;
		fieldFilteringSelect.connect(fieldFilteringSelect, "onChange", function(field){
			parent.switchOnDDChange(field);
		});
		//  fire once to add value input
		this.switchOnDDChange(this.currentField);
		var node = dojo.create('span');
		node.appendChild(fieldFilteringSelect.domNode);
		return node;
	},
	
	switchOnDDChange: function(field){
		var type ;
		var regex ;
		var options ;
		// value is current DD field value
		var field = field;		
//		var fs = dojo.query(".fieldFilteringSelect", attachNode.parentNode);
//		var inputValue = dojo.query("input", dojo.byId(fs[0].id));
		var valueNode = this.value;
		for(var i = 0; i < this.fieldTypes.length; i++){
			if(this.fieldTypes[i].field == field){
				type = this.fieldTypes[i].type;
				if(this.fieldTypes[i].regex)regex = this.fieldTypes[i].regex;
				if(this.fieldTypes[i].options)options = this.fieldTypes[i].options;
			}
		}
		this.currentFieldType = type;
		this.currentField = field;
		_sixnet_framework.log(1, type, regex, options, valueNode);
		var extras = (regex != null)? regex : options;
		_sixnet_framework.log(1, extras, " <<extras");
		this.addValueInput(valueNode, type, extras);
		/*
		//  have type, now check if we've already place a value input node of some sort, tell next for compare
		///  if same fieldType, don't worry about new input node
		if(type != mostRecentFieldType || type == "enum"){
			dojo.attr(attachNode.parentNode.parentNode, "field_type", type);
			if(regex != null)this.addValueInput(attachNode, type, rowNumber, regex);
			if(options != null)this.addValueInput(attachNode, type, rowNumber, options);
			if(regex == null && options == null)this.addValueInput(attachNode, type, rowNumber, "");
//			switch(operator){
//				case 'LESS_THAN':
//					this.addValueInput(attachNode, type, rowNumber);
//					break;
//				case 'GREATER_THAN':
//					this.addValueInput(attachNode, type, rowNumber);
//					break;
//				case 'EQUAL':
//					this.addValueInput(attachNode, type, rowNumber);
//					break;
//				case 'NOT_EQUAL':
//					this.addValueInput(attachNode, type, rowNumber);
//					break;
//			}
		}else{
			//  don't re-make, but do change regex
			if(regex != null){
				_sixnet_framework.log(1, "new regex... ", regex);
				dojo.attr(this.inputNodes[rowNumber], "regExp", regex);
			}
		}
		*/
	},
	
	addValueInput: function(attachNode, type, extras){
//		this.addValueInput(this.value, this.currentFieldType, this.currentField);
		_sixnet_framework.log(1, attachNode, type, extras, "  <<<***<<< addValueInput");
//		dojo.attr(valueNode, "innerHTML", "");
		var valueInputObject = {};
		//  if fieldType is not empty then there is some sort of input already placed
		///  destroy it.
//		if(this.inputNodes[rowNumber]){
//			this.inputNodes[rowNumber].destroyRecursive();
//		}
		if(this.inputNode){
			this.inputNode.destroyRecursive();
		}
		switch(type){
		case 'interfaces':
			// TODO:
			break;
		case 'epocseconds':
			//  dateTime
			valueInputObject = new com.sixnet.services.widgets.dateTime({
				style: "margin-left:5px"
			}).placeAt(attachNode, "after");
//			dojo.attr(attachNode.parentNode.parentNode, "value_input_class", "dateTimeWidget");
			break;
		case 'serial':
			//
			valueInputObject = new dijit.form.TextBox({
	            style: "width:100px; margin-left:5px"
	        }).placeAt(attachNode, "after");
			_sixnet_framework.log(1, valueInputObject);
			dojo.addClass(valueInputObject.domNode, "valueInput");
			break;
		case 'enum':
			//  extras == options
			var optionsDD = dojo.create("select", {}, null);
			var opts = extras;
			var hasDefault = false;
	        for(var i = 0; i < opts.length; i++){
				var opt = dojo.create("option", {value:opts[i], innerHTML:opts[i], name:opts[i], label:opts[i]}, optionsDD);
	        }
	        valueInputObject = new dijit.form.Select({}, optionsDD).placeAt(attachNode, "last");
//	        dojo.addClass(valueInputObject.domNode, "dijitComboBox");
	        break;
		case 'lightbar':
			valueInputObject = new dijit.form.NumberSpinner({
	            value: 0,
	            smallDelta: 10,
	            style: "width:100px; margin-left:5px"
	        }).placeAt(attachNode, "last");
			break;
		case 'alert':
			//  build an alert level color picker
			valueInputObject = new dijit.form.NumberSpinner({
	            value: 0,
	            smallDelta: 1,
	            style: "width:100px; margin-left:5px"
	        }).placeAt(attachNode, "last");
			break;
		case 'checkbox':
//			cell.formatter = "booleanCheck"; TODO:
			break;
		case 'string':
			if(extras == ""){
				valueInputObject = new dijit.form.TextBox({
		            style: "width:100px; margin-left:5px"
		        }).placeAt(attachNode, "last");
			}else{
				valueInputObject = new dijit.form.ValidationTextBox({
		            style: "width:100px; margin-left:5px",
		            regExp:extras
		        }).placeAt(attachNode, "last");
			}
//			dojo.addClass(valueInputObject.domNode, "valueInput");
//			dojo.attr(attachNode.parentNode.parentNode, "value_input_class", "valueInput");
			break;
		}
		this.inputNode = valueInputObject;
//		_sixnet_framework.log(1, this.inputNodes, " << inputNodes");
	}
});

}

if(!dojo._hasResource["com.sixnet.services.widgets.dndFieldSource"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.dndFieldSource"] = true;


dojo.provide("com.sixnet.services.widgets.dndFieldSource");

dojo.declare('com.sixnet.services.widgets.dndFieldSource',[com.sixnet.services.widgets.dndSource], {
	dropMarkup: function(){
		var node = dojo.create('span');
		// call to parent claSS  function - use now in grouped widget: this.addNodeHandle(node);
		var select = dojo.create('select');
		dojo.forEach(["username","email","registrationDate"], function(value){
			
			var option = dojo.create('option');
			option.innerHTML = value;
			option.setAttribute("value", value);
			select.appendChild( option);	
		});
		var filteringSelect = new dijit.form.FilteringSelect({store:null}, select);
		this.droppedNodes.push(filteringSelect);
		var dndNode = dojo.create('span');
		dndNode.appendChild(filteringSelect.domNode);
		node.appendChild(dndNode);		
		node.id = dojo.dnd.getUniqueId();
		return node;
	}
});



}

if(!dojo._hasResource['com.sixnet.services.widgets.sixnetAdvancedToolbar']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.sixnetAdvancedToolbar'] = true;
dojo.provide('com.sixnet.services.widgets.sixnetAdvancedToolbar');
//










/*
 * sixnetAdvancedToolbar: serves a an advanced query widget
 * use in conjunction with sixnetGrid.
 * 
 * 
 */
dojo.declare('com.sixnet.services.widgets.sixnetAdvancedToolbar', [dijit._Widget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\t\n<style>\n.advancedSearchBarComplete{\n}\n.fieldFilteringSelect{\n\t\n}\n.operatorSelectDD{\n}\n.valueInput{\n\t\n}\n.advancedSearchBar{\n\twidth:95%;\n\theight:2.2em;\n\tbackground: url('/dojo/com/sixnet/services/widgets/templates/images/advancedToolbarBG.png') repeat-x;\n\tborder: 1px solid #777;\n\t-moz-border-radius:.5em;\n\ttext-align:left;\n\tmargin-top:.4em;\n\tmargin-left:auto;\n\tmargin-right:auto;\n\tpadding:8px;\n}\n.symbolCP{\n\twidth:95%;\n\theight:1.8em;\n\tpadding:8px;\n\ttext-align:left;\n\tmargin-top:.3em;\n\tmargin-left:auto;\n\tmargin-right:auto;\n\tfont-weight:bold;\n\tfont-size: 1.2em;\n\tcolor:#fff;\n}\n.advancedSearchBarAndOrParens{\n\twidth:95%;\n\theight:1.8em;\n\tborder: 1px solid #777;\n\t-moz-border-radius:.5em;\n\ttext-align:left;\n\tmargin-top:.3em;\n\tmargin-left:auto;\n\tmargin-right:auto;\n\tcolor:#fff;\n\tpadding:8px;\n}\n.topDown{\n\tpadding-top:1.5em;\n}\n.advancedSearchBar input{\n\tposition:relative;\n\tmargin-top:5px;\n}\n.advancedSearchBar select.dijitComboBox{\n\tposition:relative;\n\tmargin-top:5px;\n}\n.advancedSearchBar .logical{\t\n\tposition:relative;\n\tcolor:#fff;\n\tborder:1px solid #000;\n\t-moz-border-radius:.2em;\n}\n.advancedSearchBar .grouping{\n\tposition:relative;\n\tcolor:#fff;\n\tfloat:right;\n\tpadding-top:1.5em;\n}\n.advancedSearchBar .compare{\n\tposition:relative;\n\tfont-weight: bold;\n\t\tcolor:#000;\n\tborder:1px solid #000;\n\t-moz-border-radius:.2em;\nbackground-color:#fff;\n}\n\n.rowControls{\n\tposition:relative;\n\tpadding-top:1.5em;\n\tfloat:right;\n\tclear:none;\n\twidth:23px;\n\theight:23px;\n}\n.closeButton{\n\theight:23px;\n\twidth:23px;\n\tposition:relative;\n\tfloat:right;\n\tclear:none;\n\tmargin-right:5px;\n}\n.addAdvancedSearch{\n\twidth:90px;\n\theight:23px;\n}\n.advancedSearchBar .advancedSearchTextBox{\n\tfloat:left; font-size:1.1em; width:10em; margin-top:3px;margin-left:5px;\n}\n\n.advancedSearchBar .placeHolder{\n\tcolor:#000;\n\tborder:1px solid #000;\n\t-moz-border-radius:.2em;\n\tbackground:#fff;\n\theight:1em;\n\twidth:2em;\ntext-align:center;\n\tfloat:left;\n\tclear:none;\n}\n\n.advancedSearchBar .focusToSelected{\n\tcolor:#000;\n\tborder:1px solid #000;\n\t-moz-border-radius:.2em;\nbackground-color:#fff;\n}\n.advancedSearchBar .operatorPanel{\n\tfloat:left;\n\tclear:both;\n\twidth:10em;\t\nheight: 1em;\n\tpadding:5px; \n\tborder:1px solid #ddd;\n}\n</style>\n\t<div dojoTyp=\"dijit.layout.ContentPane\" style=\"height:200px; overflow:hidden; width:100%; padding:0px; margin:0px;\">\n\t\t<div dojoType=\"dijit.Toolbar\" style=\"background: url('/dojo/com/sixnet/services/widgets/templates/images/advancedToolbarBG.png') repeat-x; height:200px; width:100%; padding:0px; margin:0px; overflow:hidden; backround-repeat:repeat\" dojoAttachPoint=\"advancedToolbar\">\n\t\t\t<div style=\"width:10%; float:left; text-align:left\">\n\t\t\t\t<div dojoType=\"com.sixnet.services.widgets.HintButton\" hint=\"Add another query-builder row.\" style=\"float:left; margin-top:4px; width:90px; height:23px; background:url(/dojo/com/sixnet/services/widgets/templates/images/addAdvancedSearch.png) no-repeat; cursor:pointer\" dojoAttachEvent=\"onClick:addAdvancedSearchBar\">&nbsp;&nbsp;</div>\n\t\t\t</div>\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"advancedToolbarAttachPoint\" style=\"overflow-x:hidden; overflow-y:scroll; float:left; height:95%; width:80%; margin:auto; margin-top:5px; background:#000\"></div>\n\t\t\t<div style=\"width:10%; float:left; text-align:right\">\n\t\t\t\t<div style=\"float:right; margin-top:4px; width:90px; height:23px; background:url(/dojo/com/sixnet/services/widgets/templates/images/backToBasic.png) no-repeat; cursor:pointer\" hint=\"Return to standard toolbar\" dojoType=\"com.sixnet.services.widgets.HintButton\" dojoAttachPoint=\"advancedToBasicButton\">&nbsp;&nbsp;</div>\n\t\t\t\t<div dojoType=\"dijit.form.Button\" dojoAttachPoint=\"showQueryButton\" label=\"prepareQuery\" dojoAttachEvent=\"onClick:prepareQuery\"></div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	grid: {},
	searchField: '',
	queryInfo:{},
	firstRun: true,
	logicalOperators: [],
	groupingOperators: [],
	compareOperators: [],
	rowClose: [],
	numRows: 0,
	currentPlaceHolder: {},
	openLeftParen:0,
	fieldTypes:[],
	inputNodes:false,
	currentFieldSelect:{},
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.inputNodes = {};
		//  logical and grouping button arrays
		this.logicalOperators = [{label:"AND", func:"switchOnButtonClick", value:"AND"}, {label:"OR", func:"switchOnButtonClick", value:"OR"}];
		this.groupingOperators = [{label:"AND(", func:"switchOnButtonClick", value:"LEFT_PAREN_AND"}, {label:"OR(", func:"switchOnButtonClick", value:"LEFT_PAREN_OR"}, {label:"(", func:"switchOnButtonClick", value:"LEFT_PAREN"}, {label:")", func:"switchOnButtonClick", value:"RIGHT_PAREN"}, {label:")OR", func:"switchOnButtonClick", value:"RIGHT_PAREN_OR"}, {label:")AND", func:"switchOnButtonClick", value:"RIGHT_PAREN_AND"}];
		//  compare operands array, for DD
		this.compareOperators = [{label:"=", value:"EQUAL"}, {label:"!=", value:"NOT_EQUAL"}, {label:"&lt;", value:"LESS_THAN"}, {label:"&gt;", value:"GREATER_THAN"}];
		//  add row 'X' button
		this.rowClose = [{label:"&nbsp;&nbsp;", img:'/dojo/com/sixnet/services/widgets/templates/images/closeAdvancedSearch.png', func:"killRow", value:"_KILL_ROW"}];
//		dojo.subscribe("mypublishedthinger", null, function(caption, message){ alert(caption + "\n" + message); });
	},

	/* ============== sixnetAdvancedToolbar functions [a-z] ================ */
	
	queryFeedback: function(){
		
	},
	
	addAdvancedSearchBar: function(){
		var searchBarComplete = new dijit.layout.ContentPane({}).placeAt(this.advancedToolbarAttachPoint.domNode, "last");
		dojo.addClass(searchBarComplete.domNode, "advancedSearchBarComplete");
		dojo.attr(searchBarComplete.domNode, "my_row_number", this.numRows);
		dojo.attr(searchBarComplete.domNode, "field_type", "");
		var searchBar = new dijit.layout.ContentPane({style:"padding:5px; opacity:1"}).placeAt(searchBarComplete.domNode, "last");
		dojo.addClass(searchBar.domNode, "advancedSearchBar");
		this.buildFieldsDD(searchBar.domNode);
		this.buildSearchBarButtons(searchBar.domNode, this.rowClose, "closeButton");
		this.addOperatorDD(searchBar.domNode);
		var andOrParens = new dijit.layout.ContentPane({}).placeAt(searchBarComplete.domNode, "last");
		dojo.addClass(andOrParens.domNode, "advancedSearchBarAndOrParens");
		this.buildSearchBarButtons(andOrParens.domNode, this.groupingOperators, "grouping");
	//	var spacer = new dijit.layout.ContentPane({style:"width:20px"}).placeAt(andOrParens.domNode, "last");
		this.buildSearchBarButtons(andOrParens.domNode, this.logicalOperators, "logical");
		//  Fire field-selected-event here so that we start with an input of some sort
		setTimeout(dojo.hitch(this, "switchOnDDChange", this.currentFieldSelect.value, this.currentFieldSelect.domNode.nextSibling.nextSibling),0);
		//this.switchOnDDChange(this.currentFieldSelect.value, this.currentFieldSelect.domNode.nextSibling.nextSibling);
		this.numRows++;
	},
	
	addSymbolCP: function(symbol, attachNode, symbolText){
		//  handleing adding selected symbol from [ (, ), AND, OR]
		var symbolCP = new dijit.layout.ContentPane({content:symbol}).placeAt(attachNode, "last");
		dojo.attr(symbolCP.domNode, "text_value", symbolText);
		dojo.addClass(symbolCP.domNode, "symbolCP");
	},
	
	setCurrentPlaceHolder: function(current){
		this.currentPlaceHolder = current.currentTarget;
	},
	
	addOperatorDD: function(searchBarDomNode){
		var operatorDD = dojo.create("select", {}, null);
		var fieldOptions = [];
		var hasDefault = false;
		var opts = this.compareOperators;
        for(var i = 0; i < opts.length; i++){
			var opt = dojo.create("option", {value:opts[i].value, innerHTML:opts[i].label, name:opts[i].value, label:opts[i].label}, operatorDD);
        }
        var operatorSelectDD = new dijit.form.Select({style:"clear:none; width:30px;"}, operatorDD).placeAt(searchBarDomNode, "last");
		dojo.addClass(operatorSelectDD.domNode, "operatorSelectDD");
//		var parent = this;
		//                        _this was taken out in favor of adding input on field select
//		operatorSelectDD.connect(operatorSelectDD, "onChange", function(operator){
//			parent.switchOnDDChange(operator, this.domNode);
//		});
	},
	
	prepareQuery: function(){
		var completeRows = dojo.query(".advancedSearchBarComplete", this.advancedToolbarAttachPoint.domNode);
		//  completeRows:
		//   1. parent of field select, operator dropdown, and value box of some sort
		//   2. andOrParams buttons - ignore
		//   3. chosen andOrParam - we want innerHTML  TODO: Make this work.
		var advancedQuery = [];
		var parent = this;
		dojo.forEach(completeRows, function(row, i){
			var rowNumber = dojo.attr(row, "my_row_number");
			var inputNode = parent.inputNodes[rowNumber];
			var field = '';
			var operator = '';
			var value = '';
			var symbol = '';
			var end = false;
			dojo.forEach(row.childNodes, function(child){
				if(dojo.hasClass(child, "advancedSearchBar")){
					dojo.forEach(child.childNodes, function(toddler){
						if(dojo.hasClass(toddler, "fieldFilteringSelect")){
							var inputValue = dojo.query("input", dojo.byId(toddler.id));
							field = inputValue[0].value;
						}
						if(dojo.hasClass(toddler, "operatorSelectDD")){
							var inputValue = dojo.query("input", dojo.byId(toddler));
							operator = inputValue[0].value;
						}
					});
				}
				if(dojo.hasClass(child, "symbolCP")){
					_sixnet_framework.log(1, "symbol value:  ", child);
					symbol = dojo.attr(child, "text_value");
				}
				if(inputNode.value){
					value = inputNode.value;
				}else{
					if(inputNode.timeSettingsDate && inputNode.timeSettingsTime){
						value = inputNode.epoch;
					}
				}
			});
			//  add query row
			if(field != '' && operator != '' /*&& value != ''*/){
//				advancedQuery.push({field:field, operator:operator, value:value, operation:symbol});
				advancedQuery.push({type:'field', value:field, row:rowNumber});
				advancedQuery.push({type:'operator', value:operator, row:rowNumber});
				advancedQuery.push({type:'value', value:value, row:rowNumber});
				if(symbol != ""){
					advancedQuery.push({type:'operator', value:symbol, row:rowNumber});
				}
			}
		});
		_sixnet_framework.log(1, "advancedQuery data:  ", dojo.clone(advancedQuery)); //, this.builtQuery);
		var row = 0;
		advancedQuery = [
		                 {type:'field', value:'username', row:row},
		                 {type:'operator', value:'=', row:row},
		                 {type:'value', value:'ted', row:row++},

		                 {type:'operator', value:'AND', row:row++},
		                 {type:'operator', value:'(', row:row++},

		                 {type:'field', value:'username', row:row},
		                 {type:'operator', value:'=', row:row},
		                 {type:'value', value:'sted', row:row++},

		                 {type:'operator', value:'OR', row:row++},

		                 {type:'field', value:'username', row:row},
		                 {type:'operator', value:'=', row:row++},
		                 {type:'value', value:'shmed', row:row},

		                 {type:'operator', value:')', row:row++}
		                 
		                 
		                 ];
		this.compileAdvancedQuery(advancedQuery);
	},
	compileAdvancedQuery: function(queryList, once){
		// private data members 
		var lock = false;
		var compilationStack = [];
		compilationStack.top = function(){
			return compilationStack[ compilationStack.length-1];
		}
		var finalQuery = {};
		var parenthesis = [];
		var _def_prcd = [')','(','OR','AND','NOT','>','<','<>','!=','=','-','+','%','/','*'];
		if( ! _def_prcd.indexOf){
			_def_prcd.indexOf = function(value){
				for(var i = 0; i < _def_prcd.length; i++){
					if( _def_prcd[i] == value) return i;
				}
				return -1;
			}
		}
		function isOperand(value){
			return ( _def_prcd.indexOf(value) == -1);
		}
		/****************************************/
		/* Check for Precedence */
		function precedence(op1,op2){
			
			return (_def_prcd.indexOf(op1) > _def_prcd.indexOf(op2));
		}

		function infixToPostFix(infixList,postfixList){
			var current ;
			while( current = infixList.shift()){
				if(isOperand(current.value)){
					postfixList.push(current);
				}else{
					if( current.value == '('){
						// everything that follows precedes 
						compilationStack.push(current);
						continue;
					}
					if( current.value == ')'){
						while( compilationStack.length && compilationStack.top().value != '('){
							postfixList.push(compilationStack.pop());
						}
						// remove the '('
						compilationStack.pop();
						continue;
					}
					while((compilationStack.length!=0) && (precedence(compilationStack.top().value,current.value))){
						postfixList.push(compilationStack.pop());
					}

					if((compilationStack.length!=0) && (compilationStack.top().value==")")){
						compilationStack.pop();
					}else{
						compilationStack.push(current);
					}
				}
			}
			while(compilationStack.length!=0){
				postfixList.push(compilationStack.pop());
			}			
		}
		/****************************************/
		
		function advancedQueryField( queryList, current){
			compilationStack.push(current);
		}
		function advancedQueryValue( queryList, current){
			compilationStack.push(current);
		}
		function advancedQueryLP(queryList, current){
			// wrap the gathered structure in a new one.
			var rp = parenthesis.pop();
			if( !rp){
				var error = new Error("Unmatched parenthesis");
				error.current;
			}
			current.rp = rp;
			rp.lp = current;
			finalQuery = { 
					type: 'expression',
					value: finalQuery
			};
		}
		
		function advancedQueryRP(queryList, current){
			parenthesis.push(current);
		}
		
		function advancedQueryConjunction(queryList, current){
			// a conjuction requires two parameters.
			// the "right" parameter is on the stack but the "left"
			// may be the next item in the queryList or the next item
			// may be a compound statement 
		}
		
		function advancedQueryOperator(queryList, current){
			switch(current.value){ // which operator?'
			case '(': advancedQueryLP(queryList, current); break;
			case ')': advancedQueryRP(queryList, current); break;
			// conjunctions with two parameters
			case 'OR':
			case 'AND':
				advancedQueryConjunction(queryList, current); break;
			case 'NOT': 
				advancedQueryUnaryConjunction(queryList, current); break;
			// comparisons with two parameters
			default:
				advancedQueryComparison(queryList, current); break;
			}
		}
		function advancedQuerySteps( queryList){
			var current ;
			while(current = queryList.pop()){
				switch(current.type){
				case 'field': advancedQueryField(queryList, current); break;
				case 'value': advancedQueryValue(queryList, current); break;
				case 'operator': advancedQueryOperator(queryList, current); break;
				}
			}
		}
		if( lock) throw new Error("Multiple calls to the sql expression compiler");
		lock = true;
		var result = [];
		try{
		//	result = advancedQuerySteps(dojo.clone(queryList));
			infixToPostFix(dojo.clone(queryList), result);
		}catch(e){
			_sixnet_framework.log(1, e);
		}
		_sixnet_framework.log(1, 'End of step', dojo.toJson(result));
		return result;
	},
	switchOnDDChange: function(field, attachNode){
			var fs = dojo.query(".fieldFilteringSelect", attachNode.parentNode);
			var inputValue = dojo.query("input", dojo.byId(fs[0].id));
			var type = '';
			var fieldType = dojo.attr(attachNode.parentNode.parentNode, "field_type");
			var rowNumber = dojo.attr(attachNode.parentNode.parentNode, "my_row_number");
			var regex ;
			var options ;
			field = inputValue[0].value;
			//  we have field value, now determine type
			// TODO: :)
			for(var i = 0; i < this.fieldTypes.length; i++){
				if(this.fieldTypes[i].field == field){
					type = this.fieldTypes[i].type;
					if(this.fieldTypes[i].regex)regex = this.fieldTypes[i].regex;
					if(this.fieldTypes[i].options)options = this.fieldTypes[i].options;
				}
			}
			//  have type, now check if we've already place a value input node of some sort, tell next for compare
			///  if same fieldType, don't worry about new input node
			if(type != fieldType || type == "enum"){
				dojo.attr(attachNode.parentNode.parentNode, "field_type", type);
				if(regex != null)this.addValueInput(attachNode, type, rowNumber, regex);
				if(options != null)this.addValueInput(attachNode, type, rowNumber, options);
				if(regex == null && options == null)this.addValueInput(attachNode, type, rowNumber, "");
//				switch(operator){
//					case 'LESS_THAN':
//						this.addValueInput(attachNode, type, rowNumber);
//						break;
//					case 'GREATER_THAN':
//						this.addValueInput(attachNode, type, rowNumber);
//						break;
//					case 'EQUAL':
//						this.addValueInput(attachNode, type, rowNumber);
//						break;
//					case 'NOT_EQUAL':
//						this.addValueInput(attachNode, type, rowNumber);
//						break;
//				}
			}else{
				//  don't re-make, but do change regex
				if(regex != null){
					_sixnet_framework.log(1, "new regex... ", regex);
					dojo.attr(this.inputNodes[rowNumber], "regExp", regex);
				}
			}
	},
	
	addValueInput: function(attachNode, type, rowNumber, extras){
		_sixnet_framework.log(1, arguments);
		var valueInputObject = {};
		//  if fieldType is not empty then there is some sort of input already placed
		///  destroy it.
		if(this.inputNodes[rowNumber]){
			this.inputNodes[rowNumber].destroyRecursive();
		}
		switch(type){
		case 'interfaces':
			// TODO:
			break;
		case 'epocseconds':
			//  dateTime
			valueInputObject = new com.sixnet.services.widgets.dateTime({
				style: "margin-left:5px"
			}).placeAt(attachNode, "after");
			dojo.attr(attachNode.parentNode.parentNode, "value_input_class", "dateTimeWidget");
			break;
		case 'serial':
			//
			valueInputObject = new dijit.form.TextBox({
	            style: "width:100px; margin-left:5px"
	        }).placeAt(attachNode, "after");
			_sixnet_framework.log(1, valueInputObject);
			dojo.addClass(valueInputObject.domNode, "valueInput");
			break;
		case 'enum':
			//  extras == options
			var optionsDD = dojo.create("select", {}, null);
			var opts = extras;
			var hasDefault = false;
	        for(var i = 0; i < opts.length; i++){
				var opt = dojo.create("option", {value:opts[i], innerHTML:opts[i], name:opts[i], label:opts[i]}, optionsDD);
	        }
	        valueInputObject = new dijit.form.Select({style:"clear:none; width:30px;"}, optionsDD).placeAt(attachNode, "after");
//	        dojo.addClass(valueInputObject.domNode, "dijitComboBox");
	        break;
		case 'lightbar':
			valueInputObject = new dijit.form.NumberSpinner({
	            value: 0,
	            smallDelta: 10,
	            style: "width:100px; margin-left:5px"
	        }).placeAt(attachNode, "after");
			break;
		case 'alert':
			//  build an alert level color picker
			valueInputObject = new dijit.form.NumberSpinner({
	            value: 0,
	            smallDelta: 1,
	            style: "width:100px; margin-left:5px"
	        }).placeAt(attachNode, "after");
			break;
		case 'checkbox':
//			cell.formatter = "booleanCheck"; TODO:
			break;
		case 'string':
			if(extras == ""){
				valueInputObject = new dijit.form.TextBox({
		            style: "width:100px; margin-left:5px"
		        }).placeAt(attachNode, "after");
			}else{
				valueInputObject = new dijit.form.ValidationTextBox({
		            style: "width:100px; margin-left:5px",
		            regExp:extras
		        }).placeAt(attachNode, "after");
			}
			dojo.addClass(valueInputObject.domNode, "valueInput");
			dojo.attr(attachNode.parentNode.parentNode, "value_input_class", "valueInput");
			break;
		}
		this.inputNodes[rowNumber] = valueInputObject;
		_sixnet_framework.log(1, this.inputNodes, " << inputNodes");
	},
	
	killRow: function(item){
		//  scope back to parent and kill advanced query row "searchBarComplete"
		var rowNumber = dojo.attr(item.target.parentNode.parentNode.parentNode, "my_row_number");
		this.inputNodes[rowNumber] = null;
		dojo.destroy(item.target.parentNode.parentNode.parentNode);
	},	
	
	switchOnButtonClick: function(item){
		//  switch on operator-button value and react
		var target = item.target;
		var rowNumber = dojo.attr(target.parentNode.parentNode.parentNode.parentNode.parentNode, "my_row_number");
		var attachNode = target.parentNode.parentNode.parentNode.parentNode.parentNode;
		var operator = target.value;
		var operatorHTML = target.label;
		//  check if the andOrParems is already set for this row. if so destroy and continue.
		var mySymbolCP = dojo.query(".symbolCP", item.target.parentNode.parentNode.parentNode.parentNode.parentNode);
		_sixnet_framework.log(1, mySymbolCP, mySymbolCP.length, mySymbolCP[0]);
		_sixnet_framework.log(1, attachNode, rowNumber, " << attachNode");
		switch(operator){
			case "LEFT_PAREN_AND":
				if(mySymbolCP.length > 0){
					mySymbolCP[0].innerHTML = " AND ( ";
				}else{
					this.openLeftParen++;
					this.addSymbolCP(" AND ( ", attachNode, operator);
					this.addAdvancedSearchBar();
				}
				break;
			case "LEFT_PAREN_OR":
				if(mySymbolCP.length > 0){
					mySymbolCP[0].innerHTML = " OR ( ";
				}else{
					this.openLeftParen++;
					this.addSymbolCP(" OR ( ", attachNode, operator);
					this.addAdvancedSearchBar();
				}
				break;
			case 'LEFT_PAREN':
				if(mySymbolCP.length > 0){
					mySymbolCP[0].innerHTML = " ( ";
				}else{
					this.openLeftParen++;
					this.addSymbolCP(" ( ", attachNode, operator);
					this.addAdvancedSearchBar();
				}
				break;
			case "RIGHT_PAREN_AND":
				if(this.openLeftParen > 0){
					if(mySymbolCP.length > 0){
						mySymbolCP[0].innerHTML = " ) AND ";
					}else{
						this.addSymbolCP(" ) AND ", attachNode, operator);
						this.addAdvancedSearchBar();
					}
				}else{
					alert("Cannot add right-side parenthesis [ ) ] with no opening left-side [ ( ]");
				}
				break;
			case "RIGHT_PAREN_OR":
				if(this.openLeftParen > 0){
					if(mySymbolCP.length > 0){
						mySymbolCP[0].innerHTML = " ) OR ";
					}else{
						this.addSymbolCP(" ) OR ", attachNode, operator);
						this.addAdvancedSearchBar();
					}
				}else{
					alert("Cannot add right-side parenthesis [ ) ] with no opening left-side [ ( ]");
				}
				break;
			case 'RIGHT_PAREN':
				if(this.openLeftParen > 0){
					if(mySymbolCP.length > 0){
						mySymbolCP[0].innerHTML = " ) ";
						this.openLeftParen--;
					}else{
						this.addSymbolCP(" ) ", attachNode, operator);
						this.addAdvancedSearchBar();
					}
				}else{
					alert("Cannot add right-side parenthesis [ ) ] with no opening left-side [ ( ]");
				}
				break;
			case 'AND':
				if(mySymbolCP.length > 0){
					mySymbolCP[0].innerHTML = " AND ";
				}else{
					this.openLeftParen++;
					this.addSymbolCP(" AND ", attachNode, operator);
					this.addAdvancedSearchBar();
				}
				break;
			case 'OR':
				if(mySymbolCP.length > 0){
					mySymbolCP[0].innerHTML = " OR ";
				}else{
					this.openLeftParen++;
					this.addSymbolCP(" OR ", attachNode, operator);
					this.addAdvancedSearchBar();
				}
				break;
		}
	},
		
	buildSearchBarButtons: function(searchBarDomNode, buttonArray, cssClass){
		var operators = buttonArray;
		for(var i = 0; i < operators.length; i++){
			var operatorButton = new dijit.form.Button({value:operators[i].value, height:"23px", label:operators[i].label, group:i}).placeAt(searchBarDomNode, "last");
			dojo.attr(operatorButton, "MY_BUTTON_GROUP", i);
			dojo.connect(operatorButton, "onClick", this, operators[i].func);
			if(operators[i].img){
				dojo.attr(operatorButton.domNode, "innerHTML", "<img src='"+operators[i].img+"' width='23' height='23' />");
				_sixnet_framework.log(1, operators);
			}
			dojo.addClass(operatorButton.domNode, cssClass);
		}
	},

	buildFieldsDD: function(searchBarDomNode){
			_sixnet_framework.log(1, this.grid.pDescriptor['cells'], " << buildFieldsDD");
			var fieldDD = dojo.create("select", {}, null);
			var fieldOptions = [];
			var hasDefault = false;
	        for(var i = 0; i < this.grid.pDescriptor['cells'].length; i++){
				var option = this.grid.pDescriptor['cells'][i].field;
				var fieldType = this.grid.pDescriptor['cells'][i].fieldType;
				if(this.grid.pDescriptor['cells'][i].regexp){
					this.fieldTypes.push({field:option, type:fieldType, regex:this.grid.pDescriptor['cells'][i].regexp});
				}else if(this.grid.pDescriptor['cells'][i].options && fieldType == "enum"){
					this.fieldTypes.push({field:option, type:fieldType, options:this.grid.pDescriptor['cells'][i].options});
				}else{
					this.fieldTypes.push({field:option, type:fieldType});
				}
				var opt = dojo.create("option", {value:option, innerHTML:option, name:option}, fieldDD);
			}
	        var fieldFilteringSelect = new dijit.form.FilteringSelect({
	        }, fieldDD).placeAt(searchBarDomNode, "last");
	        dojo.addClass(fieldFilteringSelect.domNode, "fieldFilteringSelect");
			var parent = this;
			fieldFilteringSelect.connect(fieldFilteringSelect, "onChange", function(field){
				parent.switchOnDDChange(field, this.domNode.nextSibling.nextSibling);
			});
			//  fire once to add value
			this.currentFieldSelect = fieldFilteringSelect;
	},
	
	restrictToolbar: function(){
		/*  TESTING THIS AND NOT SEEING RESULTS??? MAKE SURE YOU AREN'T SUPER! */
		var currentPermissions = dojo.clone(_sixnet_framework._currentPermissions);
//		var rolesArray = new Array();
		currentPermissions = {
				ROLES:[
				       dojo.clone(_sixnet_framework._currentPermissions)
		]};
//		currentPermissions["ROLES"][0][this.module]
		//  here we just need the roles for said module
		for(var j=0; j<currentPermissions["ROLES"].length; j++){
			_sixnet_framework.log(3, currentPermissions["ROLES"][j][this.module], currentPermissions["ROLES"][j][this.module], " roles dude");
			//  access module
			for(role in currentPermissions["ROLES"][j][this.module]){
				_sixnet_framework.log(3, "role:  ", role, "length: ", this.editRole.length);
				//  build an indicator and/or call functions from switch per role

				//  editRole is Array, so we have to loop thru to compare to all of it
				for(var i = 0; i < this.editRole.length; i++){
					_sixnet_framework.log(3, this.editRole[i], " <<<  >>> ", role);
					if(this.editRole[i] == role){
						//  has toolbar edit role
						this.edit = true;
					}
//					if(this.viewRole == role){
//						//  has toolbar view role
//						this.view = true;
//					}
				}
			}
			if(!this.edit/* && this.view*/){
				_sixnet_framework.log(3, "edit: false");
				//  hide edit controls: +/- save/revert
				dojo.addClass( this.addButton.focusNode, "hidden");
				dojo.addClass( this.removeButton.focusNode, "hidden");
				dojo.addClass( this.saveChangesButton.focusNode, "hidden");
				dojo.addClass( this.discardChangesButton.focusNode, "hidden");
			}else if(this.edit){
				_sixnet_framework.log(3, "edit: true");
				this.dimEditButtons();
			}
		}
	},
	
	dimEditButtons: function(){
		//  dim/deactive for now the remove, save, and revert buttons
		dojo.addClass( this.removeButton.focusNode, "disabledButton");
		dojo.addClass( this.saveChangesButton.focusNode, "disabledButton");
		dojo.addClass( this.discardChangesButton.focusNode, "disabledButton");
	},
	
	hideSaveRevertButton: function(){
		dojo.addClass( this.saveChangesButton.focusNode, "disabledButton");
		dojo.addClass( this.discardChangesButton.focusNode, "disabledButton");
		this.needsSaved = false;	
	},
	
	onSaveChangesClick: function(){
		//  saves store.
		this.store.save();
		this.hideSaveRevertButton();
	},
	
	onCancelChangesClick: function(){
		//  reverts any unsaved changes on store.
		this.store.revert();
		this.hideSaveRevertButton();
	},
	
	onSearchKeyUp: function(event){
		// emulate a click on the search button when the user hits enter in the search box.
		if( event.keyCode == 13){
			this.onSearchClick();
		}
	},
	
	onCancelSearchClick: function(){
		this.searchBox.setValue('');
		this.grid.setQuery({});
	},
	
	onSearchClick: function(){
		var query = {};
		if(this.searchBox.getValue() == ""){
			query[this.searchField] = "";
		}else{
			query[this.searchField] = this.searchBox.getValue();
		}
		this.grid.setQuery(query);
	},
	
	unhideSaveRevertButton: function(){
		if( dojo.hasClass( this.saveChangesButton.focusNode, "disabledButton")){
			dojo.removeClass( this.saveChangesButton.focusNode, "disabledButton");
		}
		if( dojo.hasClass( this.discardChangesButton.focusNode, "disabledButton")){
			dojo.removeClass( this.discardChangesButton.focusNode, "disabledButton");
		}
		this.needsSaved = true;
		return;
	}
});

}

if(!dojo._hasResource["com.sixnet.services.widgets.dndComparisonSource"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.dndComparisonSource"] = true;



dojo.provide("com.sixnet.services.widgets.dndComparisonSource");

dojo.declare('com.sixnet.services.widgets.dndComparisonSource',[com.sixnet.services.widgets.dndSource], {
	fields: {},
	operators: {},
	values: {},
	dropMarkup: function(option){
		var dropComp = new com.sixnet.services.widgets.dropComparison({});
		return dropComp.domNode;
	},
	onChildDrop: function(){
		_sixnet_framework.log(1, "onChildDrop() dndComparisonSource ln.15");
	}
});

}

if(!dojo._hasResource['com.sixnet.services.widgets.sixnetQueryDnD']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.sixnetQueryDnD'] = true;
dojo.provide('com.sixnet.services.widgets.sixnetQueryDnD');
//











//dojo.require("dojo.io.script");



/*
 * sixnetQueryDnD: is drag n drop advanced query builder
 */
dojo.declare('com.sixnet.services.widgets.sixnetQueryDnD', [dijit._Widget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<style type=\"text/css\">\n\t\t/* application-specific settings */\n\t\t#status\t\t\t\t\t{font-weight: bold;}\n\t\t.container\t\t\t\t{padding: 5px; cursor: default; background: #f8f8ff;}\n\t\t.wrap1\t\t\t\t\t{float: left; clear:both; text-align:center; width: 600px; height: 70px; overflow: auto; margin-right: 1em;}\n\t\t.wrap1 div\t\t\t\t{min-height: 50px;}\n\t\t.wrap2\t\t\t\t\t{float: left; text-align:center; width: 600px; height: 200px; overflow: auto;}\n\t\t.wrap2 div\t\t\t\t{min-height: 200px;}\n\t\t.container .name\t\t{font-weight: bold; padding-right: 4px;}\n\t\t.container .image\t\t{padding: 5px;}\n\t\tbody.dojoDndCopy, body.dojoDndMove\t{color: #888;}\n\t\t.dojoDndCopy .container, .dojoDndMove .container\t{background: #ddd;}\n\t\t\n\t\t/* container-specific settings */\n\t\t.dojoDndContainer\t\t{border: 1px solid white; color: black;}\n\t\t.dojoDndContainerOver\t{border: 1px solid black; color: black;}\n\t\t.container.dojoDndTargetDisabled\t{background: #ccc; color: #888;}\n\t\t\n\t\t/* item-specific settings */\n\t\t.dojoDndItemOver\t\t{background: #feb;}\n\t\t.dojoDndItemSelected\t{border:1px solid #000;}\n\t\t.dojoDndItemAnchor\t\t{background: #ccf; color: black;}\n\t\t.dojoDndItemOver.dojoDndItemSelected\t{border:1px solid #00ff00;}\n\t\t.dojoDndItemOver.dojoDndItemAnchor\t\t{border:1px solid #ff00ff;}\n\t\t.dojoDndItemBefore\t\t{border-top:    3px solid red;}\n\t\t.dojoDndItemAfter\t\t{border-bottom: 3px solid red;}\n\t\t.dojoDndHorizontal .dojoDndItemBefore\t\t{border-top:    none;}\n\t\t.dojoDndHorizontal .dojoDndItemAfter\t\t{border-bottom: none;}\n\t\t.dojoDndHorizontal .dojoDndItemBefore img\t{border-left:  3px solid green;}\n\t\t.dojoDndHorizontal .dojoDndItemAfter img\t{border-right: 3px solid red;}\n\t</style>\n\t<script type=\"text/javascript\">\t\t\n\t\t// The main image container creator\n\t\tvar main_creator = function(item, hint){\n\t\t\tconsole.log(\"what I get in main_creator: (item, hint) \", item, hint);\n\t\t\tvar type = [item.type];\n\t\t\tvar node;\n\t\t\tif(hint == \"avatar\"){\n\t\t\t\tnode = dojo.doc.createElement(\"span\");\n\t\t\t\tnode.innerHTML = \"<img src='./images/\" + item.media.m.replace(/_m\\./, \"_s.\") + \"'/>\";\n\t\t\t}else{\n\t\t\t\tvar t = [];\n\t\t\t\tt.push(\"<img class='image' src='./images/\" + item.media.m + \"'/>\");\n\t\t\t\tnode = dojo.doc.createElement(\"span\");\n\t\t\t\tnode.innerHTML = t.join(\"\");\n\t\t\t}\n\t\t\tnode.id = dojo.dnd.getUniqueId();\n\t\t\treturn {node: node, data: item, type: type};\n\t\t};\n\t\t\n\t\t// The band image container creator\n\t\tvar band_creator = function(item, hint){\n\t\t\tvar type = [item.type];\n\t\t\tvar node = dojo.doc.createElement(\"span\");\n\t\t\tvar src = item.media.m.replace(/_m\\./, \"_s.\");\n\t\t\tif(item.type == \"compare\"){ \n\t\t\t\tnode.innerHTML = \"<img src='./images/\" + src + \"'/>\";\n\t\t\t}\n\t\t\tif(item.type == \"field\"){ \n\t\t\t\t//  build field drop down as node\n\t\t\t\tnode.innerHTML = \"<select><option value='field select'>-field select</option></select>\";\n\t\t\t}\n\t\t\tif(item.type == \"value\"){ \n\t\t\t\t//  build value-per-last field\n\t\t\t\tnode.innerHTML = \"<input type='text' />\";\n\t\t\t}\n\t\t\tnode.id = dojo.dnd.getUniqueId();\n\t\t\t//c1.selectAll().deleteSelectedNodes();\n\t\t\t//c2.selectAll().deleteSelectedNodes();\n\t\t\treturn {node: node, data: item, type: type};\n\t\t};\n\t\t\n\t\t// Flickr's JSONP function\n\t\tvar jsonFlickrFeed = function(data){\n\t\t\tif(!data.items || !data.items.length){\n\t\t\t\tdojo.byId(\"status\").innerHTML = \"Flickr didn't return any images\";\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdojo.byId(\"status\").innerHTML = data.items.length + \" images were retrieved\";\n\t\t\t// initialize sources\n\t\t\tc1.selectAll().deleteSelectedNodes();\n\t\t\tc2.selectAll().deleteSelectedNodes();\n\t\t\tc3.selectAll().deleteSelectedNodes();\n\t\t\t// populate the main source\n\t\t\tc1.insertNodes(false, data.items);\n\t\t};\n\t\t\n\t\tvar init = function(){\n\t\t\t// replace the avatar string to make it more human readable\n\t\t\tdojo.dnd.Avatar.prototype._generateText = function(){\n\t\t\t\treturn (this.manager.copy ? \"copy\" : \"mov\") + \n\t\t\t\t\t\"ing \" + this.manager.nodes.length + \" item\" + \n\t\t\t\t\t(this.manager.nodes.length != 1 ? \"s\" : \"\");\n\t\t\t};\n\t\t\t// build choices item-objs\n\t\t\tvar source = [\"less_than\", \"greater_than\", \"equal\", \"not_equal\"];\n\t\t\tvar sourceObj = [];\n\t\t\tfor(var i=0; i<source.length; i++){\n\t\t\t\tsourceObj.push({title:source[i], media:{m:source[i]+\".png\"}, type:\"compare\"});\n\t\t\t}\n\t\t\tsourceObj.push({title:\"field\", media:{m:\"field.png\"}, type:\"field\"});\n\t\t\tsourceObj.push({title:\"value\", media:{m:\"value.png\"}, type:\"value\"});\n\t\t\tconsole.log(sourceObj);\n\t\t\t// populate the main source\n\t\t\tc1.insertNodes(false, sourceObj);\n\t\t};\n\t\t\n\t\tdojo.addOnLoad(init);\n\t</script>\n<div style=\"width:600px; margin-left:auto; margin-right:auto;\">\n\t<div class=\"wrap1\">\n\t\t<div dojoType=\"dojo.dnd.Source\" jsId=\"c1\" singular=\"true\" copyOnly=\"true\" selfAccept=\"false\" accept=\"[]\" horizontal=\"true\" class=\"container\">\n\t\t\t<script type=\"dojo/method\" event=\"creator\" args=\"item, hint\">return main_creator(item, hint);</script>\n\t\t</div>\n\t</div>\n\t<div class=\"wrap2\">\n\t\t<div dojoType=\"dojo.dnd.Source\" jsId=\"c2\" accept=\"compare, grouping, field, value\" horizontal=\"true\" class=\"container\">\n\t\t\t<script type=\"dojo/method\" event=\"creator\" args=\"item, hint\">return band_creator(item, hint);</script>\n\t\t</div>\n\t</div>\n</div>\n<div style=\"float:right; clear:both\">\n<div dojoType=\"dijit.form.Button\" label=\"View Query\" dojoAttachEvent=\"onClick:orderedQuery()\"></div>\n<div dojoType=\"dijit.form.Button\" label=\"Clear Query\" dojoAttachEvent=\"onClick:clearQuery()\"></div>\n</div>\n</div>\n",
	grid: {},
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
	},
	
	orderedQuery: function(){
		// iterates in the listed order
		var container = this.c2;
		var f = this.showItem;
		obj = obj || dojo.global;
		container.getAllNodes().forEach(function(node){
			var id = node.id;
			f.call(obj, container.getItem(id), id, container);
		});
	},
	
	showItem: function(obj, item, id, container){
		advancedQuery.push({type:obj.type[0], value:obj.data});
		_sixnet_framework.log(1, advancedQuery);
	},
	
	clearQuery: function(){
		var wipeThese = dojo.query(".dojoDndItem", this.c2.domNode);
		//  cannot seem to query into only the drop/not-source container
		_sixnet_framework.log(1, "wipe: ", wipeThese, "  not these: ", dojo.query(".dojoDndItem", this.c1.domNode));
		this.c2.selectAll().deleteSelectedNodes();
	}

	/* ============== sixnetQueryDnD functions [a-z] ================ */
	
});

}

if(!dojo._hasResource["com.sixnet.services.widgets.dndValueSource"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.dndValueSource"] = true;

dojo.provide("com.sixnet.services.widgets.dndValueSource");

dojo.declare('com.sixnet.services.widgets.dndValueSource',[com.sixnet.services.widgets.dndSource], {
	dropMarkup: function(){
		var node = dojo.create('span');
		var input = new dijit.form.TextBox({}); 
		this.droppedNodes.push(input);
		node.appendChild(input.domNode);
		node.id = dojo.dnd.getUniqueId();
		return node;
	}
});



}

if(!dojo._hasResource["com.sixnet.services.widgets.dropOperands"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.dropOperands"] = true;








//dojo.require("dojo.dnd");
dojo.provide("com.sixnet.services.widgets.dropOperands");

dojo.declare('com.sixnet.services.widgets.dropOperands',[dijit._Widget, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div class=\"dijit dijitInline dijitLeft\">\n\t\t<span class=\"dojoDndHandle\"><span style=\"font-size:.6em; font-weight:bold; top:0\">\\_</span></span>\n\t\t<div dojoAttachPoint=\"operands\" class=\"dijit dijitInline dijitLeft\"></div>\n</div>\n",
	
	clear: function(){
		// remove all children
		// add a single dndDropZoneSource
	},
	
	postCreate: function(){
		// populate template nodes
//		switch(option){
//			case 'close':
//				break;
//			default:
//				this.addNodeHandle(node);
//		}
		this.operands.appendChild(this.operandsSource());
		dojo.connect(this, "onDrop", this, "onChildDrop");
	},
	
	onChildDrop: function(node){
		// build any dndDropZoneSources needed according to psuedo code.
		_sixnet_framework.log(1, "Drop comparison detects child drop event NOW WE GOT ACTION");
	},
	
	valueSource: function(){
		var node = dojo.create('span');
		var input = new dijit.form.TextBox({});
		node.appendChild(input.domNode);
		return node;
	},
	
	operandsSource: function(){
		var node = dojo.create('span');
		var select = dojo.create('select');
		dojo.forEach(["AND","OR","!OR", "!AND"], function(value){
			var option = dojo.create('option');
			option.innerHTML = value;
			option.setAttribute("value", value);
			select.appendChild( option);	
		});
		var filteringSelect = new dijit.form.Select({store:null, style:"width:50px; text-align:center"}, select);
		node.appendChild(filteringSelect.domNode);
		return node;
	},
	
	fieldSource: function(){
		//_sixnet_framework.log(1, this.grid.pDescriptor['cells'], " << buildFieldsDD");
		/*var fieldDD = dojo.create("select", {}, null);
		var fieldOptions = [];
		var hasDefault = false;
        for(var i = 0; i < this.grid.pDescriptor['cells'].length; i++){
			var option = this.grid.pDescriptor['cells'][i].field;
			var fieldType = this.grid.pDescriptor['cells'][i].fieldType;
			if(this.grid.pDescriptor['cells'][i].regexp){
				this.fieldTypes.push({field:option, type:fieldType, regex:this.grid.pDescriptor['cells'][i].regexp});
			}else if(this.grid.pDescriptor['cells'][i].options && fieldType == "enum"){
				this.fieldTypes.push({field:option, type:fieldType, options:this.grid.pDescriptor['cells'][i].options});
			}else{
				this.fieldTypes.push({field:option, type:fieldType});
			}
			var opt = dojo.create("option", {value:option, innerHTML:option, name:option}, fieldDD);
		}
        var fieldFilteringSelect = new dijit.form.FilteringSelect({
        }, fieldDD).placeAt(searchBarDomNode, "last");
        dojo.addClass(fieldFilteringSelect.domNode, "fieldFilteringSelect");
		var parent = this;
		fieldFilteringSelect.connect(fieldFilteringSelect, "onChange", function(field){
			parent.switchOnDDChange(field, this.domNode.nextSibling.nextSibling);
		});
		//  fire once to add value
		this.currentFieldSelect = fieldFilteringSelect;*/
		/// ------------------
		var node = dojo.create('span');
		var select = dojo.create('select');
		dojo.forEach(["username","email","registration_date"], function(value){
			var option = dojo.create('option');
			option.innerHTML = value;
			option.setAttribute("value", value);
			select.appendChild( option);	
		});
		var filteringSelect = new dijit.form.FilteringSelect({store:null}, select);
		node.appendChild(filteringSelect.domNode);
		return node;
	}
});

}

if(!dojo._hasResource["com.sixnet.services.widgets.dndOperandsSource"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.widgets.dndOperandsSource"] = true;



dojo.provide("com.sixnet.services.widgets.dndOperandsSource");

dojo.declare('com.sixnet.services.widgets.dndOperandsSource',[com.sixnet.services.widgets.dndSource], {
	fields: {},
	operators: {},
	values: {},
	dropMarkup: function(option){
		var dropOperands = new com.sixnet.services.widgets.dropOperands({});
		return dropOperands.domNode;
	}
});

}

if(!dojo._hasResource['com.sixnet.services.core.dashDesktop']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.core.dashDesktop'] = true;
dojo.provide('com.sixnet.services.core.dashDesktop');



dojo.declare('com.sixnet.services.core.dashDesktop', [dijit._Widget, dijit._Templated], {
	templateString:"<div>\n\t\n</div>\n",
	postCreate: function(){
	}

});

}

if(!dojo._hasResource['com.sixnet.services.core.discoverServices']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.core.discoverServices'] = true;
dojo.provide('com.sixnet.services.core.discoverServices');


dojo.declare('com.sixnet.services.core.discoverServices', [], {
	
});

}

if(!dojo._hasResource['com.sixnet.services.modules.providers.dashInstaller']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.providers.dashInstaller'] = true;
dojo.provide('com.sixnet.services.modules.providers.dashInstaller');








dojo.declare('com.sixnet.services.modules.providers.dashInstaller', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n <div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">\n \t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\"> \t\n \t\n \t\n\t<!-- File Control tab container -->\n\t<div dojoType=\"dijit.layout.TabContainer\" style=\"width:100%; height:100%; margin-right:15px\" tabStrip=\"false\" tabPosition=\"left-h\">\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\t<!-- Timeout Settings -->\n      \t<div dojoType=\"dijit.layout.ContentPane\" title=\"Timeout Settings\" selected=\"true\">\t\n      \t\t<div class=\"headerLabel\">Timeout Settings</div>\n      \t\t<div class=\"introduction\">This page contains miscellaneous settings for the site. Entries for Timeout Settings must be greater than 5 minutes.</div>\n      \t\t<div class=\"form\">\n\t      \t\t<form dojoAttachPoint=\"timeoutSettings\">\t      \t\t\n\t\t\t\t\t<div class=\"fullRow\" dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"timeoutSettingsHolder\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t\t<div class=\"inputLeft\">\n\t\t\t\t\t\t\t&nbsp;         \n\t\t\t\t\t    </div>\n\t\t\t           \t<div class=\"dashInstallerInputRight\">         \n\t\t\t           \t\t<div dojoType=\"dijit.form.Button\" label=\"Apply\" dojoAttachEvent=\"onClick:onTimeOutSettingsApply\" dojoAttachPoint=\"submitTimeSettings\">\n\t\t\t           \t\t</div>\n\t\t\t            </div>\n\t\t\t\t\t</div>           \n\t\t\t\t</form>\n\t\t\t</div>\n\t\t</div>\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t<!-- Sys Log Settings -->\n        <!--<div dojoType=\"dijit.layout.ContentPane\" title=\"Sys Log Settings\">\n        \t<div class=\"headerLabel\">Sys Log Settings</div>\n        \t<div class=\"introduction\">This page will allow/disallow certain types of units (authorized, deauthorized and banned) to log check-ins into the system log.</div>\n           \t<div class=\"form\">\n        \t<form dojoAttachPoint=\"sysLogSettings\">     \n        \t\t<div class=\"fullRow\">\n        \t\t\t<div class=\"inputLeft\">\n        \t\t\t\t<input name=\"alert\" value=\"yes\" dojoAttachEvent=\"onClick:onAlertLevelClick\" dojoType=\"dijit.form.CheckBox\" />\n        \t\t\t</div>\n        \t\t\t<div class=\"dashInstallerInputRight\">\n        \t\t\t\tAlert Messages from Authorized Units\n        \t\t\t</div>\n        \t\t</div>\n\t\t       <div class=\"fullRow\">\n\t\t\t       <div class=\"inputLeft\"> \n\t\t\t\t       &nbsp;\t\n\t\t\t       </div>\n\t\t\t       <div class=\"dashInstallerInputRight\"> \n\t\t\t       \t\tFrom level \n\t\t\t\t            <div dojoType=\"dijit.form.NumberSpinner\" dojoAttachPoint=\"alertStart\" value=\"0\" intermediatechanges=\"true\" constraints= \"{ min:0, max:7, places:0 }\" maxlength=\"1\" style=\"width:55px;font-size:1.2em\" >\n\t\t           \t\t\t</div>\n\t\t        \t\tto level \n\t\t\t\t\t\t\t<div dojoType=\"dijit.form.NumberSpinner\" dojoAttachPoint=\"alertEnd\" value=\"7\" intermediatechanges=\"true\" constraints= \"{ min:1, max:7, places:0 }\" maxlength=\"1\" style=\"width:55px;font-size:1.2em\" >\n\t\t           \t\t\t</div>\n\t\t        \t</div>\n\t\t        </div>\n\t\t        <div class=\"fullRow\">\n\t\t\t        <div class=\"inputLeft\">\n\t\t\t        </div>\n\t\t\t        <div class=\"dashInstallerInputRight\"> \n\t\t\t        \t<input disabled=\"disabled\" dojoAttachPoint=\"detailed\" name=\"summary\" value=\"detailed\" dojoType=\"dijit.form.RadioButton\" /> Detailed Description \n\t\t\t        \t<input disabled=\"disabled\" dojoAttachPoint=\"shorter\" name=\"summary\" value=\"short\" dojoType=\"dijit.form.RadioButton\" /> Short Description\n\t\t            </div>\n\t\t        </div>\n\t\t        <div class=\"fullRow\">\n\t\t            <div class=\"inputLeft\"> \n\t\t\t            <input name=\"unauth\" value=\"yes\" dojoType=\"dijit.form.CheckBox\" />\n\t\t\t        </div>\n\t\t            <div class=\"dashInstallerInputRight\">\n\t\t            \tUnauthorized Unit Check-ins.\n\t\t            </div>\n\t\t\t        <div class=\"inputLeft\"> \n\t\t\t            <input name=\"ban\" value=\"yes\" dojoType=\"dijit.form.CheckBox\" />\n\t\t            </div>\n\t\t            <div class=\"dashInstallerInputRight\"> \n\t\t            \tBanned Unit Attempted Check-ins.\n\t\t            </div>\n\t\t            \n\t            </div>\n\t            \t<div class=\"fullRow\">\n\t\t            <div class=\"inputLeft\">     \n\t\t        \t\t&nbsp;  \n\t\t            </div>\n\t\t           \t<div class=\"dashInstallerInputRight\">         \n\t\t           \t\t<div dojoType=\"dijit.form.Button\" label=\"Apply\" dojoAttachPoint=\"submitSysLogSettings\">\n\t\t           \t\t</div>\n\t\t            </div>\n\t\t        </div>\n\t            \n\t\t\t</form>\n\t\t\t</div>\n      \t</div>\n      \t-->\n      \t\n      \t\n      \t\n      \t\n      \t\n      \t\n      \t\n      \t<!-- Migrate Units -->\n        <div dojoType=\"dijit.layout.ContentPane\" title=\"Auto Clear Settings\">\n        \t<div class=\"headerLabel\">Auto Clear Settings</div>\n        \t<div class=\"form\">\n        \t<form name=\"autoClearSettings\">\n\n\t\t        <div class=\"fullRow\">\n\t\t            <div class=\"inputLeft\">         \n\t\t            \tAutomatically Clear Data Usage Counts Every\t\n\t\t            </div>\n\t\t           \t<div class=\"dashInstallerInputRight\">         \n\t\t           \t\t<div dojoType=\"dijit.form.NumberSpinner\" dojoAttachPoint=\"daysAutoClear\" value=\"1\" intermediatechanges=\"true\" constraints= \"{ min:1, max:365, places:0 }\" maxlength=\"3\" style=\"width:75px;font-size:1.2em\" >\n\t\t           \t\t</div>\n\t\t           \t\tDays\n\t\t            </div>\n\t\t        </div>\n\t\t       \t<div class=\"fullRow\">\n\t\t            <div class=\"inputLeft\">     \n\t\t        \t\t&nbsp;  \n\t\t            </div>\n\t\t           \t<div class=\"dashInstallerInputRight\">         \n\t\t           \t\t<div dojoType=\"dijit.form.Button\" label=\"Apply\" dojoAttachPoint=\"submitAutoClear\">\n\t\t           \t\t</div>\n\t\t            </div>\n\t\t        </div>\n\n\n\n\t   \t\t</form>\n\t   \t\t</div>\n        </div>\n        \n        \n        \n        \n        \n        \n        \n      \t<!-- Max Unit History -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Max Unit History\">\t<!--  closable=\"true\" -->\t\n\t\t\t<div class=\"headerLabel\">Max Unit History</div>\n\t\t\t<div class=\"form\">\n\t\t\t<form name=\"maxUnitHistory\">\n\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t            <div class=\"inputLeft\">         \n\t\t            \tMaximum Unit History\n\t\t            </div>\n\t\t           \t<div class=\"dashInstallerInputRight\">         \n\t\t           \t\t<div dojoType=\"dijit.form.NumberSpinner\" dojoAttachPoint=\"maxHistoryCount\" value=\"1\" intermediatechanges=\"true\" constraints= \"{ min:1, places:0 }\" maxlength=\"4\" style=\"width:75px;font-size:1.2em\" >\n\t\t           \t\t</div>\n\t\t           \t\tEntries\n\t\t            </div>\n\t\t        </div>\n\t\t       \t<div class=\"fullRow\">\n\t\t            <div class=\"inputLeft\">     \n\t\t        \t\t&nbsp;  \n\t\t            </div>\n\t\t           \t<div class=\"dashInstallerInputRight\">         \n\t\t           \t\t<div dojoType=\"dijit.form.Button\" label=\"Apply\" dojoAttachPoint=\"submitMaxHistory\">\n\t\t           \t\t</div>\n\t\t            </div>\n\t\t        </div>\n\t\t        \n\t\t        \n\t   \t\t</form>\n\t   \t\t</div>\n\t\t</div>\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t<!-- Critical Patches -->\n\t\t<!--\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Critical Patches\">\t\n\t\t\t<div class=\"headerLabel\">Critical Patches</div>\n\t\t\t<div class=\"introduction\">Critical Patches will be applied before other jobs/commands.<br /><br />\n\t\t\tClick on a patch to view/edit it's triggering firmware versions. </div>\n\t\t\t<div class=\"form\">\n\t\t\t<form name=\"criticalPatches\">\n\t\t\t\n\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" class=\"inputLeft\" title=\"Patches\" dojoAttachPoint=\"patchList\">\n\t\t\t\t\t</div>\n\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" class=\"dashInstallerInputRight\" title=\"Patch Info\" dojoAttachPoint=\"patchInfo\">\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"inputLeft\">\n\t\t\t\t\tPATCHES DD\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"dashInstallerInputRight\">\n\t\t\t\t\t\t<div dojoType=\"dijit.form.Button\" label=\"Add\" dojoAttachPoint=\"addCriticalPatch\"></div>\n\t\t\t\t\t\t<div dojoType=\"dijit.form.Button\" label=\"Delete\" dojoAttachPoint=\"deleteCriticalPatch\"></div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"inputLeft\">\n\t\t\t\t\t\t&nbsp;\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"dashInstallerInputRight\">\n\t\t\t\t\t\t<div dojoType=\"dijit.form.Button\" label=\"Apply\" dojoAttachPoint=\"submitCriticalPatches\"></div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\n\t\t\t\n\t\t\t</form>\n\t\t\t</div>\n\t\t</div>\n\t\t-->\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t<!-- Client Update -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Client Update\">\t<!--  closable=\"true\" -->\t\n\t\t\t<div class=\"headerLabel\">Client Update</div>\n\t\t\t\n\t\t\t<div class=\"form\">\n\t\t\t<form name=\"clientUpdate\">\n\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n        \t\t\t<div class=\"inputLeft\">\n        \t\t\t\t<input dojoAttachPoint=\"clientUpdateCheck\" dojoType=\"dijit.form.CheckBox\" />\n        \t\t\t</div>\n        \t\t\t<div class=\"dashInstallerInputRight\">\n        \t\t\t\tAutomatically update clients to latest client version\n        \t\t\t</div>\n        \t\t</div>\t\t\t\n\t   \t\t</form>\n\t   \t\t</div>\n\t\t</div>\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t<!-- GMap GPS Key -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"GMap GPS Key\">\t<!--  closable=\"true\" -->\t\n\t\t\t<div class=\"headerLabel\">Google Map GPS Key Code</div>\n\t\t\t<div class=\"introduction\">View/Set Current Google Map API Keys.</div>\n<div class=\"form\">\n\t\t\t<form name=\"gMapGPSKey\">\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"GPSgridHolder\" style=\"height:115px;width:100%\"></div>\n                <div class=\"fullRow\">\n\t\t            <div class=\"inputLeft\">Add New Google Map API Key</div>\n\t\t            <div class=\"dashInstallerInputRight\">\n\t\t            \t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"newGoogleKey\"></div>\n\t\t            </div>\n\t\t            <div class=\"inputLeft\">Server Address to Register</div>\n\t\t          \t<div class=\"dashInstallerInputRight\">\n\t\t            \t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"serverAddress\"></div>\n\t\t            </div>\n\t\t            <div class=\"inputLeft\">Current Server</div>\n\t\t          \t<div class=\"dashInstallerInputRight\">\n\t\t          \t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"font-weight:bold\" dojoAttachPoint=\"currentServer\"></div>\n\t\t          \t</div>\n\t\t        </div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t            <div class=\"inputLeft\">     \n\t\t        \t\t&nbsp;  \n\t\t            </div>\n\t\t           \t<div class=\"dashInstallerInputRight\">  \n            \t\t\t<div dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:addGoogleKeyClick\" dojoAttachPoint=\"addGoogleKey\" label=\"Add Key\"></div>\n                    </div>\n                </div>             \n\t\t\t\n\t\t\t\n\t   \t\t</form>\n\t   \t\t</div>\n\t\t</div>\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t<!-- Time Settings -->\n\t\t<!--\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Time Settings\">\n\t\t\t<div class=\"headerLabel\">Time Settings</div>\n\t\t\t<div class=\"introduction\">This displays both server time and your system time. You may synch server time to your system or manually set a different time and/or date.</div>\n\t\t\t<div class=\"form\">\n\t\t\t<form name=\"timeSettings\">\n\t\t\t\t<div class=\"fullRow\">\n\t\t            <div class=\"inputLeft\">         \n\t\t            \tServer Date/Time\n\t\t            </div>\n\t\t           \t<div class=\"dashInstallerInputRight\" style=\"font-weight:bold; font-size:11px; vertical-align:bottom; height:20px\">\n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"float:left; vertical-align:bottom; padding-right:5px;\" dojoAttachPoint=\"serverTime\">SERVER TIME</div>\n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"float:left;\" dojoAttachPoint=\"refreshServerTime\" dojoAttachEvent=\"onClick:getServerTime\"><img src=\"${moduleUrl}templates/images/refresh_icon.png\"></img></div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t            <div class=\"inputLeft\">   \n\t\t            \tLocal Date/Time\n\t\t            </div>\n\t\t            <div class=\"dashInstallerInputRight\">\n\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.widgets.dateTime\" name=\"timeSettingsDateTime\" dojoAttachPoint=\"timeSettingsDateTime\"></div>   \n\t\t\t\t\t</div>\n\t\t\t\t    \n\t\t\t\t</div>\n\t\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t        <div class=\"inputLeft\">\n\t\t\t        </div>\n\t\t\t        <div class=\"dashInstallerInputRight\"> \n\t\t\t        \t<input name=\"timeSettingsRadio\" value=\"syncToSystem\" dojoType=\"dijit.form.RadioButton\" /> Sync to System \n\t\t\t        \t<input name=\"timeSettingsRadio\" value=\"useManualDateTime\" dojoType=\"dijit.form.RadioButton\" /> Use Manual Time/Date Settings\n\t\t            </div>\n\t\t        </div>\n\t\t        <div class=\"fullRow\">\n\t\t            <div class=\"inputLeft\">     \n\t\t        \t\t&nbsp;  \n\t\t            </div>\n\t\t           \t<div class=\"dashInstallerInputRight\">         \n\t\t           \t\t<div dojoType=\"dijit.form.Button\" label=\"Apply\" dojoAttachPoint=\"submitTimeSettings\">\n\t\t           \t\t</div>\n\t\t            </div>\n\t\t        </div>\n\t   \t\t</form>\n\t   \t\t</div>\n\t\t</div> -->\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t\n\t\t</div>\n\t</div>\n\t<!-- end tab container -->\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none;\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n </div>\n</div>\n",
	dashBoard: false,
	sections: [],
	bgColors: [],
	storedDate: 0,
	storedTime: 0,
	txtColors: [],
	timeSettingsDate:{},
	timeSettingsDate:{},
	icon: 'dash2.png',
	iconPath: '',
	_clearLimit: 0,
	_maxHistory: 0,
	_timeLimits:false,
	_googleKeys:{},
	_timeOutSettings:false,
	_clientUpdate: false,
	hasTimeOutSettings: false,
	googleKeyStore:{},
	googleKeyStoreFormatter:{},
	
	postCreate: function(){
		_sixnet_framework.log(1, dojo.clone(this.hasTimeOutSettings), "  <<  hasTOS");
		this.inherited("postCreate", arguments);
		var _dashInstaller = this;
//		dojo.addOnLoad(
//				function(){
//					///setTimeout(function(){console.log(_dashInstaller.googleKeyGrid.setQuery({}), dojo.isIE, "  << googleKeyGrid/isIE************  add on load fired dashInstaller.js ~38 ");}, 3000);
//				});
		this.getColorPrefs(dojo.hitch(this, "renderTimeoutSettings"));
		this.currentServer.attr('content', window.location.host);
		this.serverAddress.attr('value', window.location.host);
		this.getGoogleKeys();
		this._timeOutSettings = [];
	//  grab via sysConfig call. this lives in access - calling from within providers
//		| TIME_LIMITS   | {"time_limits":[{"section":"unit_warning_uptime_m","limit":"120"},{"section":"unit_warning_last_update_m","limit":"490"},{"section":"unit_critical_last_update_m","limit":"960"},
//		{"section":"unit_emergency_last_update_m","limit":"1500"},{"section":"unit_critical_getjob_m","limit":"1500"},{"section":"unit_emergency_getjob_m","limit":"6000"},{"section":"cli_update","limit":"0"},{"section":"max_hist","limit":"500"},{"section":"syslog_filter","limit":""},{"section":"total_usage_clear_period","limit":"60"},{"mode":"off","target":""},{"patches":[]}]} | 
//		public function getSysConfigInfo($name, $as_json){
		//  get time limits and google keys - we have sys conf alert-level colors already [SITE_COLORS]
		_sixnet_framework.bc('access', 'getSysConfigInfo', {name:"TIME_LIMITS", as_json:true}, dojo.hitch(this, function(response){
			if( response.successful ){
				this._timeLimits = response.data.value.time_limits;
				_sixnet_framework.log(1, this._timeLimits, "  response successful, this._timeLimits");
				for(var i = 0; i < this._timeLimits.length; i++){
					var data = this._timeLimits[i];
//					_sixnet_framework.log(3, row);
//					var data = dojo.fromJson(row);
					if(data.section){ 
						switch(data.section){
							case 'unit_warning_uptime_m':
								this._timeOutSettings.push(data.limit);
								break;
							case 'unit_warning_last_update_m':
								this._timeOutSettings.push(data.limit);
								break;
							case 'unit_critical_last_update_m':
								this._timeOutSettings.push(data.limit);
								break;
							case 'unit_emergency_last_update_m':
								this._timeOutSettings.push(data.limit);
								break;
							case 'unit_critical_getjob_m':
								this._timeOutSettings.push(data.limit);
								break;
							case 'unit_emergency_getjob_m':
								this._timeOutSettings.push(data.limit);
								break;
							case 'total_usage_clear_period':
								this._clearLimit = data.limit;
								break;
							case 'max_hist':
								this._maxHistory = data.limit;
								break;
							case 'cli_update':
								if(data.limit != 0 && data.limit != "0")this._clientUpdate = true;
								break;
						}
					}
				}
				this.hasTimeOutSettings = true;
//				_sixnet_framework.log(1, this._timeLimits["unit_warning_uptime_m"]);
			}else{
				_sixnet_framework.log(1, response.error);
			}
		}));
		//this.getServerTime();
		_sixnet_framework.log(1, this.submitTimeSettings, " <<< this.submitTimeSettings");
		this.connect(this.submitTimeSettings, "onClick", dojo.hitch(this, function(){
			_sixnet_framework.log(1, "subts");
			this.onTimeOutSettingsApply();
		}));
		this.connect(this.submitAutoClear, "onClick", dojo.hitch(this, function(){
			this.updateTimeLimitsSetting('total_usage_clear_period', this.daysAutoClear.attr('value'));
		}));
		this.connect(this.submitMaxHistory, "onClick", dojo.hitch(this, function(){
			this.updateTimeLimitsSetting('max_hist', this.maxHistoryCount.attr('value'));
		}));
		this.connect(this.timeSettingsDate, "onChange", dojo.hitch(this, function(){
			_sixnet_framework.log(1, this.timeSettingsDate.value, "  <<< timeSett... change");
		}));
		this._subscribes.push( dojo.subscribe( '/status/hint', dojo.hitch(this.statusLine, "setContent")));
	},
	
	checkTimeOuts: function(valuesArray){
		var flag = true;
		for(var i = 0; i<(valuesArray.length-1); i++){
			_sixnet_framework.log(1, valuesArray[i], valuesArray[i+1]);
			if(valuesArray[i] >= valuesArray[i+1]){
				flag = false;
			}
		}
		return flag;
	},
	
	onTimeOutSettingsApply: function(){
		var timeOutNumberNodes = dojo.query(".dijitInputField", dojo.byId(this.timeoutSettingsHolder.domNode));
		//  make label array. _this will align with how we first got the info, the way the TOSet form is built, etc.
		var timeOutLabels = ['unit_warning_uptime_m', 'unit_warning_last_update_m', 'unit_critical_last_update_m', 'unit_emergency_last_update_m', 'unit_critical_getjob_m', 'unit_emergency_getjob_m'];
		var timeOutValues = [];
		for(var i = 0; i < timeOutNumberNodes.length; i++){
			timeOutValues.push(timeOutNumberNodes[i].firstChild.value);
		}
		//  check all values are acceptable, i.e. 0<1<2<3...
		if(!this.checkTimeOuts(timeOutValues)){
			alert("Each timeout setting value should be higher than the last. Settings not saved.");   
			return;
		}else{
			for(var i = 0; i<timeOutValues.length; i++){
				/// do we have labels on the form elerments?
	//			_sixnet_framework.log(1, timeOutLabels[i], "  >> ", timeOutValues[i], timeOutValues[i].value);
				//  we can assume order, so just do section::limit right on thru, or not...? is nested FOR the best way here?
				for(var j = 0; j<timeOutLabels.length; j++){
					if(this._timeLimits[i].section == timeOutLabels[j]){
						//  when reloaded, while 'value' is set from database it seems the 'defaultValue' is cached (though it is originally set with same bc call)
						//timeOutNumberNodes[i].defaultValue = timeOutValues[i];
						//  set time limit
						this._timeLimits[i].limit = timeOutValues[i];
					}
				}
			}
			var putArray = {time_limits: this._timeLimits};
			this.setSysConfig('TIME_LIMITS', putArray);
		}
	},
	
	updateTimeLimitsSetting: function(setting, value){
		_sixnet_framework.bc('access', 'getSysConfigInfo', {name:"TIME_LIMITS", as_json:true}, dojo.hitch(this, function(response){
			if( response.successful ){
				this._timeLimits = response.data.value.time_limits;
				for(var i = 0; i < this._timeLimits.length; i++){
					if(this._timeLimits[i].section == setting){
						this._timeLimits[i].limit = value;
						var putArray = {time_limits: this._timeLimits};
						this.setSysConfig('TIME_LIMITS', putArray);
					}
				}
			}
		}));
	},
	
	clientUpdateChanged: function(val){
		if(val == this._clientUpdate) return;
		//  otherwise, apply to settings
		var stringVal = '';
		if(val == false){
			stringVal = '0';
		}else if(val == true){
			stringVal = '1';
		}
		this._clientUpdate = val;
		/*
		 * cli_update   {"section":"cli_update","limit":"0"}
		 */
//		alert(this._clientUpdate);
		_sixnet_framework.bc('access', 'getSysConfigInfo', {name:"TIME_LIMITS", as_json:true}, dojo.hitch(this, function(response){
			if( response.successful ){
				this._timeLimits = response.data.value.time_limits;
				_sixnet_framework.log(3, this._timeLimits);
				for(var i = 0; i < this._timeLimits.length; i++){
					if(this._timeLimits[i].section == 'cli_update'){
						this._timeLimits[i].limit = stringVal;
						var putArray = {time_limits: this._timeLimits};
						this.setSysConfig('TIME_LIMITS', putArray);
					}
				}
			}
		}));
		// update
		//
//		| TIME_LIMITS   | {"time_limits":[{"section":"unit_warning_uptime_m","limit":"120"},{"section":"unit_warning_last_update_m","limit":"490"},
//		                                  {"section":"unit_critical_last_update_m","limit":"960"},{"section":"unit_emergency_last_update_m","limit":"1500"},{"section":"unit_critical_getjob_m","limit":"1500"},{"section":"unit_emergency_getjob_m","limit":"6000"},{"section":"cli_update","limit":"0"},{"section":"max_hist","limit":"500"},{"section":"syslog_filter","limit":""},
//		                                  {"section":"total_usage_clear_period","limit":"60"},{"mode":"off","target":""},{"patches":[]}]}  
		

		
	},
	
	setSysConfig: function(name, value){
		_sixnet_framework.bc('access', 'updateSysConfigInfo', {name:name, value:value}, dojo.hitch(this, function(response){
			if( response.successful ){
				_sixnet_framework.log(1, " update sysConf success, check db ");
			}else{
				_sixnet_framework.log(3, response.error);
			}
		}));
	},
	
	deleteItem: function(idx){
		var googleKeyStore = this.googleKeyStore;
		var googleKeys = this._googleKeys;
		var parent = this;
		var saveDone = function (){
			_sixnet_framework.log(1, googleKeyStore, googleKeys);
			_sixnet_framework.log(3, "Store saved.");
			parent.deleteGoogleKeySysConfig(idx);

			parent.googleKeyGrid.setQuery({});
		};
		var saveFailed = function (){
			_sixnet_framework.log(3, "Save failed.");
		};
		var deleteRow = function(items, request){
		    _sixnet_framework.log(1, "Delete me: " + googleKeyStore.getLabel(items[idx]));
	    	googleKeyStore.deleteItem(items[idx]);
	    	googleKeyStore.save({onComplete: saveDone, onError: saveFailed});
		};
		var request = googleKeyStore.fetch({query: {}, onComplete: deleteRow});
	},
	
	deleteGoogleKeySysConfig: function(idx){
		var newKeyArray = [];
		for(var i = 0; i < this._googleKeys.length; i++){
			_sixnet_framework.log(1, this._googleKeys[i]);
			if(idx != i){
				newKeyArray.push({key:this._googleKeys[i].key, server:this._googleKeys[i].server});
			}
		}
		var putArray = {keys: newKeyArray};
		_sixnet_framework.bc('access', 'updateSysConfigInfo', {name:'GOOGLE_KEYS', value:putArray}, dojo.hitch(this, function(response){
			if( response.successful ){
				_sixnet_framework.log(3, response.successful);
			}else{
				_sixnet_framework.log(3, response.error);
			}
		}));
	},
	
	
	getGoogleKeys: function(){
		_sixnet_framework.bc('access', 'getSysConfigInfo', {name:"GOOGLE_KEYS", as_json:true}, dojo.hitch(this, function(response){
			if( response.successful ){
				if(response.data.value){
					this._googleKeys = response.data.value.keys;
					_sixnet_framework.log(1, this._googleKeys);
					this.renderGoogleKey();
				}else{
					//  build empty store
					this._googleKeys = [{key:[""], server:["no key registered"]}];
					_sixnet_framework.log(1, this._googleKeys);
					this.renderGoogleKey();
					_sixnet_framework.log(1, "no google keys registered");
				}
			}else{
				_sixnet_framework.log(1, response.error);
			}
		}));
	},
	
	addGoogleKeyClick: function(){
//		"key":["ABQIAAAAhwq__CtXEm8BI53Fae1uJBTA_YhCpk-oV2tdByVNmpolJ9UysBRbOTAIaeSC_ZR0IP5R7qJwY0fZVA"],"server":["192.168.11.21"]
		var key = this.newGoogleKey.value;
		var server = this.serverAddress.value;
		var newKeyArray = [];
		if(key != '' && server != ''){
			var keyArrayLength = this._googleKeys.length;
			for(var i = 0; i < keyArrayLength; i++){
				_sixnet_framework.log(1, this._googleKeys[i]);
				if(this._googleKeys[i].key != "" && this._googleKeys[i].server != ""){
					newKeyArray.push({key:this._googleKeys[i].key, server:this._googleKeys[i].server});
				}
			}
			_sixnet_framework.log(1, newKeyArray.push({key:[key], server:[server]}));
			this._googleKeys = newKeyArray;
		}
		//  now add it in!
		var putArray = {keys: newKeyArray};
//		GOOGLE_KEYS   | {"keys":[{"key":"ABQIAAAAV678fyVNf7SOq_SmHkklHhT1VEXEoATRvv3QjT4F7CH0WtUovRSw9kg7S0a7lh5hwmLYq5FlTRaU0A","server":"http:\/\/75.9.229.178:18080"},{"key":"ABQIAAAAuFHe9G7rS9xX1VGfqcWSMBT_zGARci_0VsYSwUL8MNULm2IaXhR-qqlyhxTWAHiD-lHGYzwVIsZ4mQ","server":"http:\/\/www.mygmu.com:18080"},{"key":"ABQIAAAAuFHe9G7rS9xX1VGfqcWSMBS-hJEL57iB1FUQ_1y2SHXg_uiWKhTRRkoD0vCf85VLV63F4sPHckRu0A","server":"http:\/\/mygmu.com:18080"},{"key":"ABQIAAAAhwq__CtXEm8BI53Fae1uJBRi_j0U6kJrkFvY4-OX2XYmEAa76BSCEe_cu-3BGSyhviQqgphj7zWx-g","server":"127.0.0.1"}]}   
		_sixnet_framework.bc('access', 'updateSysConfigInfo', {name:'GOOGLE_KEYS', value:putArray}, dojo.hitch(this, function(response){
			if( response.successful ){
				this.googleKeyStore.newItem({key:key, server:server});
				this.googleKeyGrid.setQuery({});
			}else{
				_sixnet_framework.log(3, response.error);
			}
		}));
	},
	
//	getServerTime: function(){
//		_sixnet_framework.bc('access', 'getServerTime', {}, dojo.hitch(this, function(response){
//			if( response.successful ){
//				var date = new Date(response.data*1000);
//				var formattedDate = dojo.date.locale.format(date, {datePattern:'MM/dd/y ', timePattern:'hh:mm:ss Z'});
//				this.serverTime.attr("content", formattedDate);
//			}else{
//				_sixnet_framework.log(3, response.error);
//			}
//		}));
//	},
	
	onAlertLevelClick: function(){
		//  enable radio buttons
		_sixnet_framework.log(3, this.detailed.attr("disabled"));
		if(this.detailed.attr("disabled")){
			this.detailed.attr({disabled:false});
			this.detailed.attr({checked:true});
			this.shorter.attr({disabled:false});
		}else{
			this.detailed.attr({disabled:true});
			this.detailed.attr({checked:false});
			this.shorter.attr({disabled:true});
		}
	},
	
	getColorPrefs: function(onComplete){
		// like getCustomView!
		var bgColors = new Array();
		var txtColors = new Array();
		var sections = new Array();
		_sixnet_framework.bc('access', 'getColorPreferences', {}, dojo.hitch(this, function(response){
			if( response.successful ){
				if(response.data.clrpref){
					//  if we have a clrpref, then apply it
					//  set this.update to true because we are going to update existing on Save
					this.update = true;
					var clrP = response.data.clrpref;
					for(var i=0; i<clrP.colors.length; i++){
						//  Here we fill color arrays w/ user specified colors
						bgColors.push(clrP.colors[i].background);
						txtColors.push(clrP.colors[i].color);
						sections.push(clrP.colors[i].section);
					}
					this.bgColors = bgColors;
					this.txtColors = txtColors;
					this.sections = sections;
					_sixnet_framework.log(3, bgColors, txtColors);
					onComplete();
				}else{
					//  we have a successful try, but no info - so, get default from sixnet_config
					_sixnet_framework.bc('access', 'getSysConfigInfo', {name:'STATUS_COLORS', as_json:true}, dojo.hitch(this, function(response){
						if( response.successful ){
							_sixnet_framework.log(3, "success!  :  ", response);
							if(response.data.value){
								//  we got STATUS_COLORS
								var clrP = response.data.value;

								_sixnet_framework.log(3, " herehere ", clrP);
								for(var i=0; i<clrP.colors.length; i++){
									//  Here we fill color arrays w/ user specified colors
									bgColors.push(clrP.colors[i].background);
									txtColors.push(clrP.colors[i].color);
									sections.push(clrP.colors[i].section);
								}
								this.bgColors = bgColors;
								this.txtColors = txtColors;
								this.sections = sections;
								_sixnet_framework.log(3, bgColors, txtColors, this.bgColors, " this bg");
								onComplete();							
							}
						}					
					}));
				}
			}
		}));
	},
	
	renderTimeoutSettings: function(){
		if(this.hasTimeOutSettings){
			var outputObj = new dijit.layout.ContentPane({
				}).placeAt(dojo.byId(this.timeoutSettingsHolder.domNode), "last");
	        var settingLabels = new Array("Uptime Warning", "Last Update Warning", "Last Update Critical", "Last Update Emergency", "Get Job Critical", "Get Job Emergency");
	        var settingMessages = new Array("Enter the number of <b>minutes</b> which will determine when to colorize a units uptime<br />entry to the <b>Warning</b> color.<br />If 120 is entered, then a unit with an uptime of <b>less than 120 minutes</b><br /> will have it's <b>Uptime</b> color marked. <b><i>This value must be greater than 5.</b></i><br />This field can help identify recently rebooted units.",
	        		"Enter the number of <b>minutes</b> which will determine when to colorize a units last update<br />entry to the <b>Warning</b> color.<br />If 120 is entered, then a unit which has not sent an update for <b>more than 120 minutes</b><br /> will have it's <b>Last Update</b> color marked. <b><i>This value must be greater than 5</b></i>.<br />This value should NOT be less than the checkin interval specified for edge units.",
	        		"Enter the number of <b>minutes</b> which will determine when to colorize a units last update<br />entry to the <b>Critical</b> color.<br />If 480 is entered, then a unit which has not sent an update for <b>more than 480 minutes</b><br /> will have it's <b>Last Update</b> color marked. <b><i>This value must be greater than the value entered for Last Update Warning</b></i>.",
	        		"Enter the number of <b>minutes</b> which will determine when to colorize a units last update<br />entry to the <b>Emergency</b> color.<br />If 1500 is entered, then a unit which has not sent an update for <b>more than 1500 minutes</b><br /> will have it's <b>Last Update</b> color marked.<br /><b><i>This value must be greater than the value entered for Last Update Critical</b></i>.",
	        		"Enter the number of <b>minutes</b> which will determine when to colorize a JOB's <b>Critical</b> color.<br />If 1500 is entered, then a file job which has not been sent to a unit <b>more than 1500 minutes (about 25 hours)</b><br /> will have it's <b>Pending Job</b> color marked.<br /><b><i>This value must be less than the value entered for the Get Job Emergency color entry</b></i>.",
	        		"Enter the number of <b>minutes</b> which will determine when to colorize a JOB's <b>Emergency</b> color.<br />If 6000 is entered, then a file job which has not been sent to a unit <b>more than 6000 minutes (about 4 days)</b><br /> will have it's <b>Pending Job</b> color marked.<br /><b><i>This value must be greater than the value entered for the Get Job Critical color entry</b></i>.");
	        //"Enter the maximum number of history <b>entries</b> allowed for each unit.","Key provided by Google to use the Maps API.","The server the Google Maps Key is associated with.","Current address of GMU server. If this does not match the \'Server Address Registered\' value, you must acquire a new Google GPS key for this server.","1. Copy \"Current Server:\" server address given.<br><br>2. Click \"Google API Key Sign-up\" link for registration page.<br><br>3. Paste the server address recorded earlier in the \"My Web site URL:\" input box.<br><br>4. Click agree to terms check box and then click the \"Generate API Key\" button.<br><br>5. Copy the key at top of the Google Map API page and return to this \"Other Settings\" page.<br><br>6. Paste the key into the \"Google Maps Key\" input box.<br><br>7. Input the server address recorded earlier in the \"Server Address Registered\" input box.<br><br>8. Click \"Submit Changes\" button and you should be good to go.","This sets how often a unit's wireless usage will roll to 0",""
	        var settingDefaults = this._timeOutSettings;
	         
	        for(var i = 0; i < settingLabels.length; i++){
	        	//  create cp for row
	        	
	        	var leftHalfHolderCP = new dijit.layout.ContentPane({});
	        	var leftHalfContentCP = new dijit.layout.ContentPane({content:settingLabels[i], style:"cursor:pointer"});
	        	//  attach tooltip
	        	var tt = new dijit.Tooltip({
	        		connectId:[dojo.byId(leftHalfContentCP.domNode)],
	        		label:settingMessages[i]
	        	}).placeAt(dojo.byId(leftHalfHolderCP.domNode), "last");
	        	var bg = '';
	        	var clr = '';
	        	//  find match by keyword (section), i.e section[Warning] == settingLabel[Update Warning]
	            for(var j = 0; j < this.sections.length; j++){
	            	if(settingLabels[i].match(this.sections[j])){
	            		bg = this.bgColors[j];
	            		clr = this.txtColors[j];
	//            		_sixnet_framework.log(3, "colors:  ", bg, clr);
	            	}
	            }
	            leftHalfContentCP.attr("style", {background:bg, color:clr, padding:"3px", fontWeight:"bold"});
	    		dojo.addClass(leftHalfHolderCP.domNode, "inputLeft");
	        	_sixnet_framework.log(1, "am i getting defaults coming in the second run of this module?: ", settingDefaults[i]);
	        	// left half	        	
	        	leftHalfContentCP.placeAt(dojo.byId(leftHalfHolderCP.domNode), "last");
	        	leftHalfHolderCP.placeAt(dojo.byId(outputObj.domNode), "last");
	        	// right half
	        	var rightHalfHolderCP =  new dijit.layout.ContentPane({});
	        	var rightSpinnerCP = new dijit.form.NumberSpinner({value:settingDefaults[i], style:"float:left; clear:right; text-align:left; width:80px;", constraints:{ min:5, places:0 }});
	        	rightHalfHolderCP.attr("style", {padding:"3px", fontWeight:"bold"});

	        	dojo.addClass(rightHalfHolderCP.domNode, "dashInstallerInputRight");
	        	rightSpinnerCP.placeAt(dojo.byId(rightHalfHolderCP.domNode), "last");
	        	rightHalfHolderCP.placeAt(dojo.byId(outputObj.domNode), "last");
	        }
	        outputObj.startup();
	        // now set auto clear and max history, and check client update
//	        dijit.byId('dijit_form_NumberSpinner_3').attr('value', 50);
	        dijit.byId(this.daysAutoClear).attr('value', this._clearLimit);
	        dijit.byId(this.maxHistoryCount).attr('value', this._maxHistory);
//	        dijit.byId(this.maxHistoryCount.valueNode).attr('value', this._maxHistory);
	        dijit.byId(this.clientUpdateCheck).attr('checked', this._clientUpdate);
			this.connect(this.clientUpdateCheck, "onChange", dojo.hitch(this, function(val){
//				_sixnet_framework.log(1, val, "  <<< timeSett... change");
				this.clientUpdateChanged(val);
			}));
		}else{
			//  this is to handle the case the settings are not loaded yet
			setTimeout(dojo.hitch(this,"renderTimeoutSettings"),100);
		}
	},
	
	
	renderGoogleKey: function(){
		//  Google API key set-up
		this.googleInfo = { 
				identifier: 'key',
				   items: this._googleKeys
		};
		_sixnet_framework.log(1, this.googleInfo, "  googleKeys");
		var googleKeyGridDesc = {
				cells:[
	         		{ name: 'Server URL', hidden: false, field: 'server', width: '30%'},
	         		{ name: 'Associated Key', hidden: false, editable: true, field: 'key', formatter:'shrinkKey', width: '50%'},
	         		{ name: '', hidden:false, formatter:'deleteKey', width: '20%'}
	     ]};//
		this.googleKeyStore = new dojo.data.ItemFileWriteStore({data: this.googleInfo});

		this.googleKeyGrid = new dojox.grid.DataGrid({
			query:{},
			store:this.googleKeyStore,
			editable: true,
			structure:googleKeyGridDesc
		});//, document.createElement('div');
		this.googleKeyStoreFormatter = new com.sixnet.services.modules.access.formatters({grid:this.googleKeyGrid, store:this.googleKeyStore});

		this.googleKeyStoreFormatter.setSettingsInstall(this);
		this.googleKeyGrid.attr({
			formatterScope:this.googleKeyStoreFormatter,
			style: "width:100%; height:100%"
		});
//		this.googleKeyGrid.setStructure(googleKeyGridDesc);
		this.googleKeyGrid.placeAt(this.GPSgridHolder.domNode, "last");
		this.googleKeyGrid.startup();
		//  we want the user to be able to grab the key
		//  TODO: for some reason this was unable to drop and paste from userManager... not seeing event
		//        even though "arguments" clearly shows the event is a double click and function fires... 
		//		  cannot grab rowItem!
		this.connect(this.googleKeyGrid,"onDblClick", dojo.hitch(this, "onRowDblClick"));
		//
	},
	
	
	
	onShow: function(){
	},
	
	onHide: function(){
	},
	
	onRowDblClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
//		var rowItem = this.unitGrid.grid.getItem( event.rowIndex);
		var rowItem = this.googleKeyGrid.getItem( event.rowIndex);
		this.unit = rowItem;
		_sixnet_framework.log(1, "unit set:  ", this.unit);
		var message = "";
		if(!event.cell.editable){
			message = "This cell is not editable";
		}
		dojo.publish( '/status/hint', [message]);
	},

	onClick: function(){
		this.dashBoard.showDashWidgets();
		this.destroyRecursive();
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.providers.dash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.providers.dash'] = true;
dojo.provide('com.sixnet.services.modules.providers.dash');




dojo.declare('com.sixnet.services.modules.providers.dash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.providers',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/settingsDash.png\"></img>\n</div>\n",
	dashBoard: false,
	
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){
		//this.dashBoard.startedWorking();
		_sixnet_framework.bc('providers','getInstallMode', {}, dojo.hitch(this, function(response){
			//this.dashBoard.stoppedWorking();
			if( !response.successful){
				alert('Could not determine the install mode. Aborting.');
				
				return;
			}
			_sixnet_framework.log(1, "dash.js  >> response:  ", response.data);
			if( response.data == 'preinstall'){
				this.dashBoard.runApp('com.sixnet.services.modules.providers.dashInstaller');
			}else{
				this.dashBoard.runApp( 'com.sixnet.services.modules.providers.dashInstaller');	
			}
			
		}));
		
	}
		
});

}

if(!dojo._hasResource["com.sixnet.services.modules.unit.searchCheckBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.modules.unit.searchCheckBox"] = true;
dojo.provide("com.sixnet.services.modules.unit.searchCheckBox");



dojo.declare("com.sixnet.services.modules.unit.searchCheckBox",[dijit._Widget, dijit._Templated],{
	widgetsInTemplate: true,
	templateString: dojo.cache("com.sixnet.services.modules.unit", "templates/searchCheckBox.html", "<div style=\"float:right; width:150px; margin-top:.5em\">\n\t\t<div\n\t\t\tstyle=\"float:right\"\n\t\t\tdojoType=\"dijit.form.CheckBox\"\n\t\t\tdojoAttachEvent=\"onChange: _onChange\"\n\t\t\tdojoAttachPoint=\"checkBox\" >\n\t\t</div>\n\t\t<div \n\t\t\tstyle=\"height:100%; text-align:right\"\n\t\t\tdojoType=\"dijit.layout.ContentPane\" \n\t\t\tdojoAttachPoint=\"labelPane\"\n\t\t\t >This is the dummy label\n\t\t</div>\n</div>\n"),
	_queryHandle: null,
	checkedValue: 'TRUE',
	unCheckedValue: 'FALSE',
	fieldLabel:'',
	grid: null,
	fieldName: '',
	postCreate: function(){
		this.inherited(arguments);
		// move this widget to the toolbar
		if(this.fieldLabel == ''){
			this.fieldLabel = this.fieldName;
		}
		this._queryHandle = this.grid.makeQueryHandle();
		this.checkBox.attr("checked", true);
		this.labelPane.setContent(this.fieldLabel + ": ");
		this.grid.addToToolbar(this, 'right');
		this._onChange();
	},
	_onChange: function(){
		this._queryHandle.setQuery({
			left_field: this.fieldName,
			operator: '=',
			right_value: this.getValue()
		});
	},
	getValue: function(){
		if( this.checkBox.attr("checked")){
			return this.checkedValue;
		}else{
			return this.unCheckedValue;
		}
	}
});

}

if(!dojo._hasResource["dijit.form._Spinner"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form._Spinner"] = true;
dojo.provide("dijit.form._Spinner");



dojo.declare(
	"dijit.form._Spinner",
	dijit.form.RangeBoundTextBox,
	{
		// summary:
		//		Mixin for validation widgets with a spinner.
		// description:
		//		This class basically (conceptually) extends `dijit.form.ValidationTextBox`.
		//		It modifies the template to have up/down arrows, and provides related handling code.

		// defaultTimeout: Number
		//		Number of milliseconds before a held arrow key or up/down button becomes typematic
		defaultTimeout: 500,

		// minimumTimeout: Number
		//       minimum number of milliseconds that typematic event fires when held key or button is held
		minimumTimeout: 10,

		// timeoutChangeRate: Number
		//		Fraction of time used to change the typematic timer between events.
		//		1.0 means that each typematic event fires at defaultTimeout intervals.
		//		< 1.0 means that each typematic event fires at an increasing faster rate.
		timeoutChangeRate: 0.90,

		// smallDelta: Number
		//	  Adjust the value by this much when spinning using the arrow keys/buttons
		smallDelta: 1,

		// largeDelta: Number
		//	  Adjust the value by this much when spinning using the PgUp/Dn keys
		largeDelta: 10,

		templateString: dojo.cache("dijit.form", "templates/Spinner.html", "<div class=\"dijit dijitReset dijitInlineTable dijitLeft\"\n\tid=\"widget_${id}\" waiRole=\"presentation\"\n\t><div class=\"dijitReset dijitButtonNode dijitSpinnerButtonContainer\"\n\t\t><input class=\"dijitReset dijitInputField dijitSpinnerButtonInner\" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t\t/><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitUpArrowButton\"\n\t\t\tdojoAttachPoint=\"upArrowNode\"\n\t\t\t><div class=\"dijitArrowButtonInner\"\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9650;\" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t\t\t\t\t${_buttonInputDisabled}\n\t\t\t/></div\n\t\t></div\n\t\t><div class=\"dijitReset dijitLeft dijitButtonNode dijitArrowButton dijitDownArrowButton\"\n\t\t\tdojoAttachPoint=\"downArrowNode\"\n\t\t\t><div class=\"dijitArrowButtonInner\"\n\t\t\t\t><input class=\"dijitReset dijitInputField\" value=\"&#9660;\" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t\t\t\t\t${_buttonInputDisabled}\n\t\t\t/></div\n\t\t></div\n\t></div\n\t><div class='dijitReset dijitValidationContainer'\n\t\t><input class=\"dijitReset dijitInputField dijitValidationIcon dijitValidationInner\" value=\"&Chi; \" type=\"text\" tabIndex=\"-1\" readOnly waiRole=\"presentation\"\n\t/></div\n\t><div class=\"dijitReset dijitInputField dijitInputContainer\"\n\t\t><input class='dijitReset dijitInputInner' dojoAttachPoint=\"textbox,focusNode\" type=\"${type}\" dojoAttachEvent=\"onkeypress:_onKeyPress\"\n\t\t\twaiRole=\"spinbutton\" autocomplete=\"off\" ${!nameAttrSetting}\n\t/></div\n></div>\n"),

		baseClass: "dijitTextBox dijitSpinner",

		// Set classes like dijitUpArrowButtonHover or dijitDownArrowButtonActive depending on
		// mouse action over specified node
		cssStateNodes: {
			"upArrowNode": "dijitUpArrowButton",
			"downArrowNode": "dijitDownArrowButton"
		},

		adjust: function(/* Object */ val, /*Number*/ delta){
			// summary:
			//		Overridable function used to adjust a primitive value(Number/Date/...) by the delta amount specified.
			// 		The val is adjusted in a way that makes sense to the object type.
			// tags:
			//		protected extension
			return val;
		},

		_arrowPressed: function(/*Node*/ nodePressed, /*Number*/ direction, /*Number*/ increment){
			// summary:
			//		Handler for arrow button or arrow key being pressed
			if(this.disabled || this.readOnly){ return; }
			this._setValueAttr(this.adjust(this.get('value'), direction*increment), false);
			dijit.selectInputText(this.textbox, this.textbox.value.length);
		},

		_arrowReleased: function(/*Node*/ node){
			// summary:
			//		Handler for arrow button or arrow key being released
			this._wheelTimer = null;
			if(this.disabled || this.readOnly){ return; }
		},

		_typematicCallback: function(/*Number*/ count, /*DOMNode*/ node, /*Event*/ evt){
			var inc=this.smallDelta;
			if(node == this.textbox){
				var k=dojo.keys;
				var key = evt.charOrCode;
				inc = (key == k.PAGE_UP || key == k.PAGE_DOWN) ? this.largeDelta : this.smallDelta;
				node = (key == k.UP_ARROW || key == k.PAGE_UP) ? this.upArrowNode : this.downArrowNode;
			}
			if(count == -1){ this._arrowReleased(node); }
			else{ this._arrowPressed(node, (node == this.upArrowNode) ? 1 : -1, inc); }
		},

		_wheelTimer: null,
		_mouseWheeled: function(/*Event*/ evt){
			// summary:
			//		Mouse wheel listener where supported

			dojo.stopEvent(evt);
			// FIXME: Safari bubbles

			// be nice to DOH and scroll as much as the event says to
			var scrollAmount = evt.detail ? (evt.detail * -1) : (evt.wheelDelta / 120);
			if(scrollAmount !== 0){
				var node = this[(scrollAmount > 0 ? "upArrowNode" : "downArrowNode" )];

				this._arrowPressed(node, scrollAmount, this.smallDelta);

				if(!this._wheelTimer){
					clearTimeout(this._wheelTimer);
				}
				this._wheelTimer = setTimeout(dojo.hitch(this,"_arrowReleased",node), 50);
			}

		},

		postCreate: function(){
			this.inherited(arguments);

			// extra listeners
			this.connect(this.domNode, !dojo.isMozilla ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
			this._connects.push(dijit.typematic.addListener(this.upArrowNode, this.textbox, {charOrCode:dojo.keys.UP_ARROW,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
			this._connects.push(dijit.typematic.addListener(this.downArrowNode, this.textbox, {charOrCode:dojo.keys.DOWN_ARROW,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
			this._connects.push(dijit.typematic.addListener(this.upArrowNode, this.textbox, {charOrCode:dojo.keys.PAGE_UP,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
			this._connects.push(dijit.typematic.addListener(this.downArrowNode, this.textbox, {charOrCode:dojo.keys.PAGE_DOWN,ctrlKey:false,altKey:false,shiftKey:false,metaKey:false}, this, "_typematicCallback", this.timeoutChangeRate, this.defaultTimeout, this.minimumTimeout));
		}
});

}

if(!dojo._hasResource["dijit.form.NumberTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.NumberTextBox"] = true;
dojo.provide("dijit.form.NumberTextBox");




/*=====
dojo.declare(
	"dijit.form.NumberTextBox.__Constraints",
	[dijit.form.RangeBoundTextBox.__Constraints, dojo.number.__FormatOptions, dojo.number.__ParseOptions], {
	// summary:
	//		Specifies both the rules on valid/invalid values (minimum, maximum,
	//		number of required decimal places), and also formatting options for
	//		displaying the value when the field is not focused.
	// example:
	//		Minimum/maximum:
	//		To specify a field between 0 and 120:
	//	|		{min:0,max:120}
	//		To specify a field that must be an integer:
	//	|		{fractional:false}
	//		To specify a field where 0 to 3 decimal places are allowed on input,
	//		but after the field is blurred the value is displayed with 3 decimal places:
	//	|		{places:'0,3'}
});
=====*/

dojo.declare("dijit.form.NumberTextBoxMixin",
	null,
	{
		// summary:
		//		A mixin for all number textboxes
		// tags:
		//		protected

		// Override ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
		// than a straight regexp to deal with locale (plus formatting options too?)
		regExpGen: dojo.number.regexp,

		/*=====
		// constraints: dijit.form.NumberTextBox.__Constraints
		//		Despite the name, this parameter specifies both constraints on the input
		//		(including minimum/maximum allowed values) as well as
		//		formatting options like places (the number of digits to display after
		//		the decimal point).   See `dijit.form.NumberTextBox.__Constraints` for details.
		constraints: {},
		======*/

		// value: Number
		//		The value of this NumberTextBox as a Javascript Number (i.e., not a String).
		//		If the displayed value is blank, the value is NaN, and if the user types in
		//		an gibberish value (like "hello world"), the value is undefined
		//		(i.e. attr('value') returns undefined).
		//
		//		Symmetrically, attr('value', NaN) will clear the displayed value,
		//		whereas attr('value', undefined) will have no effect.
		value: NaN,

		// editOptions: [protected] Object
		//		Properties to mix into constraints when the value is being edited.
		//		This is here because we edit the number in the format "12345", which is
		//		different than the display value (ex: "12,345")
		editOptions: { pattern: '#.######' },

		/*=====
		_formatter: function(value, options){
			// summary:
			//		_formatter() is called by format().   It's the base routine for formatting a number,
			//		as a string, for example converting 12345 into "12,345".
			// value: Number
			//		The number to be converted into a string.
			// options: dojo.number.__FormatOptions?
			//		Formatting options
			// tags:
			//		protected extension

			return "12345";		// String
		},
		 =====*/
		_formatter: dojo.number.format,

		_setConstraintsAttr: function(/* Object */ constraints){
			var places = typeof constraints.places == "number"? constraints.places : 0;
			if(places){ places++; } // decimal rounding errors take away another digit of precision
			if(typeof constraints.max != "number"){
				constraints.max = 9 * Math.pow(10, 15-places);
			}
			if(typeof constraints.min != "number"){
				constraints.min = -9 * Math.pow(10, 15-places);
			}
			this.inherited(arguments, [ constraints ]);
			if(this.focusNode && this.focusNode.value && !isNaN(this.value)){
				this.set('value', this.value);
			}
		},

		_onFocus: function(){
			if(this.disabled){ return; }
			var val = this.get('value');
			if(typeof val == "number" && !isNaN(val)){
				var formattedValue = this.format(val, this.constraints);
				if(formattedValue !== undefined){
					this.textbox.value = formattedValue;
				}
			}
			this.inherited(arguments);
		},

		format: function(/*Number*/ value, /*dojo.number.__FormatOptions*/ constraints){
			// summary:
			//		Formats the value as a Number, according to constraints.
			// tags:
			//		protected

			var formattedValue = String(value);
			if(typeof value != "number"){ return formattedValue; }
			if(isNaN(value)){ return ""; }
			// check for exponential notation that dojo.number.format chokes on
			if(!("rangeCheck" in this && this.rangeCheck(value, constraints)) && constraints.exponent !== false && /\de[-+]?\d/i.test(formattedValue)){
				return formattedValue;
			}
			if(this.editOptions && this._focused){
				constraints = dojo.mixin({}, constraints, this.editOptions);
			}
			return this._formatter(value, constraints);
		},

		/*=====
		parse: function(value, constraints){
			// summary:
			//		Parses the string value as a Number, according to constraints.
			// value: String
			//		String representing a number
			// constraints: dojo.number.__ParseOptions
			//		Formatting options
			// tags:
			//		protected

			return 123.45;		// Number
		},
		=====*/
		parse: dojo.number.parse,

		_getDisplayedValueAttr: function(){
			var v = this.inherited(arguments);
			return isNaN(v) ? this.textbox.value : v;
		},

		filter: function(/*Number*/ value){
			// summary:
			//		This is called with both the display value (string), and the actual value (a number).
			//		When called with the actual value it does corrections so that '' etc. are represented as NaN.
			//		Otherwise it dispatches to the superclass's filter() method.
			//
			//		See `dijit.form.TextBox.filter` for more details.
			return (value === null || value === '' || value === undefined) ? NaN : this.inherited(arguments); // attr('value', null||''||undefined) should fire onChange(NaN)
		},

		serialize: function(/*Number*/ value, /*Object?*/options){
			// summary:
			//		Convert value (a Number) into a canonical string (ie, how the number literal is written in javascript/java/C/etc.)
			// tags:
			//		protected
			return (typeof value != "number" || isNaN(value)) ? '' : this.inherited(arguments);
		},

		_setValueAttr: function(/*Number*/ value, /*Boolean?*/ priorityChange, /*String?*/formattedValue){
			// summary:
			//		Hook so attr('value', ...) works.
			if(value !== undefined && formattedValue === undefined){
				formattedValue = String(value);
				if(typeof value == "number"){
					if(isNaN(value)){ formattedValue = '' }
					// check for exponential notation that dojo.number.format chokes on
					else if(("rangeCheck" in this && this.rangeCheck(value, this.constraints)) || this.constraints.exponent === false || !/\de[-+]?\d/i.test(formattedValue)){
						formattedValue = undefined; // lets format comnpute a real string value
					}
				}else if(!value){ // 0 processed in if branch above, ''|null|undefined flow thru here
					formattedValue = '';
					value = NaN;
				}else{ // non-numeric values
					value = undefined;
				}
			}
			this.inherited(arguments, [value, priorityChange, formattedValue]);
		},

		_getValueAttr: function(){
			// summary:
			//		Hook so attr('value') works.
			//		Returns Number, NaN for '', or undefined for unparsable text
			var v = this.inherited(arguments); // returns Number for all values accepted by parse() or NaN for all other displayed values

			// If the displayed value of the textbox is gibberish (ex: "hello world"), this.inherited() above
			// returns NaN; this if() branch converts the return value to undefined.
			// Returning undefined prevents user text from being overwritten when doing _setValueAttr(_getValueAttr()).
			// A blank displayed value is still returned as NaN.
			if(isNaN(v) && this.textbox.value !== ''){
				if(this.constraints.exponent !== false && /\de[-+]?\d/i.test(this.textbox.value) && (new RegExp("^"+dojo.number._realNumberRegexp(dojo.mixin({}, this.constraints))+"$").test(this.textbox.value))){	// check for exponential notation that parse() rejected (erroneously?)
					var n = Number(this.textbox.value);
					return isNaN(n) ? undefined : n; // return exponential Number or undefined for random text (may not be possible to do with the above RegExp check)
				}else{
					return undefined; // gibberish
				}
			}else{
				return v; // Number or NaN for ''
			}
		},

		isValid: function(/*Boolean*/ isFocused){
			// Overrides dijit.form.RangeBoundTextBox.isValid to check that the editing-mode value is valid since
			// it may not be formatted according to the regExp vaidation rules
			if(!this._focused || this._isEmpty(this.textbox.value)){
				return this.inherited(arguments);
			}else{
				var v = this.get('value');
				if(!isNaN(v) && this.rangeCheck(v, this.constraints)){
					if(this.constraints.exponent !== false && /\de[-+]?\d/i.test(this.textbox.value)){ // exponential, parse doesn't like it
						return true; // valid exponential number in range
					}else{
						return this.inherited(arguments);
					}
				}else{
					return false;
				}
			}
		}
	}
);

dojo.declare("dijit.form.NumberTextBox",
	[dijit.form.RangeBoundTextBox,dijit.form.NumberTextBoxMixin],
	{
		// summary:
		//		A TextBox for entering numbers, with formatting and range checking
		// description:
		//		NumberTextBox is a textbox for entering and displaying numbers, supporting
		//		the following main features:
		//
		//			1. Enforce minimum/maximum allowed values (as well as enforcing that the user types
		//				a number rather than a random string)
		//			2. NLS support (altering roles of comma and dot as "thousands-separator" and "decimal-point"
		//				depending on locale).
		//			3. Separate modes for editing the value and displaying it, specifically that
		//				the thousands separator character (typically comma) disappears when editing
		//				but reappears after the field is blurred.
		//			4. Formatting and constraints regarding the number of places (digits after the decimal point)
		//				allowed on input, and number of places displayed when blurred (see `constraints` parameter).
	}
);

}

if(!dojo._hasResource["dijit.form.NumberSpinner"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.NumberSpinner"] = true;
dojo.provide("dijit.form.NumberSpinner");




dojo.declare("dijit.form.NumberSpinner",
	[dijit.form._Spinner, dijit.form.NumberTextBoxMixin],
	{
	// summary:
	//		Extends NumberTextBox to add up/down arrows and pageup/pagedown for incremental change to the value
	//
	// description:
	//		A `dijit.form.NumberTextBox` extension to provide keyboard accessible value selection
	//		as well as icons for spinning direction. When using the keyboard, the typematic rules
	//		apply, meaning holding the key will gradually increase or decrease the value and
	// 		accelerate.
	//
	// example:
	//	| new dijit.form.NumberSpinner({ constraints:{ max:300, min:100 }}, "someInput");

	adjust: function(/* Object */val, /* Number*/delta){
		// summary:
		//		Change Number val by the given amount
		// tags:
		//		protected

		var tc = this.constraints,
			v = isNaN(val),
			gotMax = !isNaN(tc.max),
			gotMin = !isNaN(tc.min)
		;
		if(v && delta != 0){ // blank or invalid value and they want to spin, so create defaults
			val = (delta > 0) ?
				gotMin ? tc.min : gotMax ? tc.max : 0 :
				gotMax ? this.constraints.max : gotMin ? tc.min : 0
			;
		}
		var newval = val + delta;
		if(v || isNaN(newval)){ return val; }
		if(gotMax && (newval > tc.max)){
			newval = tc.max;
		}
		if(gotMin && (newval < tc.min)){
			newval = tc.min;
		}
		return newval;
	},

	_onKeyPress: function(e){
		if((e.charOrCode == dojo.keys.HOME || e.charOrCode == dojo.keys.END) && !(e.ctrlKey || e.altKey || e.metaKey)
		&& typeof this.get('value') != 'undefined' /* gibberish, so HOME and END are default editing keys*/){
			var value = this.constraints[(e.charOrCode == dojo.keys.HOME ? "min" : "max")];
			if(typeof value == "number"){
				this._setValueAttr(value, false);
			}
			// eat home or end key whether we change the value or not
			dojo.stopEvent(e);
		}
	}
});

}

if(!dojo._hasResource["dojo.cldr.monetary"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.cldr.monetary"] = true;
dojo.provide("dojo.cldr.monetary");

dojo.cldr.monetary.getData = function(/*String*/code){
// summary: A mapping of currency code to currency-specific formatting information. Returns a unique object with properties: places, round.
// code: an [ISO 4217](http://en.wikipedia.org/wiki/ISO_4217) currency code

// from http://www.unicode.org/cldr/data/common/supplemental/supplementalData.xml:supplementalData/currencyData/fractions

	var placesData = {
		ADP:0,AFN:0,ALL:0,AMD:0,BHD:3,BIF:0,BYR:0,CLF:0,CLP:0,
		COP:0,CRC:0,DJF:0,ESP:0,GNF:0,GYD:0,HUF:0,IDR:0,IQD:0,
		IRR:3,ISK:0,ITL:0,JOD:3,JPY:0,KMF:0,KPW:0,KRW:0,KWD:3,
		LAK:0,LBP:0,LUF:0,LYD:3,MGA:0,MGF:0,MMK:0,MNT:0,MRO:0,
		MUR:0,OMR:3,PKR:0,PYG:0,RSD:0,RWF:0,SLL:0,SOS:0,STD:0,
		SYP:0,TMM:0,TND:3,TRL:0,TZS:0,UGX:0,UZS:0,VND:0,VUV:0,
		XAF:0,XOF:0,XPF:0,YER:0,ZMK:0,ZWD:0
	};

	var roundingData = {CHF:5};

	var places = placesData[code], round = roundingData[code];
	if(typeof places == "undefined"){ places = 2; }
	if(typeof round == "undefined"){ round = 0; }

	return {places: places, round: round}; // Object
};

}

if(!dojo._hasResource["dojo.currency"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.currency"] = true;
dojo.provide("dojo.currency");






/*=====
dojo.currency = {
	// summary: localized formatting and parsing routines for currencies
	//
	// description: extends dojo.number to provide culturally-appropriate formatting of values
	//	in various world currencies, including use of a currency symbol.  The currencies are specified
	//	by a three-letter international symbol in all uppercase, and support for the currencies is
	//	provided by the data in `dojo.cldr`.  The scripts generating dojo.cldr specify which
	//	currency support is included.  A fixed number of decimal places is determined based
	//	on the currency type and is not determined by the 'pattern' argument.  The fractional
	//	portion is optional, by default, and variable length decimals are not supported.
}
=====*/

dojo.currency._mixInDefaults = function(options){
	options = options || {};
	options.type = "currency";

	// Get locale-dependent currency data, like the symbol
	var bundle = dojo.i18n.getLocalization("dojo.cldr", "currency", options.locale) || {};

	// Mixin locale-independent currency data, like # of places
	var iso = options.currency;
	var data = dojo.cldr.monetary.getData(iso);

	dojo.forEach(["displayName","symbol","group","decimal"], function(prop){
		data[prop] = bundle[iso+"_"+prop];
	});

	data.fractional = [true, false];

	// Mixin with provided options
	return dojo.mixin(data, options);
}

/*=====
dojo.declare("dojo.currency.__FormatOptions", [dojo.number.__FormatOptions], {
	//	type: String?
	//		Should not be set.  Value is assumed to be "currency".
	//	symbol: String?
	//		localized currency symbol. The default will be looked up in table of supported currencies in `dojo.cldr`
	//		A [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code will be used if not found.
	//	currency: String?
	//		an [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD".
	//		For use with dojo.currency only.
	//	places: Number?
	//		number of decimal places to show.  Default is defined based on which currency is used.
	type: "",
	symbol: "",
	currency: "",
	places: ""
});
=====*/

dojo.currency.format = function(/*Number*/value, /*dojo.currency.__FormatOptions?*/options){
// summary:
//		Format a Number as a currency, using locale-specific settings
//
// description:
//		Create a string from a Number using a known, localized pattern.
//		[Formatting patterns](http://www.unicode.org/reports/tr35/#Number_Elements)
//		appropriate to the locale are chosen from the [CLDR](http://unicode.org/cldr)
//		as well as the appropriate symbols and delimiters and number of decimal places.
//
// value:
//		the number to be formatted.

	return dojo.number.format(value, dojo.currency._mixInDefaults(options));
}

dojo.currency.regexp = function(/*dojo.number.__RegexpOptions?*/options){
//
// summary:
//		Builds the regular needed to parse a currency value
//
// description:
//		Returns regular expression with positive and negative match, group and decimal separators
//		Note: the options.places default, the number of decimal places to accept, is defined by the currency type.
	return dojo.number.regexp(dojo.currency._mixInDefaults(options)); // String
}

/*=====
dojo.declare("dojo.currency.__ParseOptions", [dojo.number.__ParseOptions], {
	//	type: String?
	//		Should not be set.  Value is assumed to be currency.
	//	currency: String?
	//		an [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD".
	//		For use with dojo.currency only.
	//	symbol: String?
	//		localized currency symbol. The default will be looked up in table of supported currencies in `dojo.cldr`
	//		A [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code will be used if not found.
	//	places: Number?
	//		fixed number of decimal places to accept.  The default is determined based on which currency is used.
	//	fractional: Boolean?|Array?
	//		Whether to include the fractional portion, where the number of decimal places are implied by the currency
	//		or explicit 'places' parameter.  The value [true,false] makes the fractional portion optional.
	//		By default for currencies, it the fractional portion is optional.
	type: "",
	currency: "",
	symbol: "",
	places: "",
	fractional: ""
});
=====*/

dojo.currency.parse = function(/*String*/expression, /*dojo.currency.__ParseOptions?*/options){
	//
	// summary:
	//		Convert a properly formatted currency string to a primitive Number,
	//		using locale-specific settings.
	//
	// description:
	//		Create a Number from a string using a known, localized pattern.
	//		[Formatting patterns](http://www.unicode.org/reports/tr35/#Number_Format_Patterns)
	//		are chosen appropriate to the locale, as well as the appropriate symbols and delimiters
	//		and number of decimal places.
	//
	// expression: A string representation of a currency value

	return dojo.number.parse(expression, dojo.currency._mixInDefaults(options));
}

}

if(!dojo._hasResource["dijit.form.CurrencyTextBox"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.CurrencyTextBox"] = true;
dojo.provide("dijit.form.CurrencyTextBox");




/*=====
dojo.declare(
	"dijit.form.CurrencyTextBox.__Constraints",
	[dijit.form.NumberTextBox.__Constraints, dojo.currency.__FormatOptions, dojo.currency.__ParseOptions], {
	// summary:
	//		Specifies both the rules on valid/invalid values (minimum, maximum,
	//		number of required decimal places), and also formatting options for
	//		displaying the value when the field is not focused (currency symbol,
	//		etc.)
	// description:
	//		Follows the pattern of `dijit.form.NumberTextBox.constraints`.
	//		In general developers won't need to set this parameter
	// example:
	//		To ensure that the user types in the cents (for example, 1.00 instead of just 1):
	//	|		{fractional:true}
});
=====*/

dojo.declare(
	"dijit.form.CurrencyTextBox",
	dijit.form.NumberTextBox,
	{
		// summary:
		//		A validating currency textbox
		// description:
		//		CurrencyTextBox is similar to `dijit.form.NumberTextBox` but has a few
		//		extra features related to currency:
		//
		//		1. After specifying the currency type (american dollars, euros, etc.) it automatically
		//			sets parse/format options such as how many decimal places to show.
		//		2. The currency mark (dollar sign, euro mark, etc.) is displayed when the field is blurred
		//			but erased during editing, so that the user can just enter a plain number.

		// currency: [const] String
		//		the [ISO4217](http://en.wikipedia.org/wiki/ISO_4217) currency code, a three letter sequence like "USD"
		currency: "",

		// constraints: dijit.form.CurrencyTextBox.__Constraints
		//		Despite the name, this parameter specifies both constraints on the input
		//		(including minimum/maximum allowed values) as well as
		//		formatting options.   See `dijit.form.CurrencyTextBox.__Constraints` for details.
		/*=====
		constraints: {},
		======*/
		
		baseClass: "dijitTextBox dijitCurrencyTextBox",

		// Override regExpGen ValidationTextBox.regExpGen().... we use a reg-ex generating function rather
		// than a straight regexp to deal with locale  (plus formatting options too?)
		regExpGen: function(constraints){
			// if focused, accept either currency data or NumberTextBox format
			return '(' + (this._focused? this.inherited(arguments, [ dojo.mixin({}, constraints, this.editOptions) ]) + '|' : '')
				+ dojo.currency.regexp(constraints) + ')';
		},

		// Override NumberTextBox._formatter to deal with currencies, ex: converts "123.45" to "$123.45"
		_formatter: dojo.currency.format,

		parse: function(/* String */ value, /* Object */ constraints){
			// summary:
			// 		Parses string value as a Currency, according to the constraints object
			// tags:
			// 		protected extension
			var v = dojo.currency.parse(value, constraints);
			if(isNaN(v) && /\d+/.test(value)){ // currency parse failed, but it could be because they are using NumberTextBox format so try its parse
				return this.inherited(arguments, [ value, dojo.mixin({}, constraints, this.editOptions) ]);
			}
			return v;
		},

		_setConstraintsAttr: function(/* Object */ constraints){
			if(!constraints.currency && this.currency){
				constraints.currency = this.currency;
			}
			this.inherited(arguments, [ dojo.currency._mixInDefaults(dojo.mixin(constraints, { exponent: false })) ]); // get places
		}
	}
);

}

if(!dojo._hasResource["dijit.form.HorizontalSlider"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.HorizontalSlider"] = true;
dojo.provide("dijit.form.HorizontalSlider");








dojo.declare(
	"dijit.form.HorizontalSlider",
	[dijit.form._FormValueWidget, dijit._Container],
{
	// summary:
	//		A form widget that allows one to select a value with a horizontally draggable handle

	templateString: dojo.cache("dijit.form", "templates/HorizontalSlider.html", "<table class=\"dijit dijitReset dijitSlider dijitSliderH\" cellspacing=\"0\" cellpadding=\"0\" border=\"0\" rules=\"none\" dojoAttachEvent=\"onkeypress:_onKeyPress,onkeyup:_onKeyUp\"\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td dojoAttachPoint=\"topDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationT dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderDecrementIconH\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"decrementButton\"><span class=\"dijitSliderButtonInner\">-</span></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderLeftBumper\" dojoAttachEvent=\"onmousedown:_onClkDecBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><input dojoAttachPoint=\"valueNode\" type=\"hidden\" ${!nameAttrSetting}\n\t\t\t/><div class=\"dijitReset dijitSliderBarContainerH\" waiRole=\"presentation\" dojoAttachPoint=\"sliderBarContainer\"\n\t\t\t\t><div waiRole=\"presentation\" dojoAttachPoint=\"progressBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderProgressBar dijitSliderProgressBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"\n\t\t\t\t\t><div class=\"dijitSliderMoveable dijitSliderMoveableH\"\n\t\t\t\t\t\t><div dojoAttachPoint=\"sliderHandle,focusNode\" class=\"dijitSliderImageHandle dijitSliderImageHandleH\" dojoAttachEvent=\"onmousedown:_onHandleClick\" waiRole=\"slider\" valuemin=\"${minimum}\" valuemax=\"${maximum}\"></div\n\t\t\t\t\t></div\n\t\t\t\t></div\n\t\t\t\t><div waiRole=\"presentation\" dojoAttachPoint=\"remainingBar\" class=\"dijitSliderBar dijitSliderBarH dijitSliderRemainingBar dijitSliderRemainingBarH\" dojoAttachEvent=\"onmousedown:_onBarClick\"></div\n\t\t\t></div\n\t\t></td\n\t\t><td class=\"dijitReset\"\n\t\t\t><div class=\"dijitSliderBar dijitSliderBumper dijitSliderBumperH dijitSliderRightBumper\" dojoAttachEvent=\"onmousedown:_onClkIncBumper\"></div\n\t\t></td\n\t\t><td class=\"dijitReset dijitSliderButtonContainer dijitSliderButtonContainerH\"\n\t\t\t><div class=\"dijitSliderIncrementIconH\" tabIndex=\"-1\" style=\"display:none\" dojoAttachPoint=\"incrementButton\"><span class=\"dijitSliderButtonInner\">+</span></div\n\t\t></td\n\t></tr\n\t><tr class=\"dijitReset\"\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t\t><td dojoAttachPoint=\"containerNode,bottomDecoration\" class=\"dijitReset dijitSliderDecoration dijitSliderDecorationB dijitSliderDecorationH\"></td\n\t\t><td class=\"dijitReset\" colspan=\"2\"></td\n\t></tr\n></table>\n"),

	// Overrides FormValueWidget.value to indicate numeric value
	value: 0,

	// showButtons: Boolean
	//		Show increment/decrement buttons at the ends of the slider?
	showButtons: true,

	// minimum:: Integer
	//		The minimum value the slider can be set to.
	minimum: 0,

	// maximum: Integer
	//		The maximum value the slider can be set to.
	maximum: 100,

	// discreteValues: Integer
	//		If specified, indicates that the slider handle has only 'discreteValues' possible positions,
	//      and that after dragging the handle, it will snap to the nearest possible position.
	//      Thus, the slider has only 'discreteValues' possible values.
	//
	//		For example, if minimum=10, maxiumum=30, and discreteValues=3, then the slider handle has
	//		three possible positions, representing values 10, 20, or 30.
	//
	//		If discreteValues is not specified or if it's value is higher than the number of pixels
	//		in the slider bar, then the slider handle can be moved freely, and the slider's value will be
	//		computed/reported based on pixel position (in this case it will likely be fractional,
	//      such as 123.456789).
	discreteValues: Infinity,

	// pageIncrement: Integer
	//		If discreteValues is also specified, this indicates the amount of clicks (ie, snap positions)
	//      that the slider handle is moved via pageup/pagedown keys.
	//	If discreteValues is not specified, it indicates the number of pixels.
	pageIncrement: 2,

	// clickSelect: Boolean
	//		If clicking the slider bar changes the value or not
	clickSelect: true,

	// slideDuration: Number
	//		The time in ms to take to animate the slider handle from 0% to 100%,
	//		when clicking the slider bar to make the handle move.
	slideDuration: dijit.defaultDuration,

	// Flag to _Templated  (TODO: why is this here?   I see no widgets in the template.)
	widgetsInTemplate: true,

	attributeMap: dojo.delegate(dijit.form._FormWidget.prototype.attributeMap, {
		id: ""
	}),

	baseClass: "dijitSlider",

	// Apply CSS classes to up/down arrows and handle per mouse state
	cssStateNodes: {
		incrementButton: "dijitSliderIncrementButton",
		decrementButton: "dijitSliderDecrementButton",
		focusNode: "dijitSliderThumb"
	},

	_mousePixelCoord: "pageX",
	_pixelCount: "w",
	_startingPixelCoord: "x",
	_startingPixelCount: "l",
	_handleOffsetCoord: "left",
	_progressPixelSize: "width",

	_onKeyUp: function(/*Event*/ e){
		if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
		this._setValueAttr(this.value, true);
	},

	_onKeyPress: function(/*Event*/ e){
		if(this.disabled || this.readOnly || e.altKey || e.ctrlKey || e.metaKey){ return; }
		switch(e.charOrCode){
			case dojo.keys.HOME:
				this._setValueAttr(this.minimum, false);
				break;
			case dojo.keys.END:
				this._setValueAttr(this.maximum, false);
				break;
			// this._descending === false: if ascending vertical (min on top)
			// (this._descending || this.isLeftToRight()): if left-to-right horizontal or descending vertical
			case ((this._descending || this.isLeftToRight()) ? dojo.keys.RIGHT_ARROW : dojo.keys.LEFT_ARROW):
			case (this._descending === false ? dojo.keys.DOWN_ARROW : dojo.keys.UP_ARROW):
			case (this._descending === false ? dojo.keys.PAGE_DOWN : dojo.keys.PAGE_UP):
				this.increment(e);
				break;
			case ((this._descending || this.isLeftToRight()) ? dojo.keys.LEFT_ARROW : dojo.keys.RIGHT_ARROW):
			case (this._descending === false ? dojo.keys.UP_ARROW : dojo.keys.DOWN_ARROW):
			case (this._descending === false ? dojo.keys.PAGE_UP : dojo.keys.PAGE_DOWN):
				this.decrement(e);
				break;
			default:
				return;
		}
		dojo.stopEvent(e);
	},

	_onHandleClick: function(e){
		if(this.disabled || this.readOnly){ return; }
		if(!dojo.isIE){
			// make sure you get focus when dragging the handle
			// (but don't do on IE because it causes a flicker on mouse up (due to blur then focus)
			dijit.focus(this.sliderHandle);
		}
		dojo.stopEvent(e);
	},

	_isReversed: function(){
		// summary:
		//		Returns true if direction is from right to left
		// tags:
		//		protected extension
		return !this.isLeftToRight();
	},

	_onBarClick: function(e){
		if(this.disabled || this.readOnly || !this.clickSelect){ return; }
		dijit.focus(this.sliderHandle);
		dojo.stopEvent(e);
		var abspos = dojo.position(this.sliderBarContainer, true);
		var pixelValue = e[this._mousePixelCoord] - abspos[this._startingPixelCoord];
		this._setPixelValue(this._isReversed() ? (abspos[this._pixelCount] - pixelValue) : pixelValue, abspos[this._pixelCount], true);
		this._movable.onMouseDown(e);
	},

	_setPixelValue: function(/*Number*/ pixelValue, /*Number*/ maxPixels, /*Boolean, optional*/ priorityChange){
		if(this.disabled || this.readOnly){ return; }
		pixelValue = pixelValue < 0 ? 0 : maxPixels < pixelValue ? maxPixels : pixelValue;
		var count = this.discreteValues;
		if(count <= 1 || count == Infinity){ count = maxPixels; }
		count--;
		var pixelsPerValue = maxPixels / count;
		var wholeIncrements = Math.round(pixelValue / pixelsPerValue);
		this._setValueAttr((this.maximum-this.minimum)*wholeIncrements/count + this.minimum, priorityChange);
	},

	_setValueAttr: function(/*Number*/ value, /*Boolean, optional*/ priorityChange){
		// summary:
		//		Hook so attr('value', value) works.
		this.valueNode.value = this.value = value;
		dijit.setWaiState(this.focusNode, "valuenow", value);
		this.inherited(arguments);
		var percent = (value - this.minimum) / (this.maximum - this.minimum);
		var progressBar = (this._descending === false) ? this.remainingBar : this.progressBar;
		var remainingBar = (this._descending === false) ? this.progressBar : this.remainingBar;
		if(this._inProgressAnim && this._inProgressAnim.status != "stopped"){
			this._inProgressAnim.stop(true);
		}
		if(priorityChange && this.slideDuration > 0 && progressBar.style[this._progressPixelSize]){
			// animate the slider
			var _this = this;
			var props = {};
			var start = parseFloat(progressBar.style[this._progressPixelSize]);
			var duration = this.slideDuration * (percent-start/100);
			if(duration == 0){ return; }
			if(duration < 0){ duration = 0 - duration; }
			props[this._progressPixelSize] = { start: start, end: percent*100, units:"%" };
			this._inProgressAnim = dojo.animateProperty({ node: progressBar, duration: duration,
				onAnimate: function(v){ remainingBar.style[_this._progressPixelSize] = (100-parseFloat(v[_this._progressPixelSize])) + "%"; },
				onEnd: function(){ delete _this._inProgressAnim; },
				properties: props
			})
			this._inProgressAnim.play();
		}
		else{
			progressBar.style[this._progressPixelSize] = (percent*100) + "%";
			remainingBar.style[this._progressPixelSize] = ((1-percent)*100) + "%";
		}
	},

	_bumpValue: function(signedChange, /*Boolean, optional*/ priorityChange){
		if(this.disabled || this.readOnly){ return; }
		var s = dojo.getComputedStyle(this.sliderBarContainer);
		var c = dojo._getContentBox(this.sliderBarContainer, s);
		var count = this.discreteValues;
		if(count <= 1 || count == Infinity){ count = c[this._pixelCount]; }
		count--;
		var value = (this.value - this.minimum) * count / (this.maximum - this.minimum) + signedChange;
		if(value < 0){ value = 0; }
		if(value > count){ value = count; }
		value = value * (this.maximum - this.minimum) / count + this.minimum;
		this._setValueAttr(value, priorityChange);
	},

	_onClkBumper: function(val){
		if(this.disabled || this.readOnly || !this.clickSelect){ return; }
		this._setValueAttr(val, true);
	},

	_onClkIncBumper: function(){
		this._onClkBumper(this._descending === false ? this.minimum : this.maximum);
	},

	_onClkDecBumper: function(){
		this._onClkBumper(this._descending === false ? this.maximum : this.minimum);
	},

	decrement: function(/*Event*/ e){
		// summary:
		//		Decrement slider
		// tags:
		//		private
		this._bumpValue(e.charOrCode == dojo.keys.PAGE_DOWN ? -this.pageIncrement : -1);
	},

	increment: function(/*Event*/ e){
		// summary:
		//		Increment slider
		// tags:
		//		private
		this._bumpValue(e.charOrCode == dojo.keys.PAGE_UP ? this.pageIncrement : 1);
	},

	_mouseWheeled: function(/*Event*/ evt){
		// summary:
		//		Event handler for mousewheel where supported
		dojo.stopEvent(evt);
		var janky = !dojo.isMozilla;
		var scroll = evt[(janky ? "wheelDelta" : "detail")] * (janky ? 1 : -1);
		this._bumpValue(scroll < 0 ? -1 : 1, true); // negative scroll acts like a decrement
	},

	startup: function(){
		if(this._started){ return; }

		dojo.forEach(this.getChildren(), function(child){
			if(this[child.container] != this.containerNode){
				this[child.container].appendChild(child.domNode);
			}
		}, this);

		this.inherited(arguments);
	},

	_typematicCallback: function(/*Number*/ count, /*Object*/ button, /*Event*/ e){
		if(count == -1){
			this._setValueAttr(this.value, true);
		}else{
			this[(button == (this._descending? this.incrementButton : this.decrementButton)) ? "decrement" : "increment"](e);
		}
	},

	postCreate: function(){
		if(this.showButtons){
			this.incrementButton.style.display="";
			this.decrementButton.style.display="";
			this._connects.push(dijit.typematic.addMouseListener(
				this.decrementButton, this, "_typematicCallback", 25, 500));
			this._connects.push(dijit.typematic.addMouseListener(
				this.incrementButton, this, "_typematicCallback", 25, 500));
		}
		this.connect(this.domNode, !dojo.isMozilla ? "onmousewheel" : "DOMMouseScroll", "_mouseWheeled");

		// define a custom constructor for a SliderMover that points back to me
		var mover = dojo.declare(dijit.form._SliderMover, {
			widget: this
		});

		this._movable = new dojo.dnd.Moveable(this.sliderHandle, {mover: mover});
		// find any associated label element and add to slider focusnode.
		var label=dojo.query('label[for="'+this.id+'"]');
		if(label.length){
			label[0].id = (this.id+"_label");
			dijit.setWaiState(this.focusNode, "labelledby", label[0].id);
		}
		dijit.setWaiState(this.focusNode, "valuemin", this.minimum);
		dijit.setWaiState(this.focusNode, "valuemax", this.maximum);

		this.inherited(arguments);
		this._layoutHackIE7();
	},

	destroy: function(){
		this._movable.destroy();
		if(this._inProgressAnim && this._inProgressAnim.status != "stopped"){
			this._inProgressAnim.stop(true);
		}
		this._supportingWidgets = dijit.findWidgets(this.domNode); // tells destroy about pseudo-child widgets (ruler/labels)
		this.inherited(arguments);
	}
});

dojo.declare("dijit.form._SliderMover",
	dojo.dnd.Mover,
{
	onMouseMove: function(e){
		var widget = this.widget;
		var abspos = widget._abspos;
		if(!abspos){
			abspos = widget._abspos = dojo.position(widget.sliderBarContainer, true);
			widget._setPixelValue_ = dojo.hitch(widget, "_setPixelValue");
			widget._isReversed_ = widget._isReversed();
		}
		var pixelValue = e[widget._mousePixelCoord] - abspos[widget._startingPixelCoord];
		widget._setPixelValue_(widget._isReversed_ ? (abspos[widget._pixelCount]-pixelValue) : pixelValue, abspos[widget._pixelCount], false);
	},

	destroy: function(e){
		dojo.dnd.Mover.prototype.destroy.apply(this, arguments);
		var widget = this.widget;
		widget._abspos = null;
		widget._setValueAttr(widget.value, true);
	}
});



}

if(!dojo._hasResource["dijit._editor.selection"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor.selection"] = true;
dojo.provide("dijit._editor.selection");

// FIXME:
//		all of these methods branch internally for IE. This is probably
//		sub-optimal in terms of runtime performance. We should investigate the
//		size difference for differentiating at definition time.

dojo.mixin(dijit._editor.selection, {
	getType: function(){
		// summary:
		//		Get the selection type (like dojo.doc.select.type in IE).
		if(dojo.isIE){
			return dojo.doc.selection.type.toLowerCase();
		}else{
			var stype = "text";

			// Check if the actual selection is a CONTROL (IMG, TABLE, HR, etc...).
			var oSel;
			try{
				oSel = dojo.global.getSelection();
			}catch(e){ /*squelch*/ }

			if(oSel && oSel.rangeCount == 1){
				var oRange = oSel.getRangeAt(0);
				if(	(oRange.startContainer == oRange.endContainer) &&
					((oRange.endOffset - oRange.startOffset) == 1) &&
					(oRange.startContainer.nodeType != 3 /* text node*/)
				){
					stype = "control";
				}
			}
			return stype; //String
		}
	},

	getSelectedText: function(){
		// summary:
		//		Return the text (no html tags) included in the current selection or null if no text is selected
		if(dojo.isIE){
			if(dijit._editor.selection.getType() == 'control'){
				return null;
			}
			return dojo.doc.selection.createRange().text;
		}else{
			var selection = dojo.global.getSelection();
			if(selection){
				return selection.toString(); //String
			}
		}
		return '';
	},

	getSelectedHtml: function(){
		// summary:
		//		Return the html text of the current selection or null if unavailable
		if(dojo.isIE){
			if(dijit._editor.selection.getType() == 'control'){
				return null;
			}
			return dojo.doc.selection.createRange().htmlText;
		}else{
			var selection = dojo.global.getSelection();
			if(selection && selection.rangeCount){
				var i;
				var html = "";
				for(i = 0; i < selection.rangeCount; i++){
					//Handle selections spanning ranges, such as Opera
					var frag = selection.getRangeAt(i).cloneContents();
					var div = dojo.doc.createElement("div");
					div.appendChild(frag);
					html += div.innerHTML;
				}
				return html; //String
			}
			return null;
		}
	},

	getSelectedElement: function(){
		// summary:
		//		Retrieves the selected element (if any), just in the case that
		//		a single element (object like and image or a table) is
		//		selected.
		if(dijit._editor.selection.getType() == "control"){
			if(dojo.isIE){
				var range = dojo.doc.selection.createRange();
				if(range && range.item){
					return dojo.doc.selection.createRange().item(0);
				}
			}else{
				var selection = dojo.global.getSelection();
				return selection.anchorNode.childNodes[ selection.anchorOffset ];
			}
		}
		return null;
	},

	getParentElement: function(){
		// summary:
		//		Get the parent element of the current selection
		if(dijit._editor.selection.getType() == "control"){
			var p = this.getSelectedElement();
			if(p){ return p.parentNode; }
		}else{
			if(dojo.isIE){
				var r = dojo.doc.selection.createRange();
				r.collapse(true);
				return r.parentElement();
			}else{
				var selection = dojo.global.getSelection();
				if(selection){
					var node = selection.anchorNode;
					while(node && (node.nodeType != 1)){ // not an element
						node = node.parentNode;
					}
					return node;
				}
			}
		}
		return null;
	},

	hasAncestorElement: function(/*String*/tagName /* ... */){
		// summary:
		// 		Check whether current selection has a  parent element which is
		// 		of type tagName (or one of the other specified tagName)
		// tagName: String
		//		The tag name to determine if it has an ancestor of.
		return this.getAncestorElement.apply(this, arguments) != null; //Boolean
	},

	getAncestorElement: function(/*String*/tagName /* ... */){
		// summary:
		//		Return the parent element of the current selection which is of
		//		type tagName (or one of the other specified tagName)
		// tagName: String
		//		The tag name to determine if it has an ancestor of.
		var node = this.getSelectedElement() || this.getParentElement();
		return this.getParentOfType(node, arguments); //DOMNode
	},

	isTag: function(/*DomNode*/ node, /*String[]*/ tags){
		// summary:
		//		Function to determine if a node is one of an array of tags.
		// node:
		//		The node to inspect.
		// tags:
		//		An array of tag name strings to check to see if the node matches.
		if(node && node.tagName){
			var _nlc = node.tagName.toLowerCase();
			for(var i=0; i<tags.length; i++){
				var _tlc = String(tags[i]).toLowerCase();
				if(_nlc == _tlc){
					return _tlc; // String
				}
			}
		}
		return "";
	},

	getParentOfType: function(/*DomNode*/ node, /*String[]*/ tags){
		// summary:
		//		Function to locate a parent node that matches one of a set of tags
		// node:
		//		The node to inspect.
		// tags:
		//		An array of tag name strings to check to see if the node matches.
		while(node){
			if(this.isTag(node, tags).length){
				return node; // DOMNode
			}
			node = node.parentNode;
		}
		return null;
	},

	collapse: function(/*Boolean*/beginning){
		// summary:
		//		Function to collapse (clear), the current selection
		// beginning: Boolean
		//		Boolean to indicate whether to collapse the cursor to the beginning of the selection or end.
		if(window.getSelection){
			var selection = dojo.global.getSelection();
			if(selection.removeAllRanges){ // Mozilla
				if(beginning){
					selection.collapseToStart();
				}else{
					selection.collapseToEnd();
				}
			}else{ // Safari
				// pulled from WebCore/ecma/kjs_window.cpp, line 2536
				selection.collapse(beginning);
			}
		}else if(dojo.isIE){ // IE
			var range = dojo.doc.selection.createRange();
			range.collapse(beginning);
			range.select();
		}
	},

	remove: function(){
		// summary:
		//		Function to delete the currently selected content from the document.
		var sel = dojo.doc.selection;
		if(dojo.isIE){
			if(sel.type.toLowerCase() != "none"){
				sel.clear();
			}
			return sel; //Selection
		}else{
			sel = dojo.global.getSelection();
			sel.deleteFromDocument();
			return sel; //Selection
		}
	},

	selectElementChildren: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
		// summary:
		//		clear previous selection and select the content of the node
		//		(excluding the node itself)
		// element: DOMNode
		//		The element you wish to select the children content of.
		// nochangefocus: Boolean
		//		Boolean to indicate if the foxus should change or not.
		var win = dojo.global;
		var doc = dojo.doc;
		var range;
		element = dojo.byId(element);
		if(doc.selection && dojo.isIE && dojo.body().createTextRange){ // IE
			range = element.ownerDocument.body.createTextRange();
			range.moveToElementText(element);
			if(!nochangefocus){
				try{
					range.select(); // IE throws an exception here if the widget is hidden.  See #5439
				}catch(e){ /* squelch */}
			}
		}else if(win.getSelection){
			var selection = dojo.global.getSelection();
			if(dojo.isOpera){
				//Opera's selectAllChildren doesn't seem to work right
				//against <body> nodes and possibly others ... so
				//we use the W3C range API
				if(selection.rangeCount){
					range = selection.getRangeAt(0);
				}else{
					range = doc.createRange();
				}
				range.setStart(element, 0);
				range.setEnd(element,(element.nodeType == 3)?element.length:element.childNodes.length);
				selection.addRange(range);
			}else{
				selection.selectAllChildren(element);
			}
		}
	},

	selectElement: function(/*DomNode*/element,/*Boolean?*/nochangefocus){
		// summary:
		//		clear previous selection and select element (including all its children)
		// element:  DOMNode
		//		The element to select.
		// nochangefocus: Boolean
		//		Boolean indicating if the focus should be changed.  IE only.
		var range;
		var doc = dojo.doc;
		var win = dojo.global;
		element = dojo.byId(element);
		if(dojo.isIE && dojo.body().createTextRange){
			try{
				range = dojo.body().createControlRange();
				range.addElement(element);
				if(!nochangefocus){
					range.select();
				}
			}catch(e){
				this.selectElementChildren(element,nochangefocus);
			}
		}else if(dojo.global.getSelection){
			var selection = win.getSelection();
			range = doc.createRange();
			if(selection.removeAllRanges){ // Mozilla
				// FIXME: does this work on Safari?
				if(dojo.isOpera){
					//Opera works if you use the current range on
					//the selection if present.
					if(selection.getRangeAt(0)){
						range = selection.getRangeAt(0);
					}
				}
				range.selectNode(element);
				selection.removeAllRanges();
				selection.addRange(range);
			}
		}
	},

	inSelection: function(node){
		// summary:
		//		This function determines if 'node' is
		//		in the current selection.
		// tags:
		//		public
		if(node){
			var newRange;
			var doc = dojo.doc;
			var range;

			if(dojo.global.getSelection){
				//WC3
				var sel = dojo.global.getSelection();
				if(sel && sel.rangeCount > 0){
					range = sel.getRangeAt(0);
				}
				if(range && range.compareBoundaryPoints && doc.createRange){
					try{
						newRange = doc.createRange();
						newRange.setStart(node, 0);
						if(range.compareBoundaryPoints(range.START_TO_END, newRange) === 1){
							return true;
						}
					}catch(e){ /* squelch */}
				}
			}else if(doc.selection){
				// Probably IE, so we can't use the range object as the pseudo
				// range doesn't implement the boundry checking, we have to 
				// use IE specific crud.
				range = doc.selection.createRange();
				try{
					newRange = node.ownerDocument.body.createControlRange();
					if(newRange){
						newRange.addElement(node);
					}
				}catch(e1){
					try{
						newRange = node.ownerDocument.body.createTextRange();
						newRange.moveToElementText(node);
					}catch(e2){/* squelch */}
				}
				if(range && newRange){
					// We can finally compare similar to W3C
					if(range.compareEndPoints("EndToStart", newRange) === 1){
						return true;
					}
				}
			}
		}
		return false; // boolean
	}

});

}

if(!dojo._hasResource["dijit._editor.range"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor.range"] = true;
dojo.provide("dijit._editor.range");

dijit.range={};

dijit.range.getIndex=function(/*DomNode*/node, /*DomNode*/parent){
//	dojo.profile.start("dijit.range.getIndex");
	var ret=[], retR=[];
	var stop = parent;
	var onode = node;

	var pnode, n;
	while(node != stop){
		var i = 0;
		pnode = node.parentNode;
		while((n=pnode.childNodes[i++])){
			if(n === node){
				--i;
				break;
			}
		}
		//if(i>=pnode.childNodes.length){
			//dojo.debug("Error finding index of a node in dijit.range.getIndex");
		//}
		ret.unshift(i);
		retR.unshift(i-pnode.childNodes.length);
		node = pnode;
	}

	//normalized() can not be called so often to prevent
	//invalidating selection/range, so we have to detect
	//here that any text nodes in a row
	if(ret.length > 0 && onode.nodeType == 3){
		n = onode.previousSibling;
		while(n && n.nodeType == 3){
			ret[ret.length-1]--;
			n = n.previousSibling;
		}
		n = onode.nextSibling;
		while(n && n.nodeType == 3){
			retR[retR.length-1]++;
			n = n.nextSibling;
		}
	}
//	dojo.profile.end("dijit.range.getIndex");
	return {o: ret, r:retR};
}

dijit.range.getNode = function(/*Array*/index, /*DomNode*/parent){
	if(!dojo.isArray(index) || index.length == 0){
		return parent;
	}
	var node = parent;
//	if(!node)debugger
	dojo.every(index, function(i){
		if(i >= 0 && i < node.childNodes.length){
			node = node.childNodes[i];
		}else{
			node = null;
			//console.debug('Error: can not find node with index',index,'under parent node',parent );
			return false; //terminate dojo.every
		}
		return true; //carry on the every loop
	});

	return node;
}

dijit.range.getCommonAncestor = function(n1,n2,root){
	root = root||n1.ownerDocument.body;
	var getAncestors = function(n){
		var as=[];
		while(n){
			as.unshift(n);
			if(n !== root){
				n = n.parentNode;
			}else{
				break;
			}
		}
		return as;
	};
	var n1as = getAncestors(n1);
	var n2as = getAncestors(n2);

	var m = Math.min(n1as.length,n2as.length);
	var com = n1as[0]; //at least, one element should be in the array: the root (BODY by default)
	for(var i=1;i<m;i++){
		if(n1as[i] === n2as[i]){
			com = n1as[i]
		}else{
			break;
		}
	}
	return com;
}

dijit.range.getAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){
	root = root || node.ownerDocument.body;
	while(node && node !== root){
		var name = node.nodeName.toUpperCase() ;
		if(regex.test(name)){
			return node;
		}

		node = node.parentNode;
	}
	return null;
}

dijit.range.BlockTagNames = /^(?:P|DIV|H1|H2|H3|H4|H5|H6|ADDRESS|PRE|OL|UL|LI|DT|DE)$/;
dijit.range.getBlockAncestor = function(/*DomNode*/node, /*RegEx?*/regex, /*DomNode?*/root){
	root = root || node.ownerDocument.body;
	regex = regex || dijit.range.BlockTagNames;
	var block=null, blockContainer;
	while(node && node !== root){
		var name = node.nodeName.toUpperCase() ;
		if(!block && regex.test(name)){
			block = node;
		}
		if(!blockContainer && (/^(?:BODY|TD|TH|CAPTION)$/).test(name)){
			blockContainer = node;
		}

		node = node.parentNode;
	}
	return {blockNode:block, blockContainer:blockContainer || node.ownerDocument.body};
}

dijit.range.atBeginningOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){
	var atBeginning = false;
	var offsetAtBeginning = (offset == 0);
	if(!offsetAtBeginning && node.nodeType == 3){ //if this is a text node, check whether the left part is all space
		if(/^[\s\xA0]+$/.test(node.nodeValue.substr(0,offset))){
			offsetAtBeginning = true;
		}
	}
	if(offsetAtBeginning){
		var cnode = node;
		atBeginning = true;
		while(cnode && cnode !== container){
			if(cnode.previousSibling){
				atBeginning = false;
				break;
			}
			cnode = cnode.parentNode;
		}
	}
	return atBeginning;
}

dijit.range.atEndOfContainer = function(/*DomNode*/container, /*DomNode*/node, /*Int*/offset){
	var atEnd = false;
	var offsetAtEnd = (offset == (node.length || node.childNodes.length));
	if(!offsetAtEnd && node.nodeType == 3){ //if this is a text node, check whether the right part is all space
		if(/^[\s\xA0]+$/.test(node.nodeValue.substr(offset))){
			offsetAtEnd = true;
		}
	}
	if(offsetAtEnd){
		var cnode = node;
		atEnd = true;
		while(cnode && cnode !== container){
			if(cnode.nextSibling){
				atEnd = false;
				break;
			}
			cnode = cnode.parentNode;
		}
	}
	return atEnd;
}

dijit.range.adjacentNoneTextNode=function(startnode, next){
	var node = startnode;
	var len = (0-startnode.length) || 0;
	var prop = next?'nextSibling':'previousSibling';
	while(node){
		if(node.nodeType!=3){
			break;
		}
		len += node.length
		node = node[prop];
	}
	return [node,len];
}

dijit.range._w3c = Boolean(window['getSelection']);
dijit.range.create = function(/*Window?*/win){
	if(dijit.range._w3c){
		return (win || dojo.global).document.createRange();
	}else{//IE
		return new dijit.range.W3CRange;
	}
}

dijit.range.getSelection = function(/*Window*/win, /*Boolean?*/ignoreUpdate){
	if(dijit.range._w3c){
		return win.getSelection();
	}else{//IE
		var s = new dijit.range.ie.selection(win);
		if(!ignoreUpdate){
			s._getCurrentSelection();
		}
		return s;
	}
}

if(!dijit.range._w3c){
	dijit.range.ie={
		cachedSelection: {},
		selection: function(win){
			this._ranges = [];
			this.addRange = function(r, /*boolean*/internal){
				this._ranges.push(r);
				if(!internal){
					r._select();
				}
				this.rangeCount = this._ranges.length;
			};
			this.removeAllRanges = function(){
				//don't detach, the range may be used later
//				for(var i=0;i<this._ranges.length;i++){
//					this._ranges[i].detach();
//				}
				this._ranges = [];
				this.rangeCount = 0;
			};
			var _initCurrentRange = function(){
				var r = win.document.selection.createRange();
				var type=win.document.selection.type.toUpperCase();
				if(type == "CONTROL"){
					//TODO: multiple range selection(?)
					return new dijit.range.W3CRange(dijit.range.ie.decomposeControlRange(r));
				}else{
					return new dijit.range.W3CRange(dijit.range.ie.decomposeTextRange(r));
				}
			};
			this.getRangeAt = function(i){
				return this._ranges[i];
			};
			this._getCurrentSelection = function(){
				this.removeAllRanges();
				var r=_initCurrentRange();
				if(r){
					this.addRange(r, true);
				}
			};
		},
		decomposeControlRange: function(range){
			var firstnode = range.item(0), lastnode = range.item(range.length-1);
			var startContainer = firstnode.parentNode, endContainer = lastnode.parentNode;
			var startOffset = dijit.range.getIndex(firstnode, startContainer).o;
			var endOffset = dijit.range.getIndex(lastnode, endContainer).o+1;
			return [startContainer, startOffset,endContainer, endOffset];
		},
		getEndPoint: function(range, end){
			var atmrange = range.duplicate();
			atmrange.collapse(!end);
			var cmpstr = 'EndTo' + (end?'End':'Start');
			var parentNode = atmrange.parentElement();

			var startnode, startOffset, lastNode;
			if(parentNode.childNodes.length>0){
				dojo.every(parentNode.childNodes, function(node,i){
					var calOffset;
					if(node.nodeType != 3){
						atmrange.moveToElementText(node);

						if(atmrange.compareEndPoints(cmpstr,range) > 0){
							//startnode = node.previousSibling;
							if(lastNode && lastNode.nodeType == 3){
								//where shall we put the start? in the text node or after?
								startnode = lastNode;
								calOffset = true;
							}else{
								startnode = parentNode;
								startOffset = i;
								return false;
							}
						}else{
							if(i == parentNode.childNodes.length-1){
								startnode = parentNode;
								startOffset = parentNode.childNodes.length;
								return false;
							}
						}
					}else{
						if(i == parentNode.childNodes.length-1){//at the end of this node
							startnode = node;
							calOffset = true;
						}
					}
		//			try{
						if(calOffset && startnode){
							var prevnode = dijit.range.adjacentNoneTextNode(startnode)[0];
							if(prevnode){
								startnode = prevnode.nextSibling;
							}else{
								startnode = parentNode.firstChild; //firstChild must be a text node
							}
							var prevnodeobj = dijit.range.adjacentNoneTextNode(startnode);
							prevnode = prevnodeobj[0];
							var lenoffset = prevnodeobj[1];
							if(prevnode){
								atmrange.moveToElementText(prevnode);
								atmrange.collapse(false);
							}else{
								atmrange.moveToElementText(parentNode);
							}
							atmrange.setEndPoint(cmpstr, range);
							startOffset = atmrange.text.length-lenoffset;

							return false;
						}
		//			}catch(e){ debugger }
					lastNode = node;
					return true;
				});
			}else{
				startnode = parentNode;
				startOffset = 0;
			}

			//if at the end of startnode and we are dealing with start container, then
			//move the startnode to nextSibling if it is a text node
			//TODO: do this for end container?
			if(!end && startnode.nodeType == 1 && startOffset == startnode.childNodes.length){
				var nextnode=startnode.nextSibling;
				if(nextnode && nextnode.nodeType == 3){
					startnode = nextnode;
					startOffset = 0;
				}
			}
			return [startnode, startOffset];
		},
		setEndPoint: function(range, container, offset){
			//text node
			var atmrange = range.duplicate(), node, len;
			if(container.nodeType!=3){ //normal node
				if(offset > 0){
					node = container.childNodes[offset-1];
					if(node){
						if(node.nodeType == 3){
							container = node;
							offset = node.length;
							//pass through
						}else{
							if(node.nextSibling && node.nextSibling.nodeType == 3){
								container=node.nextSibling;
								offset=0;
								//pass through
							}else{
								atmrange.moveToElementText(node.nextSibling?node:container);
								var parent = node.parentNode;
								var tempNode = parent.insertBefore(node.ownerDocument.createTextNode(' '), node.nextSibling);
								atmrange.collapse(false);
								parent.removeChild(tempNode);
							}
						}
					}
				}else{
					atmrange.moveToElementText(container);
					atmrange.collapse(true);
				}
			}
			if(container.nodeType == 3){
				var prevnodeobj = dijit.range.adjacentNoneTextNode(container);
				var prevnode = prevnodeobj[0];
				len = prevnodeobj[1];
				if(prevnode){
					atmrange.moveToElementText(prevnode);
					atmrange.collapse(false);
					//if contentEditable is not inherit, the above collapse won't make the end point
					//in the correctly position: it always has a -1 offset, so compensate it
					if(prevnode.contentEditable!='inherit'){
						len++;
					}
				}else{
					atmrange.moveToElementText(container.parentNode);
					atmrange.collapse(true);
				}

				offset += len;
				if(offset>0){
					if(atmrange.move('character',offset) != offset){
						console.error('Error when moving!');
					}
				}
			}

			return atmrange;
		},
		decomposeTextRange: function(range){
			var tmpary = dijit.range.ie.getEndPoint(range);
			var startContainer = tmpary[0], startOffset = tmpary[1];
			var endContainer = tmpary[0], endOffset = tmpary[1];

			if(range.htmlText.length){
				if(range.htmlText == range.text){ //in the same text node
					endOffset = startOffset+range.text.length;
				}else{
					tmpary = dijit.range.ie.getEndPoint(range,true);
					endContainer = tmpary[0], endOffset = tmpary[1];
//					if(startContainer.tagName == "BODY"){
//						startContainer = startContainer.firstChild;
//					}
				}
			}
			return [startContainer, startOffset, endContainer, endOffset];
		},
		setRange: function(range, startContainer,
			startOffset, endContainer, endOffset, collapsed){
			var start=dijit.range.ie.setEndPoint(range, startContainer, startOffset);

			range.setEndPoint('StartToStart',start);
			if(!collapsed){
				var end=dijit.range.ie.setEndPoint(range, endContainer, endOffset);
			}
			range.setEndPoint('EndToEnd',end || start);

			return range;
		}
	}

dojo.declare("dijit.range.W3CRange",null, {
	constructor: function(){
		if(arguments.length>0){
			this.setStart(arguments[0][0],arguments[0][1]);
			this.setEnd(arguments[0][2],arguments[0][3]);
		}else{
			this.commonAncestorContainer = null;
			this.startContainer = null;
			this.startOffset = 0;
			this.endContainer = null;
			this.endOffset = 0;
			this.collapsed = true;
		}
	},
	_updateInternal: function(){
		if(this.startContainer !== this.endContainer){
			this.commonAncestorContainer = dijit.range.getCommonAncestor(this.startContainer, this.endContainer);
		}else{
			this.commonAncestorContainer = this.startContainer;
		}
		this.collapsed = (this.startContainer === this.endContainer) && (this.startOffset == this.endOffset);
	},
	setStart: function(node, offset){
		offset=parseInt(offset);
		if(this.startContainer === node && this.startOffset == offset){
			return;
		}
		delete this._cachedBookmark;

		this.startContainer = node;
		this.startOffset = offset;
		if(!this.endContainer){
			this.setEnd(node, offset);
		}else{
			this._updateInternal();
		}
	},
	setEnd: function(node, offset){
		offset=parseInt(offset);
		if(this.endContainer === node && this.endOffset == offset){
			return;
		}
		delete this._cachedBookmark;

		this.endContainer = node;
		this.endOffset = offset;
		if(!this.startContainer){
			this.setStart(node, offset);
		}else{
			this._updateInternal();
		}
	},
	setStartAfter: function(node, offset){
		this._setPoint('setStart', node, offset, 1);
	},
	setStartBefore: function(node, offset){
		this._setPoint('setStart', node, offset, 0);
	},
	setEndAfter: function(node, offset){
		this._setPoint('setEnd', node, offset, 1);
	},
	setEndBefore: function(node, offset){
		this._setPoint('setEnd', node, offset, 0);
	},
	_setPoint: function(what, node, offset, ext){
		var index = dijit.range.getIndex(node, node.parentNode).o;
		this[what](node.parentNode, index.pop()+ext);
	},
	_getIERange: function(){
		var r = (this._body || this.endContainer.ownerDocument.body).createTextRange();
		dijit.range.ie.setRange(r, this.startContainer, this.startOffset, this.endContainer, this.endOffset, this.collapsed);
		return r;
	},
	getBookmark: function(body){
		this._getIERange();
		return this._cachedBookmark;
	},
	_select: function(){
		var r = this._getIERange();
		r.select();
	},
	deleteContents: function(){
		var r = this._getIERange();
		r.pasteHTML('');
		this.endContainer = this.startContainer;
		this.endOffset = this.startOffset;
		this.collapsed = true;
	},
	cloneRange: function(){
		var r = new dijit.range.W3CRange([this.startContainer,this.startOffset,
			this.endContainer,this.endOffset]);
		r._body = this._body;
		return r;
	},
	detach: function(){
		this._body = null;
		this.commonAncestorContainer = null;
		this.startContainer = null;
		this.startOffset = 0;
		this.endContainer = null;
		this.endOffset = 0;
		this.collapsed = true;
}
});
} //if(!dijit.range._w3c)

}

if(!dojo._hasResource["dijit._editor.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor.html"] = true;
dojo.provide("dijit._editor.html");

dijit._editor.escapeXml=function(/*String*/str, /*Boolean?*/noSingleQuotes){
	// summary:
	//		Adds escape sequences for special characters in XML: &<>"'
	//		Optionally skips escapes for single quotes
	str = str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
	if(!noSingleQuotes){
		str = str.replace(/'/gm, "&#39;");
	}
	return str; // string
};

dijit._editor.getNodeHtml=function(/* DomNode */node){
	var output;
	switch(node.nodeType){
		case 1: //element node
			var lName = node.nodeName.toLowerCase();
			if(!lName || lName.charAt(0) == "/"){
				// IE does some strange things with malformed HTML input, like
				// treating a close tag </span> without an open tag <span>, as
				// a new tag with tagName of /span.  Corrupts output HTML, remove
				// them.  Other browsers don't prefix tags that way, so will
				// never show up.
				return "";
			}
			output = '<' + lName;

			//store the list of attributes and sort it to have the
			//attributes appear in the dictionary order
			var attrarray = [];
			var attr;
			if(dojo.isIE && node.outerHTML){
				var s = node.outerHTML;
				s = s.substr(0, s.indexOf('>'))
					.replace(/(['"])[^"']*\1/g, ''); //to make the following regexp safe
				var reg = /(\b\w+)\s?=/g;
				var m, key;
				while((m = reg.exec(s))){
					key = m[1];
					if(key.substr(0,3) != '_dj'){
						if(key == 'src' || key == 'href'){
							if(node.getAttribute('_djrealurl')){
								attrarray.push([key,node.getAttribute('_djrealurl')]);
								continue;
							}
						}
						var val, match;
						switch(key){
							case 'style':
								val = node.style.cssText.toLowerCase();
								break;
							case 'class':
								val = node.className;
								break;
							case 'width':
								if(lName === "img"){
									// This somehow gets lost on IE for IMG tags and the like
									// and we have to find it in outerHTML, known IE oddity.
									match=/width=(\S+)/i.exec(s);
									if(match){
										val = match[1];
									}
									break;
								}
							case 'height':
								if(lName === "img"){
									// This somehow gets lost on IE for IMG tags and the like
									// and we have to find it in outerHTML, known IE oddity.
									match=/height=(\S+)/i.exec(s);
									if(match){
										val = match[1];
									}
									break;
								}
							default:
								val = node.getAttribute(key);
						}
						if(val != null){
							attrarray.push([key, val.toString()]);
						}
					}
				}
			}else{
				var i = 0;
				while((attr = node.attributes[i++])){
					//ignore all attributes starting with _dj which are
					//internal temporary attributes used by the editor
					var n = attr.name;
					if(n.substr(0,3) != '_dj' /*&&
						(attr.specified == undefined || attr.specified)*/){
						var v = attr.value;
						if(n == 'src' || n == 'href'){
							if(node.getAttribute('_djrealurl')){
								v = node.getAttribute('_djrealurl');
							}
						}
						attrarray.push([n,v]);
					}
				}
			}
			attrarray.sort(function(a,b){
				return a[0] < b[0] ? -1 : (a[0] == b[0] ? 0 : 1);
			});
			var j = 0;
			while((attr = attrarray[j++])){
				output += ' ' + attr[0] + '="' +
					(dojo.isString(attr[1]) ? dijit._editor.escapeXml(attr[1], true) : attr[1]) + '"';
			}
			if(lName === "script"){
				// Browsers handle script tags differently in how you get content,
				// but innerHTML always seems to work, so insert its content that way
				// Yes, it's bad to allow script tags in the editor code, but some people
				// seem to want to do it, so we need to at least return them right.
				// other plugins/filters can strip them.
				output += '>' + node.innerHTML +'</' + lName + '>';
			}else{
				if(node.childNodes.length){
					output += '>' + dijit._editor.getChildrenHtml(node)+'</' + lName +'>';
				}else{
					switch(lName){
						case 'br':
						case 'hr':
						case 'img':
						case 'input':
						case 'base':
						case 'meta':
						case 'area':
						case 'basefont':
							// These should all be singly closed
							output += ' />';
							break;
						default:
							// Assume XML style separate closure for everything else.
							output += '></' + lName + '>';
					}
				}
			}
			break;
		case 4: // cdata
		case 3: // text
			// FIXME:
			output = dijit._editor.escapeXml(node.nodeValue, true);
			break;
		case 8: //comment
			// FIXME:
			output = '<!--' + dijit._editor.escapeXml(node.nodeValue, true) + '-->';
			break;
		default:
			output = "<!-- Element not recognized - Type: " + node.nodeType + " Name: " + node.nodeName + "-->";
	}
	return output;
};

dijit._editor.getChildrenHtml = function(/* DomNode */dom){
	// summary:
	//		Returns the html content of a DomNode and children
	var out = "";
	if(!dom){ return out; }
	var nodes = dom["childNodes"] || dom;

	//IE issue.
	//If we have an actual node we can check parent relationships on for IE,
	//We should check, as IE sometimes builds invalid DOMS.  If no parent, we can't check
	//And should just process it and hope for the best.
	var checkParent = !dojo.isIE || nodes !== dom;

	var node, i = 0;
	while((node = nodes[i++])){
		//IE is broken.  DOMs are supposed to be a tree.  But in the case of malformed HTML, IE generates a graph
		//meaning one node ends up with multiple references (multiple parents).  This is totally wrong and invalid, but
		//such is what it is.  We have to keep track and check for this because otherise the source output HTML will have dups.
		//No other browser generates a graph.  Leave it to IE to break a fundamental DOM rule.  So, we check the parent if we can
		//If we can't, nothing more we can do other than walk it.
		if(!checkParent || node.parentNode == dom){
			out += dijit._editor.getNodeHtml(node);
		}
	}
	return out; // String
};

}

if(!dojo._hasResource["dijit._editor.RichText"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor.RichText"] = true;
dojo.provide("dijit._editor.RichText");







// used to restore content when user leaves this page then comes back
// but do not try doing dojo.doc.write if we are using xd loading.
// dojo.doc.write will only work if RichText.js is included in the dojo.js
// file. If it is included in dojo.js and you want to allow rich text saving
// for back/forward actions, then set dojo.config.allowXdRichTextSave = true.
if(!dojo.config["useXDomain"] || dojo.config["allowXdRichTextSave"]){
	if(dojo._postLoad){
		(function(){
			var savetextarea = dojo.doc.createElement('textarea');
			savetextarea.id = dijit._scopeName + "._editor.RichText.savedContent";
			dojo.style(savetextarea, {
				display:'none',
				position:'absolute',
				top:"-100px",
				height:"3px",
				width:"3px"
			});
			dojo.body().appendChild(savetextarea);
		})();
	}else{
		//dojo.body() is not available before onLoad is fired
		try{
			dojo.doc.write('<textarea id="' + dijit._scopeName + '._editor.RichText.savedContent" ' +
				'style="display:none;position:absolute;top:-100px;left:-100px;height:3px;width:3px;overflow:hidden;"></textarea>');
		}catch(e){ }
	}
}

dojo.declare("dijit._editor.RichText", [dijit._Widget, dijit._CssStateMixin], {
	constructor: function(params){
		// summary:
		//		dijit._editor.RichText is the core of dijit.Editor, which provides basic
		//		WYSIWYG editing features.
		//
		// description:
		//		dijit._editor.RichText is the core of dijit.Editor, which provides basic
		//		WYSIWYG editing features. It also encapsulates the differences
		//		of different js engines for various browsers.  Do not use this widget
		//		with an HTML &lt;TEXTAREA&gt; tag, since the browser unescapes XML escape characters,
		//		like &lt;.  This can have unexpected behavior and lead to security issues
		//		such as scripting attacks.
		//
		// tags:
		//		private

		// contentPreFilters: Function(String)[]
		//		Pre content filter function register array.
		//		these filters will be executed before the actual
		//		editing area gets the html content.
		this.contentPreFilters = [];

		// contentPostFilters: Function(String)[]
		//		post content filter function register array.
		//		These will be used on the resulting html
		//		from contentDomPostFilters. The resulting
		//		content is the final html (returned by getValue()).
		this.contentPostFilters = [];

		// contentDomPreFilters: Function(DomNode)[]
		//		Pre content dom filter function register array.
		//		These filters are applied after the result from
		//		contentPreFilters are set to the editing area.
		this.contentDomPreFilters = [];

		// contentDomPostFilters: Function(DomNode)[]
		//		Post content dom filter function register array.
		//		These filters are executed on the editing area dom.
		//		The result from these will be passed to contentPostFilters.
		this.contentDomPostFilters = [];

		// editingAreaStyleSheets: dojo._URL[]
		//		array to store all the stylesheets applied to the editing area
		this.editingAreaStyleSheets = [];

		// Make a copy of this.events before we start writing into it, otherwise we
		// will modify the prototype which leads to bad things on pages w/multiple editors
		this.events = [].concat(this.events);

		this._keyHandlers = {};
		this.contentPreFilters.push(dojo.hitch(this, "_preFixUrlAttributes"));
		if(dojo.isMoz){
			this.contentPreFilters.push(this._normalizeFontStyle);
			this.contentPostFilters.push(this._removeMozBogus);
		}
		if(dojo.isWebKit){
			// Try to clean up WebKit bogus artifacts.  The inserted classes
			// made by WebKit sometimes messes things up.
			this.contentPreFilters.push(this._removeWebkitBogus);
			this.contentPostFilters.push(this._removeWebkitBogus);
		}
		if(dojo.isIE){
			// IE generates <strong> and <em> but we want to normalize to <b> and <i>
			this.contentPostFilters.push(this._normalizeFontStyle);
		}
		//this.contentDomPostFilters.push(this._postDomFixUrlAttributes);

		if(params && dojo.isString(params.value)){
			this.value = params.value;
		}

		this.onLoadDeferred = new dojo.Deferred();
	},

	baseClass: "dijitEditor",

	// inheritWidth: Boolean
	//		whether to inherit the parent's width or simply use 100%
	inheritWidth: false,

	// focusOnLoad: [deprecated] Boolean
	//		Focus into this widget when the page is loaded
	focusOnLoad: false,

	// name: String?
	//		Specifies the name of a (hidden) <textarea> node on the page that's used to save
	//		the editor content on page leave.   Used to restore editor contents after navigating
	//		to a new page and then hitting the back button.
	name: "",

	// styleSheets: [const] String
	//		semicolon (";") separated list of css files for the editing area
	styleSheets: "",

	// _content: [private] String
	//		temporary content storage
	_content: "",

	// height: String
	//		Set height to fix the editor at a specific height, with scrolling.
	//		By default, this is 300px.  If you want to have the editor always
	//		resizes to accommodate the content, use AlwaysShowToolbar plugin
	//		and set height="".  If this editor is used within a layout widget,
	//		set height="100%".
	height: "300px",

	// minHeight: String
	//		The minimum height that the editor should have.
	minHeight: "1em",

	// isClosed: [private] Boolean
	isClosed: true,

	// isLoaded: [private] Boolean
	isLoaded: false,

	// _SEPARATOR: [private] String
	//		Used to concat contents from multiple editors into a single string,
	//		so they can be saved into a single <textarea> node.  See "name" attribute.
	_SEPARATOR: "@@**%%__RICHTEXTBOUNDRY__%%**@@",

	// onLoadDeferred: [protected] dojo.Deferred
	//		Deferred which is fired when the editor finishes loading
	onLoadDeferred: null,

	// isTabIndent: Boolean
	//		Make tab key and shift-tab indent and outdent rather than navigating.
	//		Caution: sing this makes web pages inaccessible to users unable to use a mouse.
	isTabIndent: false,

	// disableSpellCheck: [const] Boolean
	//		When true, disables the browser's native spell checking, if supported.
	//		Works only in Firefox.
	disableSpellCheck: false,

	postCreate: function(){
		if("textarea" == this.domNode.tagName.toLowerCase()){
			console.warn("RichText should not be used with the TEXTAREA tag.  See dijit._editor.RichText docs.");
		}

		this.inherited(arguments);

		dojo.publish(dijit._scopeName + "._editor.RichText::init", [this]);
		this.open();
		this.setupDefaultShortcuts();
	},

	setupDefaultShortcuts: function(){
		// summary:
		//		Add some default key handlers
		// description:
		// 		Overwrite this to setup your own handlers. The default
		// 		implementation does not use Editor commands, but directly
		//		executes the builtin commands within the underlying browser
		//		support.
		// tags:
		//		protected
		var exec = dojo.hitch(this, function(cmd, arg){
			return function(){
				return !this.execCommand(cmd,arg);
			};
		});

		var ctrlKeyHandlers = {
			b: exec("bold"),
			i: exec("italic"),
			u: exec("underline"),
			a: exec("selectall"),
			s: function(){ this.save(true); },
			m: function(){ this.isTabIndent = !this.isTabIndent; },

			"1": exec("formatblock", "h1"),
			"2": exec("formatblock", "h2"),
			"3": exec("formatblock", "h3"),
			"4": exec("formatblock", "h4"),

			"\\": exec("insertunorderedlist")
		};

		if(!dojo.isIE){
			ctrlKeyHandlers.Z = exec("redo"); //FIXME: undo?
		}

		for(var key in ctrlKeyHandlers){
			this.addKeyHandler(key, true, false, ctrlKeyHandlers[key]);
		}
	},

	// events: [private] String[]
	//		 events which should be connected to the underlying editing area
	events: ["onKeyPress", "onKeyDown", "onKeyUp", "onClick"],

	// captureEvents: [deprecated] String[]
	//		 Events which should be connected to the underlying editing
	//		 area, events in this array will be addListener with
	//		 capture=true.
	// TODO: looking at the code I don't see any distinction between events and captureEvents,
	// so get rid of this for 2.0 if not sooner
	captureEvents: [],

	_editorCommandsLocalized: false,
	_localizeEditorCommands: function(){
		// summary:
		//		When IE is running in a non-English locale, the API actually changes,
		//		so that we have to say (for example) danraku instead of p (for paragraph).
		//		Handle that here.
		// tags:
		//		private
		if(this._editorCommandsLocalized){
			return;
		}
		this._editorCommandsLocalized = true;

		//in IE, names for blockformat is locale dependent, so we cache the values here

		//if the normal way fails, we try the hard way to get the list

		//do not use _cacheLocalBlockFormatNames here, as it will
		//trigger security warning in IE7

		//put p after div, so if IE returns Normal, we show it as paragraph
		//We can distinguish p and div if IE returns Normal, however, in order to detect that,
		//we have to call this.document.selection.createRange().parentElement() or such, which
		//could slow things down. Leave it as it is for now
		var formats = ['div', 'p', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ol', 'ul', 'address'];
		var localhtml = "", format, i=0;
		while((format=formats[i++])){
			//append a <br> after each element to separate the elements more reliably
			if(format.charAt(1) != 'l'){
				localhtml += "<"+format+"><span>content</span></"+format+"><br/>";
			}else{
				localhtml += "<"+format+"><li>content</li></"+format+"><br/>";
			}
		}
		//queryCommandValue returns empty if we hide editNode, so move it out of screen temporary
		var div = dojo.doc.createElement('div');
		dojo.style(div, {
			position: "absolute",
			top: "-2000px"
		});
		dojo.doc.body.appendChild(div);
		div.innerHTML = localhtml;
		var node = div.firstChild;
		while(node){
			dijit._editor.selection.selectElement(node.firstChild);
			dojo.withGlobal(this.window, "selectElement", dijit._editor.selection, [node.firstChild]);
			var nativename = node.tagName.toLowerCase();
			this._local2NativeFormatNames[nativename] = document.queryCommandValue("formatblock");
			//this.queryCommandValue("formatblock");
			this._native2LocalFormatNames[this._local2NativeFormatNames[nativename]] = nativename;
			node = node.nextSibling.nextSibling;
		}
		dojo.body().removeChild(div);
	},

	open: function(/*DomNode?*/ element){
		// summary:
		//		Transforms the node referenced in this.domNode into a rich text editing
		//		node.
		// description:
		//		Sets up the editing area asynchronously. This will result in
		//		the creation and replacement with an iframe.
		//
		//		A dojo.Deferred object is created at this.onLoadDeferred, and
		//		users may attach to it to be informed when the rich-text area
		//		initialization is finalized.
		// tags:
		//		private

		if(!this.onLoadDeferred || this.onLoadDeferred.fired >= 0){
			this.onLoadDeferred = new dojo.Deferred();
		}

		if(!this.isClosed){ this.close(); }
		dojo.publish(dijit._scopeName + "._editor.RichText::open", [ this ]);

		this._content = "";
		if(arguments.length == 1 && element.nodeName){ // else unchanged
			this.domNode = element;
		}

		var dn = this.domNode;

		// "html" will hold the innerHTML of the srcNodeRef and will be used to
		// initialize the editor.
		var html;

		if(dojo.isString(this.value)){
			// Allow setting the editor content programmatically instead of
			// relying on the initial content being contained within the target
			// domNode.
			html = this.value;
			delete this.value;
			dn.innerHTML = "";
		}else if(dn.nodeName && dn.nodeName.toLowerCase() == "textarea"){
			// if we were created from a textarea, then we need to create a
			// new editing harness node.
			var ta = (this.textarea = dn);
			this.name = ta.name;
			html = ta.value;
			dn = this.domNode = dojo.doc.createElement("div");
			dn.setAttribute('widgetId', this.id);
			ta.removeAttribute('widgetId');
			dn.cssText = ta.cssText;
			dn.className += " " + ta.className;
			dojo.place(dn, ta, "before");
			var tmpFunc = dojo.hitch(this, function(){
				//some browsers refuse to submit display=none textarea, so
				//move the textarea off screen instead
				dojo.style(ta, {
					display: "block",
					position: "absolute",
					top: "-1000px"
				});

				if(dojo.isIE){ //nasty IE bug: abnormal formatting if overflow is not hidden
					var s = ta.style;
					this.__overflow = s.overflow;
					s.overflow = "hidden";
				}
			});
			if(dojo.isIE){
				setTimeout(tmpFunc, 10);
			}else{
				tmpFunc();
			}

			if(ta.form){
				dojo.connect(ta.form, "onsubmit", this, function(){
					// FIXME: should we be calling close() here instead?
					ta.value = this.getValue();
				});
			}
		}else{
			html = dijit._editor.getChildrenHtml(dn);
			dn.innerHTML = "";
		}

		var content = dojo.contentBox(dn);
		this._oldHeight = content.h;
		this._oldWidth = content.w;

		this.savedContent = html;

		// If we're a list item we have to put in a blank line to force the
		// bullet to nicely align at the top of text
		if(dn.nodeName && dn.nodeName == "LI"){
			dn.innerHTML = " <br>";
		}
	
		// Construct the editor div structure.
		this.header = dn.ownerDocument.createElement("div");
		dn.appendChild(this.header);
		this.editingArea = dn.ownerDocument.createElement("div");
		dn.appendChild(this.editingArea);
		this.footer = dn.ownerDocument.createElement("div");
		dn.appendChild(this.footer);

		// User has pressed back/forward button so we lost the text in the editor, but it's saved
		// in a hidden <textarea> (which contains the data for all the editors on this page),
		// so get editor value from there
		if(this.name !== "" && (!dojo.config["useXDomain"] || dojo.config["allowXdRichTextSave"])){
			var saveTextarea = dojo.byId(dijit._scopeName + "._editor.RichText.savedContent");
			if(saveTextarea.value !== ""){
				var datas = saveTextarea.value.split(this._SEPARATOR), i=0, dat;
				while((dat=datas[i++])){
					var data = dat.split(":");
					if(data[0] == this.name){
						html = data[1];
						datas.splice(i, 1);	// TODO: this has no effect
						break;
					}
				}
			}

			// TODO: this is troublesome if this editor has been destroyed, should have global handler.
			// TODO: need to clear <textarea> in global handler
			dojo.addOnUnload(dojo.hitch(this, "_saveContent"));
		}

		this.isClosed = false;

		var ifr = (this.editorObject = this.iframe = dojo.doc.createElement('iframe'));
		ifr.id = this.id+"_iframe";
		this._iframeSrc = this._getIframeDocTxt();
		ifr.style.border = "none";
		ifr.style.width = "100%";
		if(this._layoutMode){
			// iframe should be 100% height, thus getting it's height from surrounding
			// <div> (which has the correct height set by Editor)
			ifr.style.height = "100%";
		}else{
			if(dojo.isIE >= 7){
				if(this.height){
					ifr.style.height = this.height;
				}
				if(this.minHeight){
					ifr.style.minHeight = this.minHeight;
				}
			}else{
				ifr.style.height = this.height ? this.height : this.minHeight;
			}
		}
		ifr.frameBorder = 0;
		ifr._loadFunc = dojo.hitch( this, function(win){
			this.window = win;
			this.document = this.window.document;

			if(dojo.isIE){
				this._localizeEditorCommands();
			}
			
			// Do final setup and set initial contents of editor
			this.onLoad(html);
		});

		// Set the iframe's initial (blank) content.
		var s = 'javascript:parent.' + dijit._scopeName + '.byId("'+this.id+'")._iframeSrc';
		ifr.setAttribute('src', s);
		this.editingArea.appendChild(ifr);

		// TODO: this is a guess at the default line-height, kinda works
		if(dn.nodeName == "LI"){
			dn.lastChild.style.marginTop = "-1.2em";
		}

		dojo.addClass(this.domNode, this.baseClass);
	},

	//static cache variables shared among all instance of this class
	_local2NativeFormatNames: {},
	_native2LocalFormatNames: {},

	_getIframeDocTxt: function(){
		// summary:
		//		Generates the boilerplate text of the document inside the iframe (ie, <html><head>...</head><body/></html>).
		//		Editor content (if not blank) should be added afterwards.
		// tags:
		//		private
		var _cs = dojo.getComputedStyle(this.domNode);

		// The contents inside of <body>.  The real contents are set later via a call to setValue().
		var html = "";
		var setBodyId = true;
		if(dojo.isIE || (!this.height && !dojo.isMoz)){
			// In auto-expand mode, need a wrapper div for AlwaysShowToolbar plugin to correctly
			// expand/contract the editor as the content changes.
			html = "<div id='dijitEditorBody'></div>";
			setBodyId = false;
		}else if(dojo.isMoz){
			// workaround bug where can't select then delete text (until user types something
			// into the editor)... and/or issue where typing doesn't erase selected text
			this._cursorToStart = true;
			html = "&nbsp;";
		}

		var font = [ _cs.fontWeight, _cs.fontSize, _cs.fontFamily ].join(" ");

		// line height is tricky - applying a units value will mess things up.
		// if we can't get a non-units value, bail out.
		var lineHeight = _cs.lineHeight;
		if(lineHeight.indexOf("px") >= 0){
			lineHeight = parseFloat(lineHeight)/parseFloat(_cs.fontSize);
			// console.debug(lineHeight);
		}else if(lineHeight.indexOf("em")>=0){
			lineHeight = parseFloat(lineHeight);
		}else{
			// If we can't get a non-units value, just default
			// it to the CSS spec default of 'normal'.  Seems to
			// work better, esp on IE, than '1.0'
			lineHeight = "normal";
		}
		var userStyle = "";
		var self = this;
		this.style.replace(/(^|;)\s*(line-|font-?)[^;]+/ig, function(match){ 
			match = match.replace(/^;/ig,"") + ';'; 
			var s = match.split(":")[0];
			if(s){
				s = dojo.trim(s);
				s = s.toLowerCase();
				var i;
				var sC = "";
				for(i = 0; i < s.length; i++){
					var c = s.charAt(i);
					switch(c){
						case "-":
							i++;
							c = s.charAt(i).toUpperCase();
						default:
							sC += c;
					}
				}
				dojo.style(self.domNode, sC, "");
			}
			userStyle += match + ';'; 
		});


		// need to find any associated label element and update iframe document title
		var label=dojo.query('label[for="'+this.id+'"]');

		return [
			this.isLeftToRight() ? "<html>\n<head>\n" : "<html dir='rtl'>\n<head>\n",
			(dojo.isMoz && label.length ? "<title>" + label[0].innerHTML + "</title>\n" : ""),
			"<meta http-equiv='Content-Type' content='text/html'>\n",
			"<style>\n",
			"\tbody,html {\n",
			"\t\tbackground:transparent;\n",
			"\t\tpadding: 1px 0 0 0;\n",
			"\t\tmargin: -1px 0 0 0;\n", // remove extraneous vertical scrollbar on safari and firefox

			// Set the html/body sizing.  Webkit always needs this, other browsers
			// only set it when height is defined (not auto-expanding), otherwise 
			// scrollers do not appear.
			((dojo.isWebKit)?"\t\twidth: 100%;\n":""),
			((dojo.isWebKit)?"\t\theight: 100%;\n":""),
			"\t}\n",
			
			// TODO: left positioning will cause contents to disappear out of view
			//	   if it gets too wide for the visible area
			"\tbody{\n",
			"\t\ttop:0px;\n",
			"\t\tleft:0px;\n",
			"\t\tright:0px;\n",
			"\t\tfont:", font, ";\n",
				((this.height||dojo.isOpera) ? "" : "\t\tposition: fixed;\n"),
			// FIXME: IE 6 won't understand min-height?
			"\t\tmin-height:", this.minHeight, ";\n",
			"\t\tline-height:", lineHeight,";\n",
			"\t}\n",
			"\tp{ margin: 1em 0; }\n",
			
			// Determine how scrollers should be applied.  In autoexpand mode (height = "") no scrollers on y at all.
			// But in fixed height mode we want both x/y scrollers.  Also, if it's using wrapping div and in auto-expand
			// (Mainly IE) we need to kill the y scroller on body and html.
			(!setBodyId && !this.height ? "\tbody,html {overflow-y: hidden;}\n" : ""),
			"\t#dijitEditorBody{overflow-x: auto; overflow-y:" + (this.height ? "auto;" : "hidden;") + "}\n",
			"\tli > ul:-moz-first-node, li > ol:-moz-first-node{ padding-top: 1.2em; }\n",
			"\tli{ min-height:1.2em; }\n",
			"</style>\n",
			this._applyEditingAreaStyleSheets(),"\n",
			"</head>\n<body ",
			(setBodyId?"id='dijitEditorBody' ":""),
			"onload='frameElement._loadFunc(window,document)' style='"+userStyle+"'>", html, "</body>\n</html>"
		].join(""); // String
	},

	_applyEditingAreaStyleSheets: function(){
		// summary:
		//		apply the specified css files in styleSheets
		// tags:
		//		private
		var files = [];
		if(this.styleSheets){
			files = this.styleSheets.split(';');
			this.styleSheets = '';
		}

		//empty this.editingAreaStyleSheets here, as it will be filled in addStyleSheet
		files = files.concat(this.editingAreaStyleSheets);
		this.editingAreaStyleSheets = [];

		var text='', i=0, url;
		while((url=files[i++])){
			var abstring = (new dojo._Url(dojo.global.location, url)).toString();
			this.editingAreaStyleSheets.push(abstring);
			text += '<link rel="stylesheet" type="text/css" href="'+abstring+'"/>';
		}
		return text;
	},

	addStyleSheet: function(/*dojo._Url*/ uri){
		// summary:
		//		add an external stylesheet for the editing area
		// uri:
		//		A dojo.uri.Uri pointing to the url of the external css file
		var url=uri.toString();

		//if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
		if(url.charAt(0) == '.' || (url.charAt(0) != '/' && !uri.host)){
			url = (new dojo._Url(dojo.global.location, url)).toString();
		}

		if(dojo.indexOf(this.editingAreaStyleSheets, url) > -1){
//			console.debug("dijit._editor.RichText.addStyleSheet: Style sheet "+url+" is already applied");
			return;
		}

		this.editingAreaStyleSheets.push(url);
		this.onLoadDeferred.addCallback(dojo.hitch(function(){
			if(this.document.createStyleSheet){ //IE
				this.document.createStyleSheet(url);
			}else{ //other browser
				var head = this.document.getElementsByTagName("head")[0];
				var stylesheet = this.document.createElement("link");
				stylesheet.rel="stylesheet";
				stylesheet.type="text/css";
				stylesheet.href=url;
				head.appendChild(stylesheet);
			}
		}));
	},

	removeStyleSheet: function(/*dojo._Url*/ uri){
		// summary:
		//		remove an external stylesheet for the editing area
		var url=uri.toString();
		//if uri is relative, then convert it to absolute so that it can be resolved correctly in iframe
		if(url.charAt(0) == '.' || (url.charAt(0) != '/' && !uri.host)){
			url = (new dojo._Url(dojo.global.location, url)).toString();
		}
		var index = dojo.indexOf(this.editingAreaStyleSheets, url);
		if(index == -1){
//			console.debug("dijit._editor.RichText.removeStyleSheet: Style sheet "+url+" has not been applied");
			return;
		}
		delete this.editingAreaStyleSheets[index];
		dojo.withGlobal(this.window,'query', dojo, ['link:[href="'+url+'"]']).orphan();
	},

	// disabled: Boolean
	//		The editor is disabled; the text cannot be changed.
	disabled: false,

	_mozSettingProps: {'styleWithCSS':false},
	_setDisabledAttr: function(/*Boolean*/ value){
		this.disabled = value;
		if(!this.isLoaded){ return; } // this method requires init to be complete
		value = !!value;
		if(dojo.isIE || dojo.isWebKit || dojo.isOpera){
			var preventIEfocus = dojo.isIE && (this.isLoaded || !this.focusOnLoad);
			if(preventIEfocus){ this.editNode.unselectable = "on"; }
			this.editNode.contentEditable = !value;
			if(preventIEfocus){
				var _this = this;
				setTimeout(function(){ _this.editNode.unselectable = "off"; }, 0);
			}
		}else{ //moz
			try{
				this.document.designMode=(value?'off':'on');
			}catch(e){ return; } // ! _disabledOK
			if(!value && this._mozSettingProps){
				var ps = this._mozSettingProps;
				for(var n in ps){
					if(ps.hasOwnProperty(n)){
						try{
							this.document.execCommand(n,false,ps[n]);
						}catch(e2){}
					}
				}
			}
//			this.document.execCommand('contentReadOnly', false, value);
//				if(value){
//					this.blur(); //to remove the blinking caret
//				}
		}
		this._disabledOK = true;
	},

/* Event handlers
 *****************/

	onLoad: function(/*String*/ html){
		// summary:
		//		Handler after the iframe finishes loading.
		// html: String
		//		Editor contents should be set to this value
		// tags:
		//		protected

		// TODO: rename this to _onLoad, make empty public onLoad() method, deprecate/make protected onLoadDeferred handler?

		if(!this.window.__registeredWindow){
			this.window.__registeredWindow = true;
			this._iframeRegHandle = dijit.registerIframe(this.iframe);
		}
		if(!dojo.isIE && (this.height || dojo.isMoz)){
			this.editNode=this.document.body;
		}else{
			// there's a wrapper div around the content, see _getIframeDocTxt().
			this.editNode=this.document.body.firstChild;
			var _this = this;
			if(dojo.isIE){ // #4996 IE wants to focus the BODY tag
				var tabStop = (this.tabStop = dojo.doc.createElement('<div tabIndex=-1>'));
				this.editingArea.appendChild(tabStop);
				this.iframe.onfocus = function(){ _this.editNode.setActive(); };
			}
		}
		this.focusNode = this.editNode; // for InlineEditBox


		var events = this.events.concat(this.captureEvents);
		var ap = this.iframe ? this.document : this.editNode;
		dojo.forEach(events, function(item){
			this.connect(ap, item.toLowerCase(), item);
		}, this);

		if(dojo.isIE){ // IE contentEditable
			this.connect(this.document, "onmousedown", "_onIEMouseDown"); // #4996 fix focus

			// give the node Layout on IE
			// TODO: this may no longer be needed, since we've reverted IE to using an iframe,
			// not contentEditable.   Removing it would also probably remove the need for creating
			// the extra <div> in _getIframeDocTxt()
			this.editNode.style.zoom = 1.0;
		}else{
			this.connect(this.document, "onmousedown", function(){
				// Clear the moveToStart focus, as mouse 
				// down will set cursor point.  Required to properly
				// work with selection/position driven plugins and clicks in
				// the window. refs: #10678
				delete this._cursorToStart;
			}); 
		}

		if(dojo.isWebKit){
			//WebKit sometimes doesn't fire right on selections, so the toolbar
			//doesn't update right.  Therefore, help it out a bit with an additional
			//listener.  A mouse up will typically indicate a display change, so fire this
			//and get the toolbar to adapt.  Reference: #9532
			this._webkitListener = this.connect(this.document, "onmouseup", "onDisplayChanged");
		}

		if(dojo.isIE){
			// Try to make sure 'hidden' elements aren't visible in edit mode (like browsers other than IE
			// do).  See #9103
			try{
				this.document.execCommand('RespectVisibilityInDesign', true, null);
			}catch(e){/* squelch */}
		}

		this.isLoaded = true;

		this.set('disabled', this.disabled); // initialize content to editable (or not)

		// Note that setValue() call will only work after isLoaded is set to true (above)

		// Set up a function to allow delaying the setValue until a callback is fired
		// This ensures extensions like dijit.Editor have a way to hold the value set 
		// until plugins load (and do things like register filters.
		var setContent = dojo.hitch(this, function(){
			this.setValue(html);
			if(this.onLoadDeferred){
				this.onLoadDeferred.callback(true);
			}
			this.onDisplayChanged();
			if(this.focusOnLoad){
				// after the document loads, then set focus after updateInterval expires so that
				// onNormalizedDisplayChanged has run to avoid input caret issues
				dojo.addOnLoad(dojo.hitch(this, function(){ setTimeout(dojo.hitch(this, "focus"), this.updateInterval); }));
			}
			// Save off the initial content now
			this.savedContent = this.getValue(true);
		});
		if(this.setValueDeferred){
			this.setValueDeferred.addCallback(setContent);
		}else{
			setContent();
		}

	},

	onKeyDown: function(/* Event */ e){
		// summary:
		//		Handler for onkeydown event
		// tags:
		//		protected

		// we need this event at the moment to get the events from control keys
		// such as the backspace. It might be possible to add this to Dojo, so that
		// keyPress events can be emulated by the keyDown and keyUp detection.

		if(e.keyCode === dojo.keys.TAB && this.isTabIndent ){
			dojo.stopEvent(e); //prevent tab from moving focus out of editor

			// FIXME: this is a poor-man's indent/outdent. It would be
			// better if it added 4 "&nbsp;" chars in an undoable way.
			// Unfortunately pasteHTML does not prove to be undoable
			if(this.queryCommandEnabled((e.shiftKey ? "outdent" : "indent"))){
				this.execCommand((e.shiftKey ? "outdent" : "indent"));
			}
		}
		if(dojo.isIE){
			if(e.keyCode == dojo.keys.TAB && !this.isTabIndent){
				if(e.shiftKey && !e.ctrlKey && !e.altKey){
					// focus the BODY so the browser will tab away from it instead
					this.iframe.focus();
				}else if(!e.shiftKey && !e.ctrlKey && !e.altKey){
					// focus the BODY so the browser will tab away from it instead
					this.tabStop.focus();
				}
			}else if(e.keyCode === dojo.keys.BACKSPACE && this.document.selection.type === "Control"){
				// IE has a bug where if a non-text object is selected in the editor,
				// hitting backspace would act as if the browser's back button was
				// clicked instead of deleting the object. see #1069
				dojo.stopEvent(e);
				this.execCommand("delete");
			}else if((65 <= e.keyCode && e.keyCode <= 90) ||
				(e.keyCode>=37 && e.keyCode<=40) // FIXME: get this from connect() instead!
			){ //arrow keys
				e.charCode = e.keyCode;
				this.onKeyPress(e);
			}
		}
		return true;
	},

	onKeyUp: function(e){
		// summary:
		//		Handler for onkeyup event
		// tags:
		//      callback
		return;
	},

	setDisabled: function(/*Boolean*/ disabled){
		// summary:
		//		Deprecated, use set('disabled', ...) instead.
		// tags:
		//		deprecated
		dojo.deprecated('dijit.Editor::setDisabled is deprecated','use dijit.Editor::attr("disabled",boolean) instead', 2.0);
		this.set('disabled',disabled);
	},
	_setValueAttr: function(/*String*/ value){
		// summary:
		//      Registers that attr("value", foo) should call setValue(foo)
		this.setValue(value);
	},
	_setDisableSpellCheckAttr: function(/*Boolean*/ disabled){
		if(this.document){
			dojo.attr(this.document.body, "spellcheck", !disabled);
		}else{
			// try again after the editor is finished loading
			this.onLoadDeferred.addCallback(dojo.hitch(this, function(){
				dojo.attr(this.document.body, "spellcheck", !disabled);
			}));
		}
		this.disableSpellCheck = disabled;
	},

	onKeyPress: function(e){
		// summary:
		//		Handle the various key events
		// tags:
		//		protected

		var c = (e.keyChar && e.keyChar.toLowerCase()) || e.keyCode,
			handlers = this._keyHandlers[c],
			args = arguments;

		if(handlers && !e.altKey){
			dojo.some(handlers, function(h){
				// treat meta- same as ctrl-, for benefit of mac users
				if(!(h.shift ^ e.shiftKey) && !(h.ctrl ^ (e.ctrlKey||e.metaKey))){
					if(!h.handler.apply(this, args)){
						e.preventDefault();
					}
					return true;
				}
			}, this);
		}

		// function call after the character has been inserted
		if(!this._onKeyHitch){
			this._onKeyHitch = dojo.hitch(this, "onKeyPressed");
		}
		setTimeout(this._onKeyHitch, 1);
		return true;
	},

	addKeyHandler: function(/*String*/ key, /*Boolean*/ ctrl, /*Boolean*/ shift, /*Function*/ handler){
		// summary:
		//		Add a handler for a keyboard shortcut
		// description:
		//		The key argument should be in lowercase if it is a letter character
		// tags:
		//		protected
		if(!dojo.isArray(this._keyHandlers[key])){
			this._keyHandlers[key] = [];
		}
		//TODO: would be nice to make this a hash instead of an array for quick lookups
		this._keyHandlers[key].push({
			shift: shift || false,
			ctrl: ctrl || false,
			handler: handler
		});
	},

	onKeyPressed: function(){
		// summary:
		//		Handler for after the user has pressed a key, and the display has been updated.
		//		(Runs on a timer so that it runs after the display is updated)
		// tags:
		//		private
		this.onDisplayChanged(/*e*/); // can't pass in e
	},

	onClick: function(/*Event*/ e){
		// summary:
		//		Handler for when the user clicks.
		// tags:
		//		private

		// console.info('onClick',this._tryDesignModeOn);
		this.onDisplayChanged(e);
	},

	_onIEMouseDown: function(/*Event*/ e){
		// summary:
		//		IE only to prevent 2 clicks to focus
		// tags:
		//		protected

		if(!this._focused && !this.disabled){
			this.focus();
		}
	},

	_onBlur: function(e){
		// summary:
		//		Called from focus manager when focus has moved away from this editor
		// tags:
		//		protected

		// console.info('_onBlur')

		this.inherited(arguments);
		var _c=this.getValue(true);

		if(_c!=this.savedContent){
			this.onChange(_c);
			this.savedContent=_c;
		}
	},
	_onFocus: function(/*Event*/ e){
		// summary:
		//		Called from focus manager when focus has moved into this editor
		// tags:
		//		protected

		// console.info('_onFocus')
		if(!this.disabled){
			if(!this._disabledOK){
				this.set('disabled', false);
			}
			this.inherited(arguments);
		}
	},

	// TODO: why is this needed - should we deprecate this ?
	blur: function(){
		// summary:
		//		Remove focus from this instance.
		// tags:
		//		deprecated
		if(!dojo.isIE && this.window.document.documentElement && this.window.document.documentElement.focus){
			this.window.document.documentElement.focus();
		}else if(dojo.doc.body.focus){
			dojo.doc.body.focus();
		}
	},

	focus: function(){
		// summary:
		//		Move focus to this editor
		if(!this.isLoaded){
			this.focusOnLoad = true;
			return;
		}
		if(this._cursorToStart){ 
			delete this._cursorToStart;
			if(this.editNode.childNodes){
				this.placeCursorAtStart(); // this calls focus() so return
				return;
			}
		}
		if(!dojo.isIE){
			dijit.focus(this.iframe);
		}else if(this.editNode && this.editNode.focus){
			// editNode may be hidden in display:none div, lets just punt in this case
			//this.editNode.focus(); -> causes IE to scroll always (strict and quirks mode) to the top the Iframe
			// if we fire the event manually and let the browser handle the focusing, the latest
			// cursor position is focused like in FF
			this.iframe.fireEvent('onfocus', document.createEventObject()); // createEventObject only in IE
		//	}else{
		// TODO: should we throw here?
		// console.debug("Have no idea how to focus into the editor!");
		}
	},

	// _lastUpdate: 0,
	updateInterval: 200,
	_updateTimer: null,
	onDisplayChanged: function(/*Event*/ e){
		// summary:
		//		This event will be fired everytime the display context
		//		changes and the result needs to be reflected in the UI.
		// description:
		//		If you don't want to have update too often,
		//		onNormalizedDisplayChanged should be used instead
		// tags:
		//		private

		// var _t=new Date();
		if(this._updateTimer){
			clearTimeout(this._updateTimer);
		}
		if(!this._updateHandler){
			this._updateHandler = dojo.hitch(this,"onNormalizedDisplayChanged");
		}
		this._updateTimer = setTimeout(this._updateHandler, this.updateInterval);
	},
	onNormalizedDisplayChanged: function(){
		// summary:
		//		This event is fired every updateInterval ms or more
		// description:
		//		If something needs to happen immediately after a
		//		user change, please use onDisplayChanged instead.
		// tags:
		//		private
		delete this._updateTimer;
	},
	onChange: function(newContent){
		// summary:
		//		This is fired if and only if the editor loses focus and
		//		the content is changed.
	},
	_normalizeCommand: function(/*String*/ cmd, /*Anything?*/argument){
		// summary:
		//		Used as the advice function by dojo.connect to map our
		//		normalized set of commands to those supported by the target
		//		browser.
		// tags:
		//		private

		var command = cmd.toLowerCase();
		if(command == "formatblock"){
			if(dojo.isSafari && argument === undefined){ command = "heading"; }
		}else if(command == "hilitecolor" && !dojo.isMoz){
			command = "backcolor";
		}

		return command;
	},

	_qcaCache: {},
	queryCommandAvailable: function(/*String*/ command){
		// summary:
		//		Tests whether a command is supported by the host. Clients
		//		SHOULD check whether a command is supported before attempting
		//		to use it, behaviour for unsupported commands is undefined.
		// command:
		//		The command to test for
		// tags:
		//		private

		// memoizing version. See _queryCommandAvailable for computing version
		var ca = this._qcaCache[command];
		if(ca !== undefined){ return ca; }
		return (this._qcaCache[command] = this._queryCommandAvailable(command));
	},

	_queryCommandAvailable: function(/*String*/ command){
		// summary:
		//		See queryCommandAvailable().
		// tags:
		//		private

		var ie = 1;
		var mozilla = 1 << 1;
		var webkit = 1 << 2;
		var opera = 1 << 3;
		var webkit420 = 1 << 4;

		function isSupportedBy(browsers){
			return {
				ie: Boolean(browsers & ie),
				mozilla: Boolean(browsers & mozilla),
				webkit: Boolean(browsers & webkit),
				webkit420: Boolean(browsers & webkit420),
				opera: Boolean(browsers & opera)
			};
		}

		var supportedBy = null;

		switch(command.toLowerCase()){
			case "bold": case "italic": case "underline":
			case "subscript": case "superscript":
			case "fontname": case "fontsize":
			case "forecolor": case "hilitecolor":
			case "justifycenter": case "justifyfull": case "justifyleft":
			case "justifyright": case "delete": case "selectall": case "toggledir":
				supportedBy = isSupportedBy(mozilla | ie | webkit | opera);
				break;

			case "createlink": case "unlink": case "removeformat":
			case "inserthorizontalrule": case "insertimage":
			case "insertorderedlist": case "insertunorderedlist":
			case "indent": case "outdent": case "formatblock":
			case "inserthtml": case "undo": case "redo": case "strikethrough": case "tabindent":
				supportedBy = isSupportedBy(mozilla | ie | opera | webkit420);
				break;

			case "blockdirltr": case "blockdirrtl":
			case "dirltr": case "dirrtl":
			case "inlinedirltr": case "inlinedirrtl":
				supportedBy = isSupportedBy(ie);
				break;
			case "cut": case "copy": case "paste":
				supportedBy = isSupportedBy( ie | mozilla | webkit420);
				break;

			case "inserttable":
				supportedBy = isSupportedBy(mozilla | ie);
				break;

			case "insertcell": case "insertcol": case "insertrow":
			case "deletecells": case "deletecols": case "deleterows":
			case "mergecells": case "splitcell":
				supportedBy = isSupportedBy(ie | mozilla);
				break;

			default: return false;
		}

		return (dojo.isIE && supportedBy.ie) ||
			(dojo.isMoz && supportedBy.mozilla) ||
			(dojo.isWebKit && supportedBy.webkit) ||
			(dojo.isWebKit > 420 && supportedBy.webkit420) ||
			(dojo.isOpera && supportedBy.opera);	// Boolean return true if the command is supported, false otherwise
	},

	execCommand: function(/*String*/ command, argument){
		// summary:
		//		Executes a command in the Rich Text area
		// command:
		//		The command to execute
		// argument:
		//		An optional argument to the command
		// tags:
		//		protected
		var returnValue;

		//focus() is required for IE to work
		//In addition, focus() makes sure after the execution of
		//the command, the editor receives the focus as expected
		this.focus();

		command = this._normalizeCommand(command, argument);


		if(argument !== undefined){
			if(command == "heading"){
				throw new Error("unimplemented");
			}else if((command == "formatblock") && dojo.isIE){
				argument = '<'+argument+'>';
			}
		}

		//Check to see if we have any over-rides for commands, they will be functions on this
		//widget of the form _commandImpl.  If we don't, fall through to the basic native
		//exec command of the browser.
		var implFunc = "_" + command + "Impl";
		if(this[implFunc]){
			returnValue = this[implFunc](argument);
		}else{
			argument = arguments.length > 1 ? argument : null;
			if(argument || command!="createlink"){
				returnValue = this.document.execCommand(command, false, argument);
			}
		}

		this.onDisplayChanged();
		return returnValue;
	},

	queryCommandEnabled: function(/*String*/ command){
		// summary:
		//		Check whether a command is enabled or not.
		// tags:
		//		protected
		if(this.disabled || !this._disabledOK){ return false; }
		command = this._normalizeCommand(command);
		if(dojo.isMoz || dojo.isWebKit){
			if(command == "unlink"){ // mozilla returns true always
				// console.debug(this._sCall("hasAncestorElement", ['a']));
				return this._sCall("hasAncestorElement", ["a"]);
			}else if(command == "inserttable"){
				return true;
			}
		}
		//see #4109
		if(dojo.isWebKit){
			if(command == "copy"){
				command = "cut";
			}else if(command == "paste"){
				return true;
			}
		}

		var elem = dojo.isIE ? this.document.selection.createRange() : this.document;
		try{
			return elem.queryCommandEnabled(command);
		}catch(e){
			//Squelch, occurs if editor is hidden on FF 3 (and maybe others.)
			return false;
		}

	},

	queryCommandState: function(command){
		// summary:
		//		Check the state of a given command and returns true or false.
		// tags:
		//		protected

		if(this.disabled || !this._disabledOK){ return false; }
		command = this._normalizeCommand(command);
		try{
			return this.document.queryCommandState(command);
		}catch(e){
			//Squelch, occurs if editor is hidden on FF 3 (and maybe others.)
			return false;
		}
	},

	queryCommandValue: function(command){
		// summary:
		//		Check the value of a given command. This matters most for
		//		custom selections and complex values like font value setting.
		// tags:
		//		protected

		if(this.disabled || !this._disabledOK){ return false; }
		var r;
		command = this._normalizeCommand(command);
		if(dojo.isIE && command == "formatblock"){
			r = this._native2LocalFormatNames[this.document.queryCommandValue(command)];
		}else if(dojo.isMoz && command === "hilitecolor"){
			var oldValue;
			try{
				oldValue = this.document.queryCommandValue("styleWithCSS");
			}catch(e){
				oldValue = false;
			}
			this.document.execCommand("styleWithCSS", false, true);
			r = this.document.queryCommandValue(command);
			this.document.execCommand("styleWithCSS", false, oldValue);
		}else{
			r = this.document.queryCommandValue(command);
		}
		return r;
	},

	// Misc.

	_sCall: function(name, args){
		// summary:
		//		Run the named method of dijit._editor.selection over the
		//		current editor instance's window, with the passed args.
		// tags:
		//		private
		return dojo.withGlobal(this.window, name, dijit._editor.selection, args);
	},

	// FIXME: this is a TON of code duplication. Why?

	placeCursorAtStart: function(){
		// summary:
		//		Place the cursor at the start of the editing area.
		// tags:
		//		private

		this.focus();

		//see comments in placeCursorAtEnd
		var isvalid=false;
		if(dojo.isMoz){
			// TODO:  Is this branch even necessary?
			var first=this.editNode.firstChild;
			while(first){
				if(first.nodeType == 3){
					if(first.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
						isvalid=true;
						this._sCall("selectElement", [ first ]);
						break;
					}
				}else if(first.nodeType == 1){
					isvalid=true;
					var tg = first.tagName ? first.tagName.toLowerCase() : "";
					// Collapse before childless tags.
					if(/br|input|img|base|meta|area|basefont|hr|link/.test(tg)){
						this._sCall("selectElement", [ first ]);
					}else{
						// Collapse inside tags with children.
						this._sCall("selectElementChildren", [ first ]);
					}
					break;
				}
				first = first.nextSibling;
			}
		}else{
			isvalid=true;
			this._sCall("selectElementChildren", [ this.editNode ]);
		}
		if(isvalid){
			this._sCall("collapse", [ true ]);
		}
	},

	placeCursorAtEnd: function(){
		// summary:
		//		Place the cursor at the end of the editing area.
		// tags:
		//		private

		this.focus();

		//In mozilla, if last child is not a text node, we have to use
		// selectElementChildren on this.editNode.lastChild otherwise the
		// cursor would be placed at the end of the closing tag of
		//this.editNode.lastChild
		var isvalid=false;
		if(dojo.isMoz){
			var last=this.editNode.lastChild;
			while(last){
				if(last.nodeType == 3){
					if(last.nodeValue.replace(/^\s+|\s+$/g, "").length>0){
						isvalid=true;
						this._sCall("selectElement", [ last ]);
						break;
					}
				}else if(last.nodeType == 1){
					isvalid=true;
					if(last.lastChild){
						this._sCall("selectElement", [ last.lastChild ]);
					}else{
						this._sCall("selectElement", [ last ]);
					}
					break;
				}
				last = last.previousSibling;
			}
		}else{
			isvalid=true;
			this._sCall("selectElementChildren", [ this.editNode ]);
		}
		if(isvalid){
			this._sCall("collapse", [ false ]);
		}
	},

	getValue: function(/*Boolean?*/ nonDestructive){
		// summary:
		//		Return the current content of the editing area (post filters
		//		are applied).  Users should call attr('value') instead.
		//	nonDestructive:
		//		defaults to false. Should the post-filtering be run over a copy
		//		of the live DOM? Most users should pass "true" here unless they
		//		*really* know that none of the installed filters are going to
		//		mess up the editing session.
		// tags:
		//		private
		if(this.textarea){
			if(this.isClosed || !this.isLoaded){
				return this.textarea.value;
			}
		}

		return this._postFilterContent(null, nonDestructive);
	},
	_getValueAttr: function(){
		// summary:
		//		Hook to make attr("value") work
		return this.getValue(true);
	},

	setValue: function(/*String*/ html){
		// summary:
		//		This function sets the content. No undo history is preserved.
		//		Users should use set('value', ...) instead.
		// tags:
		//		deprecated

		// TODO: remove this and getValue() for 2.0, and move code to _setValueAttr()

		if(!this.isLoaded){
			// try again after the editor is finished loading
			this.onLoadDeferred.addCallback(dojo.hitch(this, function(){
				this.setValue(html);
			}));
			return;
		}
		this._cursorToStart = true;
		if(this.textarea && (this.isClosed || !this.isLoaded)){
			this.textarea.value=html;
		}else{
			html = this._preFilterContent(html);
			var node = this.isClosed ? this.domNode : this.editNode;

			// Use &nbsp; to avoid webkit problems where editor is disabled until the user clicks it
			if(!html && dojo.isWebKit){
				html = "&nbsp;";
			}
			node.innerHTML = html;
			this._preDomFilterContent(node);
		}
		this.onDisplayChanged();
	},

	replaceValue: function(/*String*/ html){
		// summary:
		//		This function set the content while trying to maintain the undo stack
		//		(now only works fine with Moz, this is identical to setValue in all
		//		other browsers)
		// tags:
		//		protected

		if(this.isClosed){
			this.setValue(html);
		}else if(this.window && this.window.getSelection && !dojo.isMoz){ // Safari
			// look ma! it's a totally f'd browser!
			this.setValue(html);
		}else if(this.window && this.window.getSelection){ // Moz
			html = this._preFilterContent(html);
			this.execCommand("selectall");
			if(!html){ 
				this._cursorToStart = true;
				html = "&nbsp;"; 
			}
			this.execCommand("inserthtml", html);
			this._preDomFilterContent(this.editNode);
		}else if(this.document && this.document.selection){//IE
			//In IE, when the first element is not a text node, say
			//an <a> tag, when replacing the content of the editing
			//area, the <a> tag will be around all the content
			//so for now, use setValue for IE too
			this.setValue(html);
		}
	},

	_preFilterContent: function(/*String*/ html){
		// summary:
		//		Filter the input before setting the content of the editing
		//		area. DOM pre-filtering may happen after this
		//		string-based filtering takes place but as of 1.2, this is not
		//		guaranteed for operations such as the inserthtml command.
		// tags:
		//		private

		var ec = html;
		dojo.forEach(this.contentPreFilters, function(ef){ if(ef){ ec = ef(ec); } });
		return ec;
	},
	_preDomFilterContent: function(/*DomNode*/ dom){
		// summary:
		//		filter the input's live DOM. All filter operations should be
		//		considered to be "live" and operating on the DOM that the user
		//		will be interacting with in their editing session.
		// tags:
		//		private
		dom = dom || this.editNode;
		dojo.forEach(this.contentDomPreFilters, function(ef){
			if(ef && dojo.isFunction(ef)){
				ef(dom);
			}
		}, this);
	},

	_postFilterContent: function(
		/*DomNode|DomNode[]|String?*/ dom,
		/*Boolean?*/ nonDestructive){
		// summary:
		//		filter the output after getting the content of the editing area
		//
		// description:
		//		post-filtering allows plug-ins and users to specify any number
		//		of transforms over the editor's content, enabling many common
		//		use-cases such as transforming absolute to relative URLs (and
		//		vice-versa), ensuring conformance with a particular DTD, etc.
		//		The filters are registered in the contentDomPostFilters and
		//		contentPostFilters arrays. Each item in the
		//		contentDomPostFilters array is a function which takes a DOM
		//		Node or array of nodes as its only argument and returns the
		//		same. It is then passed down the chain for further filtering.
		//		The contentPostFilters array behaves the same way, except each
		//		member operates on strings. Together, the DOM and string-based
		//		filtering allow the full range of post-processing that should
		//		be necessaray to enable even the most agressive of post-editing
		//		conversions to take place.
		//
		//		If nonDestructive is set to "true", the nodes are cloned before
		//		filtering proceeds to avoid potentially destructive transforms
		//		to the content which may still needed to be edited further.
		//		Once DOM filtering has taken place, the serialized version of
		//		the DOM which is passed is run through each of the
		//		contentPostFilters functions.
		//
		//	dom:
		//		a node, set of nodes, which to filter using each of the current
		//		members of the contentDomPostFilters and contentPostFilters arrays.
		//
		//	nonDestructive:
		//		defaults to "false". If true, ensures that filtering happens on
		//		a clone of the passed-in content and not the actual node
		//		itself.
		//
		// tags:
		//		private

		var ec;
		if(!dojo.isString(dom)){
			dom = dom || this.editNode;
			if(this.contentDomPostFilters.length){
				if(nonDestructive){
					dom = dojo.clone(dom);
				}
				dojo.forEach(this.contentDomPostFilters, function(ef){
					dom = ef(dom);
				});
			}
			ec = dijit._editor.getChildrenHtml(dom);
		}else{
			ec = dom;
		}

		if(!dojo.trim(ec.replace(/^\xA0\xA0*/, '').replace(/\xA0\xA0*$/, '')).length){
			ec = "";
		}

		//	if(dojo.isIE){
		//		//removing appended <P>&nbsp;</P> for IE
		//		ec = ec.replace(/(?:<p>&nbsp;</p>[\n\r]*)+$/i,"");
		//	}
		dojo.forEach(this.contentPostFilters, function(ef){
			ec = ef(ec);
		});

		return ec;
	},

	_saveContent: function(/*Event*/ e){
		// summary:
		//		Saves the content in an onunload event if the editor has not been closed
		// tags:
		//		private

		var saveTextarea = dojo.byId(dijit._scopeName + "._editor.RichText.savedContent");
		if(saveTextarea.value){
			saveTextarea.value += this._SEPARATOR;
		}
		saveTextarea.value += this.name + ":" + this.getValue(true);
	},


	escapeXml: function(/*String*/ str, /*Boolean*/ noSingleQuotes){
		// summary:
		//		Adds escape sequences for special characters in XML.
		//		Optionally skips escapes for single quotes
		// tags:
		//		private

		str = str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;");
		if(!noSingleQuotes){
			str = str.replace(/'/gm, "&#39;");
		}
		return str; // string
	},

	getNodeHtml: function(/* DomNode */ node){
		// summary:
		//		Deprecated.   Use dijit._editor._getNodeHtml() instead.
		// tags:
		//		deprecated
		dojo.deprecated('dijit.Editor::getNodeHtml is deprecated','use dijit._editor.getNodeHtml instead', 2);
		return dijit._editor.getNodeHtml(node); // String
	},

	getNodeChildrenHtml: function(/* DomNode */ dom){
		// summary:
		//		Deprecated.   Use dijit._editor.getChildrenHtml() instead.
		// tags:
		//		deprecated
		dojo.deprecated('dijit.Editor::getNodeChildrenHtml is deprecated','use dijit._editor.getChildrenHtml instead', 2);
		return dijit._editor.getChildrenHtml(dom);
	},

	close: function(/*Boolean*/ save){
		// summary:
		//		Kills the editor and optionally writes back the modified contents to the
		//		element from which it originated.
		// save:
		//		Whether or not to save the changes. If false, the changes are discarded.
		// tags:
		//		private

		if(this.isClosed){return false; }

		if(!arguments.length){ save = true; }
		this._content = this.getValue();
		var changed = (this.savedContent != this._content);

		// line height is squashed for iframes
		// FIXME: why was this here? if (this.iframe){ this.domNode.style.lineHeight = null; }

		if(this.interval){ clearInterval(this.interval); }

		if(this._webkitListener){
			//Cleaup of WebKit fix: #9532
			this.disconnect(this._webkitListener);
			delete this._webkitListener;
		}

		// Guard against memory leaks on IE (see #9268)
		if(dojo.isIE){
			 this.iframe.onfocus = null;
		}
		this.iframe._loadFunc = null;

		if(this._iframeRegHandle){
			dijit.unregisterIframe(this._iframeRegHandle);
			delete this._iframeRegHandle;
		}

		if(this.textarea){
			var s = this.textarea.style;
			s.position = "";
			s.left = s.top = "";
			if(dojo.isIE){
				s.overflow = this.__overflow;
				this.__overflow = null;
			}
			this.textarea.value = save ? this._content : this.savedContent;
			dojo.destroy(this.domNode);
			this.domNode = this.textarea;
		}else{
			// if(save){
			// why we treat moz differently? comment out to fix #1061
			//		if(dojo.isMoz){
			//			var nc = dojo.doc.createElement("span");
			//			this.domNode.appendChild(nc);
			//			nc.innerHTML = this.editNode.innerHTML;
			//		}else{
			//			this.domNode.innerHTML = this._content;
			//		}
			// }

			// Note that this destroys the iframe
			this.domNode.innerHTML = save ? this._content : this.savedContent;
		}
		delete this.iframe;

		dojo.removeClass(this.domNode, this.baseClass);
		this.isClosed = true;
		this.isLoaded = false;

		delete this.editNode;
		delete this.focusNode;

		if(this.window && this.window._frameElement){
			this.window._frameElement = null;
		}

		this.window = null;
		this.document = null;
		this.editingArea = null;
		this.editorObject = null;

		return changed; // Boolean: whether the content has been modified
	},

	destroy: function(){
		if(!this.isClosed){ this.close(false); }
		this.inherited(arguments);
	},

	_removeMozBogus: function(/* String */ html){
		// summary:
		//		Post filter to remove unwanted HTML attributes generated by mozilla
		// tags:
		//		private
		return html.replace(/\stype="_moz"/gi, '').replace(/\s_moz_dirty=""/gi, '').replace(/_moz_resizing="(true|false)"/gi,''); // String
	},
	_removeWebkitBogus: function(/* String */ html){
		// summary:
		//		Post filter to remove unwanted HTML attributes generated by webkit
		// tags:
		//		private
		html = html.replace(/\sclass="webkit-block-placeholder"/gi, '');
		html = html.replace(/\sclass="apple-style-span"/gi, '');
		return html; // String
	},
	_normalizeFontStyle: function(/* String */ html){
		// summary:
		//		Convert 'strong' and 'em' to 'b' and 'i'.
		// description:
		//		Moz can not handle strong/em tags correctly, so to help
		//		mozilla and also to normalize output, convert them to 'b' and 'i'.
		//
		//		Note the IE generates 'strong' and 'em' rather than 'b' and 'i'
		// tags:
		//		private
		return html.replace(/<(\/)?strong([ \>])/gi, '<$1b$2')
			.replace(/<(\/)?em([ \>])/gi, '<$1i$2' ); // String
	},

	_preFixUrlAttributes: function(/* String */ html){
		// summary:
		//		Pre-filter to do fixing to href attributes on <a> and <img> tags
		// tags:
		//		private
		return html.replace(/(?:(<a(?=\s).*?\shref=)("|')(.*?)\2)|(?:(<a\s.*?href=)([^"'][^ >]+))/gi,
				'$1$4$2$3$5$2 _djrealurl=$2$3$5$2')
			.replace(/(?:(<img(?=\s).*?\ssrc=)("|')(.*?)\2)|(?:(<img\s.*?src=)([^"'][^ >]+))/gi,
				'$1$4$2$3$5$2 _djrealurl=$2$3$5$2'); // String
	},

	/*****************************************************************************
		The following functions implement HTML manipulation commands for various
		browser/contentEditable implementations.  The goal of them is to enforce
		standard behaviors of them.
	******************************************************************************/

	_inserthorizontalruleImpl: function(argument){
		// summary:
		//		This function implements the insertion of HTML 'HR' tags.
		//		into a point on the page.  IE doesn't to it right, so
		//		we have to use an alternate form
		// argument:
		//		arguments to the exec command, if any.
		// tags:
		//		protected
		if(dojo.isIE){
			return this._inserthtmlImpl("<hr>");
		}
		return this.document.execCommand("inserthorizontalrule", false, argument);
	},

	_unlinkImpl: function(argument){
		// summary:
		//		This function implements the unlink of an 'a' tag.
		// argument:
		//		arguments to the exec command, if any.
		// tags:
		//		protected
		if((this.queryCommandEnabled("unlink")) && (dojo.isMoz || dojo.isWebKit)){
			var a = this._sCall("getAncestorElement", [ "a" ]);
			this._sCall("selectElement", [ a ]);
			return this.document.execCommand("unlink", false, null);
		}
		return this.document.execCommand("unlink", false, argument);
	},

	_hilitecolorImpl: function(argument){
		// summary:
		//		This function implements the hilitecolor command
		// argument:
		//		arguments to the exec command, if any.
		// tags:
		//		protected
		var returnValue;
		if(dojo.isMoz){
			// mozilla doesn't support hilitecolor properly when useCSS is
			// set to false (bugzilla #279330)
			this.document.execCommand("styleWithCSS", false, true);
			returnValue = this.document.execCommand("hilitecolor", false, argument);
			this.document.execCommand("styleWithCSS", false, false);
		}else{
			returnValue = this.document.execCommand("hilitecolor", false, argument);
		}
		return returnValue;
	},

	_backcolorImpl: function(argument){
		// summary:
		//		This function implements the backcolor command
		// argument:
		//		arguments to the exec command, if any.
		// tags:
		//		protected
		if(dojo.isIE){
			// Tested under IE 6 XP2, no problem here, comment out
			// IE weirdly collapses ranges when we exec these commands, so prevent it
			//	var tr = this.document.selection.createRange();
			argument = argument ? argument : null;
		}
		return this.document.execCommand("backcolor", false, argument);
	},

	_forecolorImpl: function(argument){
		// summary:
		//		This function implements the forecolor command
		// argument:
		//		arguments to the exec command, if any.
		// tags:
		//		protected
		if(dojo.isIE){
			// Tested under IE 6 XP2, no problem here, comment out
			// IE weirdly collapses ranges when we exec these commands, so prevent it
			//	var tr = this.document.selection.createRange();
			argument = argument? argument : null;
		}
		return this.document.execCommand("forecolor", false, argument);
	},

	_inserthtmlImpl: function(argument){
		// summary:
		//		This function implements the insertion of HTML content into
		//		a point on the page.
		// argument:
		//		The content to insert, if any.
		// tags:
		//		protected
		argument = this._preFilterContent(argument);
		var rv = true;
		if(dojo.isIE){
			var insertRange = this.document.selection.createRange();
			if(this.document.selection.type.toUpperCase() == 'CONTROL'){
				var n=insertRange.item(0);
				while(insertRange.length){
					insertRange.remove(insertRange.item(0));
				}
				n.outerHTML=argument;
			}else{
				insertRange.pasteHTML(argument);
			}
			insertRange.select();
			//insertRange.collapse(true);
		}else if(dojo.isMoz && !argument.length){
			//mozilla can not inserthtml an empty html to delete current selection
			//so we delete the selection instead in this case
			this._sCall("remove"); // FIXME
		}else{
			rv = this.document.execCommand("inserthtml", false, argument);
		}
		return rv;
	},

	getHeaderHeight: function(){
		// summary:
		//		A function for obtaining the height of the header node
		return this._getNodeChildrenHeight(this.header); // Number
	},

	getFooterHeight: function(){
		// summary:
		//		A function for obtaining the height of the footer node
		return this._getNodeChildrenHeight(this.footer); // Number
	},

	_getNodeChildrenHeight: function(node){
		// summary:
		//		An internal function for computing the cumulative height of all child nodes of 'node'
		// node:
		//		The node to process the children of;
		var h = 0;
		if(node && node.childNodes){
			// IE didn't compute it right when position was obtained on the node directly is some cases, 
			// so we have to walk over all the children manually.
			var i; 
			for(i = 0; i < node.childNodes.length; i++){ 
				var size = dojo.position(node.childNodes[i]); 
				h += size.h;   
			} 
		}
		return h; // Number
	}
});

}

if(!dojo._hasResource["dijit._editor._Plugin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor._Plugin"] = true;
dojo.provide("dijit._editor._Plugin");



dojo.declare("dijit._editor._Plugin", null, {
	// summary
	//		Base class for a "plugin" to the editor, which is usually
	//		a single button on the Toolbar and some associated code

	constructor: function(/*Object?*/args, /*DomNode?*/node){
		this.params = args || {};
		dojo.mixin(this, this.params);
		this._connects=[];
	},

	// editor: [const] dijit.Editor
	//		Points to the parent editor
	editor: null,

	// iconClassPrefix: [const] String
	//		The CSS class name for the button node is formed from `iconClassPrefix` and `command`
	iconClassPrefix: "dijitEditorIcon",

	// button: dijit._Widget?
	//		Pointer to `dijit.form.Button` or other widget (ex: `dijit.form.FilteringSelect`)
	//		that is added to the toolbar to control this plugin.
	//		If not specified, will be created on initialization according to `buttonClass`
	button: null,

	// command: String
	//		String like "insertUnorderedList", "outdent", "justifyCenter", etc. that represents an editor command.
	//		Passed to editor.execCommand() if `useDefaultCommand` is true.
	command: "",

	// useDefaultCommand: Boolean
	//		If true, this plugin executes by calling Editor.execCommand() with the argument specified in `command`.
	useDefaultCommand: true,

	// buttonClass: Widget Class
	//		Class of widget (ex: dijit.form.Button or dijit.form.FilteringSelect)
	//		that is added to the toolbar to control this plugin.
	//		This is used to instantiate the button, unless `button` itself is specified directly.
	buttonClass: dijit.form.Button,

	getLabel: function(/*String*/key){
		// summary:
		//		Returns the label to use for the button
		// tags:
		//		private
		return this.editor.commands[key];		// String
	},

	_initButton: function(){
		// summary:
		//		Initialize the button or other widget that will control this plugin.
		//		This code only works for plugins controlling built-in commands in the editor.
		// tags:
		//		protected extension
		if(this.command.length){
			var label = this.getLabel(this.command),
				editor = this.editor,
				className = this.iconClassPrefix+" "+this.iconClassPrefix + this.command.charAt(0).toUpperCase() + this.command.substr(1);
			if(!this.button){
				var props = dojo.mixin({
					label: label,
					dir: editor.dir,
					lang: editor.lang,
					showLabel: false,
					iconClass: className,
					dropDown: this.dropDown,
					tabIndex: "-1"
				}, this.params || {});
				this.button = new this.buttonClass(props);
			}
		}
	},

	destroy: function(){
		// summary:
		//		Destroy this plugin

		dojo.forEach(this._connects, dojo.disconnect);
		if(this.dropDown){
			this.dropDown.destroyRecursive();
		}
	},

	connect: function(o, f, tf){
		// summary:
		//		Make a dojo.connect() that is automatically disconnected when this plugin is destroyed.
		//		Similar to `dijit._Widget.connect`.
		// tags:
		//		protected
		this._connects.push(dojo.connect(o, f, this, tf));
	},

	updateState: function(){
		// summary:
		//		Change state of the plugin to respond to events in the editor.
		// description:
		//		This is called on meaningful events in the editor, such as change of selection
		//		or caret position (but not simple typing of alphanumeric keys).   It gives the
		//		plugin a chance to update the CSS of its button.
		//
		//		For example, the "bold" plugin will highlight/unhighlight the bold button depending on whether the
		//		characters next to the caret are bold or not.
		//
		//		Only makes sense when `useDefaultCommand` is true, as it calls Editor.queryCommandEnabled(`command`).
		var e = this.editor,
			c = this.command,
			checked, enabled;
		if(!e || !e.isLoaded || !c.length){ return; }
		if(this.button){
			try{
				enabled = e.queryCommandEnabled(c);
				if(this.enabled !== enabled){
					this.enabled = enabled;
					this.button.set('disabled', !enabled);
				}
				if(typeof this.button.checked == 'boolean'){
					checked = e.queryCommandState(c);
					if(this.checked !== checked){
						this.checked = checked;
						this.button.set('checked', e.queryCommandState(c));
					}
				}
			}catch(e){
				console.log(e); // FIXME: we shouldn't have debug statements in our code.  Log as an error?
			}
		}
	},

	setEditor: function(/*dijit.Editor*/ editor){
		// summary:
		//		Tell the plugin which Editor it is associated with.

		// TODO: refactor code to just pass editor to constructor.

		// FIXME: detach from previous editor!!
		this.editor = editor;

		// FIXME: prevent creating this if we don't need to (i.e., editor can't handle our command)
		this._initButton();

		// Processing for buttons that execute by calling editor.execCommand()
		if(this.button && this.useDefaultCommand){
			if(this.editor.queryCommandAvailable(this.command)){
				this.connect(this.button, "onClick",
					dojo.hitch(this.editor, "execCommand", this.command, this.commandArg)
				);
			}else{
				// hide button because editor doesn't support command (due to browser limitations)
				this.button.domNode.style.display = "none";			
			}
		}

		this.connect(this.editor, "onNormalizedDisplayChanged", "updateState");
	},

	setToolbar: function(/*dijit.Toolbar*/ toolbar){
		// summary:
		//		Tell the plugin to add it's controller widget (often a button)
		//		to the toolbar.  Does nothing if there is no controller widget.

		// TODO: refactor code to just pass toolbar to constructor.

		if(this.button){
			toolbar.addChild(this.button);
		}
		// console.debug("adding", this.button, "to:", toolbar);
	}
});

}

if(!dojo._hasResource["dijit._editor.plugins.EnterKeyHandling"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._editor.plugins.EnterKeyHandling"] = true;
dojo.provide("dijit._editor.plugins.EnterKeyHandling");



dojo.declare("dijit._editor.plugins.EnterKeyHandling", dijit._editor._Plugin, {
	// summary:
	//		This plugin tries to make all browsers behave consistently w.r.t
	//		displaying paragraphs, specifically dealing with when the user presses
	//		the ENTER key.
	//
	//		It deals mainly with how the text appears on the screen (specifically
	//		address the double-spaced line problem on IE), but also has some code
	//		to normalize what attr('value') returns.
	//
	// description:
	//		This plugin has three modes:
	//
	//			* blockModeForEnter=BR
	//			* blockModeForEnter=DIV
	//			* blockModeForEnter=P
	//
	//		In blockModeForEnter=P, the ENTER key semantically means "start a new
	//		paragraph", whereas shift-ENTER means  "new line in the current paragraph".
	//		For example:
	//
	//		|	first paragraph <shift-ENTER>
	//		|	second line of first paragraph <ENTER>
	//		|
	//		|	second paragraph
	//
	//		In the other two modes, the ENTER key means to go to a new line in the
	//		current paragraph, and users [visually] create a new paragraph by pressing ENTER twice.
	//		For example, if the user enters text into an editor like this:
	//
	//		|		one <ENTER>
	//		|		two <ENTER>
	//		|		three <ENTER>
	//		|		<ENTER>
	//		|		four <ENTER>
	//		|		five <ENTER>
	//		|		six <ENTER>
	//
	//		It will appear on the screen as two paragraphs of three lines each.
	//
	//		blockNodeForEnter=BR
	//		--------------------
	//		On IE, typing the above keystrokes in the editor will internally produce DOM of:
	//
	//		|		<p>one</p>
	//		|		<p>two</p>
	//		|		<p>three</p>
	//		|		<p></p>
	//		|		<p>four</p>
	//		|		<p>five</p>
	//		|		<p>six</p>
	//
	//		However, blockNodeForEnter=BR makes the Editor on IE display like other browsers, by
	//		changing the CSS for the <p> node to not have top/bottom margins,
	//		thus eliminating the double-spaced appearance.
	//
	//		Also, attr('value') when used w/blockNodeForEnter=br on IE will return:
	//
	//		|	<p> one <br> two <br> three </p>
	//		|	<p> four <br> five <br> six </p>
	//
	//		This output normalization implemented by a filter when the
	//		editor writes out it's data, to convert consecutive <p>
	//		nodes into a single <p> node with internal <br> separators.
	//
	//		There's also a pre-filter to mirror the post-filter.
	//		It converts a single <p> with <br> line breaks
	//		into separate <p> nodes, and creates empty <p> nodes for spacing
	//		between paragraphs.
	//
	//		On FF typing the above keystrokes will internally generate:
	//
	//		|		one <br> two <br> three <br> <br> four <br> five <br> six <br>
	//
	//		And on Safari it will generate:
	//
	//		|		"one"
	//		|		<div>two</div>
	//		|		<div>three</div>
	//		|		<div><br></div>
	//		|		<div>four</div>
	//		|		<div>five</div>
	//		|		<div>six</div>
	//
	//		Thus, Safari and FF already look correct although semantically their content is a bit strange.
	//		On Safari or Firefox blockNodeForEnter=BR uses the builtin editor command "insertBrOnReturn",
	//		but that doesn't seem to do anything.
	//		Thus, attr('value') on safari/FF returns the browser-specific HTML listed above,
	//		rather than the semantically meaningful value that IE returns: <p>one<br>two</p> <p>three<br>four</p>.
	//
	//		(Note: originally based on http://bugs.dojotoolkit.org/ticket/2859)
	//
	//		blockNodeForEnter=P
	//		-------------------
	//		Plugin will monitor keystrokes and update the editor's content on the fly,
	//		so that the ENTER key will create a new <p> on FF and Safari (it already
	//		works that way by default on IE).
	//
	//		blockNodeForEnter=DIV
	//		---------------------
	//		Follows the same code path as blockNodeForEnter=P but inserting a <div>
	//		on ENTER key.  Although it produces strange internal DOM, like this:
	//
	//		|	<div>paragraph one</div>
	//		|	<div>paragraph one, line 2</div>
	//		|	<div>&nbsp;</div>
	//		|	<div>paragraph two</div>
	//
	//		it does provide a consistent look on all browsers, and the on-the-fly DOM updating
	//		can be useful for collaborative editing.

	// blockNodeForEnter: String
	//		This property decides the behavior of Enter key. It can be either P,
	//		DIV, BR, or empty (which means disable this feature). Anything else
	//		will trigger errors.
	//
	//		See class description for more details.
	blockNodeForEnter: 'BR',

	constructor: function(args){
		if(args){
			dojo.mixin(this,args);
		}
	},

	setEditor: function(editor){
		// Overrides _Plugin.setEditor().
		this.editor = editor;
		if(this.blockNodeForEnter == 'BR'){
			if(dojo.isIE){
				editor.contentDomPreFilters.push(dojo.hitch(this, "regularPsToSingleLinePs"));
				editor.contentDomPostFilters.push(dojo.hitch(this, "singleLinePsToRegularPs"));
				editor.onLoadDeferred.addCallback(dojo.hitch(this, "_fixNewLineBehaviorForIE"));
			}else{
				editor.onLoadDeferred.addCallback(dojo.hitch(this,function(d){
					try{
						this.editor.document.execCommand("insertBrOnReturn", false, true);
					}catch(e){}
					return d;
				}));
			}
		}else if(this.blockNodeForEnter){
			// add enter key handler
			// FIXME: need to port to the new event code!!
			dojo['require']('dijit._editor.range');
			var h = dojo.hitch(this,this.handleEnterKey);
			editor.addKeyHandler(13, 0, 0, h); //enter
			editor.addKeyHandler(13, 0, 1, h); //shift+enter
			this.connect(this.editor,'onKeyPressed','onKeyPressed');
		}
	},
	onKeyPressed: function(e){
		// summary:
		//		Handler for keypress events.
		// tags:
		//		private
		if(this._checkListLater){
			if(dojo.withGlobal(this.editor.window, 'isCollapsed', dijit)){
				var liparent=dojo.withGlobal(this.editor.window, 'getAncestorElement', dijit._editor.selection, ['LI']);
				if(!liparent){
					// circulate the undo detection code by calling RichText::execCommand directly
					dijit._editor.RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter);
					// set the innerHTML of the new block node
					var block = dojo.withGlobal(this.editor.window, 'getAncestorElement', dijit._editor.selection, [this.blockNodeForEnter]);
					if(block){
						block.innerHTML=this.bogusHtmlContent;
						if(dojo.isIE){
							// move to the start by moving backwards one char
							var r = this.editor.document.selection.createRange();
							r.move('character',-1);
							r.select();
						}
					}else{
						console.error('onKeyPressed: Cannot find the new block node'); // FIXME
					}
				}else{
					if(dojo.isMoz){
						if(liparent.parentNode.parentNode.nodeName == 'LI'){
							liparent=liparent.parentNode.parentNode;
						}
					}
					var fc=liparent.firstChild;
					if(fc && fc.nodeType == 1 && (fc.nodeName == 'UL' || fc.nodeName == 'OL')){
						liparent.insertBefore(fc.ownerDocument.createTextNode('\xA0'),fc);
						var newrange = dijit.range.create(this.editor.window);
						newrange.setStart(liparent.firstChild,0);
						var selection = dijit.range.getSelection(this.editor.window, true);
						selection.removeAllRanges();
						selection.addRange(newrange);
					}
				}
			}
			this._checkListLater = false;
		}
		if(this._pressedEnterInBlock){
			// the new created is the original current P, so we have previousSibling below
			if(this._pressedEnterInBlock.previousSibling){
				this.removeTrailingBr(this._pressedEnterInBlock.previousSibling);
			}
			delete this._pressedEnterInBlock;
		}
	},

	// bogusHtmlContent: [private] String
	//		HTML to stick into a new empty block
	bogusHtmlContent: '&nbsp;',

	// blockNodes: [private] Regex
	//		Regex for testing if a given tag is a block level (display:block) tag
	blockNodes: /^(?:P|H1|H2|H3|H4|H5|H6|LI)$/,

	handleEnterKey: function(e){
		// summary:
		//		Handler for enter key events when blockModeForEnter is DIV or P.
		// description:
		//		Manually handle enter key event to make the behavior consistent across
		//		all supported browsers. See class description for details.
		// tags:
		//		private

		var selection, range, newrange, doc=this.editor.document,br;
		if(e.shiftKey){		// shift+enter always generates <br>
			var parent = dojo.withGlobal(this.editor.window, "getParentElement", dijit._editor.selection);
			var header = dijit.range.getAncestor(parent,this.blockNodes);
			if(header){
				if(!e.shiftKey && header.tagName == 'LI'){
					return true; // let browser handle
				}
				selection = dijit.range.getSelection(this.editor.window);
				range = selection.getRangeAt(0);
				if(!range.collapsed){
					range.deleteContents();
					selection = dijit.range.getSelection(this.editor.window);
					range = selection.getRangeAt(0);
				}
				if(dijit.range.atBeginningOfContainer(header, range.startContainer, range.startOffset)){
					if(e.shiftKey){
						br=doc.createElement('br');
						newrange = dijit.range.create(this.editor.window);
						header.insertBefore(br,header.firstChild);
						newrange.setStartBefore(br.nextSibling);
						selection.removeAllRanges();
						selection.addRange(newrange);
					}else{
						dojo.place(br, header, "before");
					}
				}else if(dijit.range.atEndOfContainer(header, range.startContainer, range.startOffset)){
					newrange = dijit.range.create(this.editor.window);
					br=doc.createElement('br');
					if(e.shiftKey){
						header.appendChild(br);
						header.appendChild(doc.createTextNode('\xA0'));
						newrange.setStart(header.lastChild,0);
					}else{
						dojo.place(br, header, "after");
						newrange.setStartAfter(header);
					}

					selection.removeAllRanges();
					selection.addRange(newrange);
				}else{
					return true; // let browser handle
				}
			}else{
				// don't change this: do not call this.execCommand, as that may have other logic in subclass
				dijit._editor.RichText.prototype.execCommand.call(this.editor, 'inserthtml', '<br>');
			}
			return false;
		}
		var _letBrowserHandle = true;

		// first remove selection
		selection = dijit.range.getSelection(this.editor.window);
		range = selection.getRangeAt(0);
		if(!range.collapsed){
			range.deleteContents();
			selection = dijit.range.getSelection(this.editor.window);
			range = selection.getRangeAt(0);
		}

		var block = dijit.range.getBlockAncestor(range.endContainer, null, this.editor.editNode);
		var blockNode = block.blockNode;

		// if this is under a LI or the parent of the blockNode is LI, just let browser to handle it
		if((this._checkListLater = (blockNode && (blockNode.nodeName == 'LI' || blockNode.parentNode.nodeName == 'LI')))){
			if(dojo.isMoz){
				// press enter in middle of P may leave a trailing <br/>, let's remove it later
				this._pressedEnterInBlock = blockNode;
			}
			// if this li only contains spaces, set the content to empty so the browser will outdent this item
			if(/^(\s|&nbsp;|\xA0|<span\b[^>]*\bclass=['"]Apple-style-span['"][^>]*>(\s|&nbsp;|\xA0)<\/span>)?(<br>)?$/.test(blockNode.innerHTML)){
				// empty LI node
				blockNode.innerHTML = '';
				if(dojo.isWebKit){ // WebKit tosses the range when innerHTML is reset
					newrange = dijit.range.create(this.editor.window);
					newrange.setStart(blockNode, 0);
					selection.removeAllRanges();
					selection.addRange(newrange);
				}
				this._checkListLater = false; // nothing to check since the browser handles outdent
			}
			return true;
		}

		// text node directly under body, let's wrap them in a node
		if(!block.blockNode || block.blockNode===this.editor.editNode){
			try{
				dijit._editor.RichText.prototype.execCommand.call(this.editor, 'formatblock',this.blockNodeForEnter);
			}catch(e2){ /*squelch FF3 exception bug when editor content is a single BR*/ }
			// get the newly created block node
			// FIXME
			block = {blockNode:dojo.withGlobal(this.editor.window, "getAncestorElement", dijit._editor.selection, [this.blockNodeForEnter]),
					blockContainer: this.editor.editNode};
			if(block.blockNode){
				if(block.blockNode != this.editor.editNode &&
					(!(block.blockNode.textContent || block.blockNode.innerHTML).replace(/^\s+|\s+$/g, "").length)){
					this.removeTrailingBr(block.blockNode);
					return false;
				}
			}else{	// we shouldn't be here if formatblock worked
				block.blockNode = this.editor.editNode;
			}
			selection = dijit.range.getSelection(this.editor.window);
			range = selection.getRangeAt(0);
		}

		var newblock = doc.createElement(this.blockNodeForEnter);
		newblock.innerHTML=this.bogusHtmlContent;
		this.removeTrailingBr(block.blockNode);
		if(dijit.range.atEndOfContainer(block.blockNode, range.endContainer, range.endOffset)){
			if(block.blockNode === block.blockContainer){
				block.blockNode.appendChild(newblock);
			}else{
				dojo.place(newblock, block.blockNode, "after");
			}
			_letBrowserHandle = false;
			// lets move caret to the newly created block
			newrange = dijit.range.create(this.editor.window);
			newrange.setStart(newblock, 0);
			selection.removeAllRanges();
			selection.addRange(newrange);
			if(this.editor.height){
				dojo.window.scrollIntoView(newblock);
			}
		}else if(dijit.range.atBeginningOfContainer(block.blockNode,
				range.startContainer, range.startOffset)){
			dojo.place(newblock, block.blockNode, block.blockNode === block.blockContainer ? "first" : "before");
			if(newblock.nextSibling && this.editor.height){
				// position input caret - mostly WebKit needs this
				newrange = dijit.range.create(this.editor.window);
				newrange.setStart(newblock.nextSibling, 0);
				selection.removeAllRanges();
				selection.addRange(newrange);
				// browser does not scroll the caret position into view, do it manually
				dojo.window.scrollIntoView(newblock.nextSibling);
			}
			_letBrowserHandle = false;
		}else{ //press enter in the middle of P/DIV/Whatever/
			if(block.blockNode === block.blockContainer){
				block.blockNode.appendChild(newblock);
			}else{
				dojo.place(newblock, block.blockNode, "after");
			}
			_letBrowserHandle = false;

			// Clone any block level styles.
			if(block.blockNode.style){
				if(newblock.style){
					if(block.blockNode.style.cssText){
						newblock.style.cssText = block.blockNode.style.cssText;
					}
				}
			}
			
			// Okay, we probably have to split.
			var rs = range.startContainer;
			if(rs && rs.nodeType == 3){
				// Text node, we have to split it.
				var nodeToMove, tNode;
				var txt = rs.nodeValue;
				var startNode = doc.createTextNode(txt.substring(0, range.startOffset));
				var endNode = doc.createTextNode(txt.substring(range.startOffset, txt.length));

				// Place the split, then remove original nodes.
				dojo.place(startNode, rs, "before");
				dojo.place(endNode, rs, "after");
				dojo.destroy(rs);

				// Okay, we split the text.  Now we need to see if we're
				// parented to the block element we're splitting and if
				// not, we have to split all the way up.  Ugh.
				var parentC = startNode.parentNode;
				while(parentC !== block.blockNode){
					var tg = parentC.tagName;
					var newTg = doc.createElement(tg);
					// Clone over any 'style' data. 
					if(parentC.style){
						if(newTg.style){
							if(parentC.style.cssText){
								newTg.style.cssText = parentC.style.cssText;
							}
						}
					}

					nodeToMove = endNode;
					while(nodeToMove){
						tNode = nodeToMove.nextSibling;
						newTg.appendChild(nodeToMove);
						nodeToMove = tNode;
					}
					dojo.place(newTg, parentC, "after");
					startNode = parentC;
					endNode = newTg;
					parentC = parentC.parentNode;
				}

				// Lastly, move the split out tags to the new block.
				// as they should now be split properly.
				nodeToMove = endNode;
				if(nodeToMove.nodeType == 1 || (nodeToMove.nodeType == 3 && nodeToMove.nodeValue)){
					// Non-blank text and non-text nodes need to clear out that blank space
					// before moving the contents.
					newblock.innerHTML = "";
				}
				while(nodeToMove){
					tNode = nodeToMove.nextSibling;
					newblock.appendChild(nodeToMove);
					nodeToMove = tNode;
				}
			}
			
			//lets move caret to the newly created block
			newrange = dijit.range.create(this.editor.window);
			newrange.setStart(newblock, 0);
			selection.removeAllRanges();
			selection.addRange(newrange);
			if(this.editor.height){
				dijit.scrollIntoView(newblock);
			}
			if(dojo.isMoz){
				// press enter in middle of P may leave a trailing <br/>, let's remove it later
				this._pressedEnterInBlock = block.blockNode;
			}
		}
		return _letBrowserHandle;
	},

	removeTrailingBr: function(container){
		// summary:
		//		If last child of container is a <br>, then remove it.
		// tags:
		//		private
		var para = /P|DIV|LI/i.test(container.tagName) ?
			container : dijit._editor.selection.getParentOfType(container,['P','DIV','LI']);

		if(!para){ return; }
		if(para.lastChild){
			if((para.childNodes.length > 1 && para.lastChild.nodeType == 3 && /^[\s\xAD]*$/.test(para.lastChild.nodeValue)) ||
				para.lastChild.tagName=='BR'){

				dojo.destroy(para.lastChild);
			}
		}
		if(!para.childNodes.length){
			para.innerHTML=this.bogusHtmlContent;
		}
	},
	_fixNewLineBehaviorForIE: function(d){
		// summary:
		//		Insert CSS so <p> nodes don't have spacing around them,
		//		thus hiding the fact that ENTER key on IE is creating new
		//		paragraphs

		// cannot use !important since there may be custom user styling;
		var doc = this.editor.document;
		if(doc.__INSERTED_EDITIOR_NEWLINE_CSS === undefined){
			var style = dojo.create("style", {type: "text/css"}, doc.getElementsByTagName("head")[0]);
			style.styleSheet.cssText = "p{margin:0;}"; // cannot use !important since there may be custom user styling;
			this.editor.document.__INSERTED_EDITIOR_NEWLINE_CSS = true;
		}
		return d;
	},
	regularPsToSingleLinePs: function(element, noWhiteSpaceInEmptyP){
		// summary:
		//		Converts a <p> node containing <br>'s into multiple <p> nodes.
		// description:
		//		See singleLinePsToRegularPs().   This method does the
		//		opposite thing, and is used as a pre-filter when loading the
		//		editor, to mirror the effects of the post-filter at end of edit.
		// tags:
		//		private
		function wrapLinesInPs(el){
		  // move "lines" of top-level text nodes into ps
			function wrapNodes(nodes){
				// nodes are assumed to all be siblings
				var newP = nodes[0].ownerDocument.createElement('p'); // FIXME: not very idiomatic
				nodes[0].parentNode.insertBefore(newP, nodes[0]);
				dojo.forEach(nodes, function(node){
					newP.appendChild(node);
				});
			}

			var currentNodeIndex = 0;
			var nodesInLine = [];
			var currentNode;
			while(currentNodeIndex < el.childNodes.length){
				currentNode = el.childNodes[currentNodeIndex];
				if( currentNode.nodeType==3 ||	// text node
					(currentNode.nodeType==1 && currentNode.nodeName!='BR' && dojo.style(currentNode, "display")!="block")
				){
					nodesInLine.push(currentNode);
				}else{
					// hit line delimiter; process nodesInLine if there are any
					var nextCurrentNode = currentNode.nextSibling;
					if(nodesInLine.length){
						wrapNodes(nodesInLine);
						currentNodeIndex = (currentNodeIndex+1)-nodesInLine.length;
						if(currentNode.nodeName=="BR"){
							dojo.destroy(currentNode);
						}
					}
					nodesInLine = [];
				}
				currentNodeIndex++;
			}
			if(nodesInLine.length){ wrapNodes(nodesInLine); }
		}

		function splitP(el){
			// split a paragraph into seperate paragraphs at BRs
			var currentNode = null;
			var trailingNodes = [];
			var lastNodeIndex = el.childNodes.length-1;
			for(var i=lastNodeIndex; i>=0; i--){
				currentNode = el.childNodes[i];
				if(currentNode.nodeName=="BR"){
					var newP = currentNode.ownerDocument.createElement('p');
					dojo.place(newP, el, "after");
					if(trailingNodes.length==0 && i != lastNodeIndex){
						newP.innerHTML = "&nbsp;"
					}
					dojo.forEach(trailingNodes, function(node){
						newP.appendChild(node);
					});
					dojo.destroy(currentNode);
					trailingNodes = [];
				}else{
					trailingNodes.unshift(currentNode);
				}
			}
		}

		var pList = [];
		var ps = element.getElementsByTagName('p');
		dojo.forEach(ps, function(p){ pList.push(p); });
		dojo.forEach(pList, function(p){
			var prevSib = p.previousSibling;
			if(	(prevSib) && (prevSib.nodeType == 1) && 
				(prevSib.nodeName == 'P' || dojo.style(prevSib, 'display') != 'block')
			){
				var newP = p.parentNode.insertBefore(this.document.createElement('p'), p);
				// this is essential to prevent IE from losing the P.
				// if it's going to be innerHTML'd later we need
				// to add the &nbsp; to _really_ force the issue
				newP.innerHTML = noWhiteSpaceInEmptyP ? "" : "&nbsp;";
			}
			splitP(p);
		},this.editor);
		wrapLinesInPs(element);
		return element;
	},

	singleLinePsToRegularPs: function(element){
		// summary:
		//		Called as post-filter.
		//		Apparently collapses adjacent <p> nodes into a single <p>
		//		nodes with <br> separating each line.
		//
		// example:
		//		Given this input:
		//	|	<p>line 1</p>
		//	|	<p>line 2</p>
		//	|	<ol>
		//	|		<li>item 1
		//	|		<li>item 2
		//	|	</ol>
		//	|	<p>line 3</p>
		//	|	<p>line 4</p>
		//
		//		Will convert to:
		//	|	<p>line 1<br>line 2</p>
		//	|	<ol>
		//	|		<li>item 1
		//	|		<li>item 2
		//	|	</ol>
		//	|	<p>line 3<br>line 4</p>
		//
		//		Not sure why this situation would even come up after the pre-filter and
		//		the enter-key-handling code.
		//
		// tags:
		//		private

		function getParagraphParents(node){
			// summary:
			//		Used to get list of all nodes that contain paragraphs.
			//		Seems like that would just be the very top node itself, but apparently not.
			var ps = node.getElementsByTagName('p');
			var parents = [];
			for(var i=0; i<ps.length; i++){
				var p = ps[i];
				var knownParent = false;
				for(var k=0; k < parents.length; k++){
					if(parents[k] === p.parentNode){
						knownParent = true;
						break;
					}
				}
				if(!knownParent){
					parents.push(p.parentNode);
				}
			}
			return parents;
		}

		function isParagraphDelimiter(node){
			return (!node.childNodes.length || node.innerHTML=="&nbsp;");
		}

		var paragraphContainers = getParagraphParents(element);
		for(var i=0; i<paragraphContainers.length; i++){
			var container = paragraphContainers[i];
			var firstPInBlock = null;
			var node = container.firstChild;
			var deleteNode = null;
			while(node){
				if(node.nodeType != 1 || node.tagName != 'P' ||
						(node.getAttributeNode('style') || {/*no style*/}).specified){
					firstPInBlock = null;
				}else if(isParagraphDelimiter(node)){
					deleteNode = node;
					firstPInBlock = null;
				}else{
					if(firstPInBlock == null){
						firstPInBlock = node;
					}else{
						if( (!firstPInBlock.lastChild || firstPInBlock.lastChild.nodeName != 'BR') &&
							(node.firstChild) &&
							(node.firstChild.nodeName != 'BR')
						){
							firstPInBlock.appendChild(this.editor.document.createElement('br'));
						}
						while(node.firstChild){
							firstPInBlock.appendChild(node.firstChild);
						}
						deleteNode = node;
					}
				}
				node = node.nextSibling;
				if(deleteNode){
					dojo.destroy(deleteNode);
					deleteNode = null;
				}
			}
		}
		return element;
	}
});

}

if(!dojo._hasResource["dijit.Editor"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.Editor"] = true;
dojo.provide("dijit.Editor");













dojo.declare(
	"dijit.Editor",
	dijit._editor.RichText,
	{
		// summary:
		//		A rich text Editing widget
		//
		// description:
		//		This widget provides basic WYSIWYG editing features, based on the browser's
		//		underlying rich text editing capability, accompanied by a toolbar (`dijit.Toolbar`).
		//		A plugin model is available to extend the editor's capabilities as well as the
		//		the options available in the toolbar.  Content generation may vary across
		//		browsers, and clipboard operations may have different results, to name
		//		a few limitations.  Note: this widget should not be used with the HTML
		//		&lt;TEXTAREA&gt; tag -- see dijit._editor.RichText for details.

		// plugins: Object[]
		//		A list of plugin names (as strings) or instances (as objects)
		//		for this widget.
		//
		//		When declared in markup, it might look like:
		//	|	plugins="['bold',{name:'dijit._editor.plugins.FontChoice', command:'fontName', generic:true}]"
		plugins: null,

		// extraPlugins: Object[]
		//		A list of extra plugin names which will be appended to plugins array
		extraPlugins: null,

		constructor: function(){
			// summary:
			//		Runs on widget initialization to setup arrays etc.
			// tags:
			//		private

			if(!dojo.isArray(this.plugins)){
				this.plugins=["undo","redo","|","cut","copy","paste","|","bold","italic","underline","strikethrough","|",
				"insertOrderedList","insertUnorderedList","indent","outdent","|","justifyLeft","justifyRight","justifyCenter","justifyFull",
				"dijit._editor.plugins.EnterKeyHandling" /*, "createLink"*/];
			}

			this._plugins=[];
			this._editInterval = this.editActionInterval * 1000;

			//IE will always lose focus when other element gets focus, while for FF and safari,
			//when no iframe is used, focus will be lost whenever another element gets focus.
			//For IE, we can connect to onBeforeDeactivate, which will be called right before
			//the focus is lost, so we can obtain the selected range. For other browsers,
			//no equivelent of onBeforeDeactivate, so we need to do two things to make sure
			//selection is properly saved before focus is lost: 1) when user clicks another
			//element in the page, in which case we listen to mousedown on the entire page and
			//see whether user clicks out of a focus editor, if so, save selection (focus will
			//only lost after onmousedown event is fired, so we can obtain correct caret pos.)
			//2) when user tabs away from the editor, which is handled in onKeyDown below.
			if(dojo.isIE){
				this.events.push("onBeforeDeactivate");
				this.events.push("onBeforeActivate");
			}
		},

		postCreate: function(){
			//for custom undo/redo, if enabled.
			this._steps=this._steps.slice(0);
			this._undoedSteps=this._undoedSteps.slice(0);

			if(dojo.isArray(this.extraPlugins)){
				this.plugins=this.plugins.concat(this.extraPlugins);
			}

			// Set up a deferred so that the value isn't applied to the editor 
			// until all the plugins load, needed to avoid timing condition
			// reported in #10537.
			this.setValueDeferred = new dojo.Deferred();

			this.inherited(arguments);

			this.commands = dojo.i18n.getLocalization("dijit._editor", "commands", this.lang);

			if(!this.toolbar){
				// if we haven't been assigned a toolbar, create one
				this.toolbar = new dijit.Toolbar({
					dir: this.dir,
					lang: this.lang
				});
				this.header.appendChild(this.toolbar.domNode);
			}

			dojo.forEach(this.plugins, this.addPlugin, this);

			// Okay, denote the value can now be set.
			this.setValueDeferred.callback(true);

			dojo.addClass(this.iframe.parentNode, "dijitEditorIFrameContainer");
			dojo.addClass(this.iframe, "dijitEditorIFrame");
			dojo.attr(this.iframe, "allowTransparency", true);

			if(dojo.isWebKit){
				// Disable selecting the entire editor by inadvertant double-clicks.
				// on buttons, title bar, etc.  Otherwise clicking too fast on
				// a button such as undo/redo selects the entire editor.
				dojo.style(this.domNode, "KhtmlUserSelect", "none");
			}
			this.toolbar.startup();
			this.onNormalizedDisplayChanged(); //update toolbar button status
		},
		destroy: function(){
			dojo.forEach(this._plugins, function(p){
				if(p && p.destroy){
					p.destroy();
				}
			});
			this._plugins=[];
			this.toolbar.destroyRecursive();
			delete this.toolbar;
			this.inherited(arguments);
		},
		addPlugin: function(/*String||Object*/plugin, /*Integer?*/index){
			// summary:
			//		takes a plugin name as a string or a plugin instance and
			//		adds it to the toolbar and associates it with this editor
			//		instance. The resulting plugin is added to the Editor's
			//		plugins array. If index is passed, it's placed in the plugins
			//		array at that index. No big magic, but a nice helper for
			//		passing in plugin names via markup.
			//
			// plugin: String, args object or plugin instance
			//
			// args:
			//		This object will be passed to the plugin constructor
			//
			// index: Integer
			//		Used when creating an instance from
			//		something already in this.plugins. Ensures that the new
			//		instance is assigned to this.plugins at that index.
			var args=dojo.isString(plugin)?{name:plugin}:plugin;
			if(!args.setEditor){
				var o={"args":args,"plugin":null,"editor":this};
				dojo.publish(dijit._scopeName + ".Editor.getPlugin",[o]);
				if(!o.plugin){
					var pc = dojo.getObject(args.name);
					if(pc){
						o.plugin=new pc(args);
					}
				}
				if(!o.plugin){
					console.warn('Cannot find plugin',plugin);
					return;
				}
				plugin=o.plugin;
			}
			if(arguments.length > 1){
				this._plugins[index] = plugin;
			}else{
				this._plugins.push(plugin);
			}
			plugin.setEditor(this);
			if(dojo.isFunction(plugin.setToolbar)){
				plugin.setToolbar(this.toolbar);
			}
		},
		//the following 3 functions are required to make the editor play nice under a layout widget, see #4070
		startup: function(){
			// summary:
			//		Exists to make Editor work as a child of a layout widget.
			//		Developers don't need to call this method.
			// tags:
			//		protected
			//console.log('startup',arguments);
		},
		resize: function(size){
			// summary:
			//		Resize the editor to the specified size, see `dijit.layout._LayoutWidget.resize`
			if(size){
				// we've been given a height/width for the entire editor (toolbar + contents), calls layout()
				// to split the allocated size between the toolbar and the contents
				dijit.layout._LayoutWidget.prototype.resize.apply(this, arguments);
			}
			/*
			else{
				// do nothing, the editor is already laid out correctly.   The user has probably specified
				// the height parameter, which was used to set a size on the iframe
			}
			*/
		},
		layout: function(){
			// summary:
			//		Called from `dijit.layout._LayoutWidget.resize`.  This shouldn't be called directly
			// tags:
			//		protected

			// Converts the iframe (or rather the <div> surrounding it) to take all the available space
			// except what's needed for the header (toolbars) and footer (breadcrumbs, etc).
			// A class was added to the iframe container and some themes style it, so we have to
			// calc off the added margins and padding too. See tracker: #10662
			var areaHeight = (this._contentBox.h - 
				(this.getHeaderHeight() + this.getFooterHeight() + 
				 dojo._getPadBorderExtents(this.iframe.parentNode).h +
				 dojo._getMarginExtents(this.iframe.parentNode).h));
			this.editingArea.style.height = areaHeight + "px";
			if(this.iframe){
				this.iframe.style.height="100%";
			}
			this._layoutMode = true;
		},
		_onIEMouseDown: function(/*Event*/ e){
			// summary:
			//		IE only to prevent 2 clicks to focus
			// tags:
			//		private
			var outsideClientArea;
			// IE 8's componentFromPoint is broken, which is a shame since it
			// was smaller code, but oh well.  We have to do this brute force
			// to detect if the click was scroller or not.
			var b = this.document.body;
			var clientWidth = b.clientWidth;
			var clientHeight = b.clientHeight;
			var clientLeft = b.clientLeft;
			var offsetWidth = b.offsetWidth;
			var offsetHeight = b.offsetHeight;
			var offsetLeft = b.offsetLeft;

			//Check for vertical scroller click.
			bodyDir = b.dir?b.dir.toLowerCase():""
			if(bodyDir != "rtl"){
				if(clientWidth < offsetWidth && e.x > clientWidth && e.x < offsetWidth){ 
					// Check the click was between width and offset width, if so, scroller
					outsideClientArea = true;
				}
			}else{
				// RTL mode, we have to go by the left offsets.
				if(e.x < clientLeft && e.x > offsetLeft){
					// Check the click was between width and offset width, if so, scroller
					outsideClientArea = true;
				}
			}
			if(!outsideClientArea){
				// Okay, might be horiz scroller, check that.
				if(clientHeight < offsetHeight && e.y > clientHeight && e.y < offsetHeight){
					// Horizontal scroller.
					outsideClientArea = true;
				}
			}
			if(!outsideClientArea){
				delete this._cursorToStart; // Remove the force to cursor to start position. 
				delete this._savedSelection; // new mouse position overrides old selection
				if(e.target.tagName == "BODY"){
					setTimeout(dojo.hitch(this, "placeCursorAtEnd"), 0);
				}
				this.inherited(arguments);
			}
		},
		onBeforeActivate: function(e){
			this._restoreSelection();
		},
		onBeforeDeactivate: function(e){
			// summary:
			//		Called on IE right before focus is lost.   Saves the selected range.
			// tags:
			//		private
			if(this.customUndo){
				this.endEditing(true);
			}
			//in IE, the selection will be lost when other elements get focus,
			//let's save focus before the editor is deactivated
			if(e.target.tagName != "BODY"){
				this._saveSelection();
			}
			//console.log('onBeforeDeactivate',this);
		},

		/* beginning of custom undo/redo support */

		// customUndo: Boolean
		//		Whether we shall use custom undo/redo support instead of the native
		//		browser support. By default, we only enable customUndo for IE, as it
		//		has broken native undo/redo support. Note: the implementation does
		//		support other browsers which have W3C DOM2 Range API implemented.
		//		It was also enabled on WebKit, to fix undo/redo enablement. (#9613)
		customUndo: dojo.isIE || dojo.isWebKit,

		// editActionInterval: Integer
		//		When using customUndo, not every keystroke will be saved as a step.
		//		Instead typing (including delete) will be grouped together: after
		//		a user stops typing for editActionInterval seconds, a step will be
		//		saved; if a user resume typing within editActionInterval seconds,
		//		the timeout will be restarted. By default, editActionInterval is 3
		//		seconds.
		editActionInterval: 3,

		beginEditing: function(cmd){
			// summary:
			//		Called to note that the user has started typing alphanumeric characters, if it's not already noted.
			//		Deals with saving undo; see editActionInterval parameter.
			// tags:
			//		private
			if(!this._inEditing){
				this._inEditing=true;
				this._beginEditing(cmd);
			}
			if(this.editActionInterval>0){
				if(this._editTimer){
					clearTimeout(this._editTimer);
				}
				this._editTimer = setTimeout(dojo.hitch(this, this.endEditing), this._editInterval);
			}
		},
		_steps:[],
		_undoedSteps:[],
		execCommand: function(cmd){
			// summary:
			//		Main handler for executing any commands to the editor, like paste, bold, etc.
			//      Called by plugins, but not meant to be called by end users.
			// tags:
			//		protected
			if(this.customUndo && (cmd == 'undo' || cmd == 'redo')){
				return this[cmd]();
			}else{
				if(this.customUndo){
					this.endEditing();
					this._beginEditing();
				}
				var r;
				try{
					r = this.inherited('execCommand', arguments);
					if(dojo.isWebKit && cmd == 'paste' && !r){ //see #4598: safari does not support invoking paste from js
						throw { code: 1011 }; // throw an object like Mozilla's error
					}
				}catch(e){
					//TODO: when else might we get an exception?  Do we need the Mozilla test below?
					if(e.code == 1011 /* Mozilla: service denied */ && /copy|cut|paste/.test(cmd)){
						// Warn user of platform limitation.  Cannot programmatically access clipboard. See ticket #4136
						var sub = dojo.string.substitute,
							accel = {cut:'X', copy:'C', paste:'V'};
						alert(sub(this.commands.systemShortcut,
							[this.commands[cmd], sub(this.commands[dojo.isMac ? 'appleKey' : 'ctrlKey'], [accel[cmd]])]));
					}
					r = false;
				}
				if(this.customUndo){
					this._endEditing();
				}
				return r;
			}
		},
		queryCommandEnabled: function(cmd){
			// summary:
			//		Returns true if specified editor command is enabled.
			//      Used by the plugins to know when to highlight/not highlight buttons.
			// tags:
			//		protected
			if(this.customUndo && (cmd == 'undo' || cmd == 'redo')){
				return cmd == 'undo' ? (this._steps.length > 1) : (this._undoedSteps.length > 0);
			}else{
				return this.inherited('queryCommandEnabled',arguments);
			}
		},
		_moveToBookmark: function(b){
			// summary:
			//		Selects the text specified in bookmark b
			// tags:
			//		private
			var bookmark = b.mark;
			var mark = b.mark;
			var col = b.isCollapsed;
			var r, sNode, eNode, sel;
			if(mark){
				if(dojo.isIE){
					if(dojo.isArray(mark)){
						//IE CONTROL, have to use the native bookmark.
						bookmark = [];
						dojo.forEach(mark,function(n){
							bookmark.push(dijit.range.getNode(n,this.editNode));
						},this);
						dojo.withGlobal(this.window,'moveToBookmark',dijit,[{mark: bookmark, isCollapsed: col}]);
					}else{
						if(mark.startContainer && mark.endContainer){
							// Use the pseudo WC3 range API.  This works better for positions
							// than the IE native bookmark code.
							sel = dijit.range.getSelection(this.window);
							if(sel && sel.removeAllRanges){
								sel.removeAllRanges();
								r = dijit.range.create(this.window);
								sNode = dijit.range.getNode(mark.startContainer,this.editNode);
								eNode = dijit.range.getNode(mark.endContainer,this.editNode);
								if(sNode && eNode){
									// Okay, we believe we found the position, so add it into the selection
									// There are cases where it may not be found, particularly in undo/redo, when
									// IE changes the underlying DOM on us (wraps text in a <p> tag or similar.
									// So, in those cases, don't bother restoring selection.
									r.setStart(sNode,mark.startOffset);
									r.setEnd(eNode,mark.endOffset);
									sel.addRange(r);
								}
							}
						}
					}
				}else{//w3c range
					sel = dijit.range.getSelection(this.window);
					if(sel && sel.removeAllRanges){
						sel.removeAllRanges();
						r = dijit.range.create(this.window);
						sNode = dijit.range.getNode(mark.startContainer,this.editNode);
						eNode = dijit.range.getNode(mark.endContainer,this.editNode);
						if(sNode && eNode){
							// Okay, we believe we found the position, so add it into the selection
							// There are cases where it may not be found, particularly in undo/redo, when
							// formatting as been done and so on, so don't restore selection then.
							r.setStart(sNode,mark.startOffset);
							r.setEnd(eNode,mark.endOffset);
							sel.addRange(r);
						}
					}
				}
			}
		},
		_changeToStep: function(from, to){
			// summary:
			//		Reverts editor to "to" setting, from the undo stack.
			// tags:
			//		private
			this.setValue(to.text);
			var b=to.bookmark;
			if(!b){ return; }
			this._moveToBookmark(b);
		},
		undo: function(){
			// summary:
			//		Handler for editor undo (ex: ctrl-z) operation
			// tags:
			//		private
			//console.log('undo');
			var ret = false;
			if(!this._undoRedoActive){
				this._undoRedoActive = true;
				this.endEditing(true);
				var s=this._steps.pop();
				if(s && this._steps.length>0){
					this.focus();
					this._changeToStep(s,this._steps[this._steps.length-1]);
					this._undoedSteps.push(s);
					this.onDisplayChanged();
					delete this._undoRedoActive;
					ret = true;
				}
				delete this._undoRedoActive;
			}	
			return ret;
		},
		redo: function(){
			// summary:
			//		Handler for editor redo (ex: ctrl-y) operation
			// tags:
			//		private
			//console.log('redo');
			var ret = false;
			if(!this._undoRedoActive){
				this._undoRedoActive = true;
				this.endEditing(true);
				var s=this._undoedSteps.pop();
				if(s && this._steps.length>0){
					this.focus();
					this._changeToStep(this._steps[this._steps.length-1],s);
					this._steps.push(s);
					this.onDisplayChanged();
					ret = true;
				}
				delete this._undoRedoActive;
			}
			return ret;
		},
		endEditing: function(ignore_caret){
			// summary:
			//		Called to note that the user has stopped typing alphanumeric characters, if it's not already noted.
			//		Deals with saving undo; see editActionInterval parameter.
			// tags:
			//		private
			if(this._editTimer){
				clearTimeout(this._editTimer);
			}
			if(this._inEditing){
				this._endEditing(ignore_caret);
				this._inEditing=false;
			}
		},

		_getBookmark: function(){
			// summary:
			//		Get the currently selected text
			// tags:
			//		protected
			var b=dojo.withGlobal(this.window,dijit.getBookmark);
			var tmp=[];
			if(b && b.mark){
				var mark = b.mark;
				if(dojo.isIE){
					// Try to use the pseudo range API on IE for better accuracy.
					var sel = dijit.range.getSelection(this.window);
					if(!dojo.isArray(mark)){
						if(sel){
							var range;
							if(sel.rangeCount){
								range = sel.getRangeAt(0);
							}
							if(range){
								b.mark = range.cloneRange();
							}else{
								b.mark = dojo.withGlobal(this.window,dijit.getBookmark);
							}
						}
					}else{
						// Control ranges (img, table, etc), handle differently.
						dojo.forEach(b.mark,function(n){
							tmp.push(dijit.range.getIndex(n,this.editNode).o);
						},this);
						b.mark = tmp;
					}
				}
				try{
					if(b.mark && b.mark.startContainer){
						tmp=dijit.range.getIndex(b.mark.startContainer,this.editNode).o;
						b.mark={startContainer:tmp,
							startOffset:b.mark.startOffset,
							endContainer:b.mark.endContainer===b.mark.startContainer?tmp:dijit.range.getIndex(b.mark.endContainer,this.editNode).o,
							endOffset:b.mark.endOffset};
					}
				}catch(e){
					b.mark = null;
				}
			}
			return b;
		},
		_beginEditing: function(cmd){
			// summary:
			//		Called when the user starts typing alphanumeric characters.
			//		Deals with saving undo; see editActionInterval parameter.
			// tags:
			//		private
			if(this._steps.length === 0){
				// You want to use the editor content without post filtering
				// to make sure selection restores right for the 'initial' state.
				// and undo is called.  So not using this.savedContent, as it was 'processed'
				// and the line-up for selections may have been altered.
				this._steps.push({'text':dijit._editor.getChildrenHtml(this.editNode),'bookmark':this._getBookmark()});
			}
		},
		_endEditing: function(ignore_caret){
			// summary:
			//		Called when the user stops typing alphanumeric characters.
			//		Deals with saving undo; see editActionInterval parameter.
			// tags:
			//		private
			// Avoid filtering to make sure selections restore.
			var v = dijit._editor.getChildrenHtml(this.editNode);

			this._undoedSteps=[];//clear undoed steps
			this._steps.push({text: v, bookmark: this._getBookmark()});
		},
		onKeyDown: function(e){
			// summary:
			//		Handler for onkeydown event.
			// tags:
			//		private

			//We need to save selection if the user TAB away from this editor
			//no need to call _saveSelection for IE, as that will be taken care of in onBeforeDeactivate
			if(!dojo.isIE && !this.iframe && e.keyCode == dojo.keys.TAB && !this.tabIndent){
				this._saveSelection();
			}
			if(!this.customUndo){
				this.inherited(arguments);
				return;
			}
			var k = e.keyCode, ks = dojo.keys;
			if(e.ctrlKey && !e.altKey){//undo and redo only if the special right Alt + z/y are not pressed #5892
				if(k == 90 || k == 122){ //z
					dojo.stopEvent(e);
					this.undo();
					return;
				}else if(k == 89 || k == 121){ //y
					dojo.stopEvent(e);
					this.redo();
					return;
				}
			}
			this.inherited(arguments);

			switch(k){
					case ks.ENTER:
					case ks.BACKSPACE:
					case ks.DELETE:
						this.beginEditing();
						break;
					case 88: //x
					case 86: //v
						if(e.ctrlKey && !e.altKey && !e.metaKey){
							this.endEditing();//end current typing step if any
							if(e.keyCode == 88){
								this.beginEditing('cut');
								//use timeout to trigger after the cut is complete
								setTimeout(dojo.hitch(this, this.endEditing), 1);
							}else{
								this.beginEditing('paste');
								//use timeout to trigger after the paste is complete
								setTimeout(dojo.hitch(this, this.endEditing), 1);
							}
							break;
						}
						//pass through
					default:
						if(!e.ctrlKey && !e.altKey && !e.metaKey && (e.keyCode<dojo.keys.F1 || e.keyCode>dojo.keys.F15)){
							this.beginEditing();
							break;
						}
						//pass through
					case ks.ALT:
						this.endEditing();
						break;
					case ks.UP_ARROW:
					case ks.DOWN_ARROW:
					case ks.LEFT_ARROW:
					case ks.RIGHT_ARROW:
					case ks.HOME:
					case ks.END:
					case ks.PAGE_UP:
					case ks.PAGE_DOWN:
						this.endEditing(true);
						break;
					//maybe ctrl+backspace/delete, so don't endEditing when ctrl is pressed
					case ks.CTRL:
					case ks.SHIFT:
					case ks.TAB:
						break;
				}
		},
		_onBlur: function(){
			// summary:
			//		Called from focus manager when focus has moved away from this editor
			// tags:
			//		protected

			//this._saveSelection();
			this.inherited('_onBlur',arguments);
			this.endEditing(true);
		},
		_saveSelection: function(){
			// summary:
			//		Save the currently selected text in _savedSelection attribute
			// tags:
			//		private
			this._savedSelection=this._getBookmark();
			//console.log('save selection',this._savedSelection,this);
		},
		_restoreSelection: function(){
			// summary:
			//		Re-select the text specified in _savedSelection attribute;
			//		see _saveSelection().
			// tags:
			//		private
			if(this._savedSelection){
				// Clear off cursor to start, we're deliberately going to a selection.
				delete this._cursorToStart;
				// only restore the selection if the current range is collapsed
				// if not collapsed, then it means the editor does not lose
				// selection and there is no need to restore it
				if(dojo.withGlobal(this.window,'isCollapsed',dijit)){
					this._moveToBookmark(this._savedSelection);
				}
				delete this._savedSelection;
			}
		},

		onClick: function(){
			// summary:
			//		Handler for when editor is clicked
			// tags:
			//		protected
			this.endEditing(true);
			this.inherited(arguments);
		},

		_setDisabledAttr: function(/*Boolean*/ value){
			if(!this.disabled && value){
				// Disable editor: disable all enabled buttons and remember that list
				this._buttonEnabledPlugins = dojo.filter(this._plugins, function(p){
					if (p && p.button && !p.button.get("disabled")) {
						p.button.set("disabled", true);
						return true;
					}
					return false;
				});
			}else if(this.disabled && !value){
				// Enable editor: we only want to enable the buttons that should be
				// enabled (for example, the outdent button shouldn't be enabled if the current
				// text can't be outdented).
				dojo.forEach(this._buttonEnabledPlugins, function(p){
					p.button.attr("disabled", false);
					p.updateState && p.updateState();	// just in case something changed, like caret position
				});
			}
			
			this.inherited(arguments);
		},
		
		_setStateClass: function(){
			this.inherited(arguments);
			
			// Let theme set the editor's text color based on editor enabled/disabled state.
			// We need to jump through hoops because the main document (where the theme CSS is)
			// is separate from the iframe's document.
			if(this.document && this.document.body){
				dojo.style(this.document.body, "color", dojo.style(this.iframe, "color"));
			}
		}
	}
);

// Register the "default plugins", ie, the built-in editor commands
dojo.subscribe(dijit._scopeName + ".Editor.getPlugin",null,function(o){
	if(o.plugin){ return; }
	var args = o.args, p;
	var _p = dijit._editor._Plugin;
	var name = args.name;
	switch(name){
		case "undo": case "redo": case "cut": case "copy": case "paste": case "insertOrderedList":
		case "insertUnorderedList": case "indent": case "outdent": case "justifyCenter":
		case "justifyFull": case "justifyLeft": case "justifyRight": case "delete":
		case "selectAll": case "removeFormat": case "unlink":
		case "insertHorizontalRule":
			p = new _p({ command: name });
			break;

		case "bold": case "italic": case "underline": case "strikethrough":
		case "subscript": case "superscript":
			p = new _p({ buttonClass: dijit.form.ToggleButton, command: name });
			break;
		case "|":
			p = new _p({ button: new dijit.ToolbarSeparator(), setEditor: function(editor) {this.editor = editor;} });
	}
//	console.log('name',name,p);
	o.plugin=p;
});

}

if(!dojo._hasResource["dojox.grid.cells.dijit"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.grid.cells.dijit"] = true;
dojo.provide("dojox.grid.cells.dijit");



// TODO: shouldn't it be the test file's job to require these modules,
// if it is using them?  Most of these modules aren't referenced by this file.













(function(){
	var dgc = dojox.grid.cells;
	dojo.declare("dojox.grid.cells._Widget", dgc._Base, {
		widgetClass: dijit.form.TextBox,
		constructor: function(inCell){
			this.widget = null;
			if(typeof this.widgetClass == "string"){
				dojo.deprecated("Passing a string to widgetClass is deprecated", "pass the widget class object instead", "2.0");
				this.widgetClass = dojo.getObject(this.widgetClass);
			}
		},
		formatEditing: function(inDatum, inRowIndex){
			this.needFormatNode(inDatum, inRowIndex);
			return "<div></div>";
		},
		getValue: function(inRowIndex){
			return this.widget.attr('value');
		},
		setValue: function(inRowIndex, inValue){
			if(this.widget&&this.widget.attr){
				//Look for lazy-loading editor and handle it via its deferred.
				if(this.widget.onLoadDeferred){
					var self = this;
					this.widget.onLoadDeferred.addCallback(function(){
						self.widget.attr("value",inValue===null?"":inValue); 
					});
				}else{
					this.widget.attr("value", inValue); 
				}
			}else{
				this.inherited(arguments);
			}
		},
		getWidgetProps: function(inDatum){
			return dojo.mixin(
				{
					dir: this.dir,
					lang: this.lang
				},
				this.widgetProps||{},
				{
					constraints: dojo.mixin({}, this.constraint) || {}, //TODO: really just for ValidationTextBoxes
					value: inDatum
				}
			);
		},
		createWidget: function(inNode, inDatum, inRowIndex){
			return new this.widgetClass(this.getWidgetProps(inDatum), inNode);
		},
		attachWidget: function(inNode, inDatum, inRowIndex){
			inNode.appendChild(this.widget.domNode);
			this.setValue(inRowIndex, inDatum);
		},
		formatNode: function(inNode, inDatum, inRowIndex){
			if(!this.widgetClass){
				return inDatum;
			}
			if(!this.widget){
				this.widget = this.createWidget.apply(this, arguments);
			}else{
				this.attachWidget.apply(this, arguments);
			}
			this.sizeWidget.apply(this, arguments);
			this.grid.rowHeightChanged(inRowIndex);
			this.focus();
			return undefined;
		},
		sizeWidget: function(inNode, inDatum, inRowIndex){
			var
				p = this.getNode(inRowIndex),
				box = dojo.contentBox(p);
			dojo.marginBox(this.widget.domNode, {w: box.w});
		},
		focus: function(inRowIndex, inNode){
			if(this.widget){
				setTimeout(dojo.hitch(this.widget, function(){
					dojox.grid.util.fire(this, "focus");
				}), 0);
			}
		},
		_finish: function(inRowIndex){
			this.inherited(arguments);
			dojox.grid.util.removeNode(this.widget.domNode);
		}
	});
	dgc._Widget.markupFactory = function(node, cell){
		dgc._Base.markupFactory(node, cell);
		var d = dojo;
		var widgetProps = d.trim(d.attr(node, "widgetProps")||"");
		var constraint = d.trim(d.attr(node, "constraint")||"");
		var widgetClass = d.trim(d.attr(node, "widgetClass")||"");
		if(widgetProps){
			cell.widgetProps = d.fromJson(widgetProps);
		}
		if(constraint){
			cell.constraint = d.fromJson(constraint);
		}
		if(widgetClass){
			cell.widgetClass = d.getObject(widgetClass);
		}
	};

	dojo.declare("dojox.grid.cells.ComboBox", dgc._Widget, {
		widgetClass: dijit.form.ComboBox,
		getWidgetProps: function(inDatum){
			var items=[];
			dojo.forEach(this.options, function(o){
				items.push({name: o, value: o});
			});
			var store = new dojo.data.ItemFileReadStore({data: {identifier:"name", items: items}});
			return dojo.mixin({}, this.widgetProps||{}, {
				value: inDatum,
				store: store
			});
		},
		getValue: function(){
			var e = this.widget;
			// make sure to apply the displayed value
			e.attr('displayedValue', e.attr('displayedValue'));
			return e.attr('value');
		}
	});
	dgc.ComboBox.markupFactory = function(node, cell){
		dgc._Widget.markupFactory(node, cell);
		var d=dojo;
		var options = d.trim(d.attr(node, "options")||"");
		if(options){
			var o = options.split(',');
			if(o[0] != options){
				cell.options = o;
			}
		}
	};

	dojo.declare("dojox.grid.cells.DateTextBox", dgc._Widget, {
		widgetClass: dijit.form.DateTextBox,
		setValue: function(inRowIndex, inValue){
			if(this.widget){
				this.widget.attr('value', new Date(inValue));
			}else{
				this.inherited(arguments);
			}
		},
		getWidgetProps: function(inDatum){
			return dojo.mixin(this.inherited(arguments), {
				value: new Date(inDatum)
			});
		}
	});
	dgc.DateTextBox.markupFactory = function(node, cell){
		dgc._Widget.markupFactory(node, cell);
	};

	dojo.declare("dojox.grid.cells.CheckBox", dgc._Widget, {
		widgetClass: dijit.form.CheckBox,
		getValue: function(){
			return this.widget.checked;
		},
		setValue: function(inRowIndex, inValue){
			if(this.widget&&this.widget.attributeMap.checked){
				this.widget.attr("checked", inValue);
			}else{
				this.inherited(arguments);
			}
		},
		sizeWidget: function(inNode, inDatum, inRowIndex){
			return;
		}
	});
	dgc.CheckBox.markupFactory = function(node, cell){
		dgc._Widget.markupFactory(node, cell);
	};

	dojo.declare("dojox.grid.cells.Editor", dgc._Widget, {
		widgetClass: dijit.Editor,
		getWidgetProps: function(inDatum){
			return dojo.mixin({}, this.widgetProps||{}, {
				height: this.widgetHeight || "100px"
			});
		},
		createWidget: function(inNode, inDatum, inRowIndex){
			// widget needs its value set after creation
			var widget = new this.widgetClass(this.getWidgetProps(inDatum), inNode);
			dojo.connect(widget, 'onLoad', dojo.hitch(this, 'populateEditor'));
			return widget;
		},
		formatNode: function(inNode, inDatum, inRowIndex){
			this.content = inDatum;
			this.inherited(arguments);
			if(dojo.isMoz){
				// FIXME: seem to need to reopen the editor and display the toolbar
				var e = this.widget;
				e.open();
				if(this.widgetToolbar){
					dojo.place(e.toolbar.domNode, e.editingArea, "before");
				}
			}
		},
		populateEditor: function(){
			this.widget.attr('value', this.content);
			this.widget.placeCursorAtEnd();
		}
	});
	dgc.Editor.markupFactory = function(node, cell){
		dgc._Widget.markupFactory(node, cell);
		var d = dojo;
		var h = dojo.trim(dojo.attr(node, "widgetHeight")||"");
		if(h){
			if((h != "auto")&&(h.substr(-2) != "em")){
				h = parseInt(h, 10)+"px";
			}
			cell.widgetHeight = h;
		}
	};
})();

}

if(!dojo._hasResource["dijit.form.SimpleTextarea"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.SimpleTextarea"] = true;
dojo.provide("dijit.form.SimpleTextarea");



dojo.declare("dijit.form.SimpleTextarea",
	dijit.form.TextBox,
	{
	// summary:
	//		A simple textarea that degrades, and responds to
	// 		minimal LayoutContainer usage, and works with dijit.form.Form.
	//		Doesn't automatically size according to input, like Textarea.
	//
	// example:
	//	|	<textarea dojoType="dijit.form.SimpleTextarea" name="foo" value="bar" rows=30 cols=40></textarea>
	//
	// example:
	//	|	new dijit.form.SimpleTextarea({ rows:20, cols:30 }, "foo");

	baseClass: "dijitTextBox dijitTextArea",

	attributeMap: dojo.delegate(dijit.form._FormValueWidget.prototype.attributeMap, {
		rows:"textbox", cols: "textbox"
	}),

	// rows: Number
	//		The number of rows of text.
	rows: "3",

	// rows: Number
	//		The number of characters per line.
	cols: "20",

	templateString: "<textarea ${!nameAttrSetting} dojoAttachPoint='focusNode,containerNode,textbox' autocomplete='off'></textarea>",

	postMixInProperties: function(){
		// Copy value from srcNodeRef, unless user specified a value explicitly (or there is no srcNodeRef)
		if(!this.value && this.srcNodeRef){
			this.value = this.srcNodeRef.value;
		}
		this.inherited(arguments);
	},

	filter: function(/*String*/ value){
		// Override TextBox.filter to deal with newlines... specifically (IIRC) this is for IE which writes newlines
		// as \r\n instead of just \n
		if(value){
			value = value.replace(/\r/g,"");
		}
		return this.inherited(arguments);
	},

	postCreate: function(){
		this.inherited(arguments);
		if(dojo.isIE && this.cols){ // attribute selectors is not supported in IE6
			dojo.addClass(this.textbox, "dijitTextAreaCols");
		}
	},

	_previousValue: "",
	_onInput: function(/*Event?*/ e){
		// Override TextBox._onInput() to enforce maxLength restriction
		if(this.maxLength){
			var maxLength = parseInt(this.maxLength);
			var value = this.textbox.value.replace(/\r/g,'');
			var overflow = value.length - maxLength;
			if(overflow > 0){
				if(e){ dojo.stopEvent(e); }
				var textarea = this.textbox;
				if(textarea.selectionStart){
					var pos = textarea.selectionStart;
					var cr = 0;
					if(dojo.isOpera){
						cr = (this.textbox.value.substring(0,pos).match(/\r/g) || []).length;
					}
					this.textbox.value = value.substring(0,pos-overflow-cr)+value.substring(pos-cr);
					textarea.setSelectionRange(pos-overflow, pos-overflow);
				}else if(dojo.doc.selection){ //IE
					textarea.focus();
					var range = dojo.doc.selection.createRange();
					// delete overflow characters
					range.moveStart("character", -overflow);
					range.text = '';
					// show cursor
					range.select();
				}
			}
			this._previousValue = this.textbox.value;
		}
		this.inherited(arguments);
	}
});

}

if(!dojo._hasResource["dijit.form.Textarea"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.form.Textarea"] = true;
dojo.provide("dijit.form.Textarea");



dojo.declare(
	"dijit.form.Textarea",
	dijit.form.SimpleTextarea,
	{
	// summary:
	//		A textarea widget that adjusts it's height according to the amount of data.
	//
	// description:
	//		A textarea that dynamically expands/contracts (changing it's height) as
	//		the user types, to display all the text without requiring a scroll bar.
	//
	//		Takes nearly all the parameters (name, value, etc.) that a vanilla textarea takes.
	//		Rows is not supported since this widget adjusts the height.
	//
	// example:
	// |	<textarea dojoType="dijit.form.TextArea">...</textarea>


	// Override SimpleTextArea.cols to default to width:100%, for backward compatibility
	cols: "",

	_previousNewlines: 0,
	_strictMode: (dojo.doc.compatMode != 'BackCompat'), // not the same as !dojo.isQuirks

	_getHeight: function(textarea){
		var newH = textarea.scrollHeight;
		if(dojo.isIE){
			newH += textarea.offsetHeight - textarea.clientHeight - ((dojo.isIE < 8 && this._strictMode) ? dojo._getPadBorderExtents(textarea).h : 0);
		}else if(dojo.isMoz){
			newH += textarea.offsetHeight - textarea.clientHeight; // creates room for horizontal scrollbar
		}else if(dojo.isWebKit && !(dojo.isSafari < 4)){ // Safari 4.0 && Chrome
			newH += dojo._getBorderExtents(textarea).h;
		}else{ // Safari 3.x and Opera 9.6
			newH += dojo._getPadBorderExtents(textarea).h;
		}
		return newH;
	},

	_estimateHeight: function(textarea){
		// summary:
		// 		Approximate the height when the textarea is invisible with the number of lines in the text.
		// 		Fails when someone calls setValue with a long wrapping line, but the layout fixes itself when the user clicks inside so . . .
		// 		In IE, the resize event is supposed to fire when the textarea becomes visible again and that will correct the size automatically.
		//
		textarea.style.maxHeight = "";
		textarea.style.height = "auto";
		// #rows = #newlines+1
		// Note: on Moz, the following #rows appears to be 1 too many.
		// Actually, Moz is reserving room for the scrollbar.
		// If you increase the font size, this behavior becomes readily apparent as the last line gets cut off without the +1.
		textarea.rows = (textarea.value.match(/\n/g) || []).length + 1;
	},

	_needsHelpShrinking: dojo.isMoz || dojo.isWebKit,

	_onInput: function(){
		// Override SimpleTextArea._onInput() to deal with height adjustment
		this.inherited(arguments);
		if(this._busyResizing){ return; }
		this._busyResizing = true;
		var textarea = this.textbox;
		if(textarea.scrollHeight && textarea.offsetHeight && textarea.clientHeight){
			var newH = this._getHeight(textarea) + "px";
			if(textarea.style.height != newH){
				textarea.style.maxHeight = textarea.style.height = newH;
			}
			if(this._needsHelpShrinking){
				if(this._setTimeoutHandle){
					clearTimeout(this._setTimeoutHandle);
				}
				this._setTimeoutHandle = setTimeout(dojo.hitch(this, "_shrink"), 0); // try to collapse multiple shrinks into 1
			}
		}else{
			// hidden content of unknown size
			this._estimateHeight(textarea);
		}
		this._busyResizing = false;
	},

	_busyResizing: false,
	_shrink: function(){
		// grow paddingBottom to see if scrollHeight shrinks (when it is unneccesarily big)
		this._setTimeoutHandle = null;
		if(this._needsHelpShrinking && !this._busyResizing){
			this._busyResizing = true;
			var textarea = this.textbox;
			var empty = false;
			if(textarea.value == ''){
				textarea.value = ' '; // prevent collapse all the way back to 0
				empty = true;
			}
			var scrollHeight = textarea.scrollHeight;
			if(!scrollHeight){
				this._estimateHeight(textarea);
			}else{
				var oldPadding = textarea.style.paddingBottom;
				var newPadding = dojo._getPadExtents(textarea);
				newPadding = newPadding.h - newPadding.t;
				textarea.style.paddingBottom = newPadding + 1 + "px"; // tweak padding to see if height can be reduced
				var newH = this._getHeight(textarea) - 1 + "px"; // see if the height changed by the 1px added
				if(textarea.style.maxHeight != newH){ // if can be reduced, so now try a big chunk
					textarea.style.paddingBottom = newPadding + scrollHeight + "px";
					textarea.scrollTop = 0;
					textarea.style.maxHeight = this._getHeight(textarea) - scrollHeight + "px"; // scrollHeight is the added padding
				}
				textarea.style.paddingBottom = oldPadding;
			}
			if(empty){
				textarea.value = '';
			}
			this._busyResizing = false;
		}
	},

	resize: function(){
		// summary:
		//		Resizes the textarea vertically (should be called after a style/value change)
		this._onInput();
	},

	_setValueAttr: function(){
		this.inherited(arguments);
		this.resize();
	},

	postCreate: function(){
		this.inherited(arguments);
		// tweak textarea style to reduce browser differences
		dojo.style(this.textbox, { overflowY: 'hidden', overflowX: 'auto', boxSizing: 'border-box', MsBoxSizing: 'border-box', WebkitBoxSizing: 'border-box', MozBoxSizing: 'border-box' });
		this.connect(this.textbox, "onscroll", this._onInput);
		this.connect(this.textbox, "onresize", this._onInput);
		this.connect(this.textbox, "onfocus", this._onInput); // useful when a previous estimate was off a bit
		this._setTimeoutHandle = setTimeout(dojo.hitch(this, "resize"), 0);
	},

	uninitialize: function(){
		if(this._setTimeoutHandle){
			clearTimeout(this._setTimeoutHandle);
		}
		this.inherited(arguments);
	}
});

}

if(!dojo._hasResource["dijit.layout._TabContainerBase"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout._TabContainerBase"] = true;
dojo.provide("dijit.layout._TabContainerBase");




dojo.declare("dijit.layout._TabContainerBase",
	[dijit.layout.StackContainer, dijit._Templated],
	{
	// summary:
	//		Abstract base class for TabContainer.   Must define _makeController() to instantiate
	//		and return the widget that displays the tab labels
	// description:
	//		A TabContainer is a container that has multiple panes, but shows only
	//		one pane at a time.  There are a set of tabs corresponding to each pane,
	//		where each tab has the name (aka title) of the pane, and optionally a close button.

	// tabPosition: String
	//		Defines where tabs go relative to tab content.
	//		"top", "bottom", "left-h", "right-h"
	tabPosition: "top",

	baseClass: "dijitTabContainer",

	// tabStrip: Boolean
	//		Defines whether the tablist gets an extra class for layouting, putting a border/shading
	//		around the set of tabs.
	tabStrip: false,

	// nested: Boolean
	//		If true, use styling for a TabContainer nested inside another TabContainer.
	//		For tundra etc., makes tabs look like links, and hides the outer
	//		border since the outer TabContainer already has a border.
	nested: false,

	templateString: dojo.cache("dijit.layout", "templates/TabContainer.html", "<div class=\"dijitTabContainer\">\n\t<div class=\"dijitTabListWrapper\" dojoAttachPoint=\"tablistNode\"></div>\n\t<div dojoAttachPoint=\"tablistSpacer\" class=\"dijitTabSpacer ${baseClass}-spacer\"></div>\n\t<div class=\"dijitTabPaneWrapper ${baseClass}-container\" dojoAttachPoint=\"containerNode\"></div>\n</div>\n"),

	postMixInProperties: function(){
		// set class name according to tab position, ex: dijitTabContainerTop
		this.baseClass += this.tabPosition.charAt(0).toUpperCase() + this.tabPosition.substr(1).replace(/-.*/, "");

		this.srcNodeRef && dojo.style(this.srcNodeRef, "visibility", "hidden");

		this.inherited(arguments);
	},

	postCreate: function(){
		this.inherited(arguments);

		// Create the tab list that will have a tab (a.k.a. tab button) for each tab panel
		this.tablist = this._makeController(this.tablistNode);

		if(!this.doLayout){ dojo.addClass(this.domNode, "dijitTabContainerNoLayout"); }

		if(this.nested){
			/* workaround IE's lack of support for "a > b" selectors by
			 * tagging each node in the template.
			 */
			dojo.addClass(this.domNode, "dijitTabContainerNested");
			dojo.addClass(this.tablist.containerNode, "dijitTabContainerTabListNested");
			dojo.addClass(this.tablistSpacer, "dijitTabContainerSpacerNested");
			dojo.addClass(this.containerNode, "dijitTabPaneWrapperNested");
		}else{
			dojo.addClass(this.domNode, "tabStrip-" + (this.tabStrip ? "enabled" : "disabled"));
		}
	},

	_setupChild: function(/*dijit._Widget*/ tab){
		// Overrides StackContainer._setupChild().
		dojo.addClass(tab.domNode, "dijitTabPane");
		this.inherited(arguments);
	},

	startup: function(){
		if(this._started){ return; }

		// wire up the tablist and its tabs
		this.tablist.startup();

		this.inherited(arguments);
	},

	layout: function(){
		// Overrides StackContainer.layout().
		// Configure the content pane to take up all the space except for where the tabs are

		if(!this._contentBox || typeof(this._contentBox.l) == "undefined"){return;}

		var sc = this.selectedChildWidget;

		if(this.doLayout){
			// position and size the titles and the container node
			var titleAlign = this.tabPosition.replace(/-h/, "");
			this.tablist.layoutAlign = titleAlign;
			var children = [this.tablist, {
				domNode: this.tablistSpacer,
				layoutAlign: titleAlign
			}, {
				domNode: this.containerNode,
				layoutAlign: "client"
			}];
			dijit.layout.layoutChildren(this.domNode, this._contentBox, children);

			// Compute size to make each of my children.
			// children[2] is the margin-box size of this.containerNode, set by layoutChildren() call above
			this._containerContentBox = dijit.layout.marginBox2contentBox(this.containerNode, children[2]);

			if(sc && sc.resize){
				sc.resize(this._containerContentBox);
			}
		}else{
			// just layout the tab controller, so it can position left/right buttons etc.
			if(this.tablist.resize){
				this.tablist.resize({w: dojo.contentBox(this.domNode).w});
			}

			// and call resize() on the selected pane just to tell it that it's been made visible
			if(sc && sc.resize){
				sc.resize();
			}
		}
	},

	destroy: function(){
		if(this.tablist){
			this.tablist.destroy();
		}
		this.inherited(arguments);
	}
});


}

if(!dojo._hasResource["dijit.layout.TabController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.TabController"] = true;
dojo.provide("dijit.layout.TabController");



// Menu is used for an accessible close button, would be nice to have a lighter-weight solution





dojo.declare("dijit.layout.TabController",
	dijit.layout.StackController,
{
	// summary:
	// 		Set of tabs (the things with titles and a close button, that you click to show a tab panel).
	//		Used internally by `dijit.layout.TabContainer`.
	// description:
	//		Lets the user select the currently shown pane in a TabContainer or StackContainer.
	//		TabController also monitors the TabContainer, and whenever a pane is
	//		added or deleted updates itself accordingly.
	// tags:
	//		private

	templateString: "<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'></div>",

	// tabPosition: String
	//		Defines where tabs go relative to the content.
	//		"top", "bottom", "left-h", "right-h"
	tabPosition: "top",

	// buttonWidget: String
	//		The name of the tab widget to create to correspond to each page
	buttonWidget: "dijit.layout._TabButton",

	_rectifyRtlTabList: function(){
		// summary:
		//		For left/right TabContainer when page is RTL mode, rectify the width of all tabs to be equal, otherwise the tab widths are different in IE

		if(0 >= this.tabPosition.indexOf('-h')){ return; }
		if(!this.pane2button){ return; }

		var maxWidth = 0;
		for(var pane in this.pane2button){
			var ow = this.pane2button[pane].innerDiv.scrollWidth;
			maxWidth = Math.max(maxWidth, ow);
		}
		//unify the length of all the tabs
		for(pane in this.pane2button){
			this.pane2button[pane].innerDiv.style.width = maxWidth + 'px';
		}
	}
});

dojo.declare("dijit.layout._TabButton",
	dijit.layout._StackButton,
	{
	// summary:
	//		A tab (the thing you click to select a pane).
	// description:
	//		Contains the title of the pane, and optionally a close-button to destroy the pane.
	//		This is an internal widget and should not be instantiated directly.
	// tags:
	//		private

	// baseClass: String
	//		The CSS class applied to the domNode.
	baseClass: "dijitTab",

	// Apply dijitTabCloseButtonHover when close button is hovered
	cssStateNodes: {
		closeNode: "dijitTabCloseButton"
	},

	templateString: dojo.cache("dijit.layout", "templates/_TabButton.html", "<div waiRole=\"presentation\" dojoAttachPoint=\"titleNode\" dojoAttachEvent='onclick:onClick'>\n    <div waiRole=\"presentation\" class='dijitTabInnerDiv' dojoAttachPoint='innerDiv'>\n        <div waiRole=\"presentation\" class='dijitTabContent' dojoAttachPoint='tabContent'>\n        \t<div waiRole=\"presentation\" dojoAttachPoint='focusNode'>\n\t\t        <img src=\"${_blankGif}\" alt=\"\" class=\"dijitIcon\" dojoAttachPoint='iconNode' />\n\t\t        <span dojoAttachPoint='containerNode' class='tabLabel'></span>\n\t\t        <span class=\"dijitInline dijitTabCloseButton dijitTabCloseIcon\" dojoAttachPoint='closeNode'\n\t\t        \t\tdojoAttachEvent='onclick: onClickCloseButton' waiRole=\"presentation\">\n\t\t            <span dojoAttachPoint='closeText' class='dijitTabCloseText'>x</span\n\t\t        ></span>\n\t\t\t</div>\n        </div>\n    </div>\n</div>\n"),

	// Override _FormWidget.scrollOnFocus.
	// Don't scroll the whole tab container into view when the button is focused.
	scrollOnFocus: false,

	postMixInProperties: function(){
		// Override blank iconClass from Button to do tab height adjustment on IE6,
		// to make sure that tabs with and w/out close icons are same height
		if(!this.iconClass){
			this.iconClass = "dijitTabButtonIcon";
		}
	},

	postCreate: function(){
		this.inherited(arguments);
		dojo.setSelectable(this.containerNode, false);

		// If a custom icon class has not been set for the
		// tab icon, set its width to one pixel. This ensures
		// that the height styling of the tab is maintained,
		// as it is based on the height of the icon.
		// TODO: I still think we can just set dijitTabButtonIcon to 1px in CSS <Bill>
		if(this.iconNode.className == "dijitTabButtonIcon"){
			dojo.style(this.iconNode, "width", "1px");
		}
	},

	startup: function(){
		this.inherited(arguments);
		var n = this.domNode;

		// Required to give IE6 a kick, as it initially hides the
		// tabs until they are focused on.
		setTimeout(function(){
			n.className = n.className;
		}, 1);
	},

	_setCloseButtonAttr: function(disp){
		this.closeButton = disp;
		dojo.toggleClass(this.innerDiv, "dijitClosable", disp);
		this.closeNode.style.display = disp ? "" : "none";
		if(disp){
			var _nlsResources = dojo.i18n.getLocalization("dijit", "common");
			if(this.closeNode){
				dojo.attr(this.closeNode,"title", _nlsResources.itemClose);
			}
			// add context menu onto title button
			var _nlsResources = dojo.i18n.getLocalization("dijit", "common");
			this._closeMenu = new dijit.Menu({
				id: this.id+"_Menu",
				dir: this.dir,
				lang: this.lang,
				targetNodeIds: [this.domNode]
			});

			this._closeMenu.addChild(new dijit.MenuItem({
				label: _nlsResources.itemClose,
				dir: this.dir,
				lang: this.lang,
				onClick: dojo.hitch(this, "onClickCloseButton")
			}));
		}else{
			if(this._closeMenu){
				this._closeMenu.destroyRecursive();
				delete this._closeMenu;
			}
		}
	},
	_setLabelAttr: function(/*String*/ content){
		// summary:
		//		Hook for attr('label', ...) to work.
		// description:
		//		takes an HTML string.
		//		Inherited ToggleButton implementation will Set the label (text) of the button; 
		//		Need to set the alt attribute of icon on tab buttons if no label displayed
			this.inherited(arguments);
			if(this.showLabel == false && !this.params.title){
				this.iconNode.alt = dojo.trim(this.containerNode.innerText || this.containerNode.textContent || '');
			}
		},

	destroy: function(){
		if(this._closeMenu){
			this._closeMenu.destroyRecursive();
			delete this._closeMenu;
		}
		this.inherited(arguments);
	}
});

}

if(!dojo._hasResource["dijit.layout.ScrollingTabController"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.ScrollingTabController"] = true;
dojo.provide("dijit.layout.ScrollingTabController");




dojo.declare("dijit.layout.ScrollingTabController",
	dijit.layout.TabController,
	{
	// summary:
	//		Set of tabs with left/right arrow keys and a menu to switch between tabs not
	//		all fitting on a single row.
	//		Works only for horizontal tabs (either above or below the content, not to the left
	//		or right).
	// tags:
	//		private

	templateString: dojo.cache("dijit.layout", "templates/ScrollingTabController.html", "<div class=\"dijitTabListContainer-${tabPosition}\" style=\"visibility:hidden\">\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_menuBtn\" iconClass=\"dijitTabStripMenuIcon\"\n\t\t\tdojoAttachPoint=\"_menuBtn\" showLabel=false>&#9660;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_leftBtn\" iconClass=\"dijitTabStripSlideLeftIcon\"\n\t\t\tdojoAttachPoint=\"_leftBtn\" dojoAttachEvent=\"onClick: doSlideLeft\" showLabel=false>&#9664;</div>\n\t<div dojoType=\"dijit.layout._ScrollingTabControllerButton\"\n\t\t\tclass=\"tabStripButton-${tabPosition}\"\n\t\t\tid=\"${id}_rightBtn\" iconClass=\"dijitTabStripSlideRightIcon\"\n\t\t\tdojoAttachPoint=\"_rightBtn\" dojoAttachEvent=\"onClick: doSlideRight\" showLabel=false>&#9654;</div>\n\t<div class='dijitTabListWrapper' dojoAttachPoint='tablistWrapper'>\n\t\t<div wairole='tablist' dojoAttachEvent='onkeypress:onkeypress'\n\t\t\t\tdojoAttachPoint='containerNode' class='nowrapTabStrip'></div>\n\t</div>\n</div>\n"),

	// useMenu:[const] Boolean
	//		True if a menu should be used to select tabs when they are too
	//		wide to fit the TabContainer, false otherwise.
	useMenu: true,

	// useSlider: [const] Boolean
	//		True if a slider should be used to select tabs when they are too
	//		wide to fit the TabContainer, false otherwise.
	useSlider: true,

	// tabStripClass: String
	//		The css class to apply to the tab strip, if it is visible.
	tabStripClass: "",

	widgetsInTemplate: true,

	// _minScroll: Number
	//		The distance in pixels from the edge of the tab strip which,
	//		if a scroll animation is less than, forces the scroll to
	//		go all the way to the left/right.
	_minScroll: 5,

	attributeMap: dojo.delegate(dijit._Widget.prototype.attributeMap, {
		"class": "containerNode"
	}),

	postCreate: function(){
		this.inherited(arguments);
		var n = this.domNode;

		this.scrollNode = this.tablistWrapper;
		this._initButtons();

		if(!this.tabStripClass){
			this.tabStripClass = "dijitTabContainer" +
				this.tabPosition.charAt(0).toUpperCase() +
				this.tabPosition.substr(1).replace(/-.*/, "") +
				"None";
			dojo.addClass(n, "tabStrip-disabled")
		}

		dojo.addClass(this.tablistWrapper, this.tabStripClass);
	},

	onStartup: function(){
		this.inherited(arguments);

		// Do not show the TabController until the related
		// StackController has added it's children.  This gives
		// a less visually jumpy instantiation.
		dojo.style(this.domNode, "visibility", "visible");
		this._postStartup = true;
	},

	onAddChild: function(page, insertIndex){
		this.inherited(arguments);
		var menuItem;
		if(this.useMenu){
			var containerId = this.containerId;
			menuItem = new dijit.MenuItem({
				id: page.id + "_stcMi",
				label: page.title,
				dir: page.dir,
				lang: page.lang,
				onClick: dojo.hitch(this, function(){
					var container = dijit.byId(containerId);
					container.selectChild(page);
				})
			});
			this._menuChildren[page.id] = menuItem;
			this._menu.addChild(menuItem, insertIndex);
		}

		// update the menuItem label when the button label is updated
		this.pane2handles[page.id].push(
			this.connect(this.pane2button[page.id], "set", function(name, value){
				if(this._postStartup){
					if(name == "label"){
						if(menuItem){
							menuItem.set(name, value);
						}
	
						// The changed label will have changed the width of the
						// buttons, so do a resize
						if(this._dim){
							this.resize(this._dim);
						}
					}
				}
			})
		);

		// Increment the width of the wrapper when a tab is added
		// This makes sure that the buttons never wrap.
		// The value 200 is chosen as it should be bigger than most
		// Tab button widths.
		dojo.style(this.containerNode, "width",
			(dojo.style(this.containerNode, "width") + 200) + "px");
	},

	onRemoveChild: function(page, insertIndex){
		// null out _selectedTab because we are about to delete that dom node
		var button = this.pane2button[page.id];
		if(this._selectedTab === button.domNode){
			this._selectedTab = null;
		}

		// delete menu entry corresponding to pane that was removed from TabContainer
		if(this.useMenu && page && page.id && this._menuChildren[page.id]){
			this._menu.removeChild(this._menuChildren[page.id]);
			this._menuChildren[page.id].destroy();
			delete this._menuChildren[page.id];
		}

		this.inherited(arguments);
	},

	_initButtons: function(){
		// summary:
		//		Creates the buttons used to scroll to view tabs that
		//		may not be visible if the TabContainer is too narrow.
		this._menuChildren = {};

		// Make a list of the buttons to display when the tab labels become
		// wider than the TabContainer, and hide the other buttons.
		// Also gets the total width of the displayed buttons.
		this._btnWidth = 0;
		this._buttons = dojo.query("> .tabStripButton", this.domNode).filter(function(btn){
			if((this.useMenu && btn == this._menuBtn.domNode) ||
				(this.useSlider && (btn == this._rightBtn.domNode || btn == this._leftBtn.domNode))){
				this._btnWidth += dojo.marginBox(btn).w;
				return true;
			}else{
				dojo.style(btn, "display", "none");
				return false;
			}
		}, this);

		if(this.useMenu){
			// Create the menu that is used to select tabs.
			this._menu = new dijit.Menu({
				id: this.id + "_menu",
				dir: this.dir,
				lang: this.lang,
				targetNodeIds: [this._menuBtn.domNode],
				leftClickToOpen: true,
				refocus: false	// selecting a menu item sets focus to a TabButton
			});
			this._supportingWidgets.push(this._menu);
		}
	},

	_getTabsWidth: function(){
		var children = this.getChildren();
		if(children.length){
			var leftTab = children[this.isLeftToRight() ? 0 : children.length - 1].domNode,
				rightTab = children[this.isLeftToRight() ? children.length - 1 : 0].domNode;
			return rightTab.offsetLeft + dojo.style(rightTab, "width") - leftTab.offsetLeft;
		}else{
			return 0;
		}
	},

	_enableBtn: function(width){
		// summary:
		//		Determines if the tabs are wider than the width of the TabContainer, and
		//		thus that we need to display left/right/menu navigation buttons.
		var tabsWidth = this._getTabsWidth();
		width = width || dojo.style(this.scrollNode, "width");
		return tabsWidth > 0 && width < tabsWidth;
	},

	resize: function(dim){
		// summary:
		//		Hides or displays the buttons used to scroll the tab list and launch the menu
		//		that selects tabs.

		if(this.domNode.offsetWidth == 0){
			return;
		}

		// Save the dimensions to be used when a child is renamed.
		this._dim = dim;

		// Set my height to be my natural height (tall enough for one row of tab labels),
		// and my content-box width based on margin-box width specified in dim parameter.
		// But first reset scrollNode.height in case it was set by layoutChildren() call
		// in a previous run of this method.
		this.scrollNode.style.height = "auto";
		this._contentBox = dijit.layout.marginBox2contentBox(this.domNode, {h: 0, w: dim.w});
		this._contentBox.h = this.scrollNode.offsetHeight;
		dojo.contentBox(this.domNode, this._contentBox);

		// Show/hide the left/right/menu navigation buttons depending on whether or not they
		// are needed.
		var enable = this._enableBtn(this._contentBox.w);
		this._buttons.style("display", enable ? "" : "none");

		// Position and size the navigation buttons and the tablist
		this._leftBtn.layoutAlign = "left";
		this._rightBtn.layoutAlign = "right";
		this._menuBtn.layoutAlign = this.isLeftToRight() ? "right" : "left";
		dijit.layout.layoutChildren(this.domNode, this._contentBox,
			[this._menuBtn, this._leftBtn, this._rightBtn, {domNode: this.scrollNode, layoutAlign: "client"}]);

		// set proper scroll so that selected tab is visible
		if(this._selectedTab){
			if(this._anim && this._anim.status() == "playing"){
				this._anim.stop();
			}
			var w = this.scrollNode,
				sl = this._convertToScrollLeft(this._getScrollForSelectedTab());
			w.scrollLeft = sl;
		}

		// Enable/disabled left right buttons depending on whether or not user can scroll to left or right
		this._setButtonClass(this._getScroll());
		
		this._postResize = true;
	},

	_getScroll: function(){
		// summary:
		//		Returns the current scroll of the tabs where 0 means
		//		"scrolled all the way to the left" and some positive number, based on #
		//		of pixels of possible scroll (ex: 1000) means "scrolled all the way to the right"
		var sl = (this.isLeftToRight() || dojo.isIE < 8 || (dojo.isIE && dojo.isQuirks) || dojo.isWebKit) ? this.scrollNode.scrollLeft :
				dojo.style(this.containerNode, "width") - dojo.style(this.scrollNode, "width")
					 + (dojo.isIE == 8 ? -1 : 1) * this.scrollNode.scrollLeft;
		return sl;
	},

	_convertToScrollLeft: function(val){
		// summary:
		//		Given a scroll value where 0 means "scrolled all the way to the left"
		//		and some positive number, based on # of pixels of possible scroll (ex: 1000)
		//		means "scrolled all the way to the right", return value to set this.scrollNode.scrollLeft
		//		to achieve that scroll.
		//
		//		This method is to adjust for RTL funniness in various browsers and versions.
		if(this.isLeftToRight() || dojo.isIE < 8 || (dojo.isIE && dojo.isQuirks) || dojo.isWebKit){
			return val;
		}else{
			var maxScroll = dojo.style(this.containerNode, "width") - dojo.style(this.scrollNode, "width");
			return (dojo.isIE == 8 ? -1 : 1) * (val - maxScroll);
		}
	},

	onSelectChild: function(/*dijit._Widget*/ page){
		// summary:
		//		Smoothly scrolls to a tab when it is selected.

		var tab = this.pane2button[page.id];
		if(!tab || !page){return;}

		// Scroll to the selected tab, except on startup, when scrolling is handled in resize()
		var node = tab.domNode;
		if(this._postResize && node != this._selectedTab){
			this._selectedTab = node;

			var sl = this._getScroll();

			if(sl > node.offsetLeft ||
					sl + dojo.style(this.scrollNode, "width") <
					node.offsetLeft + dojo.style(node, "width")){
				this.createSmoothScroll().play();
			}
		}

		this.inherited(arguments);
	},

	_getScrollBounds: function(){
		// summary:
		//		Returns the minimum and maximum scroll setting to show the leftmost and rightmost
		//		tabs (respectively)
		var children = this.getChildren(),
			scrollNodeWidth = dojo.style(this.scrollNode, "width"),		// about 500px
			containerWidth = dojo.style(this.containerNode, "width"),	// 50,000px
			maxPossibleScroll = containerWidth - scrollNodeWidth,	// scrolling until right edge of containerNode visible
			tabsWidth = this._getTabsWidth();

		if(children.length && tabsWidth > scrollNodeWidth){
			// Scrolling should happen
			return {
				min: this.isLeftToRight() ? 0 : children[children.length-1].domNode.offsetLeft,
				max: this.isLeftToRight() ?
					(children[children.length-1].domNode.offsetLeft + dojo.style(children[children.length-1].domNode, "width")) - scrollNodeWidth :
					maxPossibleScroll
			};
		}else{
			// No scrolling needed, all tabs visible, we stay either scrolled to far left or far right (depending on dir)
			var onlyScrollPosition = this.isLeftToRight() ? 0 : maxPossibleScroll;
			return {
				min: onlyScrollPosition,
				max: onlyScrollPosition
			};
		}
	},

	_getScrollForSelectedTab: function(){
		// summary:
		//		Returns the scroll value setting so that the selected tab
		//		will appear in the center
		var w = this.scrollNode,
			n = this._selectedTab,
			scrollNodeWidth = dojo.style(this.scrollNode, "width"),
			scrollBounds = this._getScrollBounds();

		// TODO: scroll minimal amount (to either right or left) so that
		// selected tab is fully visible, and just return if it's already visible?
		var pos = (n.offsetLeft + dojo.style(n, "width")/2) - scrollNodeWidth/2;
		pos = Math.min(Math.max(pos, scrollBounds.min), scrollBounds.max);

		// TODO:
		// If scrolling close to the left side or right side, scroll
		// all the way to the left or right.  See this._minScroll.
		// (But need to make sure that doesn't scroll the tab out of view...)
		return pos;
	},

	createSmoothScroll : function(x){
		// summary:
		//		Creates a dojo._Animation object that smoothly scrolls the tab list
		//		either to a fixed horizontal pixel value, or to the selected tab.
		// description:
		//		If an number argument is passed to the function, that horizontal
		//		pixel position is scrolled to.  Otherwise the currently selected
		//		tab is scrolled to.
		// x: Integer?
		//		An optional pixel value to scroll to, indicating distance from left.

		// Calculate position to scroll to
		if(arguments.length > 0){
			// position specified by caller, just make sure it's within bounds
			var scrollBounds = this._getScrollBounds();
			x = Math.min(Math.max(x, scrollBounds.min), scrollBounds.max);
		}else{
			// scroll to center the current tab
			x = this._getScrollForSelectedTab();
		}

		if(this._anim && this._anim.status() == "playing"){
			this._anim.stop();
		}

		var self = this,
			w = this.scrollNode,
			anim = new dojo._Animation({
				beforeBegin: function(){
					if(this.curve){ delete this.curve; }
					var oldS = w.scrollLeft,
						newS = self._convertToScrollLeft(x);
					anim.curve = new dojo._Line(oldS, newS);
				},
				onAnimate: function(val){
					w.scrollLeft = val;
				}
			});
		this._anim = anim;

		// Disable/enable left/right buttons according to new scroll position
		this._setButtonClass(x);

		return anim; // dojo._Animation
	},

	_getBtnNode: function(e){
		// summary:
		//		Gets a button DOM node from a mouse click event.
		// e:
		//		The mouse click event.
		var n = e.target;
		while(n && !dojo.hasClass(n, "tabStripButton")){
			n = n.parentNode;
		}
		return n;
	},

	doSlideRight: function(e){
		// summary:
		//		Scrolls the menu to the right.
		// e:
		//		The mouse click event.
		this.doSlide(1, this._getBtnNode(e));
	},

	doSlideLeft: function(e){
		// summary:
		//		Scrolls the menu to the left.
		// e:
		//		The mouse click event.
		this.doSlide(-1,this._getBtnNode(e));
	},

	doSlide: function(direction, node){
		// summary:
		//		Scrolls the tab list to the left or right by 75% of the widget width.
		// direction:
		//		If the direction is 1, the widget scrolls to the right, if it is
		//		-1, it scrolls to the left.

		if(node && dojo.hasClass(node, "dijitTabDisabled")){return;}

		var sWidth = dojo.style(this.scrollNode, "width");
		var d = (sWidth * 0.75) * direction;

		var to = this._getScroll() + d;

		this._setButtonClass(to);

		this.createSmoothScroll(to).play();
	},

	_setButtonClass: function(scroll){
		// summary:
		//		Disables the left scroll button if the tabs are scrolled all the way to the left,
		//		or the right scroll button in the opposite case.
		// scroll: Integer
		//		amount of horizontal scroll

		var scrollBounds = this._getScrollBounds();
		this._leftBtn.set("disabled", scroll <= scrollBounds.min);
		this._rightBtn.set("disabled", scroll >= scrollBounds.max);
	}
});

dojo.declare("dijit.layout._ScrollingTabControllerButton",
	dijit.form.Button,
	{
		baseClass: "dijitTab tabStripButton",

		templateString: dojo.cache("dijit.layout", "templates/_ScrollingTabControllerButton.html", "<div dojoAttachEvent=\"onclick:_onButtonClick\">\n\t<div waiRole=\"presentation\" class=\"dijitTabInnerDiv\" dojoattachpoint=\"innerDiv,focusNode\">\n\t\t<div waiRole=\"presentation\" class=\"dijitTabContent dijitButtonContents\" dojoattachpoint=\"tabContent\">\n\t\t\t<img waiRole=\"presentation\" alt=\"\" src=\"${_blankGif}\" class=\"dijitTabStripIcon\" dojoAttachPoint=\"iconNode\"/>\n\t\t\t<span dojoAttachPoint=\"containerNode,titleNode\" class=\"dijitButtonText\"></span>\n\t\t</div>\n\t</div>\n</div>\n"),

		// Override inherited tabIndex: 0 from dijit.form.Button, because user shouldn't be
		// able to tab to the left/right/menu buttons
		tabIndex: "-1"
	}
);

}

if(!dojo._hasResource["dijit.layout.TabContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.layout.TabContainer"] = true;
dojo.provide("dijit.layout.TabContainer");





dojo.declare("dijit.layout.TabContainer",
	dijit.layout._TabContainerBase,
	{
		// summary:
		//		A Container with tabs to select each child (only one of which is displayed at a time).
		// description:
		//		A TabContainer is a container that has multiple panes, but shows only
		//		one pane at a time.  There are a set of tabs corresponding to each pane,
		//		where each tab has the name (aka title) of the pane, and optionally a close button.

		// useMenu: [const] Boolean
		//		True if a menu should be used to select tabs when they are too
		//		wide to fit the TabContainer, false otherwise.
		useMenu: true,

		// useSlider: [const] Boolean
		//		True if a slider should be used to select tabs when they are too
		//		wide to fit the TabContainer, false otherwise.
		useSlider: true,

		// controllerWidget: String
		//		An optional parameter to override the widget used to display the tab labels
		controllerWidget: "",

		_makeController: function(/*DomNode*/ srcNode){
			// summary:
			//		Instantiate tablist controller widget and return reference to it.
			//		Callback from _TabContainerBase.postCreate().
			// tags:
			//		protected extension

			var cls = this.baseClass + "-tabs" + (this.doLayout ? "" : " dijitTabNoLayout"),
				TabController = dojo.getObject(this.controllerWidget);

			return new TabController({
				id: this.id + "_tablist",
				dir: this.dir,
				lang: this.lang,
				tabPosition: this.tabPosition,
				doLayout: this.doLayout,
				containerId: this.id,
				"class": cls,
				nested: this.nested,
				useMenu: this.useMenu,
				useSlider: this.useSlider,
				tabStripClass: this.tabStrip ? this.baseClass + (this.tabStrip ? "":"No") + "Strip": null
			}, srcNode);
		},

		postMixInProperties: function(){
			this.inherited(arguments);

			// Scrolling controller only works for horizontal non-nested tabs
			if(!this.controllerWidget){
				this.controllerWidget = (this.tabPosition == "top" || this.tabPosition == "bottom") && !this.nested ?
							"dijit.layout.ScrollingTabController" : "dijit.layout.TabController";
			}
		}
});


}

if(!dojo._hasResource['com.sixnet.services.modules.unit.trigger']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.unit.trigger'] = true;
dojo.provide('com.sixnet.services.modules.unit.trigger');



dojo.declare('com.sixnet.services.modules.unit.trigger', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\ttrigger me!\n</div>\n",
	appParams: {},
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.triggerHandle = _sixnet_framework.poller.subscribe('/unit/trigger/'.concat(this.appParams.item.id), dojo.hitch(this, "triggerUpdate"));
		_sixnet_framework._logger.event(new com.sixnet.services.widgets.sixnetLoggerPane({ content:'Attempting to trigger unit: <span style="color:black">'.concat(this.appParams.item.serial).concat('</span>')}));
	},
	buildWidgetThumbnailPane:function(){
		return false;
	},
	execute: function(){
		_sixnet_framework.bc('unit', 'triggerCheckIn', { unitListId: this.appParams.item.id});
	},
	unload: function(){
		_sixnet_framework.poller.unsubscribe(this.triggerHandle);
		this.inherited("unload", arguments);
	},
	triggerUpdate: function(eventPath, payload){
		if( this.appParams.item.id != payload.unitListId) return;
		//TODO: Test unload and see how to prevent processing another unit's call back.
		_sixnet_framework._logger.event(new com.sixnet.services.widgets.sixnetLoggerPane({ content: payload.message.concat(': ').concat(this.appParams.item.serial)}));
		this.unload();
	}
});
	

}

if(!dojo._hasResource['com.sixnet.services.modules.unit.formatters']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.unit.formatters'] = true;


dojo.provide('com.sixnet.services.modules.unit.formatters');


dojo.declare('com.sixnet.services.modules.unit.formatters', [com.sixnet.services.core.data.formatters], {

	onTrigger: function(item){
	},
	onGauOpen: function(item, secure){
	},
	onFormatSerial: function(item, serialPane){
	},
	
	serial:function(value,idx,cell){
		var item = this.grid.getItem(idx);
		var output = '<img src="'+dojo.moduleUrl('com.sixnet.services.core', 'templates/images/dashWorking.gif')+'" width="15px" height="15px" />';
		var serialPane = new dijit.layout.ContentPane({content:output});
		serialPane.domNode.height = '60px';
		setTimeout(dojo.hitch(this, function(item, serialPane, value){
			serialPane.setContent(value+'<br/>');
			
			// Applies everywhere there is a serial number
			var D = "<img title='details' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/D.gif\" />");
			var detailCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; cursor:pointer;', content:D, onClick: dojo.hitch(this, function(item){
				_sixnet_framework.getDash().runApp( 'com.sixnet.services.modules.access.unitDetail', {item:item, background: false});
			}, item)});
			//  6.13.10 Neil. Adding images as the text is not showing in IE.
			detailCP.placeAt(serialPane.domNode, "last");

			// Applies only to the containing widget
			this.onFormatSerial(item, serialPane);
		},item, serialPane, value),500);
		//this.onFormatSerial(item, serialPane);
		return serialPane;
	},
//	serial:function(value,idx,cell){
//		var item = this.grid.getItem(idx);
//		var output = value.concat('<br />');
//		var serialPane = this.getContentPane('serial', true);
//		serialPane.setContent(output);
//		var D = "<img title='details' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/D.gif\" />");
//		var detailCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; cursor:pointer;', content:D, onClick: dojo.hitch(this, function(value, idx){
//		//	this.unitManager.detail(item);
//			this.onUnitDetail(item);
//		})});
//		//  6.13.10 Neil. Adding images as the text is not showing in IE.
//		var H = "<img title='history' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/H.gif\" />");
//	
//		var historyCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; margin-left:2px; cursor:pointer;', content: H, onClick: dojo.hitch(this, function(value, idx){
//			//this.unitManager.history(item);
//			this.onUnitHistory(item);
//		})});
//		var J = "<img title='add job' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/J.gif\" />");
//	    
//		var jCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; margin-left:2px; cursor:pointer;', content: J, onClick: dojo.hitch(this, function(value, idx){
//			_sixnet_framework.getDash().runApp('com.sixnet.services.modules.access.jobAdd', [item]);
//		})});
//		detailCP.placeAt(serialPane.domNode, "last");
//		historyCP.placeAt(serialPane.domNode, "last");
//		jCP.placeAt(serialPane.domNode, "last");
//
//		return serialPane;
//	},
	interfaces: function(value, idx){
		var interfacePane = new dijit.layout.ContentPane();
		setTimeout(dojo.hitch(this, function(value, idx, interfacePane){
			try{
			
			var item = this.grid.getItem(idx);
			var interfaceList = dojo.fromJson(value);
			var output = 'R/H: ' .concat(interfaceList.remote_host);
			dojo.forEach(interfaceList.interfaces, function(anInterface){
				if( anInterface.status == 'UP'){
					output += '<br />'.concat(anInterface.name).concat(": ").concat( anInterface.ipv4);
				}
			});
			output += '<br />';
			interfacePane.setContent(output);
			//  6.13.10 Neil. Adding just a trigger button via image.
			var T = "<img title='trigger check-in' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/T.gif\" />");
			var triggerCP = new dijit.layout.ContentPane({style:'float:left; clear:none; cursor:pointer;', content:T, onClick: dojo.hitch(this, function(value, idx){
				this.onTrigger(item);
				//_sixnet_framework.getDash().runApp('com.sixnet.services.modules.unit.trigger', { item: item});
				var trigger = new com.sixnet.services.modules.unit.trigger({ appParams:{ item: item} });
				trigger.execute();
			})});
			var GAU = "<img title='open GAU' style='height:12px;width:33px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/GAU.gif\" />");
			var gauCP = new dijit.layout.ContentPane({style:'float:left; clear:none; margin-left:2px; cursor:pointer;', content:GAU, onClick: dojo.hitch(this, function(value, idx){
				this.onGauOpen(interfaceList.remote_host, false);
			})});
			var sGAU = "<img title='secure GAU' style='height:12px;width:33px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/sGAU.gif\" />");
			var sgauCP = new dijit.layout.ContentPane({style:'float:left; clear:none; margin-left:2px; cursor:pointer;', content:sGAU, onClick: dojo.hitch(this, function(value, idx){
				this.onGauOpen(interfaceList.remote_host, true);
			})});
			var container = new dijit.layout.ContentPane({});
			triggerCP.placeAt(container.domNode, "last");
			gauCP.placeAt(container.domNode, "last");
			sgauCP.placeAt(container.domNode, "last");
			
			container.placeAt(interfacePane.domNode);
//			
			}catch(e){
				console.log('wwh', e);
			}
		}, value, idx, interfacePane), 10);
		
		return interfacePane;
	},
	
	client_config: function(value, idx){
		var client_configPane = new dijit.layout.ContentPane();
		setTimeout(dojo.hitch(this, function(value, idx, client_configPane){
			try{
				var item = this.grid.getItem(idx);
				var client_configList = dojo.fromJson(value);
				var output = 'Servers:<br />';
				dojo.forEach(client_configList.servers, function(server){
						if(server.type == 'primary'){
							output += 'SVM1: '.concat(server.ip).concat('<br />');
						}else{
							output += 'SVM2: '.concat(server.ip).concat('<br />');
						}
				});
				output += 'MODE: '.concat(client_configList.server_mode).concat('<br />');
				output += 'Interval @ '.concat(client_configList.interval).concat(' seconds <br />');
				client_configPane.setContent(output);
			}catch(e){
				console.log('client_config formatter error: ', e);
			}
		}, value, idx, client_configPane), 10);
		return client_configPane;
	},
	
	alertColor: function(value, idx, cell){
		var item = this.grid.getItem(idx);
		alertLevel = item.alert_level;
		// if level is _null set level to error
		if(alertLevel == null) alertLevel = 3;
		var levels = ["Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Info", "Debug"];	
		var customClass = "".concat(levels[alertLevel]);
		var alertDiv = new dijit.layout.ContentPane({content:"<p style='margin:0; padding:0'>".concat(value.substring(0,25)).concat("</p>"), style:"text-align:center; width:100%; height:100%;"});
//		var unitManager = this.unitManager;
//		dojo.connect(alertDiv, "onClick", function(){
//			unitManager.openShadow("<p>"+value+"</p>");
//		});
		cell.customClasses.push(customClass);
		dojo.addClass(alertDiv.domNode, customClass);
		return alertDiv;
	},
	cellLightbarSignal: function(value, idx, cell){
		if(value == null || value == '')value = 0;
		var lightbarPic = "<img style=\"width:33px; height:19px; vertical-align:middle;\" src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/signal");
		// graphic ...x.gif == ...0.gif
		lightbarPic = lightbarPic.concat(value).concat(".gif\" />");
//		return "<div style=\"text-align:center; margin:auto\">".concat(lightbarPic).concat("</div>");
		var cellLightbarSignalCP = new dijit.layout.ContentPane({content:"<div style=\"text-align:center; height:19px; margin:auto\">".concat(lightbarPic).concat("</div>")});
		return cellLightbarSignalCP;
	}
	
});

}

if(!dojo._hasResource['com.sixnet.services.widgets.sixnetGridView']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.widgets.sixnetGridView'] = true;
dojo.provide('com.sixnet.services.widgets.sixnetGridView');








//_this is a toolbar widget
//__________________________
// sixnetGridView processes:
/*
 * JS
 * Start with-> this.connect(this.grid, "onViewDescriptorLoaded", "_initializeViewMenu");
 * 
 * _initializeViewMenu( calls two:(
 * _getDescriptors-> calls to: 
	 * 	_makeDescriptorLookups-> onComplete is: 
	 * 	_buildColumnsMenu-> calls:
	 * xhr request function --this._getSavedViews(dojo.hitch(this, "_buildViewMenu"));--
	 * 	_getSavedViews->onComplete from server is: 
	 * 	_buildViewMenu->calls:
	 *  grid.applyNewDescriptor 
	 * 	_startGrid->calls two: (
	 * _populateViewNames
	 * 	grid functions+++)),
 * (_buildViewMenuManager))
 * 
 */
/* 
 * PHP used for this widget (access)
 * updateCustomViewName($newName, $viewId)
 * insert
 * setCustomView($grid, $name, $view, $isDefault)
 * based on name
 * setDefaultView($userId, $accountId, $grid, $name)
 * updateCustomView($grid, $name, $view, $isDefault)
 * updateChangedView($id, $view)
 * updateCustomViewName($newName, $viewId)
 * getUserView($viewId)
 * deleteViews($viewIdArray) USED
 * getViews
 * this.serverModeSelect.set("forceWidth", true);
*/
dojo.declare("com.sixnet.services.widgets.sixnetGridView",[dijit._Widget, dijit._Templated],{
	//TODO: Stay at the top and play after-comment anchor.
	widgetsInTemplate: true,
	templateString: dojo.cache("com.sixnet.services.widgets", "templates/sixnetGridView.html", "<div>\n\t<div dojoType=\"dijit.layout.ContentPane\" style=\"float:left; margin-left:.25em; width:30em\">\t\n\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"columnsMenuHolder\" style=\"float:left; margin-top:.5em;\"></div>\n\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"viewSelectHolder\" style=\"float:left; width:15em\">\n\n\t\t</div>\n\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"viewButtons\" style=\"float:left; margin-top:.5em;\"></div>\n\t</div>\n</div>\n"),
	ddButton: null,
	viewMenuManagerDD: null,
	columnsCheckBoxes: null,
	grid: null,
	_viewSet: null, /* always current seen grid view (altered or not) */
	_viewSetCells: null,
	_columnSet: null, /* always full set of possibles from server */
	_columnSetCells: null,
	_columnSetLookup: null, /* lookup on columnSet */
	_viewSetLookup: null, /* lookup on viewSet */
	_changeMarkedOn: null,
	_currentFullDescriptor: null, /* set aside */
	_currentOrder: null, /* array of current visual order */
	_viewSelect: null,
	_viewSaved: null,
	_columnSizeAltered: null,
	_orderAltered: null,
	_showHide: null,
	_hideColumn: null,
	_showColumn: null,
	_userViewsData: null, /* the data returned from getSavedViews */
	_gridName: null, /* from grid's attachPoint */
	_busySynchingChecks: null,
	_storeBusy: null,
	_firstLoad: null,
	_store: null,
	_defaultView: null,
	_viewNames: null,

	postCreate: function(){
		//  set up vars, have grid holdOff to control grid->startGrid()
		this.grid.holdOff = true;
		this._firstLoad = true;
		this._busySynchingChecks = false;
		this._storeBusy = false;
		this._columnSizeAltered = false;
		this._orderAltered = false;
		this._showHide = false;
		this._gridName = this.grid.get('dojoAttachPoint');
		this._viewSaved = true;
		this.columnsCheckBoxes = [];
		this._columnSetLookup = {};
		this._viewSetLookup = {};
		this._viewNames = {};
		//  connex
		this.connect(this.grid, "onViewDescriptorLoaded", "_initializeViewMenu");
		this.connect(this.grid, "markViewChanged", "_checkViewChanged");
		//  addToToolbar
		this.grid.addToToolbar(this, 'left');
	},
	
	_initializeViewMenu: function(){
		try{
			//  get standard (cells) and full descriptor (all_cells) --from grid--
			this._getDescriptors();
			//  start adding to template-dom with an all-_this piece (menu manager [save/manage gui])
			this._buildViewMenuManager();
		}catch(e){
			_sixnet_framework.log(1, "error in _initializeViewMenu",e);
		}
	},
	
	_populateViewNames: function(){
		this._storeBusy = true;
		var this_gridView = this;
		var item = this._store.fetch({
			query: {},
			onComplete:dojo.hitch(this, function(data){
				dojo.forEach(data, function(view){
					this_gridView._viewNames[view.name[0]] = view.id[0];
				});
				this._storeBusy = false;
			})
		});
	},
	
	_startGrid: function(){
		this._populateViewNames();
//		this.grid.holdOff = false;
//		this.grid.startGrid();
		return;
	},
	
	_buildViewMenuManager: function(){
		var holderN_width = 178;
	    var holderN = new dijit.layout.ContentPane({style: "width:".concat(holderN_width).concat("; background:#fff; padding:4px; border:1px solid #7eabcd;")});
	    dojo.addClass(dojo.byId(holderN.domNode), '.dijitMenuItem');
	    dojo.addClass(dojo.byId(holderN.domNode), '.dijitReset');
	    this.viewMenuManagerDD = new dijit.form.DropDownButton({
            label: "Views:",
            dropDown: holderN
        });
	    dojo.style(this.viewMenuManagerDD.domNode, "float", "left");
	    this.viewMenuManagerDD.placeAt(this.viewButtons.domNode, "last");
        var manageButtonsCP = new dijit.layout.ContentPane({style:"float:left; width:170px"}).placeAt(dojo.byId(holderN.domNode), "last");
        var saveView = new dijit.layout.ContentPane({
            content: "Save View",
            style: "cursor:pointer; height:23px",
            onClick: dojo.hitch(this, "onSaveViewClick")
        }).placeAt(manageButtonsCP.domNode, "last");
        var manageViews = new dijit.layout.ContentPane({
            content: "Manage Views",
            style: "cursor:pointer; height:23px",
            onClick: dojo.hitch(this, "manageViews")
        }).placeAt(manageButtonsCP.domNode, "last");
        var clearChanges = new dijit.layout.ContentPane({
            content: "Clear Changes",
            style: "cursor:pointer; height:23px",
            onClick: dojo.hitch(this, "clearChanges")
        }).placeAt(manageButtonsCP.domNode, "last");
	},
	
	_getDescriptors: function(){
		try{
			var fullDescriptor = this.grid.getFullDescriptor();
			//  set aside a copy of server response
			this._currentFullDescriptor = dojo.clone(fullDescriptor);
			//  reset and set column/view cells
			this._columnSet = {};
			this._viewSet = {};
			this._columnSet.cells = {};
			this._viewSet.cells = {};
			this._columnSet.cells = dojo.clone(this._currentFullDescriptor.all_cells);
			this._viewSet.cells = dojo.clone(this._currentFullDescriptor.cells);
			//  make look-ups and then call buildColumnsMenu
			this._makeDescriptorLookups(dojo.clone(this._columnSet), dojo.clone(this._viewSet), dojo.hitch(this, "_buildColumnsMenu"));
//			onComplete();
		}catch(e){
			//console.log("error in _getDescriptors", e);
		}
	},
	
	_makeDescriptorLookups: function(_columnSet, _viewSet, onComplete){
		//console.log("_makeDescriptorLookups", _columnSet, _viewSet);
		this._columnSetLookup = {};
		this._viewSetLookup = {};
		for(var i = 0; i < _columnSet['cells'].length; i++){
			this._columnSetLookup[_columnSet['cells'][i].field] = _columnSet['cells'][i];
		}
		for(var i = 0; i < _viewSet['cells'].length; i++){
			this._viewSetLookup[_viewSet['cells'][i].field] = _viewSet['cells'][i];
		}
		//console.log("LOOKUPS:  ", this._columnSetLookup, "____&____", this._viewSetLookup );
		onComplete();
	},
	
	_getSavedViews: function(onComplete){		
		//console.log("1: _getSavedViews");
		_sixnet_framework.bc('access', 'getViews', {grid: this._gridName }, dojo.hitch(this, function(response){
				if(response.successful){
					// send to build drop down. This includes if the data is empty.
					//console.log("getViews:  ", response);
					this._userViewsData = response.data;
					var _storeStructuredData = {"identifier": "id", "label":"name", items:this._userViewsData};
					this._store = new dojo.data.ItemFileWriteStore({data:_storeStructuredData});
					//console.log("the standard view set >>>  ", dojo.clone(this._viewSet));
					//console.log(this._store, "  <<< and the _store");
					// insure we have the default _viewSet here!
					this._viewSet.cells = dojo.clone(this._currentFullDescriptor.cells);
					this._store.newItem({id:"standard", name:["standard"], view:dojo.toJson(this._viewSet)});
					onComplete();
				}else if(!response.successful){
					//  split error returned and alert
					var alertError = response.error.split("::");
					alert(alertError[0]);
					// and do log out process
					setTimeout('_sixnet_framework.getUserRoles()', 0);
					setTimeout('_sixnet_framework.reloadDash()', 0);
					return;
				}
			})
		);
	},
	
	_buildViewMenu: function(){
		try{
			this._changeMarkedOn = null;
			this._hideColumn = null;
			this._showColumn = null;
			this._showHide = false;
			this._viewSaved = false;
			this._orderAltered = false;
			this._columnSizeAltered = false;
			this._defaultView = {};
			if(this._viewSelect && !this._firstLoad){
				this._viewSelect.destroyRecursive();
			}
			this._viewSelect = new dijit.form.Select({
				style:"margin-top:.5em; width:14em; border:1px solid #B3B3B3; background:url('images/validationInputBg.png') repeat-x scroll left top #FFFFFF;",
				forceWidth:true,
				onChange:dojo.hitch(this, "onViewMenuChange")
			}).placeAt(this.viewSelectHolder.domNode, "last");
			if(dojo.isIE){
				dojo.style(this._viewSelect.domNode, 'margin-top', '.23em');
			}
			// set _store to default or basic as default
			this._storeBusy = true;
			var item = this._store.fetch({
				query: {isDefault: "TRUE"},
				onComplete:dojo.hitch(this, function(data){
					//console.log('onComplete, isDefault: ', data);
					this._viewSelect.setStore(this._store, {}, {});
					if(data[0] && data[0].view[0]){
						this._defaultView = data[0];
						this._viewSelect.attr('value', data[0].id[0]);
						this._viewSet = {};
						this._viewSet.cells = dojo.fromJson(data[0].view[0]).cells;
						this.grid.applyNewDescriptor(this._viewSet);
					}else{
						this._viewSelect.attr('value', 'standard');
						this.grid.applyNewDescriptor(this._viewSet);
					}
					this._storeBusy = false;
				})});
	        if(this._firstLoad){
	        	this._firstLoad = false;
	        	this._startGrid();
	        }
		}catch(e){
			_sixnet_framework.log("error in _buildViewMenu", e);
		}
	},
	
	onSaveViewClick: function(){
		// create an instance of Dialog with the content (loaded from href), id and title.
		var grid = this._gridName;
		var view = this._viewSet;
		var userId = _sixnet_framework._userId;
		var accountId = _sixnet_framework._accountId;
		//
		var saveViewDialog = new dijit.Dialog({style:"width:310px; height:155px; text-align:center", id:"saveViewDialog", title:'Save View for:  '+grid, onLoad: function(){
			// this method fires when the dialog has finished loading its content.
			dijit.byId('saveViewDialog').connect(dijit.byId('saveViewDialog'), "onCancel", function(){
				// this is for the 'x' button built into the Dialog.
				this.destroyRecursive();
			});
		}});
		var cp = new dijit.layout.ContentPane({style:"margin-top:1em; margin-left:auto; margin-right:auto; width:16em"});
		if(this._viewSaved == false){
			var this_gridView = this;
			var isDefault = false;
			var doOverwrite = false;
			var form = new dijit.form.Form({}).placeAt(cp.domNode, "last");
			var inputCP = new dijit.layout.ContentPane({style:"text-align:right;"}).placeAt(form.domNode, "last");
			var viewName = new dijit.form.ValidationTextBox({
				id:"viewName",
				style:"text-align:left",
				name:"name"}).placeAt(inputCP.domNode, "last");
			dijit.byId("viewName").validator = function(){
				//console.log('checking isValid:  ', arguments, this);
				var name = arguments[0];
				var startRegex = /^[A-Z0-9]/i;
				var specialChars = new RegExp("[/</&/>/*/#/;/$/^/%/!]");
				dijit.byId('viewName').set('invalidMessage', 'Name too short (1 character min)');
				if(name.length == 0) return false;
				dijit.byId('viewName').set('invalidMessage', 'Name must start with: A-Z or 0-9');
				if(!startRegex.test(name)) return false;
				dijit.byId('viewName').set('invalidMessage', 'Invalid characters in name');
				if(specialChars.test(name)) return false;
				dijit.byId('viewName').set('invalidMessage', 'Name too long (25 character max)');
				if(name.length > 25) return false;
				dijit.byId('viewName').set('invalidMessage', 'Name exists already, check overwrite');
				if(this_gridView._viewNames[name] && !(doOverwrite)) return false;
				dijit.byId('viewName').set('invalidMessage', 'Cannot use name [standard]');
				if(name == 'standard') return false;
				return true;
			};
			var checkboxCP = new dijit.layout.ContentPane({style:"text-align:right; margin-top:3px;", content:"<b>Make default  </b>"}).placeAt(form.domNode, "last");
			var checkbox = new dijit.form.CheckBox({
				onChange:function(v){
					isDefault = v;
				}
			}).placeAt(checkboxCP.domNode, "last");
			var overwriteCP = new dijit.layout.ContentPane({style:"text-align:right; margin-top:3px;", content:"<b>Overwrite existing  </b>"}).placeAt(form.domNode, "last");
			var overwrite = new dijit.form.CheckBox({
				onChange:function(v){
					doOverwrite = v;
				}
			}).placeAt(overwriteCP.domNode, "last");
			var buttonCP = new dijit.layout.ContentPane({style:"text-align:right;"}).placeAt(form.domNode, "last");
			var saveButton = new dijit.form.Button({
				label:"Save",
				onClick:function(){
					if(!dijit.byId("viewName").isValid()) return false;
					var item = form.getValues();
					item.grid = grid;
					item.view = dojo.toJson(view);
					item.user_id = userId;
					item.account_id = accountId;
					item.isDefault = isDefault;
					if(doOverwrite && this_gridView._viewNames[item.name]){
						item.id = this_gridView._viewNames[item.name];
					}
					//console.log("view-item to put:  ", item);
					viewName.set('disabled', true);
					checkbox.set('disabled', true);
					cancelButton.set('disabled', true);
					saveButton.set('disabled', true);
					if(this_gridView._defaultView && isDefault){
						var oldId = this_gridView._defaultView.id[0];
						var oldName = (this_gridView._defaultView.original_name)?this_gridView._defaultView.original_name[0]:this_gridView._defaultView.name[0];
						var oldView = this_gridView._defaultView.view[0];
						var oldItem = {};
						oldItem.id = oldId;
						oldItem.name = oldName;
						oldItem.view = oldView;
						oldItem.isDefault = false;
						oldItem.grid = grid;
						oldItem.account_id = accountId;
						oldItem.user_id = userId;
						if(oldName != item.name){
							//  no need to update if we will anyway in next updateViewData
							_sixnet_framework.bcSilent('access','updateViewData', { viewName: 'views', items:[ oldItem ]}, dojo.hitch(this, function(response){
								if(response.successful){
									_sixnet_framework.log(2, "old default changed");
					        	}  	
							}));
						}
					}
					if(item.name != '' && grid != null && view != null){
						_sixnet_framework.bcSilent('access','updateViewData', { viewName: 'views', items:[ item ]}, dojo.hitch(this, function(response){
							if(response.successful){
								this_gridView._viewSaved = true;
								dijit.byId('saveViewDialog').hide();
								dijit.byId('saveViewDialog').destroyRecursive();
								this_gridView._getSavedViews(dojo.hitch(this_gridView, "_buildViewMenu"));
				        	}  	
						}));
						return;
					}
				}
			}).placeAt(buttonCP.domNode, "last");
			var cancelButton = new dijit.form.Button({
				label:"Cancel",
				onClick:function(){
					dijit.byId('saveViewDialog').hide();
					dijit.byId('saveViewDialog').destroyRecursive();
				}
			}).placeAt(buttonCP.domNode, "last");
		}else{
			cp.set('style', {textAlign:'center'});
			cp.set('content', "There are no changes to be saved.");
//			new dijit.layout.ContentPane({style:"text-align:center; height:20px; font-weight:bold;", content:}).placeAt(cp.domNode, "last");
		}
		if(dojo.isIE){
			dojo.style(saveViewDialog.containerNode, "text-align", "center");
//			dojo.style(saveViewDialog.containerNode, "text-align-last", "center");
		}
		cp.startup();
		saveViewDialog.set('content', cp);
		saveViewDialog.show();
	},
	
	manageViews: function(){
		// create an instance of Dialog with the content (loaded from href), id and title.
		var grid = this._gridName;
		var userId = _sixnet_framework._userId;
		var accountId = _sixnet_framework._accountId;
		//
		var dialogHeight = 135;
		var manageViewDialog = new dijit.Dialog({style:"width:310px; height:135px; text-align:center", id:"manageViewDialog", title:'Manage Views for:  '+grid, onLoad: function(){
			// this method fires when the dialog has finished loading its content.
			dijit.byId('manageViewDialog').connect(dijit.byId('manageViewDialog'), "onCancel", function(){
				// this is for the 'x' button built into the Dialog.
				this.destroyRecursive();
			});
		}});
		//  grab views info from _store
		var cp = new dijit.layout.ContentPane({style:"margin-top:1em; margin-left:auto; margin-right:auto; width:16em"});
//		var cpIntro = dijit.layout.ContentPane({content:'Check and apply to delete view(s).'}).placeAt(cp.domNode, "last");
		var form = new dijit.form.Form({}).placeAt(cp.domNode, "last");
		var hasCustom = false;
		var item = this._store.fetch({
			query: {},
			onComplete:dojo.hitch(this, function(data){
				//console.log('onComplete, full set of views: ', data);
				dojo.forEach(data, function(view){
					//console.log('onComplete, full set of view: ', view);
					if(view.name[0] != 'standard'){
						hasCustom = true;
						var viewName = (view.original_name)?view.original_name[0]:view.name[0];
						var viewCP = new dijit.layout.ContentPane({style:"clear:both; margin-top:.2em"}).placeAt(form.domNode, "last");
						var checkbox = new dijit.form.CheckBox({
							style:"float:left",
							name:view.id[0],
							onChange:function(v){
								//console.log(v, viewName, view.id[0]);
							}
						}).placeAt(viewCP.domNode, "last");
						var viewNameCP = new dijit.layout.ContentPane({content:viewName, style:'text-align:left'}).placeAt(viewCP.domNode, "last");
						dialogHeight += 16;
					}
				});
				this._storeBusy = false;
			})});
		if(hasCustom){
			var buttonCP = new dijit.layout.ContentPane({style:"text-align:right; margin-top:.5em"}).placeAt(form.domNode, "last");
			var cancelButton = new dijit.form.Button({
				label:"Cancel",
				onClick:function(){
					dijit.byId('manageViewDialog').hide();
					dijit.byId('manageViewDialog').destroyRecursive();
				}
			}).placeAt(buttonCP.domNode, "last");
			var this_gridView = this;
			var deleteButton = new dijit.form.Button({
				label:"Delete Selected",
				onClick:function(){
					var values = form.getValues();
					var toDelete = [];
					cancelButton.set('disabled', true);
					deleteButton.set('disabled', true);
					//console.log("delete these: ", values);
					//  run thru values and check for ["on"] state
					for(prop in values){
						//console.log(prop, values[prop][0]);
						if(values[prop][0]){
							//console.log("X me:  ", prop);
							toDelete.push(prop);
						}
					}
					//  make bc call deleteViews->viewIdArray
					if(toDelete.length > 0){
							_sixnet_framework.bc('access', 'deleteViews', {viewIdArray: toDelete}, dojo.hitch(this, function(response){
								if(response.successful){
									// send to build drop down. This includes if the data is empty.
									//console.log("deleteViews:  ", response);
									dijit.byId('manageViewDialog').hide();
									dijit.byId('manageViewDialog').destroyRecursive();
									this_gridView._getSavedViews(dojo.hitch(this_gridView, "_buildViewMenu"));
								}else if(!response.successful){
									//  split error returned and alert
									var alertError = response.error.split("::");
									alert(alertError[0]);
									// and do log out process
									setTimeout('_sixnet_framework.getUserRoles()', 0);
									setTimeout('_sixnet_framework.reloadDash()', 0);
									return;
								}
							})
						);
					}else{
						dijit.byId('manageViewDialog').hide();
						dijit.byId('manageViewDialog').destroyRecursive();
					}			
				}
			}).placeAt(buttonCP.domNode, "last");
			//console.log("dialogHeight:  ", dialogHeight);
			dojo.style(manageViewDialog.domNode, {height: dialogHeight});
			if(dojo.isIE){
				dojo.style(form.domNode, {textAlign:'center'});
			}
		}else{
			cp.set('style', {textAlign:'center'});
			cp.set('content', "There are no custom views saved.");
//			new dijit.layout.ContentPane({style:"text-align:center; height:20px; font-weight:bold;", content:}).placeAt(cp.domNode, "last");
		}
		if(dojo.isIE){
			dojo.style(manageViewDialog.containerNode, "text-align", "center");
		}
		cp.startup();
		manageViewDialog.set('content', cp);
		manageViewDialog.show();
	},
	
	clearChanges: function(){
		//  cause a reload of the currently selected saved view
		//  making sure _storeBusy flag is off.
		this._storeBusy = false;
		this.onViewMenuChange();
		//console.log("------------clearChanges, _viewSelect value. :  ", dojo.clone(this._viewSelect.get('value')));
	},
	
	_buildColumnsMenu: function(){
		try{
			//  server request function, we are sure to have descriptor for standard view add to _store
			this._getSavedViews(dojo.hitch(this, "_buildViewMenu"));
			//
	        this._columnSetCells = dojo.clone(this._columnSet['cells']);
        	this._columnSetCells.sort();
        	this._viewSetCells = dojo.clone(this._viewSet['cells']);
        	this._viewSetCells.sort();
			var _columnSetLength = this._columnSetCells.length;
	        //  set up holder now that we have the correct length to apply to dimensions
	        var divideOn = 10;
			var holderN_width = 178;
			if(_columnSetLength > divideOn){
				holderN_width = Math.round(((_columnSetLength/divideOn)*170)+8);
			}
			// TODO: booger here. not rendering nicely in toolbar. addClass doesn't fix
			//        harry scrolldum bar shows up on dd-close... wth?
		    var holderN = new dijit.layout.ContentPane({style: "width:".concat(holderN_width).concat("; background:#fff; padding:4px; border:1px solid #7eabcd;")});
		    dojo.addClass(dojo.byId(holderN.domNode), '.dijitMenuItem');
		    dojo.addClass(dojo.byId(holderN.domNode), '.dijitReset');
		    this.ddButton = new dijit.form.DropDownButton({
	            label: "Columns:",
	            dropDown: holderN
	        });
		    dojo.style(this.ddButton.domNode, "float", "left");
		    this.ddButton.placeAt(this.columnsMenuHolder.domNode, "last");
	        // The cells implement toString by returning the field name.  We can sort cells now.
        	for(var i = 0; i < this._columnSetCells.length; i++){
    			if(this._viewSetLookup[String(this._columnSetCells[i].field)]){
    				this._columnSetCells[i].checkState = true;
    			}else{
    				this._columnSetCells[i].checkState = false;
    			}
        	}
	        //  Add check boxes, connect to show/hide columns
	        var makeNewContentPane = true;
	        var columnCP = {};
	        //
	        for(var i = 0; i < this._columnSetCells.length; i++){
	        	//  add column to holder
	        	if(makeNewContentPane == true){
	    	        columnCP = new dijit.layout.ContentPane({style:"float:left; width:160px"}).placeAt(dojo.byId(holderN.domNode), "last");
	    	        makeNewContentPane = false;
	        	}
	        	//  add checkbox row to colummn
	        	var checkboxCP = new dijit.layout.ContentPane({style:"float:left; clear:both; height:20px; width:160px"}).placeAt(dojo.byId(columnCP.domNode), "last");
				var checkState = (this._columnSetCells[i].checkState)?true:false;
				var checkField = this._columnSetCells[i].field;
				var visualLabel = this._columnSetCells[i].name;
				var cnm = checkField;
				var color = "#000000";
				var cb = new com.sixnet.services.widgets.LabeledCheckBox({
					name:cnm, 
					value: cnm, 
					checked: (checkState?true:false), 
					onChange: dojo.hitch(this, function(field, v){
						if(typeof(v) == 'undefined') return;
						//  set new column visibility here
						if(!this._busySynchingChecks){
							if(v == false){
								this.hideColumn(field);
							}else if(v == true){
								this.showColumn(field);
							}
						}
					}, checkField)
				});
				// add CheckBox to cp (content pane)
				this.columnsCheckBoxes.push(cb);
				cb.placeAt(checkboxCP.domNode);
		       	dojo.query(dojo.byId(checkboxCP.domNode)).addContent("<div style='float:left; clear:right; margin-left:5px;'>"+visualLabel+"</div>");
		       	if(i%divideOn == 0 && i != 0){
					makeNewContentPane = true;
				}
			}
		}catch(e){
			//console.log("error in _buildColumnsMenu", e);
		}
	},
	
	_syncColumnsChecks: function(){
		this._busySynchingChecks = true;
		for(var i = 0; i < this.columnsCheckBoxes.length; i++){
			if(this._viewSetLookup[this.columnsCheckBoxes[i].value]){
				this.columnsCheckBoxes[i].set('checked', true);
			}else{
				this.columnsCheckBoxes[i].set('checked', false);
			}
		}
		this._busySynchingChecks = false;
	},
	
	onViewMenuChange: function(){
		//console.log("onViewMenuChange _viewSelect value: ", this._viewSelect.get('value'));
		console.log(this._viewSelect);
		if(!this._storeBusy){
			var id = this._viewSelect.get('value');
			if(id != "0"){
				var item = this._store.fetch({
				query: {id: id},
				onComplete:dojo.hitch(this, function(data){
					//console.log('onComplete: ', data[0].view[0]);
					this._viewSet = {};
					this._viewSet.cells = dojo.fromJson(data[0].view[0]).cells;
					this.grid.applyNewDescriptor(this._viewSet);
					this._makeDescriptorLookups(dojo.clone(this._columnSet), dojo.clone(this._viewSet), dojo.hitch(this, "_syncColumnsChecks"));
				})});
			}
//TODO
//			dojo.byId(this._viewSelect).domNode.blur();
//			this._viewSelect.containerNode.blur();
			this._orderAltered = false;
			this._columnSizeAltered = false;
			this._viewSaved = true;
			this._unmarkViewChanged();
		}
	},
	
	_markViewChanged:function(){
		this._storeBusy = true;
		var id = this._viewSelect.get('value');
		if(!this._changeMarkedOn){
			var item = this._store.fetch({
				query: {id: id},
				onComplete:dojo.hitch(this, function(data){
					this._store.setValue(data[0], "original_name", data[0].name[0]);
					this._store.setValue(data[0], "name", "*  "+data[0].name[0]);
					//console.log('_markViewChanged data/_viewSelect: ', data[0], this._viewSelect);
					this._changeMarkedOn = id;
			})});
		}
		this._storeBusy = false;
	},
	
	_unmarkViewChanged: function(){
		this._storeBusy = true;
		var setToId = this._viewSelect.get('value');
		var id = this._changeMarkedOn;
		if(id){
			var item = this._store.fetch({
				query: {id: id},
				onComplete:dojo.hitch(this, function(data){
					this._store.setValue(data[0], "name", data[0].original_name[0]);
					this._changeMarkedOn = null;
			})});
		}
		this._storeBusy = false;
	},
	
	_refreshGridStructure: function(){		
		this.grid.applyNewDescriptor(this._viewSet);
	},
	
	hideColumn: function(field){
		if(this._viewSetLookup[field]){
			this._hideColumn = field;
			this._showHide = true;
			this._checkViewChanged();
		}
	},
	
	showColumn: function(field){
		if(!this._viewSetLookup[field]){
			this._showColumn = field;
			this._showHide = true;
			this._checkViewChanged();
		}
	},
	
	_checkViewChanged: function(){
		//  have we changed from saved or restored to saved?
		//
		var structure = this.grid.getGridStructure();
		//console.log("_checkViewChanged:  ", arguments);
		if(typeof(arguments[0]) == 'number'){
			//  altered through reorder or resize column(s)
			//console.log("seeing number");
			if(arguments.length > 1){
				//console.log("you have reordered the columns", structure);
				// create new _viewSetLookup
				this._currentOrder = [];
				for(var i = 0; i < structure.length; i++){
					this._currentOrder.push(structure[i].field);
				}
				var tempLookup = {};
				for(var i = 0; i < this._currentOrder.length; i++){
					tempLookup[this._currentOrder[i]] = this._viewSetLookup[this._currentOrder[i]];
				}
				this._viewSetLookup = {};
				//  use lookup to reorder _viewSet
				this._viewSetLookup = tempLookup;
				//  at this point we have to set the order aside
				//  for futher alterations of all sorts.
				this._orderAltered = true;
			}else{
				//  easy here; we have index
				var index = arguments[0];
				var field = structure[index].field;
				var newWidth = structure[index].unitWidth;
				this._viewSetLookup[field].width = newWidth;
				//console.log("you have resized a column == ", index, structure[index]);
				this._columnSizeAltered = true;
			}
		}else if(this._showHide){
			//  we have a show/hide event
			//  hide
			if(this._hideColumn){
				this._viewSetLookup[this._hideColumn] = null;
				delete this._viewSetLookup[this._hideColumn];
			}
			//  show
			if(this._showColumn){
				//  tack on the end
				this._viewSetLookup[this._showColumn] = this._columnSetLookup[this._showColumn];
			}
		}
		//  check if different from saved view; in the case we have reshown
		//  a hidden column
		if(this._showHide || this._orderAltered || this._columnSizeAltered){
			this._viewSet = {};
			this._viewSet.cells = [];
			for(var prop in this._viewSetLookup){
				this._viewSet.cells.push(this._viewSetLookup[prop]);
			}
			this._hideColumn = null;
			this._showColumn = null;
			this._showHide = false;
			this._viewSaved = false;
			this._orderAltered = false;
			//  correct _viewSet must be set before calling this
			if(this._columnSizeAltered){
				this._columnSizeAltered = false;
			}else{
				this._refreshGridStructure();
			}
		}else{
			this._viewSaved = true;
		}
		this._markViewChanged();
	}	
});

}

if(!dojo._hasResource['com.sixnet.services.modules.unit.migrateTools']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.unit.migrateTools'] = true;


//Attached is the original template for migrate config (SVM2)
//
//Please use it only as a reference for fields/values.  
//
//User  com.sixnet.services.modules.access.migrateTool as a model for your implementation of com.sixnet.services.modules.unit.migrateTools
//
//Build a widget that is able to send the form values and query to the server.
//
//Build a dummy function unit/migrate (module/function)
dojo.provide('com.sixnet.services.modules.unit.migrateTools');





















dojo.declare('com.sixnet.services.modules.unit.migrateTools', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div dojoAttachPoint=\"MIGRATE_TOOLS\">\n\t<div dojoType=\"com.sixnet.services.core.data.store\" jsId=\"unitStore\" dojoAttachPoint=\"unitStore\" identifier=\"id\" viewName=\"job_units\" module=\"access\" ></div>\n\t\n<div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\" style=\"background:#fff\">\n <div dojoType=\"dijit.layout.ContentPane\" region=\"top\"> \n <div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"help\" style=\"cursor:pointer; position:absolute; text-align:center; font-weight:bold; right:5px; top:5px; height:16px; width:auto; overflow:hidden; border:1px solid #fff; -moz-border-radius: 4px; border-radius: 4px; background:#000; color:#fff;\">&nbsp;info&nbsp;</div>\n <div class=\"headerLabel\">Migrate Units</div>\n\t<div dojoType=\"dijit.form.Form\" dojoAttachPoint=\"migrateToolsForm\" style=\"float:left; clear:both; width:100%;\">\n\t<div dojoType=\"dijit.layout.ContentPane\" style=\"border:1px solid #000; float:left; clear:left; padding:5px; margin:5px; width:270px\">\n\t\t<div>\n\t\t\t<div class=\"migrateLabelLeft\" style=\"font-weight:bold; padding-top:5px; width:80px\">Select Action</div>\n\t\t\t<select dojoType=\"dijit.form.Select\" style=\"width:13em\" dojoAttachEvent=\"onChange:onActionChange\" name=\"actionSelect\" dojoAttachPoint=\"actionSelect\">\n\t\t\t\t<option value=\"\" >nothing</option>\n\t\t\t\t<option value=\"Migrate\" >Migrate</option>\n\t\t\t\t<option value=\"Disable\" >Disable</option>\n\t\t\t\t<option value=\"Ignore\" >Ignore</option>\n\t\t\t\t<option value=\"StopIgnoring\" >Stop Ignoring</option>\n\t\t\t\t<option value=\"IgnoreUntilNextCheckin\" >Ignore until next checkin</option>\n\t\t\t\t<option value=\"Major\" >Change Major</option>\n\t\t\t\t<option value=\"Minor\" >Change Minor</option>\n\t\t\t\t<option value=\"Architecture\" >Set Architecture</option>\n\t\t\t\t<option value=\"ExportUnits\" >Export Units</option>\n\t\t\t</select>\n\t\t</div>\n\t</div>\n\t<div style=\"float:left; width:350px;\">\n\t\t<div class=\"migrateFullRow\">\n\t\t\t<div class=\"migrateLabelLeft\">SVM1</div>\n\t\t\t<div dojoType=\"dijit.form.CheckBox\" class=\"migrateFormCB\" dojoAttachPoint=\"SVM1Check\" inputControl=\"SVM1\">\n\t\t\t</div>\n\t\t\t<div dojoType=\"dijit.form.TextBox\" class=\"migrateFormTB\" disabled=\"disabled\" name=\"SVM1\" dojoAttachPoint=\"SVM1Text\" placeHolder=\"SVM1\">\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"migrateFullRow\">\n\t\t\t<div class=\"migrateLabelLeft\">SVM2</div>\n\t\t\t<div dojoType=\"dijit.form.CheckBox\" class=\"migrateFormCB\" dojoAttachPoint=\"SVM2Check\">\n\t\t\t</div>\n\t\t\t<div dojoType=\"dijit.form.TextBox\" class=\"migrateFormTB\" disabled=\"disabled\" name=\"SVM2\" dojoAttachPoint=\"SVM2Text\" placeHolder=\"SVM2\">\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"migrateFullRow\">\n\t\t<div class=\"migrateLabelLeft\">Server Mode</div>\n\t\t\t<div dojoType=\"dijit.form.CheckBox\" class=\"migrateFormCB\" dojoAttachPoint=\"serverModeCheck\">\n\t\t\t</div>\n\t\t\n\t\t\t<select dojoType=\"dijit.form.Select\" style=\"width:10em\" name=\"serverMode\" disabled=\"disabled\" dojoAttachPoint=\"serverModeSelect\">\n\t\t\t\t<option value=\"none\">none</option>\n\t\t\t\t<option value=\"secondary\">secondary</option>\n\t\t\t\t<option value=\"both\">both</option>\n\t\t\t\t<option value=\"error\">error</option>\n\t\t\t</select>\n\t\t</div>\n\t\t<div class=\"migrateFullRow\">\n\t\t\t<div class=\"migrateLabelLeft\">&nbsp;</div>\n\t\t\t<div dojoType=\"dijit.form.CheckBox\" class=\"migrateFormOptionCB\" name=\"ignoreUnits\" dojoAttachPoint=\"ignoreUnitsCheck\" disabled=\"disabled\">\n\t\t\t</div>Ignore Units\n\t\t</div>\n\t\t\t\t<div class=\"migrateFullRow\">\n\t\t<div class=\"migrateLabelLeft\">&nbsp;</div>\n\t\t\t<div dojoType=\"dijit.form.CheckBox\" class=\"migrateFormOptionCB\" name=\"disableSVM1\" dojoAttachPoint=\"disableSVM1Check\" disabled=\"disabled\">\n\t\t\t</div>Disable SVM1\n\t\t</div>\n\t\t<div class=\"migrateFullRow\">\n\t\t\t<div class=\"migrateLabelLeft\">&nbsp;</div>\n\t\t\t<div dojoType=\"dijit.form.CheckBox\" class=\"migrateFormOptionCB\" name=\"disableSVM2\" dojoAttachPoint=\"disableSVM2Check\" disabled=\"disabled\">\n\t\t\t</div>Disable SVM2\n\t\t</div>\n\t</div>\n\t<div style=\"float:left; width:350px;\">\n\t\t<div class=\"migrateFullRow\">\n\t\t\n\t\t<div class=\"migrateLabelLeft\">Major</div>\n\t\t\t<div dojoType=\"dijit.form.CheckBox\" class=\"migrateFormCB\" dojoAttachPoint=\"majorCheck\">\n\t\t\t</div>\n\t\t\t<div dojoType=\"dijit.form.TextBox\" class=\"migrateFormTB\" disabled=\"true\" name=\"major_name\" dojoAttachPoint=\"majorText\" placeHolder=\"Major\">\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"migrateFullRow\">\n\t\t\n\t\t<div class=\"migrateLabelLeft\">Minor</div>\n\t\t\t<div dojoType=\"dijit.form.CheckBox\" class=\"migrateFormCB\" dojoAttachPoint=\"minorCheck\">\n\t\t\t</div>\n\t\t\t<div dojoType=\"dijit.form.TextBox\" class=\"migrateFormTB\" disabled=\"true\" name=\"minor_name\" dojoAttachPoint=\"minorText\" placeHolder=\"minor\">\n\t\t\t</div>\n\t\t</div>\n\t\t<div class=\"migrateFullRow\">\n\t\t\n\t\t<div class=\"migrateLabelLeft\">Architecture</div>\n\t\t\t<div dojoType=\"dijit.form.CheckBox\" class=\"migrateFormCB\" dojoAttachPoint=\"architectureCheck\">\n\t\t\t</div>\n\t\t\t<select style=\"width:10em\" dojoType=\"dijit.form.Select\" name=\"architecture\" disabled=\"disabled\" dojoAttachPoint=\"architectureSelect\">\n\t\t\t\t<option value=\"X86\">x86</option>\n\t\t\t\t<option value=\"PPC\">ppc</option>\n\t\t\t\t<option value=\"ARM\">arm</option>\n\t\t\t</select>\n\t\t</div>\n\t\t<div class=\"migrateFullRow\">\n\t\t\t<div class=\"migrateLabelLeft\">&nbsp;</div>\n\t\t\t<div dojoType=\"dijit.form.CheckBox\" class=\"migrateFormOptionCB\" name=\"export\" dojoAttachPoint=\"exportCheck\" disabled=\"disabled\">\n\t\t\t</div>Export of entries (create a unit file list)\n\t\t</div>\n\t\t<div class=\"migrateFullRow\">\n\t\t\t<div class=\"migrateLabelLeft\">&nbsp;</div>\n\t\t\t<div dojoType=\"dijit.form.Button\" label=\"Apply\" dojoAttachEvent=\"onClick:buildMigrateObj\" dojoAttachPoint=\"runMigrateButton\" style=\"float:right;\">\n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t</div>\n</div>\n\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" >\n  \t\t<div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\" style=\"height:100%\" dojoAttachPoint=\"jobUnitContainer\"  >\n\t    \t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" >\n\t    \t\t<div dojoType=\"dijit.layout.TabContainer\" dojoAttachPoint=\"unitGridTC\" style=\"width: 100%; height: 100%;\">\n\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" title=\"Existing\" selected=\"true\" dojoAttachPoint=\"existingTab\">\n\t\t\t\t\t\t<div\tdojoType=\"com.sixnet.services.widgets.sixnetGrid\"  \n\t\t\t\t\t\t\t\tjsid=\"unitGrid\" \n\t\t\t\t\t\t\t\tformatterClass=\"com.sixnet.services.modules.unit.formatters\" \n\t\t\t\t\t\t\t\tstore=\"unitStore\" \n\t\t\t\t\t\t\t\tcolumnReordering=\"false\"\n\t\t\t\t\t\t\t\tmodule=\"access\" \n\t\t\t\t\t\t\t\tviewName=\"units\" \n\t\t\t\t\t\t\t\tshowSaveView=\"true\"\t\n\t\t\t\t\t\t\t\tshowContextMenu=\"true\" \n\t\t\t\t\t\t\t\tdojoAttachPoint=\"unitGrid\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\t\n\t\t\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridCheckSearch\"\n\t\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t\tdojoAttachPoint=\"gridCheckSearch\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</div><!--\n\t\t\t\t\t\t<div\t\n\t\t\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridView\"\n\t\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t--><div\t\n\t\t\t\t\t\t\tdojoType=\"com.sixnet.services.modules.unit.searchCheckBox\"\n\t\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t\tfieldName=\"authorized\"\n\t\t\t\t\t\t\tfieldLabel=\"Authorized\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" title=\"Verify\" dojoAttachPoint=\"verifyTab\">\n\t\t\t\t\t\t<div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\" >\n\t\t\t\t\t\t\t<div dojoType=\"dijit.Toolbar\" region=\"top\" dojoAttachPoint=\"verifyToolbar\"  style=\"overflow:hidden; height:28px\">\n\t\t\t\t\t\t\t\t<div dojoType=\"dijit.form.CheckBox\" dojoAttachPoint=\"userVerifyCheck\" style=\"margin-top:.5em; margin-left:.5em;\"></div>\n\t\t\t\t\t\t\t\t<div dojoType=\"dijit.form.Button\" style=\"margin-top:.5em; font-weight:bold; font-color:green\" dojoAttachPoint=\"userVerifyButton\" dojoAttachEvent=\"onClick:onUserVerifyData\" label=\"Verify/Confirm Changes\">\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<span style=\"font-variant:italic; margin-top:.5em; margin-left:.5em;\">&nbsp;(check and click button to verify)</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" >\n\t\t\t\t\t\t\t\t<div dojoType=\"dojox.grid.DataGrid\" loadingMessage=\"...data loading\"  dojoAttachPoint=\"verifyGrid\">\n\t\t\t\t\t\t\t\t</div> \n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	targetType: 'unit',
	resultSize: 0,
	action: null,
	gridQuery: null,
	appParams: null,
	icon: 'migrateTools.png',
	iconPath: '',
	_queryHandle: null,
//	migrateObj: null,
	verifyStore: null,
	verifyDataReady: null,
	currentChange: null,
	currentChangeTo: null,
	exportUnits: null,
	
	postCreate: function(){
		this.inherited(arguments);
		//  have grid hold off, build desired layout, pass it in
		this.unitGrid.setHoldOff(true);
		this.connect(this.unitGrid, "onViewDescriptorLoaded", "_doGridLayout");
		this.exportUnits = false;
		this.verifyDataReady = false;
		var action = '';
		var text = '<div><p>This page will ignore, disable or migrate a group of units.</p><p>Use the grid to define target (unit id, major, minor). Then specify action.</p><ul><li>Ignore (Group) - Remote units will continue to check into this SVM but this unit will not appear in current status. </li><li>Ignore (Group) until checkin - Do not display this/these unit(s) in current status until it checks in again</li><li>Disabled - Units will no longer check into any SVM.</li><li>Migrate - Units will be pointed to a new SVM and will no longer check into this SVM.</li></ul><p>NOTE: All options will make the units no longer show up in unit status. Unit history will be preserved for these units on this SVM.	If you would also like to clear the unit history, you must deauthorize the units to accomplish this.</p></div>';
    	var tt = new dijit.Tooltip({
    		connectId:[dojo.byId(this.help.domNode)],
    		label:text,
    		position:["below"]
    	});//.placeAt(dojo.byId(this.helpHolder.domNode), "last");
		this.serverModeSelect.set("forceWidth", true);
		this.architectureSelect.set("forceWidth", true);
		this.actionSelect.set("forceWidth", true);
		var this_migrateTools = this;
		dojo.forEach(dojo.query(".migrateFormCB", dojo.byId(this.migrateToolsForm).domNode), 
			function(n){
				dijit.getEnclosingWidget(n).set('disabled', true);
				dojo.connect(dijit.getEnclosingWidget(n), "onChange", function(v) {
					var textLabel = ""+(this.dojoAttachPoint.split("Check")[0])+"Text";
					var selectLabel = ""+(this.dojoAttachPoint.split("Check")[0])+"Select";
					if(v == true){
						if(this_migrateTools[textLabel]){							
							this_migrateTools[textLabel].set('disabled', false);
							this_migrateTools[textLabel].focus();
						}else if(this_migrateTools[selectLabel]){
							this_migrateTools[selectLabel].set('disabled', false);
						}
						// now rebuild form JSON
//						this_migrateTools.buildMigrateObj();
					}else if(v == false){
						if(this_migrateTools[textLabel]){
							this_migrateTools[textLabel].set('disabled', 'disabled');
							if(this_migrateTools[textLabel].get('placeHolder')){
								//  put placeHolder text back via setting value to empty
								this_migrateTools[textLabel].set('value', '');
							}
						}else if(this_migrateTools[selectLabel]){
							this_migrateTools[selectLabel].set('disabled', 'disabled');
						}
						// rebuild JSON
//						this_migrateTools.buildMigrateObj();
					}
             	});
			}
		);
	},
	
	_doGridLayout: function(){
		//TODO
		var view = this.unitGrid.getDescriptor();
		console.log("descriptore original: ", dojo.clone(view));
		//  defaultCells is default viewable layout
		var defaultCells = dojo.clone(view.cells);
		//  allCells will have hiddens set to false
		var allCells = dojo.clone(view.all_cells);
		var turnOff = {interfaces:"interfaces", alert_desc:"alert_desc", cell_lightbar_signal:"cell_lightbar_signal"};
		var turnOn = {client_config:"client_config", architecture:"architecture"};
		// create look up
		var fullSetLookup = {};
		var defaultCellsLookup = {};
		for(var i = 0; i < allCells.length; i++){
			fullSetLookup[allCells[i].field] = dojo.clone(allCells[i]);
		}
		for(var i = 0; i < defaultCells.length; i++){
			defaultCellsLookup[defaultCells[i].field] = dojo.clone(defaultCells[i]);
		}
		for(var prop in turnOff){
			if(defaultCellsLookup[prop]){
				delete defaultCellsLookup[prop];
			}
		}
		for(var prop in turnOn){
			if(!defaultCellsLookup[prop]){
				defaultCellsLookup[prop] = fullSetLookup[prop];
			}
		}
		var viewSet = {};
		viewSet.cells = [];
		//TODO
		for(var prop in defaultCellsLookup){
			viewSet.cells.push(dojo.clone(defaultCellsLookup[prop]));
		}
		this.unitGrid.applyNewDescriptor(viewSet);
	},
	
	onActionChange: function(v){
		console.log(v, arguments);
		this.unitGrid.setHoldOff(false);
		dojo.forEach(dojo.query(".migrateFormCB", dojo.byId(this.migrateToolsForm).domNode), 
			function(n){
				if(dijit.getEnclosingWidget(n).get('checked')){
						dijit.getEnclosingWidget(n).set('checked', false);
				}
			}
		);
		dojo.forEach(dojo.query(".migrateFormOptionCB", dojo.byId(this.migrateToolsForm).domNode), 
				function(n){
					dijit.getEnclosingWidget(n).set('disabled', true);
					if(dijit.getEnclosingWidget(n).get('checked')){
							dijit.getEnclosingWidget(n).set('checked', false);
					}
				}
			);
		this.exportCheck.set('disabled', false);
		var query = false;
		switch(v){
			case "Migrate":
				this.SVM2Check.set('checked', true);
				this.serverModeCheck.set('checked', true);
				this.ignoreUnitsCheck.set('checked', true);
				this.ignoreUnitsCheck.set('disabled', false);
				this.SVM1Check.set('checked', true);
				break;
			case "Disable":
				this.disableSVM1Check.set('disabled', false);
				this.disableSVM2Check.set('disabled', false);
				break;
			case "Ignore":
				query = ({
					left_field: 'view_mode',
					operator: '<>',
					right_value: 'IGNORE'
				});
				break;
			case "IgnoreUntilNextCheckin":
				query = ({
					left_field: 'view_mode',
					operator: '<>',
					right_value: 'IGNORE_UNTIL_CHECKIN'
				});
				break;
			case 'StopIgnoring':
				query = ({
					left_field: 'view_mode',
					operator: '<>',
					right_value: 'NORMAL'
				});
				break;
			case "Major":
				this.majorCheck.set('checked', true);
				break;
			case "Minor":
				this.minorCheck.set('checked', true);
				break;
			case "UnitId":
				this.unitIdCheck.set('checked', true);
				break;
			case "ExportUnits":
				this.exportCheck.set('checked', true);
				this.exportCheck.set('disabled', true);
				break;
			case "Architecture":
				this.architectureCheck.set('checked', true);
				break;
			default:
				break;
		}
		// TODO make filtering of view_mode options happen
		this.unitGrid.queryLock(dojo.hitch(this, function(query){
			if(this._queryHandle){
				this._queryHandle.releaseQuery();
				this._queryHandle = false;
			}
			if(query){
				this._queryHandle = this.unitGrid.makeQueryHandle();
				this._queryHandle.setQuery(query);
			}
		}, query), dojo.hitch(this, function(){}));
	},
	
	buildMigrateObj: function(){
		var layout = [
                      { field: "serial", name: "Serial", width: "120px", editable:false },
                      { field: "unit_id", name: "Unit Id", width: "130px", editable:false }
        ];
		var formValues = this.migrateToolsForm.getValues();
		var unitGridQuery = this.unitGrid.getQuery();
		formValues.query = unitGridQuery;
		if(formValues['export']){
			if(formValues['export'][0] == "on"){
				this.exportUnits = true;
			}else{
				console.log("export not set, kill it...");
				delete formValues['export'];
			}
		}
		console.log("formValues:  ", formValues);
		var toChange ;
		var newClientConfig ;
		var viewMode ;
		var disable = false;
		var disableSVM1 = false;
		var disableSVM2 = false;
		var exportOnly = false;
		//
		switch(formValues.actionSelect){
			case 'Migrate':
				// build migrate object here
				var servers = [];
				servers.push({"ip":formValues.SVM1,"type":"primary"});
				servers.push({"ip":formValues.SVM2,"type":"secondary"});
				newClientConfig = {servers:servers, "server_mode":formValues.serverMode};
				viewMode = (formValues.ignoreUnits.length > 0)?'IGNORE':'NORMAL';
				toChange = 'client_config';
				break;
			case 'Disable':
				disable = true;
				var servers = [];
				if(formValues.disableSVM1.length > 0){
					// disable SVM1
					servers.push({"ip":"127.0.0.1","type":"primary"});
					disableSVM1 = true;
				}
				if(formValues.disableSVM2.length > 0){
					// disable SVM2
					servers.push({"ip":"127.0.0.1","type":"secondary"});
					disableSVM2 = true;
				}
				newClientConfig = {servers:servers};
				toChange = 'client_config';
				break;
			case 'Ignore':
				toChange = 'view_mode';
				viewMode = 'IGNORE';
				break;
			case 'IgnoreUntilNextCheckin':
				toChange = 'view_mode';
				viewMode = 'IGNORE_UNTIL_CHECKIN';
				break;
			case 'StopIgnoring':
				toChange = 'view_mode';
				viewMode = 'NORMAL';
				break;
			case 'Major':
				toChange = 'major_name';
				break;
			case 'Minor':
				toChange = 'minor_name';
				break;
			case 'UnitId':
				toChange = 'unit_id';
				break;
			case 'Architecture':
				toChange = 'architecture';
				break;
			case 'ExportUnits':
				this.exportUnits = true;
				exportOnly = true;
				break;
			case '':
				console.log("no action selected");
				return false;
		}
		//
		console.log('toChange', toChange, formValues);
		var this_migrateTools = this;
		//
		var buildInChanges = function(data){
			console.log("buildInChanges data:  ", data, " num items: ",data.length);
			if(data.length == 0) return false;
			var newData = [];
			var newValue = (formValues[toChange])?formValues[toChange]:(toChange == 'view_mode')?viewMode:null;
console.log(newValue, "  <<< newValue");
			dojo.forEach(data, function(item){
				console.log("ITEM SERIAL:  ", item);
				var newItem = {};
				newItem.id = item.id;
				newItem.serial = item.serial;
				newItem.unit_id = item.unit_id;
				if(toChange == 'client_config' && !disable){
					var client_config = dojo.fromJson(item.client_config);
					var temp = dojo.clone(newClientConfig);
					temp.interval = client_config.interval;
					newValue = dojo.toJson(temp);
				}else if(toChange == 'client_config' && disable){
					//  put back any non-disabled
					var client_config = dojo.fromJson(item.client_config);
					var temp = dojo.clone(newClientConfig);
					if(disableSVM1 && disableSVM2){
						temp.server_mode = 'IGNORE';
					}else if(disableSVM1 || disableSVM2){
						temp.server_mode = client_config.server_mode;
						if(!disableSVM1){
							temp.servers.push(client_config.servers[0]);
						}
						if(!disableSVM2){
							temp.servers.push(client_config.servers[1]);
						}
					}
					temp.interval = client_config.interval;
					newValue = dojo.toJson(temp);
				}
				// generic for now, just make major work
				if(newValue){
					var oldValue = item[toChange];
					newItem.changeFrom = oldValue;
					newItem[toChange] = newValue;
				}
				if(viewMode){
					newItem.view_mode = viewMode;
				}
				newData.push(newItem);
			});
			console.log("newData:  ", newData);
			this_migrateTools.verifyStore = new dojo.data.ItemFileReadStore({data:{identifier: "id", label:"id", items:newData}});
			if(toChange == 'client_config'){
				function formatClientConfig(value){
					var client_configPane = new dijit.layout.ContentPane();
						try{
							console.log(value, "  << formatClientConfig");
							var client_configList = dojo.fromJson(value);
							var output = 'Servers:<br />';
							dojo.forEach(client_configList.servers, function(server){
									if(server.type == 'primary'){
										output += 'SVM1: '.concat(server.ip).concat('<br />');
									}else{
										output += 'SVM2: '.concat(server.ip).concat('<br />');
									}
							});
							output += 'MODE: '.concat(client_configList.server_mode).concat('<br />');
							output += 'Interval @ '.concat(client_configList.interval).concat(' seconds <br />');
							client_configPane.setContent(output);
						}catch(e){
							console.log('client_config formatter error: ', e);
						}
					return client_configPane;
				}
				layout.push({ field: toChange, name: "Change TO: "+formValues.actionSelect, width: "200px", editable:false, formatter:formatClientConfig });
                layout.push({ field: "changeFrom", name: "Change FROM: "+formValues.actionSelect, width: "200px", editable:false, formatter:formatClientConfig });
			}else{
				layout.push({ field: toChange, name: "Change TO: "+formValues.actionSelect, width: "300px", editable:false });
                layout.push({ field: "changeFrom", name: "Change FROM: "+formValues.actionSelect, width: "300px", editable:false });
			}
			//
			this_migrateTools.currentChange = toChange;
			this_migrateTools.currentChangeTo = newValue;
			this_migrateTools.verifyGrid.set('structure', layout);
			this_migrateTools.verifyGrid.setStore(this_migrateTools.verifyStore, {}, {});
			this_migrateTools.verifyDataReady = true;
			console.log("Change me:  ", this_migrateTools.verifyStore);
			dijit.byId(this_migrateTools.unitGridTC).selectChild(dojo.byId(this_migrateTools.verifyTab));
		};
		// TODO pick apart unitGridQuery to somehow ONLY return serial, id, and unit_id
		//   this is very important as it will hugely limit the return data....
		this.unitStore.fetch({query:unitGridQuery, onComplete:(!exportOnly)?buildInChanges:dojo.hitch(this, "doExportUnits")});
	},
	
	reportSuccess: function(){
		console.log('report success');
		// flip back to existing grid and run query against change to value
		this.unitGrid.queryLock( dojo.hitch(this, function(){
			this.userVerifyCheck.set('checked', false);
			dijit.byId(this.unitGridTC).selectChild(dojo.byId(this.existingTab));
	//		this.gridCheckSearch.searchValue.set('value', this.currentChangeTo);
			this.verifyDataReady = false;
			this.verifyStore = new dojo.data.ItemFileReadStore({data:{identifier: "id", label:"id", items:[]}});
			this.verifyGrid.setStore(this.verifyStore, {}, {});
			//  apply search term (assuming nothing has changed in Search In)
			
			// onActionChange does not fire before the end of this function.
			// use the holdOff feature of the grid to prevent updates until it fires.
			this.unitGrid.setHoldOff(true);
			this.actionSelect.set('value', '');
			//this.gridCheckSearch.onApplyButtonClick();
		}), dojo.hitch(this, function(){}));
		// TODO clear verify table/layout/store....
	},
	
	onUserVerifyData: function(){
		if(!this.verifyDataReady) return false;
		if(!this.userVerifyCheck.get('checked')) return false;
		var this_migrateTools = this;
		var updateViewData = function(data){
			console.log('updateViewData', data);
			var newData = [];
			dojo.forEach(data, function(item){
				var newItem = {};
				for(index in item){
					if(!item.hasOwnProperty(index)) continue;
					if(index == '_S') continue;
					if(index == '_0') continue;
					if(index == '_RI') continue;
					newItem[index] = item[index][0];
				}
				newData.push(newItem);
			});
				_sixnet_framework.bc('access', 'updateViewData', { viewName: 'units', items:newData}, dojo.hitch(this, function(){
					if(this_migrateTools.exportUnits){
						this_migrateTools.doExportUnits(newData);
					}
					_sixnet_framework.log(1, 'success', arguments);
					this_migrateTools.reportSuccess();
			}), dojo.hitch(this, function(){
				_sixnet_framework.log(1, 'failish', arguments);
			}));
		};
		this.verifyStore.fetch({onComplete:updateViewData});
	},
	
	doExportUnits: function(unitData){
		//  TODO: Export CSV
		if(!this.exportUnits) return false;
		this.exportUnits = false;
		console.log("doExportUnits:  ", unitData);
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.unit.migrateToolsDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.unit.migrateToolsDash'] = true;
dojo.provide('com.sixnet.services.modules.unit.migrateToolsDash');




dojo.declare('com.sixnet.services.modules.unit.migrateToolsDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.unit',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/migrateToolsDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){
		this.dashBoard.runApp( 'com.sixnet.services.modules.unit.migrateTools');		
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource["com.sixnet.services.modules.access.newChangePass"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.modules.access.newChangePass"] = true;
dojo.provide("com.sixnet.services.modules.access.newChangePass");


//dojo.declare("com.sixnet.services.modules.access.PasswordForm", [dijit._Widget, dijit._Templated],{
dojo.declare("com.sixnet.services.modules.access.PasswordForm", [dijit.form._FormValueWidget],{
	widgetsInTemplate: true,
	templateString:"<div>\n\tNew Password <input tabIndex=\"1\" dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"firstPassword,textbox,focusNode\"></input><br/>\n\tPassword again <input tabIndex=\"2\" dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"secondPassword\"></input>\n</div>\n",
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.connect(this.focusNode, "onKeyDown", "_onFocusKeyDown");
	},
	_onFirstPasswordKeyDown: function(e){
		_sixnet_framework.log(3, 'keydown', arguments);
		if(e.keyCode == dojo.keys.TAB && !(e.ctrlKey || e.altKey || e.metaKey)){
			e.preventDefault(); // default behavior needs to be stopped here since keypress is too late
			e.cancelBubble = true;
			this.secondPassword.focus();
		}
	},
	_onFirstPasswordKeyDown: function(e){
		_sixnet_framework.log(3, 'keydown', arguments);
		if(e.keyCode == dojo.keys.TAB && !(e.ctrlKey || e.altKey || e.metaKey)){
			e.preventDefault(); // default behavior needs to be stopped here since keypress is too late
			e.cancelBubble = true;
			this.secondPassword.focus();
		}
	},
	focus:function(){
		this.firstPassword.focus();
	},
	getValue: function(){
		return 'pass';
	}
});

dojo.declare("com.sixnet.services.modules.access.newChangePass", dojox.grid.cells._Widget, {
	widgetClass: com.sixnet.services.modules.access.PasswordForm,
	getWidgetProps: function(inDatum){
		return dojo.mixin({}, this.widgetProps||{}, {
			value: inDatum
		});
	}
});

com.sixnet.services.modules.access.newChangePass.markupFactory = function(node, cell){
	dojox.grid.cells._Widget.markupFactory(node, cell);
};

}

if(!dojo._hasResource['com.sixnet.services.modules.access.alertDefinitionsDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.alertDefinitionsDash'] = true;
dojo.provide('com.sixnet.services.modules.access.alertDefinitionsDash');




dojo.declare('com.sixnet.services.modules.access.alertDefinitionsDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/alertDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.alertDefinitions');		
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource["com.sixnet.services.modules.access.HintButton"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.modules.access.HintButton"] = true;
dojo.provide("com.sixnet.services.modules.access.HintButton");


dojo.declare("com.sixnet.services.modules.access.HintButton", [dijit.form.Button],{
	hint:'',
	_limitUserMode:false,
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.connect(this, "onMouseOver", dojo.hitch( this, function(hint, event){
			dojo.publish('/status/hint', [hint]);
		}, this.hint));
		this.connect(this, "onMouseLeave", dojo.hitch( this, function(){
			dojo.publish('/status/hint', ['']);
		}));
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.loginManager']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.loginManager'] = true;











dojo.provide('com.sixnet.services.modules.access.loginManager');
dojo.declare('com.sixnet.services.modules.access.loginManager', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">\n\n\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" gutters=\"false\" dojoAttachPoint=\"loginHolderHolder\">\t\t\n\t\t\t\n\t\t\t\t<div dojoType=\"dijit.form.Form\" dojoAttachPoint=\"loginForm\" style=\"padding:10px; font-family:Myriad,Helvetica,Tahoma,Arial,clean,sans-serif; font-weight:bold; float:left; width:25em; max-width:25em; height:150px; margin-left:43px; margin-top:45px; vertical-align:center\">\n\t\t\t\t\t<div style=\"width:100%; text-align:right; padding-bottom:.5em; height:auto; clear:both; float:right;\">\n\t\t\t\t\t<span style=\"float:right; clear:none; width:12em;\"><input style=\"float:right; width:12em;\" type=\"text\" dojoType=\"dijit.form.TextBox\" name=\"username\" dojoAttachPoint=\"usernameTextBox\" /></span>\n\t\t\t\t\t<span style=\"float:right; clear:none; width:auto; text-align:right;\">Username&nbsp;&nbsp;</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"width:100%; text-align:right; padding-bottom:.5em; height:auto; clear:both; float:right;\">\n\t\t\t\t\t<span style=\"float:right; clear:none; width:12em;\"><input style=\"float:right; width:12em;\" type=\"password\" dojoType=\"dijit.form.TextBox\" name=\"password\" dojoAttachPoint=\"passwordTextBox\" /></span>\n\t\t\t\t\t<span style=\"float:right; clear:none; width:auto; text-align:right;\">Password&nbsp;&nbsp;</span>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div style=\"float:right; clear:both; margin:.5em; color:#000\" dojoType=\"dijit.form.Button\" dojoAttachPoint=\"loginButton\" dojoAttachEvent=\"onClick: onLoginClick\" >Login</div>\n\t\t\t\t\t<div style=\"float:right; width:100%; height:auto; text-align:right; clear:both; margin:.5em; cursor:help;\" dojoType=\"dijit.layout.ContentPane\" dojoAttachEvent=\"onClick: onForgotClick\" dojoAttachPoint=\"forgotLink\">Forgot username/password?</div>\n\t\t\t\t\t\n\t\t\t\t</div>\n\t\t</div>\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" editRole=\"ROLE_USER_ADMIN\" viewRole=\"ROLE_USER_VIEWER\" style=\"width:100%; margin-left:3px; padding-top:2px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	forgotLoginFormDialog:{},
	beenClicked:false,
	icon: 'padlock.png',
	iconPath: '',
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		if(_sixnet_framework.noLogin){
			this.domNode.innerHTML = 'Sixview Manager is down for maintenance.';
			return;
		}

		this.onLoadCheck();
		//  Add ENTER-active to form
		dojo.connect(dojo.byId(this.loginForm.domNode), 'onkeypress', this, function(e) {
			// 13 is ENTER
			if(e.charOrCode == 13){
				this.onLoginClick();
			}
		});
	},
	
	onHide: function(widget){
		_sixnet_framework.log(1, "login onHide fired");
	},
	
	onShow: function(){
		//dojo.byId(this.usernameTextBox.domNode).focus();
		if( _sixnet_framework.autoLogin) return;
		_sixnet_framework.log(3, "onshow");
		this.usernameTextBox.focus();
	},
	
	buildWidgetThumbnailPane: function(){
		return false;
	},
	
	onLoginClick: function(){
		_sixnet_framework.log(1, "  loginManager.js-> onLoginClick ");
		if(this.beenClicked == true) return;
		this.beenClicked = true;
		dojo.addClass(this.loginButton.domNode, 'disabledButton');
		_sixnet_framework.bc('access','login', this.loginForm.getValues(), dojo.hitch(this, function(response){
			// On Login without errors (but bad user/pass possible)
			if( response.successful){
				 var loginInfo = response.data;
				_sixnet_framework.setUserId(loginInfo.userId);
				if(loginInfo.success){
					// ["super"] is 'super' - fix for IE requires no keyword usage.
		   			_sixnet_framework.setSuper(response.data["super"]);
					_sixnet_framework.setSession(loginInfo.sessionToken);
					_sixnet_framework.setUserId(loginInfo.userId);
					_sixnet_framework.alertColorCSS();
					this.dashBoard.runApp( 'com.sixnet.services.modules.access.changeAccount');
	   				this.unload();
				}else{
					alert('Bad username or password, please try again.');
					//  failed, so set clicked indicator back to false
					this.beenClicked = false;
				}
			}else{
				alert(response.error);
				this.beenClicked = false;
			}
		}), dojo.hitch(this, function(response){
			// Error at server level... bc(,,,errback)
			_sixnet_framework.log(3, 'Server Error:',response);
		}));
	},
	
	onLoadCheck: function(){		
		if(_sixnet_framework.autoLogin){
		     //  handleAs defaults to text
			// TEST NOTE:  SUPER - admin/admin, limited role test: hellothere/hellothere
			 _sixnet_framework.bc('access','login', {"username":"admin", "password":"admin"}, dojo.hitch(this, function(response){
				 if( response.successful){
					 var loginInfo = response.data;
					 _sixnet_framework.setUserId(loginInfo.userId);
					 if(loginInfo.success){
						// ["super"] is 'super' - fix for IE requires no keyword usage.
				   		_sixnet_framework.setSuper(response.data["super"]);
		   				_sixnet_framework.setSession(loginInfo.sessionToken);
		   				_sixnet_framework.setUserId(loginInfo.userId);
		   				_sixnet_framework.alertColorCSS();
		   				_sixnet_framework.getGoogleKey();	
		   				this.dashBoard.runApp( 'com.sixnet.services.modules.access.changeAccount');
		   				this.unload();
					 }
				 }else{
					 alert('The server is not active.');
				 }
			}));
		}
	},
	
	onForgotClick: function(){
		this.forgotLoginFormDialog = {};
		// create an instance of Dialog with the content (loaded from href), id and title.
		this.forgotLoginFormDialog = new dijit.Dialog({loginManager: this, style:"width:310px;height:135px;", id:"forgotLoginFormDialog", title:'Login Look-up', href: this.templateUrl.concat('forgotLoginDialog.html'), onLoad: function(){
			// this method fires when the dialog has finished loading its content.
			this.connect(this, "onCancel", function(){
				// this is for the 'x' button built into the Dialog.
				this.hide();
				this.destroyRecursive();
			});
		}});
		this.forgotLoginFormDialog.show();
		_sixnet_framework.log(1, this.forgotLoginFormDialog, " forgotLoginFormDialog");
	}
});

}

if(!dojo._hasResource["com.sixnet.services.modules.access.toolbarAddButton"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.modules.access.toolbarAddButton"] = true;
dojo.provide("com.sixnet.services.modules.access.toolbarAddButton");



dojo.declare("com.sixnet.services.modules.access.toolbarAddButton",[dijit._Widget, dijit._Templated],{
	widgetsInTemplate: true,
	templateString: dojo.cache("com.sixnet.services.modules.access", "templates/toolbarAddButton.html", "<div style=\"float:right; width:150px; margin-top:.5em\">\n\t\t<div\n\t\t\tstyle=\"float:right\"\n\t\t\tdojoType=\"dijit.form.Button\"\n\t\t\tdojoAttachPoint=\"addButton\" >\n\t\t</div>\n</div>\n"),
	grid: null,

	postCreate: function(){
		// move this widget to the toolbar
		this.grid.addToToolbar(this, 'right');
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.userManager']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.userManager'] = true;
dojo.provide('com.sixnet.services.modules.access.userManager');















//


//dojo.require('com.sixnet.services.widgets.dndQueryBuilder');
dojo.declare('com.sixnet.services.modules.access.userManager', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div dojoType=\"com.sixnet.services.core.data.writeStore\"  style=\"display:hidden\" jsid=\"userStore\" mode=\"LIKE\" identifier=\"id\" module=\"access\" viewName=\"users\"></div>\n\t\n\t <div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\" >\n\t \t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\"> \n\t    \t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:100%; margin:auto\" gutters=\"false\">\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" >\n\t\t\t\t\t<div\tdojoType=\"com.sixnet.services.widgets.sixnetGrid\"\n\t\t\t\t\t\t\tjsid=\"userGrid\" \n\t\t\t\t\t\t\tquery=\"{}\" \n\t\t\t\t\t\t\tformatterClass=\"com.sixnet.services.modules.access.formatters\" \n\t\t\t\t\t\t\tstore=\"userStore\" \n\t\t\t\t\t\t\tmodule=\"access\" \n\t\t\t\t\t\t\tviewName=\"users\" \n\t\t\t\t\t\t\tshowSaveView=\"true\"\t\n\t\t\t\t\t\t\tshowContextMenu=\"true\" \n\t\t\t\t\t\t\tdojoAttachPoint=\"userGrid\"\n\t\t\t\t\t\t\tclass=\"gridIE\">\n\t\t\t\t\t\t\n\t\t\t\t\t</div>\n\t\t\t\t\t<div\t\n\t\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridCheckSearch\"\n\t\t\t\t\t\tgrid=\"userGrid\"\n\t\t\t\t\t\t>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div\t\n\t\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridView\"\n\t\t\t\t\t\tgrid=\"userGrid\"\n\t\t\t\t\t\t>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div\t\n\t\t\t\t\t\tdojoType=\"com.sixnet.services.modules.access.toolbarAddButton\"\n\t\t\t\t\t\tgrid=\"userGrid\"\n\t\t\t\t\t\tdojoAttachPoint=\"addUser\"\n\t\t\t\t\t\t>\n\t\t\t\t\t</div>\n\t\t\t\t\n\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none;\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	currentUser:false,
	user:false, /*user is rowItem*/
	icon: 'ppls.png',
	iconPath: '',
	_viewOnly:true,
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.currentUser = _sixnet_framework._userId;
		///////////this.userAdvancedToolbar.grid = this.userGrid;
		// TODO: Connects get abstracted from the actual grid to the SixnetGrid
		// TODO: REVISIT WITH PAUL THE TOOLBAR CONNECTS 
		// connex
		var roles = _sixnet_framework._currentPermissions;
		var admin ;
		if(roles.access){
			admin = roles.access['ROLE_USER_ADMIN'];
		}
		if(admin || _sixnet_framework._super){
			this.addUser.addButton.set("label", "Add User");
			this.connect(this.addUser.addButton, "onClick", "onAddUserClick");
			this._viewOnly = false;
		}else{
			this.addUser.destroyRecursive();
		}
		this.connect( this.userGrid.getFormatter(), "onFormatUsername", "onFormatUsername");
//		this.connect(this.userToolbar.removeButton, "onClick", "onRemoveClick");
//		this.connect(this.userGrid.grid,"onClick", "onUserRowClick");
//		this.connect(this.userGrid.grid,"onDblClick", "onUserRowDblClick");
//		this._subscribes.push( dojo.subscribe( '/status/hint', dojo.hitch(this.statusLine, "setContent")));
//		this.connect(this.userGrid.store, "onSet", dojo.hitch(this, function(item, attr, oldVal, newVal){
//				if(newVal != oldVal){
//					this.userToolbar.needsSaved = true;
//					this.userToolbar.unhideSaveRevertButton();
//				}
//	        })
//	    );
//		dojo.connect(dojo.dnd.manager(), "ondragstart", dojo.hitch(this, "startDrag"));
		dojo.subscribe("/dnd/start", function(source,nodes,iscopy){
			  //code to perform some action	
			console.log(source,nodes,iscopy);
		});

	},
	
	startDrag: function(source, nodes, copy){
		_sixnet_framework.log(1, "startDrag", arguments);
	},
	
	onFormatUsername: function(item, usernamePane){
		if(!this._viewOnly){
			var E = "<img title='edit' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/E.gif\" />");
			var editCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; cursor:pointer;', content:E, onClick: dojo.hitch(this, function(item){
				//_sixnet_framework.getDash().runApp( 'com.sixnet.services.modules.access.unitDetail', {item:item, background: false});
				this.onEditUserClick(item);
			}, item)});
			editCP.placeAt(usernamePane.domNode, "last");
			//
			var R = "<img title='edit roles' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/R.gif\" />");
			var rolesCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; margin-left:2px; cursor:pointer;', content:R, onClick: dojo.hitch(this, function(item){
				this.openRolesDialog(item);
			}, item)});
			rolesCP.placeAt(usernamePane.domNode, "last");
		}
	},
	
	onEditUserClick: function(item){
		console.log("Edit me:  ", item);
		// create an instance of Dialog with the content (loaded from href), id and title.
		var editUserFormDialog = new dijit.Dialog({userManager: this, 
			style:"width:310px;height:185px;", 
			id:"editUserFormDialog", 
			title:'Edit User:  '.concat(item.username), 
			href: this.templateUrl.concat('editUser.html'),
			onLoad: function(){
				//  set values
				dijit.getEnclosingWidget(document.getElementById('id')).set('value', item.id);
				dijit.getEnclosingWidget(document.getElementById('email')).set('value', item.email);
				dijit.getEnclosingWidget(document.getElementById('username')).set('value', item.username);
				if(item["super"] == "TRUE"){
					dijit.getEnclosingWidget(document.getElementById('superDDt')).set('checked', true);
				}
				//  do check box connects (enable/disable textboxes)
				dojo.connect(dijit.getEnclosingWidget(document.getElementById('editUsername')), "onChange", function(v){
					console.log(v);
					if(v){
						dijit.getEnclosingWidget(document.getElementById('username')).set('disabled', false);
					}else{
						dijit.getEnclosingWidget(document.getElementById('username')).set('disabled', true);
					}
				});
				dojo.connect(dijit.getEnclosingWidget(document.getElementById('editPassword')), "onChange", function(v){
					console.log(v);
					if(v){
						dijit.getEnclosingWidget(document.getElementById('password')).set('disabled', false);
					}else{
						dijit.getEnclosingWidget(document.getElementById('password')).set('disabled', true);
					}
				});
				dojo.connect(dijit.getEnclosingWidget(document.getElementById('editSuper')), "onChange", function(v){
					console.log(v);
					if(v){
						if(_sixnet_framework._super){
				    		dijit.getEnclosingWidget(document.getElementById('superDDt')).set('disabled', false);
				    		dijit.getEnclosingWidget(document.getElementById('superDDf')).set('disabled', false);
				   		}
					}else{
			    		dijit.getEnclosingWidget(document.getElementById('superDDt')).set('disabled', true);
			    		dijit.getEnclosingWidget(document.getElementById('superDDf')).set('disabled', true);
			   		}
				});
				dojo.connect(dijit.getEnclosingWidget(document.getElementById('editEmail')), "onChange", function(v){
					console.log(v);
					if(v){
						dijit.getEnclosingWidget(document.getElementById('email')).set('disabled', false);
					}else{
						dijit.getEnclosingWidget(document.getElementById('email')).set('disabled', true);
					}
				});
				// this method fires when the dialog has finished loading its content.
				dijit.byId('editUserFormDialog').connect(dijit.byId('editUserFormDialog'), "onCancel", function(){
					// this is for the 'x' button built into the Dialog.
					this.destroyRecursive();
				});
			}
		}).startup();
		
//		dijit.byId('editUserFormDialog').
//		dijit.byId('editUserFormDialog').
//		dijit.byId('editUserFormDialog').
//		dijit.byId('editUserFormDialog').
		dijit.byId('editUserFormDialog').show();
	},
	
	onAddUserClick: function(){
		// create an instance of Dialog with the content (loaded from href), id and title.
		var addUserFormDialog = new dijit.Dialog({userManager: this, 
			style:"width:310px;height:185px;", 
			id:"addUserFormDialog", 
			title:'Add User', 
			href: this.templateUrl.concat('addUser.html'),
			onLoad: function(){
				if(_sixnet_framework._super){
		    		dijit.getEnclosingWidget(document.getElementById('superDDt')).set('disabled', false);
		    		dijit.getEnclosingWidget(document.getElementById('superDDf')).set('disabled', false);
		   		}
				// this method fires when the dialog has finished loading its content.
				dijit.byId('addUserFormDialog').connect(dijit.byId('addUserFormDialog'), "onCancel", function(){
					// this is for the 'x' button built into the Dialog.
					this.destroyRecursive();
				});
			}
		}).startup();
		dijit.byId('addUserFormDialog').show();
	},
	
	openRolesDialog: function(item){
		 console.log("openRoles for: ", item);
		console.log("item: ", item);
		if(item == null) return;
		var uid = item.id;
		var allValues = function(onComplete){
    	//  first we need the "headers" of tab/accordion - these will be
    	//  module names - getInstalled is a temp for getAccountModules.
			var headers = [];
			_sixnet_framework.bcSilent('providers', 'getInstalled', {}, dojo.hitch(this, function(response){
				if( response.successful ){
					console.log(response.data.length);
					_sixnet_framework.log(1, "getInstalled (getAccountModules...tobe)",response.data);
					dojo.forEach(response.data, function(item){
						headers.push(item.name);
					}, this);
					if(headers.length > 0){
				    	var storeStructure = {identifier:'id', label: 'header', items:[]};
				    	var checkList = [];
						var roles = _sixnet_framework._currentPermissions;
						console.log("current user roles: ", roles);
				    	// now we have headers so build out checks-per
						dojo.forEach(headers, function(item, i){
							_sixnet_framework.bcSilent(item, 'getModuleRoles', {}, dojo.hitch(this, function(response){
								if(response.successful){
									// TODO: filter out tabs sin roles
									console.log(response.data.length, response.data, item);
									if(response.data.length > 0){
										var checks = new Array();
										dojo.forEach(response.data, function(check){
											//  will be roles[item]
											if(roles.access && !_sixnet_framework._super){
												//-------------
												_sixnet_framework.log(1, "check:      ", check);
												// TODO: this should not always be access... when data_descriptor is correct!!
												var checkSplit = check.split("_");
												var viewerAdmin = checkSplit.pop();
												var viewerRole = undefined;
												if(viewerAdmin == 'ADMIN'){
													// make sure to add viewer data
													checkSplit.push('VIEWER');
													viewerRole = checkSplit.join('_');
												}
												var hasRole = roles.access[check];
												if(hasRole != undefined){
													console.log("in if put:  ", hasRole);
													checks.push(check);
												}
												if(viewerRole != undefined && hasRole != undefined){
													var hasRole = roles.access[viewerRole];
													if(hasRole == undefined){
														checks.push(viewerRole);
													}
												}
												//--------------
											}else if(_sixnet_framework._super){
												checks.push(check);
											}
										});
										if((/*roles[item]*/roles.access && (checks.length > 0)) || _sixnet_framework._super){
											checkList.push( { header: item, checks: checks} );
										}
									}
									if(i+1 == headers.length){
										onComplete(checkList);
									}
								}else if(response.error){
									_sixnet_framework.log(1, response.error);
								}
							})
							);
						}, this);	
					}
				}else if(response.error){
					_sixnet_framework.log(3, response.error);
				}
			}));
	};
	// get actual current values
		var actualValues = function(onComplete){
			var uid = item.id;
			_sixnet_framework.log(3, "formatters.js-> actualValues UID:  ", uid);
			_sixnet_framework.bcSilent('access', 'getUserRoles', {userId: uid }, dojo.hitch(this, function(response){
				if(response.successful){
					var obj = {};
					dojo.forEach(response.data, function(ur){
						_sixnet_framework.log(1, 'add tab item', ur);
						if(!obj[ur.module]){
							//  if module is defined, great, but does it have roles?
							//  we don't want to show tab if no roles
							obj[ur.module] = {};
						}
						obj[ur.module][ur.role] = ur;
					});
					onComplete(obj);
				}else if(response.error){
					_sixnet_framework.log(3, response.error);
				}
				})
			);
		};
		// true+value
		// addValue(section,value,checkbox)
		var addValue = function ( module, role, cb){
				_sixnet_framework.bcSilent('access', 'addUserRole', {userId: uid, roleModule:module, roleName:role}, dojo.hitch(this, function(response){
					if(response.successful){
						// with this response we have the roleId - add it to the now-positive checkbox.
						cb.sid = response.data;
						//_sixnet_framework.log(3, obj.roleId, "  ->  roleId ADDed");
					}else if(response.error){
						_sixnet_framework.log(3, response.error);
					}
				})
				);		   
		};
		// false-value
		var removeValue = function ( sid, cb){
			//  this is attached to the cb-checkbox, sid being special id.
			_sixnet_framework.bcSilent('access', 'removeUserRole', {roleId:sid}, dojo.hitch(this, function(response){
				if(response.successful){
					// roleId - take it away from the now-false checkbox.
					cb.sid = "";
				}else if(response.error){
					_sixnet_framework.log(3, response.error);
				}
			})
			);
	    };
//			if( value == null) value = '';
//			var editPane = new dijit.layout.ContentPane({style:"margin-right:auto;margin-left:auto"});
//			var editButton = new dijit.form.Button({ label: 'Assign', onClick: dojo.hitch(this, function(value, idx){
			//  make sure uId is set before initiating the visuals.
			var myDialog = new dijit.Dialog({style:"width:310px;height:335px;top:40px;left:100px;", item: item, content:'', title:'Edit User Roles:  '.concat(item.username),
				onLoad: function(){
				// this method fires when the dialog has finished loading its content.allValues:f1, actualValues:f2, addValue:f3, removeValue: f4
					// whether has role to make changes or not we
					//  never allow user to adjust own roles.
					var disabled = true;
					if(uid != _sixnet_framework._userId || _sixnet_framework._super){
						disabled = false;
					}
					//  check for role 
					this.myWid = new com.sixnet.services.widgets.checkAccordion({allValues:allValues, actualValues:actualValues, addValue:addValue, removeValue: removeValue, disabled:disabled});
					this.myWid.placeAt(this.containerNode, "last");
				}
			});
			//  add close button
			var cp = new dijit.layout.ContentPane({
				style:"margin-right:auto;margin-left:auto; width:90%; text-align:right"
			});
			var closeButton = new dijit.form.Button({
				label:"Close",
				onClick:function(){
					myDialog.hide();
					myDialog.destroyRecursive();
				}
			}).placeAt(cp.domNode, "last");
			cp.startup();
			cp.placeAt(myDialog.domNode, "last");
			//
			//  dojo.connect(myDialog, "onCancel", this, function(){
			//  the second obj param "this" would refer to the whole
			//  formatter object!
			//  disable checkboxes
			
			dojo.connect(myDialog, "onCancel" ,dojo.hitch(myDialog, function(){
				// this method fires when the user clicks the close button in the title bar or presses escape
				// we do not want this dialog to stick around when we are done with it.  Tear it down.
				this.hide();
				this.destroyRecursive();
				//_sixnet_framework.log(3, this, " This should be dead.");
			}));
			myDialog.show();
//				_sixnet_framework.log(3, myDialog, "  in formatters", dojo.byId(myDialog), dojo.query('.pane').length, dojo.query('input[type="checkbox"]', myDialog.domNode).length);
//
//			}, value, idx)});
		return;
	},
	
	getUserInfo: function(addedUserId, onComplete){
//		dijit.byId('addUserFormDialog').destroyRecursive();
		_sixnet_framework.bcSilent('access', 'getViewData', { 
			viewName:'users', 
			startingOffset: 0,
			sort: [],
			mode:'=', 
			maxCount:1,
			query: {
				id: addedUserId
			}
			
		}, dojo.hitch(this, function(response){
			if(response.successful){
				onComplete(response.data.items[0]);
				//this.unitHasAttribute(this.authorizedBy, response.data.items[0].username);
			}else{
				//this.unitHasAttribute(this.authorizedBy, 'Access denied');
			}
			_sixnet_framework.log(1, 'success-add user', arguments);
		}), dojo.hitch(this, function(){
			_sixnet_framework.log(1, 'failure-add user', arguments)
		}));
		
	},
	
	onUserRowClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		var rowItem = this.userGrid.grid.getItem( event.rowIndex);
		this.user = rowItem;
		var message = "";
		dojo.removeClass( this.userToolbar.removeButton.focusNode, "disabledButton");
		if(event.cell.editable){
			message = "Double-click to edit user detail";
			dojo.publish( '/status/hint', [message]);
		}
	},
	
	onUserRowDblClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		_sixnet_framework.log(3, "DblClick ", event);
		var rowItem = this.userGrid.grid.getItem( event.rowIndex);
		this.user = rowItem;
		_sixnet_framework.log(3, "user set:  ", this.user);
		var message = "";
		if(!event.cell.editable){
			message = "This cell is not editable";
		}
		dojo.publish( '/status/hint', [message]);
	},
	
	onRemoveClick: function(){
		if( dojo.hasClass( this.userToolbar.removeButton.focusNode, "disabledButton")) return;
		if( !confirm("Delete  `".concat( this.user.username).concat( "` from users?"))) return;
		//  don't allow user to delete self... 
		if(this.user.id == this.currentUser){
			alert("You cannot delete yourself!");
		}else{
			_sixnet_framework.bc('access', 'removeUser', { userId: this.user.id }, dojo.hitch(this, function(response){
				if( response.successful ){
					dojo.addClass( this.userToolbar.removeButton.focusNode, "disabledButton");
					this.userGrid.reloadGrid();
					_sixnet_framework.log(1, "reload?");
				}
			}));
		}
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.testDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.testDash'] = true;
dojo.provide('com.sixnet.services.modules.access.testDash');




dojo.declare('com.sixnet.services.modules.access.testDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/testDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.jobAdd');		
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.logDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.logDash'] = true;
// tell package managerthat a specific package has been loaded
dojo.provide('com.sixnet.services.modules.access.logDash');
// load dojo dashWidgetBash

// _Templated == mix-in Widget HTML


// simulate Class system like Java with dojo.declare 
// 3 arguments (optional_global_name, null or base class or array of objects (multiple inheritance), object hash of properties to be mixed in after all other inheritance has been solved)
// dojo.moduleUrl is used to return a dojo._Url object relative to a module.
dojo.declare('com.sixnet.services.modules.access.logDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/logDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.log');
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.unitPlotDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.unitPlotDash'] = true;
// tell package managerthat a specific package has been loaded
dojo.provide('com.sixnet.services.modules.access.unitPlotDash');
// load dojo dashWidgetBash

// _Templated == mix-in Widget HTML


// simulate Class system like Java with dojo.declare 
// 3 arguments (optional_global_name, null or base class or array of objects (multiple inheritance), object hash of properties to be mixed in after all other inheritance has been solved)
// dojo.moduleUrl is used to return a dojo._Url object relative to a module.
dojo.declare('com.sixnet.services.modules.access.unitPlotDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/unitPlotDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){
		// attempt to make dash of own here.
//		this.dashBoard = new com.sixnet.services.core.dashBoard({ _app: dijit.byId('body')});
		// below works just fine, but is not in a dash of it's own.
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.unitPlot');
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.log']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.log'] = true;
dojo.provide('com.sixnet.services.modules.access.log');













dojo.declare('com.sixnet.services.modules.access.log', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div dojoType=\"com.sixnet.services.core.data.writeStore\" jsid=\"logStore\" identifier=\"id\" pushModule=\"access\" pushMethod=\"getAccountUsers\" updateMethod=\"logMassUpdate\">\n\t</div>\n\t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:100%; margin-right:15px; border:none;\" gutters=\"false\">\n\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"top\" gutters=\"false\">\t\t\n\t\t\t<div dojoType=\"com.sixnet.services.widgets.sixnetToolbar\" module=\"access\" editRole=\"ROLE_USER_ADMIN\" viewRole=\"ROLE_USER_VIEWER\" jsid=\"logToolbar\" store=\"logStore\" searchField=\"logname\" dojoAttachPoint=\"logToolbar\" region=\"top\">\t\t\t\t\n\t\t\t</div>\t\n\t\t</div>\n\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" gutters=\"false\">\t\t\n\t\t\t<div dojoType=\"com.sixnet.services.widgets.sixnetGrid\" jsid=\"logGrid\" query=\"{}\" formatterClass=\"com.sixnet.services.modules.access.formatters\" toolbar=\"logToolbar\" store=\"logStore\" region=\"center\" gridName=\"logGrid\" showSaveView=\"true\" showContextMenu=\"true\" dojoAttachPoint=\"logGrid\">\n\t\t\t</div>\t\t\n\t\t</div>\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; padding-top:2px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	//values:{count:0},
	currentUser:false,
	log:false,/*log is rowItem*/
	clearLogButton:{},
	icon: 'log.png',
	iconPath: '',
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		//this.connect( this.dashBoard, "onHideWidget", "onHide");
		this.currentUser = _sixnet_framework._logId;
		// this is temp and just makes the search work.
		this.logToolbar.grid = this.logGrid.grid;
		//
		this.logToolbar.searchField = "logname";
		this.clearLogButton = new dijit.form.Button({
			label:"Clear Log"}).placeAt(this.logToolbar.extras.domNode);
		this.connect(this.clearLogButton, "onClick", "onClearLogClick");
		//
		// TODO: Connects get abstracted from the actual grid to the SixnetGrid
		// TODO: REVISIT WITH PAUL THE TOOLBAR CONNECTS 
		// connex
//		this.connect(this.logToolbar.addButton, "onClick", "onAddUserClick");
//		this.connect(this.logToolbar.removeButton, "onClick", "onRemoveClick");
//		this.connect(this.logGrid.grid,"onClick", "onUserRowClick");
//		this.connect(this.logGrid.grid,"onDblClick", "onUserRowDblClick");
		this._subscribes.push( dojo.subscribe( '/status/hint', dojo.hitch(this.statusLine, "setContent")));
		this.connect(this.logGrid.store, "onSet", dojo.hitch(this, function(item, attr, oldVal, newVal){
				if(newVal != oldVal){
					this.logToolbar.needsSaved = true;
					this.logToolbar.unhideSaveRevertButton();
				}
	        })
	    );
	},

	
	onClearLogClick: function(){
		var clearLogFormDialog = new dijit.Dialog({
			style:"width:310px;height:235px;",
			title:'Clear Log',
			onLoad: function(){
			// this method fires when the dialog has finished loading its content.
				this.connect(this, "onCancel", function(){
					// this is for the 'x' button built into the Dialog.
					_sixnet_framework.log(3, "in onCancel");
					this.hide();
			    	this.destroyRecursive();
					return;
				});
			}
		});
		var cp0 = new dijit.layout.ContentPane({
	        style: "height:300px; width:100%; text-align:center; margin-right:auto; margin-left:auto; overflow:hidden"
	    }).placeAt(dojo.byId(clearLogFormDialog.domNode), "last");
		// create info text
		dojo.create("<p>", {innerHTML:"<b>This clears system logs, not unit history.</b>"}, cp0.domNode);
//		// create number spinner
//		var prompt = dojo.create("<p>", {innerHTML:"Number of records to keep: "}, cp0.domNode);

		var cp1 = new dijit.layout.ContentPane({
			content:"Number of records to <b>keep</b>: ",
	        style: "height:50px; width:100%; text-align:center; margin-right:auto; margin-left:auto; overflow:hidden"
	    }).placeAt(dojo.byId(cp0.domNode), "last");		
		var numberSpinner = new dijit.form.NumberSpinner({
			// we want log-count for max constraint
		    //constraints: "{ min:1, max:5, places:0 }",
			constraints: {min:0},
		    // we want value = .5(total)
		    value: "1",
		    style:"width:55px;font-size:1.2em"
		}).placeAt(dojo.byId(cp1.domNode), "last");
		
		// create button
		var clearLog = new dijit.form.Button({
			style:"margin-top:10px",
			label:"Clear Log"}).placeAt(dojo.byId(cp0.domNode), "last");
		dojo.connect(clearLog, "onClick", function(){
			_sixnet_framework.log(3, "clearLog()", numberSpinner.value);
		});
		//
		clearLogFormDialog.show();
	},
	
	onUserRowClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		var rowItem = this.logGrid.grid.getItem( event.rowIndex);
		this.log = rowItem;
		var message = "";
		dojo.removeClass( this.logToolbar.removeButton.focusNode, "disabledButton");
		if(event.cell.editable){
			message = "Double-click to edit log detail";
			dojo.publish( '/status/hint', [message]);
		}
	},
	
	onUserRowDblClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		_sixnet_framework.log(3, "DblClick ", event);
		var rowItem = this.logGrid.grid.getItem( event.rowIndex);
		this.log = rowItem;
		_sixnet_framework.log(3, "log set:  ", this.log);
		var message = "";
		if(!event.cell.editable){
			message = "This cell is not editable";
		}
		dojo.publish( '/status/hint', [message]);
	},
	
	onRemoveClick: function(){
		if( dojo.hasClass( this.logToolbar.removeButton.focusNode, "disabledButton")) return;
		if( !confirm("Delete  `".concat( this.log.logname).concat( "` from logs?"))) return;
		//  don't allow log to delete self... 
		if(this.log.id == this.currentUser){
			alert("You cannot delete yourself!");
		}else{
			_sixnet_framework.bc('access', 'removeUser', { logId: this.log.id }, dojo.hitch(this, function(response){
				if( response.successful ){
					dojo.addClass( this.logToolbar.removeButton.focusNode, "disabledButton");
					this.reloadGrid();
				}
			}));
		}
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.serverUtilitiesDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.serverUtilitiesDash'] = true;
// tell package managerthat a specific package has been loaded
dojo.provide('com.sixnet.services.modules.access.serverUtilitiesDash');
// load dojo dashWidgetBash

// _Templated == mix-in Widget HTML


// simulate Class system like Java with dojo.declare 
// 3 arguments (optional_global_name, null or base class or array of objects (multiple inheritance), object hash of properties to be mixed in after all other inheritance has been solved)
// dojo.moduleUrl is used to return a dojo._Url object relative to a module.
dojo.declare('com.sixnet.services.modules.access.serverUtilitiesDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/serverDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){
		// attempt to make dash of own here.
//		this.dashBoard = new com.sixnet.services.core.dashBoard({ _app: dijit.byId('body')});
		// below works just fine, but is not in a dash of it's own.
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.serverUtilities');
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.unitDetail']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.unitDetail'] = true;
dojo.provide('com.sixnet.services.modules.access.unitDetail');
//

















dojo.declare('com.sixnet.services.modules.access.unitDetail', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div dojoAttachPoint=\"UNIT_DETAIL\">\n <div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">\n \t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" dojoAttachPoint=\"unitDetailMain\"> \n \t<div dojoType=\"dijit.layout.ContentPane\" class=\"isHistory\"></div>\t\n\t<!-- File Control tab container -->\n\t<div dojoType=\"dijit.layout.TabContainer\" style=\"width:100%; height:100%; margin-right:15px\" tabStrip=\"false\" tabPosition=\"left-h\">\n\t\t<!-- Group jobs -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Features\">\t<!--  closable=\"true\" -->\t\n\t    \t<div class=\"headerLabel\">Device Configuration</div>\n\t    \t\n\t    \t<div dojoType=\"dijit.layout.ContentPane\" style=\"float:left; width:400px;\">\n\t\t    \t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tSerial Number\t\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"serialNumber\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tAuthorizing User\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"authorizedBy\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tSmart Modem\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"smartModem\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\n\t\t\t\t\n\t\t\t\t</div>\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"float:left; width:400px;\">\t\t\n\t\t\t\t\n\t  \n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tPlatform\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"platform\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tUnit Status\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">        \n\t\t\t\t   \t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"unitStatus\" ></div> \n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tDescription\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"description\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div dojoType=\"dijit.layout.ContentPane\" title=\"Configuration\">\t<!--  closable=\"true\" -->\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"width:800px; clear:none\">\n\t\t\t\t<div class=\"headerLabelF\" style=\"float:left; width:379px; clear:none; clear:left\" >Server Settings</div>\n\t\t\t\t<div class=\"headerLabelF\" style=\"float:left; width:379px\">Client Settings</div>\n\t\t\t</div>\n\t\t\n\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"clear:both; width:800px;\">\n\t\t    \n\t\t\t<div dojoType=\"dijit.form.Form\" dojoAttachPoint=\"unitConfigForm\" style=\"border:1px solid #b41319; background:#f7f7f7; float:left; height:auto; width:49%;\" class=\"unitDetailForm\">\n\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tAllow Changes\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\"  dojoAttachPoint=\"unitIdAllowChanges\">\n\t\t\t\t\t\t</div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tMajor Name\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.TextBox\" class=\"unitIdFormTB\" disabled=\"disabled\" name=\"major_name\" dojoAttachPoint=\"majorName\" placeHolder=\"major name\">\n\t\t\t\t\t\t</div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tMinor Name\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.TextBox\" class=\"unitIdFormTB\" disabled=\"disabled\" name=\"minor_name\" dojoAttachPoint=\"minorName\" placeHolder=\"minor name\">\n\t\t\t\t\t\t</div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tUnit Id\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.TextBox\" class=\"unitIdFormTB\" disabled=\"disabled\" name=\"unit_id\" dojoAttachPoint=\"unitId\" placeHolder=\"unit id\">\n\t\t\t\t\t\t</div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tAuthorized\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitIdFormCB\" dojoAttachPoint=\"unitAuthorized\" dojoAttachEvent=\"onChange:onAuthorizedChange\">\n\t\t\t\t\t\t</div>\n\t\t\t\t    </div>\n\t\t\t\t\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tBanned\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitIdFormCB\" dojoAttachPoint=\"unitBanned\" dojoAttachEvent=\"onChange:onBannedChange\">\n\t\t\t\t\t\t</div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tLow Bandwidth Unit\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitIdFormCB\" dojoAttachPoint=\"unitLowBandwidth\">\n\t\t\t\t\t\t</div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \t&nbsp;\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\"> \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.Button\" disabled=\"disabled\" dojoAttachPoint=\"cancelIdConfig\" dojoAttachEvent=\"onClick:setIdConfig\" label=\"Cancel\">\n\t\t\t\t   \t\t</div>\n\t\t\t\t   \t\t<div dojoType=\"dijit.form.Button\" disabled=\"disabled\" dojoAttachPoint=\"applyIdConfig\" dojoAttachEvent=\"onClick:updateIdConfig\" label=\"Apply\">\n\t\t\t\t   \t\t</div>\n\t\t\t\t   \t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t  \t<div dojoType=\"dijit.form.Form\" dojoAttachPoint=\"clientConfigForm\" style=\"border:1px solid #b41319; background:#f7f7f7; float:left; height:auto; width:49%;\" class=\"unitDetailForm\">\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tSixview Manager 1\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitDetailControlCB\" dojoAttachPoint=\"GMU1Check\">\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div dojoType=\"dijit.form.TextBox\" class=\"unitDetailFormTB\" disabled=\"disabled\" name=\"GMU1\" dojoAttachPoint=\"GMU1Text\" placeHolder=\"GMU1\">\n\t\t\t\t\t\t</div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tSixview Manager 2\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">   \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitDetailControlCB\" dojoAttachPoint=\"GMU2Check\">\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div dojoType=\"dijit.form.TextBox\" class=\"unitDetailFormTB\" disabled=\"disabled\" name=\"GMU2\" dojoAttachPoint=\"GMU2Text\" placeHolder=\"GMU2\">\n\t\t\t\t\t\t</div>      \n<!--\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"gmuServer2\"></div>-->\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tPoll Interval\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">     \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitDetailControlCB\" dojoAttachPoint=\"pollIntervalCheck\">\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div dojoType=\"dijit.form.NumberSpinner\" class=\"unitDetailFormTB\" disabled=\"disabled\" name=\"pollInterval\" dojoAttachPoint=\"pollIntervalText\" placeHolder=\"240\">\n\t\t\t\t\t\t</div>         \n<!--\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"managementClientPollInterval\"></div>-->\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tServer Mode\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">   \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitDetailControlCB\" dojoAttachPoint=\"serverModeCheck\">\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<select dojoType=\"dijit.form.Select\" style=\"width:10em\" name=\"serverMode\" disabled=\"disabled\" dojoAttachPoint=\"serverModeSelect\">\n\t\t\t\t\t\t\t<option value=\"none\">none</option>\n\t\t\t\t\t\t\t<option value=\"secondary\">secondary</option>\n\t\t\t\t\t\t\t<option value=\"both\">both</option>\n\t\t\t\t\t\t\t<option value=\"error\">error</option>\n\t\t\t\t\t\t</select>      \n<!--\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"serverMode\"></div>-->\n\t\t\t\t    </div>\n\t\t\t\t</div>\n<!-- \t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \t&nbsp;\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\"> \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitDetailMiniAuthCB\" dojoAttachPoint=\"unitMiniAuth\">\n\t\t\t\t\t\t</div>        \n\t\t\t\t\t\t<span style=\"color:#b41319; font-size:.75em; font-style:italic;\">Apply these setting on next checkin.</span>\n\t\t\t\t    </div>\n\t\t\t\t</div> -->\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \t&nbsp;\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\"> \n\t\t\t\t   \t\t<div dojoType=\"dijit.form.Button\" disabled=\"disabled\" dojoAttachPoint=\"cancelClientConfig\" dojoAttachEvent=\"onClick:setClientConfig\" label=\"Cancel\">\n\t\t\t\t   \t\t</div>\n\t\t\t\t   \t\t<div dojoType=\"dijit.form.Button\" disabled=\"disabled\" dojoAttachPoint=\"applyClientConfig\" dojoAttachEvent=\"onClick:updateClientConfig\" label=\"Apply\">\n\t\t\t\t   \t\t</div>\n\t\t\t\t   \t</div>\n\t\t\t\t</div>\n\t\t\t\t\n\t\t\t</div>\n\t\t\t\t\n\t\t\t</div>\n\t    </div>\n\t\t<!-- Pending jobs -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Unit Actions\">\t\n\t    \t<div class=\"headerLabel\">Unit Actions</div>\n\t    \t\n\t    \t<div dojoType=\"dijit.form.Form\" dojoAttachPoint=\"unitActionsForm\">\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\" style=\"color:darkgrey; width:100%; text-align:left\">\n\t\t\t\t    \tA check indicates the activity is pending.  Uncheck to cancel the activity.  Changes take effect on next check-in.\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t    \t<div dojoType=\"dijit.form.Form\" dojoAttachPoint=\"unitActionsForm\">\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tMini-Gatherstats\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitDetailFormCB\" dojoAttachPoint=\"miniGatherstatsRequest\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tSystem Log Request\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitDetailFormCB\" dojoAttachPoint=\"systemLogRequest\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tGwlnx Log Request\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitDetailFormCB\" dojoAttachPoint=\"gwlnxLogRequest\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tGPS Lock\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitDetailFormCB\" dojoAttachPoint=\"gpsLock\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tGPS Monitor\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitDetailFormCB\" dojoAttachPoint=\"gpsMonitor\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\t\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tGPS Detail Request\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.form.CheckBox\" disabled=\"disabled\" class=\"unitDetailFormCB\" dojoAttachPoint=\"gpsDetailRequest\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t\t<!-- Received Info -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Received Info\">\n\t    \t<div class=\"headerLabel\">Received Info</div>\n\t    \t\n\t    \t<div style=\"float:left; width:370px;\">\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tUpdate Time\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"updateTime\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\t\t\t\t\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tAlert Message\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"alertMessage\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\t\t\t\t\n\t\t\t\t<!-- \n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tHeartbeat\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"heartbeat\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\t\n\t\t\t\t-->\t\t\t\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tSource IP\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"sourceIP\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\t\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tInterfaces\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"interfaces\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tHostname\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"hostname\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\t\t\t\t\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tModel Number\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"modelNumber\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tFirmware Version\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"firmwareVersion\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\t\n\t\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tClient Version\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"managementClientVersion\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\t\t\t\t\t\t\t\t\n\t\t\t\t</div>\n\t\t\t\t<div style=\"float:left; width:370px;\">\t\t\t\t\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tUptime\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"uptime\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\t\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tSignal Strength\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"signalStrength\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\t\t\t\t\t\t\t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tRSSI\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"RSSI\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tWireless Uptime\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"wirelessUptime\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tCell Modem Name\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"cellModemName\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tESN / IMEI\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"ESNIMEI\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tMDN\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"MDN\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tGPS\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"GPS\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t</div>\n\t\t<!-- Wireless Data Usage -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Data Usage\">\t<!--  closable=\"true\" -->\t\n\t    \t<div class=\"headerLabel\">Wireless Data Usage</div>\n\t    \t\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tCurrent Data Usage\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"currentDataUsage\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t<div class=\"labelLeft\">\n\t\t\t\t    \tPrevious Data Usage\n\t\t\t\t    </div>\n\t\t\t\t   \t<div class=\"inputRightBold\">         \n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"previousDataUsage\"></div>\n\t\t\t\t    </div>\n\t\t\t\t</div>\n\t\t</div>\n\t</div>\n\t</div>\n\t<!-- end tab container -->\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; padding-top:2px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n </div>\n</div>\n\n\n",
	currentUser:false,
	unitID: '',
	icon: 'unit_detail.png',
	iconPath: '',
	appParams: {},
	serial: '',
	mini_info_request:0,
	checkInDate: null,
	currentItemParams: {},
	useHistory: false,
	_addedBy: null,
	_viewOnly: true,
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
//		_sixnet_framework.log(1, "dojoattachpoints >>> ", dojo.query("dojoattachpoint", this.UNIT_DETAIL));
		//  using attach points with appParam.item fill in the blanks
		var roles = _sixnet_framework._currentPermissions;
		var admin = false;
		if(roles.unit){
			admin = ('undefined' != typeof(roles.unit['ROLE_UNIT_ADMIN']));
		}
		if(admin || _sixnet_framework._super){
			this._viewOnly = false;
		}
		if(this.appParams.item.isHistory){
			this.useHistory = true;
			this.currentItemParams.item = {};
			var n = dojo.query(".isHistory", dojo.byId(this.unitDetailMain).domNode)[0];
			var message = "Unit Detail from "+(this.epochToHuman(this.appParams.item.check_in_date))+"<br>";
			var messageCP = new dijit.layout.ContentPane({
				style:'float:left; padding-left:5px;',
				content: message}
			).placeAt(n, "last");
			//
			var D = "Show / Edit current Unit Detail  ";
			var detailCP = new dijit.layout.ContentPane({
				style:'float:left; padding-left:5px;clear:both',
				content: D}
			).placeAt(n, "last");
			var showHistoryCheck = new dijit.form.CheckBox({}).placeAt(detailCP.domNode, "last");
			this.connect(showHistoryCheck, "onChange", dojo.hitch(this, function(v){
				console.log(v, this.appParams);
				if(v){
					this.useHistory = false;
					this.populateTemplate();
				}else{
					this.useHistory = true;
					this.populateTemplate();
				}
			}));
			dijit.getEnclosingWidget(n).set('style', {display:"block"});
		}
		this.populateTemplate();
		console.log("item:  ", this.appParams.item);
	},
	
	populateTemplate: function(){
		this.serverModeSelect.set("forceWidth", true);
//		var id = (this.appParams.item.originalItem)? this.appParams.item.originalItem.id:this.appParams.item.id;
		var server_mode ;
		var interval ;
		var json ;
		var interfaces ;
		try{
			this.currentItemParams.item = {};
			if(!this.useHistory){
				console.log("not using history");
				if(this.appParams.item.originalItem){
					//  we've arrived from history-detail, use originalItem
					this.currentItemParams.item = dojo.clone(this.appParams.item.originalItem);
				}else{
					//  we are not coming from history-detail
					this.currentItemParams.item = dojo.clone(this.appParams.item);
				}
			}else{
				this.currentItemParams.item = dojo.clone(this.appParams.item);
				//  grab actual id because this id will be from the history entry's id
				this.currentItemParams.item.id = this.currentItemParams.item.originalItem.id;
			}
			_sixnet_framework.log(1, "unitDetail check in date>>> ", dojo.clone(this.currentItemParams.item.check_in_date));
			json = this.currentItemParams.item.interfaces;
			interfaces = dojo.fromJson(json);
			var remote_host = interfaces.remote_host;
			this.interfaces.set('content', '');
			for(var i=0; i<interfaces.interfaces.length; i++){
				//  set status class
				var interfaceStatusClass = 'interfaceStatus';
				if(interfaces.interfaces[i].status == 'UP'){
					interfaceStatusClass = 'interfaceStatusUp';
				}else if(interfaces.interfaces[i].status == 'DOWN'){
					interfaceStatusClass = 'interfaceStatusDown';
				}else{
					interfaceStatusClass = 'interfaceStatusUnknown';
				}
				var status = interfaces.interfaces[i].status;
				if(status == '') status = "??";
				var interfaceDiv = dojo.create("div", {innerHTML:'<span class="interfaceName">'.concat(interfaces.interfaces[i].name).concat('</span><span class="').concat(interfaceStatusClass).concat('">').concat(status).concat('</span><span class="interfaceIP">').concat(interfaces.interfaces[i].ipv4).concat('</span>')});
				dojo.query(dojo.byId(this.interfaces).domNode).addContent(interfaceDiv);
			}
			//  set client config info
			this.setClientConfig();
			//  do gps
			var json = this.currentItemParams.item.gps_position;
			var gps_position = dojo.fromJson(json);
			if(gps_position != null && gps_position.gps != null){
				var lat = gps_position.gps[0].gps_lat;
				var longitude = gps_position.gps[1].gps_long;
				var gpsDiv = dojo.create("div", {innerHTML:'<span class="interfaceName">LAT: </span><span class="interfaceIP">'.concat(lat).concat('</span>').concat('<br /><span class="interfaceName">LNG: </span><span class="interfaceIP">').concat(longitude).concat('</span>')});
				dojo.query(dojo.byId(this.GPS).domNode).addContent(gpsDiv);
			}else{
				this.unitHasAttribute(this.GPS, "");
			}
			//  do serial display with H/J buttons
			this.doSerial(this.serialNumber, this.currentItemParams.item.serial);
			
			this.setIdConfig();
			this.unitHasAttribute(this.platform, this.currentItemParams.item.architecture);
			console.log("setting check in date:  ", this.currentItemParams.item.check_in_date);
			this.unitHasAttribute(this.updateTime, this.epochToHuman(this.currentItemParams.item.check_in_date));
			// Set placeholder "working" icon
			this.unitHasAttribute(this.authorizedBy, '<img style="height:20px; width:20px" src="' + dojo.moduleUrl( 'com.sixnet.services.core', 'templates/images/dashWorking.gif') + '"/>');
	//		dojo.attr(this.authorizedOn,{content:this.currentItemParams.item.});
			//  formate uptime/wireless
			this.unitHasAttributeDHMS(this.wirelessUptime, this.currentItemParams.item.cell_uptime);
			this.unitHasAttributeDHMS(this.uptime, this.currentItemParams.item.uptime);
			//  turn TRUE/FALSE to display YES/NO
			//this.unitHasAttributeTF(this.banned, this.currentItemParams.item.banned);
			//this.unitHasAttributeTF(this.lowBandwidthUnit, this.currentItemParams.item.low_bandwidth);
			this.unitHasAttributeTF(this.smartModem, this.currentItemParams.item.smfc);
			var viewModeText =this.currentItemParams.item.view_mode;
			switch(viewModeText){
			case 'IGNORE': viewModeText = 'Ignore unit in current list'; break;
			case 'IGNORE_UNTIL_CHECKIN': viewModeText = 'Ignore unit in current list until it checks in'; break;
			case 'NORMAL':
			default:
					break;
			}
			dojo.attr(this.unitStatus,{content:viewModeText});
			/*
				<select forceWidth="true" style="width:20em" dojoType="dijit.form.Select" dojoAttachPoint="unitStatus">
							<option value="NORMAL">Normal</option>
							<option value="IGNORE">Ignore (Omit from unit list)</option>
							<option value="IGNORE_UNTIL_CHECKIN">Ignore until checkin</option>
						</select>
			 */
			var description = this.currentItemParams.item.description;
			var description = (description)?description:'<span style="opacity:.4; filter:alpha(opacity=40)">empty</span>';
			this.unitHasAttribute(this.description, description);
			//  format rssi - n db
			var rssi = this.currentItemParams.item.cell_modem_rssi;
			var rssi = (rssi)?'-'+rssi+' db':'<span style="opacity:.4">not provided</span>';
			this.unitHasAttribute(this.RSSI, rssi);
	//		dojo.attr(this.triggers,{content:this.currentItemParams.item.});
	//		dojo.attr(this.updateTime,{content:this.currentItemParams.item.});
			this.unitHasAttribute(this.alertMessage, this.currentItemParams.item.alert_desc);
			this.unitHasAttribute(this.sourceIP, remote_host);
			this.unitHasAttribute(this.hostname, this.currentItemParams.item.host_name);
			this.unitHasAttribute(this.modelNumber, this.currentItemParams.item.model);
			this.unitHasAttribute(this.firmwareVersion, this.currentItemParams.item.firmware_version);
			this.unitHasAttribute(this.managementClientVersion, this.currentItemParams.item.client_version);
			this.unitHasAttribute(this.cellModemName, this.currentItemParams.item.cell_modem_name);
			this.unitHasAttribute(this.ESNIMEI, this.currentItemParams.item.cell_modem_esn);
			this.unitHasAttribute(this.MDN, this.currentItemParams.item.cell_modem_mdn);
			var total_rx = parseInt(this.currentItemParams.item.total_rx);
			if(typeof(total_rx) != 'number') total_rx = 0;
			var total_tx = parseInt(this.currentItemParams.item.total_tx);
			if(typeof(total_tx) != 'number') total_tx = 0;
			this.unitHasAttribute(this.currentDataUsage,(total_rx+total_tx));
			//  use graphical rep for signal (like grid)
			this.unitCellLightbarSignal(this.signalStrength, this.currentItemParams.item.cell_lightbar_signal);
			this.unitHasAttribute(this.previousDataUsage,this.currentItemParams.item.prev_sx, 'Not available');
			//  unit action tab - using check boxes
			this.mini_info_request = this.currentItemParams.item.mini_info_request;
			this.setCheckBoxState(this.currentItemParams.item.mini_info_request);
//			dojo.attr(this.rapidRf,{content:this.currentItemParams.item.rapid_rf});
			//  unit action tab - using check boxes
			//  unit action tab - using check boxes
			this.mini_info_request = this.currentItemParams.item.mini_info_request;
			this.setCheckBoxState(this.currentItemParams.item.mini_info_request);
//			dojo.attr(this.rapidRf,{content:this.currentItemParams.item.rapid_rf});
			//  unit action tab - using check boxes
			this.mini_info_request = this.currentItemParams.item.mini_info_request;
			this.setCheckBoxState(this.currentItemParams.item.mini_info_request);
//			dojo.attr(this.rapidRf,{content:this.currentItemParams.item.rapid_rf});
			//  unit action tab - using check boxes
			this.mini_info_request = this.currentItemParams.item.mini_info_request;
			this.setCheckBoxState(this.currentItemParams.item.mini_info_request);
//			dojo.attr(this.rapidRf,{content:this.currentItemParams.item.rapid_rf});
			setTimeout(dojo.hitch(this, "populateDataUsage"),10);
			setTimeout(dojo.hitch(this, "_getAddedBy"),10);
		}catch(e){
			_sixnet_framework.log(1, 'Error in detail startup', e);
		}
		//  setup unit action cbs
		if(!this._viewOnly){
			var this_unitDetail = this;
			this.unitIdAllowChanges.set('disabled', false);
			dojo.forEach(dojo.query(".unitDetailFormCB", this.unitActionsForm.domNode), 
					function(n){
						dijit.getEnclosingWidget(n).set('disabled', false);
			});
			setTimeout(dojo.hitch(this, function(){
				dojo.forEach(dojo.query(".unitDetailFormCB", this.unitActionsForm.domNode),
						function(n){
						dojo.connect(dijit.getEnclosingWidget(n), "onChange", function(v) {
							var actionsLabel = this.dojoAttachPoint;
							if(v == true){
								this_unitDetail.turnBit(actionsLabel, v);
							}else if(v == false){
								this_unitDetail.turnBit(actionsLabel, v);
							}
					 	});
				});				
			}),10);
			dojo.forEach(dojo.query(".unitDetailControlCB", dojo.byId(this.clientConfigForm).domNode), 
					function(n){
						dijit.getEnclosingWidget(n).set('disabled', false);
			});
			var onCount = 0;
			setTimeout(dojo.hitch(this, function(){
				dojo.forEach(dojo.query(".unitDetailControlCB", dojo.byId(this.clientConfigForm).domNode), 
						function(n){
						dojo.connect(dijit.getEnclosingWidget(n), "onChange", function(v) {
							var textLabel = ""+(this.dojoAttachPoint.split("Check")[0])+"Text";
							var selectLabel = ""+(this.dojoAttachPoint.split("Check")[0])+"Select";
							if(v == true){
								onCount++;
								if(this_unitDetail[textLabel]){						
									this_unitDetail[textLabel].set('disabled', false);
								}else if(this_unitDetail[selectLabel]){
									this_unitDetail[selectLabel].set('disabled', false);
								}
							}else{
								onCount--;
								if(this_unitDetail[textLabel]){
									this_unitDetail[textLabel].set('disabled', 'disabled');
									if(this_unitDetail[textLabel].get('value')){
										this_unitDetail[textLabel].set('value', this_unitDetail[textLabel].get('value'));
									}else{
										if(this_unitDetail[textLabel].get('placeHolder')){
											//  put placeHolder text back via setting value to empty
											this_unitDetail[textLabel].set('value', '');
										}
									}
								}else if(this_unitDetail[selectLabel]){
									this_unitDetail[selectLabel].set('disabled', 'disabled');
								}
							}
							if(onCount > 0){
								this_unitDetail.cancelClientConfig.set('disabled', false);
								this_unitDetail.applyClientConfig.set('disabled', false);
							}else{
								this_unitDetail.cancelClientConfig.set('disabled', true);
								this_unitDetail.applyClientConfig.set('disabled', true);
							}
		            
		             	});
				});
			}),10);
			this.connect(this.unitIdAllowChanges, "onChange", "onAllowChangesChange");
		}else{
			this.disableAllEdits();
		}
		//this.connect(this.unitIdAllowChanges, "onClick", "onAllowChangesClick");
		this.connect(this.unitIdAllowChanges, "onChange", "onAllowChangesChange");
	},
	
	disableAllEdits: function(){
		console.log("disable all edits");
		var this_unitDetail = this;
		this.unitIdAllowChanges.set('disabled', true);
		dojo.forEach(dojo.query(".unitDetailFormCB", this.unitActionsForm.domNode), 
				function(n){
//					dijit.getEnclosingWidget(n).set('checked', false);
					dijit.getEnclosingWidget(n).set('disabled', true);
		});
		dojo.forEach(dojo.query(".unitDetailControlCB", dojo.byId(this.clientConfigForm).domNode), 
				function(n){
//					dijit.getEnclosingWidget(n).set('checked', false);
					dijit.getEnclosingWidget(n).set('disabled', true);
		});
		dojo.forEach(dojo.query(".unitIdFormCB", dojo.byId(this.unitConfigForm).domNode), 
				function(n){
//					dijit.getEnclosingWidget(n).set('checked', false);
					dijit.getEnclosingWidget(n).set('disabled', true);
		});
	},
	
	setIdConfig: function(){
		this.unitHasAttributeTextBox(this.majorName, this.appParams.item.major_name);
		this.unitHasAttributeTextBox(this.minorName, this.appParams.item.minor_name);
		this.unitHasAttributeTextBox(this.unitId, this.appParams.item.unit_id);
		this.unitHasAttributeCheckbox(this.unitAuthorized, this.appParams.item.authorized);
		this.unitHasAttributeCheckbox(this.unitBanned, this.appParams.item.banned);
		this.unitHasAttributeCheckbox(this.unitLowBandwidth, this.appParams.item.low_bandwidth);
	},
	updateIdConfig:function(){
		try{
			var values = this.unitConfigForm.getValues();
			if(this.appParams.item.unit_id != values.unit_id){
				values.unit_sync_dirty = 'TRUE';
			}
			this.appParams.item.major_name = values.major_name;
			this.appParams.item.minor_name = values.minor_name;
			this.appParams.item.unit_id = values.unit_id;
			values.authorized = this.appParams.item.authorized = (this.unitAuthorized.get("checked")?'TRUE':'FALSE');
			values.banned = (this.appParams.item.banned = this.unitBanned.get("checked"))?'TRUE':'FALSE';
			values.low_bandwidth = (this.appParams.item.low_bandwidth = this.unitLowBandwidth.get("checked"))?'TRUE':'FALSE';
			values.id = this.appParams.item.id;
			_sixnet_framework.bc('access','updateViewData',{ viewName:'units',items:[ values ]});
			this.unitIdAllowChanges.set('checked', false);
		}catch(e){
			_sixnet_framework.log(0, "Error updating id configuration", e);
		}
	},
	onAllowChangesChange: function(v){
//		this._allowOnChange = false;
		if(v){
			dojo.forEach(dojo.query(".unitIdFormTB", dojo.byId(this.unitConfigForm).domNode), 
					function(n){
						dijit.getEnclosingWidget(n).set('disabled', false);
			});
			dojo.forEach(dojo.query(".unitIdFormCB", dojo.byId(this.unitConfigForm).domNode), 
					function(n){
						dijit.getEnclosingWidget(n).set('disabled', false);
			});
			this.cancelIdConfig.set("disabled",false);
			this.applyIdConfig.set("disabled",false);
		}else{
			dojo.forEach(dojo.query(".unitIdFormTB", dojo.byId(this.unitConfigForm).domNode), 
					function(n){
						dijit.getEnclosingWidget(n).set('disabled', true);
			});
			dojo.forEach(dojo.query(".unitIdFormCB", dojo.byId(this.unitConfigForm).domNode), 
					function(n){
						dijit.getEnclosingWidget(n).set('disabled', true);
			});
			this.cancelIdConfig.set("disabled",true);
			this.applyIdConfig.set("disabled",true);
		}
	},
//	onAllowChangesClick: function(event ){
//		this._allowOnChange = true;
//		return true;
//	},
	onAuthorizedChange: function(v){
		if(v && this.unitBanned.get("checked")){
			this.unitBanned.set("checked", false);
		}
	},
	onBannedChange: function(v){
		if(v && this.unitAuthorized.get("checked")){
			this.unitAuthorized.set("checked", false);
		}
	},
	setClientConfig: function(){
		var json = this.appParams.item.client_config;
		try{
			var clientConfig = dojo.fromJson(json);
			if(clientConfig != null){
				if(clientConfig.server_mode){
					this.serverModeSelect.set('value', clientConfig.server_mode);
				}else{
					this.serverModeSelect.set('value', 'none');
				}
				if(clientConfig.client_poll_interval){
					this.pollIntervalText.set('value', clientConfig.client_poll_interval);
				}else{
					this.pollIntervalText.set('value', '240');
				}
				if(clientConfig.servers[0]){
					this.GMU1Text.set('value', clientConfig.servers[0].ip);
				}else{
					this.GMU1Text.set('value', '');
				}
				if(clientConfig.servers[1]){
					this.GMU2Text.set('value', clientConfig.servers[1].ip);
				}else{
					this.GMU2Text.set('value', '');
				}
			}
			dojo.forEach(dojo.query(".unitDetailControlCB", dojo.byId(this.clientConfigForm).domNode), 
					function(n){
						dijit.getEnclosingWidget(n).set('checked', false);
			});
		}catch(e){
		}
	},
	
	updateClientConfig: function(){
		var clientConfigFormValues = this.clientConfigForm.getValues();
		//
		var hasGMU1 = (clientConfigFormValues.GMU1)?true:false;
		var hasGMU2 = (clientConfigFormValues.GMU2)?true:false;
		var hasPollInterval = (clientConfigFormValues.pollInterval)?true:false;
		var hasServerMode = (clientConfigFormValues.serverMode)?true:false;
		//
		var json = this.appParams.item.client_config;
		var clientConfig = dojo.fromJson(json);
		clientConfig = clientConfig?clientConfig:{};
		var servers = [];
		var pollInterval = (clientConfig.client_poll_interval)?clientConfig.client_poll_interval:240;
		var serverMode = (clientConfig.server_mode)?clientConfig.server_mode:'none';
		//
		if(hasGMU1){
			servers.push({"ip":clientConfigFormValues.GMU1, "type":"primary"});
		}else if(clientConfig.servers[0].ip){
			servers.push({"ip":clientConfig.servers[0].ip, "type":"primary"});
		}
		if(hasGMU2){
			servers.push({"ip":clientConfigFormValues.GMU2, "type":"secondary"});
		}
		else if(clientConfig.servers[1]){
			if(this.GMU2Text.get('value')){
				servers.push({"ip":clientConfig.servers[1].ip, "type":"secondary"});
			}
		}
		//
		if(hasServerMode){
			serverMode = clientConfigFormValues.serverMode;
		}
		if(hasPollInterval){
			pollInterval = clientConfigFormValues.pollInterval;
		}
		var clientConfigPut = {
			servers:servers,
			server_mode:serverMode,
			client_poll_interval:String(pollInterval)
		};
		this.appParams.item.client_config = dojo.toJson(clientConfigPut);
		// This is, turn on the 128 bit in mini_info_request when updating client
		this.appParams.item.mini_info_request |= 128;
		//
		_sixnet_framework.bc('access','updateViewData', { viewName: 'units', items:[this.appParams.item]}, dojo.hitch(this, function(response){
			if(response.successful){
				dojo.forEach(dojo.query(".unitDetailControlCB", dojo.byId(this.clientConfigForm).domNode), 
					function(n){
						dijit.getEnclosingWidget(n).set('checked', false);
				});
				this.setClientConfig();
        	}else{
				_sixnet_framework.log(2, response.error);
			}     	
		}));
	},
	
	turnBit: function(actionsLabel, on){
		var bit ;
		switch(actionsLabel){
			case 'miniGatherstatsRequest':
				bit = 1;
				break;
			case 'systemLogRequest':
				bit = 2;
				break;
			case 'gwlnxLogRequest':
				bit = 4;
				break;
			case 'gpsLock':
				bit = 8;
				break;
			case 'gpsMonitor':
				bit = 16;
				break;
			case 'gpsDetailRequest':
				bit = 32;
				break;
			case 'unitMiniAuth':
				bit = 128;
				break;
		}
		if(on){
			this.mini_info_request = this.mini_info_request | bit;

		}else{
			this.mini_info_request = this.mini_info_request & (~bit);
		}
		this.appParams.item.mini_info_request = ""+this.mini_info_request+"";
		if(typeof(bit) == "number"){
			_sixnet_framework.bc('access','updateViewData', { viewName: 'units', items:[this.appParams.item]}, dojo.hitch(this, function(response){
				if(response.successful){
					_sixnet_framework.log(3, response.data);
					this.updateClientConfig();
	        	}else{
					_sixnet_framework.log(3, response.error);
				}     	
			}));
		}
	},
	
	setCheckBoxState: function(bits){
//		define ( 'UNIT_MINI_GATHER', 1 );
//		define ( 'UNIT_MINI_SLOG', 2 );
//		define ( 'UNIT_MINI_GLOG', 4 );
//		define ( 'UNIT_MINI_GPSLOCK', 8 );
//		define ( 'UNIT_MINI_GPSMONITOR', 16 );
//		define ( 'UNIT_MINI_GPSDETAIL', 32 );
//		define ( 'UNIT_MINI_RAPID_RF', 64 );
//		define ( 'UNIT_MINI_AUTH', 128 );
		if((bits & 1)>0){
			this.miniGatherstatsRequest.set('checked', true);
		}
		if((bits & 2)>0){
			this.systemLogRequest.set('checked', true);
		}
		if((bits & 4)>0){
			this.gwlnxLogRequest.set('checked', true);
		}
		if((bits & 8)>0){
			this.gpsLock.set('checked', true);
		}
		if((bits & 16)>0){
			this.gpsMonitor.set('checked', true);
		}
		if((bits & 32)>0){
			this.gpsDetailRequest.set('checked', true);
		}
		//unitDetailMiniAuthCB
//		if((bits & 64)>0){
//			_sixnet_framework.log(3, "UNIT_MINI_RAPID_RF");
//		}
//		if((bits & 128)>0){
//			this.unitMiniAuth.set('checked', true);
//		}
	},
	
	doSerial: function(templateNode, attributeValue){
		templateNode.set('content', '');
		var completeCP = new dijit.layout.ContentPane({});
		var serialCP = new dijit.layout.ContentPane({content:attributeValue, style:"float:left; clear:both; width:100%; height:auto"}).placeAt(completeCP.domNode, "last");
		var H = "<img title='history' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/H.gif\" />");
		var historyCP = new dijit.layout.ContentPane({style:'float:left; clear:none; margin-left:2px; width:12px; cursor:pointer;', content: H, onClick: dojo.hitch(this, function(item){
			_sixnet_framework.getDash().runApp( 'com.sixnet.services.modules.access.unitHistory', {item:item, background: false});
		}, this.appParams.item)}).placeAt(completeCP.domNode, "last");
		if(this.appParams.item.authorized == 'TRUE'){
			var J = "<img title='add job' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/J.gif\" />"); 
			var jCP = new dijit.layout.ContentPane({style:'float:left; clear:none; width:12px; margin-left:2px; cursor:pointer;', content: J, onClick: dojo.hitch(this, function(item){
				_sixnet_framework.getDash().runApp('com.sixnet.services.modules.access.jobAdd', item);
			}, this.appParams.item)}).placeAt(completeCP.domNode, "last");
		}
		completeCP.placeAt(templateNode.domNode);
	},
	
	unitHasAttributeCheckbox: function(templateNode, attributeValue){
		templateNode.set('content', '');
		if(typeof(attributeValue) != 'undefined'){
			templateNode.set('checked', (attributeValue=='TRUE'?true:false));
		}else{
			templateNode.set('checked', false);
		}
	},
	
	unitHasAttributeTextBox: function(templateNode, attributeValue){
		if(typeof(attributeValue) != 'undefined'){
			templateNode.setValue(attributeValue);
		}
	},
	
	unitHasAttribute: function(templateNode, attributeValue, emptyMessage){
		templateNode.set('content', '');
		if('undefined' == typeof(emptyMessage)){
			emptyMessage = '<span style="opacity:.4; filter:alpha(opacity=40)">not provided</span>';
		}
		if(typeof(attributeValue) != 'undefined'){
			templateNode.set("content", attributeValue.toString());
		}else{
			templateNode.set("content", emptyMessage);	
		}
	},
	
	unitHasAttributeDHMS: function(templateNode, attributeValue){
		if(attributeValue){
			var time = attributeValue;
			var days = Math.floor(time / 86400);
			var hours = Math.floor((time % 86400) / 3600);
			var minutes = Math.floor(((time % 86400) % 3600) / 60);
			var seconds = ((time % 86400) % 3600) % 60;
			var formattedTime = ""+days+"d "+hours+"h "+minutes+"m "+seconds+"s";
			templateNode.set("content", formattedTime);
		}else{
			templateNode.set("content", '<span style="opacity:.4; filter:alpha(opacity=40)">not provided</span>');	
		}
	},
	
	unitHasAttributeTF: function(templateNode, attributeValue){
		if(attributeValue != '' && attributeValue != 'undefined'){
			if(attributeValue == "TRUE"){
				templateNode.set("content", "YES");
			}else{
				templateNode.set("content", "NO");
			}
		}else{
			templateNode.set("content", '<span style="opacity:.4; filter:alpha(opacity=40)">not provided</span>');
		}
	},
	
	epochToHuman: function(attributeValue){
//		1269466008
		if(attributeValue){
			var zdate = new Date(attributeValue*1000);
			var formattedDate = dojo.date.locale.format( zdate, { datePattern: "M/d/y"} );
			this.checkInDate = formattedDate;
			return formattedDate;
		}
	},
	
	unitCellLightbarSignal: function(templateNode, attributeValue){
		if(attributeValue == null || attributeValue == ''){
			attributeValue = "x";
		}
		var lightbarPic = "<img src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/signal");
		// graphic ...x.gif == ...0.gif
		lightbarPic = lightbarPic.concat(attributeValue).concat(".gif\" />");
		templateNode.set("content", "<div style=\"text-align:center; margin:auto\">".concat(lightbarPic).concat("</div>"));
	},
	
	populateDataUsage: function(){
		//TODO
		var id = (this.appParams.item.originalItem)? this.appParams.item.originalItem.id:this.appParams.item.id;
		_sixnet_framework.bc('access', 'getViewData', { 
			viewName:'units', 
			startingOffset: 0,
			sort: [],
			mode:'=', 
			maxCount:-1,
			query: {
				id: id
			}
			
		}, dojo.hitch(this, function(){
			_sixnet_framework.log(1, 'success populate data usage: ', arguments);
		}), dojo.hitch(this, function(){
			_sixnet_framework.log(1, 'failure', arguments);
		}));
	},
	_getAddedBy: function(){
		// TODO: Complete request for addedby
		_sixnet_framework.bc('access', 'getViewData', { 
			viewName:'users', 
			startingOffset: 0,
			sort: [],
			mode:'=', 
			maxCount:-1,
			query: {
				left_field:'id',
				operator: '=',
				right_value:this.appParams.item.added_by
			}
			
		}, dojo.hitch(this, function(response){
			if(response.successful){
				this.unitHasAttribute(this.authorizedBy, response.data.items[0].username);
			}else{
				this.unitHasAttribute(this.authorizedBy, 'Access denied');
			}
			_sixnet_framework.log(1, 'success-addedby', arguments);
		}), dojo.hitch(this, function(){
			_sixnet_framework.log(1, 'failure-addedby', arguments)
		}));
	},
	gpsBreakdown: function(gpsJson){
		var gpsHtml ;
		for(var i = 0; i < gpsJson.length; i++){
			gpsHtml += gpsJson[i];
		}
		dojo.attr(this.GPS,{content:gpsHtml});
	},
	
//	buildWidgetThumbnailPane: function(){
//		this.iconPath = this.buildIconImage().concat('<span class="serial">').concat(this.appParams.item.serial).concat('</span>');
//		return new dijit.layout.ContentPane({content:this.iconPath});
//	}
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce thumbnail in "Running Apps" pane on side of dashboard
		this.inherited(arguments);
		this.iconPath = this.buildIconImage().concat('<div class="serial">').concat(this.appParams.item.serial).concat('</div>');

		return new dijit.layout.ContentPane({content:this.iconPath});
	}

});

}

if(!dojo._hasResource["dojo.io.iframe"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.io.iframe"] = true;
dojo.provide("dojo.io.iframe");

/*=====
dojo.declare("dojo.io.iframe.__ioArgs", dojo.__IoArgs, {
	constructor: function(){
		//	summary:
		//		All the properties described in the dojo.__ioArgs type, apply
		//		to this type. The following additional properties are allowed
		//		for dojo.io.iframe.send():
		//	method: String?
		//		The HTTP method to use. "GET" or "POST" are the only supported
		//		values.  It will try to read the value from the form node's
		//		method, then try this argument. If neither one exists, then it
		//		defaults to POST.
		//	handleAs: String?
		//		Specifies what format the result data should be given to the
		//		load/handle callback. Valid values are: text, html, xml, json,
		//		javascript. IMPORTANT: For all values EXCEPT html and xml, The
		//		server response should be an HTML file with a textarea element.
		//		The response data should be inside the textarea element. Using an
		//		HTML document the only reliable, cross-browser way this
		//		transport can know when the response has loaded. For the html
		//		handleAs value, just return a normal HTML document.  NOTE: xml
		//		is now supported with this transport (as of 1.1+); a known issue
		//		is if the XML document in question is malformed, Internet Explorer
		//		will throw an uncatchable error.
		//	content: Object?
		//		If "form" is one of the other args properties, then the content
		//		object properties become hidden form form elements. For
		//		instance, a content object of {name1 : "value1"} is converted
		//		to a hidden form element with a name of "name1" and a value of
		//		"value1". If there is not a "form" property, then the content
		//		object is converted into a name=value&name=value string, by
		//		using dojo.objectToQuery().
		this.method = method;
		this.handleAs = handleAs;
		this.content = content;
	}
});
=====*/

dojo.io.iframe = {
	// summary: 
	//		Sends an Ajax I/O call using and Iframe (for instance, to upload files)
	
	create: function(/*String*/fname, /*String*/onloadstr, /*String?*/uri){
		//	summary:
		//		Creates a hidden iframe in the page. Used mostly for IO
		//		transports.  You do not need to call this to start a
		//		dojo.io.iframe request. Just call send().
		//	fname: String
		//		The name of the iframe. Used for the name attribute on the
		//		iframe.
		//	onloadstr: String
		//		A string of JavaScript that will be executed when the content
		//		in the iframe loads.
		//	uri: String
		//		The value of the src attribute on the iframe element. If a
		//		value is not given, then dojo/resources/blank.html will be
		//		used.
		if(window[fname]){ return window[fname]; }
		if(window.frames[fname]){ return window.frames[fname]; }
		var cframe = null;
		var turi = uri;
		if(!turi){
			if(dojo.config["useXDomain"] && !dojo.config["dojoBlankHtmlUrl"]){
				console.warn("dojo.io.iframe.create: When using cross-domain Dojo builds,"
					+ " please save dojo/resources/blank.html to your domain and set djConfig.dojoBlankHtmlUrl"
					+ " to the path on your domain to blank.html");
			}
			turi = (dojo.config["dojoBlankHtmlUrl"]||dojo.moduleUrl("dojo", "resources/blank.html"));
		}
		var ifrstr = dojo.isIE ? '<iframe name="'+fname+'" src="'+turi+'" onload="'+onloadstr+'">' : 'iframe';
		cframe = dojo.doc.createElement(ifrstr);
		with(cframe){
			name = fname;
			setAttribute("name", fname);
			id = fname;
		}
		dojo.body().appendChild(cframe);
		window[fname] = cframe;
	
		with(cframe.style){
			if(!(dojo.isSafari < 3)){
				//We can't change the src in Safari 2.0.3 if absolute position. Bizarro.
				position = "absolute";
			}
			left = top = "1px";
			height = width = "1px";
			visibility = "hidden";
		}

		if(!dojo.isIE){
			this.setSrc(cframe, turi, true);
			cframe.onload = new Function(onloadstr);
		}

		return cframe;
	},

	setSrc: function(/*DOMNode*/iframe, /*String*/src, /*Boolean*/replace){
		//summary:
		//		Sets the URL that is loaded in an IFrame. The replace parameter
		//		indicates whether location.replace() should be used when
		//		changing the location of the iframe.
		try{
			if(!replace){
				if(dojo.isWebKit){
					iframe.location = src;
				}else{
					frames[iframe.name].location = src;
				}
			}else{
				// Fun with DOM 0 incompatibilities!
				var idoc;
				//WebKit > 521 corresponds with Safari 3, which started with 522 WebKit version.
				if(dojo.isIE || dojo.isWebKit > 521){
					idoc = iframe.contentWindow.document;
				}else if(dojo.isSafari){
					idoc = iframe.document;
				}else{ //  if(d.isMozilla){
					idoc = iframe.contentWindow;
				}
	
				//For Safari (at least 2.0.3) and Opera, if the iframe
				//has just been created but it doesn't have content
				//yet, then iframe.document may be null. In that case,
				//use iframe.location and return.
				if(!idoc){
					iframe.location = src;
					return;
				}else{
					idoc.location.replace(src);
				}
			}
		}catch(e){ 
			console.log("dojo.io.iframe.setSrc: ", e); 
		}
	},

	doc: function(/*DOMNode*/iframeNode){
		//summary: Returns the document object associated with the iframe DOM Node argument.
		var doc = iframeNode.contentDocument || // W3
			(
				(
					(iframeNode.name) && (iframeNode.document) && 
					(dojo.doc.getElementsByTagName("iframe")[iframeNode.name].contentWindow) &&
					(dojo.doc.getElementsByTagName("iframe")[iframeNode.name].contentWindow.document)
				)
			) ||  // IE
			(
				(iframeNode.name)&&(dojo.doc.frames[iframeNode.name])&&
				(dojo.doc.frames[iframeNode.name].document)
			) || null;
		return doc;
	},

	send: function(/*dojo.io.iframe.__ioArgs*/args){
		//summary: 
		//		Function that sends the request to the server.
		//		This transport can only process one send() request at a time, so if send() is called
		//multiple times, it will queue up the calls and only process one at a time.
		if(!this["_frame"]){
			this._frame = this.create(this._iframeName, dojo._scopeName + ".io.iframe._iframeOnload();");
		}

		//Set up the deferred.
		var dfd = dojo._ioSetArgs(
			args,
			function(/*Deferred*/dfd){
				//summary: canceller function for dojo._ioSetArgs call.
				dfd.canceled = true;
				dfd.ioArgs._callNext();
			},
			function(/*Deferred*/dfd){
				//summary: okHandler function for dojo._ioSetArgs call.
				var value = null;
				try{
					var ioArgs = dfd.ioArgs;
					var dii = dojo.io.iframe;
					var ifd = dii.doc(dii._frame);
					var handleAs = ioArgs.handleAs;

					//Assign correct value based on handleAs value.
					value = ifd; //html
					if(handleAs != "html"){
						if(handleAs == "xml"){
							//	FF, Saf 3+ and Opera all seem to be fine with ifd being xml.  We have to
							//	do it manually for IE.  Refs #6334.
							if(dojo.isIE){
								dojo.query("a", dii._frame.contentWindow.document.documentElement).orphan();
								var xmlText=(dii._frame.contentWindow.document).documentElement.innerText;
								xmlText=xmlText.replace(/>\s+</g, "><");
								xmlText=dojo.trim(xmlText);
								//Reusing some code in base dojo for handling XML content.  Simpler and keeps
								//Core from duplicating the effort needed to locate the XML Parser on IE.
								var fauxXhr = { responseText: xmlText };
								value = dojo._contentHandlers["xml"](fauxXhr); // DOMDocument
							}
						}else{
							value = ifd.getElementsByTagName("textarea")[0].value; //text
							if(handleAs == "json"){
								value = dojo.fromJson(value); //json
							}else if(handleAs == "javascript"){
								value = dojo.eval(value); //javascript
							}
						}
					}
				}catch(e){
					value = e;
				}finally{
					ioArgs._callNext();				
				}
				return value;
			},
			function(/*Error*/error, /*Deferred*/dfd){
				//summary: errHandler function for dojo._ioSetArgs call.
				dfd.ioArgs._hasError = true;
				dfd.ioArgs._callNext();
				return error;
			}
		);

		//Set up a function that will fire the next iframe request. Make sure it only
		//happens once per deferred.
		dfd.ioArgs._callNext = function(){
			if(!this["_calledNext"]){
				this._calledNext = true;
				dojo.io.iframe._currentDfd = null;
				dojo.io.iframe._fireNextRequest();
			}
		}

		this._dfdQueue.push(dfd);
		this._fireNextRequest();
		
		//Add it the IO watch queue, to get things like timeout support.
		dojo._ioWatch(
			dfd,
			function(/*Deferred*/dfd){
				//validCheck
				return !dfd.ioArgs["_hasError"];
			},
			function(dfd){
				//ioCheck
				return (!!dfd.ioArgs["_finished"]);
			},
			function(dfd){
				//resHandle
				if(dfd.ioArgs._finished){
					dfd.callback(dfd);
				}else{
					dfd.errback(new Error("Invalid dojo.io.iframe request state"));
				}
			}
		);

		return dfd;
	},

	_currentDfd: null,
	_dfdQueue: [],
	_iframeName: dojo._scopeName + "IoIframe",

	_fireNextRequest: function(){
		//summary: Internal method used to fire the next request in the bind queue.
		try{
			if((this._currentDfd)||(this._dfdQueue.length == 0)){ return; }
			//Find next deferred, skip the canceled ones.
			do{
				var dfd = this._currentDfd = this._dfdQueue.shift();
			} while(dfd && dfd.canceled && this._dfdQueue.length);

			//If no more dfds, cancel.
			if(!dfd || dfd.canceled){
				this._currentDfd =  null;
				return;
			}

			var ioArgs = dfd.ioArgs;
			var args = ioArgs.args;

			ioArgs._contentToClean = [];
			var fn = dojo.byId(args["form"]);
			var content = args["content"] || {};
			if(fn){
				if(content){
					// if we have things in content, we need to add them to the form
					// before submission
					var pHandler = function(name, value) {
						var tn;
						if(dojo.isIE){
							tn = dojo.doc.createElement("<input type='hidden' name='"+name+"'>");
						}else{
							tn = dojo.doc.createElement("input");
							tn.type = "hidden";
							tn.name = name;
						}
						tn.value = value;
						fn.appendChild(tn);
						ioArgs._contentToClean.push(name);
					};
					for(var x in content){
						var val = content[x];
						if(dojo.isArray(val) && val.length > 1){
							var i;
							for (i = 0; i < val.length; i++) {
								pHandler(x,val[i]);
							}
						}else{
							if(!fn[x]){
								pHandler(x,val);
							}else{
								fn[x].value = val;
							}
						}
					}
				}
				//IE requires going through getAttributeNode instead of just getAttribute in some form cases, 
				//so use it for all.  See #2844
				var actnNode = fn.getAttributeNode("action");
				var mthdNode = fn.getAttributeNode("method");
				var trgtNode = fn.getAttributeNode("target");
				if(args["url"]){
					ioArgs._originalAction = actnNode ? actnNode.value : null;
					if(actnNode){
						actnNode.value = args.url;
					}else{
						fn.setAttribute("action",args.url);
					}
				}
				if(!mthdNode || !mthdNode.value){
					if(mthdNode){
						mthdNode.value= (args["method"]) ? args["method"] : "post";
					}else{
						fn.setAttribute("method", (args["method"]) ? args["method"] : "post");
					}
				}
				ioArgs._originalTarget = trgtNode ? trgtNode.value: null;
				if(trgtNode){
					trgtNode.value = this._iframeName;
				}else{
					fn.setAttribute("target", this._iframeName);
				}
				fn.target = this._iframeName;
				dojo._ioNotifyStart(dfd);
				fn.submit();
			}else{
				// otherwise we post a GET string by changing URL location for the
				// iframe
				var tmpUrl = args.url + (args.url.indexOf("?") > -1 ? "&" : "?") + ioArgs.query;
				dojo._ioNotifyStart(dfd);
				this.setSrc(this._frame, tmpUrl, true);
			}
		}catch(e){
			dfd.errback(e);
		}
	},

	_iframeOnload: function(){
		var dfd = this._currentDfd;
		if(!dfd){
			this._fireNextRequest();
			return;
		}

		var ioArgs = dfd.ioArgs;
		var args = ioArgs.args;
		var fNode = dojo.byId(args.form);
	
		if(fNode){
			// remove all the hidden content inputs
			var toClean = ioArgs._contentToClean;
			for(var i = 0; i < toClean.length; i++) {
				var key = toClean[i];
				//Need to cycle over all nodes since we may have added
				//an array value which means that more than one node could
				//have the same .name value.
				for(var j = 0; j < fNode.childNodes.length; j++){
					var chNode = fNode.childNodes[j];
					if(chNode.name == key){
						dojo.destroy(chNode);
						break;
					}
				}
			}

			// restore original action + target
			if(ioArgs["_originalAction"]){
				fNode.setAttribute("action", ioArgs._originalAction);
			}
			if(ioArgs["_originalTarget"]){
				fNode.setAttribute("target", ioArgs._originalTarget);
				fNode.target = ioArgs._originalTarget;
			}
		}

		ioArgs._finished = true;
	}
}

}

if(!dojo._hasResource["dojox.form.FileInput"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.form.FileInput"] = true;
dojo.provide("dojox.form.FileInput");
dojo.experimental("dojox.form.FileInput"); 


 

dojo.declare("dojox.form.FileInput",
	dijit.form._FormWidget,
	{
	// summary: A styled input type="file"
	//
	// description: A input type="file" form widget, with a button for uploading to be styled via css,
	//	a cancel button to clear selection, and FormWidget mixin to provide standard dijit.form.Form
	//	support (FIXME: maybe not fully implemented) 

	// label: String
	//	the title text of the "Browse" button
	label: "Browse ...",

	// cancelText: String
	//	the title of the "Cancel" button
	cancelText: "Cancel",

	// name: String
	//	ugh, this should be pulled from this.domNode
	name: "uploadFile",

	templateString: dojo.cache("dojox.form", "resources/FileInput.html", "<div class=\"dijitFileInput\">\n\t<input id=\"${id}\" class=\"dijitFileInputReal\" type=\"file\" dojoAttachPoint=\"fileInput\" name=\"${name}\" />\n\t<div class=\"dijitFakeInput\">\n\t\t<input class=\"dijitFileInputVisible\" type=\"text\" dojoAttachPoint=\"focusNode, inputNode\" />\n\t\t<div class=\"dijitInline dijitFileInputText\" dojoAttachPoint=\"titleNode\">${label}</div>\n\t\t<div class=\"dijitInline dijitFileInputButton\" dojoAttachPoint=\"cancelNode\" \n\t\t\tdojoAttachEvent=\"onclick:reset\">${cancelText}</div>\n\t</div>\n</div>\n"),
	
	startup: function(){
		// summary: listen for changes on our real file input
		this._listener = this.connect(this.fileInput,"onchange","_matchValue");
		this._keyListener = this.connect(this.fileInput,"onkeyup","_matchValue");
	},

	//get rid of the this.connect in _FormWidget.postCreate to allow IE to show
	//the file picker dialog properly
	postCreate: function(){},
	
	_matchValue: function(){
		// summary: set the content of the upper input based on the semi-hidden file input
		this.inputNode.value = this.fileInput.value;
		if(this.inputNode.value){
			this.cancelNode.style.visibility = "visible";
			dojo.fadeIn({ node: this.cancelNode, duration:275 }).play();
		}
	},

	setLabel: function(/* String */label,/* String? */cssClass){
		// summary: method to allow use to change button label
		this.titleNode.innerHTML = label;
	},

	reset: function(/* Event */e){
		// summary: on click of cancel button, since we can't clear the input because of
		// 	security reasons, we destroy it, and add a new one in it's place.
		this.disconnect(this._listener);
		this.disconnect(this._keyListener);
		if(this.fileInput){
			this.domNode.removeChild(this.fileInput);
		}
		dojo.fadeOut({ node: this.cancelNode, duration:275 }).play(); 

		// should we use cloneNode()? can we?
		this.fileInput = document.createElement('input');
		// dojo.attr(this.fileInput,{
		//	"type":"file", "id":this.id, "name": this.name	
		//});
		this.fileInput.setAttribute("type","file");
		this.fileInput.setAttribute("id", this.id);
		this.fileInput.setAttribute("name", this.name);
		dojo.addClass(this.fileInput,"dijitFileInputReal");
		this.domNode.appendChild(this.fileInput);

		this._keyListener = this.connect(this.fileInput, "onkeyup", "_matchValue");
		this._listener = this.connect(this.fileInput, "onchange", "_matchValue"); 
		this.inputNode.value = ""; 
	}

});

}

if(!dojo._hasResource["dojox.form.FileInputAuto"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.form.FileInputAuto"] = true;
dojo.provide("dojox.form.FileInputAuto");


 

dojo.declare("dojox.form.FileInputAuto",
	dojox.form.FileInput,
	{
	// summary: An extension on dojox.form.FileInput providing background upload progress
	//
	// description: An extended version of FileInput - when the user focuses away from the input
	//	the selected file is posted via dojo.io.iframe to the url. example implementation
	//	comes with PHP solution for handling upload, and returning required data.
	//	
	// notes: the return data from the io.iframe is used to populate the input element with 
	//	data regarding the results. it will be a JSON object, like:
	//	
	//	results = { size: "1024", filename: "file.txt" }
	//	
	//	all the parameters allowed to dojox.form.FileInput apply

	// url: String
	// 	the URL where our background FileUpload will be sent
	url: "",

	// blurDelay: Integer
	//	time in ms before an un-focused widget will wait before uploading the file to the url="" specified
	//	default: 2 seconds
	blurDelay: 2000,

	// duration: Integer
	//	The time in ms to use as the generic timing mechanism for the animations
	//	set to 1 or 0 for "immediate respose"
	duration: 500,

	// uploadMessage: String
	//	
	//	FIXME: i18n somehow?
	uploadMessage: "Uploading ...", 
	
	// triggerEvent: String
	//		Event which triggers the upload. Defaults to onblur, sending the file selected
	//		'blurDelay' milliseconds after losing focus. Set to "onchange" with a low blurDelay
	// 		to send files immediately after uploading.
	triggerEvent: "onblur",
	
	_sent: false,
	
	// small template changes, new attachpoint: overlay
	templateString: dojo.cache("dojox.form", "resources/FileInputAuto.html", "<div class=\"dijitFileInput\">\n\t<input id=\"${id}\" name=\"${name}\" class=\"dijitFileInputReal\" type=\"file\" dojoAttachPoint=\"fileInput\" />\n\t<div class=\"dijitFakeInput\" dojoAttachPoint=\"fakeNodeHolder\">\n\t\t<input class=\"dijitFileInputVisible\" type=\"text\" dojoAttachPoint=\"focusNode, inputNode\" />\n\t\t<div class=\"dijitInline dijitFileInputText\" dojoAttachPoint=\"titleNode\">${label}</div>\n\t\t<div class=\"dijitInline dijitFileInputButton\" dojoAttachPoint=\"cancelNode\" dojoAttachEvent=\"onclick:reset\">${cancelText}</div>\n\t</div>\n\t<div class=\"dijitProgressOverlay\" dojoAttachPoint=\"overlay\">&nbsp;</div>\n</div>\n"),
	
	onBeforeSend: function(){
		// summary: Called immediately before a FileInput sends it's file via io.iframe.send. 
		//		The return of this function is passed as the `content` member in the io.iframe IOArgs
		//		object.
		return {};
	},
	
	startup: function(){
		// summary: add our extra blur listeners
		this._blurListener = this.connect(this.fileInput, this.triggerEvent, "_onBlur");
		this._focusListener = this.connect(this.fileInput, "onfocus", "_onFocus"); 
		this.inherited(arguments);
	},

	_onFocus: function(){
		// summary: clear the upload timer
		if(this._blurTimer){ clearTimeout(this._blurTimer); }
	},

	_onBlur: function(){
		// summary: start the upload timer
		if(this._blurTimer){ clearTimeout(this._blurTimer); }
		if(!this._sent){
			this._blurTimer = setTimeout(dojo.hitch(this,"_sendFile"),this.blurDelay);		
		}
	},

	setMessage: function(/*String*/title){
		// summary: set the text of the progressbar
		
		// innerHTML throws errors in IE! so use DOM manipulation instead
		//this.overlay.innerHTML = title;
		this.overlay.removeChild(this.overlay.firstChild);
		this.overlay.appendChild(document.createTextNode(title));
	},
	
	_sendFile: function(/* Event */e){
		// summary: triggers the chain of events needed to upload a file in the background.
		if(this._sent || this._sending || !this.fileInput.value){ return; }

		this._sending = true;

		dojo.style(this.fakeNodeHolder,"display","none");
		dojo.style(this.overlay,{
			opacity:0,
			display:"block"
		});

		this.setMessage(this.uploadMessage);

		dojo.fadeIn({ node: this.overlay, duration:this.duration }).play();

		var _newForm; 
		if(dojo.isIE){
			// just to reiterate, IE is a steaming pile of code. 
			_newForm = document.createElement('<form enctype="multipart/form-data" method="post">');
			_newForm.encoding = "multipart/form-data";
			
		}else{
			// this is how all other sane browsers do it
			_newForm = document.createElement('form');
			_newForm.setAttribute("enctype","multipart/form-data");
		}
		_newForm.appendChild(this.fileInput);
		dojo.body().appendChild(_newForm);
	
		dojo.io.iframe.send({
			url: this.url,
			form: _newForm,
			handleAs: "json",
			handle: dojo.hitch(this,"_handleSend"),
			content: this.onBeforeSend()
		});
	},
	
	_handleSend: function(data,ioArgs){
		// summary: The callback to toggle the progressbar, and fire the user-defined callback

		// innerHTML throws errors in IE! so use DOM manipulation instead
		this.overlay.removeChild(this.overlay.firstChild);
		
		this._sent = true;
		this._sending = false;
		dojo.style(this.overlay,{
			opacity:0,
			border:"none",
			background:"none"
		}); 

		this.overlay.style.backgroundImage = "none";
		this.fileInput.style.display = "none";
		this.fakeNodeHolder.style.display = "none";
		dojo.fadeIn({ node:this.overlay, duration:this.duration }).play(250);

		this.disconnect(this._blurListener);
		this.disconnect(this._focusListener);

		//remove the form used to send the request
		dojo.body().removeChild(ioArgs.args.form);
		this.fileInput = null;

		this.onComplete(data,ioArgs,this);
	},

	reset: function(e){
		// summary: accomodate our extra focusListeners
		if(this._blurTimer){ clearTimeout(this._blurTimer); }

		this.disconnect(this._blurListener);
		this.disconnect(this._focusListener);

		this.overlay.style.display = "none";
		this.fakeNodeHolder.style.display = "";
		this.inherited(arguments);
		this._sent = false;
		this._sending = false;
		this._blurListener = this.connect(this.fileInput, this.triggerEvent,"_onBlur");
		this._focusListener = this.connect(this.fileInput,"onfocus","_onFocus"); 
	},

	onComplete: function(data,ioArgs,widgetRef){
		// summary: stub function fired when an upload has finished. 
		// data: the raw data found in the first [TEXTAREA] tag of the post url
		// ioArgs: the dojo.Deferred data being passed from the handle: callback
		// widgetRef: this widget pointer, so you can set this.overlay to a completed/error message easily
	}
});

dojo.declare("dojox.form.FileInputBlind",
	dojox.form.FileInputAuto,
	{
	// summary: An extended version of dojox.form.FileInputAuto
	//	that does not display an input node, but rather only a button
	// 	and otherwise behaves just like FileInputAuto
	
	startup: function(){
		// summary: hide our fileInput input field
		this.inherited(arguments);
		this._off = dojo.style(this.inputNode,"width");
		this.inputNode.style.display = "none";
		this._fixPosition();
	},
	
	_fixPosition: function(){		
		// summary: in this case, set the button under where the visible button is 
		if(dojo.isIE){
			dojo.style(this.fileInput,"width","1px");
		}else{
			dojo.style(this.fileInput,"left","-"+(this._off)+"px");
		}
	},

	reset: function(e){
		// summary: onclick, we need to reposition our newly created input type="file"
		this.inherited(arguments);
		this._fixPosition(); 
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.unitHistory']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.unitHistory'] = true;
dojo.provide('com.sixnet.services.modules.access.unitHistory');












//


//dojo.require("dojo.io.*");



dojo.declare('com.sixnet.services.modules.access.unitHistory', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div dojoType=\"com.sixnet.services.core.data.writeStore\" jsid=\"unitHistoryStore\" identifier=\"id\" module=\"access\" viewName=\"unit_history\" >\n\t</div>\n\t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:100%; margin-right:15px; border:none;\" gutters=\"false\">\n\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" gutters=\"false\">\t\t\n\t\t\t<div\n\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGrid\" \n\t\t\t\tjsId=\"unitHistoryGrid\"\n\t\t\t\tmodule=\"access\" \n\t\t\t\teditRole=\"ROLE_UNIT_ADMIN\" \n\t\t\t\tcells=\"{ name:'Roles', formatter: 'assignRoles'}\" \n\t\t\t\tviewRole=\"ROLE_UNIT_VIEWER\"\n\t\t\t\tquery=\"{ left_expression:{ left_field:'serial', operator:'=', right_value:'${searchSerial}'}, operator:'AND', right_expression: { left_field:'architecture', operator:'=', right_value:'${searchArchitecture}'}}\" \n\t\t\t\tformatterClass=\"com.sixnet.services.modules.unit.formatters\" \n\t\t\t\tstore=\"unitHistoryStore\" \n\t\t\t\tregion=\"center\" \n\t\t\t\tviewName=\"unit_history\" \n\t\t\t\tshowSaveView=\"true\" \n\t\t\t\tshowContextMenu=\"true\" \n\t\t\t\tdojoAttachPoint=\"unitHistoryGrid\"\n\t\t\t\tclass=\"gridIE\"\n\t\t\t\t>\n\t\t\t\t<div\t\n\t\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridCheckSearch\"\n\t\t\t\t\t\tgrid=\"unitHistoryGrid\"\n\t\t\t\t\t\t>\n\t\t\t\t\t</div>\n\t\t\t</div>\t\t\n\t\t</div>\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; padding-top:2px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	currentunit:false,
	currentPermissions:false,
	unit:false, /*unit is rowItem*/
	stackController:false,
	icon: 'unit_history.png',
	iconPath: '',
	appParams: {},
	originalItem:null,
	
	constructor: function(mixin){
		this.originalItem = mixin.appParams.item;
		this.searchArchitecture = mixin.appParams.item.architecture;
		this.searchSerial = mixin.appParams.item.serial;
	},
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this._subscribes.push( dojo.subscribe( '/status/hint', dojo.hitch(this.statusLine, "setContent")));
	},
	
	onFormatSerial: function(item, serialPane){
		// Applies everywhere there is a serial number
		item.isHistory = true;
		item.originalItem = this.originalItem;
		var D = "<img title='details' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/D.gif\" />");
		var detailCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; cursor:pointer;', content:D, onClick: dojo.hitch(this, function(item){
			_sixnet_framework.getDash().runApp( 'com.sixnet.services.modules.access.unitDetail', {item:item, background: false});
		}, item)});
		//  6.13.10 Neil. Adding images as the text is not showing in IE.
		detailCP.placeAt(serialPane.domNode, "last");
	},
	
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce thumbnail in "Running Apps" pane on side of dashboard
		this.inherited(arguments);
		this.iconPath = this.buildIconImage().concat('<div class="serial">').concat(this.appParams.item.serial).concat('</div>');

		return new dijit.layout.ContentPane({content:this.iconPath});
	},
	
	onunitRowClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		var rowItem = this.unitGrid.grid.getItem( event.rowIndex);
		this.unit = rowItem;
		var message = "";
		if(event.cell.editable){
			message = "Double-click to edit unit detail";
		}
		dojo.publish( '/status/hint', [message]);
		//dojo.removeClass( this.unitToolbar.removeButton.focusNode, "disabledButton");
	},
	
	onunitRowDblClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		_sixnet_framework.log(3, "DblClick ", event);
		var rowItem = this.unitGrid.grid.getItem( event.rowIndex);
		this.unit = rowItem;
		_sixnet_framework.log(3, "unit set:  ", this.unit);
		var message = "";
		if(!event.cell.editable){
			message = "This cell is not editable";
		}
		dojo.publish( '/status/hint', [message]);
	},
	
	onRemoveClick: function(){
//		if( dojo.hasClass( this.unitToolbar.removeButton.focusNode, "disabledButton")) return;
//		if( !confirm("Delete  `".concat( this.unit.unitname).concat( "` from units?"))) return;
//		_sixnet_framework.bc('access', 'removeunit', { unitId: this.unit.id }, dojo.hitch(this, function(response){
//			if( response.successful ){
//				dojo.addClass( this.unitToolbar.removeButton.focusNode, "disabledButton");
//				this.reloadGrid();
//			}
//		}));
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.unitDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.unitDash'] = true;
// tell package managerthat a specific package has been loaded
dojo.provide('com.sixnet.services.modules.access.unitDash');
// load dojo dashWidgetBash

// _Templated == mix-in Widget HTML


// simulate Class system like Java with dojo.declare 
// 3 arguments (optional_global_name, null or base class or array of objects (multiple inheritance), object hash of properties to be mixed in after all other inheritance has been solved)
// dojo.moduleUrl is used to return a dojo._Url object relative to a module.
dojo.declare('com.sixnet.services.modules.access.unitDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/unitDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){
		// attempt to make dash of own here.
//		this.dashBoard = new com.sixnet.services.core.dashBoard({ _app: dijit.byId('body')});
		// below works just fine, but is not in a dash of it's own.
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.unitManager');
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.jobManagerDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.jobManagerDash'] = true;
// tell package managerthat a specific package has been loaded
dojo.provide('com.sixnet.services.modules.access.jobManagerDash');
// load dojo dashWidgetBash

// _Templated == mix-in Widget HTML


// simulate Class system like Java with dojo.declare 
// 3 arguments (optional_global_name, null or base class or array of objects (multiple inheritance), object hash of properties to be mixed in after all other inheritance has been solved)
// dojo.moduleUrl is used to return a dojo._Url object relative to a module.
dojo.declare('com.sixnet.services.modules.access.jobManagerDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/jobDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	
	onClick: function(){

		//this.dashBoard.startedWorking();
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.jobManager');
		//this.dashBoard.stoppedWorking();	
		// end copy dash.js onClick-
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.serverUtilities']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.serverUtilities'] = true;
dojo.provide('com.sixnet.services.modules.access.serverUtilities');











//


dojo.declare('com.sixnet.services.modules.access.serverUtilities', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div dojoAttachPoint=\"SERVER_UTILITIES\">\n\t<div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">\n\t\n\t</div>\n</div>\n",
	thumbnail:false,
	icon: 'server_utilities.png',
	iconPath: '',
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.getMostRecentDBFile(dojo.hitch(this, "buildDataBaseForm"));
	},
	
	backUpFileSuccess:function(){
		
	},
	
	buildDataBaseForm: function(data){
//		this.dashBoard.stoppedWorking();
		// wipe login form
//		dijit.byId(this.loginHolder).attr({content:""});
		var filename = data;
		myParent = this;
		var dataBaseFormDialog = new dijit.Dialog({
			style:"width:310px;height:285px;",
			title:'Server Utilities'
		});
		var cp0 = new dijit.layout.ContentPane({
	        style: "height:270px; width:100%; text-align:center; margin-right:auto; margin-left:auto; overflow:hidden"
	    }).placeAt(dojo.byId(dataBaseFormDialog.domNode), "last");
		//
//		var accountDD = dojo.create("select", {style:"width:200px; margin-left:auto; margin-right:auto; font-size:14px"}, cp0.domNode);
//		dojo.create("option", {value:'', innerHTML:" - Select Account"}, accountDD);
//		for(i=0; i<data.length; i++){
//			dojo.create("option", {value:data[i].account_id, innerHTML:data[i].name}, accountDD);
//		}
//		dojo.query(dojo.byId(accountDD)).addClass("dijitComboBox");
		
		// create backupUpload for database file upload
		var backupUpload = new dojox.form.FileInputBlind({
				triggerEvent:"onchange",
					label:"Restore Database File (_.tgzip only)",
							blurDelay:"1",
								uploadMessage:"Uploading...",
									style:"height:50px; width:256px; maxWidth:256px; margin-left:auto; margin-right:auto",
										url:"test_up.php"}).placeAt(dojo.byId(cp0.domNode), "last");
		dojo.connect(backupUpload, "onComplete", function(){
			this.domNode.innerHTML = "Database file applied.";
		});
		backupUpload.startup();
		//-------------------------------------------------
		//	padding:14px 12px 14px 12px;
		// list most recent file as retrievable dbLink
		// create buttons for Create and Clear All
		// here style controls the domNode, not the actual button - use dojo.query for that.
		var dbLink = new dijit.form.Button({
			style:"margin-top:10px",
			label:"Get Latest Back-up File"}).placeAt(dojo.byId(cp0.domNode), "last");
		_sixnet_framework.log(3, dbLink, "  dbLink");
		//
		var createDBBackup = new dijit.form.Button({
			style:"margin-top:10px",
			label:"Create Database Back-up"}).placeAt(dojo.byId(cp0.domNode), "last");
		dojo.query(dojo.byId(createDBBackup.domNode)).addClass("button");
		//
		var clearAll = new dijit.form.Button({
			style:"margin-top:10px",
			label:"Clear All Back-up Files"}).placeAt(dojo.byId(cp0.domNode), "last");
		//  must query into button to style it. at declare time won't work
		var styleObj = {width:"250px", marginTop:"10px", marginBottom:"10px"};
		dojo.query("button", dbLink.domNode).attr("style", styleObj);
		dojo.query("button", createDBBackup.domNode).attr("style", styleObj);
		dojo.query("button", clearAll.domNode).attr("style", styleObj);
		//  style FileInput to match height and width of buttons
		dojo.query(".dijitFileInputText", backupUpload.domNode).attr("style", {paddingTop:"15px", paddingBottom:"15px", border:"solid 1px lightgray"});
		dojo.connect(dbLink, "onMouseOver", function(){
			//  on mouse over show the name of the latest db file.
			this.attr({label:filename});
		});
//		dojo.connect(backupUpload, "onMouseOver", function(){
//			//  on mouse over show the name of the latest db file.
//			dojo.addClass(this.domNode, ".tundra .dijitButtonHover");
//		});
//		.tundra .dijitButtonHover
		dojo.connect(dbLink, "onMouseOut", function(){
			this.attr({label:"Get Latest Back-up File"});
		});
		dojo.connect(dbLink, "onClick", function(){
			_sixnet_framework.log(3, "getDBFile()");
		});
		dojo.connect(createDBBackup, "onClick", function(){
			_sixnet_framework.log(3, "createDBBackup()");
		});
		dojo.connect(clearAll, "onClick", function(){
			_sixnet_framework.log(3, "clearAll()");
		});
		//  connect close button to destroy thumb and parent (and self)
	    dojo.connect(dataBaseFormDialog, "onCancel", this,  function(){
	    	//  if the choose account is closed just return to same working account
			this.dashBoard.showDashWidgets();
			this.destroyRecursive();
			return;
		});
		dataBaseFormDialog.show();
		//var accountChooseButton = new dijit.form.Button({label:"Choose", style:"float:right"}).placeAt(dojo.byId(cp0.domNode), "last");
//	    dojo.connect(accountDD, "onchange", this, function(){
//	    	//_sixnet_framework.log(3, accountDD.value, " value---");
//	    	this.setAccount(accountDD.value);
//	    	dataBaseFormDialog.hide();
//	    	dataBaseFormDialog.destroyRecursive();
//	    })
	},
	
	getMostRecentDBFile: function(onComplete){
		//  API *** 
		//  Grab the most recent db back-up file.
		onComplete("fake_db_backup.tar");
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.logoutDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.logoutDash'] = true;
// tell package managerthat a specific package has been loaded
dojo.provide('com.sixnet.services.modules.access.logoutDash');
// load dojo dashWidgetBash

// _Templated == mix-in Widget HTML


// simulate Class system like Java with dojo.declare 
// 3 arguments (optional_global_name, null or base class or array of objects (multiple inheritance), object hash of properties to be mixed in after all other inheritance has been solved)
// dojo.moduleUrl is used to return a dojo._Url object relative to a module.
dojo.declare('com.sixnet.services.modules.access.logoutDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/logoutDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){
		//this.dashBoard.startedWorking();
		_sixnet_framework.setSession('');
		_sixnet_framework.reloadDash();
		//this.dashBoard.stoppedWorking();
		// end copy dash.js onClick-
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.alertDefinitions']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.alertDefinitions'] = true;
dojo.provide('com.sixnet.services.modules.access.alertDefinitions');












dojo.declare('com.sixnet.services.modules.access.alertDefinitions', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div dojoAttachPoint=\"ALERT_DEFINITIONS\">\n <div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">\n \t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\"> \t\n\t<!-- File Control tab container -->\n\t<div dojoType=\"dijit.layout.TabContainer\"  dojoAttachEvent=\"selectChild:childSelected\" dojoAttachPoint=\"tabContainer\" style=\"width:100%; height:100%; margin-right:15px\" tabStrip=\"false\" tabPosition=\"left-h\">\n\t\t<!-- define alert tab -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Late Checkin\">\t<!--  closable=\"true\" -->\t\n\t\t\t<div class=\"headerLabel\">Late Checkin</div>\n\t\t\t<div class=\"introduction\">Define and view alert definitions.</div>\n\t\t\t<div style=\"float:left; clear:both; width:100%\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"float:left; width:30%\">\n\n\t\t\t<form dojoAttachPoint=\"late_checkinDefinition\" dojoType=\"dijit.form.Form\">\n                \n\t\t            <div class=\"alertFormLeft\">Min Late</div>\n\t\t            <div class=\"alertFormRight\">\n\t\t            \t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"latecheckinMin\" name=\"late_min\"></div>\n\t\t            </div>\n\t\t            <div class=\"alertFormLeft\">Action</div>\n\t\t          \t<div class=\"alertFormRight\">\n\t\t            \t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"action\" name=\"action\"></div>\n\t\t            </div>\n\t\t            <div class=\"alertFormLeft\">Target</div>\n\t\t          \t<div class=\"alertFormRight\">\n\t\t          \t\t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"target\" name=\"target\"></div>\n\t\t          \t</div>\n\t\t\n\t\t            <div class=\"alertFormLeft\">     \n\t\t        \t\t&nbsp;  \n\t\t            </div>\n\t\t           \t<div class=\"alertFormRight\">  \n            \t\t\t<div dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:onApplyDefinitionClick\" label=\"Add Definition\"></div>\n                    </div>            \n\t\t\t\n\t\t\t\n\t   \t\t</form>\n\t   \t\t</div>\n\t   \t\t<div style=\"float:left; width:640px; height:400px; overflow:auto; overflow-x:visible; min-height:300px;\" dojoAttachPoint=\"late_checkinExisting\" dojoType=\"dijit.layout.ContentPane\">\n\t   \t\t\n\t   \t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t\t\t\t<!-- define alert tab -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Crashed\">\t<!--  closable=\"true\" -->\t\n\t\t\t<div class=\"headerLabel\">Crashed</div>\n\t\t\t<div class=\"introduction\">Define and view alert definitions.</div>\n\t\t\t<div style=\"float:left; clear:both; width:100%\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"float:left; width:30%\">\n\n\t\t\t<form dojoAttachPoint=\"crashedDefinition\" dojoType=\"dijit.form.Form\">\n                \n\t\t            <div class=\"alertFormLeft\">Min Late</div>\n\t\t            <div class=\"alertFormRight\">\n\t\t            \t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"crashedMin\" name=\"crashedMin\"></div>\n\t\t            </div>\n\t\t            <div class=\"alertFormLeft\">Action</div>\n\t\t          \t<div class=\"alertFormRight\">\n\t\t            \t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"CAction\" name=\"CAction\"></div>\n\t\t            </div>\n\t\t            <div class=\"alertFormLeft\">Target</div>\n\t\t          \t<div class=\"alertFormRight\">\n\t\t          \t\t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"CTarget\" name=\"CTarget\"></div>\n\t\t          \t</div>\n\t\t\n\t\t            <div class=\"alertFormLeft\">     \n\t\t        \t\t&nbsp;  \n\t\t            </div>\n\t\t           \t<div class=\"alertFormRight\">  \n            \t\t\t<div dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:onApplyDefinitionClick\" label=\"Add Definition\"></div>\n                    </div>            \n\t\t\t\n\t\t\t\n\t   \t\t</form>\n\t   \t\t</div>\n\t   \t\t<div style=\"float:left; width:640px; height: 400px; overflow:auto; overflow-x:visible; min-height:300px;\" dojoAttachPoint=\"crashedExisting\" dojoType=\"dijit.layout.ContentPane\">\n\t   \t\t\n\t   \t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t\t\t\t\t\t<!-- define alert tab -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Low Signal\">\t<!--  closable=\"true\" -->\t\n\t\t\t<div class=\"headerLabel\">Low Signal</div>\n\t\t\t<div class=\"introduction\">Define and view alert definitions.</div>\n\t\t\t<div style=\"float:left; clear:both; width:100%\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"float:left; width:30%\">\n\n\t\t\t<form dojoAttachPoint=\"low_signalDefinition\" dojoType=\"dijit.form.Form\">\n                \n\t\t            <div class=\"alertFormLeft\">Min Late</div>\n\t\t            <div class=\"alertFormRight\">\n\t\t            \t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"low_signalMin\" name=\"low_signalMin\"></div>\n\t\t            </div>\n\t\t            <div class=\"alertFormLeft\">Action</div>\n\t\t          \t<div class=\"alertFormRight\">\n\t\t            \t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"lsAction\" name=\"lsAction\"></div>\n\t\t            </div>\n\t\t            <div class=\"alertFormLeft\">Target</div>\n\t\t          \t<div class=\"alertFormRight\">\n\t\t          \t\t<div dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"lsTarget\" name=\"lsTarget\"></div>\n\t\t          \t</div>\n\t\t\n\t\t            <div class=\"alertFormLeft\">     \n\t\t        \t\t&nbsp;  \n\t\t            </div>\n\t\t           \t<div class=\"alertFormRight\">  \n            \t\t\t<div dojoType=\"dijit.form.Button\" dojoAttachEvent=\"onClick:onApplyDefinitionClick\" label=\"Add Definition\"></div>\n                    </div>            \n\t\t\t\n\t\t\t\n\t   \t\t</form>\n\t   \t\t</div>\n\t   \t\t<div style=\"float:left; width:640px; height: 400px; overflow:auto; overflow-x:visible; min-height:300px;\" dojoAttachPoint=\"low_signalExisting\" dojoType=\"dijit.layout.ContentPane\">\n\t   \t\t\n\t   \t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\n\n\t</div>\n\t</div>\n\t<!-- end tab container -->\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none;\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n </div>\n</div>\n",
	dashBoard: false,
	currentDefinitionType: '',
	rules:null, /* set this to null because it is shared by reference */
	editing:false,
	oldEditValues:null,
	icon: 'log.png',
	iconPath: '',
	storedEditButtonNode:null,
	storedEditButtonHTML:'',
	editingPosition: -1,
	
	///////////////////
	///
	///////////
	
	///
	
	//   TODO: separate get data

	//
	
	
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		
//		//  currentDefinitionType will correlate with the sixnet_rule->name
		this._subscribes.push( dojo.subscribe( '/status/hint', dojo.hitch(this.statusLine, "setContent")));
		setTimeout(dojo.hitch(this, "ini"), 0);
	},
	
	ini: function(){
		_sixnet_framework.log(1, this.tabContainer);
		this.setCurrentDefinitionType();
		this.oldEditValues = [];
		this.getRules();		
	},
	
	setCurrentDefinitionType: function(){
		var tabName = (this.tabContainer.selectedChildWidget.title).toLowerCase();
		var splitName = tabName.split(' ');
		var storeName = '';
		for(var i = 0; i < splitName.length; i++){
			if(i > 0){
				storeName += "_";
			}
			storeName += splitName[i];
		}
		_sixnet_framework.log(1, ">>>>>>><<<<<<<     storeName: ", storeName);
		this.currentDefinitionType = storeName;
	},
	
	childSelected: function(){
		_sixnet_framework.log(1, "cS fired");
//		this.editing = false;
		this.cancelEdit();
		// TODO: clear all values of all inputs in all hidden tabs...
		this.setCurrentDefinitionType();
	},
	
	getRules: function(){
		this.rules = [];
		_sixnet_framework.bc('access', 'getAlertRules', {}, dojo.hitch(this, function(response){
			if( response.successful ){
				for(var i = 0; i < response.data.length; i++){
					_sixnet_framework.log(1, "in for.. ini");
					var name = response.data[i].name;
					var rule = response.data[i].rule;
					var id = response.data[i].id;
					this.rules.push({name:name, rule:rule, id:id});
				}
				this.displayExisting();
			}else{
				_sixnet_framework.log(1, "failed", response.error);
			}
		}));	
	},
	
	displayExisting: function(){
		//  may have to get Paul on this.
		var ruleDiv ;
		var nodeName ;
		if(this.rules.length > 0){
			for(var i = 0; i < this.rules.length; i++){
				ruleDiv = new dijit.layout.ContentPane({});
				var ruleName = this.rules[i].name;
				var ruleId = this.rules[i].id;
				//  nodeName will Always have the ruleName followed by "Existing"
				nodeName = ruleName+"Existing";
				if(this[nodeName]){
					_sixnet_framework.log(1, "nodeName: ", this[nodeName], ruleName, nodeName);
					this[nodeName].domNode.innerHTML = '';
					var ruleJSON = dojo.fromJson(this.rules[i].rule);
					this[ruleName] = ruleJSON.alerts;
					// breakdown rule and loop into dom, rulesDefinitionBox
					for(var j = 0; j < ruleJSON.alerts.length; j++){
						var ruleBox = new com.sixnet.services.widgets.rulesDefinitionBox({alerts:ruleJSON.alerts[j], arrayPosition:j});
						ruleBox.setRuleId(ruleId);
						_sixnet_framework.log(1, ruleBox.getRuleId(), " get rule id");
						this.connect(ruleBox, "onCloseWidget", "killRule");
						this.connect(ruleBox, "onEditClick", "editRule");
						this.connect(ruleBox, "onCancelEditClick", "cancelEdit");
						ruleDiv.domNode.appendChild(ruleBox.domNode);
					}
					this[nodeName].domNode.appendChild(ruleDiv.domNode);
				}
			}
		}
	},

	cancelEdit: function(){
		this.editing = false;
		this.editingPosition = -1;
		this.clearInputs();
		if(this.storedEditButtonNode != null){
			dojo.style(this.storedEditButtonNode, "display", "block");
			dojo.style(this.storedEditButtonNode.previousSibling, "display", "none");
			this.storedEditButtonNode = null;
		}
	},
	
	clearInputs: function(){
		dojo.forEach(dojo.query("input"), function(input){
			input.value = '';
		});
	},
	
	editRule: function(){
		// first we cancel edit in the case there was another active edit
		this.cancelEdit();
		var node = arguments[0].currentTarget.parentNode.parentNode.parentNode;
		_sixnet_framework.log(1, "LOOK FOR ruleEditButton:  ", arguments[0].currentTarget);
		this.storedEditButtonNode = arguments[0].currentTarget;
		dojo.style(this.storedEditButtonNode, "display", "none");
		dojo.style(this.storedEditButtonNode.previousSibling, "display", "inline");
		this.editingPosition = dijit.getEnclosingWidget(node).getPosition();
		var fieldValueInnards = dojo.query('.ruleBoxLabel', node);
		var valueValueInnards = dojo.query('.ruleBoxDetail', node);
		for(var i = 0; i < fieldValueInnards.length; i++){
			var field = fieldValueInnards[i].innerHTML;
			var value = valueValueInnards[i].innerHTML;
			_sixnet_framework.log(1, field, "  <<field:value>> ", value, "  << get 'er done n' put this stuff in the form, now!");
			var formInput = dojo.query('[name="'+field+'"]');
			_sixnet_framework.log(1, "formInput array", formInput);
			formInput[0].value = value;
			this.oldEditValues.push({field:field, value:value});
		}
		// turn on editing flag, show Cancel Edit
//		ruleEditButton
		this.editing = true;
		_sixnet_framework.log(1, fieldValueInnards, valueValueInnards);
//		var ruleId = dijit.getEnclosingWidget(arguments[0].currentTarget.parentNode.parentNode.parentNode).getRuleId();
//		_sixnet_framework.log(1, "event ediRule: ", ruleId);
	},
	
	killRule: function(){
//		var ruleId = dijit.getEnclosingWidget(arguments[0].currentTarget.parentNode.parentNode.parentNode).getRuleId();
//		_sixnet_framework.log(1, "event ediRule: ", ruleId, arguments[0].currentTarget);

//		_sixnet_framework.log(1, "event killRule: ", arguments[0]);	
		//  grab box attr of ruleId, bc call to kill, delete box entirely
		//  NEVERMIND! we have to pull ONE rule out of the alerts for this panel
		//  we need the values
		var node = arguments[0].currentTarget.parentNode.parentNode.parentNode;
		var position = dijit.getEnclosingWidget(node).getPosition();
		this.doKillthenStore(position);
	},
	
	doKillthenStore: function(position){
		// need current values as well as the values to be edited from.
//		var oldEditValues = this.oldEditValues;
		//           new        was        particularOldValues for compare
		var drules = this[this.currentDefinitionType];
		drules[position] = null;
		_sixnet_framework.log(1, "  deletePosition?? >>> ", position, drules.length);
		var tempArray = [];
		for(var i = 0; i<drules.length; i++){
			//  object to push should match stored format if everything is coherent with form
			if(drules[i] == null){
				_sixnet_framework.log(1, drules[i], "  << throw", i);
			}else{
				_sixnet_framework.log(1, drules[i], "  << keep", i);
				tempArray.push(drules[i]);
			}
		}
		// just take this out for delete function
		//     tempArray.push(formValues);
		/////////////////////////////////////////
		_sixnet_framework.log(1, "tempA.len", tempArray.length);
		this[this.currentDefinitionType] = tempArray;
		//  just in the case we had edited and then chose to delete entry
		if(this.editing){
//			this.editing = false;
			this.cancelEdit();
		}
		//  apply (could be improved) TODO
		var rule = {alerts:tempArray};
		var call = 'builtIn.call("'+this.currentDefinitionType+'", initParams);';
		_sixnet_framework.log(1, rule, " << rule | call >> ", call);
		_sixnet_framework.bc('access', 'putAlertRules', {name:this.currentDefinitionType, rule:rule, call:call}, dojo.hitch(this, function(response){
			if( response.successful ){
				this[this.currentDefinitionType] = drules;
				this.getRules();
			}else{
				alert("Something is wrong with what you have attempted to add to this definition.");
			}
		}));
	},
	
	showRuleInForm: function(){
		_sixnet_framework.log(1, "showRuleInForm");
	},
	
	ruleBox: function(prop, value){
		var box = new dijit.layout.ContentPane({});
		var propLabel = '<span class="ruleBoxLabel">'+prop+'</span>';
		var propDetail = '<span class="ruleBoxDetail">'+value+'</span>';
//		dojo.addClass(box.domNode, "ruleBox");
		dojo.attr(box.domNode, "innerHTML", propLabel+propDetail);
		return box.domNode;
	},
	
	sortEdited: function(formValues, drules){
		// need current values as well as the values to be edited from.
//		var oldEditValues = this.oldEditValues;
		//           new        was        particularOldValues for compare
		drules[this.editingPosition] = null;
		_sixnet_framework.log(1, "  editPosition?? >>> ", this.editingPosition, drules.length);
		var tempArray = [];
		for(var i = 0; i<drules.length; i++){
			//  object to push should match stored format if everything is coherent with form
			if(drules[i] == null){
				_sixnet_framework.log(1, drules[i], "  << throw", i);
			}else{
				_sixnet_framework.log(1, drules[i], "  << keep", i);
				tempArray.push(drules[i]);
			}
		}
		_sixnet_framework.log(1, "tempA.len", tempArray.length);
		this[this.currentDefinitionType] = tempArray;
		this.editing = false;
		this.onApplyDefinitionClick();
	},
	
	onApplyDefinitionClick: function(){
		var formName = this.currentDefinitionType+"Definition";
		var formValues = this[formName].getValues();
		var drules = this[this.currentDefinitionType];
		_sixnet_framework.log(1, this.editing);
		if(this.editing){
			// sort, turn off _this.editing, come back
			this.sortEdited(formValues, drules);
		}else{			
			
			if(!drules){
				drules = [];
			}
			drules.push(formValues);   
			//  verify, at the least, that we don't have empties.
			for(var i = 0; i < formValues.length; i++){
				if(formValues[i] == ''){
					alert("Empty form input detected. Correct and re-submit.");
					return;
				}
			}
			var rule = {alerts:drules};
			var call = 'builtIn.call("'+this.currentDefinitionType+'", initParams);';
			_sixnet_framework.log(1, rule, " << rule | call >> ", call);
			_sixnet_framework.bc('access', 'putAlertRules', {name:this.currentDefinitionType, rule:rule, call:call}, dojo.hitch(this, function(response){
				if( response.successful ){
					this[this.currentDefinitionType] = drules;
					//  cancelEdit will reset everything wheter or not 
					//  this stored rule was an edited rule
					this.cancelEdit();
					this.getRules();
				}else{
					alert("Something is wrong with what you have attempted to add to this definition.");
				}
			}));
		}		
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.accountManager']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.accountManager'] = true;
dojo.provide('com.sixnet.services.modules.access.accountManager');
















dojo.declare('com.sixnet.services.modules.access.accountManager', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div dojoType=\"com.sixnet.services.core.data.writeStore\"  style=\"display:hidden\" jsid=\"accountStore\" mode=\"LIKE\" identifier=\"id\" module=\"access\" viewName=\"accounts\"></div>\n\t\n\t <div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\" >\n\t \t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\"> \n\t    \t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:100%; margin:auto\" gutters=\"false\">\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\">\n\t\t\t\t\t<div\tdojoType=\"com.sixnet.services.widgets.sixnetGrid\"  \n\t\t\t\t\t\t\tjsid=\"accountGrid\" \n\t\t\t\t\t\t\tquery=\"{}\" \n\t\t\t\t\t\t\tformatterClass=\"com.sixnet.services.modules.access.formatters\" \n\t\t\t\t\t\t\tstore=\"accountStore\" \n\t\t\t\t\t\t\tmodule=\"access\" \n\t\t\t\t\t\t\tviewName=\"accounts\" \n\t\t\t\t\t\t\tshowSaveView=\"true\"\t\n\t\t\t\t\t\t\tshowContextMenu=\"true\" \n\t\t\t\t\t\t\tdojoAttachPoint=\"accountGrid\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\n\t\t\t\t\t</div>\n\t\t\t\t\t<div\t\n\t\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridCheckSearch\"\n\t\t\t\t\t\tgrid=\"accountGrid\"\n\t\t\t\t\t\t>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div\t\n\t\t\t\t\t\tdojoType=\"com.sixnet.services.modules.access.toolbarAddButton\"\n\t\t\t\t\t\tgrid=\"accountGrid\"\n\t\t\t\t\t\tdojoAttachPoint=\"addAccount\"\n\t\t\t\t\t\t>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none;\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	account:false,
	installedModules:null,
	modules:null,
	icon: 'wrld_accnt.png',
	iconPath: '',
	_viewOnly:true,
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
//		this.connect( this.dashBoard, "onHideWidget", "onHide");
//		this.currentUser = _sixnet_framework._accountId;
//		
//		// connex
//		this.connect(this.accountGrid.grid,"onClick", "onRowClick");
//		this.connect(this.accountGrid.grid,"onDblClick", "onRowDblClick");
////		this.connect(this.accountToolbar.addButton, "onClick", "onAddAccountClick");
		// IF user has admin/super
		var roles = _sixnet_framework._currentPermissions;
		var admin ;
		if(roles.access){
			admin = roles.access['ROLE_UNIT_ADMIN'];
		}
		if(admin || _sixnet_framework._super){
			this.addAccount.addButton.set("label", "Add Account");
			this.connect(this.addAccount.addButton, "onClick", "onAddAccountClick");
			this._viewOnly = false;
		}else{
			this.addAccount.destroyRecursive();
		}
		this.connect( this.accountGrid.getFormatter(), "onFormatAccount", "onFormatAccount");
//		//this.connect(this.accountToolbar.removeButton, "onClick", "onRemoveAccountClick");
//		this.connect(this.accountGrid.store, "onSet", dojo.hitch(this, function(item, attr, oldVal, newVal){
//			if(newVal != oldVal){
////				this.accountToolbar.needsSaved = true;
//				//this.accountToolbar.unhideSaveRevertButton();
//			}
//        	})
//		);
		//
		this.installedModules = [];
		_sixnet_framework.bcSilent('providers', 'getInstalled', {}, dojo.hitch(this, function(response){
			if( response.successful ){
				console.log(response.data.length);
				_sixnet_framework.log(1, "getInstalled (getAccountModules...tobe)",response.data);
				dojo.forEach(response.data, function(item){
					this.installedModules.push(item.name);
				}, this);
			}
		}));
		console.log(_sixnet_framework._accountId, "  << accountId");
		var currentAccountModules = [];
		_sixnet_framework.bcSilent('access', 'getViewData', { 
			viewName:'account_modules', 
			startingOffset: 0,
			sort: [],
			mode:'=', 
			maxCount:-1,
			query: {
				account_id: _sixnet_framework._accountId
			}
			
		}, dojo.hitch(this, function(response){
			if(response.successful){
				console.log(this, " << this");
				dojo.forEach(response.data.items, function(item){
					currentAccountModules.push(item.module);
				});
				this.filterModules(currentAccountModules);
			}else{
				console.log('error');
			}
			_sixnet_framework.log(1, 'success-add user', arguments);
		}), dojo.hitch(this, function(){
			_sixnet_framework.log(1, 'failure-add user', arguments)
		}));
		console.log("currentAccountModules: ", currentAccountModules);
		console.log("installedModules:  ", this.installedModules);
		this._subscribes.push( dojo.subscribe( '/status/hint', dojo.hitch(this.statusLine, "setContent")));
	},
	
	onFormatAccount: function(item, accountnamePane){
		if(!this._viewOnly){
			var E = "<img title='edit' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/E.gif\" />");
			var editCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; cursor:pointer;', content:E, onClick: dojo.hitch(this, function(item){
				this.onEditAccountClick(item);
			}, item)});
			editCP.placeAt(accountnamePane.domNode, "last");
			//
			var M = "<img title='edit modules' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/M.gif\" />");
			var modulesCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; margin-left:2px; cursor:pointer;', content:M, onClick: dojo.hitch(this, function(item){
				this.openModulesDialog(item);
			}, item)});
			modulesCP.placeAt(accountnamePane.domNode, "last");
		}
	},
	
	onEditAccountClick: function(item){
		console.log("Edit me:  ", item);
		// create an instance of Dialog with the content (loaded from href), id and title.
		var editAccountFormDialog = new dijit.Dialog({accountManager: this, 
			style:"width:310px;height:135px;", 
			id:"editAccountFormDialog", 
			title:'Edit Account:  '.concat(item.name), 
			href: this.templateUrl.concat('editAccount.html'),
			onLoad: function(){
				//  set values
				dijit.getEnclosingWidget(document.getElementById('id')).set('value', item.id);
				dijit.getEnclosingWidget(document.getElementById('name')).set('value', item.name);
				//  do check box connects (enable/disable textboxes)
				dojo.connect(dijit.getEnclosingWidget(document.getElementById('editAccountname')), "onChange", function(v){
					console.log(v);
					if(v){
						dijit.getEnclosingWidget(document.getElementById('name')).set('disabled', false);
					}else{
						dijit.getEnclosingWidget(document.getElementById('name')).set('disabled', true);
					}
				});
				// this method fires when the dialog has finished loading its content.
				dijit.byId('editAccountFormDialog').connect(dijit.byId('editAccountFormDialog'), "onCancel", function(){
					// this is for the 'x' button built into the Dialog.
					this.destroyRecursive();
				});
			}
		}).startup();
		dijit.byId('editAccountFormDialog').show();
	},
	
	filterModules: function(current){
		console.log("filterModules", dojo.clone(current), dojo.clone(this.installedModules), current.length, this.installedModules.length);
		var keepers = [];
		for(var i = 0; i < this.installedModules.length; i++){
			for(var j = 0; j < current.length; j++){
				if(this.installedModules[i] == current[j]){
					keepers.push(current[j]);
				}
			}
		}
		console.log(keepers);
		this.modules = keepers;
	},

	onRowClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		var rowItem = this.accountGrid.grid.getItem( event.rowIndex);
		this.account = rowItem;
		var message = "";
		//dojo.removeClass( this.accountToolbar.removeButton.focusNode, "disabledButton");
		if(event.cell.editable){
			message = "Double-click to edit account detail";
		}
		dojo.publish( '/status/hint', [message]);
	},
	
	getAccountInfo: function(accountId, onComplete){
//		dijit.byId('addUserFormDialog').destroyRecursive();
		if(this.modules.length > 0 || _sixnet_framework._super){
			_sixnet_framework.bcSilent('access', 'getViewData', { 
				viewName:'accounts', 
				startingOffset: 0,
				sort: [],
				mode:'=', 
				maxCount:1,
				query: {
					id: accountId
				}
				
			}, dojo.hitch(this, function(response){
				if(response.successful){
					console.log("pass on: ", response.data.items[0]);
					onComplete(response.data.items[0]);
				}
				_sixnet_framework.log(1, 'success-add account', arguments);
			}), dojo.hitch(this, function(){
				_sixnet_framework.log(1, 'failure-add account', arguments)
			}));
		}
	},
	
	openModulesDialog: function(item){
//			var item = this.grid.getItem(idx);
		console.log(item, "  << item at accountManager");
		var changeDialogHeight = 90;
		var modChangeDialog = new dijit.Dialog({
			accountManager: this,
			style:"width:310px;",
			id:"modChangeDialog",
			title:'Account Modules:  '.concat(item.name)
		});
		var cp0 = new dijit.layout.ContentPane({
			style:"margin-right:auto; margin-left:auto; text-transform: capitalize; width:100%; text-align:center"
		});
		var modulesInfo = {};
		//  if super then always use all getInstalled modules
		var modules = (_sixnet_framework._super)? this.installedModules : this.modules;
		
		var this_accountManager = this.accountManager;
		var accountModules = new Object();
		_sixnet_framework.bcSilent('access', 'getAccountModulesPerId', { accountId: item.id }, dojo.hitch(this, function(response){
			if( response.successful ){
				dojo.forEach(modules, function(module, i){
					var checked = false;
					for(var i = 0; i<response.data.length; i++){
						if(module == response.data[i].module){
							checked = true;
						}
					}
					var cp = new dijit.layout.ContentPane({
						style:"margin-right:auto;margin-left:auto; text-transform: capitalize; width:200px; text-align:left"
					});
					var cb = new dijit.form.CheckBox({
						value: module, 
						checked: checked,                 
						onChange: function(v) {
							if(v == true){
								_sixnet_framework.bcSilent('access', 'addModule', { module: this.value, accountId:item.id }, dojo.hitch(this, function(response){
									if( response.successful ){
//												alert("success");
									}else{
										alert(response.error);
									}
								}));
//									},
							}else if(v == false){
								_sixnet_framework.bcSilent('access', 'removeModule', { module: this.value, accountId:item.id }, dojo.hitch(this, function(response){
									if( response.successful ){
//												alert("success");
									}else{
										alert(response.error);
									}
								}));
//									},
							}
		             	}
					});
					dojo.query(dojo.byId(cp.domNode)).addContent(cb.domNode);
					dojo.query(dojo.byId(cp.domNode)).addContent("  ".concat(module));
					changeDialogHeight += 15;
					cp.startup();
					cp.placeAt(cp0.domNode);
				});
				dojo.style(dojo.byId(modChangeDialog).domNode, 'height', ""+changeDialogHeight+"px");
				//  add close button
				var cp = new dijit.layout.ContentPane({
					style:"margin-right:auto;margin-left:auto; width:200px; text-align:right"
				});
				var closeButton = new dijit.form.Button({
					label:"Close",
					onClick:function(){
						modChangeDialog.hide();
						modChangeDialog.destroyRecursive();
					}
				}).placeAt(cp.domNode, "last");
				cp.startup();
				cp.placeAt(cp0.domNode);
				//
				cp0.startup();
				cp0.placeAt(modChangeDialog.domNode);
			}else{
				alert(response.error);
			}
		}));
//				deferred.addCallbacks(function(){_sixnet_framework.log(3, "Callback 0");},moduleForEach);
		dojo.connect(modChangeDialog, "onCancel", function(){
			this.hide();
			this.destroyRecursive();
		});
		modChangeDialog.show();
	},
	
	onRowDblClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		_sixnet_framework.log(3, "DblClick ", event);
		var rowItem = this.accountGrid.grid.getItem( event.rowIndex);
		this.account = rowItem;
		var message = "";
		if(!event.cell.editable){
			message = "This cell is not editable";
		}
		dojo.publish( '/status/hint', [message]);
	},
	onAddAccountClick: function(){
		// create an instance of Dialog with the content (loaded from href), id and title.
		var addAccountDialog = new dijit.Dialog({accountManager: this, style:"width:310px; height:135px;", id:"addAccountDialog", title:'Add Account', href: this.templateUrl.concat('addAccount.html'), onLoad: function(){
			// this method fires when the dialog has finished loading its content.
			dijit.byId('addAccountDialog').connect(dijit.byId('addAccountDialog'), "onCancel", function(){
				// this is for the 'x' button built into the Dialog.
				this.destroyRecursive();
			});
		}});
		addAccountDialog.show();
	},
	onRemoveAccountClick: function(){
//		if( dojo.hasClass( this.accountToolbar.removeButton.focusNode, "disabledButton")) return;
		//var account = this.accountGrid.grid.selection.getSelected();
		_sixnet_framework.log(3, "accountId: " + this.account.id);
		if( !confirm("Delete account `".concat( this.account.name).concat( "` and linked users?"))) return;
		_sixnet_framework.bc('access', 'removeAccount', { accountId: this.account.id }, dojo.hitch(this, function(response){
			if( response.successful ){
				//alert("success");
				this.accountGrid.reloadGrid();
			}else{
				alert(response.error);
			}
		}));
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.testManager']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.testManager'] = true;
dojo.provide('com.sixnet.services.modules.access.testManager');












dojo.declare('com.sixnet.services.modules.access.testManager', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\ttest manager\n</div>\n",
	icon: 'wrld_accnt.png',
	iconPath: '',
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.connect( this.dashBoard, "onHideWidget", "onHide");
	}
});

}

if(!dojo._hasResource["dojox.form.DropDownSelect"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.form.DropDownSelect"] = true;
dojo.deprecated("dojox.form.DropDownSelect", "Use dijit.form.Select instead", "2.0");

dojo.provide("dojox.form.DropDownSelect");


dojo.setObject("dojox.form.DropDownSelect", dijit.form.Select);

}

if(!dojo._hasResource["dojo.colors"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojo.colors"] = true;
dojo.provide("dojo.colors");

//TODO: this module appears to break naming conventions

/*=====
dojo.colors = {
	// summary: Color utilities
}
=====*/

(function(){
	// this is a standard conversion prescribed by the CSS3 Color Module
	var hue2rgb = function(m1, m2, h){
		if(h < 0){ ++h; }
		if(h > 1){ --h; }
		var h6 = 6 * h;
		if(h6 < 1){ return m1 + (m2 - m1) * h6; }
		if(2 * h < 1){ return m2; }
		if(3 * h < 2){ return m1 + (m2 - m1) * (2 / 3 - h) * 6; }
		return m1;
	};
	
	dojo.colorFromRgb = function(/*String*/ color, /*dojo.Color?*/ obj){
		// summary:
		//		get rgb(a) array from css-style color declarations
		// description:
		//		this function can handle all 4 CSS3 Color Module formats: rgb,
		//		rgba, hsl, hsla, including rgb(a) with percentage values.
		var m = color.toLowerCase().match(/^(rgba?|hsla?)\(([\s\.\-,%0-9]+)\)/);
		if(m){
			var c = m[2].split(/\s*,\s*/), l = c.length, t = m[1], a;
			if((t == "rgb" && l == 3) || (t == "rgba" && l == 4)){
				var r = c[0];
				if(r.charAt(r.length - 1) == "%"){
					// 3 rgb percentage values
					a = dojo.map(c, function(x){
						return parseFloat(x) * 2.56;
					});
					if(l == 4){ a[3] = c[3]; }
					return dojo.colorFromArray(a, obj);	// dojo.Color
				}
				return dojo.colorFromArray(c, obj);	// dojo.Color
			}
			if((t == "hsl" && l == 3) || (t == "hsla" && l == 4)){
				// normalize hsl values
				var H = ((parseFloat(c[0]) % 360) + 360) % 360 / 360,
					S = parseFloat(c[1]) / 100,
					L = parseFloat(c[2]) / 100,
					// calculate rgb according to the algorithm 
					// recommended by the CSS3 Color Module 
					m2 = L <= 0.5 ? L * (S + 1) : L + S - L * S, 
					m1 = 2 * L - m2;
				a = [
					hue2rgb(m1, m2, H + 1 / 3) * 256,
					hue2rgb(m1, m2, H) * 256,
					hue2rgb(m1, m2, H - 1 / 3) * 256,
					1
				];
				if(l == 4){ a[3] = c[3]; }
				return dojo.colorFromArray(a, obj);	// dojo.Color
			}
		}
		return null;	// dojo.Color
	};
	
	var confine = function(c, low, high){
		// summary:
		//		sanitize a color component by making sure it is a number,
		//		and clamping it to valid values
		c = Number(c);
		return isNaN(c) ? high : c < low ? low : c > high ? high : c;	// Number
	};
	
	dojo.Color.prototype.sanitize = function(){
		// summary: makes sure that the object has correct attributes
		var t = this;
		t.r = Math.round(confine(t.r, 0, 255));
		t.g = Math.round(confine(t.g, 0, 255));
		t.b = Math.round(confine(t.b, 0, 255));
		t.a = confine(t.a, 0, 1);
		return this;	// dojo.Color
	};
})();


dojo.colors.makeGrey = function(/*Number*/ g, /*Number?*/ a){
	// summary: creates a greyscale color with an optional alpha
	return dojo.colorFromArray([g, g, g, a]);
};

// mixin all CSS3 named colors not already in _base, along with SVG 1.0 variant spellings
dojo.mixin(dojo.Color.named, {
	aliceblue:	[240,248,255],
	antiquewhite:	[250,235,215],
	aquamarine:	[127,255,212],
	azure:	[240,255,255],
	beige:	[245,245,220],
	bisque:	[255,228,196],
	blanchedalmond:	[255,235,205],
	blueviolet:	[138,43,226],
	brown:	[165,42,42],
	burlywood:	[222,184,135],
	cadetblue:	[95,158,160],
	chartreuse:	[127,255,0],
	chocolate:	[210,105,30],
	coral:	[255,127,80],
	cornflowerblue:	[100,149,237],
	cornsilk:	[255,248,220],
	crimson:	[220,20,60],
	cyan:	[0,255,255],
	darkblue:	[0,0,139],
	darkcyan:	[0,139,139],
	darkgoldenrod:	[184,134,11],
	darkgray:	[169,169,169],
	darkgreen:	[0,100,0],
	darkgrey:	[169,169,169],
	darkkhaki:	[189,183,107],
	darkmagenta:	[139,0,139],
	darkolivegreen:	[85,107,47],
	darkorange:	[255,140,0],
	darkorchid:	[153,50,204],
	darkred:	[139,0,0],
	darksalmon:	[233,150,122],
	darkseagreen:	[143,188,143],
	darkslateblue:	[72,61,139],
	darkslategray:	[47,79,79],
	darkslategrey:	[47,79,79],
	darkturquoise:	[0,206,209],
	darkviolet:	[148,0,211],
	deeppink:	[255,20,147],
	deepskyblue:	[0,191,255],
	dimgray:	[105,105,105],
	dimgrey:	[105,105,105],
	dodgerblue:	[30,144,255],
	firebrick:	[178,34,34],
	floralwhite:	[255,250,240],
	forestgreen:	[34,139,34],
	gainsboro:	[220,220,220],
	ghostwhite:	[248,248,255],
	gold:	[255,215,0],
	goldenrod:	[218,165,32],
	greenyellow:	[173,255,47],
	grey:	[128,128,128],
	honeydew:	[240,255,240],
	hotpink:	[255,105,180],
	indianred:	[205,92,92],
	indigo:	[75,0,130],
	ivory:	[255,255,240],
	khaki:	[240,230,140],
	lavender:	[230,230,250],
	lavenderblush:	[255,240,245],
	lawngreen:	[124,252,0],
	lemonchiffon:	[255,250,205],
	lightblue:	[173,216,230],
	lightcoral:	[240,128,128],
	lightcyan:	[224,255,255],
	lightgoldenrodyellow:	[250,250,210],
	lightgray:	[211,211,211],
	lightgreen:	[144,238,144],
	lightgrey:	[211,211,211],
	lightpink:	[255,182,193],
	lightsalmon:	[255,160,122],
	lightseagreen:	[32,178,170],
	lightskyblue:	[135,206,250],
	lightslategray:	[119,136,153],
	lightslategrey:	[119,136,153],
	lightsteelblue:	[176,196,222],
	lightyellow:	[255,255,224],
	limegreen:	[50,205,50],
	linen:	[250,240,230],
	magenta:	[255,0,255],
	mediumaquamarine:	[102,205,170],
	mediumblue:	[0,0,205],
	mediumorchid:	[186,85,211],
	mediumpurple:	[147,112,219],
	mediumseagreen:	[60,179,113],
	mediumslateblue:	[123,104,238],
	mediumspringgreen:	[0,250,154],
	mediumturquoise:	[72,209,204],
	mediumvioletred:	[199,21,133],
	midnightblue:	[25,25,112],
	mintcream:	[245,255,250],
	mistyrose:	[255,228,225],
	moccasin:	[255,228,181],
	navajowhite:	[255,222,173],
	oldlace:	[253,245,230],
	olivedrab:	[107,142,35],
	orange:	[255,165,0],
	orangered:	[255,69,0],
	orchid:	[218,112,214],
	palegoldenrod:	[238,232,170],
	palegreen:	[152,251,152],
	paleturquoise:	[175,238,238],
	palevioletred:	[219,112,147],
	papayawhip:	[255,239,213],
	peachpuff:	[255,218,185],
	peru:	[205,133,63],
	pink:	[255,192,203],
	plum:	[221,160,221],
	powderblue:	[176,224,230],
	rosybrown:	[188,143,143],
	royalblue:	[65,105,225],
	saddlebrown:	[139,69,19],
	salmon:	[250,128,114],
	sandybrown:	[244,164,96],
	seagreen:	[46,139,87],
	seashell:	[255,245,238],
	sienna:	[160,82,45],
	skyblue:	[135,206,235],
	slateblue:	[106,90,205],
	slategray:	[112,128,144],
	slategrey:	[112,128,144],
	snow:	[255,250,250],
	springgreen:	[0,255,127],
	steelblue:	[70,130,180],
	tan:	[210,180,140],
	thistle:	[216,191,216],
	tomato:	[255,99,71],
	transparent: [0, 0, 0, 0],
	turquoise:	[64,224,208],
	violet:	[238,130,238],
	wheat:	[245,222,179],
	whitesmoke:	[245,245,245],
	yellowgreen:	[154,205,50]
});

}

if(!dojo._hasResource["dijit._PaletteMixin"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit._PaletteMixin"] = true;
dojo.provide("dijit._PaletteMixin");


dojo.declare("dijit._PaletteMixin",
	[dijit._CssStateMixin],
	{
	// summary:
	//		A keyboard accessible palette, for picking a color/emoticon/etc.
	// description:
	//		A mixin for a grid showing various entities, so the user can pick a certain entity.

	// defaultTimeout: Number
	//		Number of milliseconds before a held key or button becomes typematic
	defaultTimeout: 500,

	// timeoutChangeRate: Number
	//		Fraction of time used to change the typematic timer between events
	//		1.0 means that each typematic event fires at defaultTimeout intervals
	//		< 1.0 means that each typematic event fires at an increasing faster rate
	timeoutChangeRate: 0.90,

	// value: String
	//		Currently selected color/emoticon/etc.
	value: null,
	
	// _selectedCell: [private] Integer
	//		Index of the currently selected cell. Initially, none selected
	_selectedCell: -1,

	// _currentFocus: [private] DomNode
	//		The currently focused cell (if the palette itself has focus), or otherwise
	//		the cell to be focused when the palette itself gets focus.
	//		Different from value, which represents the selected (i.e. clicked) cell.
/*=====
	_currentFocus: null,
=====*/

	// _xDim: [protected] Integer
	//		This is the number of cells horizontally across.
/*=====
	_xDim: null,
=====*/

	// _yDim: [protected] Integer
	//		This is the number of cells vertically down.
/*=====
	_yDim: null,
=====*/

	// tabIndex: String
	//		Widget tab index.
	tabIndex: "0",

	// cellClass: [protected] String
	//		CSS class applied to each cell in the palette
	cellClass: "dijitPaletteCell",

	// dyeClass: [protected] String
	//	 Name of javascript class for Object created for each cell of the palette.
	//	 dyeClass should implements dijit.Dye interface
	dyeClass: '',

	_preparePalette: function(choices, titles) {
		// summary:
		//		Subclass must call _preparePalette() from postCreate(), passing in the tooltip
		//		for each cell
		// choices: String[][]
		//		id's for each cell of the palette, used to create Dye JS object for each cell
		// titles: String[]
		//		Localized tooltip for each cell

		this._cells = [];
		var url = this._blankGif;
		
		var dyeClassObj = dojo.getObject(this.dyeClass);

		for(var row=0; row < choices.length; row++){
			var rowNode = dojo.create("tr", {tabIndex: "-1"}, this.gridNode);
			for(var col=0; col < choices[row].length; col++){
				var value = choices[row][col];
				if(value){
					var cellObject = new dyeClassObj(value);
					
					var cellNode = dojo.create("td", {
						"class": this.cellClass,
						tabIndex: "-1",
						title: titles[value]
					});

					// prepare cell inner structure
					cellObject.fillCell(cellNode, url);

					this.connect(cellNode, "ondijitclick", "_onCellClick");
					this._trackMouseState(cellNode, this.cellClass);

					dojo.place(cellNode, rowNode);

					cellNode.index = this._cells.length;

					// save cell info into _cells
					this._cells.push({node:cellNode, dye:cellObject});
				}
			}
		}
		this._xDim = choices[0].length;
		this._yDim = choices.length;

		// Now set all events
		// The palette itself is navigated to with the tab key on the keyboard
		// Keyboard navigation within the Palette is with the arrow keys
		// Spacebar selects the cell.
		// For the up key the index is changed by negative the x dimension.

		var keyIncrementMap = {
			UP_ARROW: -this._xDim,
			// The down key the index is increase by the x dimension.
			DOWN_ARROW: this._xDim,
			// Right and left move the index by 1.
			RIGHT_ARROW: this.isLeftToRight() ? 1 : -1,
			LEFT_ARROW: this.isLeftToRight() ? -1 : 1
		};
		for(var key in keyIncrementMap){
			this._connects.push(
				dijit.typematic.addKeyListener(
					this.domNode,
					{charOrCode:dojo.keys[key], ctrlKey:false, altKey:false, shiftKey:false},
					this,
					function(){
						var increment = keyIncrementMap[key];
						return function(count){ this._navigateByKey(increment, count); };
					}(),
					this.timeoutChangeRate,
					this.defaultTimeout
				)
			);
		}
	},

	postCreate: function(){
		this.inherited(arguments);

		// Set initial navigable node.
		this._setCurrent(this._cells[0].node);
	},

	focus: function(){
		// summary:
		//		Focus this widget.  Puts focus on the most recently focused cell.

		// The cell already has tabIndex set, just need to set CSS and focus it
		dijit.focus(this._currentFocus);
	},

	_onCellClick: function(/*Event*/ evt){
		// summary:
		//		Handler for click, enter key & space key. Selects the cell.
		// evt:
		//		The event.
		// tags:
		//		private

		var target = evt.currentTarget,	
			value = this._getDye(target).getValue();

		// First focus the clicked cell, and then send onChange() notification.
		// onChange() (via _setValueAttr) must be after the focus call, because
		// it may trigger a refocus to somewhere else (like the Editor content area), and that
		// second focus should win.
		// Use setTimeout because IE doesn't like changing focus inside of an event handler.
		this._setCurrent(target);
		setTimeout(dojo.hitch(this, function(){
			dijit.focus(target);		
			this._setValueAttr(value, true);		
		}));

		// workaround bug where hover class is not removed on popup because the popup is
		// closed and then there's no onblur event on the cell
		dojo.removeClass(target, "dijitPaletteCellHover");

		dojo.stopEvent(evt);
	},

	_setCurrent: function(/*DomNode*/ node){
		// summary:
		//		Sets which node is the focused cell.
		// description:
   		//		At any point in time there's exactly one
		//		cell with tabIndex != -1.   If focus is inside the palette then
		// 		focus is on that cell.
		//
		//		After calling this method, arrow key handlers and mouse click handlers
		//		should focus the cell in a setTimeout().
		// tags:
		//		protected
		if("_currentFocus" in this){
			// Remove tabIndex on old cell
			dojo.attr(this._currentFocus, "tabIndex", "-1");
		}

		// Set tabIndex of new cell
		this._currentFocus = node;
		if(node){
			dojo.attr(node, "tabIndex", this.tabIndex);
		}
	},

	_setValueAttr: function(value, priorityChange){
		// summary:
		// 		This selects a cell. It triggers the onChange event.
		// value: String value of the cell to select
		// tags:
		//		protected
		// priorityChange:
		//		Optional parameter used to tell the select whether or not to fire
		//		onChange event.
		
		// clear old value and selected cell
		this.value = null;
		if(this._selectedCell >= 0){
			dojo.removeClass(this._cells[this._selectedCell].node, "dijitPaletteCellSelected");
		}
		this._selectedCell = -1;

		// search for cell matching specified value
		if(value){
			for(var i = 0; i < this._cells.length; i++){
				if(value == this._cells[i].dye.getValue()){
					this._selectedCell = i;
					this.value = value;

					dojo.addClass(this._cells[i].node, "dijitPaletteCellSelected");

					if(priorityChange || priorityChange === undefined){
						this.onChange(value);
					}

					break;
				}
			}
		}
	},

	onChange: function(value){
		// summary:
		//		Callback when a cell is selected.
		// value: String
		//		Value corresponding to cell.
	},

	_navigateByKey: function(increment, typeCount){
		// summary:
		// 	  	This is the callback for typematic.
		// 		It changes the focus and the highlighed cell.
		// increment:
		// 		How much the key is navigated.
		// typeCount:
		//		How many times typematic has fired.
		// tags:
		//		private

		// typecount == -1 means the key is released.
		if(typeCount == -1){ return; }

		var newFocusIndex = this._currentFocus.index + increment;
		if(newFocusIndex < this._cells.length && newFocusIndex > -1){
			var focusNode = this._cells[newFocusIndex].node;
			this._setCurrent(focusNode);

			// Actually focus the node, for the benefit of screen readers.
			// Use setTimeout because IE doesn't like changing focus inside of an event handler
			setTimeout(dojo.hitch(dijit, "focus", focusNode), 0);
		}
	},

	_getDye: function(/*DomNode*/ cell){
		// summary:
		//		Get JS object for given cell DOMNode

		return this._cells[cell.index].dye;
	}
});

/*=====
dojo.declare("dijit.Dye",
	null,
	{
		// summary:
		//		Interface for the JS Object associated with a palette cell (i.e. DOMNode)

		constructor: function(alias){
			// summary:
			//		Initialize according to value or alias like "white"
			// alias: String
		},

		getValue: function(){
			// summary:
			//		Return "value" of cell; meaning of "value" varies by subclass.
			// description:
			//		For example color hex value, emoticon ascii value etc, entity hex value.
		},

		fillCell: function(cell, blankGif){
			// summary:
			//		Add cell DOMNode inner structure
			//	cell: DomNode
			//		The surrounding cell
			//	blankGif: String
			//		URL for blank cell image
		}
	}
);
=====*/

}

if(!dojo._hasResource["dijit.ColorPalette"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dijit.ColorPalette"] = true;
dojo.provide("dijit.ColorPalette");










dojo.declare("dijit.ColorPalette",
	[dijit._Widget, dijit._Templated, dijit._PaletteMixin],
	{
	// summary:
	//		A keyboard accessible color-picking widget
	// description:
	//		Grid showing various colors, so the user can pick a certain color.
	//		Can be used standalone, or as a popup.
	//
	// example:
	// |	<div dojoType="dijit.ColorPalette"></div>
	//
	// example:
	// |	var picker = new dijit.ColorPalette({ },srcNode);
	// |	picker.startup();


	// palette: String
	//		Size of grid, either "7x10" or "3x4".
	palette: "7x10",

	// _palettes: [protected] Map
	// 		This represents the value of the colors.
	//		The first level is a hashmap of the different palettes available.
	//		The next two dimensions represent the columns and rows of colors.
	_palettes: {
		"7x10":	[["white", "seashell", "cornsilk", "lemonchiffon","lightyellow", "palegreen", "paleturquoise", "lightcyan",	"lavender", "plum"],
				["lightgray", "pink", "bisque", "moccasin", "khaki", "lightgreen", "lightseagreen", "lightskyblue", "cornflowerblue", "violet"],
				["silver", "lightcoral", "sandybrown", "orange", "palegoldenrod", "chartreuse", "mediumturquoise", 	"skyblue", "mediumslateblue","orchid"],
				["gray", "red", "orangered", "darkorange", "yellow", "limegreen", 	"darkseagreen", "royalblue", "slateblue", "mediumorchid"],
				["dimgray", "crimson", 	"chocolate", "coral", "gold", "forestgreen", "seagreen", "blue", "blueviolet", "darkorchid"],
				["darkslategray","firebrick","saddlebrown", "sienna", "olive", "green", "darkcyan", "mediumblue","darkslateblue", "darkmagenta" ],
				["black", "darkred", "maroon", "brown", "darkolivegreen", "darkgreen", "midnightblue", "navy", "indigo", 	"purple"]],

		"3x4": [["white", "lime", "green", "blue"],
			["silver", "yellow", "fuchsia", "navy"],
			["gray", "red", "purple", "black"]]
	},

	// _imagePaths: [protected] Map
	//		This is stores the path to the palette images
	_imagePaths: {
		"7x10": dojo.moduleUrl("dijit.themes", "a11y/colors7x10.png"),
		"3x4": dojo.moduleUrl("dijit.themes", "a11y/colors3x4.png"),
		"7x10-rtl": dojo.moduleUrl("dijit.themes", "a11y/colors7x10-rtl.png"),
		"3x4-rtl": dojo.moduleUrl("dijit.themes", "a11y/colors3x4-rtl.png")
	},

	// templateString: String
	//		The template of this widget.
	templateString: dojo.cache("dijit", "templates/ColorPalette.html", "<div class=\"dijitInline dijitColorPalette\">\n\t<img class=\"dijitColorPaletteUnder\" dojoAttachPoint=\"imageNode\" waiRole=\"presentation\" alt=\"\"/>\n\t<table class=\"dijitPaletteTable\" cellSpacing=\"0\" cellPadding=\"0\">\n\t\t<tbody dojoAttachPoint=\"gridNode\"></tbody>\n\t</table>\n</div>\n"),

	baseClass: "dijitColorPalette",

	dyeClass: 'dijit._Color',

	buildRendering: function(){
		// Instantiate the template, which makes a skeleton into which we'll insert a bunch of
		// <img> nodes

		this.inherited(arguments);

		this.imageNode.setAttribute("src", this._imagePaths[this.palette + (this.isLeftToRight() ? "" : "-rtl")].toString());

		var i18nColorNames = dojo.i18n.getLocalization("dojo", "colors", this.lang);
		this._preparePalette(
			this._palettes[this.palette],
			i18nColorNames
		);
	}
});

dojo.declare("dijit._Color", dojo.Color,
	// summary:
	//		Object associated with each cell in a ColorPalette palette.
	//		Implements dijit.Dye.
	{
		constructor: function(/*String*/alias){
			this._alias = alias;
			this.setColor(dojo.Color.named[alias]);
		},

		getValue: function(){
			// summary:
			//		Note that although dijit._Color is initialized with a value like "white" getValue() always
			//		returns a hex value
			return this.toHex();
		},

		fillCell: function(/*DOMNode*/ cell, /*String*/ blankGif){
			dojo.create("img", {
				src: blankGif,
				"class": "dijitPaletteImg",
				alt: this._alias
			}, cell);
		}
	}
);

}

if(!dojo._hasResource['com.sixnet.services.modules.access.colorPicker']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.colorPicker'] = true;
dojo.provide('com.sixnet.services.modules.access.colorPicker');








//

dojo.declare('com.sixnet.services.modules.access.colorPicker', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div dojoAttachPoint=\"COLOR_PICKER\" style=\"margin:0; padding:0\" >\n\t<div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">\n\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" style=\"margin-right:auto; margin-left:160px; margin-top:30px; width:520px; min-width:520px; max-width:520px; overflow:hidden\">\n\t\t\t<!-- left colorPicker div -->\n\t\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"float:left; padding:10px; width:250px; min-width:250px; max-width:250px\" dojoAttachPoint=\"colorPickerHolder\" >\n\t\t\t\t</div>\n\t\t\n\t\t\t<!-- right colorPicker div -->\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"currentColorsHolder\" style=\"float:left; width:230px; padding:10px;\">\n\t\t\t</div>\n\t\t</div>\t\t\n\t</div>\n</div>\n",
	applyButton:false,
	backgroundRadio:false,
	textRadio:false,
	saveButton:false,
	currentUser:false,
	colorPicker:false,
	previewBox:false,
	innerText:false,
	sections:false,
	colorPickerNum:false,
	toColorSelect:null,
	currentBG:false,
	currentFG:false,
	update:false,
	icon: 'clr_pckr.png',
	iconPath: '',
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.currentUser = _sixnet_framework._userId;
		this.sections = new Array("Emergency","Alert","Critical","Error","Warning","Notice","Info","Debug");
		//  here we should grab the current user's preferences... leave these for install mode
		this.bgColors = new Array("#555","#666","#777","#000","#111","#222","#333","#444");
		this.txtColors = new Array("#000","#111","#222","#333","#444","#555","#666","#777");
		//
		//clr_pckr
		this.getColorPrefs();
	},
	
	getColorPrefs: function(){
		// like getCustomView!
		var bgColors = new Array();
		var txtColors = new Array();
		var sections = new Array();
		_sixnet_framework.bc('access', 'getColorPreferences', {}, dojo.hitch(this, function(response){
			if( response.successful ){
				if(response.data.clrpref){
					//  if we have a clrpref, then apply it
					//  set this.update to true because we are going to update existing on Save
					this.update = true;
					var clrP = response.data.clrpref;
					for(var i=0; i<clrP.colors.length; i++){
						//  Here we fill color arrays w/ user specified colors
						bgColors.push(clrP.colors[i].background);
						txtColors.push(clrP.colors[i].color);
						sections.push(clrP.colors[i].section);
					}
					this.bgColors = bgColors;
					this.txtColors = txtColors;
					this.sections = sections;
					_sixnet_framework.log(3, bgColors, txtColors);
					this.buildDropDown(dojo.hitch(this, "createColorPickerGUI"));
				}else{
					//  we have a successful try, but no info - so, get default from sixnet_config
					_sixnet_framework.bc('access', 'getSysConfigInfo', {name:'STATUS_COLORS', as_json:true}, dojo.hitch(this, function(response){
						if( response.successful ){
							_sixnet_framework.log(3, "success!  :  ", response);
							if(response.data.value){
								//  we got STATUS_COLORS
								var clrP = response.data.value;

								_sixnet_framework.log(3, " herehere ", clrP);
								for(var i=0; i<clrP.colors.length; i++){
									//  Here we fill color arrays w/ user specified colors
									_sixnet_framework.log(3, " herehere ");
									bgColors.push(clrP.colors[i].background);
									txtColors.push(clrP.colors[i].color);
									sections.push(clrP.colors[i].section);
								}
								this.bgColors = bgColors;
								this.txtColors = txtColors;
								this.sections = sections;
								_sixnet_framework.log(3, bgColors, txtColors, this.bgColors, " this bg");
								this.buildDropDown(dojo.hitch(this, "createColorPickerGUI"));
							}
						}					
					}));
				}
			}
		}));
	},
	
	buildDropDown: function(onComplete){
		//
		this.toColorSelect = new dijit.form.Select({
			style:"width:208px; margin-left:0px;",
			forceWidth:true
		});
		for(var i = 0; i < this.sections.length; i++){
			var section = this.sections[i];
			this.toColorSelect.addOption({value:i+"", label:section});
		}
		this.toColorSelect.placeAt(this.colorPickerHolder.domNode, "last");
		_sixnet_framework.log(1, this.toColorSelect);
		onComplete();
	},
//->  dojo.style(dojo.query(".dijitMenuActive")[0], "width", "208px");

	createColorPickerGUI: function(){
		this.colorPicker = new dijit.ColorPalette({
			title: "Color Options"
		}).placeAt(dojo.byId(this.colorPickerHolder.domNode), "last");
		this.connect(this.colorPicker, "onChange", dojo.hitch(this, "newColor"));
		//  style fix for Chrome, doesn't interfere with FF
		dojo.style(this.colorPicker.domNode, "width", "206px");
		if(dojo.isIE){
			//  style fix for IE (-4 more px)
			dojo.query(".dijitPaletteImg", this.colorPicker.domNode).forEach(function(node){
				dojo.style(node, "margin", ".01em");
			});
			dojo.style(this.colorPicker.domNode, "width", "202px");
		}
		this.createPreviewBox();
	},
	
	createPreviewBox: function(){
		// wrap under color picker
		dojo.create("br", null, dojo.byId(this.colorPickerHolder.domNode));
		this.backgroundRadio = new dijit.form.RadioButton({
			name:"whatToColor",
			checked:"checked",
			value:"background"
		}).placeAt(dojo.byId(this.colorPickerHolder.domNode), "last");
		dojo.create("label", {innerHTML:"Background   "}, dojo.byId(this.colorPickerHolder.domNode));
		this.textRadio = new dijit.form.RadioButton({
			name:"whatToColor",
			value:"text"
		}).placeAt(dojo.byId(this.colorPickerHolder.domNode), "last");
		dojo.create("label", {innerHTML:"Text"}, dojo.byId(this.colorPickerHolder.domNode));
		dojo.create("br", null, dojo.byId(this.colorPickerHolder.domNode));
		this.currentBG = this.bgColors[0];
		this.currentFG = this.txtColors[0];
		this.previewBox = new dijit.layout.ContentPane({
			style:"width:206px; border:1px solid #000000; height:70px; vertical-align:middle; text-align:center; color:".concat(this.txtColors[0]).concat("; background:").concat(this.bgColors[0]),
			content:"<p>Lorum ipsum!</p>"
		}).placeAt(dojo.byId(this.colorPickerHolder.domNode), "last");
		this.applyButton = new dijit.form.Button({label:" Apply to Alert Colors >>> ", style:"float:right; padding-right:40px;"}).placeAt(dojo.byId(this.colorPickerHolder.domNode), "last");
//		var styleObj = {width:"100%"};
//		dojo.query("button", this.applyButton.domNode).attr("style", styleObj);
		dojo.connect(this.applyButton, "onClick", this, "applyToCurrent");
		this.populateCurrent();
	},
	
	newColor: function(color){
		// 1. Background or Text?
		// 2. Color
		// 3. on apply, which section?
		if(this.backgroundRadio.checked){
			// color background
			this.currentBG = color;
			this.previewBox.attr("style", {background:color});
		}else if(this.textRadio.checked){
			// color text
			this.currentFG = color;
			this.previewBox.attr("style", {color:color});
		}
	},
	
	applyToCurrent: function(){
		var section = this.toColorSelect.value;
		var divs = dojo.query("div", dojo.byId(this.currentColorsHolder.domNode));
		_sixnet_framework.log(1, divs, divs[section]);
		//  the number of current selection lines-up with the number of the div
		dojo.style(divs[section], "background", this.currentBG);
		dojo.style(divs[section], "color", this.currentFG);
	},
	
	populateCurrent: function(){
		for(var i =0; i < this.sections.length; i++){
			var cp = new dijit.layout.ContentPane({
				style:"cursor:pointer; width:206px; height:32px; vertical-align:middle; text-align:center; color:".concat(this.txtColors[i]).concat("; background:").concat(this.bgColors[i]), 
				content:this.sections[i]}).placeAt(dojo.byId(this.currentColorsHolder.domNode), "last");	
			dojo.connect(cp, "onClick", this, "sectionChange");
		}
		this.saveButton = new dijit.form.Button({label:" Save to My Preferences ", style:"float:right; margin-right:24px;"}).placeAt(dojo.byId(this.currentColorsHolder.domNode), "last");
		this.connect(this.saveButton, "onClick", "saveToPreferences");
		if(_sixnet_framework._super){
			this.saveMasterButton = new dijit.form.Button({label:"&nbsp;&nbsp;Make System Defaults ", style:"float:right; margin-right:24px;"}).placeAt(dojo.byId(this.currentColorsHolder.domNode), "last");
			this.connect(this.saveMasterButton, "onClick", "saveMasterPreferences");
		}
	},
	
	sectionChange: function(item){
		// using the "onclick" of the display divs of created
		// to show the current set diplay colors
		// we set the drop-down which controls what section to apply
		// the changes to (dd:onclick)
		_sixnet_framework.log(1, "sectionChange, item: ", item);
		var section = item.target.innerHTML;
		_sixnet_framework.log(1, item.target.style.backgroundColor, item.target.style.color);
		//  make drop-down set at this section
		for(var i = 0; i < this.toColorSelect.options.length; i++){
			_sixnet_framework.log(1, this.toColorSelect.options[i], this.toColorSelect.options[i].label);
			if(this.toColorSelect.options[i].label == section){
				var color = item.target.style.color;
				var bgColor = item.target.style.background;
				this.toColorSelect.value = i;
				this.toColorSelect.options[i].selected = true;
				this.toColorSelect.setValue(i);
				//  apply this selection's colors to preview
				this.previewBox.attr("style", {color:color, background:bgColor});
				this.currentBG = bgColor;
				this.currentFG = color;
			}else{
				this.toColorSelect.options[i].selected = false;
			}
		}
		_sixnet_framework.log(1, this.toColorSelect, "  << toColorSelect");
	},
	
	saveMasterPreferences: function(){
		//  account master preferences (unavailable w/o role)
		var divs = dojo.query("div", dojo.byId(this.currentColorsHolder.domNode));
		var styleObj = [];
		for(var i = 0; i < divs.length; i++){
	        styleObj.push({section: this.toColorSelect.options[i].label, color: dojo.style(divs[i], "color"), background: dojo.style(divs[i], "backgroundColor")});
		}
		var toPut = {
				colors:styleObj
		};
		_sixnet_framework.bc('access', 'masterColorPreferences', { customColors: toPut }, dojo.hitch(this, function(response){
			if( response.successful ){
				//  rebuild the index->alertColor styles
				_sixnet_framework.alertColorCSS();
			}
		}));
		
	},
	
	saveToPreferences: function(){
		//  per-user preferences
		var divs = dojo.query("div", dojo.byId(this.currentColorsHolder.domNode));
		var styleObj = [];

		console.log(this.toColorSelect);
		for(var i = 0; i < divs.length; i++){
	        styleObj.push({section: this.toColorSelect.options[i].label, color: dojo.style(divs[i], "color"), background: dojo.style(divs[i], "backgroundColor")});
		}
		var toPut = {
				colors:styleObj
		};
		_sixnet_framework.log(3, toPut);
		if(this.update){
			//  update current
			_sixnet_framework.bc('access', 'updateColorPreferences', { customColors: toPut }, dojo.hitch(this, function(response){
				if( response.successful ){
					//  rebuild the index->alertColor styles
					_sixnet_framework.alertColorCSS();
				}
			}));
		}else{
			_sixnet_framework.bc('access', 'setColorPreferences', { customColors: toPut }, dojo.hitch(this, function(response){
				if( response.successful ){
					//  rebuild the index->alertColor styles
					_sixnet_framework.alertColorCSS();
				}
			}));
		}
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.accountDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.accountDash'] = true;
dojo.provide('com.sixnet.services.modules.access.accountDash');




dojo.declare('com.sixnet.services.modules.access.accountDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/accountDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.accountManager');		
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource["dojox.layout.TableContainer"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["dojox.layout.TableContainer"] = true;
dojo.experimental("dojox.layout.TableContainer");
dojo.provide("dojox.layout.TableContainer");


dojo.declare("dojox.layout.TableContainer",
	dijit.layout._LayoutWidget,
	{
	// summary: 
	//		A container that lays out its child widgets in a table layout.
	//
	// description:
	//		The TableContainer lays out child widgets in a Table layout.
	//		Each widget can specify a "label" or a "title" parameter.
	//		This label is displayed either above or to the left of
	//		a widget depending on whether the "orientation" attribute
	//		is "horiz" or "vert", for horizontal and vertical respectively.
	//		The number of columns is configured using the "cols" attribute.
	//		The width of labels can be configured using the "labelWidth" parameter.
	//
	// example:
	// |	<div dojoType="dojox.layout.TableContainer" orientation="vert" cols="3>
	// |		<div dojoType="dijit.form.TextInput" value="John" label="First Name:"></div>
	// |		<div dojoType="dijit.form.CheckBox" label="Is Student?:"></div>
	// |		<div dojoType="dojox.form.DateTextBox" label="Date Of Birth:"></div>
	// |	</div>
	//

	cols: 1,
	
	// labelWidth: Number|String
	//		Defines the width of a label.  If the value is a number, it is
	//		treated as a pixel value.  The other valid value is a percentage, 
	//		e.g. "50%"
	labelWidth: "100",

	// showLabels: Boolean
	//		True if labels should be displayed, false otherwise.
	showLabels: true,

	// orientation: String
	//		Either "horiz" or "vert" for label orientation. 
	orientation: "horiz", 
	
	// spacing: Number
	//		The cell spacing to apply to the table.
	spacing: 1,

	// customClass: String
	//		A CSS class that will be applied to child elements.  For example, if
	//		the class is "myClass", the table will have "myClass-table" applied to it,
	//		each label TD will have "myClass-labelCell" applied, and each 
	//		widget TD will have "myClass-valueCell" applied.
	customClass: "",

	postCreate: function(){
		this.inherited(arguments);
		this._children = [];
		
		// If the orientation, customClass or cols attributes are changed, 
		// layout the widgets again.
		dojo.connect(this, "attr", dojo.hitch(this, function(name, value){
			if(value && (name == "orientation" || name == "customClass" || name == "cols")) {
				this.layout();
			}
		}))
	},

	startup: function() {
		if(this._started) {
			return;
		}
		this.inherited(arguments);
		if(this._initialized) {
			return;
		}
		var children = this.getChildren();
		if(children.length < 1) {
			return;
		}
		this._initialized = true;

		dojo.addClass(this.domNode, "dijitTableLayout");

		// Call startup on all child widgets
		dojo.forEach(children, function(child){
			if(!child.started && !child._started) {
				child.startup();
			}
		});
		this.resize();
		this.layout();
	},

	resize: function(){
		// summary: 
		//		Resizes all children.  This widget itself
		//		does not resize, as it takes up 100% of the
		//		available width.
		dojo.forEach(this.getChildren(), function(child){
			if(typeof child.resize == "function") {
				child.resize();
			}
		});
	},

	layout: function(){
		// summary: 
		//		Lays out the child widgets.
		if(!this._initialized){
			return;
		}

		var children = this.getChildren();

		var childIds = {};
		var _this = this;

		function addCustomClass(node, type, count) {
			if(_this.customClass != "") {
				var clazz = _this.customClass+ "-" + (type || node.tagName.toLowerCase());
				dojo.addClass(node, clazz);

				if(arguments.length > 2) {
					dojo.addClass(node, clazz + "-" + count);
				}
			}
		}

		// Find any new children that have been added since the last layout() call
		dojo.forEach(this._children, dojo.hitch(this, function(child){
			childIds[child.id] = child;
		}));

		dojo.forEach(children, dojo.hitch(this, function(child, index){
			if(!childIds[child.id]) {
				// Add pre-existing children to the start of the array
				this._children.push(child);
			}
		}));

		// Create the table.  It fills the width of it's container.
		var table = dojo.create("table", {
			"width": "100%",
			 "class": "tableContainer-table tableContainer-table-" + this.orientation,
			 "cellspacing" : this.spacing
			},
			this.domNode);

		var tbody = dojo.create("tbody");
		table.appendChild(tbody);

		addCustomClass(table, "table", this.orientation);

		var width = Math.floor(100 / this.cols) + "%";

		var labelRow = dojo.create("tr", {}, tbody);
		var childRow = (!this.showLabels || this.orientation == "horiz")
											? labelRow : dojo.create("tr", {}, tbody);
		var maxCols = this.cols * (this.showLabels ? 2 : 1);
		var numCols = 0;

		// Iterate over the children, adding them to the table.
		dojo.forEach(this._children, dojo.hitch(this, function(child, index){
			
			var colspan = child.colspan || 1;
			
			if(colspan > 1) {
				colspan = this.showLabels ? 
					Math.min(maxCols - 1, colspan * 2 -1): Math.min(maxCols, colspan);
			}

			// Create a new row if we need one
			if(numCols + colspan - 1 + (this.showLabels ? 1 : 0)>= maxCols) {
				numCols = 0;
				labelRow = dojo.create("tr", {}, tbody);
				childRow = this.orientation == "horiz" ? labelRow : dojo.create("tr", {}, tbody);
			}
			var labelCell;
			
			// If labels should be visible, add them
			if(this.showLabels) {
				labelCell = dojo.create("td", {"class": "tableContainer-labelCell"}, labelRow);

				// If the widget should take up both the label and value,
				// then just set the class on it.
				if(child.spanLabel) {
					dojo.attr(labelCell, this.orientation == "vert" ? "rowspan" : "colspan", 2);
				}
				else {
					// Add the custom label class to the label cell
					addCustomClass(labelCell, "labelCell");
					var labelProps = {"for": child.attr("id")};
					var label = dojo.create("label", labelProps, labelCell);

					if(Number(this.labelWidth) > -1 ||
						String(this.labelWidth).indexOf("%") > -1) {
							
						// Set the width of the label cell with either a pixel or percentage value
						dojo.style(labelCell, "width", 
							String(this.labelWidth).indexOf("%") < 0 
								? this.labelWidth + "px" : this.labelWidth);
					}

					label.innerHTML = child.attr("label") || child.attr("title");
				}
			}
			var childCell;

			if(child.spanLabel && labelCell) {
				childCell = labelCell;
			} else {
				 childCell = dojo.create("td", {
				 	"class" : "tableContainer-valueCell"
				}, childRow);
			}
			if(colspan > 1) {
				dojo.attr(childCell, "colspan", colspan);
			}
			
			// Add the widget cell's custom class, if one exists.
			addCustomClass(childCell, "valueCell", index);

			childCell.appendChild(child.domNode);
			numCols += colspan + (this.showLabels ? 1 : 0);
		}));

		if(this.table)	 {
			this.table.parentNode.removeChild(this.table);
		}
		// Refresh the layout of any child widgets, allowing them to resize
		// to their new parent.
		dojo.forEach(children, function(child){
			if(typeof child.layout == "function") {
				child.layout();
			}
		});
		this.table = table;
		this.resize();
	},
	
	destroyDescendants: function(/*Boolean*/ preserveDom){
		// summary:
		//      Destroys all the widgets inside this.containerNode,
		//      but not this widget itself
		dojo.forEach(this._children, function(child){ child.destroyRecursive(preserveDom); });
	},
	
	_setSpacingAttr: function(value) {
		// summary: 
		//		Sets the spacing attribute.
		this.spacing = value;
		if(this.table) {
			this.table.cellspacing = Number(value);
		}
	}
});

// Extend the default widget with both label and title elements, as
// well as a "spanLabel" attribute.  If a widget
dojo.extend(dijit._Widget, {
	// label: String
	//		The label to display for a given widget
	label: "",
	
	// title: String
	//		The label to display for a given widget.  This is interchangeable
	//		with the 'label' parameter, as some widgets already have a use
	//		for the 'label', and this can be used instead to avoid conflicts.
	title: "",
	
	// spanLabel: Boolean
	//		Setting spanLabel to true makes the widget take up both the
	//		label and value cells. Defaults to false.
	spanLabel: false,
	
	// colspan: Number
	//		The number of columns this widget should span.
	colspan: 1
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.addUser']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.addUser'] = true;
dojo.provide('com.sixnet.services.modules.access.addUser');
















//dojo.require('com.sixnet.services.modules.access.surveyReportImport');


dojo.declare("com.sixnet.services.modules.access.HintButton", [dijit.form.Button],{
	hint:'',
	_limitSurveyMode:false,
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.connect(this, "onMouseOver", dojo.hitch( this, function(hint, event){
			dojo.publish('/status/hint', [hint]);
		}, this.hint));
		this.connect(this, "onMouseLeave", dojo.hitch( this, function(){
			dojo.publish('/status/hint', ['']);
		}));
	}
});

dojo.declare('com.sixnet.services.modules.access.addUser', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n<div dojoType=\"dijit.form.Form\" onSubmit=\"return false;\" id=\"addUserForm\" dojoAttachPoint=\"addUserForm\" style=\"width: 310px; margin-right:auto;margin-left:auto;\">\n\t\t<div style=\"margin-left:auto; margin-right:auto\">\n\t\t\t<div class=\"migrateFullRow\">\n\t\t\t<div class=\"migrateLabelLeft\">Name</div><input style=\"width:10em;\" dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"username\" name=\"username\" id=\"username\" />\n\t\t\t</div>\n\t\t\t<div class=\"migrateFullRow\">\n\t\t\t<div class=\"migrateLabelLeft\">Password</div><input style=\"width:10em;\" dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"password\" name=\"password\" id=\"password\" />\n\t\t\t</div>\n\t\t\t<div class=\"migrateFullRow\">\n\t\t\t<div class=\"migrateLabelLeft\">Super</div>\n\t\t\t\t&nbsp;&nbsp;No<input type=\"radio\" disabled=\"disabled\" dojoType=\"dijit.form.RadioButton\" id=\"superDDf\" name=\"super\" value=\"FALSE\" checked=\"checked\" />&nbsp;Yes<input type=\"radio\" disabled=\"disabled\" dojoType=\"dijit.form.RadioButton\" id=\"superDDt\" name=\"super\" value=\"TRUE\" />\n\t\t\t</div>\n\t\t\t<div class=\"migrateFullRow\">\n\t\t\t<div class=\"migrateLabelLeft\">Email</div><input style=\"width:10em;\" dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"email\" name=\"email\" />\n\t\t\t</div>\n\t\t\t<div class=\"migrateFullRow\" style=\"margin-top:15px;\">\n\t\t\t<div class=\"migrateLabelLeft\">&nbsp;&nbsp;&nbsp;</div>\n\t\t<div dojoType=\"dijit.form.Button\" id=\"addUserButton\" label=\"Add\" type=\"submit\">\n<script type=\"dojo/connect\" event=\"onClick\">\n\t\tvar v = dijit.byId('addUserForm').getValues();\n        // set the properties for the new item:\n\t\tif(!dijit.byId('addUserFormDialog').userManager._viewOnly && !_sixnet_framework._super){\n\t\t\tdelete v['super'];\n\t\t}\n\t\tdijit.byId('username').set('disabled', true);\n\t\tdijit.byId('password').set('disabled', true);\n\t\tdijit.byId('superDDf').set('disabled', true);\n\t\tdijit.byId('superDDt').set('disabled', true);\n\t\tdijit.byId('closeAddUser').set('disabled', true);\n\t\tdijit.byId('addUserButton').set('disabled', true);\n\t\t_sixnet_framework.bcSilent('access','updateViewData', { viewName: 'users', items:[v]}, dojo.hitch(this, function(response){\n\t\t\tif(response.successful){\n\t\t\t\t// clear the user-add form\n\t\t\t\tdijit.byId('addUserFormDialog').hide();\n\t\t\t\tvar userManager = dijit.byId('addUserFormDialog').userManager;\n\t\t\t\tuserManager.userGrid.reloadGrid();\n\t\t\t\tuserManager.getUserInfo(response.data[0], dojo.hitch(userManager, \"openRolesDialog\"));\n\t\t\t\tdijit.byId('addUserFormDialog').hide();\n\t\t\t\tdijit.byId('addUserFormDialog').destroyRecursive();\n        \t}else{\n\t\t\t\tvar english = response.error.split(\"::\");\n        \t\talert(english[0].concat('.'));\n\t\t\t}     \t\n\t\t}));\n</script>\n\t\t</div>\n\t\t\t<div dojoType=\"dijit.form.Button\" id=\"closeAddUser\">\n\t\t\t<script type=\"dojo/connect\" event=\"onClick\">\n\t\t\t\t\tdijit.byId('addUserFormDialog').hide();\n\t\t\t\t\tdijit.byId('addUserFormDialog').destroyRecursive();\n\t\t\t</script>\n\t\t\tCancel\n\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.connect( this.dashBoard, "onHideWidget", "onHide");
		// When the mouse is over a hint item, show the hint on the status line
		//////////////this._subscribes.push( dojo.subscribe( '/status/hint', dojo.hitch(this.statusLine, "setContent")));		
	},
	onHide: function(widget){
		var me = (widget == this);
		_sixnet_framework.log(3, 'onhide fired', arguments, me);
		this.framePane.setContent('');
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce thumbnail in "Running Apps" pane on side of dashboard
		return new dijit.layout.ContentPane({content:'Add User'});
	},
	openChooseUserPage: function(){
		this.surveyStack.selectChild(this.chooseUserPage.id);
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.file.VersionTextBox']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.file.VersionTextBox'] = true;

dojo.provide('com.sixnet.services.modules.file.VersionTextBox');

dojo.declare('com.sixnet.services.modules.file.VersionTextBox', [ dijit.form.ValidationTextBox ], {
	validField:false,
	validator: function(value, constraints){
		_sixnet_framework.log(2, "validator called", arguments);
		if( !this.inherited(arguments)) return false;
		this.validField = true;
		this.onValidate(this);
		dijit.hideTooltip(this.domNode);
		if(!this.validField){
			this.state = 'Error';
			this.displayMessage('The Version must be greater than any on the server.');
		}
		return this.validField;
	},
	_setValidField: function(boolValue){
		this.validField = boolValue;
		_sixnet_framework.log(2, "validField set to ", boolValue);
	},
	onValidate: function(versionTextBox){
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.file.fileAdd']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.file.fileAdd'] = true;




















dojo.declare('com.sixnet.services.modules.file.fileAdd', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateName: 'templates/fileAdd.html',
	icon: 'unit.png',
	title:'',
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.connect(this.version, "onValidate", "onVersionValidate");
		console.log("dojo.query('.dijitFileInputVisible', this.packageForm.domNode)[0]", dojo.query(".dijitFileInputVisible", this.packageForm.domNode)[0]);
		// fix width of file upload textbox
		if(dojo.isIE){
			dojo.style(dojo.query(".dijitFileInputVisible", this.packageForm.domNode)[0], "width", "13.5em");
		}else{
			dojo.style(dojo.query(".dijitFileInputVisible", this.packageForm.domNode)[0], "width", "14.3em");
		}
	},
	onVersionValidate: function(versionWidget){
		var newVersion = this.version.getValue();
		var oldVersion = this.titleVersion.domNode.innerHTML;
		_sixnet_framework.log(1, 'version check', newVersion, oldVersion, 'valid:', ( newVersion != oldVersion));
		versionWidget.validField = ( newVersion != oldVersion);
	},
	onMassConfigChecked:function(){
		// mimick GMU1 in force-setting file type upon selecting Mass Config radio
		// then disable select
		this.fileType.setValue('pat');
		this.fileType.setAttribute( "disabled", true);
		this.onFormChange();
	},
	onFormChange: function(){
		// validate form.
		_sixnet_framework.log(1, 'version widget:', this.version);
		this.packageUploadButton.set("disabled", true);
		if( this.fileField.fileInput.files && (this.fileField.fileInput.files.length < 1)){
			_sixnet_framework.log(1, "fileField", this.fileField);
			return;
		}
		if( !this.titleWidget.isValid()){
			_sixnet_framework.log(1, "title", this.titleWidget.isValid());
			return;
		}
		if( !this.version.isValid()){
			_sixnet_framework.log(1, "version", this.version.isValid());
			return;
		}
		var filePlatform = this.packageForm.getValues().platform;
		
		if( filePlatform.length > 0)
			this.packageUploadButton.set("disabled", false);
		
	},
	onTitleChange: function(){
		// See what the version of this file is on the server...
		_sixnet_framework.bc('file','getCurrentVersion', { title: this.titleWidget.getValue()}, dojo.hitch(this, function(response){
			if( response.successful && response.data){
				this.titleVersion.setContent(response.data);
				if( this.version.getValue() == '1.0.0'){
					this.version.setValue(response.data);
				}
			}else{
				this.titleVersion.setContent('<div style="color:red">None</div>');
			}
			this.version._refreshState();
			this.onFormChange();
		}));
	},
	onFileFieldChange: function(){
		if( this.titleWidget.get("value") == ''){
			this.titleWidget.set("value", ((this.fileField.fileInput.value).split('\\').pop()).split('.')[0]);
		}
		this.onFormChange();
	},
	onNormalChecked: function(){
		// reverse massConfigChecked - de-disable select
		_sixnet_framework.log(1, "onNormalChecked", this.fileType);
		//this.fileType.removeAttribute("disabled");
		this.fileType.setAttribute( "disabled", false);
		this.onFormChange();
	},
	onFileUpload: function(){
		// event stub
	},
	packageFormSubmit: function(){
		var formValues = this.packageForm.getValues();
		console.log(formValues, "  <<<<<<<<<< formValues >>>>>>>>>");
		formValues.massConfig = (formValues.massOrNormal == "1")?'TRUE':'FALSE';
		//formValues.fileName = this.fileField.fileInput.value;
		//delete formValues.fileField;
		delete formValues.massOrNormal;
		_sixnet_framework.bc('file', 'importFile', formValues, dojo.hitch(this, function(){
			_sixnet_framework.log(1, 'successish', arguments);
			this.packageForm.reset();
			this.onFileUpload();
		}), dojo.hitch(this, function(){
			_sixnet_framework.log(1, 'failish', arguments);
		}), this.packageForm.domNode);
	}
	
});
dojo.provide('com.sixnet.services.modules.file.fileAdd');

}

if(!dojo._hasResource['com.sixnet.services.modules.file.formatters']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.file.formatters'] = true;


dojo.provide('com.sixnet.services.modules.file.formatters');


dojo.declare('com.sixnet.services.modules.file.formatters', [com.sixnet.services.core.data.formatters], {
	timeToDate: function(value,idx){
		var time = '';
		var adate = new Date();
		if(value != 0){
			adate.setTime(value * 1000);
			return dojo.date.locale.format(adate,{datePattern:'M/d/y ', timePattern:'K:mm Z'});
		}else{
			//  you need to know how to make sort work with formATTERS.
			var cp = new dijit.layout.ContentPane({content:"Legacy", value:value});
			return cp;
		}
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.file.fileManager']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.file.fileManager'] = true;

















dojo.declare('com.sixnet.services.modules.file.fileManager', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateName: 'templates/fileManager.html',
	icon: 'unit.png',
	postCreate: function(){
		this.inherited("postCreate", arguments);
	},
	reload: function(){
		this.fileGrid.reloadGrid();
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce thumbnail in "Running Apps" pane on side of dashboard
		
		return false;//new dijit.layout.ContentPane({content:this.buildIconImage()});
	}
	
});
dojo.provide('com.sixnet.services.modules.file.fileManager');

}

if(!dojo._hasResource['com.sixnet.services.modules.access.jobAdd']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.jobAdd'] = true;
dojo.provide('com.sixnet.services.modules.access.jobAdd');
















dojo.declare('com.sixnet.services.modules.access.jobAdd', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n<div dojoType=\"com.sixnet.services.core.data.store\" jsid=\"addJobFileStore\" filteringSelectMode=\"true\" identifier=\"id\" module=\"access\" viewName=\"sixnet_file\" ></div>\n<div dojoType=\"com.sixnet.services.core.data.store\" jsId=\"unitStore\" dojoAttachPoint=\"unitStore\" identifier=\"id\" viewName=\"job_units\" module=\"access\" ></div>\n\t\n\n <div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\" style=\"background:#fff\">\n \t<div dojoType=\"dijit.layout.ContentPane\" region=\"top\"> \t\n\t    \t<div dojoType=\"dijit.form.Form\" dojoAttachPoint=\"jobForm\" style=\"font-family:Myriad,Helvetica,Tahoma,Arial,clean,sans-serif;\">\n\t\t    \t<div class=\"headerLabel\">Add Job</div>\n\t\t    \t<div style=\"float:left; width:350px\" dojoType=\"dijit.layout.ContentPane\">\n\t\t\t    \t<div class=\"fullRow\">\n\t\t\t\t\t\t<div class=\"jobAddLabelLeft\">\n\t\t\t\t\t    \tJob Name\n\t\t\t\t\t    </div>\n\t\t\t\t\t   \t<div class=\"jobAddInputRight\">         \n\t\t\t\t\t\t\t<div dojoType=\"dijit.form.ValidationTextBox\" style=\"width:240px;\" regExp=\"[0-9a-zA-z]{1}[0-9a-zA-z _-]*\" dojoAttachEvent=\"onChange:onJobNameChange\" required=\"true\" dojoAttachPoint=\"addJobName\" name=\"jobName\"></div>\n\t\t\t\t\t    </div>\n\t\t\t\t\t</div>\n\t\t\t    \t<div class=\"fullRow\" style=\"height:25px;\">\n\t\t\t\t\t\t<div class=\"jobAddLabelLeft\">\n\t\t\t\t\t    \tFile Type\n\t\t\t\t\t    </div>  \n\t\t\t\t    \t<select class=\"jobAddInputRight\" dojoType=\"dijit.form.FilteringSelect\" dojoAttachEvent=\"onChange:onJobFileTypeChange\" name=\"addJobFileType\" dojoAttachPoint=\"addJobFileType\" style=\"width:auto; margin-left:0px;\">\n\t\t\t\t    \t\t<option value=\"APP\">Application</option>\n\t\t\t\t    \t\t<option value=\"CFG\">Configuration</option>\n\t\t\t\t    \t\t<option value=\"PAT\">Patch</option>\n\t\t\t\t    \t\t<option value=\"CMD\">Command</option>\n\t\t\t\t    \t\t<option value=\"CLI\">Client Update</option>\n\t\t\t\t    \t</select>\n\t\t\t    \t</div>\n\t\t\t    \t<div class=\"fullRow\">\n\t\t\t\t    \t\t<div class=\"jobAddLabelLeft\">\n\t\t\t\t    \t\t\tPlatforms\n\t\t\t\t    \t\t</div>\n\t\t\t\t\t    \t<div class=\"jobAddInputRight\" style=\"border: solid 1px lightgrey; padding:1em; width:auto;text-align:center;\" >\n\n\t\t\t\t\t    \t\t<div style=\"float:left; width:33%; text-align:center;\">\n\t\t\t\t\t\t\t\t    <div style=\"width:5em; padding:.5em\" >\n\t\t\t\t\t\t\t\t    \tX86\n\t\t\t\t\t\t\t\t    </div>\n\t\t\t\t\t\t    \t\t<div style=\"margin-left:.5em\" dojoType=\"dijit.form.CheckBox\" dojoAttachPoint=\"platform_x86\" name=\"addJobPlatform\" dojoAttachEvent=\"onChange:onPlatformChange\" value=\"x86\">x86</div>\n\t\t\t\t\t\t    \t</div>\n\t\t\t\t\t    \t\t<div style=\"float:left; width:33%; text-align:center;\">\n\t\t\t\t\t\t\t\t    <div style=\"width:5em; padding:.5em\" >\n\t\t\t\t\t\t\t\t    \tppc\n\t\t\t\t\t\t\t\t    </div>\n\t\t\t\t\t\t    \t\t<div style=\"margin-left:.5em\" dojoType=\"dijit.form.CheckBox\" dojoAttachPoint=\"platform_ppc\" name=\"addJobPlatform\" dojoAttachEvent=\"onChange:onPlatformChange\" value=\"ppc\">ppc</div>\n\t\t\t\t\t\t\t\t </div>\n\t\t\t\t\t    \t\t<div style=\"float:left; width:33%; text-align:center;\">\n\t\t\t\t\t\t\t\t    <div style=\"width:5em; padding:.5em\" >\n\t\t\t\t\t\t\t\t    \tarm\n\t\t\t\t\t\t\t\t    </div>\n\t\t\t\t\t\t    \t\t<div style=\"margin-left:.5em\" dojoType=\"dijit.form.CheckBox\" name=\"addJobPlatform\" dojoAttachPoint=\"platform_arm\" dojoAttachEvent=\"onChange:onPlatformChange\" value=\"arm\">arm</div>\n\t\t\t\t\t\t    \t</div>\n\t\t\t\t\t    \t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t\t<div class=\"jobAddLabelLeft\">\n\t\t\t\t\t    \tChoose File\n\t\t\t\t\t    </div>\n\t\t\t\t\t    \n\t\t\t\t\t    <div class=\"jobAddInputRight\">\n\t\t\t\t\t    \t<div dojoAttachPoint=\"addJobFileMessage\"></div> \n\t\t\t\t\t    \t<div dojoType=\"dijit.form.ComboBox\" style=\"width:auto;\" query=\"{}\" name=\"jobFile\" fetchProperties=\"{ extendedQuery: { left_expression:{ left_field:'type', operator:'RLIKE', right_value:'^APP$' }, operator: 'AND', right_expression:{ left_field:'platform', operator:'RLIKE', right_value:'^$' }} , sort: {attribute:'title', descending: false} }\" autoComplete=\"false\" searchDelay=\"300\" valueAttr=\"id\" searchAttr=\"title\" labelAttr=\"title\" store=\"addJobFileStore\" dojoAttachEvent=\"onChange:onJobFileChange\" dojoAttachPoint=\"addJobFileName\"></div>\n\t\t\t\t\t    </div>\n\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div style=\"float:left; width:350px\" dojoType=\"dijit.layout.ContentPane\">\n\t\t\t\t \n\t\t\t\t\t<div class=\"fullRow\">\n\t\t\t\t\t\t<div class=\"jobAddLabelLeft\">\n\t\t\t\t\t    \t* Job Start Date\n\t\t\t\t\t    </div>\n\t\t\t\t\t    \n\t\t\t\t\t    \n\t\t\t           \t<div class=\"jobAddInputRight\">\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.widgets.dateTime\" name=\"jobStart\" dojoAttachPoint=\"addJobDateTime\" style=\"font-family:Myriad,Helvetica,Tahoma,Arial,clean,sans-serif;\"></div>   \n\t\t\t\t\t    </div>\n\t\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t<div class=\"fullRow\">\n\t\t\t\t<div class=\"jobAddLabelLeft\">\t\n\t\t\t\t\t&nbsp;\n\t\t\t    </div>\n\t\t\t   \t<div class=\"jobAddInputRight\"> \n\t\t\t\t<em>* Add job date/time will default to current.</em>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div class=\"fullRow\">\n\t\t\t\t<div class=\"jobAddLabelLeft\">\n\t\t\t    \tDescription\n\t\t\t    </div>\n\t\t\t   \t<div class=\"jobAddInputRight\">         \n\t\t\t    \t<textarea class=\"dijitTextArea\" dojoType=\"dijit.form.Textarea\" dojoAttachPoint=\"addJobDescription\" name=\"jobDescription\" style=\"width:15em; height:50px\" maxLength=\"250\"></textarea>\n\t\t\t    </div>\n\t\t\t</div>\n   \t\t\t<div class=\"fullRow\">\n\t\t\t\t<div class=\"jobAddLabelLeft\">\n\t\t\t\t\t&nbsp;         \n\t\t\t    </div>\n\t           \t<div class=\"jobAddInputRight\">         \n\t           \t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"unitCount\"></div>\n\t           \t\t<div dojoType=\"dijit.form.Button\" label=\"Add This Job\" disabled=\"true\" dojoAttachEvent=\"onClick:sendJobAdd\" dojoAttachPoint=\"submitAddJob\"></div>\n\t           \t\t\n\t            </div>\n\t\t\t</div>  \n\t\t\t</div>\n\t\t</div>\n\t</div>\n\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" >\n  \t\t<div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\" style=\"height:100%\" dojoAttachPoint=\"jobUnitContainer\"  >\n\t    \t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\">\n\t\t\t\t<div \n\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGrid\" \n\t\t\t\t\tjsId=\"unitGrid\" \n\t\t\t\t\tquery=\"{ left_field:'authorized', operator:'=', right_value: 'TRUE'}\"  \n\t\t\t\t\tstore=\"unitStore\" \n\t\t\t\t\tmodule=\"access\" \n\t\t\t\t\tviewName=\"units\"\n\t\t\t\t\tholdOff=\"true\"\n\t\t\t\t\tformatterClass=\"com.sixnet.services.modules.unit.formatters\"  \n\t\t\t\t\tdojoAttachPoint=\"unitGrid\">\n\t\t\t\t\t<div\t\n\t\t\t\t\t\tdojoAttachPoint=\"searchWidget\"\n\t\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridCheckSearch\"\n\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n</div>\n",
	targetType: 'unit',
	resultSize: 0,
	gridQuery: null,
	appParams: null,
	icon: 'unit_job.png',
	iconPath: '',
	_queryHandle: null,
	postCreate: function(){
		this.inherited(arguments);
		_sixnet_framework.log(3, "******** JOB ADD APP PARAMS:  ", this.appParams);
		this.fileSearchQuery = dojo.clone(this.addJobFileName.fetchProperties);
		this.fileSearchQuery.extendedError = dojo.hitch(this, "onAddJobFileError");
		this.addJobFileName.fetchProperties = this.fileSearchQuery; 
		//this.connect(this.unitGrid, "onSearchFieldChange", "onSearchFieldChange");
		this.connect(this.unitGrid, "onResultSizeChange", "onResultSizeChange");
		this.connect(this.unitGrid, "onQueryChange", "onGridQueryChange");
		this.connect(this, "onJobSuccess", function(){ _sixnet_framework.log(1, 'WTF-under');});
		this.connect(this.unitStore, "onEvent", "onStoreEvent");
		this._queryHandle = this.unitGrid.makeQueryHandle();
		this._queryHandle.setQuery({ 
					left_field:'architecture', 
					operator:'RLIKE', 
					right_value: '^$' 
					
				});
		if(this.appParams){
			this.preFormatForm();
		}
		_sixnet_framework.log(1, this.unitGrid.store, " <<<<<<<<<<<<< jobAdd >>>>>>>>>>>>>>> ", this.unitGrid);
		// The sixnetGrid requires that you maintain a handle to the query.
		
		//setTimeout(dojo.hitch(this.unitGrid, "reloadGrid"), 25000);
	},
	
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce thumbnail in "Running Apps" pane on side of dashboard
		console.log("buildWidgetThumbnailPane");
		this.inherited(arguments);
		if(this.appParams){
			this.iconPath = this.buildIconImage().concat('<div class="serial">').concat(this.appParams.serial).concat('</div>');
		}else{
			this.iconPath = this.buildIconImage();
		}
		return new dijit.layout.ContentPane({content:this.iconPath});
	},
	
	preFormatForm: function(){
		_sixnet_framework.log(1, 'Form data:', this.appParams);
		this.connect(this.searchWidget,"onSearchMenuInitialized",
			dojo.hitch(this, function(){
				console.log("ENTERING PREFORMAT.  THIS SHOULD HAPPEN ONCE!", this.id);
				this.unitGrid.queryLock( dojo.hitch(this, function(){
					try{
						var now = new Date();
						this.addJobName.setValue(this.appParams.serial+'-'+this.appParams.architecture+' ' + now.getTime());
						if('undefined' != typeof(this.appParams.architecture)){
							if('undefined' != typeof(this['platform_'+this.appParams.architecture.toLowerCase()])){
								this['platform_'+this.appParams.architecture.toLowerCase()].attr("checked", true);
							}
						}
						this.searchWidget.setSearchText(this.appParams.serial);
						this.searchWidget.applyChanges(false); // checks didn't change.
						console.log("Exiting querylock in preformatform");
					}catch(e){
						_sixnet_framework.log(0, 'Error in queryLock/preFormatForm:', e);
					}
				}),
					dojo.hitch(this, function(){
						setTimeout(dojo.hitch(this, function(){
							this.unitGrid.holdOff = false;
							this.unitGrid.startGrid();	
						}),10);
						
					})
				);
			}));
	},
	onStoreEvent: function(keywordArgs, data){
		var itemCount = data.data.totalItemCount;
		_sixnet_framework.log(1, 'Units:', itemCount);
		this.unitCount.setContent('Units to receive job: ' + itemCount);
	},
	onTestClick: function(){
		this.sendJobAdd(null, true); // send job (test info)
	},
	onGridQueryChange: function(newQuery){
		this.gridQuery = newQuery;
		_sixnet_framework.log(1, 'grid query', newQuery);
	},
	onResultSizeChange: function(size){
		this.resultSize = size;
		this.validate();
	},
	sendJobAdd: function(eventInfo, isTest){
		if(typeof(isTest) == 'undefined') isTest = false;
		var formValues = this.jobForm.getValues();
		_sixnet_framework.log(1, 'ajfn', this.addJobFileName.item, 'used in tab: ', this.usedInTab);
		if(this.addJobFileName.item){
			var targetData = '';
			var testTargetData = '001baf';
			var addJobParam = {
					name: isTest?'testjob':formValues.jobName,
					target: { 
						query: this.gridQuery
					},
					description: formValues.jobDescription,
					dateActive: formValues.jobStart,
					implementation: {
						type: 'file',
						data: isTest?'aab542094545f09usfdjsf0f0jswfsjdfj':this.addJobFileName.item.id[0],
						fileName: this.addJobFileName.item.title[0]
					}
				};
			_sixnet_framework.log(1, 'Add job param', addJobParam);
			_sixnet_framework.bc('job','addJob', addJobParam, dojo.hitch(this, "onJobAddSuccess"), dojo.hitch(this, "onJobAddFail"));
		}
	},
	onJobSuccess: function(){
		_sixnet_framework.log(1, 'WTF');
	},
	onJobAddSuccess: function(){
		this.jobForm.reset();
		this.onJobSuccess();
	},
	
	setTabFunction: function(tabFunction){
		_sixnet_framework.log(1, tabFunction, this.tabFunction, "  << tabF");
		this.tabFunction = tabFunction;
	},
	
	onJobAddFail: function(){
		_sixnet_framework.log(1, 'job call error', arguments);
	},
	onSearchFieldChange: function(fieldName, checked, secondSearch){
		_sixnet_framework.log(1, 'onSearchFieldChange');
		if( fieldName == 'major_name'){
			this.unitGrid.showSecondSearch(checked);
		}
		if( checked && !secondSearch){
			switch(fieldName){
				case 'major_name': this.targetType = 'major'; break;
				case 'minor_name': this.targetType = 'minor'; break;
				case 'serial': this.targetType = 'unit'; break;
			}
		}
		if( checked && secondSearch){
			this.targetType = 'major_minor';
		}
	},
	onResize: function(){
		this.inherited(arguments);
		this.jobUnitContainer.resize();
	},
	onJobNameChange: function(){
		this.validate();
	},
	onPlatformChange: function(){
		this.addJobFileName.setValue('');
		this.onJobFileQueryChange();
	},
	onAddJobFileError: function(message){
		dojo.publish('/status/hint', [message]);
		setTimeout(dojo.hitch(dojo,"publish", '/status/hint', ['']),2000);
	},
	onJobFileTypeChange: function(){
		this.addJobFileName.setValue('');
		var formValues = this.jobForm.getValues();
		var fileType = formValues.addJobFileType;
		if( typeof(fileType) == 'undefined') fileType = '';
		this.fileSearchQuery.extendedQuery = this.buildFileSearchQuery();  
	},
	onJobFileChange: function(){
		this.validate();
	},
	buildFileSearchQuery: function(){
		var formValues = this.jobForm.getValues();
		var fileType = formValues.addJobFileType;
		return {
			left_expression: {
				left_expression:{ 
					left_field:'type', 
					operator:'=', 
					right_value: fileType
				}, 
				operator: 'AND', 
				right_expression:{ 
					left_field:'platform', 
					operator:'RLIKE', 
					right_value: '^' + formValues.addJobPlatform.join('|') + '$' 
				}
			},
			operator:'AND',
			right_expression:{
				left_field:'deleted',
				operator:'=',
				right_value:'FALSE'
			}
		};
	},
	validate: function(){
		var formValues = this.jobForm.getValues();
		this.submitAddJob.attr("disabled", true);
		if(! this.addJobName.isValid()) return;
		if( formValues.jobFile == '' || !this.addJobFileName.isValid()) return;
		if( formValues.addJobPlatform.length == 0) return;
		this.submitAddJob.attr("disabled", false);
		if(this.resultSize == 0){
			var eventPane = new dijit.layout.ContentPane({content: "Warning:  No units selected for this job."});
			_sixnet_framework._logger.event(eventPane);
		}
	},
	onJobFileQueryChange: function(){
		// change the file list query (drop down)
		
		var formValues = this.jobForm.getValues();
		var fileType = formValues.addJobFileType;
		if( typeof(fileType) == 'undefined') fileType = '';
		
		this.fileSearchQuery.extendedQuery = this.buildFileSearchQuery();  
		this.addJobFileName.fetchProperties = this.fileSearchQuery; 
		
		
		// change the unit grid query
		this._queryHandle.setQuery(
				{ 
					left_field:'architecture', 
					operator:'RLIKE', 
					right_value: '^' + formValues.addJobPlatform.join('|') + '$' 
					
				}
		);
		this.validate();
		
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.colorPickerDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.colorPickerDash'] = true;
dojo.provide('com.sixnet.services.modules.access.colorPickerDash');
//


//
dojo.declare('com.sixnet.services.modules.access.colorPickerDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/colorDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.colorPicker');
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
});


}

if(!dojo._hasResource['com.sixnet.services.modules.access.userDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.userDash'] = true;
// tell package managerthat a specific package has been loaded
dojo.provide('com.sixnet.services.modules.access.userDash');
// load dojo dashWidgetBash

// _Templated == mix-in Widget HTML


// simulate Class system like Java with dojo.declare 
// 3 arguments (optional_global_name, null or base class or array of objects (multiple inheritance), object hash of properties to be mixed in after all other inheritance has been solved)
// dojo.moduleUrl is used to return a dojo._Url object relative to a module.
dojo.declare('com.sixnet.services.modules.access.userDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/userDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){

		//this.dashBoard.startedWorking();
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.userManager');
		//this.dashBoard.stoppedWorking();	
		// end copy dash.js onClick-
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.changeAccount']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.changeAccount'] = true;
dojo.provide('com.sixnet.services.modules.access.changeAccount');




dojo.declare('com.sixnet.services.modules.access.changeAccount', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div dojoAttachPoint=\"CHANGE_ACCOUNT\" style=\"margin:0; padding:0\">\n\t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:100%; margin-right:15px; border:none\" gutters=\"false\">\n\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"padding:0; margin:0;\" dojoAttachPoint=\"accountButtonHolder\" region=\"center\">\t\t\n\t\t</div>\n\t</div>\n</div>\n",
	icon: 'wrld_accnt_change.png',
	iconPath: '',
	postCreate: function(){
		this.inherited("postCreate", arguments);
		// get user accounts and then do select account dialog (same as login)
		this.getUserAccounts();
	},
	
	onClickAccount: function(){
		var widgetBase = new com.sixnet.services.core.dashWidgetBase({ dashBoard: this.dashBoard });
		widgetBase.resetWidgetCount();
//		_sixnet_framework.log(1, this, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
    	this.setAccount(arguments[0].currentTarget.value);
	},
	
	buildSelectAccount: function(data){
		for(i=0; i<data.length; i++){
			var accountIcon = "";
			if(data[i].iconLink){
				accountIcon = data[i].iconLink;
			}else{
				accountIcon = './images/favicon.png';
			}
			var content = '<img class="dashImage" src="'.concat(accountIcon).concat('"></img><div class="dashLabel">').concat(data[i].name).concat('</div>');
			var cp1 = new dijit.layout.ContentPane({
				content: content
	    	}).placeAt(dojo.byId(this.accountButtonHolder.domNode), "last");
			
			dojo.addClass(cp1.domNode, 'sudoDashBoard');
//			dojo.addClass(cp1.domNode, 'dashBoardWidget');
			dojo.attr(dojo.byId(cp1.domNode), 'value', data[i].account_id);
			this.connect(cp1.domNode, 'onmousedown', this.onClickAccount);
		}
	},

	getUserAccounts: function(){
		_sixnet_framework.bc('access','getUserAccounts', { userId: _sixnet_framework._userId}, dojo.hitch(this, function(response){
			// dialog w/ dd and list of accounts goes here.
			if(response.successful){
				if(typeof(response.data) != 'object'){
					alert("Your login session is corrupted. Please login again.");
					//  and do log out process
					this.unload();
					_sixnet_framework.setSession('');
					_sixnet_framework.reloadDash();
				}
				if(response.data.length > 1){
					this.buildSelectAccount(response.data);
				}else{
					this.setAccount(response.data[0].account_id);
				}
			}else if(!response.successful){
				//  split error returned and alert
				var alertError = response.error.split("::");
				alert(alertError[0]);
				//  and do log out process
				this.unload();
				_sixnet_framework.setSession('');
				_sixnet_framework.reloadDash();
				
			}
		}));
	},
	
	buildWidgetThumbnailPane: function(){
//		return false;
	},
	
	setAccount: function(accountId){
		//this.dashBoard.startedWorking();
//		setTimeout(dojo.hitch(this, function(){
//			//dojo.addOnLoad(dojo.hitch(this.dashBoard, "stoppedWorking"));
//		}), 1500);
		var changeAccount = this;
//
//			changeAccount.unload();
		_sixnet_framework.bc('access', 'setAccount', { accountId: accountId }, dojo.hitch(this, function(response){
					if( !response.successful){
						alert('Could not set account. Aborting.');
						return;
					}else{
		   				this.unload();
						_sixnet_framework.setAccount(accountId);
		   				_sixnet_framework.getUserRoles();
		   				_sixnet_framework.reloadDash();
		   				console.log(this, " << change account after account is set");
					}
			
		}));

	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.job.jobDetailList']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.job.jobDetailList'] = true;
dojo.provide('com.sixnet.services.modules.job.jobDetailList');












//


//dojo.require("dojo.io.*");



dojo.declare('com.sixnet.services.modules.job.jobDetailList', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div dojoType=\"com.sixnet.services.core.data.writeStore\" jsid=\"jobDetailListStore\" identifier=\"id\" module=\"access\" viewName=\"job_detail\" >\n\t</div>\n\t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:100%; margin-right:15px; border:none;\" gutters=\"false\">\n\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" gutters=\"false\">\t\t\n\t\t\t<div \n\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGrid\"  \n\t\t\t\tmodule=\"access\" \n\t\t\t\teditRole=\"ROLE_JOB_ADMIN\" \n\t\t\t\tviewRole=\"ROLE_JOB_VIEWER\" \n\t\t\t\tjsid=\"jobDetailListGrid\" \n\t\t\t\tquery=\"{}\" \n\t\t\t\tformatterClass=\"com.sixnet.services.modules.unit.formatters\"\n\t\t\t\tstore=\"jobDetailListStore\" \n\t\t\t\tregion=\"center\" \n\t\t\t\tviewName=\"job_detail\" \n\t\t\t\tshowSaveView=\"true\" \n\t\t\t\tshowContextMenu=\"true\" \n\t\t\t\tdojoAttachPoint=\"jobDetailListGrid\">\n\t\t\t\t<div \n\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridCheckSearch\"\n\t\t\t\t\tgrid=\"jobDetailListGrid\"\n\t\t\t\t\t></div>\n\t\t\t</div>\t\t\n\t\t</div>\n\t</div>\n</div>\n",
	icon: 'job_detail_list.png',
	iconPath: '',
	appParams: {},
	_queryHandle: null,
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this._queryHandle = this.jobDetailListGrid.makeQueryHandle();
		this._queryHandle.setQuery({ left_field: 'job_id', operator:'=', right_value: this.appParams.item.id});
		//this.jobDetailListGrid.formatter.setJobListDetail(this);
	},
	
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce thumbnail in "Running Apps" pane on side of dashboard
		
		this.buildIconImage();
		this.iconPath = this.iconPath.concat('<div class="serial" style="overflow:hidden; width:90%; text-align:center">').concat(this.appParams.item.name).concat('</div>');
		
		return new dijit.layout.ContentPane({content:this.iconPath});
	},
	reIssue: function(item){
		item.status = 'PENDING';
		_sixnet_framework.bc('access', 'updateViewData', { viewName: 'job_detail_update', items:[item ] }, dojo.hitch(this, function(){
			this.onReIssue();
			this.jobDetailListGrid.reloadGrid();
			_sixnet_framework.log(1, 'No error setting detail to pending');
		}), dojo.hitch(this, function(error){
			_sixnet_framework.log(1, 'Error setting detail to pending:' + error );
		}));
	},
	onReIssue: function(){
	}

});

}

if(!dojo._hasResource['com.sixnet.services.modules.job.formatters']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.job.formatters'] = true;



dojo.provide('com.sixnet.services.modules.job.formatters');


dojo.declare('com.sixnet.services.modules.job.formatters', [com.sixnet.services.modules.unit.formatters], {
	onReIssue: function(item){
	},
	onDetail: function(item){
	},
	jobname: function(value, idx, cell){
		var item = this.grid.getItem(idx);
		var dContainer = new dijit.layout.ContentPane({});
		var name = new dijit.layout.ContentPane({style:'text-align:left; float:left; height:auto; cursor:pointer; width:100%;', content: value });
		var D = "<img title='details' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/D.gif\" />");
		var detailCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; cursor:pointer;', content:D, onClick: dojo.hitch(this, function(value, idx){
			this.onDetail(item);
		})});
		name.placeAt(dContainer.domNode);
		detailCP.placeAt(dContainer.domNode);
		return dContainer;
	},
	jobtarget: function(value, idx, cell){
		var content = new dijit.layout.ContentPane({ });
		var targetData = dojo.fromJson(value);
		var contentText = '';
		switch( targetData.type){
		case 'unit':
			contentText += 'Unit: ' + targetData.data ;
			break;
		case 'major':
			contentText += 'Major Name: ' + targetData.data ;
			break;
		case 'minor':
			contentText += 'Minor Name: ' + targetData.data ;
			break;
		case 'major_minor':
			contentText += 'Major Name: ' + targetData.data.major_name + '<br/>';
			contentText += 'Minor Name: ' + targetData.data.minor_name ;
			break;
		default:
			//contentText += 'Query: ' + dojo.toJson( targetData.query);
			contentText += 'Custom Query';
		break;
		}
		content.setContent(contentText);
		return content;
	},
	jobimplementation: function(value, idx, cell){
		var content = new dijit.layout.ContentPane({ });
		var implData = dojo.fromJson(value);
		var contentText = 'Implementation: ' + implData.type + '<br/>';
		switch( implData.type){
		case 'file':
			contentText += 'File: ' + implData.fileName ;
			break;
		}
		content.setContent(contentText);
		return content;
	}

});

}

if(!dojo._hasResource['com.sixnet.services.modules.job.jobList']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.job.jobList'] = true;
dojo.provide('com.sixnet.services.modules.job.jobList');











//


//dojo.require("dojo.io.*");



dojo.declare('com.sixnet.services.modules.job.jobList', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div dojoType=\"com.sixnet.services.core.data.writeStore\" jsid=\"jobListStore\" identifier=\"id\" module=\"access\" viewName=\"sixnet_job\" >\n\t</div>\n\t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:100%; margin-right:15px; border:none;\" gutters=\"false\">\n\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" gutters=\"false\">\t\t\n\t\t\t<div \n\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGrid\" \n\t\t\t\tmodule=\"access\" \n\t\t\t\teditRole=\"ROLE_JOB_ADMIN\" \n\t\t\t\tcells=\"{ name:'Detail', formatter: 'jobControls'}\" \n\t\t\t\tviewRole=\"ROLE_JOB_VIEWER\" \n\t\t\t\tjsid=\"jobListUnitGrid\" \n\t\t\t\tquery=\"{}\" \n\t\t\t\tformatterClass=\"com.sixnet.services.modules.job.formatters\"  \n\t\t\t\tstore=\"jobListStore\" \n\t\t\t\tregion=\"center\" \n\t\t\t\tviewName=\"sixnet_job\" \n\t\t\t\tshowSaveView=\"true\" \n\t\t\t\tshowContextMenu=\"true\" \n\t\t\t\tdojoAttachPoint=\"jobListGrid\">\n\t\t\t\t<div \n\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridCheckSearch\"\n\t\t\t\t\tgrid=\"jobListUnitGrid\"\n\t\t\t\t\t></div>\n\t\t\t</div>\t\t\n\t\t</div>\n\t</div>\n</div>\n",
	icon: 'job_list.png',
	iconPath: '',
	appParams: {},
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.connect( this.jobListGrid.getFormatter() ,"onDetail", "onJobDetail");
		//this.jobListGrid.formatter.setJobList(this);
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce thumbnail in "Running Apps" pane on side of dashboard
		
		return false;//new dijit.layout.ContentPane({content:this.buildIconImage()});
	},
	onJobDetail: function(item){
		this.dashBoard.runApp( 'com.sixnet.services.modules.job.jobDetailList', {item:item, background: false});
	}
	
//	onunitRowClick: function(event){
//		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
//		var rowItem = this.unitGrid.grid.getItem( event.rowIndex);
//		this.unit = rowItem;
//		var message = "";
//		if(event.cell.editable){
//			message = "Double-click to edit unit detail";
//		}
//		dojo.publish( '/status/hint', [message]);
//		dojo.removeClass( this.unitToolbar.removeButton.focusNode, "disabledButton");
//	},
//	
//	onunitRowDblClick: function(event){
//		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
//		_sixnet_framework.log(3, "DblClick ", event);
//		var rowItem = this.unitGrid.grid.getItem( event.rowIndex);
//		this.unit = rowItem;
//		_sixnet_framework.log(3, "unit set:  ", this.unit);
//		var message = "";
//		if(!event.cell.editable){
//			message = "This cell is not editable";
//		}
//		dojo.publish( '/status/hint', [message]);
//	},
//	
//	onRemoveClick: function(){
//		if( dojo.hasClass( this.unitToolbar.removeButton.focusNode, "disabledButton")) return;
//		if( !confirm("Delete  `".concat( this.unit.unitname).concat( "` from units?"))) return;
//		_sixnet_framework.bc('access', 'removeunit', { unitId: this.unit.id }, dojo.hitch(this, function(response){
//			if( response.successful ){
//				dojo.addClass( this.unitToolbar.removeButton.focusNode, "disabledButton");
//				this.reloadGrid();
//			}
//		}));
//	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.jobManager']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.jobManager'] = true;
dojo.provide('com.sixnet.services.modules.access.jobManager');



















dojo.declare('com.sixnet.services.modules.access.jobManager', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n <div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\">\n \t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\"> \t\n\t<!-- File Control tab container -->\n\t<div dojoType=\"dijit.layout.TabContainer\" dojoAttachEvent=\"selectChild:childSelected\" dojoAttachPoint=\"tabContainer\" controllerWidget=\"dijit.layout.TabController\" style=\"width:100%; height:100%; margin-right:15px\" tabStrip=\"false\" tabPosition=\"left-h\">\n\t\t\n\t\t<!-- Job List -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Jobs\" dojoAttachPoint=\"jobsTab\">\t<!--  closable=\"true\" -->\t\n\t    \t<div dojoType=\"com.sixnet.services.modules.job.jobList\" dojoAttachPoint=\"jobList\"></div>\n\t    \t\n\t\t</div>\n\t\t\n\t\t<!-- Add jobs -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Add Job\" dojoAttachPoint=\"addJobTab\">\t<!--  closable=\"true\" -->\t\n\t    \t<div dojoType=\"com.sixnet.services.modules.access.jobAdd\" dojoAttachPoint=\"addJob\"></div>\n\t    \t\n\t\t</div>\n\t\t\n\t\t<!-- File List -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Files\" dojoAttachPoint=\"fileTab\">\t<!--  closable=\"true\" -->\n\t    \t<div dojoType=\"com.sixnet.services.modules.file.fileManager\" dojoAttachPoint=\"fileManager\"></div>\t\n\t    </div>\n\t\t\n\t\t<!-- Add Files -->\n\t    <div dojoType=\"dijit.layout.ContentPane\" title=\"Add Files\" dojoAttachPoint=\"addFileTab\">\t<!--  closable=\"true\" -->\n\t    \t<div dojoType=\"com.sixnet.services.modules.file.fileAdd\" dojoAttachPoint=\"addFile\" ></div>\t\n\t    </div>\n\t\t\n\t</div>\n\t</div>\n\t<!-- end tab container -->\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; padding-top:2px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n </div>\n</div>\n",
	//values:{count:0},
	currentUser:false,
	job:false, /*job is rowItem*/
	fileSearchQuery: null,
	addJobDate:{},
	addJobTime:{},
	storedDate:0,
	storedTime:0,
	icon: 'job.png',
	iconPath: '',
	currentTab: null,
	inAddJob: false,	
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		_sixnet_framework.log(1, "  got NEW ONE !!!!!!!!!!!!!!!!!!!!");
		//this.connect( this.dashBoard, "onHideWidget", "onHide");
		this.currentjob = _sixnet_framework._jobId;
		this.jobList.setDashBoard(this.dashBoard);
		this._subscribes.push( dojo.subscribe( '/status/hint', dojo.hitch(this.statusLine, "setContent")));
		setTimeout(dojo.hitch(this, "ini"), 0);
	},
	
	ini: function(){
		// initialize all connects and all here (had to be done via setTimeout)
		// we want: Jobs/Files "+" button to trigger their respective workers
		//           also, in reverse, we want the workers to return to display
		//             tabs on submit of form (and clear forms)
		this.connect(this.addJob, "onJobSuccess", "gotoJobList");
		this.connect(this.addFile, "onFileUpload", "gotoFileList");
	},
	gotoJobList: function(){
		this.tabContainer.selectChild(this.jobsTab.id);
		this.jobList.jobListGrid.reloadGrid();
	},
	
	gotoAddJob: function(){
		this.tabContainer.selectChild(this.addJobTab.id);
	},
	
	gotoFileList: function(){
		this.tabContainer.selectChild(this.fileTab.id);
		this.fileManager.reload();
	},
	
	gotoAddFiles: function(){
		this.tabContainer.selectChild(this.addFileTab.id);
	},
	
	childSelected: function(child){
		this.currentTab = child;
	},
	
	makeTimeTextBox: function(){
		var parent = this;
		//  TimeTextBox onChange fires with JS Date object (ignore M/D/Y)
		this.addJobTime = new dijit.form.TimeTextBox({
			constraints:{timePattern:'HH:mm:ss', clickableIncrement:'T00:15:00', visibleIncrement:'T00:15:00', visibleRange:'T01:00:00'},
			required:"true",
			onChange:function(){
				var date = new Date(arguments[0]);
				parent.setAMPM(date.getHours());
			},
			invalidMessage:"Invalid time. Use HH:MM:SS where HH is 00 - 23 hours."
		}).placeAt(dojo.byId(this.addJobTimeHolder.domNode, "last"));
		this.addJobTime.startup();
		var date = new Date();
		if(this.storedTime > 0){
			date = new Date(this.storedTime);
		}
		this.addJobTime.attr("value", date);
		this.setAMPM(this.addJobTime.value.getHours());
	},
	
	
	makeCalendar: function(){
		this.addJobDate = new dijit.form.DateTextBox({
			promptMessage:"mm/dd/yyyy",
			constraints:{datePattern:'MM/dd/yyyy', strict:true},
			invalidMessage:"Invalid date. Use mm/dd/yyyy format."
		}).placeAt(dojo.byId(this.addJobDateHolder.domNode, "last"));
		this.addJobDate.startup();
		var date = new Date();
		if(this.storedDate > 0){
			date = new Date(this.storedDate);
		}
		this.addJobDate.attr("value", date);
		_sixnet_framework.log(1, this.addJobDate, "  << addJobDate");
	},
	
//	onShow: function(widget){
//		if(this == widget){
//
//			_sixnet_framework.log(1, " << onShow jobMANAGER");
//			this.makeCalendar();
//			this.makeTimeTextBox();
//		}
//	},
//	
//	onHide: function(widget){
//		if(this == widget){
//			this.storedDate = this.addJobDate.value;
//			this.storedTime = this.addJobTime.value;
//			_sixnet_framework.log(1, " << onHide jobMANAGER", this.storedDate, this.storedTime);
//			this.addJobTime.destroyRecursive();
//			this.addJobDate.destroyRecursive();
//			return;
//		} else{
//			return;
//		}
//	},
//	
	setAMPM: function(hour){
		var ampm = "";
		if(hour < 12){
			ampm = "am";
		}else{
			ampm = "pm";
		}
		this.AMPM.attr("content", ampm);
	},
	
	showDate: function(){
		var date = new Date(this.addJobCalendar.value);
		//  this format yeilds the equivalent of:  YYYY-MM-DD HH:MM:SS
		_sixnet_framework.log(1, date, Math.floor(date.getTime()/1000));
		var formattedDate = dojo.date.locale.format(date,{datePattern:'y-MM-dd', timePattern:'hh:mm:ss'});
		var hour = date.getHours();
		this.addJobHour.attr("value", hour);
		this.addJobMinute.attr("value", date.getMinutes());
		this.setAMPM(hour);
//		_sixnet_framework.log(1, date.setDate(1267634028499000));
	},
	
	
	onAddJobClick: function(){
		// create an instance of Dialog with the content (loaded from href), id and title.
		var addJobFormDialog = new dijit.Dialog({jobManager: this, style:"width:310px;height:335px;", id:"addJobFormDialog", title:'Add job', href: this.templateUrl.concat('addJob.html'), onLoad: function(){
			// this method fires when the dialog has finished loading its content.
			dijit.byId('addJobFormDialog').connect(dijit.byId('addJobFormDialog'), "onCancel", function(){
				// this is for the 'x' button built into the Dialog.
				this.destroyRecursive();
			});
		}});
		addJobFormDialog.show();
		_sixnet_framework.log(1, dojo.byId(addJobFormDialog), " addJobFormDialog");
	},
	
	onjobRowClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		var rowItem = this.jobGrid.grid.getItem( event.rowIndex);
		this.job = rowItem;
		var message = "";
		if(event.cell.editable){
			message = "Double-click to edit job detail";
			dojo.publish( '/status/hint', [message]);
		}
	},
	
	onjobRowDblClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		_sixnet_framework.log(1, "DblClick ", event);
		var rowItem = this.jobGrid.grid.getItem( event.rowIndex);
		this.job = rowItem;
		_sixnet_framework.log(1, "job set:  ", this.job);
		var message = "";
		if(!event.cell.editable){
			message = "This cell is not editable";
		}
		dojo.publish( '/status/hint', [message]);
	},
	
	onRemoveClick: function(){
		if( !confirm("Delete  `".concat( this.job.jobname).concat( "` from jobs?"))) return;
		//  don't allow job to delete self... 
		if(this.job.id == this.currentjob){
			alert("You cannot delete yourself!");
		}else{
			_sixnet_framework.bc('access', 'removejob', { jobId: this.job.id }, dojo.hitch(this, function(response){
				if( response.successful ){
					this.reloadGrid();
				}
			}));
		}
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.loginDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.loginDash'] = true;
// tell package managerthat a specific package has been loaded
dojo.provide('com.sixnet.services.modules.access.loginDash');
// load dojo dashWidgetBash

// _Templated == mix-in Widget HTML


// simulate Class system like Java with dojo.declare 
// 3 arguments (optional_global_name, null or base class or array of objects (multiple inheritance), object hash of properties to be mixed in after all other inheritance has been solved)
// dojo.moduleUrl is used to return a dojo._Url object relative to a module.
dojo.declare('com.sixnet.services.modules.access.loginDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardDashImage\" src=\"${moduleUrl}templates/images/loginDash.png\"></img>\n</div>\n",
	dashBoard: false,
	postCreate: function(){
//		_sixnet_framework.log(3, "_s:  ", _sixnet_framework);
	},
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onMouseOver: function(){
		dojo.addClass( this.domNode, "mouseOver");
	},
	onMouseOut: function(){
		dojo.removeClass( this.domNode, "mouseOver");
	},
	onClick: function(){

		//  add dialog login real quick.
//		var loginDialog = new dijit.Dialog({
//			style:"width:310px;height:165px;",
//			title:'Login'
//		});
//		// first/last/before.
//	    var cp0 = new dijit.layout.ContentPane({
//	        style: "height:130px; width:90%; text-align:center; margin-right:auto; margin-left:auto"
//	    }).placeAt(loginDialog.domNode, "last");
//	    loginDialog.connect("onCancel", function(){
//			this.destroyRecursive();
//		});
//	    var loginManager = new com.sixnet.services.modules.access.loginManager({killMe:loginDialog});
//		loginManager.placeAt(cp0.domNode,"last");
//		loginDialog.show();
		//this.dashBoard.startedWorking();
//		_sixnet_framework.setSession('');
//		_sixnet_framework.reloadDash();
	    this.dashBoard.runApp( 'com.sixnet.services.modules.access.loginManager');
		//this.dashBoard.stoppedWorking();
		
		// end copy dash.js onClick-
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
		
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.unitPlot']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.unitPlot'] = true;
dojo.provide('com.sixnet.services.modules.access.unitPlot');










//dojo.require('com.sixnet.services.widgets.myMarkerClusterer');

dojo.declare('com.sixnet.services.modules.access.unitPlot', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n<style>\n\n.labelLeft{\n\tfloat:left;\n\ttext-align:right;\n\tcolor:b41319;\n\twidth:40%;\n\tmargin-right:5px;\n\tmargin-bottom:5px;\n\tclear:left;\n}\n.inputRight{\n\tfloat:left;\n\ttext-align:left;\n\twidth:50%;\n\tmargin-bottom:5px;\n\tfont-weight: bold;\n}\n</style>\n<div dojoType=\"com.sixnet.services.core.data.writeStore\" dojoAttachPoint=\"unitStore\" jsid=\"unitStore\" identifier=\"id\" module=\"access\" viewName=\"units\"></div>\n<div dojoType=\"com.sixnet.services.core.data.writeStore\" dojoAttachPoint=\"markerStore\" jsid=\"markerStore\" identifier=\"id\" module=\"access\" viewName=\"units\"></div>\n\t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:100%; margin-right:15px; border:none;\" gutters=\"false\">\n\t\n\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" gutters=\"false\">\t\n\t\t\t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:60%; border:none;\" gutters=\"false\">\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" gutters=\"false\">\t\n\t\t\t\t\t<div dojoType=\"com.sixnet.services.widgets.sixnetGMap\" dojoAttachPoint=\"unitGMap\" style=\"height: 100%; width:100%;\">\t\t\t\t\n\t\t\t\t\t</div>\t\t\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:40%; border:none;\" gutters=\"false\">\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"top\" gutters=\"false\">\t\t\n\t\t\t\t\t<div dojoType=\"com.sixnet.services.widgets.sixnetToolbar\" module=\"access\" editRole=\"ROLE_USER_ADMIN\" viewRole=\"ROLE_USER_VIEWER\" jsid=\"unitGPSToolbar\" store=\"unitStore\" searchField=\"serial\" dojoAttachPoint=\"unitGPSToolbar\" region=\"top\">\t\t\t\t\n\t\t\t\t\t</div>\t\n\t\t\t\t</div>\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" gutters=\"false\">\t\t\n\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.widgets.sixnetGrid\" jsid=\"unitGrid\" query=\"{ gps_position: { action:'NE', value:'false' }}\" formatterClass=\"com.sixnet.services.modules.access.formatters\" toolbar=\"unitGPSToolbar\" store=\"unitStore\" viewName=\"units\" showSaveView=\"true\"\tshowContextMenu=\"true\" dojoAttachPoint=\"unitGrid\">\n\t\t\t\t\t</div>\t\t\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; padding-top:2px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	user:false, /*user is rowItem*/
	icon: 'unit_plot.png',
	iconPath: '',
	markerData: false,
	markerClustererReady: false,
	markers: false,
	
	postCreate: function(){
		this.inherited("postCreate", arguments);
		// temp use of setUnitManager - just to populate grid. This is pre Clusterer.
		this.unitGrid.formatter.setUnitManager(this);
		this._subscribes.push( dojo.subscribe( '/status/hint', dojo.hitch(this.statusLine, "setContent")));
		this.unitGPSToolbar.restrictToolbar();
//		select gps_position from sixnet_unit_list where gps_position IS NOT NULL;
//		this.getGPSUnits();
//		unitStore
		this.markerData = this.markerStore.fetch({count:-1, start:0, query: { gps_position: { action:'NE', value:'false' }}, onComplete:dojo.hitch(
				this, "setMarkerData")});
		this.connect(this.unitGrid.grid,"onDblClick", "onUnitRowDblClick");
		//		var unitPlot = this;
//		dojo.addOnLoad(
//				function(){
//					// create the script to load the google maps api
//					_sixnet_framework.log(1, "addOnLoad");
//					var script = document.createElement("script");
//					script.type = "text/javascript";
//					script.src = window.location.host+"/misc/markerclusterer.js";
//					dojo.doc.getElementsByTagName("head")[0].appendChild(script);
//					unitPlot.markerClustererReady = true;
//					_sixnet_framework.log(1, " markerClustererReady ");
//				});
	},
	
	setMarkerData: function(items, i){
		this.markerData = items;
		this.setMarkers();
	},
	
	getGPSUnits: function(){
		_sixnet_framework.log(1, "inGPSUnits");
		_sixnet_framework.bc('access', 'getGPSUnits', { }, dojo.hitch(this, function(response){
			if( response.successful ){
//				_sixnet_framework.log(1, response.data, "  GPSUNITS");
				this.markerData = response.data;
				this.setMarkers();
			}else{
				_sixnet_framework.log(1, response.error, "error");
			}
		}));
	},

	setMarkers: function(){
//		_sixnet_framework.log(1, "at setMarkers");
		this.markers = [];
		// {"gps":[{"gps_lat":"26.105397783"},{"gps_long":"-80.257980967"},{"gps_alt":"-32"},{"gps_time":"205956"},{"gps_sat":"5"},{"gps_type":"1"},{"gps_feet":"6"},{"gps_cp_lat":""},{"gps_cp_long":""},{"gps_cp_rad":"0"}]}
		if(this.unitGMap.isReady /*&& this.markerClustererReady*/){
//			_sixnet_framework.log(1, this.markerData);
			//  add MarkerClusterer
			var data = this.markerData;
//			var markers = [];
			for(var i = 0; i < data.length; i++){
				var position ;
				try{
					position = dojo.fromJson(data[i].gps_position);
				}catch(e){
					// json error
					continue; // loop ignoring this entry.
				}
				var model = data[i].model;
				var architecture = data[i].architecture;
				var id = data[i].id;
				var serial = data[i].serial;
				var unit_id = data[i].unit_id;
				var description = data[i].description;
//				_sixnet_framework.log(1, "<<position json", position.gps);
				var gps_lat = 0;
				var gps_long = 0;
				if(typeof(position.gps) == 'undefined' || !position.gps) continue; 
				for(var j = 0; j < position.gps.length; j++){
					if(position.gps[j].gps_lat){
						gps_lat = position.gps[j].gps_lat;
					}
					if(position.gps[j].gps_long){
						gps_long = position.gps[j].gps_long;
					}
				}
			    var latlng = new GLatLng(gps_lat, gps_long);
//			    var marker = new GMarker(latlng);
//			    var marker = this.createMarker(latlng, model, architecture);
//			    markers.push(marker);
			    this.unitGMap.map.addOverlay(this.createMarker(latlng, model, architecture, gps_lat, gps_long, serial, unit_id, id, description, data[i]));
			}
			_sixnet_framework.log(1, this.unitMap.map, " <<< MAP");
//			this.unitGrid.grid.resize();
//			setTimeout(dojo.hitch(this.unitGMap.map, "setCenter", new GLatLng(38.055218650, -91.398930833), 3), 0);
//			var mcOptions = {gridSize: 50, maxZoom: 15};
//			var mc = new com.sixnet.services.widgets.myMarkerClusterer({map:this.unitGMap.map, markers:markers});
//			var mc = new MarkerClusterer(this.unitGMap.map, markers);//, mcOptions);
		}else{
			//  this is to handle the case the map is not loaded yet
//			_sixnet_framework.log(1, "not ready yet");
			setTimeout(dojo.hitch(this,"setMarkers"), 100);

		}
	},
	
	createMarker: function(destination, model, architecture, gps_lat, gps_long, serial, unit_id, id, description, item){
        // Create a lettered icon for this point using our icon class
		
        var baseIcon = new GIcon(G_DEFAULT_ICON);
        baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
        var modelIcon = new GIcon(baseIcon);
        var architecture = architecture.toLowerCase();
        if(architecture == 'unknown'){
        	architecture = 'x86';
        }
//	        modelIcon.image = "http://"+window.location.host+"/images/" + architecture + ".png";
        modelIcon.image = "http://"+window.location.host+"/images/marker_red.png";
        // Set up our GMarkerOptions object
        markerOptions = { icon:modelIcon, maxWidth:100 };
        var marker = new GMarker(destination, markerOptions);
        var parent = this;
        var map = this.unitGMap.map;
        // unit_id, serial, platform, and link to detail view.
        var attributeLabels = ['unit_id','model', 'architecture', 'gps_lat', 'gps_long', 'serial'];
        var attributeValues = [unit_id, model, architecture, gps_lat, gps_long, serial];
        var content = '';
        for(var i=0; i < attributeLabels.length; i++){
            content += "<div class='labelLeft'>"+attributeLabels[i]+"</div><div class='inputRight'>"+attributeValues[i]+"</div>"
        }
		var d = new dijit.layout.ContentPane({style:'text-align:center; font-size:9px; float:left; clear:none; height:12px; width:13px; cursor:pointer; background:#ccc; color:#b5111a; border: solid 1px #777', content: 'D', onClick: dojo.hitch(this, function(){
			this.detail(item);
		})});
        var contentDiv = dojo.create('div', {innerHTML:content, style:"margin:auto; text-align:center"});
        contentDiv.appendChild(d.domNode);
        GEvent.addListener(marker, "click", function() {
        	marker.openInfoWindowHtml(contentDiv);
        });
        marker.ID = id;
        this.markers.push(marker);
        return marker;
	},
	
	focusItemRow: function(id){
		_sixnet_framework.log(1, id, this.unitGrid.grid.getItemIndex(id));
//		this.unitGrid.grid.setQuery({id:id});
//		>	$this->grid->scriptCaptureStart('dojo/method', 'onClick', array('args' => 'row')); 
//		echo "var item = profileGrid.getItem(row.rowIndex);"; 
//		echo "var value = store.getIdentity(item);";
//		this.unitGrid.grid.scrollToRow(this.unitGrid.grid.getItemIndex(id));
	},
	
	onUserRowClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		var rowItem = this.unitGrid.grid.getItem( event.rowIndex);
		this.user = rowItem;
		var message = "";
		dojo.removeClass( this.userToolbar.removeButton.focusNode, "disabledButton");
		if(event.cell.editable){
			message = "Double-click to edit user detail";
			dojo.publish( '/status/hint', [message]);
		}
	},
	
	onUnitRowDblClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		_sixnet_framework.log(1, "DblClick ", event);
		var rowItem = this.unitGrid.grid.getItem(event.rowIndex);
		this.unit = rowItem;
		//
		for(var i=0; i<this.markers.length; i++){
			if(this.markers[i].ID == this.unit.id){
				_sixnet_framework.log(1, this.markers[i]);
//				this.unitGMap.map.setCenter(this.markers[i].C);
				GEvent.trigger(this.markers[i],'click');
//				this.unitGMap.map.panTo(this.markers[i].C)
			}
		}
		_sixnet_framework.log(1, "unit set:  ", this.unit);
		var message = "";
		if(!event.cell.editable){
			message = "This cell is not editable";
		}
		dojo.publish( '/status/hint', [message]);
	},
	
	detail: function(item){
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.unitDetail', {item:item, background: false});
	}
});

}

if(!dojo._hasResource["com.sixnet.services.modules.unit.unitSearchActions"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.modules.unit.unitSearchActions"] = true;
dojo.provide("com.sixnet.services.modules.unit.unitSearchActions");




dojo.declare("com.sixnet.services.modules.unit.unitSearchActions",[dijit._Widget, dijit._Templated],{
	widgetsInTemplate: true,
	templateString: dojo.cache("com.sixnet.services.modules.unit", "templates/unitSearchActions.html", "<div style=\"float:right; width:150px; margin-top:.5em\">\n\t\t<div style=\"float:left\" dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"actionMenu\"></div>\n</div>\n"),
	grid: null,
	authorizedSearch: null,
	postCreate: function(){
		this.inherited(arguments);
		this.grid.addToToolbar(this, 'right');
		this.connect(this.grid, "onResultSizeChange", "onGridResultSizeChange");
	},
	onGridResultSizeChange: function(size){
		if(size == 0 || ( this.authorizedSearch && this.authorizedSearch.getValue() == 'TRUE')){
			this.domNode.style.display = 'none';
			this.actionMenu.setContent(''); // get rid of current drop menu
			return;
		}
		this.domNode.style.display = 'block';
		// build option list
	    var menuHolder = new dijit.layout.ContentPane({style: "width:178px; background:#fff; padding:4px; border:1px solid #7eabcd;"});
		var menuItem = new dijit.layout.ContentPane({ content:'Authorize Units', style:"float:left; clear:both; height:20px; width:160px"});
		dojo.addClass(dojo.byId(menuItem.domNode), '.dijitMenuItem');
		dojo.addClass(dojo.byId(menuItem.domNode), '.dijitReset');
		menuItem.placeAt(menuHolder.domNode);
		
		
		var dropMenu = new dijit.form.DropDownButton({ 
			label: "Search Actions:",
			dropDown: menuHolder
		});
		dropMenu.placeAt(this.actionMenu.domNode);
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.access.unitManager']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.unitManager'] = true;





















//dojo.require("dojo.io.*");



dojo.declare('com.sixnet.services.modules.access.unitManager', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateName: 'templates/unitManager.html',
	//templateString:"<div>\n\t<div dojoType=\"com.sixnet.services.core.data.writeStore\"  style=\"display:hidden\" jsid=\"unitStore\" mode=\"LIKE\" dojoAttachPoint=\"unitStore\" identifier=\"id\" module=\"access\" viewName=\"units\"></div>\n\t\n\t <div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\" >\n\t \t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\"> \n\t    \t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:100%; margin:auto\" gutters=\"false\">\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" >\n\t\t\t\t\t<div\tdojoType=\"com.sixnet.services.widgets.sixnetGrid\"  \n\t\t\t\t\t\t\tjsid=\"unitGrid\" \n\t\t\t\t\t\t\tquery=\"{}\" \n\t\t\t\t\t\t\tformatterClass=\"com.sixnet.services.modules.unit.formatters\" \n\t\t\t\t\t\t\tstore=\"unitStore\" \n\t\t\t\t\t\t\tmodule=\"access\" \n\t\t\t\t\t\t\tviewName=\"units\" \n\t\t\t\t\t\t\tshowSaveView=\"true\"\t\n\t\t\t\t\t\t\tshowContextMenu=\"true\" \n\t\t\t\t\t\t\tdojoAttachPoint=\"unitGrid\"\n\t\t\t\t\t\t\tclass=\"gridIE\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t<div\t\n\t\t\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridCheckSearch\"\n\t\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\t\n\t\t\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridView\"\n\t\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\t\n\t\t\t\t\t\t\tdojoType=\"com.sixnet.services.modules.unit.searchCheckBox\"\n\t\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t\tfieldName=\"authorized\"\n\t\t\t\t\t\t\tfieldLabel=\"Authorized\"\n\t\t\t\t\t\t\tjsId=\"authorizedBox\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\t\n\t\t\t\t\t\t\tdojoType=\"com.sixnet.services.modules.unit.unitSearchActions\"\n\t\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t\tauthorizedSearch=\"authorizedBox\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\n\t\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none;\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	//templateString: dojo.cache("com.sixnet.services.modules.access", "templates/unitManager.html", "<div>\n\t<div dojoType=\"com.sixnet.services.core.data.writeStore\"  style=\"display:hidden\" jsid=\"unitStore\" mode=\"LIKE\" dojoAttachPoint=\"unitStore\" identifier=\"id\" module=\"access\" viewName=\"units\"></div>\n\t\n\t <div dojoType=\"dijit.layout.BorderContainer\" gutters=\"false\" >\n\t \t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\"> \n\t    \t<div dojoType=\"dijit.layout.BorderContainer\" style=\"width:100%; height:100%; margin:auto\" gutters=\"false\">\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"center\" >\n\t\t\t\t\t<div\tdojoType=\"com.sixnet.services.widgets.sixnetGrid\"  \n\t\t\t\t\t\t\tjsid=\"unitGrid\" \n\t\t\t\t\t\t\tquery=\"{}\" \n\t\t\t\t\t\t\tformatterClass=\"com.sixnet.services.modules.unit.formatters\" \n\t\t\t\t\t\t\tstore=\"unitStore\" \n\t\t\t\t\t\t\tmodule=\"access\" \n\t\t\t\t\t\t\tviewName=\"units\" \n\t\t\t\t\t\t\tshowSaveView=\"true\"\t\n\t\t\t\t\t\t\tshowContextMenu=\"true\" \n\t\t\t\t\t\t\tdojoAttachPoint=\"unitGrid\"\n\t\t\t\t\t\t\tclass=\"gridIE\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t<div\t\n\t\t\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridCheckSearch\"\n\t\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\t\n\t\t\t\t\t\t\tdojoType=\"com.sixnet.services.widgets.sixnetGridView\"\n\t\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\t\n\t\t\t\t\t\t\tdojoType=\"com.sixnet.services.modules.unit.searchCheckBox\"\n\t\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t\tfieldName=\"authorized\"\n\t\t\t\t\t\t\tfieldLabel=\"Authorized\"\n\t\t\t\t\t\t\tjsId=\"authorizedBox\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<div\t\n\t\t\t\t\t\t\tdojoType=\"com.sixnet.services.modules.unit.unitSearchActions\"\n\t\t\t\t\t\t\tgrid=\"unitGrid\"\n\t\t\t\t\t\t\tauthorizedSearch=\"authorizedBox\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\n\t\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t\t</div>\n\t\t\t\t\t\n\t\t\t</div>\n\t\t</div>\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"height:25px; background:none;\">\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%; margin-left:3px; font-weight:bold;\">\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n"),
	currentunit:false,
	currentPermissions:false,
	unit:false, /*unit is rowItem*/
	stackController:false,
	icon: 'unit.png',
	iconPath: '',
	updateSubscription: null,
	postCreate: function(){
		this.inherited("postCreate", arguments);
		
		this.connect( this.fileAdd, "onFileUpload", "onFileUpload");
		this.connect( this.unitGrid.getFormatter(), "onFormatSerial", "onFormatSerial");
		this.connect( this.unitGrid.getFormatter(), "onGauOpen", "onGauOpen");
//		this.unitGrid.formatter.setUnitManager(this);
//		this.unitGrid.addRowStyler({styleGridRow:function(grid, row){
//				if(row.index < 0) return;
//				var levels = ["Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Info", "Debug"];	
//				var item = grid.getItem(row.index);
//				if(!item) return;
//				var value = parseInt(item["alert_level"]);
//				row.customClasses += " ".concat(levels[value]);
//			}
//		});
//		this.unitGrid.addRowStyler({styleGridRow:function(grid, row){
//			if(row.index < 0) return;
//			var levels = ["Emergency", "Alert", "Critical", "Error", "Warning", "Notice", "Info", "Debug"];	
//			var item = grid.getItem(row.index);
//			if(!item) return;
//			var value = parseInt(item["alert_level"]);
//			row.customClasses += " ".concat(levels[value]);
//			}
//		});
		this._subscribes.push( dojo.subscribe( '/status/hint', dojo.hitch(this.statusLine, "setContent")));
		// TODO: Code to make the user interface reflect changes to the writeStore
		
//		this.connect(this.selectOperation, "onchange", dojo.hitch(this, function(item){
//			if(item.target.value != ''){
//				dojo.attr(item.target, {selected:"selected"});
//				_sixnet_framework.log(3, "selectOperationChange", item.target.value);
//				this.selectOperationChange(item.target.value);
//				
//			}
//	    }));
//		this.unitToolbar.restrictToolbar();

		//  call to dashWidgetBase to add shadow.
		//  _this will add shadow in base class
		//  but not open/set content.
		//this.addShadow();
		this.updateSubscription =  _sixnet_framework.poller.subscribe('/unit/update', 
				dojo.hitch(this, function(eventName, payload){
					console.log("Handle update", payload);
					var item = this.unitStore.fetchItemByIdentity( { identity: this.unitStore.getIdentity(payload) });
					for(index in payload){
						if(!payload.hasOwnProperty(index)) continue;
						this.unitStore.setValue(item, index, payload[index]);
					}
				}));
	},
	unload: function(){
		_sixnet_framework.poller.unsubscribe(this.updateSubscription);
		this.inherited(arguments);
	},
	onGauOpen: function(address, secure){
		window.open((secure?"https":"http") + "://" + address + ":10000/", "Sixview Unit GUI", "menubar=1,resizable=1,width=1000,height=700");
	},
	onFormatSerial: function(item, serialPane){
	       
		
		var H = "<img title='history' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/H.gif\" />");

		var historyCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; margin-left:2px; cursor:pointer;', content: H, onClick: dojo.hitch(this, function(item){
			_sixnet_framework.getDash().runApp( 'com.sixnet.services.modules.access.unitHistory', {item:item, background: false});
		}, item)});
		historyCP.placeAt(serialPane.domNode, "last");
		
		if(item.authorized == 'TRUE'){
			var J = "<img title='add job' style='height:12px;width:12px;' src=\"".concat(dojo.moduleUrl("com.sixnet.services.modules.access")).concat("templates/images/J.gif\" />");
	        
			var jCP = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:12px; margin-left:2px; cursor:pointer;', content: J, onClick: dojo.hitch(this, function(item){
				_sixnet_framework.getDash().runApp('com.sixnet.services.modules.access.jobAdd', item);
			}, item)});
			jCP.placeAt(serialPane.domNode, "last");
		}
		
		//		if(this.jobListDetail){
//			var h = new dijit.layout.ContentPane({style:'text-align:center; float:left; clear:none; height:12px; width:13px; margin-left:2px; cursor:pointer; background:#ccc; color:#b5111a; border: solid 1px #777', content: 'R', onClick: dojo.hitch(this, function(value, idx){
//				this.jobListDetail.reIssue(item);
//			})});
//			h.placeAt(serialPane.domNode, "last");
//		}

	},
	onFileUpload: function(){
		// file was uploaded, switch to file view and refresh
		this.toolsTab.selectChild(this.fileListTab.id);
		this.fileList.reload();
	},
	
	trigger: function(item){
		//this.dashBoard.runApp( 'com.sixnet.services.modules.unit.trigger', {item:item}, true);
	},
	
	selectOperationChange: function(childNumber){
		//  switch operation
		return;
		_sixnet_framework.log(3, childNumber, " CN");
		var html = '';
		var height = 0;
		switch(childNumber){
			case '0':
				height = 100;
				html = '<div dojoType="dijit.layout.ContentPane" style="width:400px;height:100px" title="Migrate Group">				<div class="labelLeft">Migrate Group</div>				<div class="inputRight"><div style="border-style: solid; border-width: 1px; padding: 4px;">				New GMU Server 1: <input name="new_ipserv" size="20" maxlength="75" dojoType="dijit.form.TextBox">				<br />				New GMU Server 2: <input name="new_ipserv2" size="20" maxlength="75" dojoType="dijit.form.TextBox">				    <br /> Mode:<select dojoAttachPoint="servMode" class="dijitComboBox"><option value="none" selected="selected">Primary Only</option>				        <option value="secondaryonly">Secondary Only</option>				        <option value="both">Dual Use</option>			        <option value="error">Primary/Backup</option>				     </select>  <br />				     <input name="unitfile" value="1" dojoType="dijit.form.CheckBox" /> Create a Unit file list.				     <input name="ignore_on_migrate" checked="checked" value="1" dojoType="dijit.form.CheckBox" /> Ignore the units.				     </div>				</div>			</div>';
				break;
			case '1':
				height = 50;
				html = '<div dojoType="dijit.layout.ContentPane" title="Disable Group" style="width:100%;height:100px">				<div class="labelLeft">Disable Group</div>				<div class="inputRight"><input name="dis_1" value="1" dojoType="dijit.form.CheckBox" /> Disable GMU Server Address 1<br /><input name="dis_2" value="1" dojoType="dijit.form.CheckBox" /> Disable GMU Server Address 2</div>			</div>';
				break;
			case '2':
				height = 50;
				html = '<div dojoType="dijit.layout.ContentPane" title="Ignore Group">				<div class="labelLeft">Ignore Group</div>				<div class="inputRight"><em>Remote units will continue to check into this GMU but this unit will not appear in current status.</em></div>			</div>';
				break;
			case '3':
				height = 50;
				html = '<div dojoType="dijit.layout.ContentPane" title="Ignore Group Until Check-in">				<div class="labelLeft">Until Check-in</div>				<div class="inputRight"><em>Do not display this unit in current status until it checks in again</em></div>			</div>';
				break;
			case '4':
				height = 50;
				html = '<div dojoType="dijit.layout.ContentPane" title="Change Major Name">				<div class="labelLeft">Change Major Name</div>				<div class="inputRight"><input name="new_major" size="15" maxlength="45" value="" dojoType="dijit.form.TextBox"></div>			</div>';
				break;
			case '5':
				height = 50;
				html = '<div dojoType="dijit.layout.ContentPane" title="Change minor Name"><div class="labelLeft">Change minor Name</div><div class="inputRight"><input name="newMinorName" size="15" maxlength="45" value="" dojoType="dijit.form.TextBox"></div></div>';
				break;
			case '6':
				height = 50;
				html = '<div dojoType="dijit.layout.ContentPane" title="Change Unit ID"><div class="labelLeft">Change Unit ID</div><div class="inputRight"><input name="new_unitid" size="15" maxlength="32" value="" dojoType="dijit.form.TextBox"></div></div>';
				break;
			case '7':
				height = 50;
				html = '<div dojoType="dijit.layout.ContentPane" title="Export Units"><div class="labelLeft">Export Units</div><div class="inputRight"><em>Export</em></div></div>';
				break;
			default:
				height = 50;
				html = 'Select an operation from drop-down list.';
		}
		_sixnet_framework.log(3, "THNTLT : ", html);
		this.migrateFormHolder.attr({content:html, style:"height:".concat(height)});
		_sixnet_framework.log(3, "THNTLT : ", this.migrateFormHolder);
	},
	
		
	setunitPermissions: function(){
		// ??? Roles ???
		_sixnet_framework.bc('access', 'getunitRoles', {unitId: this.currentunit }, dojo.hitch(this, function(response){
			if(response.successful){
				var obj = {};
				dojo.forEach(response.data, function(ur){
					//_sixnet_framework.log(3, 'add item', ur);
					if(!obj[ur.module]){
						obj[ur.module] = {};
					}
					obj[ur.module][ur.role] = ur;
				});
				this.currentPermissions = obj;
				//_sixnet_framework.log(3, "Current unit ROLES:   ",dojo.toJson(obj, true));
			}else if(response.error){
				_sixnet_framework.log(3, response.error);
			}
			})
		);
		
	},
	
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce thumbnail in "Running Apps" pane on side of dashboard
		return new dijit.layout.ContentPane({content:this.buildIconImage()+this.incrementWidgetCount()});
//		return new dijit.layout.ContentPane({content:'Unit Management<br />'+this.incrementWidgetCount()});
	},
	
	onAddunitClick: function(){
		// create an instance of Dialog with the content (loaded from href), id and title.
		var addunitFormDialog = new dijit.Dialog({unitManager: this, style:"width:310px;height:335px;", id:"addunitFormDialog", title:'Add unit', href: this.templateUrl.concat('addunit.html'), onLoad: function(){
			// this method fires when the dialog has finished loading its content.
			dijit.byId('addunitFormDialog').connect(dijit.byId('addunitFormDialog'), "onCancel", function(){
				// this is for the 'x' button built into the Dialog.
				this.destroyRecursive();
			});
		}});
		addunitFormDialog.show();
		_sixnet_framework.log(3, dojo.byId(addunitFormDialog), " addunitFormDialog");
	},
	
	onunitRowClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		var rowItem = this.unitGrid.grid.getItem( event.rowIndex);
		this.unit = rowItem;
		var message = "";
		if(event.cell.editable){
			message = "Double-click to edit unit detail";
		}
		dojo.publish( '/status/hint', [message]);
//		dojo.removeClass( this.unitToolbar.removeButton.focusNode, "disabledButton");
	},
	
	onunitRowDblClick: function(event){
		if( typeof(event.cell) == 'undefined' || event.rowIndex < 0) return;
		_sixnet_framework.log(3, "DblClick ", event);
		var rowItem = this.unitGrid.grid.getItem( event.rowIndex);
		this.unit = rowItem;
		_sixnet_framework.log(3, "unit set:  ", this.unit);
		var message = "";
		if(!event.cell.editable){
			message = "This cell is not editable";
		}
		dojo.publish( '/status/hint', [message]);
	},
	
	onRemoveClick: function(){
//		if( dojo.hasClass( this.unitToolbar.removeButton.focusNode, "disabledButton")) return;
		if( !confirm("Delete  `".concat( this.unit.unitname).concat( "` from units?"))) return;
		_sixnet_framework.bc('access', 'removeunit', { unitId: this.unit.id }, dojo.hitch(this, function(response){
			if( response.successful ){
//				dojo.addClass( this.unitToolbar.removeButton.focusNode, "disabledButton");
				this.reloadGrid();
			}
		}));
	}
});
dojo.provide('com.sixnet.services.modules.access.unitManager');

}

if(!dojo._hasResource['com.sixnet.services.modules.access.changeAccountDash']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.access.changeAccountDash'] = true;
// tell package managerthat a specific package has been loaded
dojo.provide('com.sixnet.services.modules.access.changeAccountDash');
// load dojo dashWidgetBash

// _Templated == mix-in Widget HTML


// simulate Class system like Java with dojo.declare 
// 3 arguments (optional_global_name, null or base class or array of objects (multiple inheritance), object hash of properties to be mixed in after all other inheritance has been solved)
// dojo.moduleUrl is used to return a dojo._Url object relative to a module.
dojo.declare('com.sixnet.services.modules.access.changeAccountDash', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	moduleUrl: dojo.moduleUrl('com.sixnet.services.modules.access',''),
	templateString:"<div dojoAttachEvent=\"onmousedown:onMouseDown, onmouseover:onMouseOver, onmouseout:onMouseOut, onmouseup:onMouseUp,onclick:onClick\">\n\t<img class=\"dashBoardImage\" src=\"${moduleUrl}templates/images/accountChangeDash.png\"></img>\n</div>\n",
	dashBoard: false,
	onMouseDown: function(){
		dojo.addClass( this.domNode, "mouseDown");
	},
	onMouseUp: function(){
		dojo.removeClass( this.domNode, "mouseDown");
	},
	onClick: function(){
		//this.dashBoard.startedWorking();
		this.dashBoard.runApp( 'com.sixnet.services.modules.access.changeAccount');
		//this.dashBoard.stoppedWorking();	
		// end copy dash.js onClick-
	},
	buildWidgetThumbnailPane: function(){
		// subclass should override this method to produce customer ContentPane for "Running Clients"
		return false;
	}
	
});

}

if(!dojo._hasResource["com.sixnet.services.modules.sitesurvey.formatters"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource["com.sixnet.services.modules.sitesurvey.formatters"] = true;

dojo.provide("com.sixnet.services.modules.sitesurvey.formatters");

dojo.declare("com.sixnet.services.modules.sitesurvey.formatters", [com.sixnet.services.core.data.formatters], {
	siteSurvey: false,
	setSiteSurvey: function(survey){
		this.siteSurvey = survey;
	},
	timeToDate: function(value,idx){
		var adate = new Date();
		adate.setTime(value * 1000);
		return adate.toString();
	},
	userNotes: function(value, idx, cell){
		if( value == null) value = '';
		var editPane = new dijit.layout.ContentPane({ content: value.concat('<br>') });
		var editButton = new dijit.form.Button({ label: 'Edit', onClick: dojo.hitch(this, function(value, idx){
			var item = this.grid.getItem(idx);
			new dijit.Dialog({ siteSurvey: this.siteSurvey, item: item, id:"editUserNotesDialog", title:'Edit user notes', href: this.templateUrl.concat('editUserNotesDialog.html'), onLoad: function(){
				// this method fires when the dialog has finished loading its content.
				dijit.byId('editUserNotesDialog').connect(dijit.byId('editUserNotesDialog'), "onCancel", function(){
					// this method fires when the user clicks the close button in the title bar or presses escape
					// we do not want this dialog to stick around when we are done with it.  Tear it down.
					this.destroyRecursive();
				});
				dijit.byId('user_notes').setValue(value);
			}}).show();

		}, value, idx)});
		editButton.placeAt( editPane.domNode);
		return editPane;
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.sitesurvey.surveyReportImport']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.sitesurvey.surveyReportImport'] = true;
dojo.provide('com.sixnet.services.modules.sitesurvey.surveyReportImport');















dojo.declare("com.sixnet.services.modules.sitesurvey.surveyReportImportFormatters", [com.sixnet.services.modules.sitesurvey.formatters], {
	surveyReportImport: false,
	setSurveyReportImport: function(surveyReportImport){
		this.surveyReportImport = surveyReportImport ;
	},
	inSurvey: function(value,idx,cell){
		var surveyItem = this.grid.getItem(idx);
		var surveyId = this.siteSurvey.survey.id ;
		var siteSurvey = this.siteSurvey;
		var gridBox = new dijit.layout.ContentPane({});
		var surveyReportImport = this.surveyReportImport;
		var addMode = true;
		_sixnet_framework.bc('sitesurvey','getSurveyReports', { 
				startingOffset: 0,
				query: { survey_id: surveyId, report_date: surveyItem.date, serial: surveyItem.serial },
				sort: [],
				mode: 'EXACT',
				maxCount: 1
			}, function(response){
				if( response.data.totalItemCount == 0){
					// we can add it
					var addButton = new dijit.form.Button({ label:"Add", onClick: function(){
						_sixnet_framework.bc('sitesurvey','importSurveyReport', { surveyId: surveyId, serial: surveyItem.serial, reportDate: surveyItem.date }, function(){
							siteSurvey.reloadSurveyDetailGrid();
							surveyReportImport.setQuerySerial();
						});
					}});
					addButton.placeAt(gridBox.domNode);
				}else{
					gridBox.setContent('Added')
				}
				_sixnet_framework.log(1, 'in survey', response);
				
		});
		return gridBox;
	}
});

dojo.declare('com.sixnet.services.modules.sitesurvey.surveyReportImport', [com.sixnet.services.core.dashWidgetEmbedded, dijit._Templated], {
	widgetsInTemplate: true,
	siteSurvey: false,
	templateString:"<div>\n\t<h3>Import from Unit History</h3>\n\t<div dojoType=\"com.sixnet.services.core.data.writeStore\" mode=\"EXACT\" dojoAttachPoint=\"addSurveyDetailStore\" jsId=\"addSurveyDetailStore\" identifier=\"index\" pushModule=\"sitesurvey\" pushMethod=\"getLegacyUnits\" updateMethod=\"surveyReportsMassUpdate\"></div>\n\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.surveyReportImportFormatters\" dojoAttachPoint=\"addSurveyDetailFormatter\" jsId=\"addSurveyDetailFormatter\" store=\"addSurveyDetailStore\"></div>\n\t\t\t\t\t\t\t\n\t<div dojoType=\"dijit.Toolbar\" dojoAttachPoint=\"surveyToolbar\" style=\"width:100%\">\n\t\t<div style=\"float:right\" dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" dojoAttachPoint=\"cancelAddSurveyDetailButton\" dojoAttachEvent=\"onClick:cancelAddSurveyDetail\" hint=\"Cancel import\" ><img style=\"width:23px\" width=\"23\" src=\"${iconUrl}delete.png\"></div>\t\t\n\t\t<div dojoType=\"dijit.form.Form\" dojoAttachPoint=\"importForm\">\n\t\t\t<div style=\"float:left; margin-top:.5em\" dojoType=\"dijit.layout.ContentPane\" >Serial:</div>\n\t\t\t<div style=\"float:left; margin-top:.5em\" dojoType=\"dijit.form.ValidationTextBox\" regExp=\"^[0-9a-fA-FJ]{1}[0-9a-fA-f]{5}$\" required=\"true\" name=\"serial\" ></div>\n\t\t\t<div style=\"float:left; margin-top:.5em\" dojoType=\"dijit.layout.ContentPane\" >Start:</div>\n\t\t\t<div style=\"width:8em; float:left; margin-top:.5em\" dojoType=\"dijit.form.DateTextBox\" required=\"true\" name=\"startDate\" ></div>\n\t\t\t<div style=\"float:left; margin-top:.5em\" dojoType=\"dijit.layout.ContentPane\" >End:</div>\n\t\t\t<div style=\"width:8em; float:left; margin-top:.5em\" dojoType=\"dijit.form.DateTextBox\" required=\"true\" name=\"endDate\" ></div>\n\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Enter a serial to import survey data\" dojoAttachEvent=\"onClick:setQuerySerial\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}find.png\"></div>\n\t\t</div>\n\t\t\n\t</div>\n\t<table style=\"height:200px; margin-bottom: 30px\" dojoType=\"dojox.grid.DataGrid\" singleClickEdit=\"true\" escapeHTMLInData=\"false\" store=\"addSurveyDetailStore\" editable=\"true\" formatterScope=\"addSurveyDetailFormatter\" dojoattachpoint=\"addSurveyDetailGrid\" dojoAttachEvent=\"onClick:onAddSurveyDetailRowClick\" query=\"{ serial: ''}\" rowsPerPage=\"20\" rowSelector=\"20px\" >\n\t\t<thead>\n\t\t\t<tr>\n\t\t\t\t<th field=\"serial\" width=\"8em\">Serial</th>\n\t\t\t\t<th field=\"date\" width=\"12em\" formatter=\"timeToDate\">Report Date</th>\n\t\t\t\t<th field=\"start_date\" width=\"12em\" formatter=\"timeToDate\">Start Date/Time</th>\n\t\t\t\t<th editable=\"false\" field=\"user_notes\" width=\"40em\">User Notes</th>\n\t\t\t\t<th formatter=\"inSurvey\" width=\"40em\">Add/Remove</th>\n\t\t\t</tr>\n\t\t</thead>\n\t</table>\n\t<p/>\n</div>\n",
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.addSurveyDetailFormatter.setSurveyReportImport(this);
		this.addSurveyDetailFormatter.setSiteSurvey(this.siteSurvey);
		this.addSurveyDetailFormatter.setGrid(this.addSurveyDetailGrid);
		this.query = { serial: ''};
		dojo.connect( this, "onResize", this.addSurveyDetailGrid, "resize");
		var oldDestroy = this.addSurveyDetailGrid.destroy;
		
		this.addSurveyDetailGrid.destroy = dojo.hitch( this.addSurveyDetailGrid,function(preserveDom){
			if( typeof(this.domNode) == 'undefined'){
				return ; // we're destroyed already
			}
			dojo.hitch( this, oldDestroy, preserveDom);
		});
	},
	setQuerySerial: function(){
		var form = this.importForm;
		if( !form.isValid()) return;
		this.query.serial = form.getValues().serial;
		this.query.startDate = {
				action: "GT",
				field: "date",
				value: form.getValues().startDate.getTime() / 1000
		};
		this.query.endDate = {
				action: "LT",
				field: "date",
				value: (form.getValues().endDate.getTime() / 1000) + ( 60 * 60 * 24)  
		};
		//this.query.endDate = form.getValues().endDate.getTime() / 1000;
		// TODO: typeof(this.query.alert_desc) == undefined {  this.query.0: { action: 'RLIKE', field:'alert_desc', value:'throughput'}}
		this.addSurveyDetailGrid.setQuery(this.query);
	},
	onAddSurveyDetailRowClick: function(){
		
	},
	cancelAddSurveyDetail: function(){
		this.onClose();
	},
	onClose: function(){
		
	}
});

}

if(!dojo._hasResource['com.sixnet.services.modules.sitesurvey.siteSurvey']){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
dojo._hasResource['com.sixnet.services.modules.sitesurvey.siteSurvey'] = true;
dojo.provide('com.sixnet.services.modules.sitesurvey.siteSurvey');

















dojo.declare("com.sixnet.services.modules.sitesurvey.HintButton", [dijit.form.Button],{
	hint:'',
	_limitSurveyMode:false,
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.connect(this, "onMouseOver", dojo.hitch( this, function(hint, event){
			dojo.publish('/status/hint', [hint]);
		}, this.hint));
		this.connect(this, "onMouseLeave", dojo.hitch( this, function(){
			dojo.publish('/status/hint', ['']);
		}));
	}
});

dojo.declare('com.sixnet.services.modules.sitesurvey.siteSurvey', [com.sixnet.services.core.dashWidgetBase, dijit._Templated], {
	widgetsInTemplate: true,
	templateString:"<div>\n\t<div dojoType=\"dijit.layout.BorderContainer\" style=\"background:lightgray; width:100%; height:100%\">\n\t\t<div dojoType=\"dijit.layout.ContentPane\" region=\"top\" style=\"background:lightgray; height:4em; text-align:center\">\n\t\t\t\t<div style=\"width:100%\" ><h2>Site Survey Management</h2></div>\n\t\t</div>\n\t\t<div dojoType=\"dijit.layout.StackContainer\" region=\"center\" dojoAttachPoint=\"surveyStack\" style=\"width:100%\">\n\t\t<!-- /********************************** COMPANY PAGE ****************************************************/ -->\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"chooseCompanyPage\"  >\n\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"width:500px; margin-left:auto; margin-right:auto\"  >\n\t\t\t\t\t\t\t<p style=\"width:500px; margin-left:auto; margin-right:auto\">Choose a customer (or add a new one) to work with:</p>\n\t\t\t\t\t\t\t<div dojoType=\"dijit.Toolbar\" dojoAttachPoint=\"companyToolbar\" style=\"width:500px; margin-left:auto; margin-right:auto\">\n\t\t\t\t\t\t\t\t<div style=\"float:left; font-size:1.1em; width:10em; margin-top:5px\" dojoType=\"dijit.form.TextBox\" dojoAttachPoint=\"companySearchBox\" dojoAttachEvent=\"onKeyUp:onSearchCompanyKeyUp\"></div>\n\t\t\t\t\t\t\t\t<div style=\"float:left\" dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Search by company name\" dojoAttachEvent=\"onClick:onSearchCompaniesClick\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}find.png\"></div>\n\t\t\t\t\t\t\t\t<div style=\"float:left\" dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Clear Search\" dojoAttachEvent=\"onClick:onCancelSearchCompaniesClick\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}cancelFind.png\"></div>\n\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Add a company\" dojoAttachEvent=\"onClick:onAddCompanyClick\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}insrow.png\"></div>\n\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Remove the selected company and related data\" dojoAttachEvent=\"onClick:onRemoveCompanyClick\" dojoAttachPoint=\"removeCompanyButton\" ><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}remrow.png\"></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.core.data.store\" jsId=\"companyStore\" identifier=\"id\" pushModule=\"sitesurvey\" pushMethod=\"getCompanies\"></div>\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.formatters\" dojoAttachPoint=\"customerFormatter\"  jsId=\"companyFormatter\" store=\"companyStore\"></div>\n\t\t\t\t\t\t\t<table dojoType=\"dojox.grid.DataGrid\"  dojoAttachEvent=\"onDblClick:onCompanyRowDblClick,onClick:onCompanyRowClick\" store=\"companyStore\" dojoAttachPoint=\"companyGrid\" formatterScope=\"companyFormatter\" query=\"{}\" rowsPerPage=\"20\" rowSelector=\"20px\" style=\"height:300px; width:500px; margin-left:auto; margin-right:auto\">\n\t\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t<th field=\"name\" width=\"200px\">Customer</th>\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t</table>\t\n\t\t\t\t\t</div>\t\t\t\t\n\t\t\t\t</div>\t\n\t\t<!-- /********************************** CHOOSE SURVEY PAGE ****************************************************/ -->\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"chooseSurveyPage\"  >\n\t\t\t\t\t<div dojoType=\"dijit.Toolbar\" style=\"float:left\" dojoAttachPoint=\"surveyCrumbBar\">\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Choose a different company\"  dojoAttachEvent=\"onClick:onChooseCompanyButtonClick\">Change Company</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<br style=\"clear:both\"/>\n\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"width:400px; margin-left:auto; margin-right:auto\">\n\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"width:200px; height:50px; float:left; text-align:cener\">\n\t\t\t\t\t\t\t<div style=\"width:100%; text-align:center\"><h3>Company</h3></div>\n\t\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\"  style=\"width:100%; text-align:center\" dojoAttachPoint=\"currentCompanyLabel\"></div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"width:50em; margin-left:auto; margin-right:auto\"  >\n\t\t\t\t\t\t\t<p style=\"width:100%; margin-left:auto; margin-right:auto\">Choose a survey (or add a new one) to work with:</p>\n\t\t\t\t\t\t\t<div dojoType=\"dijit.Toolbar\" dojoAttachPoint=\"surveyToolbar\" style=\"width:100%\">\n\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Add a new Survey for this company\" dojoAttachEvent=\"onClick:onAddSurveyClick\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}insrow.png\"></div>\n\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Remove the selected survey and related data\" dojoAttachEvent=\"onClick:onRemoveSurveyClick\" dojoAttachPoint=\"removeSurveyButton\"><img style=\"width:23px; height:23px; cursor: auto\" width=\"23\" height=\"23\" src=\"${iconUrl}remrow.png\"></div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.core.data.writeStore\" mode=\"EXACT\" jsId=\"surveyStore\" dojoAttachPoint=\"surveyStore\" identifier=\"id\"  dojoAttachEvent=\"onSave:onSurveySaved,onDirty:onSurveyChanged\" updateMethod=\"surveyMassUpdate\" pushModule=\"sitesurvey\" pushMethod=\"getSurveys\" ></div>\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.formatters\" jsId=\"surveyFormatter\" dojoAttachPoint=\"surveyFormatter\" store=\"surveyStore\"></div>\n\t\t\t\t\t\t\t<table dojoType=\"dojox.grid.DataGrid\" store=\"surveyStore\" formatterScope=\"surveyFormatter\" singleClickEdit=\"true\" dojoAttachEvent=\"onClick:onSurveyRowClick,onDblClick:onSurveyRowDblClick\" dojoAttachPoint=\"surveyGrid\" query=\"{ company_id: ''}\" rowsPerPage=\"20\" rowSelector=\"20px\" style=\"height:300px; width:100%\">\n\t\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t<th field=\"description\" width=\"16em\">Survey Description</th>\n\t\t\t\t\t\t\t\t\t\t<th field=\"create_date\" width=\"19em\" formatter=\"timeToDate\">Date Created</th>\n\t\t\t\t\t\t\t\t\t\t<th editable=\"true\" field=\"preparer\" width=\"9em\" >Prepared By</th>\n\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t<!--  /********************************* SURVEY DETAIL PAGE *******************************************************/  -->\n\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"surveyDetailPage\"  >\n\t\t\t\t\t<div dojoType=\"dijit.Toolbar\" style=\"float:left; width:100%\" dojoAttachPoint=\"surveyDetailCrumbBar\">\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Choose a different company\" dojoAttachEvent=\"onClick:onChooseCompanyButtonClick\">Change Company</div>\n\t\t\t\t\t\t\t<div dojoType=\"dijit.ToolbarSeparator\"  ></div>\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Choose a different survey\" dojoAttachEvent=\"onClick:onChooseSurveyButtonClick\">Change Survey</div>\n\t\t\t\t\t\t\t<div dojoType=\"dijit.ToolbarSeparator\"  ></div>\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Download PDF\" dojoAttachEvent=\"onClick:onGenerateReport\">Generate PDF Report</div>\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Download CSV Averages\" dojoAttachEvent=\"onClick:onGenerateCsvAveragesReport\">Generate CSV Averages Report</div>\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Download CSV Details\" dojoAttachEvent=\"onClick:onGenerateCsvDetailReport\">Generate CSV Detail Report</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<br style=\"clear:both\"/>\n\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"width:70em; margin-left:auto; margin-right:auto\"  >\n\t\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"width:40em; margin-left:auto; margin-right:auto\">\n\t\t\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"width:20em; height:50px; float:left; text-align:cener\">\n\t\t\t\t\t\t\t\t\t<div style=\"width:100%; text-align:center\"><h3>Company</h3></div>\n\t\t\t\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\"  style=\"width:100%; text-align:center\" dojoAttachPoint=\"currentCompanyLabel2\"></div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"width:20em; height:50px; float:left; text-align:center\">\n\t\t\t\t\t\t\t\t\t<div style=\"width:100%; text-align:center\"><h3>Survey</h3></div>\n\t\t\t\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"width:100%; text-align:center\" dojoAttachPoint=\"currentSurveyLabel\"></div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.core.data.writeStore\" mode=\"EXACT\" dojoAttachPoint=\"surveyDetailStore\" jsId=\"surveyDetailStore\" dojoAttachEvent=\"onSave:onReportsSaved,onDirty:onReportsChanged\" identifier=\"survey_id,serial,report_date\" pushModule=\"sitesurvey\" pushMethod=\"getSurveyReports\" updateMethod=\"surveyReportsMassUpdate\"></div>\n<!--\t\t\t\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" style=\"width:100%; height:130px; margin-left:auto; margin-right:auto\">\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t<h3>Survey Averages</h3>\n\t\t\t\t\t\t\t\t<table dojoType=\"dojox.grid.DataGrid\" dojoAttachPoint=\"singleSurveyGrid\" store=\"surveyStore\" formatterScope=\"surveyFormatter\" query=\"{ id: ''}\" rowsPerPage=\"20\" rowSelector=\"20px\" style=\"height:100px\">\n\t\t\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t<th field=\"description\" width=\"16em\">Survey Description</th>\n\t\t\t\t\t\t\t\t\t\t\t<th field=\"create_date\" width=\"9em\" formatter=\"timeToDate\">Date Created</th>\n\t\t\t\t\t\t\t\t\t\t\t<th field=\"down\" width=\"5em\">Down kb/s</th>\n\t\t\t\t\t\t\t\t\t\t\t<th field=\"up\" width=\"5em\">Up kb/s</th>\n\t\t\t\t\t\t\t\t\t\t\t<th field=\"ping\" width=\"5em\">Ping ms</th>\n\t\t\t\t\t\t\t\t\t\t\t<th field=\"rssi\" width=\"5em\">RSSI db</th>\n\t\t\t\t\t\t\t\t\t\t\t<th field=\"ecio\" width=\"5em\">ECIO</th>\n\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t-->\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t<div dojoType=\"dijit.layout.StackContainer\" dojoAttachPoint=\"surveyReportImportTool\" >\n\t\t\t\t\t\t\t</div>\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t<h3>Edit Report Entries</h3>\n\t\t\t\t\t\t\t<div style=\"width:100%\">\n\t\t\t\t\t\t\t\t<div dojoType=\"dijit.Toolbar\" dojoAttachPoint=\"surveyToolbar\" style=\"width:100%\">\n\t\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" dojoAttachPoint=\"importSurveyDetailButton\" hint=\"Import a row from unit history\" dojoAttachEvent=\"onClick:onImportSurveyDetailClick\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}improw.png\"></div>\n\t\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" dojoAttachPoint=\"addSurveyDetailButton\" hint=\"Manually add a report row\" dojoAttachEvent=\"onClick:onAddSurveyDetailClick\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}insrow.png\"></div>\n\t\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" dojoAttachPoint=\"removeSurveyDetailButton\" hint=\"Remove selected report row\" dojoAttachEvent=\"onClick:onRemoveSurveyDetailClick\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}remrow.png\"></div>\n\t\t\t\t\t\t\t\t\t<!-- <div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" hint=\"Import data from GMU\" dojoAttachEvent=\"onClick:onImportReportsClick\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}improw.png\"></div>  -->\n\t\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" dojoAttachPoint=\"saveSurveyDetailButton\" hint=\"Save changes\" dojoAttachEvent=\"onClick:onSaveReportChanges\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}filesave.png\"></div>\n\t\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" dojoAttachPoint=\"revertSurveyDetailButton\" hint=\"Revert changes\" dojoAttachEvent=\"onClick:onUndoSurveyReportChanges\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}delete.png\"></div>\n\t\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" dojoAttachPoint=\"limitSurveyDetailButton\" hint=\"Limit view to just the serial number in the selected row\" dojoAttachEvent=\"onClick:onLimitSurveyReportView\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}find.png\"></div>\n\t\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.HintButton\" dojoAttachPoint=\"unLimitSurveyDetailButton\" hint=\"View all of the reports\" dojoAttachEvent=\"onClick:onUnlimitSurveyReportView\"><img style=\"width:23px; height:23px\" width=\"23\" height=\"23\" src=\"${iconUrl}cancelFind.png\"></div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div dojoType=\"com.sixnet.services.modules.sitesurvey.formatters\" dojoAttachPoint=\"surveyDetailFormatter\" jsId=\"surveyDetailFormatter\" store=\"surveyDetailStore\"></div>\n\t\t\t\t\t\t\t\t<table dojoType=\"dojox.grid.DataGrid\" singleClickEdit=\"true\" escapeHTMLInData=\"false\" store=\"surveyDetailStore\" editable=\"true\" formatterScope=\"surveyDetailFormatter\" dojoattachpoint=\"surveyDetailGrid\" dojoAttachEvent=\"onClick:onSurveyDetailRowClick\" query=\"{ survey_id: ''}\" rowsPerPage=\"20\" rowSelector=\"20px\" style=\"height:300px; width:100%\">\n\t\t\t\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t\t\t\t<th field=\"serial\" width=\"8em\">Serial</th>\n\t\t\t\t\t\t\t\t\t\t\t<th field=\"report_date\" width=\"12em\" formatter=\"timeToDate\">Report Date</th>\n\t\t\t\t\t\t\t\t\t\t\t<th field=\"start_time\" width=\"12em\" formatter=\"timeToDate\">Start Date/Time</th>\n\t\t\t\t\t\t\t\t\t\t\t<th cellType=\"dojox.grid.cells._Widget\" widgetClass=\"dijit.form.NumberTextBox\" editable=\"true\" field=\"down\" width=\"6em\">Down kb/s</th>\n\t\t\t\t\t\t\t\t\t\t\t<th cellType=\"dojox.grid.cells._Widget\" widgetClass=\"dijit.form.NumberTextBox\" editable=\"true\" field=\"up\" width=\"6em\">Up kb/s</th>\n\t\t\t\t\t\t\t\t\t\t\t<th cellType=\"dojox.grid.cells._Widget\" widgetClass=\"dijit.form.NumberTextBox\" editable=\"true\" field=\"ping\" width=\"4em\">Ping ms</th>\n\t\t\t\t\t\t\t\t\t\t\t<th cellType=\"dojox.grid.cells._Widget\" widgetClass=\"dijit.form.NumberTextBox\" editable=\"true\" field=\"rssi\" width=\"4em\">RSSI db</th>\n\t\t\t\t\t\t\t\t\t\t\t<th cellType=\"dojox.grid.cells._Widget\" widgetClass=\"dijit.form.NumberTextBox\" editable=\"true\" field=\"ecio\" width=\"4em\">ECIO</th>\n\t\t\t\t\t\t\t\t\t\t\t<th formatter=\"userNotes\" editable=\"false\" field=\"user_notes\" width=\"20em\">User Notes</th>\n\t\t\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t\t\t</table>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"framePane\" ></div>\n\t\t</div>\n\t\t<div dojoType=\"dijit.Toolbar\" region=\"bottom\" style=\"background:lightgray; height:2em\">\n\t\t\t\t<div dojoType=\"dijit.layout.ContentPane\" dojoAttachPoint=\"statusLine\" style=\"width:100%\">\n\t\t\t\t</div>\n\t\t</div>\n\t</div>\n</div>\n",
	postCreate: function(){
		this.inherited("postCreate", arguments);
		this.connect( this.dashBoard, "onHideWidget", "onHide");
		this.surveyDetailFormatter.setSiteSurvey(this);
		this.surveyDetailFormatter.setGrid(this.surveyDetailGrid);
		this.customerFormatter.setGrid(this.companyGrid);
		this.customerFormatter.setSiteSurvey(this);
		this.surveyFormatter.setSiteSurvey(this);
		this.surveyFormatter.setGrid(this.surveyGrid);
		// make these buttons initially dimmed out.		
		dojo.addClass( this.removeCompanyButton.focusNode, "disabledButton");
		dojo.addClass( this.removeSurveyButton.focusNode, "disabledButton");
		dojo.addClass( this.saveSurveyDetailButton.focusNode, "disabledButton");
		dojo.addClass( this.revertSurveyDetailButton.focusNode, "disabledButton");
		dojo.addClass( this.removeSurveyDetailButton.focusNode, "disabledButton");
		dojo.addClass( this.limitSurveyDetailButton.focusNode, "disabledButton");
		//
