text: dojo._xdResourceLoaded({
  depends: [["provide", "dojo.back"]],
  defineResource: function(dojo){if(!dojo._hasResource["dojo.back"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  dojo._hasResource["dojo.back"] = true;
  dojo.provide("dojo.back");
  
  (function() { 
  	
  	var back = dojo.back;
  	
  	// everyone deals with encoding the hash slightly differently
  	
  	function getHash(){ 
  		var h = window.location.hash;
  		if(h.charAt(0) == "#") { h = h.substring(1); }
  		return dojo.isMozilla ? h : decodeURIComponent(h); 
  	}
  	
  	function setHash(h){
  		if(!h) { h = "" };
  		window.location.hash = encodeURIComponent(h);
  		historyCounter = history.length;
  	}
  	
  	// if we're in the test for these methods, expose them on dojo.back. ok'd with alex.
  	if(dojo.exists("tests.back-hash")){
  		back.getHash = getHash;
  		back.setHash = setHash;		
  	}
  	
  	var initialHref = (typeof(window) !== "undefined") ? window.location.href : "";
  	var initialHash = (typeof(window) !== "undefined") ? getHash() : "";
  	var initialState = null;
  
  	var locationTimer = null;
  	var bookmarkAnchor = null;
  	var historyIframe = null;
  	var forwardStack = [];
  	var historyStack = [];
  	var moveForward = false;
  	var changingUrl = false;
  	var historyCounter;
  
  	function handleBackButton(){
  		//summary: private method. Do not call this directly.
  
  		//The "current" page is always at the top of the history stack.
  		//console.debug("handlingBackButton");
  		var current = historyStack.pop();
  		if(!current){ return; }
  		var last = historyStack[historyStack.length-1];
  		if(!last && historyStack.length == 0){
  			last = initialState;
  		}
  		if(last){
  			if(last.kwArgs["back"]){
  				last.kwArgs["back"]();
  			}else if(last.kwArgs["backButton"]){
  				last.kwArgs["backButton"]();
  			}else if(last.kwArgs["handle"]){
  				last.kwArgs.handle("back");
  			}
  		}
  		forwardStack.push(current);
  		//console.debug("done handling back");
  	}
  
  	back.goBack = handleBackButton;
  
  	function handleForwardButton(){
  		//summary: private method. Do not call this directly.
  		//console.debug("handling forward");
  		var last = forwardStack.pop();
  		if(!last){ return; }
  		if(last.kwArgs["forward"]){
  			last.kwArgs.forward();
  		}else if(last.kwArgs["forwardButton"]){
  			last.kwArgs.forwardButton();
  		}else if(last.kwArgs["handle"]){
  			last.kwArgs.handle("forward");
  		}
  		historyStack.push(last);
  		//console.debug("done handling forward");
  	}
  
  	back.goForward = handleForwardButton;
  
  	function createState(url, args, hash){
  		//summary: private method. Do not call this directly.
  		return {"url": url, "kwArgs": args, "urlHash": hash};	//Object
  	}
  
  	function getUrlQuery(url){
  		//summary: private method. Do not call this directly.
  		var segments = url.split("?");
  		if (segments.length < 2){
  			return null; //null
  		}
  		else{
  			return segments[1]; //String
  		}
  	}
  	
  	function loadIframeHistory(){
  		//summary: private method. Do not call this directly.
  		var url = (djConfig["dojoIframeHistoryUrl"] || dojo.moduleUrl("dojo", "resources/iframe_history.html")) + "?" + (new Date()).getTime();
  		moveForward = true;
          if (historyIframe) {
  		    (dojo.isSafari) ? historyIframe.location = url : window.frames[historyIframe.name].location = url;
          } else {
              //console.warn("dojo.back: Not initialised. You need to call dojo.back.init() from a <script> block that lives inside the <body> tag.");
          }
  		return url; //String
  	}
  
  	function checkLocation(){
  		//console.debug("checking url");
  		if(!changingUrl){
  			var hsl = historyStack.length;
  			
  			var hash = getHash();
  
  			if((hash === initialHash||window.location.href == initialHref)&&(hsl == 1)){
  				// FIXME: could this ever be a forward button?
  				// we can't clear it because we still need to check for forwards. Ugg.
  				// clearInterval(this.locationTimer);
  				handleBackButton();
  				return;
  			}
  			
  			// first check to see if we could have gone forward. We always halt on
  			// a no-hash item.
  			if(forwardStack.length > 0){
  				if(forwardStack[forwardStack.length-1].urlHash === hash){
  					handleForwardButton();
  					return;
  				}
  			}
  	
  			// ok, that didn't work, try someplace back in the history stack
  			if((hsl >= 2)&&(historyStack[hsl-2])){
  				if(historyStack[hsl-2].urlHash === hash){
  					handleBackButton();
  					return;
  				}
  			}
  			
  			if(dojo.isSafari && dojo.isSafari < 3){
  				var hisLen = history.length;
  				if(hisLen > historyCounter) handleForwardButton();
  				else if(hisLen < historyCounter) handleBackButton();
  			  historyCounter = hisLen;
  			}
  		}
  		//console.debug("done checking");
  	};
  	
  	back.init = function(){
  		//summary: Initializes the undo stack. This must be called from a <script> 
  		//         block that lives inside the <body> tag to prevent bugs on IE.
  		if(dojo.byId("dj_history")){ return; } // prevent reinit
  		var src = djConfig["dojoIframeHistoryUrl"] || dojo.moduleUrl("dojo", "resources/iframe_history.html");
  		document.write('<iframe style="border:0;width:1px;height:1px;position:absolute;visibility:hidden;bottom:0;right:0;" name="dj_history" id="dj_history" src="' + src + '"></iframe>');
  	};
  
  	back.setInitialState = function(/*Object*/args){
  		//summary: 
  		//		Sets the state object and back callback for the very first page
  		//		that is loaded.
  		//description:
  		//		It is recommended that you call this method as part of an event
  		//		listener that is registered via dojo.addOnLoad().
  		//args: Object
  		//		See the addToHistory() function for the list of valid args properties.
  		initialState = createState(initialHref, args, initialHash);
  	};
  
  	//FIXME: Make these doc comments not be awful. At least they're not wrong.
  	//FIXME: Would like to support arbitrary back/forward jumps. Have to rework iframeLoaded among other things.
  	//FIXME: is there a slight race condition in moz using change URL with the timer check and when
  	//       the hash gets set? I think I have seen a back/forward call in quick succession, but not consistent.
  
  	
  	/*=====
  	dojo.__backArgs = function(kwArgs){
  		// back: Function?
  		//		A function to be called when this state is reached via the user
  		//		clicking the back button.
  		//	forward: Function?
  		//		Upon return to this state from the "back, forward" combination
  		//		of navigation steps, this function will be called. Somewhat
  		//		analgous to the semantic of an "onRedo" event handler.
  		//	changeUrl: Boolean?|String?
  		//		Boolean indicating whether or not to create a unique hash for
  		//		this state. If a string is passed instead, it is used as the
  		//		hash.
  	}
  	=====*/
  
  	back.addToHistory = function(/*dojo.__backArgs*/ args){
  		//	summary: 
  		//		adds a state object (args) to the history list. 
  		//	description:
  		//		To support getting back button notifications, the object
  		//		argument should implement a function called either "back",
  		//		"backButton", or "handle". The string "back" will be passed as
  		//		the first and only argument to this callback.
  		//	
  		//		To support getting forward button notifications, the object
  		//		argument should implement a function called either "forward",
  		//		"forwardButton", or "handle". The string "forward" will be
  		//		passed as the first and only argument to this callback.
  		//
  		//		If you want the browser location string to change, define "changeUrl" on the object. If the
  		//		value of "changeUrl" is true, then a unique number will be appended to the URL as a fragment
  		//		identifier (http://some.domain.com/path#uniquenumber). If it is any other value that does
  		//		not evaluate to false, that value will be used as the fragment identifier. For example,
  		//		if changeUrl: 'page1', then the URL will look like: http://some.domain.com/path#page1
  		//
  	 	//	example:
  		//		|	dojo.back.addToHistory({
  		//		|		back: function(){ console.debug('back pressed'); },
  		//		|		forward: function(){ console.debug('forward pressed'); },
  		//		|		changeUrl: true
  		//		|	});
  
  		//	BROWSER NOTES:
  		//  Safari 1.2: 
  		//	back button "works" fine, however it's not possible to actually
  		//	DETECT that you've moved backwards by inspecting window.location.
  		//	Unless there is some other means of locating.
  		//	FIXME: perhaps we can poll on history.length?
  		//	Safari 2.0.3+ (and probably 1.3.2+):
  		//	works fine, except when changeUrl is used. When changeUrl is used,
  		//	Safari jumps all the way back to whatever page was shown before
  		//	the page that uses dojo.undo.browser support.
  		//	IE 5.5 SP2:
  		//	back button behavior is macro. It does not move back to the
  		//	previous hash value, but to the last full page load. This suggests
  		//	that the iframe is the correct way to capture the back button in
  		//	these cases.
  		//	Don't test this page using local disk for MSIE. MSIE will not create 
  		//	a history list for iframe_history.html if served from a file: URL. 
  		//	The XML served back from the XHR tests will also not be properly 
  		//	created if served from local disk. Serve the test pages from a web 
  		//	server to test in that browser.
  		//	IE 6.0:
  		//	same behavior as IE 5.5 SP2
  		//	Firefox 1.0+:
  		//	the back button will return us to the previous hash on the same
  		//	page, thereby not requiring an iframe hack, although we do then
  		//	need to run a timer to detect inter-page movement.
  
  		//If addToHistory is called, then that means we prune the
  		//forward stack -- the user went back, then wanted to
  		//start a new forward path.
  		forwardStack = []; 
  
  		var hash = null;
  		var url = null;
  		if(!historyIframe){
  			if(djConfig["useXDomain"] && !djConfig["dojoIframeHistoryUrl"]){
  				console.debug("dojo.back: When using cross-domain Dojo builds,"
  					+ " please save iframe_history.html to your domain and set djConfig.dojoIframeHistoryUrl"
  					+ " to the path on your domain to iframe_history.html");
  			}
  			historyIframe = window.frames["dj_history"];
  		}
  		if(!bookmarkAnchor){
  			bookmarkAnchor = document.createElement("a");
  			dojo.body().appendChild(bookmarkAnchor);
  			bookmarkAnchor.style.display = "none";
  		}
  		if(args["changeUrl"]){
  			hash = ""+ ((args["changeUrl"]!==true) ? args["changeUrl"] : (new Date()).getTime());
  			
  			//If the current hash matches the new one, just replace the history object with
  			//this new one. It doesn't make sense to track different state objects for the same
  			//logical URL. This matches the browser behavior of only putting in one history
  			//item no matter how many times you click on the same #hash link, at least in Firefox
  			//and Safari, and there is no reliable way in those browsers to know if a #hash link
  			//has been clicked on multiple times. So making this the standard behavior in all browsers
  			//so that dojo.back's behavior is the same in all browsers.
  			if(historyStack.length == 0 && initialState.urlHash == hash){
  				initialState = createState(url, args, hash);
  				return;
  			}else if(historyStack.length > 0 && historyStack[historyStack.length - 1].urlHash == hash){
  				historyStack[historyStack.length - 1] = createState(url, args, hash);
  				return;
  			}
  
  			changingUrl = true;
  			setTimeout(function() { 
  					setHash(hash); 
  					changingUrl = false; 					
  				}, 1);
  			bookmarkAnchor.href = hash;
  			
  			if(dojo.isIE){
  				url = loadIframeHistory();
  
  				var oldCB = args["back"]||args["backButton"]||args["handle"];
  
  				//The function takes handleName as a parameter, in case the
  				//callback we are overriding was "handle". In that case,
  				//we will need to pass the handle name to handle.
  				var tcb = function(handleName){
  					if(getHash() != ""){
  						setTimeout(function() { setHash(hash); }, 1);
  					}
  					//Use apply to set "this" to args, and to try to avoid memory leaks.
  					oldCB.apply(this, [handleName]);
  				};
  		
  				//Set interceptor function in the right place.
  				if(args["back"]){
  					args.back = tcb;
  				}else if(args["backButton"]){
  					args.backButton = tcb;
  				}else if(args["handle"]){
  					args.handle = tcb;
  				}
  		
  				var oldFW = args["forward"]||args["forwardButton"]||args["handle"];
  		
  				//The function takes handleName as a parameter, in case the
  				//callback we are overriding was "handle". In that case,
  				//we will need to pass the handle name to handle.
  				var tfw = function(handleName){
  					if(getHash() != ""){
  						setHash(hash);
  					}
  					if(oldFW){ // we might not actually have one
  						//Use apply to set "this" to args, and to try to avoid memory leaks.
  						oldFW.apply(this, [handleName]);
  					}
  				};
  
  				//Set interceptor function in the right place.
  				if(args["forward"]){
  					args.forward = tfw;
  				}else if(args["forwardButton"]){
  					args.forwardButton = tfw;
  				}else if(args["handle"]){
  					args.handle = tfw;
  				}
  
  			}else if(!dojo.isIE){
  				// start the timer
  				if(!locationTimer){
  					locationTimer = setInterval(checkLocation, 200);
  				}
  				
  			}
  		}else{
  			url = loadIframeHistory();
  		}
  
  		historyStack.push(createState(url, args, hash));
  	};
  
  	back._iframeLoaded = function(evt, ifrLoc){
  		//summary: 
  		//		private method. Do not call this directly.
  		var query = getUrlQuery(ifrLoc.href);
  		if(query == null){ 
  			// alert("iframeLoaded");
  			// we hit the end of the history, so we should go back
  			if(historyStack.length == 1){
  				handleBackButton();
  			}
  			return;
  		}
  		if(moveForward){
  			// we were expecting it, so it's not either a forward or backward movement
  			moveForward = false;
  			return;
  		}
  	
  		//Check the back stack first, since it is more likely.
  		//Note that only one step back or forward is supported.
  		if(historyStack.length >= 2 && query == getUrlQuery(historyStack[historyStack.length-2].url)){
  			handleBackButton();
  		}
  		else if(forwardStack.length > 0 && query == getUrlQuery(forwardStack[forwardStack.length-1].url)){
  			handleForwardButton();
  		}
  	};
   })();
  
  }
  
  }});