/******************************************************************************************************
DEBUGGING FUNCTIONS
******************************************************************************************************/
function appendToLog(msg,boolClear) {
	var e=document.getElementById("debug_console");
	if (e) {
		(boolClear) ? e.innerHTML=msg+"<br>" : e.innerHTML +=msg+"<br>";
	};
};

/******************************************************************************************************
TEXT FUNCTIONS
******************************************************************************************************/
function getSalt(n) {
	var arChars="0123456789abcdefghijklmnopqrstuvwxyz";
	var s="";
	for (var i=0;i<n;i++) {
		r=Math.floor(Math.random()*36);
		s +=arChars.charAt(r);
	};
	return(s);
};

String.prototype.trim=function() {
	return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
};

String.prototype.deleteCharAt=function(index) {
	if (index==0) return(this.substring(1));
	return this.substring(0,index) + this.substring(index+1);
};

String.prototype.startsWith=function(str){
    return (this.toUpperCase().indexOf(str.toUpperCase())===0);
}

String.prototype.equalsIgnoreCase=function(str){
    return (this.toUpperCase()==str.toUpperCase());
}

String.prototype.setLength=function(len){
	if (len>this.length) return(this);
	return(this.substring(0,len));
}

function replaceAllSubstrings(str,target,replace) 
{
	if (replace.toUpperCase().indexOf(target.toUpperCase())>=0) {
		alert("The replacement: "+replace+" includes the target: "+target);
		return(str);
	};
	
	do {
		Int1=str.indexOf(target);
		if (Int1>=0) str=str.substring(0,Int1)+replace+str.substring((Int1+target.length),str.length);
	} while (Int1>=0);
	return(str);
};

function quote(str) {
	return("\""+str+"\"");
};

function getSubStringArray(Src,ADelimit,ARemoveQuotes)
{
	var Str1="";
	var Len=Src.length;
	var cDelimiters	=0;
	var LastIndex=0;
	var InQuotes=false;

	if (Len==0) return("");
	
	//initialize array for recording location of commas
	var arDelimit=new Array(Len+1);

	//get locations of delimiters
	for (var i=0;i<Len;i++) {
		var Ch=Src.charAt(i);
		if (Ch=='\x22') {
			InQuotes=!InQuotes;
		}
		else {
			if ((Ch==ADelimit) && (!InQuotes)) {
				arDelimit[cDelimiters]=i;
				cDelimiters++;
			};
		};
	};

	//fake a delimiter at the end of the string
	arDelimit[cDelimiters]=Len;
	cDelimiters++;
	
	var arString=new Array(cDelimiters);
	
	for (var i=0;i<cDelimiters;i++)	
	{
		Str1="";
		
		if (arDelimit[i]>LastIndex) 
		{
			Str1 +=Src.substring(LastIndex,arDelimit[i]);

			//remove quotes
			if (ARemoveQuotes) {
				if (Str1.length>0) {
					if (Str1.charAt(0)=="\x22") {
						Str1=Str1.deleteCharAt(0);
						if ((Str1.length>0) && (Str1.charAt(Str1.length-1)=='\x22')) {
							Str1=Str1.setLength(Str1.length-1);
						};
					};
				}
			};

			//trim
			Str1=Str1.trim();
			//while ((Str1.length>0) && (Str1.charAt(0)==' ')) Str1=Str1.deleteCharAt(0);
			//while ((Str1.length>0) && (Str1.charAt(Str1.length-1)==' ')) Str1=Str1.setLength(Str1.length-1);

			arString[i]=Str1;
		}
		else {
			arString[i]="";
		}

		LastIndex=arDelimit[i]+1;
	};

	if (false) {
		String1="";
		for (var i=0;i<arString.length;i++) String1 +=arString[i]+"\n";
		alert("arString="+String1);
	};

	return(arString);
};

//returns the element at the given index from the delimited array in str
function getElement(str,index,delimiter)
{
	arString=getSubStringArray(str,delimiter,true);
	if (index>=arString.length) {
		alert("index out of bounds in getElement("+str+","+index+","+delimiter+")");
		return("");
	};
	return(arString[index]);
};

//returns the value of the element with the given name in a delimited string of the form "name1=value2|name2=value2..."
function getElementValue(str,name,delimiter)
{
	var arElement=getSubstringArray(str,delimiter,true);
	for (var i=0;i<arElement.length;i++) {
		var arString=getSubstringArray(arElement[i],"=",true);
		if (arString.length>0) {
			if (arString[0].equalsIgnoreCase("name")) {
				var strValue="";
				if (arString.length>1) strValue=arString[1];
				return(strValue);
			};
		};
	};

	return("");
};

function addElement(str,name,Delimiter)
{
	if (!Delimiter) Delimiter=",";
	if (str.length>0) str +=Delimiter;
	str +=name;
	return(str);
};

function padLeft(str,ch,len)
{
	var strResult=str.toString();
	while (strResult.length<len) strResult=ch + strResult;
	return(strResult);
};

function formatDate(dt,Pattern)
{
	//set a default pattern used to pass time to Aspect
	var strResult="MM-dd-yyyy HH:mm:ss z";
	if (Pattern) strResult=Pattern;
	
	strResult=replaceAllSubstrings(strResult,"MM",padLeft(dt.getMonth()+1,"0",2));
	strResult=replaceAllSubstrings(strResult,"dd",padLeft(dt.getDate(),"0",2));
	strResult=replaceAllSubstrings(strResult,"yyyy",padLeft(dt.getFullYear(),"0",4));
	strResult=replaceAllSubstrings(strResult,"HH",padLeft(dt.getHours(),"0",2));
	strResult=replaceAllSubstrings(strResult,"mm",padLeft(dt.getMinutes(),"0",2));
	strResult=replaceAllSubstrings(strResult,"ss",padLeft(dt.getSeconds(),"0",2));
	
	switch(dt.getTimezoneOffset()) {
		case 300: strResult=replaceAllSubstrings(strResult,"tz","(EST)"); break;
		case 360: strResult=replaceAllSubstrings(strResult,"tz","(CST)"); break;
		case 420: strResult=replaceAllSubstrings(strResult,"tz","(MST)"); break;
		case 480: strResult=replaceAllSubstrings(strResult,"tz","(PST)"); break;
		default: strResult=replaceAllSubstrings(strResult,"tz","GMT-"+padLeft((dt.getTimezoneOffset()/60),"0",2)+"00");
	};
	
	strResult=replaceAllSubstrings(strResult,"z","-"+padLeft((dt.getTimezoneOffset()/60),"0",2)+"00");
	return(strResult);
};

function formatNumber(n,Pattern) 
{
	if (typeof(n).equalsIgnoreCase("string")) {
		Num=parseFloat(n);
	}
	else if ((typeof(n)=="int") || (typeof(n)=="float")) {
		Num=n;
	}
	else {
		return("Unrecognized type: "+n+" type: "+typeof(n));
	};
	
	//for right now, just look for a decimal in the pattern and return two digits if there's a decimal.
	//Otherwise return no digits after the decimal
	var strResult="";
	if (Pattern.indexOf(".")>=0) {
		strResult=Num.toFixed(2);
	}
	else {
		strResult=Num.toFixed(0);
	};
	
	return(strResult);
};

//Replaces special characters with tokens and vice versa
function tokenizeSpecialChars(str,bool) 
{
	//alert("tokenizeSpecialChars "+bool+" "+str);
	if (bool) {
		var strResult=replaceAllSubstrings(str,"&","\\\\am"+"p\\\\");
		strResult=replaceAllSubstrings(strResult,"+","\\\\pl"+"us\\\\");
		strResult=replaceAllSubstrings(strResult,"\"","\\\\qu"+"ot\\\\");
		strResult=replaceAllSubstrings(strResult,"'","\\\\ap"+"os\\\\");
		strResult=replaceAllSubstrings(strResult,"#","\\\\pou"+"nd\\\\");
	}
	else {
		var strResult=replaceAllSubstrings(str,"\\\\am"+"p\\\\","&");
		strResult=replaceAllSubstrings(strResult,"\\\\pl"+"us\\\\","+");
		strResult=replaceAllSubstrings(strResult,"\\\\qu"+"ot\\\\","\"");
		strResult=replaceAllSubstrings(strResult,"\\\\ap"+"os\\\\","'");
		strResult=replaceAllSubstrings(strResult,"\\\\pou"+"nd\\\\","#");

		strResult=replaceAllSubstrings(strResult,"//am"+"p//","&");
		strResult=replaceAllSubstrings(strResult,"//pl"+"us//","+");
		strResult=replaceAllSubstrings(strResult,"//qu"+"ot//","\"");
		strResult=replaceAllSubstrings(strResult,"//ap"+"os//","'");
		strResult=replaceAllSubstrings(strResult,"//pou"+"nd//","#");
	};
	
	//alert("strResult="+strResult);
	return(strResult);
};

//Use this in place of Boolean(value).  IE and Firefox handle booleans differently.
function boolVal(s) {
	if(!s) return(false);
	if(s=="true") return(true);
	if(s==true) return(true);
	return(false);
};

function getBrowserName() {
	return(navigator.appName);
};

function isVisible(aitem) {
	var e=document.getElementById(aitem);
	if(!e) e=aitem;
	if(!e.nodeName) return;

	if (e) {
		var strOn="block";
		var strOff="none";
		
		//if it's a table row, need to use inline or table-row
		if (e.nodeName.equalsIgnoreCase("tr")) {
			strOn="inline";
			if (getBrowserName().toUpperCase().indexOf("NETSCAPE")>=0) strOn="table-row";
		};
		//alert("e.style.display="+e.style.display);
		//get the current display status
		if (getBrowserName().toUpperCase().indexOf("EXPLORER")>=0) {
			//Internet Explorer
			if ((e.style.display.length==0) || (e.style.display.equalsIgnoreCase(strOff))) {return(false);} else {return(true);};
		}
		else {
			//Everything else
			if ((e.style.display.length==0) || (e.style.display.equalsIgnoreCase(strOff))) {return(false);}	else {return(true);};
		};
	}
	else {
		alert("Error: isVisible cannot find element with ID="+aitem);
	};
};

function toggleVisible(aitem) {
	var e=document.getElementById(aitem);
	if(!e) e=aitem;
	if(!e.nodeName) return;
	
	if (e) {
		var strOn="block";
		var strOff="none";
		
		//if it's a table row, need to use inline or table-row
		if (e.nodeName.equalsIgnoreCase("tr")) {
			strOn="inline";
			if (getBrowserName().toUpperCase().indexOf("NETSCAPE")>=0) {
				strOn="table-row";
			};
		};
		
		//get the current display status
		if (getBrowserName().toUpperCase().indexOf("EXPLORER")>=0) {
			//Internet Explorer
			setVisible(aitem,(e.style.display==strOff));
		}
		else {
			//Everything else
			setVisible(aitem,(e.style.display==strOff));
		};
	}
	else {
		//alert("Error: toggleVisible cannot find element with ID="+strID);
	};
};

function setVisible(aitem,boolVisible)
{
	var e=document.getElementById(aitem);
	if(!e) e=aitem;
	if(!e.nodeName) return;
	
	if (e) {
		var strOn="block";
		var strOff="none";
		
		//if it's a table row, need to use inline or table-row
		if (e.nodeName.equalsIgnoreCase("tr")) {
			strOn="inline";
			if (getBrowserName().toUpperCase().indexOf("NETSCAPE")>=0) strOn="table-row";
		};
		
		//set the display on/off
		if (getBrowserName().toUpperCase().indexOf("EXPLORER")>=0) {
			//Internet Explorer
			if (boolVisible) {
				e.style.display=strOn;
				e.display=strOn;
			}
			else {
				e.style.display=strOff;
				e.display=strOff;
			};
		}
		else {
			//Everything else
			(boolVisible) ? e.style.display=strOn : e.style.display=strOff;
		};
	}
	else {
		//alert("Error: setVisible cannot find element with ID="+strID);
	};
};

/******************************************************************************************************
XMLHTTPREQUEST FUNCTIONS
******************************************************************************************************/
function getxmlHttpRequestObject()
{
	var req=false;

	// For Safari, Firefox, and other non-MS browsers
	if (window.XMLHttpRequest) {
		try {req=new XMLHttpRequest();} 
		catch (e) {req=false;}
	} 
	else if (window.ActiveXObject) {
		// For Internet Explorer on Windows
		try {
			req=new ActiveXObject("Msxml2.XMLHTTP");
		} 
		catch (e) {
			try {req=new ActiveXObject("Microsoft.XMLHTTP");} 
			catch (e) {req=false;}
		}
	}
	
	return(req);
};

//Executes a synchrounous request for content and returns the result.  This method waits until the content is received before returning.
//The asynchInclude function can be used to make an asynchronous request.
function getxmlHttpRequest(url)
{
	var req=getxmlHttpRequestObject();

	if (req) {
		if(url.indexOf("127.0.0.1")>=0) {
			url +="&random="+Math.floor(Math.random()*99999999);
			url +="&HashID={AspectHashID}";
		};
		req.open('GET',url, false);
		if (getBrowserName().toUpperCase().indexOf("EXPLORER")<0) {
			req.timeout=60000; //not recognized by IE (IE6 at least)
		};
		req.setRequestHeader("Accept-Encoding","gzip");
		req.send(null);
		return(req.responseText);
	} 
	else {
		return("Sorry, your browser does not support XMLHTTPRequest objects. This page requires Internet Explorer 5 or better for Windows, or Firefox for any system, or Safari. Other compatible browsers may also exist.");
	}
	
	return("Error in getxmlHttpRequest: "+url);
};

//Entry for asynchInclude.  Used to allow recursion in asynchIncludesub so that an include can be tried a 2nd time if an empty string is returned
function asynchInclude(element,url,func,errfunc) {
	//for some reason, href="#" gets mangled in firefox.  The # symbol is replaced with a goofy url.  This prevents that from happening.
	var strUrl=replaceAllSubstrings(url,"href=\"#\"","href=\"%"+"23\"");
	strUrl=replaceAllSubstrings(url,"href='#'","href='%"+"23'");
	//appendToLog("asynchInclude: "+url);
	asynchIncludesub(0,element,strUrl,func,errfunc);
};

//Does an asynchronous request to set the content for the given element.  This method allows the content of an element to be set
//without waiting for the server to return the content.  
function asynchIncludesub(count,element,url,func,errfunc)
{
	var req=getxmlHttpRequestObject();

	if (req) {
		var strUrl=url;
		if(strUrl.indexOf("127.0.0.1")>=0) {
			strUrl +="&random="+Math.floor(Math.random()*99999999);
			strUrl +="&HashID={AspectHashID}";
		};
		req.onreadystatechange=function()
		{ 
			//appendToLog("req.readyState="+req.readyState);
			if(req.readyState==4) {
				if (req.status==200) {
					if (element!=null) {
						//alert("setting innerHTML "+req.responseText);
						var str=req.responseText;
						
						if ((str.length==0) && (count==0)) {
							//alert("asynchInclude getting "+url);
							asynchIncludesub(1,element,url,func,errfunc);
							return;
							//str=clientSideInclude(element,url);
						};

						element.innerHTML=str;
						element.setAttribute("updating",false);
					};
					
					if (func) eval(func);
				}
				else {
					//Remember: Browser security prevents request across different domains
					appendToLog("asynchInclude error: "+req.status+" url: "+url);
					//alert("asynchInclude error: "+req.status+" url: "+url);
					//alert("server returned status: "+req.status);
					if (element!=null) {
						element.setAttribute("updating",false);
						element.setAttribute("counter",60);
					};
					if (errfunc) eval(errfunc);
				};
			};
		}; 
		
		try {
			//appendToLog("req.open: "+strUrl);
			req.open('GET',strUrl, true);
		}
		catch(e) {
			if (errfunc) eval(errfunc);
		};

		if (getBrowserName().toUpperCase().indexOf("EXPLORER")<0) {
			req.timeout=120000; //not recognized by IE (IE6 at least)
		};
		req.setRequestHeader("Accept-Encoding","gzip");
		req.send(null);
	} 
	else {
		element.innerHTML="Sorry, your browser does not support XMLHTTPRequest objects. This page requires Internet Explorer 5 or better for Windows, or Firefox for any system, or Safari. Other compatible browsers may also exist.";
	}
};

/******************************************************************************************************
MISCELLANEOUS FUNCTIONS
******************************************************************************************************/
/* Sets the contents of a select box given a string of options in the form option1=value1|option2=value2 */
function setOptions(eSelect,strOptions) {
  var options=eSelect.options;
  options.length=0;
  arCollection=getSubStringArray(strOptions,"|",true);
  for(var i=0;i<arCollection.length;i++) {
    arPair=getSubStringArray(arCollection[i],"=",true);
    options[options.length]=new Option(arPair[1],arPair[0],false,false);
  };
};

/******************************************************************************************************
FUNCTIONS USED FOR DROP-DOWN MENUS
******************************************************************************************************/
var timerDropDownMenu=null;

// open drop-down list
function menuOpen(id) {	
	menuCancelTimeout();
	menuCloseAll();
	setVisible(id,true);
}

// close drop-down list
function menuCloseAll() {
	var arMenu=document.getElementsByTagName("div");
	for (var i=0;i<arMenu.length;i++) {
		if (arMenu[i].getAttribute("isMenu")) setVisible(arMenu[i],false);
	};
}

//go close timer
function menuSetTimeout()	{
	//The timeout here is important.  If it is too short, the menu will disappear in IE before the mouse is moved to a selection
	timerDropDownMenu=window.setTimeout("menuCloseAll()",500);
}

// cancel close timer
function menuCancelTimeout() {
	if(timerDropDownMenu) {
		window.clearTimeout(timerDropDownMenu);
		timerDropDownMenu=null;
	}
}

/******************************************************************************************************
FUNCTIONS USED FOR TABBED DIALOG
******************************************************************************************************/
function setDialogTabStyle(aCell,aLink,bSelected) {
	if (bSelected) {
		aLink.style.color="black";
		aLink.style.fontWeight="bold";
		aCell.style.backgroundColor="#48f";
	}
	else {
		aLink.style.color="black";
		aLink.style.fontWeight="normal";
		aCell.style.backgroundColor="#bdf";
	};
};

//Searches for tabbed dialogs and sets the style of the default tab
function initializeTabbedDialogs() {
//appendToLog("initializeTabbedDialogs");
	//initialize all tabbed dialogs
	var arTable=document.getElementsByTagName("TABLE");
	for (var i=0;i<arTable.length;i++) {
		if(!boolVal(arTable[i].getAttribute("tabsInitialized")))
		{
			var bAllTabsLoaded=true;
			var bInitialized=false;
			var arTableRow=arTable[i].getElementsByTagName("tr");
			for (var j=0;j<arTableRow.length;j++) {
				var arTableCell=arTableRow[j].getElementsByTagName("td");
				for (var k=0;k<arTableCell.length;k++) {
					var arChild=arTableCell[k].childNodes;
					for (var l=0;l<arChild.length;l++) {
						if ((arChild[l].nodeName.equalsIgnoreCase("A")) || (arChild[l].nodeName.equalsIgnoreCase("SPAN"))) {
							if(arChild[l].onclick) {
								var str1=String(arChild[l].onclick);
								if(str1.toUpperCase().indexOf("SHOWTAB")>=0) {
									var n1=str1.toUpperCase().indexOf("SHOWTAB(");
									var n2=str1.indexOf(")",n1);
									var str2=str1.substring(n1+8,n2);
									var arStr=getSubStringArray(str2,",",true);
									var arTabName=getSubStringArray(replaceAllSubstrings(replaceAllSubstrings(arStr[1],"'",""),"\"",""),"|");
									if(bInitialized) {
										setDialogTabStyle(arTableCell[j],arChild[l],false);
										for(var cTab=0;cTab<arTabName.length;cTab++) setVisible(arTabName[cTab],false);
										//appendToLog(strTabName+" not visible");
									}
									else {
										setDialogTabStyle(arTableCell[j],arChild[l],true);
										for(var cTab=0;cTab<arTabName.length;cTab++) setVisible(arTabName[cTab],true);
										//appendToLog(strTabName+" visible");
										bInitialized=true;
									};
									for(var cTab=0;cTab<arTabName.length;cTab++) {
										if (!document.getElementById(arTabName[cTab])) bAllTabsLoaded=false;
									};
								};
							};
						};
					};
				};
			};
			arTable[i].setAttribute("tabsInitialized",bAllTabsLoaded);
		};
	};

	//initialize all select boxes
	var arSelect=document.getElementsByTagName("SELECT");
	for (i=0;i<arSelect.length;i++) {
		if(!boolVal(arSelect[i].getAttribute("tabsInitialized"))) {
			for (var j=0;j<arSelect[i].options.length;j++) {
				if (document.getElementById(arSelect[i].options[j].value)) {
					setVisible(arSelect[i].options[j].value,arSelect[i].options[j].selected);
				};
			};
			arSelect[i].setAttribute("tabsInitialized",true);
		};
	};
	
	//initialize all drop-down menus
	menuCloseAll();
};

function showTab(eClicked,aName) {
	if((eClicked.nodeName.equalsIgnoreCase("a")) || (eClicked.nodeName.equalsIgnoreCase("span")))
	{
		//get the table the hyperlink belongs to
		var eTable=null;
		var eDiv=null;
		var e=eClicked.parentNode;
		while ((e) && (!eTable) && (!eDiv)) {
			if(e.nodeName.equalsIgnoreCase("table")) eTable=e;
			if(e.nodeName.equalsIgnoreCase("div")) eDiv=e;
			e=e.parentNode;
		};
		
		if((!eTable) && (!eDiv)) {
			appendToLog("Cannot locate table containing tabs or div containing menu");
			return;
		};

		if(eTable)
		{
			//hide all divs and set the font for the selected/unselected tabs
			var arTableRow=eTable.getElementsByTagName("tr");
			for (var i=0;i<arTableRow.length;i++) {
				var arTableCell=arTableRow[i].getElementsByTagName("td");
				for (var j=0;j<arTableCell.length;j++) {
					var arChild=arTableCell[j].childNodes;
					for (var k=0;k<arChild.length;k++) {
						if ((arChild[k].nodeName.equalsIgnoreCase("A")) || (arChild[k].nodeName.equalsIgnoreCase("SPAN")))
						{
							//hide all divs except the selected one
							var str1=String(arChild[k].onclick);
							var n1=str1.toUpperCase().indexOf("SHOWTAB(");
							var n2=str1.indexOf(")",n1);
							var str2=str1.substring(n1+8,n2);
							var arStr=getSubStringArray(str2,",",true);
							var arTabName=getSubStringArray(replaceAllSubstrings(replaceAllSubstrings(arStr[1],"'",""),"\"",""),"|");
							for(var cTab=0;cTab<arTabName.length;cTab++) {
								setVisible(arTabName[cTab],("|"+aName).toUpperCase().indexOf("|"+arTabName[cTab].toUpperCase())>=0);
							};
							
							//appendToLog("setVisible: "+strTabName+" "+strTabName.equalsIgnoreCase(aName));
							setDialogTabStyle(arTableCell[j],arChild[k],arChild[k]==eClicked);
							if(false) {
								//set the font for the tab
								if (arChild[k]==eClicked) {
									arChild[k].style.color="black";
									arChild[k].style.fontWeight="bold";
									arTableCell[j].style.backgroundColor="#48f";
								}
								else {
									arChild[k].style.color="black";
									arChild[k].style.fontWeight="normal";
									arTableCell[j].style.backgroundColor="#bdf";
								};
							};
						};
					};
				};
			};
		}
		else {
			//the control is a drop-down menu, so hide the menu and show the tab
			menuCloseAll();
			var arLink=eDiv.getElementsByTagName("a");
			for (var i=0;i<arLink.length;i++) {
				var str1=String(arLink[i].onclick);
				var n1=str1.toUpperCase().indexOf("SHOWTAB(");
				var n2=str1.indexOf(")",n1);
				var str2=str1.substring(n1+8,n2);
				var arStr=getSubStringArray(str2,",",true);
				var strTabName=replaceAllSubstrings(replaceAllSubstrings(arStr[1],"'",""),"\"","");
				setVisible(strTabName,strTabName.equalsIgnoreCase(aName));
			};
		};
	}
	else if (eClicked.nodeName.equalsIgnoreCase("select")) 
	{
		//the contol is a select box - so show the selected tab
		for (var i=0;i<eClicked.options.length;i++) {
			if (document.getElementById(eClicked.options[i].value)) {
				setVisible(eClicked.options[i].value,eClicked.options[i].selected);
			};
		};
	};
};

/******************************************************************************************************
TOOLTIP FUNCTIONS
******************************************************************************************************/
function hideTooltip(e)
{
	if (e) e.style.display="none";
};

function showTooltip(e,Msg,OffsetX,OffsetY,MaxWidth)
{
	//disable tooltips for Microsoft version 6 (which shows as version 4 in getBrowserVersion) because the tooltips are not z-indexed properly
	//if ((getBrowserName().startsWith("Microsoft")) && (getBrowserVersion().startsWith("4.0"))) return;
	
	strMsg=replaceAllSubstrings(Msg,"||q"+"uot||","&#34;");
	strMsg=replaceAllSubstrings(strMsg,"||a"+"pos||","&#39;");
	strMsg=replaceAllSubstrings(strMsg,"%"+"3c","<");
	strMsg=replaceAllSubstrings(strMsg,"%"+"3e",">");

	if (OffsetX==0) OffsetX=10;
	if (OffsetY==0) OffsetY=10;
	
	if ((MaxWidth==null) || (MaxWidth==0)) MaxWidth=400;
	
	div=document.getElementById("tooltip");
	
	if (div==null) {
		tagBody=document.getElementsByTagName('BODY')[0];
		div=document.createElement('div');
		div.id="tooltip";
		div.className="tooltip"; //apparently setAttrubute("class"...) doesn't work in IE
		div.onclick=Function("javascript:hideTooltip(this);");
		tagBody.appendChild(div);		
	};

	div.innerHTML=strMsg;

	//don't use the event (e) if just hiding with a blank message.  This allows the showTooltip method to be called
	//without an event if it needs to be cleared manually.  One example of this is when a div is made visible under
	//a tooltip that is being displayed.  
	if (strMsg.length>0) {
		W=div.offsetWidth;
		H=div.offsetHeight;
		X=e.clientX;
		Y=e.clientY;
		Top	=Y+OffsetY;
		Left=X+OffsetX;
		div.style.border="1pt solid";
		div.style.top=Top+"px";
		div.style.left=Left+"px";

		if (div.offsetWidth>MaxWidth) {
			div.style.width=MaxWidth+"px";
		};
		
		div.style.padding="5px";
		//div.style.border=5;
	}
	else {
		div.style.padding=0;
		//alert("border="+div.style.border);
		div.style.border="none";
		div.style.width="auto";
	};

	//div.innerHTML="W:"+W+" H:"+H+" ScreenX:"+e.screenX+" ScreenY:"+e.screenY+" clientX="+e.clientX+" clientY="+e.clientY;
};

/******************************************************************************************************
Cookie functions
******************************************************************************************************/
function setCookie(name,value,exp_y,exp_m,exp_d,path,domain,secure) {
	var sCookie=name + "=" + escape(value);

	if (exp_y) {
		var expires=new Date(exp_y,exp_m,exp_d);
		sCookie +="; expires=" + expires.toGMTString();
	}

	if (path) sCookie +="; path=" + escape(path);
	if (domain) sCookie +="; domain=" + escape(domain);
	if (secure) sCookie +="; secure";
	document.cookie=sCookie;
};

function getCookie(cookie_name) {
	var sResult=document.cookie.match ('(^|;) ?' + cookie_name + '=([^;]*)(;|$)');
	if(sResult) {
		return(unescape(sResult[2]));
	}
	else {
		return null;
	};
}

function eraseCookie(name) {
	setCookie(name,"",-1);
}


