<!-- ********************************** -->
<!-- *		Scripts for the Home page		* -->
<!-- ********************************** -->
var mainWindow = window;
var _agt;					//AgentInfo.htc
var _askedAboutClosing = false;				//Set when user confirms he wants to log out
var _currentAlbum = "";								//Name of current album used to save reports
var _currentSnapshot = "";						//Name of current snapshot in album
var _dashboardWindow;									//Window containing dashboard
var _lastErrorMessage= "";						//Used to pass error messages from routines
var _latestWindow;										//Last window we created
var _loginAlgorithm;									//Used for password help
var _photoURLArray;										//Number of photos allowed by resource
var _searchCriteriaArray = new Array();			//List of searches we have run
var _trustedSite = false;										//Is this a trusted site?
var validationTables = new Array();		//List of tables we have loaded
var _updateSets = new Array();				//List of update sets we have loaded
var _valetParking = new ActiveXObject('MSXML2.DOMDocument');		//List of recent searches
var _valetParkingMax = 20;

var _fso;															//File system Object

/**************************************************
*			Load marketwatch XML structure.  If it is		*
*			already loaded, we do not load it again 		*
*			unless the forceLoad flag is true.					*
**************************************************/
function getMarketWatchList(forceLoad)
{
	if (_agt.offlineflag) return "You cannot look at Market Watch schedules when you are off line";
	if (!forceLoad)
	{
		if (marketwatch.status) return "";
	}

	var uri = _agt.getUrl("MARKETWATCH", true);
	marketwatch.agt = _agt;
	marketwatch.load("GET", uri, false);
	if (marketwatch.status) return "";
	var txt = marketwatch.statustext;
	marketwatch.xmlobject.loadXML("<MWLIST/>");
	marketwatch.status = false;
	marketwatch.statustext = txt;
	return txt;
}



/*********************************************************
*     Check to see if we are a trusted site.
*			We will check to see if setting the src to a local file 
* 		triggers an event.  It does not in IE7 when the site is 
*     not trusted
* 	  Be sure to recheck this for IE8.
*     i am not sure what to do for other browsers.
*********************************************************/	
var checkTrustedSite = {
	
	'value': false,
	
	'init': function ()	{

		if ($type(window._trustedSite) == false) window._trustedSite = false;
		

		// If we are running IE6, then I don't know how to check for trusted sites in ie6
		// The code windows.ie6 is specific to mootools 1.11.  when we change to version 1.12, this code will 
		// have to change
		if(window.ie6) return;


		// check using the window status method.
		if(1==1)
		{ 
			// Try to change the window status bar
			// If it changes the the user (probably) has this site set as a trusted site
			// They could also have changed the "allow status bar updates via script" security setting
		  var originalStatus = window.status;
		  if (!originalStatus) originalStatus = "";
		  window.status="trusted site";
			if (window.status == "trusted site") 
			{
				window.status=originalStatus;
				checkTrustedSite.value = true;
				_trustedSite = true;
			}
		}
		else
		{
			// Set the image source to a local file.
			// in ie7 the onerror event will trigger if the site is trusted  
			var el = new Element("img", {'id':'trustedcheckimg',
							                     'src':'file://c:/temp/trustcheck.jpg',
																	 'events': { 'load': function(){ checkTrustedSite.trustcheck(true); },
																	             'error': function(){checkTrustedSite.trustcheck(false); } }} )
														.setStyle('display', 'none').inject(document.body);
			
			setTimeout("checkTrustedSite.cleanup()", "15000");
		}
	},
	
	'trustcheck': function (){
		checkTrustedSite.value = true;
		_trustedSite = true;
	},
		
	'cleanup': function (){
		var el = $('trustedcheckimg');
		if (el) el.remove();
	}
}




/**************************************************
*			Called when homepage is first loaded				*
**************************************************/
function Init()
{

	_valetParking.loadXML("<RECENTSEARCHES/>");
	checkTrustedSite.init();

	if (document.cookie.length > 0)
	{
		//valetConfirm("You are already running a copy of Vision on this computer");
		//return window.close();
	}
	//document.cookie = "ValetHost=empty; expires=Fri, 31 Dec 1999 23:59:59 GMT; path=/;";			//This is supposed to delete any cookie we might have
	
	windows.initwindow("default");
	_agt = document.getElementById("agt");

	_agt.configurationoptions = "../configurations.xml";
	if (dashboardFormat.XMLDocument.parseError.errorCode) 
		return alert("The XSL file " + dashboardFormat.src + " did not parse correctly" +
			"\r\nerror code="+dashboardFormat.XMLDocument.parseError.errorCode +
			"\r\n" + dashboardFormat.XMLDocument.parseError.reason +
			"\r\nLine=" + dashboardFormat.XMLDocument.parseError.line +
			"\r\n" + dashboardFormat.XMLDocument.parseError.srcText.replace(/^\s*/, ""));

	var lNode = loginObject.selectSingleNode("LOGIN");
	lNode.setAttribute("format", "login");
	displayArea.innerHTML = lNode.transformNode(dashboardFormat.XMLDocument);

	if (displayArea.childNodes.length)
	{
		w = displayArea.childNodes[0].width;
		if (!w) w = displayArea.childNodes[0].style.pixelWidth;
		h = displayArea.childNodes[0].height;
		if (!h) h = displayArea.childNodes[0].style.pixelHeight;
		//if ((w) && (h)) window.resizeTo(w+20, h+110);
	}
	
	loginInit();
}

/**************************************************
*	 This is intented for the photos in the         *
*  page header but should work for other photos.  *
*  It will read a couple of non-stardard          *
*  max height/width properties from the img tag   *
*  and reduce the img if the size is too big.     *
**************************************************/
function resizeImage(obj)
{
	var img = $(obj);
	if (img)
	{
		var maxH = img.getProperty("maxheight");
		var maxW = img.getProperty("maxwidth");

		var tImg = new Element('img', { 'src':img.getAttribute("src") } );
		var imgH = tImg.getProperty("height")
		var imgW = tImg.getProperty("width")
//debugIf('armo3agent');

		if (!maxH) maxH = 999999;
		if (!maxW) maxW = 999999;
		
		if (imgW > maxW || imgH > maxH) 
		{ 
		  var pw = imgW / maxW;
		  var ph = imgH / maxH;

			if (pw > ph)
					img.setStyles({ 'width': maxW, 'height':'' }).removeProperty("height"); 
				else
					img.setStyles({ 'height': maxH, 'width':'' }).removeProperty("width"); 
		}
	}
}


/**********************************
*			Save search permanently			*
*		If we cannot save the search,	*
*		set _lastErrorMessage and			*
*		return "false".  Otherwise,		*
*		return "true".								*
**********************************/
function saveSearch(node)
{
	var track = "line 72";
	try
	{
		var resource = node.selectSingleNode("RESOURCE").text;
		var id = node.getAttribute("id");
		var lvl = node.getAttribute("savelevel");
		
		/****************************************
		*		Remove it from our existing list		*
		****************************************/
		var mNode = searchlist.xmlobject.selectSingleNode("//SEARCHLIST");
		var sNode = mNode.selectSingleNode(".//SEARCH[@id $ieq$ '" + id + "' and @savelevel $ieq$ '" + lvl + "']");
		if (sNode) mNode.removeChild(sNode);
		
		/****************************************
		*		Get the new search ready to save		*
		****************************************/
		var searchDom = new ActiveXObject('MSXML2.DOMDocument');
		searchDom.async=false;
		searchDom.loadXML(node.xml);
		if (searchDom.parseError.errorCode)
		{
			_lastErrorMessage = searchDom.parseError.errorCode + "\n" + searchDom.parseError.reason +
				"\nLine number=" + searchDom.parseError.line +
				"\nFile position=" + searchDom.parseError.filepos +
				"\n" + searchDom.parseError.srcText;
			return false;
		}
		var searchNode = searchDom.selectSingleNode("//SEARCH");
		if (lvl != "Agent")
		{
			searchNode.removeAttribute("mwagent");
			searchNode.removeAttribute("mwclient");
			searchNode.removeAttribute("mwlogin");
			searchNode.removeAttribute("mwtext");
		}
		
		track = "line 108";
		sNode = searchNode.selectSingleNode("DATETIME");
		if (!sNode)
		{
			sNode = searchDom.createNode(1, "DATETIME", "");
			searchNode.appendChild(sNode);
		}

		sNode.text = dateToText(textToDate("UTC"), "ISO");
		var newNode = searchNode.cloneNode("true");
		mNode.appendChild(newNode);				//append to accumulated list
		
		var uri;
		if (!_agt.remote)
		{
			/**********************************************
			*			Save it to the appropriate local file		*
			**********************************************/
			uri = _agt.getOwnerDirectory(lvl, "private") + "/searchlist.xml";
			extra.agt = _agt;
			extra.statusnode = false;				//Do not do XML status check
			extra.load("GET", uri, false);
			if (!extra.status)
			{
				extra.xmlobject.loadXML('<SEARCHLIST xmlns="x-schema:searchlistSchema.xml" xmlns:vds="www.valetmls.com"/>');
				extra.status = true;
			}
	
			mNode = extra.xmlobject.selectSingleNode("//SEARCHLIST");
			sNode = mNode.selectSingleNode(".//SEARCH[@id $ieq$ '" + id + "' and @savelevel $ieq$ '" + lvl + "']");
			if (sNode) mNode.removeChild(sNode);
			
			mNode.appendChild(newNode.cloneNode(true));
			if (extra.checkForDirectory(uri)) 
			{
				extra.xmlobject.save(uri);
			}
			if (!extra.status) 
			{
				_lastErrorMessage = extra.errorMessage("Unable to save the file " + uri, "<br/>");
				return false;
			}
		}

		if (!_agt.offlineflag)
		{
			/**********************************************
			*			Save it to the appropriate server file	*
			*			Start by getting the current copy.			*
			**********************************************/
			track = "line 153";
			uri = _agt.valetDirectoryURL(lvl, "private", "read", "/searchlist.xml");
			extra.agt = _agt;
			extra.statusnode = false;				//Do not do XML status check
			track = "line 157";
			extra.load("GET", uri, false);
			track = "line 159, status=" + extra.status;
			if (!extra.status)
			{
				extra.xmlobject.loadXML('<SEARCHLIST xmlns="x-schema:searchlistSchema.xml" xmlns:vds="www.valetmls.com"/>');
				extra.status = true;
			}
			track = "line 165, extra contains "+extra.xmlobject.xml;
			
			/**********************************************
			*			Add (or replace) this search						*
			**********************************************/
			mNode = extra.xmlobject.selectSingleNode("//SEARCHLIST");
			sNode = mNode.selectSingleNode(".//SEARCH[@id $ieq$ '" + id + "' and @savelevel $ieq$ '" + lvl + "']");
			if (sNode) mNode.removeChild(sNode);			
			track = "line 173";
			mNode.appendChild(newNode.cloneNode(true));

			/**********************************************
			*			Post the search to the host							*
			**********************************************/
			track = "Attempting to post searchlist.xml to host";
			uri = _agt.valetDirectoryURL(lvl, "private", "post", "/searchlist.xml");
			extra.statusnode = true;
			extra.vdsobj.createObject(uri);				//Be sure the httpobj object exists
			extra.vdsobj.setRequestHeader("Content-Type", "application/upload");
			extra.postText(uri, extra.xmlobject.xml, false);
			if (!extra.status)
			{
				_lastErrorMessage = extra.errorMessage("Unable to save the file " + uri, "<br/>");
				return false;
			}
		}
	}

	catch(err)
	{
		_lastErrorMessage = "Failed to save search :\n" + track + "\r\n" + err;
		return false;
	}
	return true;
	
}

/******************************************
*			User has asked to delete a saved
*			search.  We have to delete it from	
*
*			The searchlist.xml structure in memory
*			The searchlist.xml file (saved by hierarchy level)
*			Market watch (if level=agent)
***************************************************************/
function deleteSearch(node)
{
	try
	{
		var id = node.getAttribute("id");
		var lvl = node.getAttribute("savelevel");
		var track = "Begin search delete";
		
		/****************************************
		*			Find this seach in our list				*
		****************************************/
		var mNode = searchlist.xmlobject.selectSingleNode("//SEARCHLIST");
		var sNode = mNode.selectSingleNode(".//SEARCH[@id $ieq$ '" + id + "' and @savelevel $ieq$ '" + lvl + "']");
		if (sNode)
		{


			/****************************************
			*		If this is an market watch search,	*
			*		we have to delete the schedules too.*
			****************************************/
			if ((sNode.getAttribute("mwagent") == "yes") |
					(sNode.getAttribute("mwclient") == "yes") |
					(sNode.getAttribute("mwlogin") == "yes") |
					(sNode.getAttribute("mwtext") == "yes"))
			{
				if (agt.offlineflag)
				{
					_lastErrorMessage = "This search has a market watch schedule." +
								"\nYou may not delete it while in offline mode.";
					return false;
				}
				track += "\nPast offlineflag check";


				if (!deleteMarketWatch(sNode)) return false;
				track += "\nPast deleteMarketWatch";
			}

			/****************************************
			*		Remove it from our existing list		*
			****************************************/
			track += "\nRemoving node from accumulated searchlist";
			mNode.removeChild(sNode);


			/****************************************
			*		Remove it from the appropriate file	*
			****************************************/
			var uri;
			var topNode;
			if (!agt.remote)
			{
				uri = agt.getOwnerDirectory(lvl, "private") + "/searchlist.xml";
				extra.agt = agt;
				extra.load("GET", uri, false);
				if (extra.status)
				{
					mNode = extra.xmlobject.selectSingleNode("//SEARCHLIST");
					sNode = mNode.selectSingleNode(".//SEARCH[@id $ieq$ '" + id + "' and @savelevel $ieq$ '" + lvl + "']");
					if (sNode) mNode.removeChild(sNode);
					extra.xmlobject.save(uri);
				}			
			}	
			else
			{
				/**********************************************
				*			Delete it from the appropriate server file	*
				*			Start by getting the current copy.			*
				**********************************************/
				uri = _agt.valetDirectoryURL(lvl, "private", "read", "/searchlist.xml");
				extra.agt = _agt;
				extra.statusnode = false;				//Do not do XML status check
				extra.load("GET", uri, false);
				if (!extra.status)
				{
					_lastErrorMessage = extra.errorMessage("Unable to retrieve original value of searches " + uri, "<br/>");
					return false;
				}
				
				/**********************************************
				*			Remove this search						*
				**********************************************/
				mNode = extra.xmlobject.selectSingleNode("//SEARCHLIST");
				sNode = mNode.selectSingleNode(".//SEARCH[@id $ieq$ '" + id + "' and @savelevel $ieq$ '" + lvl + "']");
				if (sNode) mNode.removeChild(sNode);			
	
				/**********************************************
				*			Post the search to the host							*
				**********************************************/
				uri = _agt.valetDirectoryURL(lvl, "private", "post", "/searchlist.xml");
				extra.statusnode = true;				//Must have <STATUS> node
				extra.postText(uri, extra.xmlobject.xml, false);
				extra.statusnode = false;				//Do not do XML status check
				if (!extra.status)
				{
					_lastErrorMessage = extra.errorMessage("Unable to save the file " + uri, "<br/>");
					return false;
				}
			}
			return true;
		}
		else 
		{
			_lastErrorMessage = "Did not find a search " + id + " at level " + lvl;
			copyToClipboard(mNode.xml, top, "SearchList");
		}
	}
	catch(e)
	{
		_lastErrorMessage = track + "\nFailed to delete search:\n" + e;
	}
	return false;
}

/***************************************
*			Login has completed.
***************************************/
function finishedLogin(userSwitch)
{
	if (!userSwitch)
	{
		if (!loginComplete()) return;						//Save settings
		
		/******************************************
		*		If running in desktop mode, create
		*		the ActveX objects we will need.
		******************************************/
		if (!_agt.remote)
		{
			_fso = new ActiveXObject("Scripting.FileSystemObject");
		}
	
		/******************************************************
		*				Load structures we may need right away
		******************************************************/
		messagelist.agt = agt;
		messagelist.readHierarchyFile("MESSAGES.XML", false);
		//messagelist.readSetupFile("MESSAGES.XML");
		
		if (!messagelist.status) messagelist.loadXML("<MESSAGES/>");	

	
		tasklist.agt = agt;
		tasklist.readHierarchyFile("TASKLIST.XML", false);
		//tasklist.readSetupFile("TASKLIST.XML");
		tasklist.errorCheck("Unable to read task list");
	}
	
	var tNodes = tasklist.xmlobject.selectNodes("//*[@mtype]");					//A list of all nodes
	for (var tt=0; tt<tNodes.length; tt++) tNodes[tt].setAttribute("allow", "yes");

	tNodes = tasklist.xmlobject.selectNodes("//PERMISSIONS[.!='']");
	for (var tt=0; tt<tNodes.length; tt++)
	{
		if (!permissionCheck(tNodes[tt].parentNode, _agt.permissions)) tNodes[tt].parentNode.setAttribute("allow", "no");
	}
	tNodes = tasklist.xmlobject.selectNodes("//*[@disabled='yes']");
	for (var tt=0; tt<tNodes.length; tt++) tNodes[tt].setAttribute("allow", "no");

	/******************************************************
	*						Change this screen size if necessary			*
	******************************************************/
	try
	{
		var wNode = agt.preferences.selectSingleNode(".//WINDOWS/@screenSize");
		if (wNode)
		{
			switch (wNode.text.toUpperCase())
			{
				case "SMALL":
					resizeTo(800,600);
					break;
				case "LARGE":
					resizeTo(screen.availWidth-5, screen.availHeight-5);
					moveTo(10,10);
					break;
				default:
					match = wNode.text.match(/(\d*)\:(\d*)/);
					if (match)
					{
						resizeTo(parseInt(match[1],10), parseInt(match[2],10));
					}
					break;			
			}
		}
	}
	catch(err) {}
	//getCurrentAnnouncements();
	
	/******************************************************
	*				Load the other structures											*
	*      ---------------------------------------------  *
	*       Changed SEARCHLIST.XML to not cache becasue   *
	*       so that if someone resets their agent data    *
	*       the old files are not downloaded.             *
	******************************************************/
	exportlist.agt = agt;
	exportlist.readHierarchyFile("EXPORTLIST.XML", false);
	//exportlist.readSetupFile("EXPORTLIST.XML");
	exportlist.errorCheck("Unable to read export list file", _dashboardWindow);
	
//debugIf('armo3agent');
	searchlist.agt = _agt;
	searchlist.readHierarchyFile("SEARCHLIST.XML", true, false);  
	//searchlist.readSetupFile("SEARCHLIST.XML");
	//searchlist.errorCheck("Could not read searchlist.xml", _dashboardWindow);

	reportlist.agt = agt;
	reportlist.readHierarchyFile("REPORTLIST.XML", false);
	//reportlist.readSetupFile("REPORTLIST.XML");
	reportlist.errorCheck("Unable to read report list file", _dashboardWindow);

	hyperlinks.agt = agt;
	hyperlinks.readHierarchyFile("HYPERLINKS.XML", false);
	//hyperlinks.readSetupFile("HYPERLINKS.XML");
	hyperlinks.errorCheck("Unable to read hyperlinks file", _dashboardWindow);

	albums.agt = agt;
	//albums.readHierarchyFile("ALBUMS.XML", false);
	//albums.readSetupFile("ALBUMS.XML");
	//if (!albums.status) albums.loadXML("<ALBUMS/>");
	
	/******************************************************
	*				Display the dashboard													*
	******************************************************/
	var xNode = dashboardFormat.selectSingleNode("//xsl:param[@name='permissions']");
	if (xNode) xNode.text = "," + _agt.permissions.toUpperCase() + ",";
	else alert("Did not find a place in dashboardFormat to insert agent permissions");

	loadDashboard();
	
}
	/************************************************************************
	*				If not already loaded, load the dashboard menu format						*
	************************************************************************/
function loadMenuFormat()
{
	
	if ((!menuFormatXSL.src) || (menuFormatXSL.src.length == 0))
	{
		var txt;
		var ms = _agt.menustyle;
		switch (ms.toUpperCase())
		{
			case "BIGBUTTONS":
				txt ="../bigButtonsMenuFormat.xsl";
				break;
			case "DROPDOWN":
			default:
				txt = "../dropDownMenuFormat.xsl";
				break;
		}
		menuFormatXSL.load("GET", txt, false);
	}
}
function loadDashboard()
{
	if (_ModalDiv == null) initModalDiv();

	loadMenuFormat();

if (document.getElementById("podarea"))
{

	// clear any old data
	$('podarea').empty();
	$('navcontainer').empty();

	loadUserObjects();

  $('displayArea').setStyle("display", "none");
  document.body.className = "pagebackground";

  
  $('headerArea').setStyle("display", "")
  $('footerArea').setStyle("display", "")

	try
	{
	  podTools.loginDataXML = _agt.loginobject.xmlobject;
	  podTools.dashOpts = _agt.loginobject.xmlobject.selectSingleNode("//DASHBOARD");
	  podTools.tranDspArea = $('pendtran_dash');
	}
	catch(err) {alert(err);debugger;}
	// check to see if the user has PODs defined inside of DASHBOARDOPTIONS
	var dNode = _agt.loginobject.xmlobject.selectSingleNode("//LOGIN/DASHBOARD/PODTABS");			//Has this user customized the dashboard?
	if (!dNode) 
	{
		var topNode = _agt.loginobject.xmlobject.selectSingleNode("//LOGIN/DASHBOARD");
		if (!topNode) 
		{
			topNode = _agt.loginobject.xmlobject.selectSingleNode("//LOGIN");
			topNode = topNode.appendChild(topNode.ownerDocument.createElement("DASHBOARD"));
		}
		
		var uri = window.top._agt.valetDirectoryURL("MLS","private", "read", "dashboardoptions.xml");
		window.top.temptran.load("GET", uri, false);

		topNode.appendChild(window.top.temptran.xmlobject.selectSingleNode("//DASHBOARD/PODTABS").cloneNode(true));				//Insert the default dashboard
	}

	/******************************************
	*  If the screen size is less than ####   *
  *  then change all of the wide podtabs    *
  *  to two even columns                    *
  ******************************************/
  if (window.screen.availWidth < 1200 && window.screen.availWidth > 0)
  {
  	var tbList = podTools.dashOpts.selectNodes("//PODTAB[@layout='2B' or @layout='3A']");
  	for (var i=0; i<tbList.length; i++)
  	{
 			var newcol = "0";
  		tbList[i].setAttribute("layout", "2A");
  		for (var c=0; c<tbList[i].childNodes.length; c++)
  		{
  			if (tbList[i].childNodes[c].getAttribute("col") == "3")
  			  tbList[i].childNodes[c].setAttribute("col", (newcol++ % 2) + 1);
  		}
  	}
  	
  	if (tbList.length > 0)
  	{
  		var msg = "We are changing your dashboard format to use two equal columns to better fit " +
  		          "your monitor.";
 		  window.top._ModalDiv.showMessage(msg, 'Automatic Preference Change', 480, 140);
			prefTools.postData.beginDelayedPost();  // save the changes
  	}
  }

  podTools.dspInit(true);

  // if the user preferences says to start our with the header shrunk, then toggle the header.
  if (agt.preference("/PREFERENCES/COMMON/@headersize")=="shrink") podTools.toggleShowHeader(true);
 
  
	setHeaderTogglePos();

//  podTools.setPodAreaMinHeight();

	_dashboardWindow = window;

	//Load any required information (like compliance or unread announcements	    
  checkImportantMessages(false, false);

}
else
{

			
	/************************************************************************
	*				Decide if the user has their own list of dashboard panels.			*
	************************************************************************/
	var dNode = _agt.loginobject.xmlobject.selectSingleNode("//LOGIN/DASHBOARD/PANELS/PANEL");			//Has this user customized the dashboard?
	if (!dNode) 
	{
		var topNode = _agt.loginobject.xmlobject.selectSingleNode("//LOGIN");
		topNode.appendChild(dashboardOptions.selectSingleNode("//DASHBOARD").cloneNode(true));				//Insert the default dashboard
	}
	
	
	/************************************************************************
	*		Add the key values for each consortium level to the XSL template.		*
	************************************************************************/
	var hNode = _agt.loginobject.xmlobject.selectSingleNode("//LOGIN/HIERARCHY");
	if (hNode)
	{
		var cNodes = hNode.selectNodes(".//CONSORTIUMNAME");
		for (var cc=0; cc<cNodes.length; cc++)
		{
			var parentNode = cNodes[cc].parentNode;			//<AGENT>, <OFFICE>, etc.
			var kNode = parentNode.selectSingleNode("KEY");
			if (kNode)
			{
				var keyText = kNode.text.replace(/\s*$/, "");												//Key value (agent id, office id, etc.)
				var paramName = cNodes[cc].text.replace(/\s*$/, "") + "Key";				//Consotrium name + "KEY" (AgentKey, OfficeKey, etc.)
				var paramNode = dashboardFormat.selectSingleNode("//xsl:param[@name='" + paramName + "']");
				if (!paramNode) 
				{
					paramNode = dashboardFormat.createNode(1, "xsl:param", "http://www.w3.org/1999/XSL/Transform");
					paramNode.setAttribute("name") = paramName;
					dashboardFormat.selectSingleNode("xsl:stylesheet").appendChild(paramNode);
				}
				paramNode.text = keyText;					
				kNode.text.replace(/\s*$/, "");
			}
		}
	}
	
	loadUserObjects();			//Reload objects from user preferences into dashboard layout

	/************************************************************************
	*							Launch the dashboard window																*
	************************************************************************/
	if (_agt.loginobject.xmlobject.selectSingleNode("//PREFERENCES/WINDOWS[@multi='false']"))
	{
		rebuildMainPodDisplay();
	}
	else
	{
		genericNewWindow("Dashboard", "dashboard.htm", null, null, null, top);
		_dashboardWindow = _latestWindow.window;
	}
}
}

/************************************************************************
*				Add the values for each Objects in the user preferences.				*
************************************************************************/
function loadUserObjects()
{
//debugIf('armo3agent');	
	var replacedParams = ",";
	var oNodes = _agt.loginobject.xmlobject.selectNodes("//OBJECTS/OBJECT");
	var objectNames = new Array();
	var uris = new Array();
	var owners = new Array();

	/********************************************************
	*			Decide where each of the objects can be found			*
	*			We may have more than one uri for each object			*
	*			if it is saved at multiple levels.								*
	********************************************************/
	for (var oo=0; oo<oNodes.length; oo++)
	{
		var oName = oNodes[oo].getAttribute("name");			//Name of object (e.g. officelogo)
		for (var nn=0; nn<objectNames.length; nn++) if (objectNames[nn] == oName) break;			//We've already identified it
		if (nn >= objectNames.length)
		{
			var idx = objectNames.length;
			objectNames[idx] = oName;
			owners[idx] = oNodes[oo].getAttribute("owner");
			uris[idx] = oNodes[oo].text;

			/***********************************************
			*		If the object is not an agent object,
			*		see if there is an "agent" copy of the 
			*		object (e.g. agent copy of the office logo.
			************************************************/
			if (owners[idx].toUpperCase() != "AGENT")			//Is it "default" or "office"?
			{
				var aNode = _agt.loginobject.xmlobject.selectSingleNode("//OBJECTS/OBJECT[@owner='agent' and @name=\"" + oName + "\"]");		//See if there is an agent copy
				if ((!aNode) || (aNode.text.length == 0))
				{
					if (owners[idx].toUpperCase() == "DEFAULT")				//If this is default, and there is no agent copy, look for the official (e.g. office) copy
					{
						aNode = _agt.loginobject.xmlobject.selectSingleNode("//OBJECTS/OBJECT[@owner != 'default' and @name=\"" + oName + "\"]");
					}
				}
				if ((!aNode) || (aNode.text.length == 0)) aNode = oNodes[oo];
				owners[idx] = aNode.getAttribute("owner");
				uris[idx] = aNode.text;
			}
		}
	}

	/********************************************************
	*				Pick one URI for each object										*
	********************************************************/
	for (var uu=0; uu<uris.length; uu++)
	{
		var objectsRoot = _agt.loginobject.xmlobject.selectSingleNode("//OBJECTS");
		//http://63.121.160.42/GAMLS/ValetDirectories.srf?resource=agent&type=public&option=read&filename=weeks:images/DHWPhoto.jpg
		if (uris[uu].length > 0)
		{
			var paramName = objectNames[uu];
			if (replacedParams.indexOf("," + paramName.toUpperCase() + ",") < 0)			//Have we already loaded this parameter?
			{
				replacedParams += paramName.toUpperCase() + ",";
				var uri = uris[uu];
				var absoluteURI = uri.match(/^\//);
				if (!absoluteURI) absoluteURI = uri.match(/^\.\./);		//added by DHW 4/14/09
				if (!absoluteURI) absoluteURI = uri.match(/^http\:/);
				if (!absoluteURI)			//If reference starts with a "/", it is an absolute reference
				{
					var fileName = uris[uu];
					uri = _agt.valetDirectoryURL(owners[uu],"public", "read", fileName);
				}
				var paramNode = dashboardFormat.selectSingleNode("//xsl:param[@name='" + paramName + "']");
				if (!paramNode) 
				{
					paramNode = dashboardFormat.createNode(1, "xsl:param", "http://www.w3.org/1999/XSL/Transform");
					paramNode.setAttribute("name") = paramName;
					dashboardFormat.selectSingleNode("xsl:stylesheet").appendChild(paramNode);
				}
				paramNode.text = uri;
				objectsRoot.setAttribute(paramName.toUpperCase(), escape(uri));
			}
		}
	}
}

/******************************************
*			Run an item by task id							*
******************************************/
function launchWindowFromTaskId(taskid, callingWindow)
{
	var tNode = tasklist.xmlobject.selectSingleNode("//*[@id=\"" + taskid + "\"]");
	if (!tNode) callingWindow.valetAlert("There is no task with id=" + taskid + " in tasklist.xml");
	
	if (!permissionCheck(tNode, _agt.permissions)) return callingWindow.valetAlert("You do not have permissions to do this");
	if (tNode.getAttribute("disabled") == "yes") return callingWindow.valetAlert("That option is disabled");
	return launchWindowFromTaskNode(tNode, callingWindow);

}
/**************************************************
*				Run an item from the Tasklist.xml list.		*
**************************************************/
function launchWindowFromTaskNode(taskNode, callingWindow)
{
	var target = taskNode.getAttribute("target");
	if ((!target) || (target == "")) target="_blank";
	var dt = new Date();
	var linkid = taskNode.getAttribute("id") + "." + dt.getTime();
	

	/**************************************************
	*				Decide what window to use									*
	**************************************************/
	var targetWindow = null;
	switch(target)
	{
		case "single":
			linkid = taskNode.getAttribute("id")
			if (typeof(podTools) != "undefined") 
			{
				var targetID = taskNode.selectSingleNode(".//@id").text;
				for (var ww=0; ww<mainWindow.windows.list.length; ww++) 
				{
					var windowIdSegs = mainWindow.windows.list[ww].id.split(".");
					if (windowIdSegs[0] == targetID) break;
				}
				if (ww < mainWindow.windows.list.length)
				{
					if (mainWindow.windows.list[ww].window)
					{
						if (mainWindow.windows.list[ww].window.closed) mainWindow.windows.remove(targetID);
						else return mainWindow.windows.list[ww].window.focus();
					}
				}
			}
			break;			

		case "_self":
			targetWindow = window;
			break;

		case "home":
		case "_blank":
		default:
			break;
	}

	/**************************************************
	*				Load the window with the task.						*
	**************************************************/
	switch (taskNode.getAttribute("mtype"))
	{
		case "page":
			if (typeof(podTools) == "undefined") 
			{
				dt = new Date();
				genericNewWindow(linkid, taskNode.selectSingleNode("URL").text,  taskNode, null, "no main window", callingWindow);
			}
			else
			{
				var tasktext = "";
				var windowTitle = taskNode.getAttribute("id");
				var dNode = taskNode.selectSingleNode("MENUTEXT");
				if ((dNode) && (dNode.text.length > 0)) windowTitle = dNode.text;
				var params = 'p1=' + escape(taskNode.selectSingleNode("URL").text);
				params += ';p2=' + escape(windowTitle);
				params += ';p3=' + escape(tasktext);
	
				/**************************************************
				*			If the task id matches a gadget id,					*
				*			we will just add and display the gadget.		*
				**************************************************/
				var gadgetId = taskNode.getAttribute("id");
				var podGadget = podTools.getGadgetDef(gadgetId, true);
				if (podGadget)
				{
					var pod = podTools.findPodById(linkid);			//Is it already running?
					if (!pod) 
					{
						podTools.insertNewPod(null, null, null, gadgetId, linkid, null, true) ;
						podTools.hidePodPrefs(linkid);
					}
					podTools.maximizePod(linkid, true);
				}
				else
				{
					var toolTipNode = taskNode.selectSingleNode("TOOLTIP");
					if (toolTipNode) tasktip = toolTipNode.text;
					genericNewPod("windowpage", linkid, windowTitle, params);
				}
			}
			break;
		case "update":
			if (typeof(podTools) == "undefined") mainWindow.genericNewWindow("Search" + linkid, "updatePage.htm", taskNode, "searchid=" + taskNode.getAttribute("id"), "no main window", callingWindow)	;
			else
			{
				var windowTitle = taskNode.getAttribute("id");
				var dNode = taskNode.selectSingleNode("MENUTEXT");
				if ((dNode) && (dNode.text.length > 0)) windowTitle = dNode.text;
				var params = 'p1=' + escape('updateid=' + taskNode.getAttribute("id"));
				genericNewPod("updateframe", linkid, windowTitle, params, windowTitle);
			}			
			break;
		case "search":
			if (typeof(podTools) == "undefined") mainWindow.genericNewWindow("Search" + linkid, "searchPage.htm", taskNode, "searchid=" + taskNode.getAttribute("id"), "no main window", callingWindow)	;
			else
			{
				var windowTitle = taskNode.getAttribute("id");
				var dNode = taskNode.selectSingleNode("MENUTEXT");
				if ((dNode) && (dNode.text.length > 0)) windowTitle = dNode.text;
				var params = 'p1=' + escape("searchid=" + taskNode.getAttribute("id"));
				genericNewPod("searchframe", linkid, windowTitle, params, windowTitle);
			}			
			break;
		default:
			var uNode = taskNode.selectSingleNode("URL");
			if ((uNode) && (uNode.text.length > 0)) mainWindow.genericNewWindow(linkid, uNode.text, taskNode, "", "no main window", callingWindow)	;
			else mainWindow.genericNewWindow(linkid, "badTaskListEntry.htm", taskNode, "", "no main window", callingWindow)	;
			break;
	}

}

/******************************************************
*				User asked to display page help								*
******************************************************/
function helpWindowByTaskId(tdElement, passedLibraryName, passedLibraryTopic)
{
	var tNode;
	
	var helpLibrary = "valethelp/valethelp.xml";					//Library of last resort
	var helpTopic = "gettingStarted";				//Topic of last resort

	if (passedLibraryName) helpLibrary = passedLibraryName;
	if (passedLibraryTopic) helpTopic = passedLibraryTopic;

	var pObj = new Object();
	pObj.library = helpLibrary;
	pObj.topic = helpTopic;
	pObj.agt = _agt;
	pObj.window = window;
	pObj.mainWindow = mainWindow;
	pObj.httpobj = top.mainWindow.loginHelpObject;

	var nw = windows.initwindow("Help" + new Date().getTime());
	nw.mNode = null;
	nw.parameters = null;
	nw.mainWindowSrc = "helpPage.htm";
	nw.baseURL = "";
	_latestWindow = nw;

	nw.window = window.showModelessDialog("helpPage.htm", pObj, "dialogHeight:500px;dialogWidth:600px;status:no;help:no;resizable:yes;unadorned:no;");
}

/**************************************************
*			Diagnostic to copy text to the clipboard,		*
*			and then optionally display a message.			*
**************************************************/
function copyToClipboard(clipboardBuffer, wnd, passedBufferName)
{
	try
	{
		mainWindowdiagnosticsDisplay.value = clipboardBuffer;
		var rng = mainWindowdiagnosticsDisplay.createTextRange();
		rng.execCommand("Copy");

		if (wnd)
		{
			var bufferName;
			if (passedBufferName) bufferName = passedBufferName;
			else bufferName = "Buffer";
			var params = new Array("buffername="+bufferName, "buffersize=" + clipboardBuffer.length);
			var msg = top.messageText("copytoclipboard", "{buffername} is in the clipboard.\\nBuffer size={buffersize}", params);
			wnd.valetAlert(msg);
		}
	}
	catch(err)
	{
		alert("Error copying to clipboard:\n" + err + "\n" + clipboardBuffer);
	}
}

/**************************************************
*					Close all our windows										*
**************************************************/
function confirmLogout()
{
	if ((windows.list.length > 1) && (!_askedAboutClosing))
	{
		window.event.returnValue = "Are you sure you want to exit Valet and all its windows?";
		return;
	}
}
function closeWindows()
{
	_askedAboutClosing = true;
	try {_agt.logout()} catch(err) {};
}

/****************************************
*		When we store photos, some sites
*		wanted us to store the photo by URL
*		rather htan using the RETSObject
*		interface
****************************************/
function populatePhotoURLArray()
{
	if (_photoURLArray) return _photoURLArray;
	if (!datadictionary.status) readDataDictionary();
	var resources = datadictionary.xmlobject.selectNodes("//RESOURCE");
	_photoURLArray = new Array(resources.length);
	for (var rr=0; rr<resources.length; rr++)
	{
		for (var pp=1; pp<100; pp++)
		{
			var photoNumber = "0" + pp.toString();
			var fieldname = "photourl" + photoNumber.substring(photoNumber.length-2, photoNumber.length);
			if (!resources[rr].selectSingleNode("FIELD[@name='" + fieldname + "']")) break;
		}
		var pObj = new Object();
		pObj.resource = resources[rr].getAttribute("name").toUpperCase();
		pObj.count = pp-1;
		_photoURLArray[rr] = pObj;
	}
	return _photoURLArray;
}

/****************************************
*				Read the "Add fields" list			*
****************************************/
function readAddFields()
{
	var uri = _agt.valetDirectoryURL("MLS","private", "read", "AddFields.xml");
	uri += "&allowcache=true";
	addfields.agt = agt;
	addfields.load("GET", uri, false);
	if (!addfields.status) addfields.loadXML("<FIELDGROUPS/>");

	var sNodes = _agt.preferences.selectNodes("//FIELDUSAGE/SEARCH");
	for (var ss=0; ss<sNodes.length; ss++)
	{
		var fNodes = sNodes[ss].selectNodes("FIELD[@count != 0]");
		for (var ff=0; ff<fNodes.length; ff++)
		{
			uri = "//FIELDGROUP[@resource=\"" + sNodes[ss].getAttribute("resource").toLowerCase() + "\"]/FIELD[@name=\"" + fNodes[ff].getAttribute("name").toUpperCase() + "\"]";
			var gNodes = addfields.xmlobject.selectNodes(uri);
			for (var gg=0; gg<gNodes.length; gg++) gNodes[gg].setAttribute("searchcount", fNodes[ff].getAttribute("count"));
		}
	}
}

/****************************************
*				Read the data dictionary				*
****************************************/
function readDataDictionary()
{
	datadictionary.agt = agt;					//Set user structure
	var uri = _agt.valetDirectoryURL("MLS","private", "read", "datadictionary.xml");
	uri += "&allowcache=true";
	//datadictionary.domload(uri, false);
	datadictionary.load("GET", uri, false);
	return datadictionary.status;
}


function genericNewPod(frameName, windowID, podLabel, params, title)
{
if (windowID=="about") debugger;
  var podId = podTools.insertWindowNavPod(frameName, windowID, podLabel, params);	
 	if (title)
	{
		var titleText = $(podId + '_titletext');
		titleText.innerHTML = title;
	}
	return podId;
}

/****************************************
*		Generic routine to open a window.		
*			windowID = value uniquely identifying the window
*			baseURL = htm file to open				
*								subpage.htm
*								popupWindow.htm
*								cmaWizard.htm
*			mNode = node from TASKLIST (if any)
*			params = string to pass to window
*			mainWindowSrc = page to be loaded into main display (used if there is no mNode)
*			passedWindow = window requesting the open
****************************************/
function genericNewWindow(windowID,baseURL, mNode, params, mainWindowSrc, passedWindow)
{

	var callingWindow;		//Window doing the open
	var nw;
	var dt = new Date();


	if (passedWindow) callingWindow = passedWindow;
	else callingWindow = window;

	if (windowID == null) nw = windows.initwindow(dt.getTime());
	else nw = windows.initwindow(windowID);
	nw.mNode = mNode;
	nw.parameters = params;
	nw.mainWindowSrc = mainWindowSrc;
	nw.baseURL = baseURL;
	_latestWindow = nw;
	if (mNode)
	{
		var hNode = mNode.selectSingleNode(".//HELP/LIBRARY");
		if ((hNode) && (hNode.text.length))
		{
			nw.helplibrary = hNode.text;
			hNode = mNode.selectSingleNode(".//HELP/TOPIC");
			if ((hNode) && (hNode.text.length)) nw.helptopic = hNode.text;
		}
	}
	else if ((mainWindowSrc) && (mainWindowSrc.match(/updatepage.htm/i)))
	{
		nw.helptopic = "";
	}
	nw.window = window.showModelessDialog(baseURL,window,modelessFeatures(callingWindow));
	return "";
}

/**************************************************
*					Create the modeless features string			*
*					for a dialog window.										*
**************************************************/
function modelessFeatures(callingWindow)
{
	var features = "resizable:yes;unadorned:yes;scrollbars=no;status=no;";
	//features += "dialogTop:" + windows.nexty + "px;dialogLeft:" + windows.nextx + "px;";
	var wNode = _agt.loginobject.xmlobject.selectSingleNode("//PREFERENCES/WINDOWS/@screenSize");			//Has this user customized the dashboard?

	var screenSize = "";
	if (wNode) screenSize = wNode.text;
	var staggerWindow = true;
	var windowHeight = null;
	var windowWidth = null;
	switch (screenSize.toUpperCase())
	{
		case "SMALL":
			windowWidth = 800;
			windowHeight = 600;
			break;
		case "LARGE":
			windowWidth = screen.width - 20;
			windowHeight = screen.height - 20;
			features += "dialogTop:20px;";
			features += "dialogLeft:20px;";		
			staggerWindow = false;
			break;
		default:
			var match = screenSize.match(/(\d*)\:(\d*)/);
			if (match)
			{
				windowWidth = parseInt(match[1], 10);
				windowHeight = parseInt(match[2], 10);
			}
	}

	if (windows.list.length <= 2)
	{
		features += "dialogTop:" + callingWindow.screenTop + "px;";
		features += "dialogLeft:" + callingWindow.screenLeft + "px;";		
		staggerWindow = false;
	}

	if ((!windowWidth) || (isNaN(windowWidth))) windowWidth = callingWindow.document.body.clientWidth;
	if ((!windowHeight) || (isNaN(windowHeight))) windowHeight = callingWindow.document.body.clientHeight;
	
	if (staggerWindow)
	{
		var top = callingWindow.screenTop + 15;
		if ((top + callingWindow.document.body.clientHeight) > screen.availHeight) top = 20;
		features += "dialogTop:" + top.toString() + "px;";
		features += "dialogLeft:" + (callingWindow.screenLeft + 15) + "px;";
	}
	features += "dialogHeight:" + windowHeight + "px;dialogWidth:" + windowWidth + "px;";
	return features;
}

/********************************************
*			Get the current set of announcements	*
*			for the current user.									*
********************************************/
function getCurrentAnnouncements()
{
	announcements.agt = agt;
	temptran.agt = agt;
	temptran.readUserFile("announcements.xml");
	if (!temptran.status) temptran.xmlobject.loadXML("<Data/>");

	if (!agt.offlineflag)
	{
		var utcTime = dateToText(textToDate("UTC"), "ISO");
		var dmql = "(Audience=All)";
		dmql += "|((Audience=Office),(OWNEROFFICE=" + _agt.office + "))";
		dmql += "|((Audience=Broker),(OWNERBROKER=" + _agt.broker + "))";
		dmql += "(Audience=All),(StartDate=" + utcTime + "-),(EndDate=" + utcTime + "%2b)";
		dmql += "&order=GROUPNAME";
		var uri = _agt.dataURL("ANNOUNCEMENTS", null, dmql,"*");
		announcements.statusnode=true;
		announcements.load("GET", uri, false);
		var pendingAnnouncements = false;
		if (announcements.status) 
		{
			var aNodes = announcements.xmlobject.selectNodes("//Data/Record");
			for (var ii=0; ii<aNodes.length; ii++)
			{
				aNodes[ii].removeAttribute("unread");
				var tNode = temptran.xmlobject.selectSingleNode("//Data/Record[ID='" + aNodes[ii].selectSingleNode("ID").text + "']");
				if (tNode) 
				{
					var rd = tNode.getAttribute("readDate");
					if (!rd) rd = "2000-01-01T00:00";
					aNodes[ii].setAttribute("readDate", rd);
					if (rd < aNodes[ii].selectSingleNode(".//UPDATEDATE").text)
					{
						aNodes[ii].setAttribute("unread", "true");
						pendingAnnouncements = true;
					}
				}
				else 
				{
					aNodes[ii].setAttribute("unread", "true");
					aNodes[ii].setAttribute("readDate", "2000-01-01T00:00");
					pendingAnnouncements = true;
				}
			}
			announcements.saveUserFile("announcements.xml");
			
			var plt;
			var lNode = agt.preferences.selectSingleNode("//PreviousLoginTime");
			if (lNode) plt = lNode.text;
			else plt = "2000-01-01";
			aNodes = announcements.xmlobject.selectNodes("//Data/Record[@unread='true'][REQUIRED='Y']");
			if (aNodes.length) _startPage = 'Announcements';
			else
			{
				aNodes = announcements.xmlobject.selectNodes("//Data/Record[UPDATEDATE >'" + plt + "']");
				if (aNodes.length)
				{
					if (confirm("There are new announcements since you last logged in.\nDo you want to see them now?"))
					{
						_startPage = 'Announcements';
					}
				}
			}
		}
	}
	else announcements.xmlobject.loadXML(temptran.xmlobject.xml);
}


/***********************************************************
*					User wants to do an update, and the update verb	*
*					is defined by the select box option.						*
***********************************************************/
function openUpdateWindowSelect(resourceName, className, selectBox, recordID, extraParams, wnd)
{
	var verb = selectBox.options[selectBox.selectedIndex].value;
	if (verb.length == 0) return;				//User picked a display-only value
	selectBox.selectedIndex = 0;
	return openUpdateWindow(resourceName, className, verb, recordID, extraParams, wnd);
}

/***********************************************************
*					User wants to do an update
***********************************************************/
function openUpdateWindow(resourceName, className, verb, recordID, extraParams, wnd)
{
	var params = "resource=" + resourceName + ";classname=" + className + ";";
	params += "verb=" + verb + ";";
	if (recordID) 
	{
		if (recordID.indexOf("=") > 0) params = params + recordID + ";";
		else params += "id=" + recordID + ";";
	}
	if ((extraParams) && (extraParams.length > 0)) params += extraParams;
	if (typeof(podTools) == "undefined") genericNewWindow(null, "updatepage.htm", null, params, "updatepage.htm", wnd);
	else
	{
		var windowTitle = verb + " " + recordID;
		var params = 'p1=' + escape(params);
		var linkid = "Update." + new Date().getTime();
		genericNewPod("updateframe", linkid, windowTitle, params, windowTitle);
	}			

}

/***********************************************************
*			Check the permissions for a node in TaskList.xml
***********************************************************/
function permissionCheck(node, agentPrivs)    
{
	var pNode = node.selectSingleNode("PERMISSIONS");
	if (pNode) 
	{
		var compare = pNode.getAttribute("compare");
		var pSegs = pNode.text.toUpperCase().split(",");		//Privs listed
		var aSegs = agentPrivs.toUpperCase().split(",");		//Privs this agent has
		var a,p;
		switch (compare)
		{
			case "matchany":
				for (a=0; a<aSegs.length; a++)
				{
					for (p=0; p<pSegs.length; p++)
					{
						if (aSegs[a] == pSegs[p]) return true;
					}
				}
				return false;
				break;
			case "matchall":
				for (a=0; a<aSegs.length; a++)
				{
					for (p=0; p<pSegs.length; p++)
					{
						if (aSegs[a] == pSegs[p]) break;
					}
					if (p >= pSegs.length) return false;
				}
				break;
			case "denyany":
				for (a=0; a<aSegs.length; a++)
				{
					for (p=0; p<pSegs.length; p++)
					{
						if (aSegs[a] == pSegs[p]) return false;
					}
				}
				break;
			case "denyall":
				for (a=0; a<aSegs.length; a++)
				{
					for (p=0; p<pSegs.length; p++)
					{
						if (aSegs[a] == pSegs[p]) break;
					}
					if (p >= pSegs.length) break;
				}
				if (a >= aSegs.length) return false;
				break;
			
		}
	}
	return true;
}
/********************************************
*		When a search window exits, we save the	*
*		search values here.  If the user runs		*
*		the same search, we can restore the			*
*		values they last used.									*
********************************************/
function saveSearchCriteria(sNode)
{
	var resourceName = sNode.selectSingleNode("RESOURCE").text;
	var id = sNode.getAttribute("id").toUpperCase();
	var lvl = sNode.getAttribute("savelevel").toUpperCase();
	for (var ii=0; ii<_searchCriteriaArray.length; ii++)
	{
		if ((_searchCriteriaArray[ii].resource == resourceName.toUpperCase()) &
				(_searchCriteriaArray[ii].id == id) &
				(_searchCriteriaArray[ii].lvl == lvl))
		{
			_searchCriteriaArray[ii].xml = sNode.xml;
			return;
		}
	}
	var sObj = new Object();
	sObj.resource = resourceName.toUpperCase();
	sObj.id = id;
	sObj.lvl = lvl;
	sObj.xml = sNode.xml;
	_searchCriteriaArray[_searchCriteriaArray.length] = sObj;
}

/****************************************
*			The dashboard is closing.
*			Remove all traces of this user.
****************************************/
function dashboardClosed()
{
	for (var ii=0; ii<_searchCriteriaArray.length; ii++)
	{
		delete(_searchCriteriaArray[ii]);				//Give back the object
	}
	_searchCriteriaArray = new Array();
	clearLogout();
}

/********************************************************
*			Load a group of tables in a single transaction		*
********************************************************/
function loadTableList(resource, className, tableArray)
{
	if (!_agt.remote) return;					//If we have the tables locally, don't bother
	var tname;
	var vObj;
	var rname = resource.toLowerCase();
	var cname = className;
	if (cname) cname = cname.toLowerCase();

	var notLoadedCount = 0;
	var objectList = "";
	for (var tt=0; tt<tableArray.length; tt++)
	{
		tname = tableArray[tt].toLowerCase();
		objectList += "tables/" + tname + ".xml|";
		for (var ii=0; ii<validationTables.length; ii++)
		{
			if ((validationTables[ii].name == tname) &&
					(validationTables[ii].resource == rname) &&
					(validationTables[ii].classname == cname)) break;
		}
		if (ii >= validationTables.length) notLoadedCount++;
	}
	/*********************************************
	*		If any of the tables were not loaded,
	*		we will load the entire set.
	*********************************************/
	if (notLoadedCount)
	{
		uri  = _agt.valetDirectoryURL("MLS", "private", "read") + "&format=xml&allowcache=true";
		if (objectList.length > 3000) extra.postText(uri, "OBJECT="+objectList.replace(/\|$/, ""), false);
		else
		{
			uri += "&OBJECT=" + objectList.replace(/\|$/, "");
			extra.load("GET", uri, false);
		}
		if (extra.status)
		{
			var vNodes = extra.xmlobject.selectNodes("//XML/validate[@name]");
			for (var vv=0; vv<vNodes.length; vv++)
			{
				tname = vNodes[vv].getAttribute("name").toLowerCase();
				{
					for (var ii=0; ii<validationTables.length; ii++)
					{
						if ((validationTables[ii].name == tname) &&
								(validationTables[ii].resource == rname) &&
								(validationTables[ii].classname == cname)) break;
					}
					if (ii >= validationTables.length)
					{
						vObj = new Object();
						vObj.resource = rname;
						vObj.classname = cname;
						vObj.name = tname;
						vObj.tbl = new ActiveXObject('MSXML2.DOMDocument');
						vObj.tbl.async = false;
						validationTables[validationTables.length] = vObj;
					}
					else vObj = validationTables[ii];					
					vObj.tbl.loadXML(vNodes[vv].xml);					
				}
			}
		}
	}

	//http://douglas-2f59b59/valethost/ValetDirectories.srf?resource=MLS&type=private&option=read&object=tables/amenities.xml|tables/basement.xml&version=01.01.0001&agentid=weeks4&format=xml&allowcache=true

	return;
}

/********************************************
*			Load a validation table.  We keep a		*
*			local array to minimize access				*
*			to the local disk or remote host.			*
********************************************/
function loadValidationTable(resource,tablename,fieldname,className)
{
	var ii;
	var tranStat;
	var fileName;
	var rname = resource.toLowerCase();
	var tname = tablename.toLowerCase();
	var cname = className;
	if (cname) cname = cname.toLowerCase();
	if ((tname == null) || (tname == "")) tname = fieldname;
	tname = tname.toLowerCase();

	for (ii=0; ii<validationTables.length; ii++)
	{
		if ((validationTables[ii].name == tname) &&
				(validationTables[ii].resource == rname) &&
				(validationTables[ii].classname == cname)) return ii;
	}

	/**************************************
	*		We did not find the table in our	*
	*		array.  Look for it.							*
	**************************************/
	var vObj = new Object();
	vObj.resource = rname;
	vObj.classname = cname;
	vObj.name = tname;
	vObj.tbl = new ActiveXObject('MSXML2.DOMDocument');
	vObj.tbl.async = false;

	/**************************************
	*			Decide where this validation		*
	*			file is located.  If the file		*
	*			name contains a colon, it is		*
	*			not a "system" table.						*
	**************************************/
	var checkHost = true;
	var tsegs = tname.split(":");
	var xmlName;
	if (tsegs.length < 2)
	{
		xmlName = tname;
		fileName = unescape(agt.basedirectory + agt.site) + "/tables/" + tname + ".xml";
	}
	else
	{
		xmlName = tsegs[1];
		fileName = agt.getOwnerDirectory(tsegs[0], "private") + "/tables/" + tsegs[1] + ".xml";
		var checkHost = false;
	}

	/********************************
	*		If we are not running from	*
	*		the host system, check the	*
	*		local disk.									*
	********************************/
	if (!_agt.remote)
	{
		var st = new Date().getTime();
		vObj.tbl.load(fileName);
		vObj.source = fileName;
		var et = new Date().getTime();
		tranStat = domTransactionHistory(vObj.tbl, "Validation table", fileName,et-st );
		if (tranStat) checkHost = false;
		else
		{
			var perr = vObj.tbl.parseError;
			logConsole("Error reading file " + fileName +
					".  Error=" + perr.errorCode.toString(16) + " " + perr.reason);
		}
	}

	/****************************************
	*		If checkHost is set, we are either	*
	*		could not find the file or we are		*
	*		running remotely.  In either case,	*
	*		we will look on the host.						*
	****************************************/
	if ((checkHost) && (!_agt.offline))
	{
		var uri = _agt.valetDirectoryURL("MLS", "private", "read", "/tables/" + xmlName + ".xml");
		uri = uri.replace(/\&agentid\s([^\&])*/, "");			//Remove agentid=value from string (tables do not vary between users)
		tranStat = finishLoadingTable(vObj.tbl, uri);
		if (!tranStat) tranStat=loadTableFromHost(vObj.tbl, rname, fieldname, className);
		if (tranStat) vObj.source = fileName;
	}

	if (!tranStat)
	{
		delete (vObj.tbl);
		delete (vObj);
		logConsole("Unable to load table " + tablename + ".  See transactions list for details");
		return null;
	}
	vObj.length = vObj.tbl.selectNodes("//value").length;

	validationTables[validationTables.length] = vObj;
	return validationTables.length -1;
}

/****************************************************
*			Load a validation from the table using the
*			same ASP page we use to create the local
*			copy of the table validation.
****************************************************/
function loadTableFromHost(tbl, rname, fieldname, className)
{
	var uri = agt.baseurl + "PWEBValidationTable.asp?site="+agt.database;
	uri += "&resource=" + rname + "&lookup=" + fieldname;
	if (className) uri += "&classname=" + className;
	return finishLoadingTable(tbl, uri);
}

function finishLoadingTable(tbl, uri)
{
	validationtable.agt = _agt;
	validationtable.statusnode = true;					//We expect a <STATUS> node
	validationtable.load("GET", uri + "&allowcache=true", false);
	validationtable.statusnode = false;				//Clear for next time
	if (validationtable.status)
	{
		tbl.loadXML(validationtable.httpobj.responseText);

		/************************************
		*		Unless we are running remotely,	*
		*		save this file for next time.		*
		************************************/
		if (!_agt.remote)
		{
			var fso = new ActiveXObject("Scripting.FileSystemObject");
			var newFile = unescape(agt.basedirectory + agt.site) + "/tables";
			if (checkForFolder(newFile))
			{
				var vName = tbl.selectSingleNode("//validate/@name");
				if (!vName) return false;
				var fileName = unescape(agt.basedirectory + agt.site) + "/tables/" + vName.text + ".xml";
				//validationtable.xmlobject.save(fileName);		//Save it for next time
				tbl.save(fileName);
			}
		}
	}
	return validationtable.status;
}

/*******************************************
*		Load the contents of a CHOICES table.		*
*		This works just like a validation table	*
*		except that the data comes from a 			*
*		business rule rather than a file.				*
********************************************/
function loadChoicesTable(resource, choicesID, fieldname, fielddescription, choicesNode)
{
	var ii;
	var rname = resource.toLowerCase();
	var tname = choicesID.toLowerCase();
	for (ii=0; ii<validationTables.length; ii++)
	{
		if ((validationTables[ii].name == tname) && (validationTables[ii].resource == rname)) return ii;
	}

	var vObj = new Object();
	vObj.resource = rname;
	vObj.name = tname;
	vObj.source = "choices";
	vObj.tbl = new ActiveXObject('MSXML2.DOMDocument');
	choicesToTable.selectSingleNode("//title").text = fieldname;
	choicesToTable.selectSingleNode("//description").text = fielddescription;
	choicesNode.transformNodeToObject(choicesToTable.XMLDocument, vObj.tbl);
	vObj.length = vObj.tbl.selectNodes("//value").length;
	validationTables[validationTables.length] = vObj;
	return validationTables.length -1;
}


/******************************************
*		The TableHelp.htm dialog box wants		*
*		to toggle the selected attribute for	*
*		one entry in a validation table.			*
******************************************/
function tableHelpRowToggle(tableIdx, uri, setFlag)
{
	var dNodes = validationTables[tableIdx].tbl.selectNodes(uri);
	var netChange = 0;
	for (var dd=0; dd<dNodes.length; dd++)
	{
		if ((setFlag) && (dNodes[dd].getAttribute("selected") != "true"))
		{
			dNodes[dd].setAttribute("selected", "true");
			netChange++;
		}
		else 	if ((!setFlag) && (dNodes[dd].getAttribute("selected") == "true"))
		{
			dNodes[dd].removeAttribute("selected");
			netChange--;
		}
	}
	return netChange;
}


/************************************************************
*			tableMatch for validation tables cached in memory			*
************************************************************/
function tableMatch(idx, keyField, matchField, passedValue, returnField, passedMethod)
{
	return tableMatchByTable(validationTables[idx].tbl, keyField, matchField, passedValue, returnField, passedMethod)
}

/************************************************************
*		We cannot call the transformNode method for objects			*
*		that were created by this page in the java script of		*
*		other pages.																						*
************************************************************/
function tableMatchByTable(tbl, keyField, matchField, passedValue, returnField, passedMethod)
{
	var mNode;
	var testText;
	var trailingPoundSign = false;
	
	var matchValue = passedValue.replace(/[\*]*$/, "");			//Remove trailing asterisks
	var method = passedMethod;
	if (matchValue != passedValue) method = "startswith";
	if (matchValue.match(/\#$/))
	{
		matchValue = matchValue.replace(/\#$/, "");
		method = "exact";
		trailingPoundSign = true;
	}
		
	/*****		Set the text value to match  ******/
	mNode = tableValidate.selectSingleNode("//xsl:variable[@name='matchText']");
	mNode.text = matchValue.toLowerCase();

	/******		Pick the field to return	*******/
	mNode = tableValidate.selectSingleNode("//xsl:value-of");
	//mNode.setAttribute("select", returnField.toLowerCase());
	mNode.setAttribute("select", returnField);

	/*****		Set selection clause  ******/
	mNode = tableValidate.selectSingleNode("//xsl:if");
	switch (method)
	{
		case "exact":
			testText = 
				'$matchText=' +
				'translate(' + matchField + ',"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "abcdefghijklmnopqrstuvwxyz0123456789")';
			break;
			
		case "startswith":
			testText = 
				'starts-with(' +
				'translate(' + matchField + ',"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "abcdefghijklmnopqrstuvwxyz0123456789")' +
				',$matchText)';
			break;
		
		case "contains":
			testText = 
				'contains(' +
				'translate(' + matchField + ',"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", "abcdefghijklmnopqrstuvwxyz0123456789")' +
				',$matchText)';
			break;
		
		case "range":
			var matchLimits = matchValue.split("-");
			testText =
				'(number(' + matchField + ') >=' + matchLimits[0] + ' and number(' + matchField + ') <=' + matchLimits[1] + ')';
			break;
	}
	mNode.setAttribute("test", testText);

	var xstr = tbl.transformNode(tableValidate.XMLDocument);
	
	if (xstr.length) xstr = xstr.substring(0, xstr.length-1);			//Trim trailing comma
	tableMatches = xstr;
	if (trailingPoundSign) tableMatches += "#";
	
	if ((returnField != keyField) & (xstr.length > 0))
	{
		mNode = tableValidate.selectSingleNode("//xsl:value-of");
		mNode.setAttribute("select", keyField.toLowerCase());
		tableMatches = tbl.transformNode(tableValidate.XMLDocument);
		if (tableMatches.length > 0) tableMatches = tableMatches.substring(0,tableMatches.length-1);
	}
/*********************************
	copyToClipboard("Method=" + method +
		"\nkeyField=" + keyField +
		"\nreturnField=" + returnField +
		"\nmatches=" + tableMatches+
		"\nXSL table\n" + tableValidate.XMLDocument.xml);
	valetAlert("DEBUG: check clipboard for " + tableMatches);
*******************************/
	if (trailingPoundSign) xstr += "#";
	return xstr;
}


/******************************************
*			Find entries in table that match		*
*			what the caller has entered.				*
******************************************/
function tableHelp(idx, matchValues, keyField, orderField, subqualifiers, firstTime, firstRecord, lastRecord)
{
	var mNode;
	var sNode;
	/*****		Set the text value to match  ******/
	mNode = tableHelpFormat.selectSingleNode("//xsl:variable[@name='matchText']");
	mNode.text = matchValues.toLowerCase();
	
	/************************************
	*		If the key value is already in	*
	*		the matchValues, we want to 		*
	*		highlight that row.							*
	************************************/
	if (firstTime)
	{
		var sNodes = validationTables[idx].tbl.selectNodes("//*[@selected]");
		for (var ss=0; ss<sNodes.length; ss++) sNodes[ss].removeAttribute("selected");
		var segs = matchValues.split(",");
		for (var ss=0; ss<segs.length; ss++)
		{
			var txt = segs[ss].replace(/^\s*/, "");	//trim leading spaces
			txt = txt.replace(/\s*$/, "");					//trim trailing spaces
			if (txt.length > 0)
			{
				var qry = "//" + keyField + '[ . $ieq$ "' + txt + '"]';
				var sNodes = validationTables[idx].tbl.selectNodes(qry);
				for (var sss=0; sss<sNodes.length; sss++) sNodes[sss].parentNode.setAttribute('selected', 'true');
			}
		}	
	}
		
	sNode = tableHelpFormat.selectSingleNode("//xsl:variable[@name='firstRecord']");
	sNode.text = firstRecord.toString();
	sNode = tableHelpFormat.selectSingleNode("//xsl:variable[@name='lastRecord']");
	sNode.text = lastRecord.toString();

	if (orderField)
	{

		sNode = tableHelpFormat.selectSingleNode("//xsl:sort");
		var sortField = sNode.getAttribute("select");
		sNode.setAttribute("data-type", "text");
	
		fNode = datadictionary.xmlobject.selectSingleNode("//FIELD[@name $ieq$ '" + orderField + "']");
		if (fNode)
		{
			switch(fNode.getAttribute("dtype"))
			{
				case "smallint":
				case "int":
				case "tinyint":
				case "real":
				case "float":
				case "money":
				case "counter":
				case "listnumber":
				case "smallmoney":
					sNode.setAttribute("data-type", "number");
					mNode.text = keyField + "=$matchText";
					break;
				default:
					sNode.setAttribute("data-type", "text");
			}
		}	
		else if (orderField.toLowerCase() == "number")
		{
			sNode.setAttribute("data-type", "number");
			mNode.text = keyField + "=$matchText";
		}

		if ((!firstTime) && (sortField.toUpperCase() == orderField.toUpperCase()))
		{
			if (sNode.getAttribute("order") == "ascending") sNode.setAttribute("order", "descending");
			else sNode.setAttribute("order", "ascending");
		}
		else
		{
			sNode.setAttribute("select", orderField);
			sNode.setAttribute("order", "ascending");
		}
	}

	/****************************************
	*		If there are subqualifiers, reduce	*
	*		the table using a XSL.					 		*
	*		Subqualiers is expected to be in		*
	*		the format:
	*				field=value,value,value|field=value,value,value....
	****************************************/
//		<xsl:apply-templates select='value[(ar $ieq$ "26" or ar $ieq$ "6") and (oca $ieq$ "cs")]'/>
	var sourceTable;
	if (subqualifiers.length != 0)
	{
		mNode = tableHelpFilter.XMLDocument.selectSingleNode("//xsl:if");
		if (mNode)
		{
			var fsegs = subqualifiers.split("|");
			var searchText = "";
			var fieldCount = 0;
			for (var ff=0; ff<fsegs.length; ff++)
			{
				var valueCount = 0;
				var match = fsegs[ff].match(/([^!=]*)(=|\!=)([^\|]*)/);
				/** match[0] = fsegs[ff] match[1]=field name match[2] = operator match[3] = value */
				if (match)
				{
					if (fieldCount > 0) searchText += " and ";
					if (valueCount == 0) 
					{
						searchText += "(";
						fieldCount++;
					}
					else searchText += " or ";
					var vsegs = match[3].split(",");
					if (match[2] == "=")
					{
						for (var vv=0; vv<vsegs.length; vv++)
						{
							searchText += 'starts-with(' + 
							'translate(' + match[1] + ', "abcdefghijklmnopqrsturwxyz", "ABCDEFGHIJKLMNOPQRSTURWXYZ"),' +
							'"' + vsegs[vv].replace(/\*$/, "").replace(/^\s*/, "").toUpperCase() + '") or ';
							valueCount++;
						}
						searchText = searchText.replace(/\sor\s$/, "");		//Trim last "or";
					}
					else			//field != a,b,c
					{
						for (var vv=0; vv<vsegs.length; vv++)
						{
							searchText += 'not (starts-with(' + 
							'translate(' + match[1] + ', "abcdefghijklmnopqrsturwxyz", "ABCDEFGHIJKLMNOPQRSTURWXYZ"),' +
							'"' + vsegs[vv].replace(/\*$/, "").replace(/^\s*/, "").toUpperCase() + '")) and ';
							valueCount++;
						}
						searchText = searchText.replace(/\sand\s$/, "");		//Trim last "and";
					}
				}
				if (valueCount > 0) searchText += ")";
			}
			if (searchText.length == 0) searchText="1=1";
			mNode.setAttribute("test", searchText);
			validationTables[idx].tbl.transformNodeToObject(tableHelpFilter, extra.xmlobject);
			sourceTable = extra.xmlobject;
		}
		else 
		{
			alert("Did not find //xsl:template[@match='validate'] in \n" + tableHelpFilter.XMLDocument.xml);
			sourceTable = validationTables[idx].tbl;
		}
	}
	else 
	{
		sourceTable = validationTables[idx].tbl;
	}

	/********************************************
	*		If no values qualified, return a table	*
	*		with just a header row.									*
	********************************************/
	var firstValue = sourceTable.selectSingleNode('//value');
	if (!firstValue)
	{
		var xstr = "<table class='searchCriteriaTable' cellpadding='0' ";
		xstr += "setCount='0' selectedCount='0' id='tableHelpDisplay'";
		xstr += " unfilteredRecords='" + validationTables[idx].length + "'";
		xstr += " firstRecord='" + firstRecord + "'";
		xstr += " lastRecord='" + lastRecord + "'>";
		var fieldNames = "";
		var fNode = sourceTable.selectSingleNode("//fieldnames");
		if (fNode) fieldNames = fNode.text;
		else
		{
			var firstNode = validationTables[idx].tbl.selectSingleNode("//value");
			for (var cc=0; cc<firstNode.childNodes.length; cc++)
				fieldNames = fieldNames + firstNode.childNodes[cc].nodeName + ",";
			fieldNames = fieldNames.replace(/\,$/, "");
		}
		xstr += "<tr>";
		var fsegs = fieldNames.split(",");
		for (var ff=0; ff<fsegs.length; ff++)
		{
			xstr += "<th>" + fsegs[ff] + "</th>";
		}
		xstr += "</tr>";
		xstr += "</table>";
		return xstr;
	}

	var xNode = tableHelpFormat.XMLDocument.selectSingleNode("//xsl:attribute[@name='unfilteredRecords']");
	xNode.text = validationTables[idx].length;

	return sourceTable.transformNode(tableHelpFormat.XMLDocument);
}

/**************************************************
*		When a MarketWatch schedule changes, we have	*
*		to replace the corresponding entry in the			*
*		marketwatch structure.												*
**************************************************/
function replaceMWSearch(mwNode, window)
{
	var topNode = marketwatch.xmlobject.selectSingleNode("//MWLIST");
	
	var sid = mwNode.selectSingleNode("//SEARCH/SEARCHID").text;
	var url = agt.baseurl + "valetmarketwatch.srf?option=FIND";
	url += "&resource=" + mwNode.selectSingleNode("//SEARCH/RESOURCE").text;
	url += "&searchID=" + sid;
	
	extra.statusnode = true;					//We expect a <STATUS> tag
	extra.load("GET", url, false);
	if (!extra.status)
	{
		if (extra.statustext.substring(0,12) != 'Did not find')
			return extra.errorCheck("Unable to get new MARKETWATCH option from host", window);
	}



	
	var newNode = extra.xmlobject.selectSingleNode("//MARKETWATCH");
	var eNode = marketwatch.xmlobject.selectSingleNode("//MARKETWATCH[SEARCH/SEARCHID='" + sid + "']");
	if (eNode)
	{
		eNode.parentNode.removeChild(eNode);	
	}
	if (newNode) topNode.appendChild(newNode.cloneNode(true));		//Add new entry

	dashboardMarketWatchDisplays('marketwatchdiv', false);
	dashboardMarketWatchGlance();

	return newNode;
}

/**********************************************
*			Delete a market watch from the host
**********************************************/
function deleteMarketWatch(sNode)
{
	var url = agt.baseurl;
	var id = sNode.getAttribute("id");
	url += "valetmarketwatch.srf?Option=DELETE";
	url += "&resource=" + sNode.selectSingleNode("RESOURCE").text.toUpperCase();
	url += "&SearchID=" + id;	

	extra.agt = agt;
	
	var messageBody = 
		"<MWLIST><MARKETWATCH><SEARCH>" +
			"<SEARCHID>" + id + "</SEARCHID>" +
			"<RESOURCE>" + sNode.selectSingleNode("RESOURCE").text.toUpperCase() + "</RESOURCE>";
	messageBody += "</SEARCH>";
	if (sNode.getAttribute("mwagent") == "yes") messageBody += "<EMAIL EVENTID='EmailAgent'/>";
	if (sNode.getAttribute("mwclient") == "yes") messageBody += "<EMAIL EVENTID='EmailPublic'/>";
	if (sNode.getAttribute("mwtext") == "yes") messageBody += "<EMAIL EVENTID='EmailText'/>";
	if (sNode.getAttribute("mwlogin") == "yes") messageBody += "<LOGIN EVENTID='Login01'/>";

	messageBody += "</MARKETWATCH></MWLIST>";
	extra.xmlobject.loadXML(messageBody);

	extra.load("POST", url, false);
	if (!extra.status)
	{
		_lastErrorMessage = "Error deleting Market Watch\n" + extra.statustext;
		return false;
	}

	/****************************************
	*		Remove it from marketwatch list			*
	****************************************/
	if (marketwatch.status)
	{
		tNode = marketwatch.xmlobject.selectSingleNode("//MARKETWATCH[SEARCH/SEARCHID='" + id + "']");
		if (tNode) 
		{
			tNode.parentNode.removeChild(tNode);
			dashboardMarketWatchDisplays('marketwatchdiv', false);
			dashboardMarketWatchGlance();
		}
	}
	
	/****************************************
	*				Resave the search without 			*
	*				the market watch attributes			*
	****************************************/
	sNode.removeAttribute("mwagent");
	sNode.removeAttribute("mwclient");
	sNode.removeAttribute("mwtext");
	sNode.removeAttribute("mwlogin");
	if (!saveSearch(sNode))  return false;


	return true;
}			

/*********************************************************
*		Change one part of the user preference structure.
*********************************************************/
function changeUserPreference(uri, newValue)
{
	var setValue;
	var vNode = _agt.preferences.selectSingleNode(uri);
	switch(newValue.toString())
	{
		case "0":
			setValue = "false";
			break;
		case "-1":
			setValue = "true";
			break;
		default:
			setValue = newValue;
			break;
	}
	if (vNode) vNode.text = setValue.toString();
	else
	{
		var segs = uri.split("/");
		var lastSeg = segs[segs.length-1];
		segs.pop();
		var newURI = segs.join("/");
		if (lastSeg.match(/^\@/))
		{
			var att = segs[segs.length-1].substring(1, segs[segs.length-1].length);
			vNode = _agt.preferences.selectSingleNode(newURI);
			if (vNode) vNode.setAttribute(att, setValue.toString());
			else return alert("Did not find " + uri + " in \r\n" + _agt.preferences.xml);
		}
		else
		{
			vNode = _agt.loginobject.xmlobject.createNode(1, lastSeg, "x-schema:preferencesSchema.xml");
			_agt.preferences.appendChild(vNode);
			vNode.text = setValue.toString();
		}
	}
	_agt.saveUserPreferences(true);
}

/**************************************
*			User wants to update (or add)		*
*			a <REPORT> node or a <REPORTMENU>
*			node to one of the reportlist		*
*			files.  We must also modify the	*
*			memory-resident copy.						*
*
*			Obsolete - use tranobj.writeSetupFile method
**************************************/
function updateReportList(newNode, updateMode)
{
	var lvl = newNode.getAttribute("savelevel");
	if (!lvl)
	{
		copyToClipboard(newNode.xml);
		return "This update did not specify a savelevel attribute.<br/>The node is in the paste buffer";
	}
	
	try
	{
		/****************************************
		*			Save it to the appropriate file		*
		****************************************/
		var uri;
		if (!_agt.remote)
		{
			uri = _agt.getOwnerDirectory(lvl, "private") + "/reportlist.xml";
			extra.agt = _agt;
			extra.load("GET", uri, false);
			if (!extra.status)
			{
				extra.xmlobject.loadXML('<REPORTS/>');
				extra.status = true;
			}
	
			mNode = extra.xmlobject.selectSingleNode("//REPORTS");			//Top node
			var nodeName = newNode.nodeName;
			var id = newNode.getAttribute("name");
			
			/************************************
			*			We always delete the current	*
			*			copy of the node.  If we are	*
			*			adding a node, it will not be	*
			*			here, but we check anyway.		*
			************************************/
			sNode = mNode.selectSingleNode(".//" + nodeName + "[@name $ieq$ '" + id + "' and @savelevel $ieq$ '" + lvl + "']");
			if (sNode) mNode.removeChild(sNode);
			
			if (updateMode.toLowerCase() != "delete") mNode.appendChild(newNode.cloneNode(true));
			if (extra.checkForDirectory(uri)) 
			{
				extra.xmlobject.save(uri);
			}
			if (!extra.status) return extra.errorMessage("Unable to save the file " + uri, "<br/>");
			
			/**************************************
			*			Now change the memory-resident	*
			*			version of REPORTLIST.					*
			**************************************/
			var topNode = reportlist.xmlobject.selectSingleNode("//REPORTS");
			sNode = topNode.selectSingleNode("//" + nodeName + "[@name $ieq$ '" + id + "' and @savelevel $ieq$ '" + lvl + "']");
			if (sNode) topNode.removeChild(sNode);
			if (updateMode.toLowerCase() != "delete") topNode.appendChild(newNode.cloneNode(true));
		}
		else
		{
			/********************************************
			*			Save a report menu change to server		*
			********************************************/
			alert("We do not update reportlist.xml on the server just yet");
		}
	}

	catch(e)
	{
		copyToClipboard("updateMode=" + updateMode + "\ninserting\n" + newNode.xml);
		return "Failed to save this report change.<br/>" + e + 
		"\nCheck the paste buffer";
	}
	return "";
	
}

/******************************************************
*				Get a list of all updates from updates.xml		*
******************************************************/
function loadUpdates()
{
	if ((updates.status) &&	(_agt.permissions.indexOf("disableCachingDiagnostic") < 0)) return true;		//Exit if already loaded
	var upd = top.mainWindow.updates;
	upd.agt = _agt;
	upd.async = false;
	upd.statusnode = true;			//We expect this to be in XML format

	var checkHost = true;
	var fileName = unescape(agt.basedirectory + agt.site) + "/updates/updates.xml";

	/************************************
	*		Try loading it from disk first	*
	************************************/
	if (!_agt.remote)
	{
		var userfile =  unescape(agt.basedirectory + agt.site) + "/agents/" + agt.agentid + "/updates/updates.xml";
		upd.load("GET",userfile,false);				//Try our copy first
		if (upd.status) return true;
		upd.load("GET",fileName,false);				//Try our copy first
		if (upd.status) return true;					//Just use site copy
	}
	if (_agt.offline)	return false;

	/************************************
	*		Read the data dictionary				*
	************************************/
	if (!top.mainWindow.datadictionary.status)
	{
		if (!top.mainWindow.readDataDictionary())		//Read it again
		{
			top.mainWindow.datadictionary.errorCheck("Unable to read data dictionary");
			return;
		}
	}
	/******************************************
	*			Get a list of all the update sets		*
	******************************************/
	var url = _agt.dataURL("UPDATES", "UPDATES", "(resource=*)", "*", null);
	if (upd.load("GET", url, false))
	{
		/************************************
		*		Unless we are running remotely,	*
		*		save this file for next time.		*
		************************************/
		if (!_agt.remote)
		{
			top.mainWindow.logConsole("Calling saveXMLToFile to save " + fileName);
			upd.saveXMLToFile(fileName);
		}
	}
	return upd.status;
}

/********************************************
*		Get a list of all validation routines		*
********************************************/
function loadValidationRoutines()
{
	if ((top.mainWindow.validationroutines.status) &&
			(top.mainWindow._agt.permissions.indexOf("disableCachingDiagnostic") < 0)) return true;

	var vr = top.mainWindow.validationroutines;
	vr.agt = top.mainWindow._agt;
	vr.async = false;
	vr.statusnode = false;			//We may not have a <STATUS> tag if we have update this file

	var checkHost = true;
	var fileName = unescape(_agt.basedirectory + _agt.site) + "/updates/validationroutines.xml";

	/************************************
	*		Try loading it from disk first	*
	************************************/
	if (!top.mainWindow._agt.remote)
	{
		var userfile =  _agt.site + "/agents/" + _agt.agentid + "/updates/validationroutines.xml";
		vr.load("GET",userfile,false);				//Try our copy first
		if (vr.status) return true;
		vr.load("GET",fileName,false);				//Try copy used for all users
		if (vr.status) return true;
	}

	/************************************
	*			We do not have a list of all	*
	*			the validation routines on		*
	*			our local PC.  Get one from		*
	*			the host.											*
	************************************/
	if (top.mainWindow._agt.offline)	return false;
	vr.statusnode = true;			//We expect a <STATUS> tag
	var uri = _agt.valetDirectoryURL("MLS", "private", "read", "/updates/validationroutines.xml");
	vr.load("GET", uri, false);
	if (!uri)
	{
		uri = top.mainWindow._agt.baseurl + "PWEBSetup.asp?validation=*";
		vr.load("GET", uri, false);
	}
	return vr.status;
}

/**********************************************
*			Read an update set.  If possible, use		*
*			a copy that has already been cached.		*
**********************************************/
function findCachedUpdateSet(targetUpdateSet, resourceName, className, verb, parameterList)
{
	if (_agt.permissions.indexOf("disableCachingDiagnostic") < 0)
	{
		for (var uu=0; uu<_updateSets.length; uu++)
		{
			if ((_updateSets[uu].resource == resourceName.toUpperCase()) &
					(_updateSets[uu].updateclass == className.toUpperCase()) &
					(_updateSets[uu].verb == verb.toUpperCase()))
			{
				/************************************
				*		Sometimes the update set contains "include"
				*		files which are selected based on parameters
				*		passed to this call.  If we are going to
				*		reuse the cached update set, its parameter
				*		list has to match this caller's list - except
				*		for the key field value.
				*************************************************/
				var stringsMatch = true;
				var wl = parameterList;
				if (!wl) wl = "";
				var pl = _updateSets[uu].parameterlist;
				var keyField = _updateSets[uu].keyfieldname.toUpperCase();
				if (keyField.length)
				{
					psegs = pl.split(";");			//List from cached update set
					wsegs = wl.split(";");			//List from this call
					for (var ww=0; ww<wsegs.length; ww++)
					{
						if ((wsegs[ww].substring(0,keyField.length).toUpperCase() != keyField) &
								(wsegs[ww].substring(0,3).toUpperCase() != "ID="))
						{
							for (var pp=0; pp<psegs.length; pp++) if (psegs[pp] == wsegs[ww]) break;
							if (pp >= psegs.length) stringsMatch = false;
						}
					}
				}				
				if (stringsMatch) return _updateSets[uu].copy(targetUpdateSet);
			}
		}
		var newObject = document.createElement("vds:updateset");
		var sts;
		try
		{
			sts = newObject.loadUpdateSet(resourceName, className, verb, parameterList);
		}
		catch(err)
		{
			debugger;
			return false;
		}
		if (sts) 
		{
			_updateSets[_updateSets.length] = newObject;								//Save it in cached array

			/**************************************************
			*				Preload any validation tables we need			*
			**************************************************/
			var tableNodes = newObject.businessrules.selectNodes("//RULE[@type='lookup']");
			var tablecount = 0;
			var objectList = new Array();
			for (var tt=0; tt<tableNodes.length; tt++)
			{
				var tNode = tableNodes[tt].selectSingleNode(".//VALIDATE/@lookup");
				if (tNode)
				{
					var fsegs = tNode.text.split(";");
					if (fsegs[0].length > 0)
					{
						objectList[objectList.length] = fsegs[0].replace(/\s*$/, "").toLowerCase();
					}
				}
			}		
			if (objectList.length) top.mainWindow.loadTableList(resourceName, className, objectList);
		}
		newObject.copy(targetUpdateSet);
		return sts;
	}
	return targetUpdateSet.loadUpdateSet(resourceName, className, verb, parameterList);
}

/**********************************************
*			Update the Parking array.  This is a list
*			of recently performed searches.
*
*			sNode = <SEARCH> node from search page
*			keyValue = value uniquely identifying this entry.
***********************************************/
function updateValetParking(sNode, keyValue, displayQueryText, latestCount)
{
	if (latestCount <= 0) return;
	uri = "RECENTSEARCHES/RECENTSEARCH[KEY=\"" + keyValue + "\"]";
	var vNode =_valetParking.selectSingleNode(uri);
	
	/******************************************
	*		If we did not find the search, create	*
	*		a new node.  Otherwise, remove it and	*
	*		readd it to the front of the list.		*
	******************************************/
	if (!vNode)
	{
		vNode = _valetParking.createNode(1, "RECENTSEARCH", "");
		vNode.setAttribute("created", new Date().getTime());
		var kNode = _valetParking.createNode(1, "KEY", "");
		var kText = _valetParking.createCDATASection(keyValue);
		kNode.appendChild(kText);
		vNode.appendChild(kNode);
		kNode = _valetParking.createNode(1, "DISPLAY", "");
		kText = _valetParking.createCDATASection(displayQueryText);
		kNode.appendChild(kText);
		vNode.appendChild(kNode);
		vNode.appendChild(sNode.cloneNode(true));
		kNode = _valetParking.createNode(1, "DATERUN", "");
		vNode.appendChild(kNode);
	}
	else vNode.parentNode.removeChild(vNode);
	
	/**************************************
	*			Add this object to the start		*
	*			of the array.										*
	**************************************/
	vNode.setAttribute("latestCount", latestCount);
	vNode.selectSingleNode("DATERUN").text = textToDate("NOW", "ISO");
	var topNode = _valetParking.selectSingleNode("RECENTSEARCHES");
	if (topNode.childNodes.length > 0) topNode.insertBefore(vNode, topNode.childNodes[0]);
	else topNode.appendChild(vNode);

	topNode.setAttribute("dirty", "true");
			
	/**************************************
	*		Do not exceed the max searches		*
	**************************************/
	var vNodes = topNode.selectNodes("RECENTSEARCH");
	for (var vv=vNodes.length; vv > _valetParkingMax; vv--) topNode.removeChild(vNodes[vv-1]);

	var displayDiv = $('quicksearchControl_RECENT');
	if (displayDiv) displayDiv.innerHTML = topNode.transformNode(searchPageFormats.XMLDocument);
}

/**************************************
*				User asked to rerun a search	*
**************************************/
function runRecentSearch(searchID)
{
	var rNode = _valetParking.selectSingleNode("//RECENTSEARCH[@created=\"" + searchID + "\"]/SEARCH");
	if (!rNode) return;
	//genericNewPod(frameName, windowID, podLabel, params, title)
	var linkid = rNode.parentNode.getAttribute("created");
	var params = 'p1=' + escape("recentid=" + linkid);
	var windowTitle = rNode.selectSingleNode("TOOLTIP").text;
	genericNewPod("searchframe", linkid, windowTitle, params, windowTitle);
}

/******************************************
*			User would like to delete one of		*
*			the recent searches.								*
******************************************/
function deleteRecentSearch(searchID)
{
	var rNode = _valetParking.selectSingleNode("//RECENTSEARCH[@created=\"" + searchID + "\"]");
	if (rNode)
	{
		rNode.parentNode.removeChild(rNode);
		var displayDiv = $('quicksearchControl_RECENT');
		if (displayDiv)	displayDiv.innerHTML = _valetParking.selectSingleNode("RECENTSEARCHES").transformNode(searchPageFormats.XMLDocument);
	}
	_valetParking.selectSingleNode("//RECENTSEARCHES").setAttribute("dirty", "true");
}

/******************************************
*			User would like to rename one of		*
*			the recent searches.								*
******************************************/
function renameRecentSearch(searchID)
{
	var rNode = _valetParking.selectSingleNode("//RECENTSEARCH[@created=\"" + searchID + "\"]");
	if (rNode)
	{
		var tNode = rNode.selectSingleNode(".//SEARCH/TOOLTIP");
		pObj = new Object();
		if (tNode) pObj.value = tNode.text;
		else pObj.value = "";
		pObj.prompt = "What do you want to call this search?";
		pObj.searchid = searchID;
		pObj.wnd = window;
		_ModalDiv.arguments = pObj;		
	  _ModalDiv.showPopup("promptForResponse.htm", 300, 200, "Rename search", renameRecentSearch_Callback);

		var displayDiv = $('quicksearchControl_RECENT');
		if (displayDiv)	displayDiv.innerHTML = _valetParking.selectSingleNode("RECENTSEARCHES").transformNode(searchPageFormats.XMLDocument);
	}
}

function renameRecentSearch_Callback(retValue)
{
	if (retValue == "OK")
	{		
		var pObj = 	window.top._ModalDiv.arguments;	
		if (pObj.value.length > 0)
		{
			var rNode = _valetParking.selectSingleNode("//RECENTSEARCH[@created=\"" + pObj.searchid + "\"]/SEARCH");
			if (rNode)
			{
				var tNode = rNode.selectSingleNode(".//TOOLTIP");
				if (tNode)
				{
					tNode.text = pObj.value;
					_valetParking.selectSingleNode("//RECENTSEARCHES").setAttribute("dirty", "true");
					var displayDiv = $('quicksearchControl_RECENT');
					if (displayDiv)	displayDiv.innerHTML = _valetParking.selectSingleNode("RECENTSEARCHES").transformNode(searchPageFormats.XMLDocument);
				}
			}
		}
	}
}

