You are viewing a plain text version of this content. The canonical link for it is here.
Posted to xap-commits@incubator.apache.org by mt...@apache.org on 2006/08/16 20:18:12 UTC

svn commit: r432019 [4/7] - in /incubator/xap/trunk/dist: dojo.js xapcore.js zimbra.js

Added: incubator/xap/trunk/dist/xapcore.js
URL: http://svn.apache.org/viewvc/incubator/xap/trunk/dist/xapcore.js?rev=432019&view=auto
==============================================================================
--- incubator/xap/trunk/dist/xapcore.js (added)
+++ incubator/xap/trunk/dist/xapcore.js Wed Aug 16 13:18:11 2006
@@ -0,0 +1,27691 @@
+/*
+	Copyright  2006 The Apache Software Foundation.
+ 
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+ 
+	http://www.apache.org/licenses/LICENSE-2.0
+ 
+	Unless readAndOuputFile by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+ 
+ */
+
+/*
+	This is a compiled version of XAP, built for deployment.
+*/
+
+dojo.provide("xap.util.Utils") ;
+
+xap.util.Utils = function(){}
+
+xap.util.Utils.importFile = function( path ) {
+	if( xap.util.Utils.s_pathCache == null ) {
+		xap.util.Utils.s_pathCache = new Object();
+	}
+	if ( xap.util.Utils.s_pathCache[path] ){
+		return;
+	}
+	xap.util.Utils.s_pathCache[path] = true;
+	var scriptElement = "<script language=\"JavaScript\" " +
+		"type=\"text/javascript\" src=\"" + path + "\"></script>";
+	document.write( scriptElement );
+}
+
+xap.util.Utils.s_pathCache = null;
+
+/**
+ * Method for debugging---less than a full object-dump, more than toString()
+**/
+xap.util.Utils.interrogate = function(obj,withFun){
+	var s="" ;
+	if (typeof obj != "object"){
+		s = "<not an object>" ;
+	} else {
+		for (var keyy in obj){ 
+			var valStr = ""+obj[keyy] ; 
+			if (valStr.substring(0,8)=="function" && !withFun){
+				continue ;
+			}
+			s += "^"+keyy+':'+valStr ;
+		}
+	}
+	// Puts the result, with CR/LFs turned to carets, into
+	// the copyable part of a prompt box:
+	prompt("",s.replace(/[\r\n]/g,"^")) ;  
+}
+
+
+
+
+
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+Xap = function () {}
+
+//make xap load from the xap directory
+dojo.hostenv.setModulePrefix("xap", "../xap");
+dojo.hostenv.setModulePrefix("google", "../google");
+
+
+Xap.kwCompoundRequire = function(){
+	dojo.kwCompoundRequire.apply(dojo, arguments);
+}
+
+
+Xap.provide = function(){
+	dojo.provide.apply(dojo,arguments);
+}
+
+
+
+// We use these repeatedly, why re-create them each time?
+Xap.trailingSlashRegexp = /^.*\/$/ ;
+Xap.allFullstopsRegexp = /\./g ;
+Xap.anyAsteriskRegexp = /\*/g ;
+
+Xap.ourLoadedClasses = new Object() ;
+
+Xap.require = function(){
+
+// Modules will have to go through Dojo:
+	var toLoad = arguments[0] ;
+	var notModule = (toLoad.search(Xap.anyAsteriskRegexp)==-1) ;
+//
+//	
+// Don't overload, don't depend on ArrayHelper being around:
+	var alreadyLoaded = (Xap.ourLoadedClasses[toLoad])?true:false ;
+	if( alreadyLoaded ){
+		Xap._logString += "Redundant load attempt: "+toLoad ;
+		return ;
+	}
+
+	// do we need to reload this file?
+	//---is it in the "debuggables" list?--are we reloading everything?
+	var needToDebugLoad = notModule 
+											&&  (Xap._debugAll
+													||  (Xap._debugLoad && Xap._debuggables[toLoad]) 
+													) ;
+
+
+	try {		
+		dojo.require.apply(dojo,arguments) ;
+		if(needToDebugLoad){
+
+			Xap.addDebuggables([toLoad]) ;	
+			Xap.ourLoadedClasses[toLoad] = true ;			
+		}
+	} catch (ee) {
+		Xap._logString += '\n'+ee ;
+	}
+
+}
+
+Xap.addDebuggables = function(){
+	if( !Xap._debuggables ){
+		Xap._debuggables = new Object() ;
+	}
+	for (var ii=0; ii<arguments.length; ++ii ){
+		Xap._debuggables[arguments[ii]] = true ; 
+	}
+}
+
+
+
+Xap._loadDebuggable = function(str){
+	var path = str.replace(Xap.allFullstopsRegexp,"/") ;
+	if ( !Xap._sourceRootDir.match(Xap.trailingSlashRegexp)){
+		Xap._sourceRootDir +="/" ;
+	}
+	path = Xap._sourceRootDir +"src/"+path +".js" ;
+	//alert(path) ;
+	xap.util.Utils.importFile(path) ;
+}
+
+Xap._loadDebuggables = function(pathHolderObj){
+	if( !pathHolderObj){
+	// Default behavior:
+		Xap._loadDebuggables(Xap._debuggables) ;
+		return ;
+	} else { 
+		for (var nom in pathHolderObj){
+			Xap._loadDebuggable(  nom ) ;
+		}
+	}
+}
+
+Xap.debugLoad = function(){
+	Xap._addDebuggables(arguments) ;
+	Xap._loadDebuggables() ;
+}
+
+
+
+
+
+/**
+
+/**
+ *  @private
+ *  Looks for nodes with the criteria we want
+**/  
+Xap._findAppElements = function(){
+//Experiment  Xap.require("google.xpath");
+	var currentContext =   new google.ExprContext(document) ;
+// The following _should_ work, but I think google's XPath
+// is a little broken---an earlier attempt to run //*[id='anId']
+// in xap.xml.xmodify.Xmodify code didn't work, either	
+//	var parsedXPathExpr = google.xpathParse("//*[@appName]") ;
+	var parsedXPathExpr = google.xpathParse("//") ;
+	var targetNodes = parsedXPathExpr.evaluate( currentContext );
+	var targetNodesArray = targetNodes.nodeSetValue();	
+	return targetNodesArray ;
+
+}
+
+
+Xap.scanPage = function(){
+	var allPossibleContainerNodes = Xap._findAppElements() ;
+	for (var i =0; i<allPossibleContainerNodes.length; i++){
+		var element = allPossibleContainerNodes[i] ; 	
+		if( !element.getAttribute ){
+			continue;
+		}
+		var thisElementsAppName = null ;		
+		thisElementsAppName = element.getAttribute("appName");
+		if(!thisElementsAppName){
+			continue;
+		}
+		var src = element.getAttribute("src");	
+//		alert("Found xap tag with \n        appName:" + thisElementsAppName + ", \n        and source " + src+ "\n        under element of type: "+element.nodeName);
+		var context = element.getAttribute("context");
+		var toolkit = element.getAttribute("toolkit");
+		
+		var session = Xap.createSession(context, src, toolkit , element);
+		// these might be handy to keep around:
+		session.appName = thisElementsAppName ;
+		session.src = src ;
+		session.domContainer = element ;
+		if (window[thisElementsAppName]==null){
+			window[thisElementsAppName]= session;
+		}
+		else{
+			//TODO throw some error?
+		}
+	}
+}
+
+
+
+
+
+
+Xap.bootstrap = function( sourceRootDir,loadType ) {
+	// Will need this later to hold dojo configuration information:
+	if (!djConfig){
+		if (!config){
+			djConfig={} ;
+		} else {
+			djConfig = config ;
+		}
+	}
+
+
+	// debugger-friendlier loader?:
+	Xap._debugLoad = (loadType)?true:false ;
+	Xap._debugAll = (loadType && loadType == "debugAll") ;
+	if( !Xap._debuggables ){
+		Xap._debuggables = new Object()  ;
+	}
+
+	Xap._logString = "" ;
+	Xap._showLog = function(){
+		prompt("",Xap._logString.replace(/\n/g,"^")) ;
+	} 	
+
+	Xap._sourceRootDir = sourceRootDir;
+	Xap.loadXap( sourceRootDir );
+	//Xap.loadZimbra( sourceRootDir );
+	
+// We've done all the "real" loading, now let's attach code to source files 
+// previously targetted for debugger-friendly (specified before we bootstrap):
+//Later: don't load automatically, wait for latest possible moment:
+//	if( Xap._debugLoad ){
+//		Xap._loadDebuggables() ;
+//	}
+
+}
+
+Xap.createSession = function( context, startPage,toolkitType , element) {
+   Xap.require("xap.session.ClientSession");
+	var session = new xap.session.ClientSession( context,toolkitType ,element );
+	session._start( startPage );
+	return session;
+}
+
+
+
+
+Xap.loadXap = function( sourceRootDir ) {
+	
+	
+}
+
+
+//for some reason dojo.hostent.loadUri() doesn't work on some (one?)
+//of these files, it gives an error on this.func being undefined.
+//That's ok as we are going to ditch these files anyway
+Xap.loadZimbra = function( sourceRootDir ) {
+
+	if ( !sourceRootDir.match(Xap.trailingSlashRegexp)){
+		sourceRootDir +="/" ;
+	}
+
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/msgs/AjxMsg.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/core/AjxCore.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/core/AjxEnv.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxUtil.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxText.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/core/AjxException.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxCookie.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/soap/AjxSoapException.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/soap/AjxSoapFault.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/soap/AjxSoapDoc.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/net/AjxRpcRequest.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/net/AjxRpc.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxWindowOpener.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxVector.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxStringUtils.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/debug/AjxDebug.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/debug/AjxDebugXmlDocument.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/xml/AjxXmlDoc.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/config/data/AjxConfig.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/core/AjxEnv.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/core/AjxImg.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/core/AjxException.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxCallback.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxTimedAction.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/events/AjxEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/events/AjxEventMgr.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/events/AjxListener.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxDateUtils.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxStringUtils.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxVector.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxSelectionManager.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/net/AjxPost.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxBuffer.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/util/AjxCache.js" );
+	
+	// DWT classes
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/core/DwtImg.js" );
+	
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/core/Dwt.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/core/DwtException.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/core/DwtDraggable.js" );
+	
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/graphics/DwtCssStyle.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/graphics/DwtPoint.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/graphics/DwtRectangle.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/graphics/DwtUnits.js" );
+	
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtEventManager.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtDateRangeEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtDisposeEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtUiEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtControlEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtKeyEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtMouseEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtMouseEventCapture.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtListViewActionEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtSelectionEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtHtmlEditorStateEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtTreeEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtHoverEvent.js" );
+	
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/dnd/DwtDragEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/dnd/DwtDragSource.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/dnd/DwtDropEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/dnd/DwtDropTarget.js" );
+	
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtHoverMgr.js" );
+	
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtControl.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtComposite.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtShell.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtColorPicker.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtBaseDialog.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtDialog.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtLabel.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtListView.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtButton.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtMenuItem.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtMenu.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtMessageDialog.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtHtmlEditor.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtInputField.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtSash.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtToolBar.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/graphics/DwtBorder.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtToolTip.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtStickyToolTip.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtTreeItem.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtTree.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtCalendar.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtPropertyPage.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtTabView.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtWizardDialog.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtSelect.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtAddRemove.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtAlert.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtText.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtIframe.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtXFormDialog.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtPropertySheet.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtGrouper.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/widgets/DwtProgressBar.js" );
+	
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/events/DwtXFormsEvent.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/xforms/XFormGlobal.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/xforms/XModel.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/xforms/XModelItem.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/xforms/XForm.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/xforms/XFormItem.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/xforms/XFormChoices.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/xforms/OSelect_XFormItem.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/js/dwt/xforms/ButtonGrid.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/zimbra/examples/tree/TreeExample.js" );
+	
+	//TODO this really shouldn't be here, but they rely on some zimbra stuff
+	//and are zimbra extensions
+	xap.util.Utils.importFile(  sourceRootDir + "src/xap/components/zimbra/DwtSplitter.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/xap/components/zimbra/DwtSplitChild.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/xap/components/zimbra/DwtTablePanel.js" );
+	xap.util.Utils.importFile(  sourceRootDir + "src/xap/components/zimbra/DwtVerticalLayoutPanel.js" );	
+	xap.util.Utils.importFile(  sourceRootDir + "src/xap/components/zimbra/DwtHorizontalLayoutPanel.js" );	
+
+}
+
+Xap.resolveConstructor = function(aString){
+	var scoper = dj_global ;
+	var arr  = aString.split(".") ;
+	for( var kk=0; kk< arr.length - 1; ++kk ){
+		scoper = scoper[arr[kk]] ;
+	}
+	return  scoper[arr[arr.length-1]] ;
+}
+
+
+/**
+ * Handles common class set-up routines, assumes constructors for subclass and superclass already exist:
+**/ 
+Xap.setupClassAsSubclassOf = function(subclassName,superclassName,sub,sup){
+	var subclassConstructor = Xap.resolveConstructor( subclassName ) ;
+	var superclassConstructor = Xap.resolveConstructor( superclassName ) ;	
+
+
+	subclassConstructor.prototype = new superclassConstructor();
+	subclassConstructor.prototype.superclass = 	superclassConstructor.prototype ;
+
+	// This can by default the same for all objects; can overwrite this definition in
+	// the source file, if desired...
+	subclassConstructor.prototype.toString = function(){
+		return subclassName ;	
+	}
+
+	subclassConstructor.s_log = xap.util.LogFactory.getLog( subclassName ) ;
+}
+
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+//Let Dojo know what to expect from this file:
+Xap.provide("xap.util.LogFactory");
+Xap.provide("xap.util.LogFactory.ConsoleLog");
+ /**
+  * @constructor
+ * TODO either replace or expand this to work with some other logging 
+ * framework
+ * 
+ * xap.util.LogFactory provides a single static method that may be used to retrieve
+ * a named Log interface.  Multiple calls to the <code>getLog()</code> method
+ * with the same argument will return the same instance of the Log.
+ *
+ * @author ikaplansky
+ */
+xap.util.LogFactory = function(){} ;
+
+//-----------------------------------------------------------------------
+// Class Variables.
+//-----------------------------------------------------------------------
+xap.util.LogFactory.s_nameToConsoleLog = new Object();
+xap.util.LogFactory.s_loggingEnabled = true;
+//-----------------------------------------------------------------------
+// Constructors.
+//-----------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------
+// Public Class Methods.
+//-----------------------------------------------------------------------
+
+
+
+
+
+/**
+ * Returns an instance of Log for use in logging.
+ * Bypasses an IE Object problem by replacing all 
+ * @param name The named instance to return.
+ */
+xap.util.LogFactory.getLog = function( name ) {
+    if ( ! xap.util.LogFactory.s_nameToConsoleLog[name] ) {
+        xap.util.LogFactory.s_nameToConsoleLog[name] = new xap.util.LogFactory.ConsoleLog( name );
+    }
+    var log = xap.util.LogFactory.s_nameToConsoleLog[name];
+	return log;
+} 
+
+xap.util.LogFactory.disableLogging = function() {
+	xap.util.LogFactory.s_loggingEnabled = false;
+}
+
+xap.util.LogFactory.enableLogging = function() {
+	xap.util.LogFactory.s_loggingEnabled = true;
+}
+
+//-----------------------------------------------------------------------
+// Inner Classes.
+//-----------------------------------------------------------------------
+              
+
+
+xap.util.LogFactory.ConsoleLog = function( name ) {
+    this._name = name;
+    this._isDebug = true;    
+}
+
+xap.util.LogFactory.ConsoleLog.s_logWindow = null;
+    
+xap.util.LogFactory.ConsoleLog.prototype.isDebug = function() {
+    return this._isDebug; 
+}
+
+xap.util.LogFactory.ConsoleLog.prototype.setDebug = function( debug ) {
+	this._isDebug = debug;
+}
+
+xap.util.LogFactory.ConsoleLog.prototype.debug = function ( message ) { 
+	if ( this.isDebug() ) {
+    	this.output( "Debug", message ); 
+    }
+}
+
+xap.util.LogFactory.ConsoleLog.prototype.info = function( message ) { 
+	this.output( "Info", message );
+}
+
+xap.util.LogFactory.ConsoleLog.prototype.warn = function( message ) { 
+	this.output( "Warn", message );
+}
+
+xap.util.LogFactory.ConsoleLog.prototype.error = function( message ) {
+	this.outputErr( "Error", message ); 
+}
+
+xap.util.LogFactory.ConsoleLog.prototype.exception = function ( message, throwable ) {
+    this.outputErr( "Exception", message );
+    if ( throwable ) {
+	    this.outputErr( throwable );
+    }
+}
+
+//---------------------------------------------
+// Private Methods.
+xap.util.LogFactory.ConsoleLog.prototype.output = function( id, message ) {
+	
+	if( xap.util.LogFactory.s_loggingEnabled ) {
+		var output = this.format(id, message);
+		
+	
+		if ( !xap.util.LogFactory.ConsoleLog.s_logWindow || xap.util.LogFactory.ConsoleLog.s_logWindow.closed ) {
+
+	
+			xap.util.LogFactory.ConsoleLog.s_logWindow = window.open('', "XAPLOG");			
+			if (!xap.util.LogFactory.ConsoleLog.s_logWindow || xap.util.LogFactory.ConsoleLog.s_logWindow.closed) return;
+			xap.util.LogFactory.ConsoleLog.s_logWindow.document.open();
+			xap.util.LogFactory.ConsoleLog.s_logWindow.document.writeln("<head><title>Log</title></head><body><div id=\"log\"/></body>" );
+			xap.util.LogFactory.ConsoleLog.s_logWindow.document.close();
+		}
+		
+		if (!xap.util.LogFactory.ConsoleLog.s_logWindow || xap.util.LogFactory.ConsoleLog.s_logWindow.closed) return;
+
+
+		//then write to log window
+		var consoleDoc = xap.util.LogFactory.ConsoleLog.s_logWindow.document;
+		var log = consoleDoc.getElementById('log');
+		var p = consoleDoc.createElement('p');
+		
+		('Error Exception'.indexOf(id) != -1) && (p.style.color = '#BB0000');
+		
+		p.appendChild(consoleDoc.createTextNode(output));
+		
+		log.appendChild(p);
+		
+		var opener = xap.util.LogFactory.ConsoleLog.s_logWindow.opener;
+		if (opener && opener.focus) {opener.focus();}
+		
+
+	}
+}
+
+xap.util.LogFactory.ConsoleLog.prototype.outputErr = function( id, message ) {
+    this.output( id, message );
+}
+
+xap.util.LogFactory.ConsoleLog.prototype.format = function( id, message ) {
+    var buff = "[" + id + " - " + new Date() + " (" + this._name +
+        "): " + message + "]";
+    return buff;
+}
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+ /**
+ * @fileoverview Helper class for testing is items are letters,
+ *  whitespace, alphanumeric, etc.
+ * 
+ * @author ikaplansky
+ */
+
+Xap.provide("xap.util.Character");
+
+
+/**
+ * There is no need to ever construct a Character object
+ * at this time, just use the static methods.
+ * 
+ * @class  Helper class for testing is items are letters,
+ * whitespace, alphanumeric, etc.
+ * 
+ * @constructor
+ */
+ 
+xap.util.Character = function(){}
+
+/** @private */
+xap.util.Character._reLetter = /^[a-zA-Z]$/;
+
+
+/** @private */
+xap.util.Character._reDigit = /^\d/;
+
+/** @private */
+xap.util.Character._reLetterOrDigit = /^([a-zA-Z]|\d)$/;
+
+/** @private */
+xap.util.Character._reWhitespace = /^(\s)*$/;
+
+
+//None of these are used right now,
+//comment them back in as needed
+//Character.reAlphabetic = /^[a-zA-Z]+$/;
+//Character.reAlphanumeric = /^[a-zA-Z0-9]+$/;
+//Character.reInteger = /^\d+$/;
+//Character.reSignedInteger = /^(\+|-)?\d+$/;
+//Character.reFloat = /^((\d+(\.\d*)?)|((\d*\.)?\d+))$/;
+//Character.reSignedFloat = /^(((\+|-)?\d+(\.\d*)?)|((\+|-)?(\d*\.)?\d+))$/;
+
+
+xap.util.Character.isLetter = function ( c ) {
+	return xap.util.Character._reLetter.test( c );
+}
+
+xap.util.Character.isDigit = function ( c ) {
+	return xap.util.Character._reDigit.test( c );
+}
+
+xap.util.Character.isLetterOrDigit = function( c ) {
+	return xap.util.Character._reLetterOrDigit.test( c );
+}
+
+xap.util.Character.isWhiteSpace = function ( str ) {
+	return xap.util.Character._reWhitespace.test( str );
+}
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+ /**
+ * This class contains useful helper methods for working with XML.
+ * 
+ * @author ikaplansky
+ */
+//ExperimentXap.require("xap.util.Character");
+
+
+xap.util.XmlUtils = function(){}
+
+// We need to special-case validating tag names to include this
+xap.util.XmlUtils.INDENTATION = "    ";
+
+/**
+ * Provides an indentation String for the given level of indentation.
+ *
+ * @param indentationLevel The level of indentation.
+ */
+xap.util.XmlUtils.getIndentation = function( indentationLevel ) {
+    var indentation = "";
+    for ( var i = 0; i < indentationLevel; i++ ) {
+        indentation += xap.util.XmlUtils.INDENTATION;
+    }
+    return indentation;
+}
+
+/**
+ * This method will XML-encode a string.
+ * 
+ * @param s - the string to be encoded
+ * @return - the encoded string
+ * @see #xmlDecode(String)
+ */
+xap.util.XmlUtils.encode = function( s ) {
+    if ( s == null ) {
+		return "";
+    }
+    
+	var buffer = new Array( s.length );
+	var c;
+	for ( var i = 0; i < s.length; i++ ) {
+		c = s.charAt( i );
+		
+		if (c == '&') {
+			buffer[i] = "&amp;";
+        } else if (c == '<') {
+			buffer[i] = "&lt;";
+        } else if (c == '>') {
+			buffer[i] = "&gt;";
+        } else if (c == '\'') {
+			buffer[i] = "&apos;";
+        } else if (c == '\"') {
+			buffer[i] = "&quot;";
+        } else {
+			buffer[i] = c;
+        }
+	}
+	return buffer.join("");
+}
+
+/**
+ * This method will perform a simple XML-encoding of double quotes only.
+ * This can be useful for readability of attribute values where a strict
+ * parser is not in use.  
+ * 
+ * @param s - the string to be encoded
+ * @return - the encoded string
+ * @see #xmlDecode(String)
+ */
+xap.util.XmlUtils.encodeDoubleQuotes = function( s ) {
+    if ( s == null ) {
+		return "";
+    }
+	var buffer = new Array( s.length );
+	var c;
+	for (var i = 0; i < s.length; i++) {
+		c = s.charAt( i );
+		if ( c == '\"' ) {
+			buffer[i] = "&quot;";
+        } else {
+			buffer[i] = c;
+        }
+	}
+	return buffer.join("");
+}
+
+/**
+ * This method will XML-decode a string.
+ * 
+ * @param s - the string to be decoded
+ * @return - the decoded string
+ * @see #xmlEncode(String)
+ */
+xap.util.XmlUtils.decode = function( str ) {
+	if ( str == null ) {
+        return "";
+    }
+	
+	var buffer = new Array( str.length );
+	var s = str.toLowerCase();
+	var c;
+
+	for ( var i = 0; i < s.length; i++) {
+		c = s.charAt(i);
+		
+		if (c == '&') {
+			if ( s.indexOf( "&amp;", i ) != -1 ) {
+				buffer[i] = "&";
+				i += 4;
+			} else if ( s.indexOf( "&lt;", i ) != -1 ) {
+				buffer[i] = "<";
+				i += 3;
+			} else if ( s.indexOf( "&gt;", i ) != -1 ) {
+				buffer[i] = ">";
+				i += 3;
+			} else if ( s.indexOf( "&apos;", i ) != -1) {
+				buffer[i] = "\'";
+				i += 5;
+			} else if ( s.indexOf( "&quot;", i ) != -1) {
+				buffer[i] = "\"";
+				i += 5;
+			} else {
+				buffer[i] = c;
+			}
+		} else {
+			buffer[i] = c;
+		}
+	}
+	return buffer.join("");
+}
+
+/**
+ * Checks to make sure a given string is a valud XML-1.0 tag name.
+ * 
+ * @param tagName - the string to check
+ * @return - true if valid, false otherwise
+ */
+xap.util.XmlUtils.isValidXmlTagName = function( tagName ) {
+    if( tagName == null ) {
+        return false;
+    }
+    if( tagName.length == 0 ) {
+        return false;
+    }
+    var firstChar = tagName.charAt( 0 );
+    if( xap.util.Character.isLetter( firstChar ) == false && firstChar != '_'){
+        //tags can begin with only letters or underscore
+        return false;
+    }
+    if( tagName.length >= 3 ) {
+        var test = tagName.substring( 0, 3 );
+	    if( test.toLowerCase() == "xml" ) {
+            // Tags cannot start with any variation of "xml"
+            return false;
+        }
+    }
+    for( var i = 1; i < tagName.length; i++ ) {
+        var c = tagName.charAt( i );
+        if( xap.util.Character.isLetterOrDigit(c) == false && 
+           c != '.' &&
+           c != '_' &&
+           c != '-') {
+		    return false;
+        }
+    }
+    return true;
+}
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ Xap.provide( "xap.util.HttpUtils" ) ;
+ 
+ 
+ 
+ /**
+ * TODO either expand or replace this with another good set of utilities to deal
+ * with HTTP/network functionality. We need to be able to do things like post,
+ * set headers, etc, and we need to return the request itself rather than
+ * the content so we can check status code etc etc
+ * 
+ * Creates an HTTP request that can then be sent to the server.
+ * @param url The url to the server page. This follows the rules
+ * of createFullyQualifiedUrl. If the url doesn't have a leading slash, the 
+ * current application context will be used.
+ * @return, a new HttpRequest object with uri set to the provided url information. The 
+ * 			request's "Content-Type" is set to "application/octet-stream" by default.
+ * 
+ * @author ikaplansky
+ */
+
+xap.util.HttpUtils = function(){}
+
+xap.util.HttpUtils.s_log = xap.util.LogFactory.getLog( "xap.util.HttpUtils" ); 
+
+
+
+xap.util.HttpUtils.createHttpRequest = function() {
+	var request;
+	try {
+       	if ( window.XMLHttpRequest ) {
+       		request = new XMLHttpRequest();
+        } else {
+           	request = new ActiveXObject("Microsoft.XMLHTTP");
+       	}
+    } catch( e ) {
+    	xap.util.HttpUtils.s_log( "XMLHttpRequest is not supported in this browser"
+							  + e );
+    } 
+	return request;
+}
+
+
+xap.util.HttpUtils.get = function( url, callback){
+	var request = xap.util.HttpUtils.createHttpRequest();
+	request.open( "GET", url, callback!=null );
+	if( callback ) {
+		request.onreadystatechange = function() {
+ 			if( request.readyState == 4 ) {
+ 				//TODO need object here? other states?
+ 				callback.apply( request );
+ 			}
+   	}
+	}
+	
+	request.send( null );
+	return request;
+}
+
+xap.util.HttpUtils.post = function( url, callback, content){
+	var request = xap.util.HttpUtils.createHttpRequest();
+	request.open( "POST", url, callback!=null );
+	if( callback ) {
+		request.onreadystatechange = function() {
+ 			if( request.readyState == 4 ) {
+ 				//TODO need object here? other states?
+ 				callback.apply( request );
+ 			}
+   	}
+	}
+	
+	request.send( content );
+	return request;
+}
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+//Let Dojo know what to expect from this file:
+Xap.provide('xap.util.UidProvider'); 
+ 
+ /**
+ * @fileoverview xap.util.UidProvider generates a sequences of unique ids. 
+ * 
+ * @author ikaplansky
+ */
+
+
+/**
+ * Creates a xap.util.UidProvider with the given seed.
+ * 
+ * @class xap.util.UidProvider generates a sequences of unique ids. You can use it 
+ * by instantiating an instance of a xap.util.UidProvider or through the static 
+ * createId method.
+ * 
+ * @param {String} seed A unique-ish string.
+ */
+xap.util.UidProvider = function( seed ) {
+    this._count = 0;
+    if ( seed == null ) {
+         this._seed = xap.util.UidProvider._createSeed();
+    } else {
+         this._seed = seed;
+    }
+    
+    if ( this._seed[ this._seed.length -1 ] != '-' ) {
+    	this._seed = this._seed + "-";
+    }
+}
+
+
+/** @private */
+xap.util.UidProvider.XAP_ID_PREFIX = "xap:";
+
+/** @private */
+xap.util.UidProvider.s_count = 0;
+
+/** @private */
+xap.util.UidProvider._createSeed = function () {
+	return new Date().getTime();
+}
+
+/** @private */
+xap.util.UidProvider.s_seed = xap.util.UidProvider._createSeed();
+
+//-----------------------------------------------------------------------
+// Public Class Methods.
+//-----------------------------------------------------------------------
+
+/**
+ * Returns a unique id.
+ * 
+ * @type String
+ */
+xap.util.UidProvider.createId = function() {
+	return new String( xap.util.UidProvider.XAP_ID_PREFIX + 
+    				   xap.util.UidProvider.s_seed + xap.util.UidProvider.s_count++ );
+}
+
+
+//-----------------------------------------------------------------------
+// Public Methods.
+//-----------------------------------------------------------------------
+
+/**
+ * Returns a unique id that directly follows the last created ID.
+ * Different runs of nextId() starting with the same seed should always
+ * return the same IDs.
+ * 
+ * @type String
+ */
+xap.util.UidProvider.prototype.nextId = function () {
+	return xap.util.UidProvider.XAP_ID_PREFIX + this._seed + this._count++;
+}
+
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+//Let Dojo know what to expect from this file:
+Xap.provide('xap.util.Hashtable'); 
+
+ 
+//TODO like many classes exception handling here needs to be
+//more thought out.
+
+/**
+ * @fileoverview A standard hashtable implementation.
+ *
+ * @author ikaplansky
+ * @author jmargaris
+ * 
+ */
+ 
+/** 
+ * Creates a new xap.util.Hashtable.
+ * 
+ * @class A standard hashtable implementation. Unlike
+ * many hashtable implementations this will work for object to object
+ * mappings, not just strings to objects. Unique keys should
+ * always map properly, regardless of their toString() implementations.
+ */
+xap.util.Hashtable  =function(){
+    this._hashtable = new Object();
+    this._size = 0;
+}
+
+
+/**
+ * @private
+ * A key we keep incrementing to help us assign
+ * new unique has keys to objects.
+ */
+xap.util.Hashtable.s_uniqueKey = 0;
+
+/**
+ * Clears the hashtable of all key/value pairs.
+ */
+xap.util.Hashtable.prototype.clear = function() {
+    this._hashtable = new Object();
+}
+
+/**
+ * Returns true if the given object is a key in the hashtable.
+ * @type boolean
+ */
+xap.util.Hashtable.prototype.containsKey = function( key ) {
+	if (key===null){
+		throw new xap.util.Exception( "key cannot be null in xap.util.Hashtable.containsKey()" );
+	}
+	key = this._computeKey(key);
+	return this._hashtable[key]!=null;
+}
+
+/**
+ * Returns true if the given object is a value in the hashtable.
+ * @type boolean
+ */
+xap.util.Hashtable.prototype.containsValue = function( value ) {
+	if (value==null){
+		throw new xap.util.Exception( "value cannot be null at xap.util.Hashtable.containsValue()" );
+	}
+	for ( var i in this._hashtable ) {
+		if ( this._hashtable[i] == value ) {
+			return true;
+		}
+	}
+	return false;
+}
+
+/**
+ * Returns the object mapped to the given key, or null
+ * if no mapping exists for that key.
+ */
+xap.util.Hashtable.prototype.get = function ( key ) {
+	if (key==null){
+		throw new xap.util.Exception( "key cannot be null at xap.util.Hashtable.get()" );
+	}
+	key = this._computeKey(key);
+	return this._hashtable[key];
+}
+
+/**
+ * Maps the given key to the given value, replacing and returning any old value.
+ * @return The old value that was mapped to the given key.
+ */
+xap.util.Hashtable.prototype.put = function( key, value ) {
+    if ( key == null ) {
+        throw new xap.util.Exception( "key cannot be null at xap.util.Hashtable.put()" );
+    }
+    if( value == null ) {
+        throw new xap.util.Exception( "value cannot be null at xap.util.Hashtable.put()" );
+    }
+    key = this._computeKey(key);
+    if( this._hashtable[key] == null ) {
+    	this._size++;
+    }
+    
+    var o = this._hashtable[key];
+    this._hashtable[key] = value;
+    return o;
+}
+
+/**
+ * Removes the mapping for this key.
+ * @return The object that was mapped to this key.
+ */
+xap.util.Hashtable.prototype.remove = function( key ) {
+	if (key==null){
+		throw new xap.util.Exception( "key cannot be null at xap.util.Hashtable.remove()" );
+	}
+	key = this._computeKey(key);
+	var rtn = this._hashtable[key];
+	delete( this._hashtable[key] );
+	if( rtn != null ) {
+		this._size--;
+	}
+	return rtn;
+}
+
+/**
+ * Returns the number of key/value mappings in the hashtable.
+ * @type integer
+ */
+xap.util.Hashtable.prototype.size = function() {
+    return this._size;
+}
+
+
+xap.util.Hashtable.prototype.toString = function() {
+    var result = "{";
+    for ( var i in this._hashtable) {      
+        if ( this._hashtable[i] != null ) { 
+            result += i + "=>" + this._hashtable[i] + "\n";   
+        }
+    }
+    result += "}";
+    return result;
+}
+
+
+//TODO this is a bit messed up right now as it returns
+//the keys AFTER they have been transformed by
+//_computeKey so they may not match the keys the things
+//were added with originally. We should keep a map of
+//keys to original objects?
+/**
+ * Returns an array of all the keys in the hashtable.
+ * @type Array
+ */
+xap.util.Hashtable.prototype.keys = function() {
+	var keys = new Array(this.size());
+	var index = 0;
+	for ( var i in this._hashtable ) {
+		
+		//TODO do we really need this check?
+		if ( this._hashtable[i] != null ) { 
+			keys[index]=i;
+			index++;
+		}
+	}
+	return keys;
+}
+
+/**
+ * Returns an array of all the values in the hashtable.
+ * @type Array
+ */
+xap.util.Hashtable.prototype.values = function() {
+	var values = new Array(this.size());
+	var index = 0;
+	for ( var i in this._hashtable ) {
+		if ( this._hashtable[i] != null ) { 
+			values[index] = this._hashtable[i];
+			index++;
+		}
+	}
+	return values;
+}
+
+/**
+ * @private
+ * Compute a hashtable key. If the thing is a number or string
+ * or has a _hashKey use that, otherwise assign a unique one.
+ * We need to do this because js objects don't have
+ * any innate sort of hashKey() function and we can't rely
+ * on toString() because that's just silly.
+ * (Most hs hashtables do rely on toString - and don't work)
+ * TODO look over this more
+ */
+xap.util.Hashtable.prototype._computeKey = function( x ){
+
+	if (typeof(x) != 'object'){
+		return x.toString();
+	}
+	
+	if (x.constructor==Number || x.constructor==String){
+		return x.toString();
+	}
+	
+	if (x._xapHashKey==null){
+		x._xapHashKey = xap.util.Hashtable.s_uniqueKey++;
+	}
+	return x._xapHashKey.toString();
+}
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+ 
+ 
+Xap.provide("xap.util.Exception");
+ 
+/**
+ * @fileoverview Base class for non-internationalized exceptions
+ * 
+ * @author ikaplansky
+ * @author jmargaris
+ */
+ 
+ 
+/**
+ * Creates a new exception with the given message and cause.
+ * 
+ * @class Base class for non-internationalized exceptions
+ * 
+ * @param message The message
+ * @param cause The cause of the message, typically another exception
+ */
+xap.util.Exception = function( message, cause, location ) {
+	this._message = message;
+	this._cause = cause;
+	this._location = location;
+}
+
+xap.util.Exception .prototype.getLocation = function() {
+	return this._location;
+}
+
+xap.util.Exception .prototype.getMessage = function() {
+	return this._message;
+}
+
+xap.util.Exception .prototype.getCause = function() {
+	return this._cause;
+}
+
+xap.util.Exception .prototype.toString = function() {
+	var buf = "Message:" + this._message;
+	if( this._cause != null ){
+		buf += "\nCause:" + this._cause.toString();
+	}
+	return buf;
+}
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+Xap.provide("xap.util.EscapeSyntaxParser");
+//ExperimentXap.require("xap.util.Exception");
+
+
+//TODO docs here need help, mostly ported over unchanged.
+
+/**
+ * @fileoverview A parser for escaping/unescaping strings based on
+ * escape sequences.
+ * 
+ * @author jmargaris
+ */
+ 
+/**
+ * Creates a new EscapeSyntaxParser.
+ * 
+ * @class This class is used for escaping/unescaping strings that have single-character
+ * escape sequences in them. An escape syntax parser maps escape sequences
+ * of the form 'Xa' to 'b' where 'X' is the escape lead (typically a \),
+ * 'a' is the character being escaped and 'b' is the resulting character.
+ * <br><br>
+ * For example take the following EscapeSyntaxParser: <br><br>
+ * <code>
+ * new xap.util.EscapeSyntaxParser('\\', ['\\', '{', '}'], ['\\', '{', '}'], false);
+ * </code>
+ * <br><br>
+ * In this case '\' is the escape sequence starter. '\\' is mapped to '\', 
+ * '\{' is mapped to '{', and '\}' is mapped to '}'<br><br>
+ * Now consider the following alernate parser:<br>
+ * <code>
+ * new xap.util.EscapeSyntaxParser('x', ['\\', '{', '}'], ['a', 'b', 'c'], false);
+ * </code><br><br>
+ * In this case 'x' is the escape sequence starter. 'x\' is mapped to 'a', 
+ * 'x{' is mapped to 'b', and 'x}' is mapped to 'c'
+ * 
+ * 
+ * 
+ * @param {Character} escapeLead The character that signifies an escape sequence, typically \
+ * @param {Array} escapeChars An array of characters to escape
+ * @param {Array} resolvedChars A parallel array of characters to resolve to
+ * @param {Boolean} strict If true report all unrecognized escape sequences as errors
+ */
+xap.util.EscapeSyntaxParser = function( escapeLead, escapeChars, resolvedChars, strict ){
+	this._escapeLead = escapeLead;
+	this._escapeSequenceCharacters = escapeChars;
+	this._resolvedCharacters = resolvedChars;
+	this._reportUnknownEscapeSequencesAsErrors = strict;
+	
+}
+
+xap.util.EscapeSyntaxParser.UNRESOLVED_CHARACTER = new Object();
+
+
+/**
+ * Returns the resolved character at the given index in the given string.
+ * If the escapeSequenceIndex does not point to the start of an escape
+ * sequence UNRESOLVED_CHARACTER is returned, NOT the original character. This method
+ * exists for complex parsing operations such as parsing a comma separated
+ * list of parameters which may each have different escape sequences.
+ * 
+ * @param s
+ * @param escapeSequenceIndex
+ * @return TODO
+ * @throws RuntimeException
+ */	
+xap.util.EscapeSyntaxParser.prototype.getResolvedCharacter = function( s, index){
+	var c = s.charAt(index);
+
+	//if we don't start with the escape sequence starter we are done
+	if (c!=this._escapeLead){
+		return xap.util.EscapeSyntaxParser.UNRESOLVED_CHARACTER;
+	}	
+	//if \ was the last character that's not valid
+	if (index+1>=s.length && this._reportUnknownEscapeSequencesAsErrors){
+		throw new xap.util.Exception("Invalid escape sequence: " + this._escapeLead +
+			" at index " + index + " in string: " + s);
+	}
+		
+	//get the next character after the \ and check it against our list
+	//if we find it, return the corresponding resolved character
+	var keyCharacter = s.charAt(index+1);
+	for (var i = 0 ; i<this._escapeSequenceCharacters.length; i++){
+		if (keyCharacter==this._escapeSequenceCharacters[i]){
+			return this._resolvedCharacters[i];
+		}
+	}
+		
+	if (this._reportUnknownEscapeSequencesAsErrors){
+		throw new xap.util.Exception("Invalid escape sequence: " + this._escapeLead + keyCharacter +
+			" at index " + index + " in string: " + s);
+	}
+		
+	//if we got here it means we had \x where that is not a valid
+	//escape sequence AND we are not reporting that as error so 
+	//just say we didn't need to do any resolution which should make
+	//the caller just accept the \ as a normal character
+	return xap.util.EscapeSyntaxParser.UNRESOLVED_CHARACTER;
+}
+
+	/**
+	 * Given an unescaped string, convert it into an escaped one that
+	 * fits this escape syntax. For example given the string
+	 * "hello\there" turn it into "hello\\there".
+	 * @param s The string to escape.
+	 * @return A properly escaped string
+	 */
+xap.util.EscapeSyntaxParser.prototype.escape = function( s ){
+	var b = new String();
+	for (var i =0; i<s.length; i++){
+		var c = s.charAt(i);
+		var neededReplace = false;
+		for (var j=0; j<this._resolvedCharacters.length; j++ ){	
+			//replace character with an escape sequence
+			if (c==this._resolvedCharacters[j]){
+				b += this._escapeLead;
+				b += this._escapeSequenceCharacters[j];
+				neededReplace = true;
+				break;
+			}
+		}
+			
+		//if we didn't replace the character
+		//with an escape sequence just append it directly.
+		if (!neededReplace){
+			b += c;
+		}
+	}
+	return b;
+}
+	
+/**
+ * Parses the string and returns a new string with escape sequences
+ * replaced with resolved values if any resolution was needed. If not
+ * the original string is returned. 
+ */
+xap.util.EscapeSyntaxParser.prototype.parse = function( s ){
+	var buffer = null;
+	for (var i =0; i<s.length; i++){
+		var c = this.getResolvedCharacter(s,i);
+		
+		//if c==UNRESOLVED_CHARACTER it means no resolution was needed, so just
+		//apend on the original character
+		if (c==xap.util.EscapeSyntaxParser.UNRESOLVED_CHARACTER){
+			
+			//if we are building up a resolved string append to it
+			if (buffer!=null){
+				buffer += s.charAt(i);
+			}
+		}
+		
+		//if we got some value back, that is what we should use and we
+		//also need to SKIP over the next character!
+		else{
+			//if we don't have a buffer yet we need to make one now
+			//that has all the content we've skipped over so far
+			if (buffer==null){
+				buffer = s.substring(0,i);
+			}
+			buffer+=c;
+			i++;
+		}
+	}
+	return buffer==null?s:buffer;
+}
+
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+
+Xap.provide("xap.util.MessageFormat");
+Xap.require("xap.util.EscapeSyntaxParser")
+
+/**
+ * @fileoverview Provides an approximation of Java message format.
+ * @author jmargaris
+ * 
+ */
+ 
+/**
+ * @class Provides an approximation of Java message format.
+ */ 
+xap.util.MessageFormat = function() {}
+
+
+/**
+ * A simple approximation of Java message format,
+ * takes a string like "aaa{0} bbb{1} ccc{2}" and plugs
+ * in arguments in that order. Currently there is no escape syntax at all. TODO
+ * 
+ * @param {String} formatString The string message format.
+ * @param {Array} args An array of arguments to plug into the message format.
+ */
+xap.util.MessageFormat.format = function( formatString, args ){
+	if (!formatString){
+		return null;
+	}
+	
+	//TODO escaping syntax?? And if we replace something
+	//and it has a {1} we are in trouble...
+	for (var i =0; args && i<args.length; i++){	
+		var replacementString = "\\{" + i + "\\}";
+		var regEx = new RegExp(replacementString, "gm");
+		
+		formatString = formatString.replace(regEx, ""+args[i]);
+	}
+	return formatString;
+}
+
+//TODO if nothing else put this in a general
+//xap.string.... method
+//along with trim() and others.
+
+
+//DOJO code that is similar
+//no escape syntax here either?
+//this lets you do something like:
+//asd {hello} asd {goodbye}
+//then pass in an object[hello]=x and object[goodby]=y and do the sub that way
+
+// dojo.string.substituteParams = function(template /*string */, hash /* object - optional or ... */) {
+//	var map = (typeof hash == 'object') ? hash : dojo.lang.toArray(arguments, 1);
+//
+//	return template.replace(/\%\{(\w+)\}/g, function(match, key){
+//		return map[key] || dojo.raise("Substitution not found: " + key);
+//	});
+//};
+// 
+//
+
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+Xap.provide( "xap.util.ResourceDictionary" ) ;
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.util.Hashtable");
+//Experiment
+Xap.require("xap.util.MessageFormat");
+
+ 
+ 
+ 
+ /**
+ * xap.util.ResourceDictionary's purpose is to look up messages (i.e. debug, info) by
+ * ids.  The messages should be defined in property files that are specific to
+ * given locales.
+ * 
+ * @author ikaplansky
+ */
+
+
+
+xap.util.ResourceDictionary = function() {}
+
+//-------------------------------------------------------------------
+// Class Variables.
+//-------------------------------------------------------------------
+xap.util.ResourceDictionary.s_classnameToResourceObject = new xap.util.Hashtable();
+xap.util.ResourceDictionary.s_log = xap.util.LogFactory.getLog( "xap.util.ResourceDictionary" );
+
+//-------------------------------------------------------------------
+// Public Class Methods.
+//-------------------------------------------------------------------
+xap.util.ResourceDictionary.getMessage = function( msgId, className, args ) {
+	var resourceObject = xap.util.ResourceDictionary.s_classnameToResourceObject.get
+																( className );
+	if( resourceObject == null ) {
+		try {
+//Experiment      Xap.require(className);
+			var resourceObject = eval ( "new " + className + "Res();" );
+			xap.util.ResourceDictionary.s_classnameToResourceObject.put( className, resourceObject );
+		} catch ( e ){
+			xap.util.ResourceDictionary.s_log.exception( "Exception getting message:" +
+				"id=" + msgId + ",classname=" + className + 
+				", args:" + args + ", exception:" + e );
+		}
+	}
+	if( resourceObject != null ) {
+		var messagePattern = resourceObject.messages[msgId];	
+		return xap.util.MessageFormat.format( messagePattern, args);
+	}
+	return "MsgId:" + msgId + ",class:" + className + ",args:" + args;
+}
+
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+//Let Dojo know what to expect from this file:
+Xap.provide('xap.util.XapException'); 
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.util.ResourceDictionary");
+
+
+ 
+ /**
+ * @fileoverview Base class for internationalized exceptions
+ * 
+ * @author ikaplansky
+ */
+ 
+
+/**
+ * Creates a new exception with the given message id, args and cause.
+ * 
+ * @class Base class for internationalized exceptions. These exceptions
+ * are created with a message ID rather than a text message. That ID
+ * is looked up in another resource set and the args are plugged into
+ * the message format. Currently the resource set is defined
+ * as getClassName() + "Res" but that should probably change,
+ * this scheme needs to be thought out a lot more. The ideal is that
+ * it's easy to swap in different sets of messages with a minimal
+ * amount of effort.
+ * 
+ * @param msgId The ID of the message format to use
+ * @param args An array of arguments that plug into the message format.
+ * @param cause The cause of the message, typically another exception
+ * @param location Information on where the exception occured, for example 
+ * classname-methodname
+ */
+
+xap.util.XapException = function( msgId, args, cause, location ) {
+	// any time when this exception is subclassed, the xap.util.XapException constructor
+	// gets called without any args to define the prototype of the subclass.
+	// we want to ignore those calls.
+	if( msgId ) {
+		this._msgId = msgId;
+		this._localizedMessage = xap.util.ResourceDictionary.getMessage( msgId,
+			this.getClassName(), args );
+		this._cause = cause;
+		this._location = location;
+	}
+}
+
+xap.util.XapException.CLASSNAME = "xap.util.XapException";
+
+//-----------------------------------------------------------------------
+// Public Methods.
+//-----------------------------------------------------------------------
+    
+/**
+ * Returns the Throwable object that was specified in the constructor
+ * of this exception as the cause.  This may be null.
+ * 
+ * @return The cause exception.
+ */
+xap.util.XapException.prototype.getCause = function() {
+	return this._cause;
+}
+
+xap.util.XapException.prototype.getLocation = function() {
+	return this._location;
+}
+
+/**
+ * Returns the id of the message that was used for localization.
+ * This is the value passed in the constructor.
+ *
+ * @return The message id.
+ */
+xap.util.XapException.prototype.getMessageId = function() {
+	return this._msgId;
+}
+
+xap.util.XapException.prototype.getMessage = function() {
+	return this._localizedMessage;
+}
+
+xap.util.XapException.prototype.toString = function() {
+	return this._localizedMessage;
+}
+
+xap.util.XapException.prototype.getClassName = function() {
+	return xap.util.XapException.CLASSNAME;
+}
+
+/**
+ * Converts an exception to a string. This should work for
+ * xap.util.XapException, xap.util.Exception and built-in JS exceptions
+ */
+xap.util.XapException.exceptionToString = function(exception){
+	var s = new String();
+	
+	if (!exception){
+		return s;
+	}
+	
+	if (exception.name && exception.message){ //should exist for browser exceptions
+		s+= "Exception: " + exception.name + " - " + exception.message + "\n";
+	}
+	
+	else if (exception.getMessage){//should exist for xap exceptions
+		s+="Exception:" + exception.getMessage() + "\n";
+	}
+	
+	if (exception.getLocation && exception.getLocation()){
+		s+="Occured at:" + exception.getLocation() + "\n";
+	}
+	
+	if (exception.getCause && exception.getCause()){
+		s+="Caused by:\n" + xap.util.XapException.exceptionToString(exception.getCause());
+	}
+	
+	//next-to-last resort just use toString
+	if (s.length==0 && exception.toString){
+		s = exception.toString();
+	}
+	// last resort: let JS sort it out:
+	if (s.length==0){
+		s = "" +exception ;
+	}
+	
+	return s;
+	
+	
+}
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+//Let Dojo know what to expect from this file:
+Xap.provide('xap.util.XapExceptionRes'); 
+
+ 
+ /**
+ * @fileoverview Base class for internationalized exceptions
+ * 
+ * @author ikaplansky
+ */
+ 
+
+/**
+ * Resource for XapException.
+ * 
+ * @class Resource for XapException---will need to keep this around as long
+ * as XapException is around, otherwise we get errors when it's expected.
+ */
+
+xap.util.XapExceptionRes = function( ) {}
+
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+Xap.provide( "xap.util.Profiler" ) ;
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.util.Hashtable");
+
+
+xap.util.Profiler = function (){}
+
+xap.util.Profiler._hashtable = new xap.util.Hashtable();
+
+xap.util.Profiler.s_log = xap.util.LogFactory.getLog("xap.util.Profiler");
+
+xap.util.Profiler.start = function( message ){
+	var x = xap.util.Profiler._hashtable.get(message);
+	if (!x){
+		x = new Array();
+	}
+	
+	x.push(new Date());
+	
+	xap.util.Profiler._hashtable.put(message, x);
+}
+
+xap.util.Profiler.end = function( message ){
+	var now = new Date();
+	var x = xap.util.Profiler._hashtable.get(message);
+
+	
+	if (!x || x.length==0) return;
+	var startTime = x.pop();
+
+	var message = message + "[" + x.length + "] took " + (now.getTime()-startTime.getTime()) + "ms";	
+	xap.util.Profiler.s_log.debug(message);	
+}
+
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+//Let Dojo know what to expect from this file:
+Xap.provide('xap.xml.dom.events.DomChangeEvent'); 
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.events.StructureChangeEvent");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.XapElement");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.Document");
+
+ 
+ /* @fileoverview xap.xml.dom.events.DomChangeEvent is the base class for {@link xap.xml.dom.events.AttributeChangeEvent}
+ * and {@link xap.xml.dom.events.StructureChangeEvent}.
+ * 
+ * @author ikaplansky
+ */
+ 
+/*
+ * xap.xml.dom.events.DomChangeEvent should not be instantiated directly.
+ * 
+ * @class xap.xml.dom.events.DomChangeEvent is the base class for {@link xap.xml.dom.events.AttributeChangeEvent}
+ * and {@link xap.xml.dom.events.StructureChangeEvent}.
+ * 
+ * @param source The source xap.xml.dom.XapElement on which the event occurred.
+ * 
+ * @author ikaplansky
+ */
+xap.xml.dom.events.DomChangeEvent = function( source ) {
+	this._sourceElement = source;
+}
+
+
+
+//-----------------------------------------------------------------------
+// Public Methods.
+//-----------------------------------------------------------------------
+    
+/**
+ * Get the Element on which the event is being triggered.  For 
+ * attribute changes, this will be the element on which the attribute
+ * was changed, for element additions and removals this is the parent
+ * on which the change was triggered.
+ *
+ * <br><br>
+ *
+ * This method will return null if there is no source element.  This
+ * can happen when the event is generated as the result of setting
+ * a xap.xml.dom.Document root node.
+ *
+ * @return The Element that triggered the event or null if there is
+ * no element parent.
+ */
+xap.xml.dom.events.DomChangeEvent.prototype.getSourceElement = function () {
+	return this._sourceElement;
+}
+
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+//Let Dojo know what to expect from this file:
+Xap.provide('xap.xml.dom.events.AttributeChangeEvent'); 
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.events.DomChangeEvent");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.events.AttributeChangeListener");
+
+
+/**
+ * @fileoverview Event object that encapsulates attribute changes.
+ * 
+ * @author ikaplansky
+ * @author jmargaris
+ */
+
+
+/**
+ * Creates an xap.xml.dom.events.AttributeChangeEvent instance.
+ * 
+ * @class xap.xml.dom.events.AttributeChangeEvent objects are passed to methods on {@link
+ * xap.xml.dom.events.AttributeChangeListener}.  They contain information about attribute
+ * changes.
+ * 
+ * @see xap.xml.dom.events.AttributeChangeListener
+ * 
+ * @param source The source xap.xml.dom.XapElement
+ * @param name The attribute name
+ * @param newValue The new value for the attribute
+ */
+xap.xml.dom.events.AttributeChangeEvent = function( source, name, newValue ) {
+	xap.xml.dom.events.DomChangeEvent.call( this, source );
+	this._attributeName = name;
+  	this._oldValue = source.getAttribute( this._attributeName );
+	this._newValue = newValue;
+}
+
+xap.xml.dom.events.AttributeChangeEvent.prototype = new xap.xml.dom.events.DomChangeEvent;
+
+
+//-----------------------------------------------------------------------
+// Public Methods
+//-----------------------------------------------------------------------
+
+
+
+/**
+ * Returns the name of the attribute being changed.
+ * 
+ * @return The name of the attribute being changed.
+ */
+xap.xml.dom.events.AttributeChangeEvent.prototype.getName = function() {
+	return this._attributeName;
+}
+
+/**
+ * Returns the value of the attribute before the change.
+ * This method returns null if the attribute didn't previously
+ * exist on the source element.
+ * 
+ * @return The value of the attribute before the change.
+ */
+xap.xml.dom.events.AttributeChangeEvent.prototype.getOldValue = function() {
+	return this._oldValue;
+}
+
+/**
+ * Returns the new value of the attribute.
+ * This method returns null if the attribute is being removed
+ * from the source element.
+ * 
+ * @return The new value of the attribute.
+ */
+xap.xml.dom.events.AttributeChangeEvent.prototype.getNewValue = function() {
+	return this._newValue;
+}
+
+/**
+ * Set the new value of the attribute.  It is only valid to set
+ * the attribute value if the event is passed to you in the
+ * beforeAttributeChange() call.  If the event was passed to
+ * you in the onAttributeChange() call then setting the value
+ * will cause an UnsupportedOperationException to be thrown.
+ * 
+ * Calling this method in the beforeAttributeRemoval() and
+ * onAttributeRemoval() will have no effect.
+ * 
+ * @param value The new value of the attribute.
+ * @exception UnsupportedOperationException if the attribute value
+ * has already been accepted by all attribute listeners.
+ */
+xap.xml.dom.events.AttributeChangeEvent.prototype.setNewValue = function( value ) {
+	if ( value == null ) {
+		// TODO - internationalize
+		throw new xap.util.Exception
+			("Can't set the attribute value as null");
+	}
+	var elementValue = this.getSourceElement().getAttribute( this.getName() );
+	if ( elementValue != null && elementValue != this._oldValue ) {
+		// TODO - internationalize
+		throw new xap.util.Exception
+			("You may only change the new value of attributes " +
+			"before the change has been committed (accepted by " +
+			"all registered xap.xml.dom.events.AttributeChangeListener objects)");
+	}
+	if ( this._newValue != null && this._newValue == this._oldValue ) {  
+		// TODO - 
+		// 
+		// This may need an UnsupportedOperationException if 
+		// the value has already been accepted by the listeners.
+		// This is a boundary case, it means that the new value
+		// has been set the same as the old value.  IIF this
+		// call has been made after all the acceptAttributeChange()
+		// calls have been made, then it should throw an exception.
+		// However, there is no way to know since the new value
+		// and the old value are the same.
+		//
+		// Consider adding a package protected method that sets the
+		// new value as immutable.
+    }
+	this._newValue = value;
+}
+
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+//Let Dojo know what to expect from this file:
+Xap.provide('xap.xml.dom.events.AttributeChangeListener'); 
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.events.ChangeRejectedException");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.events.AttributeChangeEvent");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.XapElement");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.Document");
+
+ 
+ /**
+ * @fileoverview A listener that is notified of XML attribute changes.
+ * @author ikaplansky
+ * @author jmargaris
+ */
+
+/**
+ * @class xap.xml.dom.events.AttributeChangeListener is notified of changes to
+ * XML element attributes. Listeners may be added to individual xap.xml.dom.XapElement objects 
+ * or on the xap.xml.dom.Document as a whole.  They are ordered and will be called in the 
+ * order in which they were registered.  Listeners registered at the xap.xml.dom.Document 
+ * level will be called before listeners registered at the xap.xml.dom.XapElement level.
+ * Objects that wish to listen for attribute changes should either
+ * extend this object or implement that same method names.
+ *
+ * @see xap.xml.dom.XapElement#addAttributeChangeListener
+ * @see xap.xml.dom.XapElement#removeAttributeChangeListener
+ * @see xap.xml.dom.Document#addAttributeChangeListener
+ * @see xap.xml.dom.Document#removeAttributeChangeListener
+ */
+
+
+//-----------------------------------------------------------------------
+// Constructors.
+//-----------------------------------------------------------------------
+xap.xml.dom.events.AttributeChangeListener = function(){}
+
+
+//-----------------------------------------------------------------------
+// Public Methods.
+//-----------------------------------------------------------------------
+
+/**
+ * This method is called after Element.setAttribute() is called, but 
+ * before the value is actually changed.  Listeners have the opportunity
+ * to modify the new value or reject the change.  Modifying the value
+ * will NOT fire a new event.  The value is modified and the new value
+ * is passed to subsequent listeners beforeAttributeChange() methods for
+ * their review.  Should they decide to modify it, the final value will
+ * reflect their changes too.
+ * 
+ * @param event The xap.xml.dom.events.AttributeChangeEvent representing the change.
+ * @exception xap.xml.dom.events.ChangeRejectedException Implementors may throw this 
+ * if they wish to provide a reason that they rejected the change
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.events.ChangeRejectedException");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.events.AttributeChangeEvent");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.XapElement");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.Document");
+
+ * in the exception message.
+ */
+xap.xml.dom.events.AttributeChangeListener.prototype.beforeAttributeSet = function( event ) {}
+
+/**
+ * This method is called after Element.setAttribute() and after all
+ * listeners have accepted the change.  The underlying value of the
+ * attribute on the Element object has already been changed.
+ * Listeners may not modify the value or reject the change.
+ * 
+ * @param event The xap.xml.dom.events.AttributeChangeEvent representing the change.
+ */
+xap.xml.dom.events.AttributeChangeListener.prototype.onAttributeSet = function( event ){}
+
+
+/**
+ * This method is called after Element.removeAttribute() is called,
+ * but before the attribute is actually removed.  Listeners have
+ * the opportunity to reject the removal by throwing a 
+ * xap.xml.dom.events.ChangeRejectedException.
+ *
+ * @param event The xap.xml.dom.events.AttributeChangeEvent representing the change.
+ * @exception xap.xml.dom.events.ChangeRejectedException thrown to reject the remove.
+ */
+xap.xml.dom.events.AttributeChangeListener.prototype.beforeAttributeRemoved = function( event ){}
+
+/**
+ * This method is called after Element.removeAttribute() is called
+ * and after all listeners have accepted the removal.  When this
+ * method is called the attribute has already been removed from
+ * the element.
+ *
+ * @param event The xap.xml.dom.events.AttributeChangeEvent representing the remove.
+ */
+xap.xml.dom.events.AttributeChangeListener.prototype.onAttributeRemoved = function( event ){}
+
+
+/*
+ * Copyright  2006 The Apache Software Foundation.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+//Let Dojo know what to expect from this file:
+Xap.provide('xap.xml.dom.events.ChangeRejectedException'); 
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.events.StructureChangeListener");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.events.DomChangeEvent");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.events.AttributeChangeListener");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.xml.dom.Document");
+
+// Auto-added---o.k.?
+//ExperimentXap.require("xap.util.XapException");
+
+ 
+ /**
+ * @fileoverview An exception indicating a DOM attribute or structure
+ * change was rejected.
+ * 
+ * @author ikaplansky
+ * @author jmargaris
+ * 
+ * 
+ * @class This is thrown from by {@link xap.xml.dom.events.AttributeChangeListener} and {@link
+ * xap.xml.dom.events.StructureChangeListener} "before" methods.  Consequently, they are thrown
+ * by many of the DOM API methods.  When thrown, it signals that the operation
+ * being performed on the xap.xml.dom.Document was rejected by one of the event listeners.
+ */
+xap.xml.dom.events.ChangeRejectedException = function( msgId, args, cause, event ) {
+    xap.util.XapException.call( this, msgId, args, cause );
+    this._event = event;
+}
+xap.xml.dom.events.ChangeRejectedException.prototype = new xap.util.XapException;
+
+//-----------------------------------------------------------------------
+// Constants.
+//-----------------------------------------------------------------------
+xap.xml.dom.events.ChangeRejectedException.CLASSNAME = "xap.xml.dom.events.ChangeRejectedException";
+xap.xml.dom.events.ChangeRejectedException.CHANGE_ATTRIBUTE_TO_NULL_MSGID = "listenerChangedAttributeToNull";
+xap.xml.dom.events.ChangeRejectedException.CHANGE_CHILD_TO_NULL_MSGID = "listenerChangedChildToNull";
+xap.xml.dom.events.ChangeRejectedException.REJECTED_WITH_REASON_MSGID = "rejectedWithReason";
+xap.xml.dom.events.ChangeRejectedException.ROOT_NODE_CHANGE_DISALLOWED_MSGID = "rootNodeChangeDisallowed";
+
+
+//-----------------------------------------------------------------------
+// Public Methods.
+//-----------------------------------------------------------------------
+
+/**
+ * Returns the <code>xap.xml.dom.events.DomChangeEvent</code> that was rejected.
+ */
+xap.xml.dom.events.ChangeRejectedException.prototype.getEvent = function() {
+    return this._event;
+}
+
+xap.xml.dom.events.ChangeRejectedException.prototype.getClassName = function() {
+	return xap.xml.dom.events.ChangeRejectedException.CLASSNAME;
+}
+
+
+if(!this["dojo"]){
+	alert("\"dojo/__package__.js\" is now located at \"dojo/dojo.js\". Please update your includes accordingly");
+}
+
+// Copyright 2005 Google Inc.
+// All Rights Reserved
+//
+// Miscellania that support the ajaxslt implementation.
+//
+// Author: Steffen Meschkat <me...@google.com>
+//
+
+Xap.provide("google.misc");
+
+
+with (google){
+	// Returns the text value if a node; for nodes without children this
+	// is the nodeValue, for nodes with children this is the concatenation
+	// of the value of all children.
+	google.xmlValue = function(node) {
+	  if (!node) {
+	    return '';
+	  }
+	
+	  var ret = '';
+	  if (node.nodeType == DOM_TEXT_NODE ||
+	      node.nodeType == DOM_CDATA_SECTION_NODE ||
+	      node.nodeType == DOM_ATTRIBUTE_NODE) {
+	    ret += node.nodeValue;
+	
+	  } else if (node.nodeType == DOM_ELEMENT_NODE ||
+	             node.nodeType == DOM_DOCUMENT_NODE ||
+	             node.nodeType == DOM_DOCUMENT_FRAGMENT_NODE) {
+	    for (var i = 0; i < node.childNodes.length; ++i) {
+	      ret += arguments.callee(node.childNodes[i]);
+	    }
+	  }
+	  return ret;
+	}
+	
+	// Returns the representation of a node as XML text.
+	google.xmlText  =function(node) {
+	  var ret = '';
+	  if (node.nodeType == DOM_TEXT_NODE) {
+	    ret += xmlEscapeText(node.nodeValue);
+	    
+	  } else if (node.nodeType == DOM_ELEMENT_NODE) {
+	    ret += '<' + node.nodeName;
+	    for (var i = 0; i < node.attributes.length; ++i) {
+	      var a = node.attributes[i];
+	      if (a && a.nodeName && a.nodeValue) {
+	        ret += ' ' + a.nodeName;
+	        ret += '="' + xmlEscapeAttr(a.nodeValue) + '"';
+	      }
+	    }
+	
+	    if (node.childNodes.length == 0) {
+	      ret += '/>';
+	
+	    } else {
+	      ret += '>';
+	      for (var i = 0; i < node.childNodes.length; ++i) {
+	        ret += arguments.callee(node.childNodes[i]);
+	      }
+	      ret += '</' + node.nodeName + '>';
+	    }
+	    
+	  } else if (node.nodeType == DOM_DOCUMENT_NODE || 
+	             node.nodeType == DOM_DOCUMENT_FRAGMENT_NODE) {
+	    for (var i = 0; i < node.childNodes.length; ++i) {
+	      ret += arguments.callee(node.childNodes[i]);
+	    }
+	  }
+	  
+	  return ret;
+	}
+	
+	// Applies the given function to each element of the array.
+	google.mapExec = function(array, func) {
+	  for (var i = 0; i < array.length; ++i) {
+	    func(array[i]);
+	  }
+	}
+	
+	// Returns an array that contains the return value of the given
+	// function applied to every element of the input array.
+	google.mapExpr = function(array, func) {
+	  var ret = [];
+	  for (var i = 0; i < array.length; ++i) {
+	    ret.push(func(array[i]));
+	  }
+	  return ret;
+	};
+	
+	// Reverses the given array in place.
+	google.reverseInplace = function(array) {
+	  for (var i = 0; i < array.length / 2; ++i) {
+	    var h = array[i];
+	    var ii = array.length - i - 1;
+	    array[i] = array[ii];
+	    array[ii] = h;
+	  }
+	}
+	
+	// Shallow-copies an array.
+	google.copyArray = function(dst, src) { 
+	  for (var i = 0; i < src.length; ++i) {
+	    dst.push(src[i]);
+	  }
+	}
+	
+	google.assert = function(b) {
+	  if (!b) {
+	    throw 'assertion failed';
+	  }
+	}
+	
+	
+	// Based on
+	// <http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247>
+	google.DOM_ELEMENT_NODE = 1;
+	google.DOM_ATTRIBUTE_NODE = 2;
+	google.DOM_TEXT_NODE = 3;
+	google.DOM_CDATA_SECTION_NODE = 4;
+	google.DOM_ENTITY_REFERENCE_NODE = 5;
+	google.DOM_ENTITY_NODE = 6;
+	google.DOM_PROCESSING_INSTRUCTION_NODE = 7;
+	google.DOM_COMMENT_NODE = 8;
+	google.DOM_DOCUMENT_NODE = 9;
+	google.DOM_DOCUMENT_TYPE_NODE = 10;
+	google.DOM_DOCUMENT_FRAGMENT_NODE = 11;
+	google.DOM_NOTATION_NODE = 12;
+	
+	
+	google.xpathdebug = false; // trace xpath parsing
+	google.xsltdebug = false; // trace xslt processing
+	
+	
+	// Escape XML special markup chracters: tag delimiter < > and entity
+	// reference start delimiter &. The escaped string can be used in XML
+	// text portions (i.e. between tags).
+	google.xmlEscapeText = function(s) {
+	  return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+	}
+	
+	// Escape XML special markup characters: tag delimiter < > entity
+	// reference start delimiter & and quotes ". The escaped string can be
+	// used in double quoted XML attribute value portions (i.e. in
+	// attributes within start tags).
+	google.xmlEscapeAttr = function(s) {
+	  return xmlEscapeText(s).replace(/\"/g, '&quot;');
+	}
+	
+	// Escape markup in XML text, but don't touch entity references. The
+	// escaped string can be used as XML text (i.e. between tags).
+	google.xmlEscapeTags = function(s) {
+	  return s.replace(/</g, '&lt;').replace(/>/g, '&gt;');
+	}
+	
+	// An implementation of the debug log. 
+	
+	google.logging__ = true;
+	
+	google.Log = function() {};
+	
+	Log.lines = [];
+	
+	Log.write = function(s) {
+	  if (logging__) {
+	    this.lines.push(xmlEscapeText(s));
+	    this.show();
+	  }
+	};
+	
+	// Writes the given XML with every tag on a new line.
+	Log.writeXML = function(xml) {
+	  if (logging__) {
+	    var s0 = xml.replace(/</g, '\n<');
+	    var s1 = xmlEscapeText(s0);
+	    var s2 = s1.replace(/\s*\n(\s|\n)*/g, '<br/>');
+	    this.lines.push(s2);
+	    this.show();
+	  }
+	}
+	
+	// Writes without any escaping
+	Log.writeRaw = function(s) {
+	  if (logging__) {
+	    this.lines.push(s);
+	    this.show();
+	  }
+	}
+	
+	Log.clear = function() {
+	  if (logging__) {
+	    var l = this.div();
+	    l.innerHTML = '';
+	    this.lines = [];
+	  }
+	}
+	
+	Log.show = function() {
+	  var l = this.div();
+	  l.innerHTML += this.lines.join('<br/>') + '<br/>';
+	  this.lines = [];
+	  l.scrollTop = l.scrollHeight;
+	}
+	
+	Log.div = function() {
+	  var l = document.getElementById('log');
+	  if (!l) {
+	    l = document.createElement('div');
+	    l.id = 'log';
+	    l.style.position = 'absolute';
+	    l.style.right = '5px';
+	    l.style.top = '5px';
+	    l.style.width = '250px';
+	    l.style.height = '150px';
+	    l.style.overflow = 'auto';
+	    l.style.backgroundColor = '#f0f0f0';
+	    l.style.border = '1px solid gray';
+	    l.style.fontSize = '10px';
+	    l.style.padding = '5px';
+	    document.body.appendChild(l);
+	  }
+	  return l;
+	}
+
+}
+// Copyright 2005 Google Inc.
+// All Rights Reserved
+//
+// An XML parse and a minimal DOM implementation that just supportes
+// the subset of the W3C DOM that is used in the XSLT implementation.
+//
+// References: 
+//
+// [DOM] W3C DOM Level 3 Core Specification
+//       <http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/>.
+//
+// 
+// Author: Steffen Meschkat <me...@google.com>
+
+Xap.provide("google.dom");
+//ExperimentXap.require("google.misc");
+
+
+
+// Our W3C DOM Node implementation. Note we call it google.XNode because we
+// can't define the identifier Node. We do this mostly for Opera,
+// where we can't reuse the HTML DOM for parsing our own XML, and for
+// Safari, where it is too expensive to have the template processor
+// operate on native DOM nodes.
+google.XNode = function(type, name, value, owner) {
+  this.attributes = [];
+  this.childNodes = [];
+
+  google.XNode.init.call(this, type, name, value, owner);
+}
+
+
+with (google){
+	// Don't call as method, use apply() or call().
+	XNode.init = function(type, name, value, owner) {
+	  this.nodeType = type - 0;
+	  this.nodeName = '' + name;
+	  this.nodeValue = '' + value;
+	  this.ownerDocument = owner;
+	
+	  this.firstChild = null;
+	  this.lastChild = null;
+	  this.nextSibling = null;
+	  this.previousSibling = null;
+	  this.parentNode = null;
+	}
+	
+	
+	XNode.unused_ = [];
+	
+	XNode.recycle = function(node) {
+	  if (!node) {
+	    return;
+	  }
+	
+	  if (node.constructor == google.XDocument) {
+	    XNode.recycle(node.documentElement);
+	    return;
+	  }
+	
+	  if (node.constructor != this) {
+	    return;
+	  }
+	
+	  XNode.unused_.push(node);
+	  for (var a = 0; a < node.attributes.length; ++a) {
+	    XNode.recycle(node.attributes[a]);
+	  }
+	  for (var c = 0; c < node.childNodes.length; ++c) {
+	    XNode.recycle(node.childNodes[c]);
+	  }
+	  node.attributes.length = 0;
+	  node.childNodes.length = 0;
+	  XNode.init.call(node, 0, '', '', null);
+	}
+	
+	
+	
+	XNode.create = function(type, name, value, owner) {
+	  if (XNode.unused_.length > 0) {
+	    var node = XNode.unused_.pop();
+	    XNode.init.call(node, type, name, value, owner);
+	    return node;
+	  } else {
+	    return new XNode(type, name, value, owner);
+	  }
+	}
+	
+	XNode.prototype.appendChild = function(node) {
+	  // firstChild
+	  if (this.childNodes.length == 0) {
+	    this.firstChild = node;
+	  }
+	
+	  // previousSibling
+	  node.previousSibling = this.lastChild;
+	
+	  // nextSibling
+	  node.nextSibling = null;
+	  if (this.lastChild) {
+	    this.lastChild.nextSibling = node;
+	  }
+	
+	  // parentNode
+	  node.parentNode = this;
+	
+	  // lastChild
+	  this.lastChild = node;
+	
+	  // childNodes
+	  this.childNodes.push(node);
+	}
+	
+	
+	
+	
+	XNode.prototype.replaceChild = function(newNode, oldNode) {
+	  if (oldNode == newNode) {
+	    return;
+	  }
+	
+	  for (var i = 0; i < this.childNodes.length; ++i) {
+	    if (this.childNodes[i] == oldNode) {
+	      this.childNodes[i] = newNode;
+	      
+	      var p = oldNode.parentNode;
+	      oldNode.parentNode = null;
+	      newNode.parentNode = p;
+	      
+	      p = oldNode.previousSibling;
+	      oldNode.previousSibling = null;
+	      newNode.previousSibling = p;
+	      if (newNode.previousSibling) {
+	        newNode.previousSibling.nextSibling = newNode;
+	      }
+	      
+	      p = oldNode.nextSibling;
+	      oldNode.nextSibling = null;
+	      newNode.nextSibling = p;
+	      if (newNode.nextSibling) {
+	        newNode.nextSibling.previousSibling = newNode;
+	      }
+	
+	      if (this.firstChild == oldNode) {
+	        this.firstChild = newNode;
+	      }
+	
+	      if (this.lastChild == oldNode) {
+	        this.lastChild = newNode;
+	      }
+	
+	      break;
+	    }
+	  }
+	}
+	
+	XNode.prototype.insertBefore = function(newNode, oldNode) {
+	  if (oldNode == newNode) {
+	    return;
+	  }
+	
+	  if (oldNode.parentNode != this) {
+	    return;
+	  }
+	
+	  if (newNode.parentNode) {
+	    newNode.parentNode.removeChild(newNode);
+	  }
+	
+	  var newChildren = [];
+	  for (var i = 0; i < this.childNodes.length; ++i) {
+	    var c = this.childNodes[i];
+	    if (c == oldNode) {
+	      newChildren.push(newNode);
+	
+	      newNode.parentNode = this;
+	
+	      newNode.previousSibling = oldNode.previousSibling;
+	      oldNode.previousSibling = newNode;
+	      if (newNode.previousSibling) {
+	        newNode.previousSibling.nextSibling = newNode;
+	      }
+	      
+	      newNode.nextSibling = oldNode;
+	
+	      if (this.firstChild == oldNode) {
+	        this.firstChild = newNode;
+	      }
+	    }
+	    newChildren.push(c);
+	  }
+	  this.childNodes = newChildren;
+	}
+	

[... 24922 lines stripped ...]