// Type checking functions

function isFunction(a) {
    return typeof a == 'function';
}
function isNull(a) {
    return typeof a == 'object' && !a;
}
function isNumber(a) {
    return typeof a == 'number' && isFinite(a);
}
function isObject(a) {
    return (typeof a == 'object' && !!a) || isFunction(a);
}
function isString(a) {
    return typeof a == 'string';
}
function isUndefined(a) {
    return typeof a == 'undefined';
} 
function isDefined(a) {
    return typeof a != 'undefined';
} 

/*********************************************************************/

	var gXMLhttp;

/*********************************************************************/

	function XMLhttpInit ()
		{
		try {
			if (!gXMLhttp)
				gXMLhttp = new XMLHttpRequest();
			}
		catch(e)
			{
			}


		try {
			if (!gXMLhttp)
				gXMLhttp = new ActiveXObject("Msxml2.XMLHTTP");
			}
		catch(e)
			{
			}


		try {
			if (!gXMLhttp)
				gXMLhttp = new ActiveXObject("Microsoft.XMLHTTP");
			}
		catch(e)
			{
			}

		}

/*********************************************************************/

	function XMLhttpGetValue (xmlPayload, tag, notFoundValue)
		{
		var result = xmlPayload.getElementsByTagName ("qdbapi");

		for (var p = 0; p < result[0].childNodes.length; ++p)
			{
			if (result[0].childNodes[p].nodeType != 1)
				continue;
			
			var nodeName	= result[0].childNodes[p].nodeName;
			var nodeValue	= "";
			
			if (result[0].childNodes[p].hasChildNodes)
				nodeValue = result[0].childNodes[p].childNodes[0].nodeValue;

			if (nodeName == tag)
				return nodeValue;
			}

		if (notFoundValue)
			return notFoundValue;

		return null;
		}


/**********************************************************************/

	function urlencode (s)		// urlencodes a string, including + and / which built-in escape ignores
		{
		var r = escape (s);
		var q = r.replace (/\+/g, "%2B")

		return q.replace (/\//g, "%2F");
		}


/************************/
/*	Cookie functions	*/
/************************/


/**************************/

	function getNextPair(s, offset)
		{
		var e = s.indexOf ("; ", offset);
		if (e == -1)
			return s.substring (offset);
		return s.substring (offset, e);
		}

/**************************/

	function hasCookie(cookieName)
		{
		var nameLen    = cookieName.length;
		var allcookies = document.cookie;
		var cLen       = allcookies.length;

		var i = 0

		while (i < cLen)
			{
			var pair = getNextPair (allcookies, i);

			if (pair.substring (0,nameLen) == cookieName)		// just check for prefix
				{
				return 1;
				}

			i = i + pair.length + 2;
			}
		return 0;
		}

/**************************/

	function cpair (cname, cvalue)
		{
		this.name  = cname;
		this.value = cvalue;
		}

/**************************/

	function StringToSubValueArray (s, varArray)
		{
		var pairArray = s.split ("~");

		for (var i=0; i < pairArray.length; ++i)
			{
			var pair = pairArray[i];
			var epos = pair.indexOf ("^");
			if (epos != -1)
				{
				var subname = pair.substring (0, epos);
				
				if (pair.length > epos+1)
					{
					var subval  = pair.substring (epos+1, pair.length);
					varArray[i] = new cpair (subname, subval);
					}
				}
			}

		}

/**************************/

	function SubValueArrayToString (varArray)
		{
		var s = "";

		for (var i=0; i < varArray.length; ++i)
			{
			if (varArray[i].value != "")
				s += varArray[i].name + "^" + varArray[i].value + "~";
			}
		
		return s;
		}


/**************************/

	function getCookieValue(cookieName, cookieSubName)
		{
		var allcookies = document.cookie;

		var pos = allcookies.indexOf (cookieName + "=");
		if (pos != -1)
			{
			var start = pos + cookieName.length + 1;
			var end   = allcookies.indexOf (";", start);
			if (end == -1)
				end = allcookies.length;

			var cookieVal = unescape (allcookies.substring(start,end));

			if (!cookieSubName)
				return cookieVal;

			var varArray = new Array();
			
			StringToSubValueArray (cookieVal, varArray);

			for (var i=0; i < varArray.length; ++i)
				{
				if (varArray[i].name == cookieSubName)
					return varArray[i].value;
				}
			}

		return "";
		}

/**************************/

	function SetCookie (cookieName, cookieValue, minutesToExpiration)
		{
		ExpireCookie (cookieName);		// migrates old cookies that were in the root path
		
		var d = new Date();
		d.setTime (d.getTime() + (minutesToExpiration * 60 * 1000));

		var c = cookieName + "=" + cookieValue + "; expires=" + d.toGMTString();
						
		document.cookie = c;
		}

/**************************/

	function SetSubCookie (cookieName, cookieSubName, cookieSubValue, minutesToExpiration)
		{
		var cookieFullValue = getCookieValue (cookieName);

		var varArray = new Array();
		
		StringToSubValueArray (cookieFullValue, varArray);

		var found = false;

		for (var i=0; i < varArray.length; ++i)
			{
			if (varArray[i].name == cookieSubName)
				{
				varArray[i].value = cookieSubValue;
				found = true;
				}
			}

		if (!found)
			varArray[varArray.length] = new cpair (cookieSubName, cookieSubValue);

		SetCookie (cookieName, SubValueArrayToString(varArray),  minutesToExpiration);
		}

/**************************/

	function GetLocalVar (varName)
		{
		if (!varName)
			return null;

		return getCookieValue ("localVars", varName);
		}

/**************************/

	function SetLocalVar (varName, varValue)
		{
		SetSubCookie ("localVars", varName, varValue, 60*24*100);
		}

/**************************/

	function ExpireCookie (cookieName)
		{
		var d = new Date();
		d.setTime (d.getTime() - (60 * 1000));

		// expire both in the root path and the default path

		var c = cookieName + "=expiring; path=/; expires=" + d.toGMTString();					
		document.cookie = c;

		c = cookieName + "=expiring; expires=" + d.toGMTString();					
		document.cookie = c;
		}

/**************************/

	function ExpireAllCookies ()
		{
		var cnameArray = new Array();
		
		var allcookies = document.cookie;

		var pairArray = allcookies.split (";");

		for (var i=0; i < pairArray.length; ++i)
			{
			var pair = pairArray[i];
			var epos = pair.indexOf ("=");
			if (epos == -1)
				break;

			cnameArray[i] = pair.substring (0, epos);
			}

		for (var k=0; k < cnameArray.length; ++k)
			{
			ExpireCookie (cnameArray[k]);
			defaultStatus = cnameArray[k];
			}
		}



/**************************/


	function getElementBy (elemTag)		// name OR id
		{
		var elem = document.getElementById (elemTag);
		
		if (elem)
			return elem;

		var elems = document.getElementsByName (elemTag);

		if (elems.length > 0)
			return elems[0];
		
		return null;
		}

	function toElem (elemParam)
		{
		if (!elemParam)
			return elemParam;

		if (isString(elemParam))
			return getElementBy (elemParam);
		else
			return elemParam;
		}

	function closeElem(elemName)
		{
		var elem = toElem (elemName);
		
		if (elem)
			elem.style.display = "none";
		}

	function openElem(elemName)
		{
		var elem = toElem (elemName);
		
		if (elem)
			elem.style.display = "";
		}

	function openCloseElem(elemName, doOpen)
		{
		var elem = toElem (elemName);
		
		if (!elem)
			return false;
		
		if (doOpen)
			elem.style.display = "";
		else
			elem.style.display = "none";
		
		return doOpen;
		}

	function togOpenCloseElem(elemName)
		{
		var elem = toElem (elemName);

		if (!elem)
			return false;

		if (elem.style.display == "")
			elem.style.display = "none";
		else
			elem.style.display = "";
		
		return (elem.style.display != "none");
		}
			


	function hideShowElem(elemName, doShow)
		{
		var elem = toElem (elemName);
		
		if (!elem)
			return;

		if (doShow)
			elem.style.visibility = "visible";
		else
			elem.style.visibility = "hidden";

		}

	function hideElem(elemName)
		{
		var elem = toElem (elemName);
		
		if (!elem)
			return;

		elem.style.visibility = "hidden";
		}

	function showElem(elemName)
		{
		var elem = toElem (elemName);
		
		if (!elem)
			return;

		elem.style.visibility = "visible";
		}

	function GetMenuIndex (menu, val)
		{
		for (var n = 0; n < menu.length; n++)
			{
			if (menu[n].value == val)
				return n;
			}
		return -1;
		}

/****************************************************

	SetInnerHTML

*/
function SetInnerHTML (el, newHTML)
	{
	var elem = toElem (el);	
	if (elem)
		elem.innerHTML = newHTML;
	}

/****************************************************

	SetFocus

*/
function SetFocus (el)
	{
	var elem = toElem (el);
	
	if (!elem)
		return;

	elem.focus();
	}

/****************************************************

	HasFocus

*/
function HasFocus (el)
	{
	var elem = toElem (el);
	
	if (!elem)
		return false;

	return (document.activeElement == elem);
	}

/****************************************************

	SetPosition

*/
function SetPosition (el, position)
	{
	var elem = toElem (el);
	
	if (elem)
		elem.style.position = position;
	}

/****************************************************

	SetStyleVisibility

*/
function SetStyleVisibility (el, value)
	{
	var elem = toElem (el);
	
	if (elem)
		elem.style.visibility = value;
	}

/****************************************************

	SetStyleDisplay

*/
function SetStyleDisplay (el, value)
	{
	var elem = toElem (el);
	
	if (elem)
		elem.style.display = value;
	}

/****************************************************

	GetNthOptionValue

		Gets the value of an option in a select.
*/
function GetNthOptionValue (sel, n)
	{
	if (!sel)
		return null;

	if (sel.type != "select-one" && sel.type != "select")
		return null;

	if (sel.options.length <= n)
		return null;
		
	var value = sel.options[n].value;
	if (value == "")
		return sel.options[n].text;

	return value;
	}

/****************************************************

	IsChecked

*/
function IsChecked (el)
	{
	var elem = toElem (el);

	if (!elem)
		return false;

	return elem.checked;
	}

/****************************************************

	GetValue

		Gets the value of an element.
		Works for normal elements and for "select" elements
*/
function GetValue (el)
	{
	var elem = toElem (el);

	if (!elem)
		return "";

	if (elem.type == "select-one" || elem.type == "select")
		{
		if (elem.selectedIndex >= 0)
			{
			var value = elem.options[elem.selectedIndex].value;
			if (value == "")
				return elem.options[elem.selectedIndex].text;

			return value;
			}
		else
			return "";
		}

	return elem.value;
	}

/****************************************************

	GetRadioValue

		Gets the value of a radio element.  
		This could be merged into GetValue but it's a little tricky since GetValue deals
		with scalars and radio buttons are vectors.
*/
function GetRadioValue (el)
	{
	var elems = el;

	if (isString(el))
		elems = document.getElementsByName (el);

	if (!elems || elems.length == 0)
		return "";

	var numItems = elems.length;
	
	for (var i = 0; i < numItems; ++i)
		{
		var rb = elems[i];
		if (rb && rb.checked)
			{
			return rb.value;
			}
		}
	return "";
	}

/****************************************************

	SetValue

		Sets the value of an element.
		For "select" elements (dropdown menus) searches the
		menu for an option with the appropriate value.
*/
function SetValue (el, val)
	{
	var elem = toElem (el);

	if (!elem)
		return false;

	if (elem.type == "select-one" || elem.type == "select")
		{
		var len = elem.options.length;

		for (var n = 0; n < len; ++n)
			{
			var elemVal = elem[n].value;
			
			if ((elemVal == val && elemVal != "") || (elemVal == "" && elem[n].text == val))
				{
				elem.selectedIndex = n;
				return true;
				}
			}
		
		elem.selectedIndex = 0;
		}
	else if (elem.type == "checkbox" || elem.type == "radio")
		{
		elem.checked = val;
		return true;
		}
	else
		{
		elem.value = val;
		return true;
		}

	return false;
	}

/****************************************************

	AddOption

		Adds a new option element to a menu (select element)
*/
function AddOption (menu, i, text, val)
	{
	menu.options[i] = new Option (text, val)
	}

/****************************************************

	PrepMenu

		Function unclear
*/
function PrepMenu (menu, n)
	{
	menu.disabled=true;

	for (var m = menu.options.length-1; m >= 0; m--)
		menu.options[m] = null;
		
	menu.options[0] = new Option ("                             ", "X")
	for (var k=1; k <= n; k++)
		menu.options[k] = new Option ("", "X")

	menu.selectedIndex = 0;		// Otherwise it will be -1 for Netscape
	menu.disabled=false;
	}

/****************************************************

	oldSelectedIndex

		Global variables for FixIfDividerSelected
*/

var oldSelectedIndex = -1;

/****************************************************

	CaptureSelectState

		Works with FixIfDividerSelected.  Must be called
		from the body onclick event.
*/
function CaptureSelectState()
	{
	var srcElem;

	if (window.event)
		srcElem = window.event.srcElement;
	else
		return;

	if (srcElem.type == "select-one" || srcElem.type == "select")
		oldSelectedIndex = srcElem.selectedIndex;
	else
		oldSelectedIndex = -1;
	}

/****************************************************

	FixIfDividerSelected

		If the user selects a disabled item from a select
		this routine will return the selectIndex to the
		previously selected item.  For this to work though,
		CaptureSelectState() must be called from the body
		onclick event.
*/
function FixIfDividerSelected (sel)
	{
	if (!sel)
		return false;

	var opt = sel.options[sel.selectedIndex];
	if (opt.disabled)
		{
		if (oldSelectedIndex != -1)
			sel.selectedIndex = oldSelectedIndex;
		
		else if (sel.selectedIndex > 0)
			sel.selectedIndex--;
		else if (sel.selectedIndex < sel.options.length-1)
			sel.selectedIndex++;
		else
			sel.selectedIndex = -1;

		return true;
		}

	return false;
	}

/****************************************************

	SetFocusToFirstElem

		Sets the focus to the first form element
*/
function SetFocusToFirstElem (form)
	{
	var numElems	= form.elements.length;
	var	i;

	for (i=0; i < numElems; i++)
		{
		var t = form.elements[i].type;

		var visibility = true;
		var	elem  = form.elements[i];

		// Fix for issue #7132.
		if (elem.name == "_newowner")
			continue;
	
		if (!IsReallyVisible (elem))
			continue;

		if (t=="select" ||
			t=="select-one" ||
			t=="radio" ||
			t=="checkbox" ||
			t=="textarea" ||
			t=="text") 

			{
			if (t == "textarea" || t == "text")
				form.elements[i].select();

			form.elements[i].focus();
			break;
			}
		}
	}

/****************************************************

	IsReallyVisible

		An item is only really visible if it and all its
		containing items are visible.
*/
function IsReallyVisible (el)
	{
	var elem = toElem (el);	
	if (!elem)
		return;

	var k;	// just to be paranoid so we don't hang anyone's browser

	for (k = 0; elem && k < 100; ++k)
		{
		if (elem.style && (elem.style.display == "none" || elem.style.visibility == "hidden"))
			return false;

		elem = elem.parentElement;
		}

	return true;
	}

/****************************************************

	RefreshElem

		Needed on iemac to make sure selects that were set
		while invisible, now display correctly
*/
function RefreshElem (e)
	{
	if (!e)
		return;

	var wasDisabled = e.disabled;

	e.disabled = true;
	e.selectedIndex = e.selectedIndex;
	e.disabled = wasDisabled;
	}

/****************************************************

	Types and Variables for BuildSelInfoArray

*/
function SelectInfo (formIndex, elemIndex)
	{
	this.formIndex		= formIndex;
	this.elemIndex		= elemIndex;
	}

var selinfo			= new Array();
var hiddenSelects	= new Array();

/****************************************************

	BuildSelInfoArray

*/
function BuildSelInfoArray()
	{
	var	arrayIsBusted = false;
	
	// always check it

	for (var k = 0; k < selinfo.length; ++k)
		{
		var sinfo = selinfo[k];
		var elem  = document.forms[sinfo.formIndex].elements[sinfo.elemIndex];

		if (!elem || (elem.type != "select" && elem.type != "select-one"))
			{
			arrayIsBusted = true;
			break;
			}
		}

	if (selinfo.length && !arrayIsBusted)
		return;
	
	// rebuild it

	var si = 0;

	selinfo.length = 0;

	for (var i = 0; i < document.forms.length; ++i)
		{
		var form = document.forms[i];

		for (var j = 0; j < form.elements.length; ++j)
			{
			var elem = form.elements[j];
			var t = elem.type;

			if (t == "select" || t == "select-one")
				{
				selinfo[si] = new SelectInfo (i, j);
				++si;
				}
			}

		}
	
	}



/****************************************************

	HideSelects

*/
function HideSelects (menu)
	{
	if (navigator.appName == "Netscape")
		return;

	BuildSelInfoArray();

	var bmenu = GetBox (menu);

	var hi = 0;
	
	for (var i = 0; i < selinfo.length; ++i)
		{
		var sinfo = selinfo[i];
		var elem  = document.forms[sinfo.formIndex].elements[sinfo.elemIndex];

		if (!elem || (elem.type != "select" && elem.type != "select-one"))
			{
			continue;
			}

		if (elem.style.visibility != "hidden")
			{			
			var b = GetBox (elem);
			
			InsetBox (b, 2);

			if (!(b.left > bmenu.right || b.right < bmenu.left || b.top > bmenu.bottom || b.bottom < bmenu.top))
				{
				elem.style.visibility = "hidden";
				hiddenSelects[hi] = new SelectInfo (sinfo.formIndex, sinfo.elemIndex);
				++hi;
				}
			}
		}
	
	}

/****************************************************

	ShowSelects

*/
function ShowSelects()
	{
	if (hiddenSelects.length == 0)
		return;

	for (var i = 0; i < hiddenSelects.length; ++i)
		{
		var sinfo = hiddenSelects[i];
		var elem  = document.forms[sinfo.formIndex].elements[sinfo.elemIndex];
		
		if (elem && (elem.type == "select" || elem.type == "select-one"))
			elem.style.visibility = "visible";
		}
	
	hiddenSelects.length = 0;
	}


/****************************************************

	OverlapsSelect

*/
function OverlapsSelect (elem)
	{
	BuildSelInfoArray();

	var bmenu = GetBox (elem);

	for (var i = 0; i < selinfo.length; ++i)
		{
		var sinfo = selinfo[i];
		var elem  = document.forms[sinfo.formIndex].elements[sinfo.elemIndex];

		if (elem.style.visibility != "hidden")
			{			
			var b = GetBox (elem);
			
			InsetBox (b, 2);

			if (!(b.left > bmenu.right || b.right < bmenu.left || b.top > bmenu.bottom || b.bottom < bmenu.top))
				{
				return true;
				}
			}
		}
	
	return false;
	}


/****************************************************

	DoElementsOverlap

*/
function DoElementsOverlap (elem1, elem2)
	{
	var box1 = GetBox (toElem (elem1));
	var box2 = GetBox (toElem (elem2));

	return DoBoxesOverlap (box1, box2);
	}

/****************************************************

	DoBoxesOverlap

*/
function DoBoxesOverlap (box1, box2)
	{
	if (box1.left > box2.right || box1.right < box2.left || box1.top > box2.bottom || box1.bottom < box2.top)
		{
		return false;
		}
	
	return true;
	}

/****************************************************

	HiliteDelite

*/
function HiliteDeliteLink (el, doHilite, hiliteColor, deliteColor)
	{
	var elem = toElem (el);
	
	if (!elem)
		return;

	if (doHilite)
		elem.style.color = hiliteColor;
	else
		elem.style.color = deliteColor;
	}

/****************************************************

	Hilite

*/
function Hilite (elem)
	{
	prevBackgroundColor = elem.style.backgroundColor;
	elem.style.backgroundColor = "#E1E1C2";
	}

/****************************************************

	Delite

*/
function Delite (elem)
	{
	elem.style.backgroundColor = prevBackgroundColor;
	}


/****************************************************

	Center

		Centers an element (usually a div) in the window

*/
function Center (el)
	{
	var elem = toElem (el);

	elem.style.position = "absolute";

	PositionX (elem, "center", 0);
	PositionY (elem, "center", 0);
	}

/****************************************************

	PositionX

		Positions an element horizontally (usually a div) in the window
*/
function PositionX (el, relativeTo, offset)
	{
	var elem = toElem (el);

	if (!elem)
		return;

	docLeft  = DocLeft();
	docRight = DocRight();

	elemWid  = elem.offsetWidth;

	if (relativeTo == "center")
		{
		docMid = (docLeft + docRight) / 2;
		elem.style.left = docMid - (elemWid / 2) + offset;
		}
	else if (relativeTo == "right")
		{
		elem.style.left = docRight - (elemWid + offset);
		}
	else
		{
		elem.style.left = docLeft + offset;
		}
	}

/****************************************************

	PositionY

		Positions an element vertically (usually a div) in the window
*/
function PositionY (el, relativeTo, offset)
	{
	var elem = toElem (el);

	if (!elem)
		return;

	var docTop  = DocTop();
	var docBot  = DocBot();

	elemHei  = elem.offsetHeight;

	if (relativeTo == "center")
		{
		docMid = (docTop + docBot) / 2;
		elem.style.top = docMid - (elemHei / 2) + offset;
		}
	else if (relativeTo == "centerButAtMost")
		{
		docMid = (docTop + docBot) / 2;
		var newtop = docMid - (elemHei / 2)
		if (newtop > offset)
			newtop = offset;
			
		elem.style.top = newtop;
		}
	else if (relativeTo == "bottom")
		{
		var newTop = docBot - (elemHei + offset);
		if (elem.style.top != newTop)
			elem.style.top = newTop;
		}
	else
		{
		elem.style.top = docTop + offset;
		}
	}


/****************************************************

	PositionBottomButNot

		Positions an element at the bottom of a window but
		not above existing elements
*/
function PositionBottomButNot (el, offset, bodyHeight)
	{
	var elem = toElem (el);

	if (!elem)
		return;

	var docTop  = DocTop();
	var docBot  = DocBot();

	elemHei  = elem.offsetHeight;

	var newTop = docBot - (elemHei + offset);

	if (newTop > bodyHeight)
		{
		elem.style.top = newTop;
		}
	else
		{
		elem.style.top = bodyHeight;
		}
	}

/****************************************************

	IsOnScreen

		Returns true if the element is entirely on the screen (not scrolled off)
*/
function IsOnScreen (elem)
	{
	if (!elem)
		return false;

	var b = GetBox (elem);
	
	if (b.top		>= DocTop()		&&
		b.bottom	<= DocBot()		&&
		b.left		>= DocLeft()	&&
		b.right		<= DocRight())
		{
		return true;
		}

	return false;
	}

/****************************************************

	ScrollPageToShow

		Scrolls the page so that the element is in the window
*/
function ScrollPageToShow (elem)
	{
	if (!elem)
		return;

	var b = GetBox (elem);

	var newtop  = b.top  - ((DocBot() - DocTop()) >> 2);
	var newleft = b.left - ((DocRight() - DocLeft()) >> 2);
	
	if (newtop < 0)
		newtop = 0;
	if (newleft < 0)
		newleft = 0;

	// first scroll vertically

	if (document.body.clientHeight)
		document.body.scrollTop = newtop;
	else
		window.pageYOffset = newtop;

	if (IsOnScreen (elem))
		return;

	// second scroll horizontally

	if (document.body.clientHeight)
		document.body.scrollLeft = newleft;
	else
		window.pageXOffset = newleft;

	}

//****************************************************

function	WindowWidth ()
	{
	if (document.body.clientWidth)
		return document.body.clientWidth;

	return window.innerWidth;
	}		

//****************************************************

function	WindowHeight ()
	{
	if (document.body.clientHeight)
		return document.body.clientHeight;

	return window.innerHeight;
	}		

//****************************************************

function	DocTop ()
	{
	if (document.body.clientHeight)
		return document.body.scrollTop;

	return window.pageYOffset;
	}		

//****************************************************

function	DocBot ()
	{
	if (document.body.clientHeight)
		return document.body.scrollTop + document.body.clientHeight;

	return window.pageYOffset + window.innerHeight;
	}		

//****************************************************

function	DocLeft ()
	{
	if (document.body.clientHeight)
		return document.body.scrollLeft;

	return window.pageXOffset;
	}		

//****************************************************

function	DocRight ()
	{
	if (document.body.clientHeight)
		return document.body.scrollLeft + document.body.clientWidth;

	return window.pageXOffset + window.innerWidth;
	}		

/****************************************************

	InsetBox

*/
function InsetBox (b, val)
	{
	b.left += val;
	b.right -= val;
	b.top += val;
	b.bottom -= val;
	}

//****************************************************

		var currentMenuSet = 0;
		var currentMenu;


/****************************************************

	GetBox

*/
function GetBox (elem)
	{
	var result = new Object;
	
	var left	= 0;
	var top		= 0;

	for (var item = elem; item; item = item.offsetParent)
		{
		left += item.offsetLeft;
		top  += item.offsetTop;
		
		if (item.style.borderLeftWidth)
			{
			var bwid = parseInt (item.style.borderLeftWidth);
			if (!isNaN (bwid))
				left += bwid;
			}
		}
	
	result.left		= left;
	result.top		= top;
	result.right	= left + elem.offsetWidth;
	result.bottom	= top  + elem.offsetHeight;

	return result;
	}

/****************************************************

	Box2Text

*/
function Box2Text (box)
	{
	return "l:" + box.left + "t:" + box.top + "r:" + box.right + "b:" + box.bottom;
	}

/****************************************************

	RepositionMenu

*/
function RepositionMenu (elem, base, positioning)
	{
	var b = GetBox(base);

	if (b.left > 400 || positioning == "belowRight")
		{
		elem.style.left = b.right - elem.offsetWidth - 4;
		elem.style.top  = b.bottom;
		}
	else if (b.bottom > 100 && positioning != "below")
		{
		elem.style.left = b.right;
		elem.style.top  = b.top - 20;
		}
	else
		{
		elem.style.left = b.left;
		elem.style.top  = b.bottom;
		}
	}

/****************************************************

	RepositionMenuByMouse

*/
function RepositionMenuByMouse (menu)
	{
	var x = GetMouseX();
	var y = GetMouseY();

	var wid = menu.offsetWidth;
	var hei = menu.offsetHeight;

	var windowRight = document.body.clientWidth;

	if (x + wid > windowRight)
		{
		menu.style.left = x - wid;
		}
	else
		menu.style.left = x + 4;

	menu.style.width = wid;

	menu.style.top	= y + 1;
	}

/****************************************************

	ShowMenu

		Displays a menu on the screen.

			base		- the element (or ID of the element) next to which the menu should appear

							"mousePosition" is a special value that says to position relative to the current
							  mouse position - most useful for right-click popups

			clicked		- whether the menu is being shown in response to a click or a mouseOver
			menuSet		- a number of the set of menus to which this menu belongs
			positioning	- how the menu should be positioned relative to the "base"
							
							"auto" is the default and implies dynamic positioning
							"below" means that the menu should always appear below the base

			noFocus		- if present, means that no attempt should be made to set the focus to the "base"

*/
function ShowMenu (menuID, base, clicked, menuSet, positioning, noFocus)
	{
	var menu = document.getElementById (menuID);

	var baseElem = toElem (base);

	if (menu && (clicked || currentMenuSet == menuSet))
		{
		var doFocus = true;

		if (noFocus)
			doFocus = false;

		if (currentMenu == menu && !clicked)
			return;
		
		HideMenus();
		
		BuildSelInfoArray();

		if (doFocus && baseElem)
			{
			if (isFunction (baseElem.focus))
				baseElem.focus();		// side effect is that it brings the window forward
			}

		menu.style.display = "";

		if (base == "mousePosition")
			RepositionMenuByMouse (menu);
		else	
			RepositionMenu (menu, baseElem, positioning);


		HideSelects(menu);
		menu.style.visibility = "visible";
		currentMenuSet = menuSet;
		currentMenu = menu;
		}
	}


/****************************************************

	HideMenus

		Hides any open menu
*/
function HideMenus()
	{
	if (currentMenu)
		{
		currentMenu.style.visibility = "hidden";
		currentMenu.style.display = "none";
		}
	
	currentMenu = null;
	currentMenuSet = 0;

	ShowSelects();
	}

//****************************************************
function SetCurrentMenuElem (elem, menuSet)
	{
	if (elem)
		{
		HideMenus ();
	
		currentMenu = elem;
		currentMenuSet = menuSet;
		}
	}

//****************************************************

function ShowPopupDiv (elem, pos, persist)
	{
	var popup = toElem (elem);

	if (popup)
		{
		openElem (popup);
		
		PositionX (popup, "center", 0);
		
		if (pos == "centerY")
			PositionY (popup, "center", 0);
		else
			PositionY (popup, "top", 100);

		showElem (popup);
		
		if (!persist || persist == false)
			{
			SetCurrentMenuElem (popup, 0);
			}
		HideSelects(popup);
		}
	
	return popup;
	}


//****************************************************
var lastEventX = 0;
var lastEventY = 0;

//****************************************************
function CaptureEventInfo(e)
	{
	lastEventX = GetMouseX(e);
	lastEventY = GetMouseY(e);
	}

//****************************************************
function GetMouseX(e)
	{
	if (!e) var e = window.event;

	if (!e)
		return lastEventX;
	else if (e.pageX)
		{
		return e.pageX;
		}
	else if (e.clientX)
		{
		return e.clientX + document.body.scrollLeft;
		}
	else if (e.offsetX)
		{
		return -e.offsetX + 1;
		}

	return 0;
	}

//****************************************************
function GetMouseY(e)
	{
	if (!e) var e = window.event;

	if (!e)
		return lastEventY;
	else 	if (e.pageY)
		return e.pageY;
	else if (e.clientY)
		return e.clientY + document.body.scrollTop;
	else if (e.offsetY)
		return -e.offsetY + 1;
	
	return 0;
	}


//****************************************************
function IsClickInElem (el, event)
	{
	var elem = toElem (el);
	if (elem)
		{

		var	x = GetMouseX(event);
		var	y = GetMouseY(event);
		
		var b = GetBox(elem);

//	alert ("xy:  " + x + " " + y + "   tlbr:  " + b.top + "  " + b.left + "  " + b.bottom + "  " + b.right);

		if (b.left < x && b.right > x && b.top < y && b.bottom > y)
			{
			return true;
			}
		}
	return false;
	}


//****************************************************
function IsClickInOpenMenu (event)
	{
	if (!currentMenu)
		return false;

	return IsClickInElem (currentMenu, event);
	}

//****************************************************
function GetTarget (e)
	{
	var targ;

	if (!e) var e = window.event;

	if (e)
		{
		if (e.target) targ = e.target;
		else if (e.srcElement) targ = e.srcElement;
		}

	return targ;
	}

//****************************************************
//
//		GetTargetTag
//
//			Always returns lowercase tagname
//
function GetTargetTag (e)
	{
	return GetTagName (GetTarget(e));
	}

//****************************************************
//
//		GetTagName
//
//			Always returns lowercase tagname
//
function GetTagName (elem)
	{
	if (elem && elem.tagName)
		return elem.tagName.toLowerCase();

	return "";
	}

//*********************************************************************************
//
// The functions below implement Array.splice for browsers that don't yet support it
//

// This adds an easy way to redefine methods on objects based on the Function object
Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

if (!isFunction(Array.prototype.splice)) {
    Array.method('splice', function (s, d) {
        var max = Math.max,
            min = Math.min,
            a = [], // The return value array
            e,  // element
            i = max(arguments.length - 2, 0),   // insert count
            k = 0,
            l = this.length,
            n,  // new length
            v,  // delta
            x;  // shift count
 
        s = s || 0;
        if (s < 0) {
            s += l;
        }
        s = max(min(s, l), 0);  // start point
        d = max(min(isNumber(d) ? d : l, l - s), 0);    // delete count
        v = i - d;
        n = l + v;
        while (k < d) {
            e = this[s + k];
            if (!isUndefined(e)) {
                a[k] = e;
            }
            k += 1;
        }
        x = l - s - d;
        if (v < 0) {
            k = s + i;
            while (x) {
                this[k] = this[k - v];
                k += 1;
                x -= 1;
            }
            this.length = n;
        } else if (v > 0) {
            k = 1;
            while (x) {
                this[n - k] = this[l - k];
                k += 1;
                x -= 1;
            }
        }
        for (k = 0; k < i; ++k) {
            this[s + k] = arguments[k + 2];
        }
        return a;
    });
}

//
//	End of routines to provide Array.splice
//*********************************************************************************

function LooksLikeEmailAddress (email)
	{
	var atpos = email.indexOf("@");
	var dotpos = email.lastIndexOf(".");
	var len = email.length;

	var tld;
	
	if (len > dotpos+1)
		tld = email.substring (dotpos+1, len);

	if (len == 0)
		{
		return false;
		}
	else if (atpos == -1 || dotpos == -1 || dotpos < atpos || dotpos == atpos + 1 || len < 5 || dotpos >= len-2)
		{
		return false;
		}
	else if (tld.length >= 3 && tld.toUpperCase() != "COM" &&
                                        tld.toUpperCase() != "ORG"		&&
                                        tld.toUpperCase() != "NET"		&&
                                        tld.toUpperCase() != "EDU"		&&
                                        tld.toUpperCase() != "GOV"		&&
										tld.toUpperCase() != "BIZ"		&&
										tld.toUpperCase() != "PRO"		&&
										tld.toUpperCase() != "AERO"		&&
										tld.toUpperCase() != "INFO"		&&
										tld.toUpperCase() != "NAME"		&&
										tld.toUpperCase() != "COOP"		&&
										tld.toUpperCase() != "MUSEUM"	&&
                                        tld.toUpperCase() != "MIL")
		{
		return false;
		}

	return true;
	}


/*********************************************************************/

function Commify (val)
	{
	if (isNumber(val))
		val = val.toString();

	var a, b;

	for (var k = 3; val.length > k; k = k + 4)
		{
		a = val.substr(0, val.length-k);
		b = val.substr(val.length-k, k);
		val = a + "," + b;
		}

	return val;
	}

/*********************************************************************/

	var gMonthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

/*********************************************************************/

function FormatDateTime (val)
	{
	var	s;

	s = gMonthNames[val.getMonth()] + " " + val.getDate() + ", " + val.getFullYear();

	return s;
	}