//-----------------------------------------------------------------------------------------
// Copyright (c) 2005-2010 by NetQuarry, Inc.
// All rights reserved.
//
// This file contains confidential NetQuarry trade secret information.
// Use, disclosure, or copying without written consent is strictly prohibited.
//
// www.netquarry.com
//-----------------------------------------------------------------------------------------

var	cssFile = "styles/EAPDefault.css";
var nameDelim = ':';    // '$';
var eapUtilVer = 662;

BrowserScan();

function BrowserScan()
{
	var	agent = navigator.userAgent.toLowerCase();
	
	window.is_opera = (agent.indexOf('opera') >= 0);
	window.is_opera9 = (agent.indexOf('opera/9') >= 0);
	window.is_ie = (typeof(document.all) == 'object' && !window.is_opera);
	window.ie_ver = (!window.is_ie) ? 0 : (window.XMLHttpRequest) ? 7 : 6;
	window.is_ff = (agent.indexOf('firefox') >= 0);
	window.is_mozilla = (agent.indexOf('mozilla') >= 0);
	window.is_chrome = (agent.indexOf('chrome') >= 0);
	window.is_safari = (!window.is_chrome && agent.indexOf('safari') >= 0);
	window.is_safari4 = (window.is_safari && agent.indexOf('applewebkit/4') >= 0);
	window.is_webkit = (agent.indexOf('applewebkit') >= 0);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsIE()
{
	return (is_ie);
}

//-----------------------------------------------------------------------------------------
// Returns the IE version if IE, else zero.
//-----------------------------------------------------------------------------------------
function IEVer()
{
	return (window.ie_ver);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsOpera()
{
	return (window.is_opera);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsOpera9()
{
	return (window.is_opera9);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsFirefox()
{
	return (window.is_ff);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsMozilla()
{
	return (window.is_mozilla);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsSafari()
{
	return (window.is_safari);
}

function IsSafariPre5()
{
	return (window.is_safari4);
}

function IsAppleWebKit()
{
	return (window.is_webkit);
}

function IsChrome()
{
	return (window.is_chrome);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function SetCssClass(item, name)
{
	if (item) 
	{
		item.setAttribute(IsIE() ? 'className' : 'class', name);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetCssClass(item)
{
	return ((item) ? item.getAttribute(IsIE() ? 'className' : 'class') : '');
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ReplaceCssClass(item, oldClass, newClass)
{
	var c = GetCssClass(item);
	
	if (c == oldClass)
	{
		c = newClass;
	}
	else
	{
		c = ' ' + c + ' ';
		
		//--- Remove old class if present.
		
		if (c.indexOf(' ' + oldClass + ' ') >= 0)
		{
			c = ' ' + Trim(StrReplace(c, ' ' + oldClass + ' ', ' '), true, true) + ' ';
		}
		
		//--- Add new class if not present.

		if (c.indexOf(' ' + newClass + ' ') < 0)
		{
			c += newClass;
		}
		
		c = Trim(c, true, true);
	}
	
	SetCssClass(item, c);
}

function HasCssClass(item, name)
{
    return ((' ' + GetCssClass(item) + ' ').indexOf(' ' + name + ' ') >= 0);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function RemoveCssClass(item, oldClass)
{
	var c = GetCssClass(item);
	
	if (c == oldClass)
	{
		SetCssClass(item, '');
	}
	else
	{
		c = ' ' + c + ' ';
		if (c.indexOf(' ' + oldClass + ' ') >= 0)
		{
			c = StrReplace(c, ' ' + oldClass + ' ', ' ');	// Remove
			SetCssClass(item, Trim(c, true, true));
		}
	}
}

//-----------------------------------------------------------------------------------------
function IsString(s)
{
    return (typeof s == 'string');
}

// If item is a string, assume it's an element id and lookup element, else rtn item.
function GetElement(item, win)
{
	if (!win) win = window;
	return (item != null && typeof item == 'string') ? win.document.getElementById(item) : item;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsVisible(ctrl)
{
	var vis = false;
	
	// Maybe it's an id.
	
	if (typeof ctrl == 'string') 
	{
		ctrl = (ctrl != '') ? document.getElementById(ctrl) : null;
	}
	
	var elType = ElementType(ctrl);
	
	if (elType == 'tbody' || elType == 'html' || elType == 'body')
	{
		vis = true;
	}
	else if (!ctrl || elType == 'hidden')
	{
		vis = false;
	}
	else if (ctrl.offsetWidth > 0 || (IsAppleWebKit() && (elType == 'dbginfo' || elType == 'tr' || elType == 'a')))
	{
		//--- tr/dbginfo/a offsetWidth always 0 in Safari.
		
		var style = ctrl.style;
		
		vis = (!style || (style.visibility != 'hidden' && style.display != 'none'));
	}
	
	return (vis);
}

//-----------------------------------------------------------------------------------------
function IsEnabled(ctrl)
{
	if (!ctrl) return false;
	if (ctrl.disabled) return false;

	if (IsSafari())
	{
		if (ctrl.readOnly) return false;
	}
	else
	{
		if (ctrl.getAttribute && (ctrl.getAttribute('disabled') || ctrl.getAttribute('readonly'))) { return false };
	}

	return true;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsVisibleAndEnabled(ctrl)
{
	var bSafari = IsAppleWebKit();
	var dis = (!ctrl) ? true : (bSafari) ? ctrl.disabled : ctrl.getAttribute('disabled');
	var readonly = (!ctrl) ? true : (bSafari) ? ctrl.readOnly : ctrl.getAttribute('readonly');
	var elType = ElementType(ctrl);
	
	if (elType == 'tbody' || elType == 'html' || elType == 'body')
	{
		return true;
	}
	else if (!ctrl || !IsVisible(ctrl) || ctrl.disabled || dis || readonly)
	{
		return false;
	}
	else if (!ctrl.parentElement)
	{
		return true;
	}
	else
	{
		return IsVisibleAndEnabled(ctrl.parentElement);
	}
}

//-----------------------------------------------------------------------------------------
// Inverse of .Net HttpUtility.UrlEncode()
//-----------------------------------------------------------------------------------------
function UrlDecode(s)
{
	if (s)
		return decodeURIComponent(s.replace(/\+/g,' '));
	else
		return (s);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsKeyArrow(key)
{
	return (key >= 37 && key <= 40);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsKeyCtrl(key)
{
	return (key < 32 || IsKeyArrow(key));
}

//-----------------------------------------------------------------------------------------
// Browser-independed event listener adder.
function AddListener(item, evt, fn)
{
	if (item.addEventListener)
	{
		item.addEventListener(evt, fn, true);
	}
	else if (item.attachEvent)
	{
		if (evt == 'focus') evt = 'focusin';
		evt = 'on' + evt;
		item.attachEvent(evt, fn);
	}
}

//-----------------------------------------------------------------------------------------
// Browser-independed event listener remover.
function RemoveListener(item, evt, fn)
{
	if (item.removeEventListener)
	{
		item.removeEventListener(evt, fn, true);
	}
	else if (item.detachEvent)
	{
		if (evt == 'focus') evt = 'focusin';
		evt = 'on' + evt;
		item.detachEvent(evt, fn);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function Trim(s, trimLeft, trimRight)
{
	if (arguments.length == 1)
	{
		trimLeft = true;
		trimRight = true;
	}
	
	if (s)
	{
		if (trimLeft) s = s.trimLeft();
		if (trimRight) s = s.trimRight();
	}
	
	return (s);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
String.prototype.trim = function () 
{
	return this.trimLeft().trimRight();
};

String.prototype.trimLeft = function ()
{
	return this.replace(/^\s*/, '');
};

String.prototype.trimRight = function ()
{
	return this.replace(/\s*$/, '');
};

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FixDigits(n, digits)
{
	n = '0' + n;
	n = n.substr(n.length-digits);
			
	return (n);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetFormElements()
{
	var els = null;
	var frm = document.forms[0];
	
	if (frm) els = frm.elements;
	
	return (els);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ThrowError(code, source, message)
{
	throw new Error(code, message + '\r\n' + source);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function bndLkupTxtFromBtn(btn)
{
	var pattern = /_btn$/;

	return btn.id.replace(pattern, '_txt');
}

//-----------------------------------------------------------------------------------------
function bndLkupBtnFromTxt(btn)
{
	return btn.id.replace(/_txt$/, '_btn');
}

//-----------------------------------------------------------------------------------------
function bndLkupBase(ctrl)
{
	return ctrl.id.replace(/_txt$/, '').replace(/_tbl$/, '').replace(/_btn$/, '');
}

//-----------------------------------------------------------------------------------------
// Given a bndlkup button or textbox, return the bndlkup table element.
//-----------------------------------------------------------------------------------------
function bndLkupTable(ctrl)
{
	return FindParent(ctrl, 'table');
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsBndLkup(ctrl)
{
	var is = false;
	var elType = ElementType(ctrl);
	var nm = ctrl.name;
	
	if (!nm) nm = '';
	
    var delim = nm.indexOf('$') > 0 ? '$' : ':';
    var parts = nm.split(delim);
	
	if (elType == 'image') //'button')
	{
		is = (parts[parts.length-1] == 'btn');
	}
	else if (elType == 'text')
	{
		is = (parts[parts.length-1] == 'txt');
	}
	else if (elType == 'table')
	{
		is = (ctrl.getAttribute('use') == 'bndlkup');
	}
	
	return (is);
}

//-----------------------------------------------------------------------------------------
// Returns the control's base name.  For example, a datasheet might have a field whose
// KeyName is "prod_nm", but in HTML .Net renders it as "ctl0_grid__ctl5_prod_nm".
//-----------------------------------------------------------------------------------------
function baseName(ctrl, keyname)
{
	var	nEnd = ctrl.id.lastIndexOf(keyname);
	
	return ctrl.id.substr(0, nEnd);
}

//-----------------------------------------------------------------------------------------
// #2679 - Never set title=null.
function SetTip(ctrl, tip)
{
	if (ctrl)
	{
		if (tip)
			ctrl.title = tip;
		else
			ctrl.removeAttribute('title');	
	}
}

//-----------------------------------------------------------------------------------------
// Given a semi colon delimited list of field names, will return a semicolon delimited
// list of name value pairs (colon delimited) that represent the name of the field, and its value
// on the current instance of the page
//-----------------------------------------------------------------------------------------
function resolvePageInstanceValues(ctrl, keyNames)
{
    var resolvedNames='';
    var list=keyNames.split(';');
    var	ii;

    for (ii=0; ii<list.length; ii++)
    {
        var item = Trim(list[ii], true, true);
        
        //--- #5719 - Handle items resolved in prior wiz page.
        
        if (item.indexOf('=') > 0)
        {
	        resolvedNames += item + ';'
        }
        else
        {
	        var keyVal = GetSiblingValue(ctrl, item);
		    if (keyVal == null) keyVal = '';
	        resolvedNames += item + ':' + keyVal + ';'
        }
    }
    
    if (resolvedNames.length > 0)
        resolvedNames = resolvedNames.substring(0,resolvedNames.length-1);

    return resolvedNames;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function bndLkupCal(evt, btn, fmt, strs, cul, cap)
{
	if (!evt) evt = window.event;
	
	//--- BndLkup button click, we need to find the related text control.
	
	//var pattern = /_btn$/;
	var id = bndLkupTxtFromBtn(btn); //btn.id.replace(pattern, '_txt');

	//--- Constants used to configure calendar.
	
	//IMGDIR = "images/calendar/"; //"~/images/calendar/"; 
	//CELLSIZE = 28;
	//CALENDAR_TITLE = "Calendar";

	//--- Convert standard date format to a simplified version expected by the calendar.
	
	if (!fmt) fmt = 'm/d/yyyy';
	fmt = fmt.replace(/[+]/, '');
	fmt = fmt.replace(/dd/, 'd');
	fmt = fmt.replace(/M/g, 'm');		// #4901 - Support MMM and MMMM w/ (requires popcal2).
	
	//--- Dynamic localization. #1492
	
	if (strs)
	{
		var s = strs.split('|');
		
		MONTHS = new Array(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11]);	// JFMAMJJASOND
		WEEKS = new Array(s[12], s[13], s[14], s[15], s[16], s[17], s[18]);								// SunMonTueWedThuFriSat
		DATELONG = s[19];
		DATESHORT = s[20];
	}
	
	//--- Invoke the popup calendar.
	
	popCal(document.getElementById(id), 'DATEFORMAT=' + fmt, evt.clientX, evt.clientY, cul, cap);
}


//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function menuShow(menu_btn, menu_id, cascade)
{
//	event.cancelBubble = true;

	var	mnu = document.getElementById(menu_id);
	
	mnu.style.position = 'absolute';
	if (cascade)
	{
		mnu.style.top = menu_btn.offsetTop;
		mnu.style.left = event.x;
	}
	else
	{
//		var	top = menu_btn.offsetTop + menu_btn.offsetHeight;
//		var	left = menu_btn.offsetLeft + menu_btn.offsetWidth/2;
		var	top = event.y - 10;
		var	left = event.x - 10;
		
		mnu.style.top = top;
		mnu.style.left = left;
	}
		
	mnu.style.display = 'inline';
//	mnu.style.visibility = 'visible';
	
	mnu.focus();
	
//	mnu.onmouseover = menuMouseOver;
//	mnu.onmouseout = menuMouseOut;
	
//	event.cancel = true;
	
//	return false;
try
{
	var	e;
	
	for (var ii=0; ii<mnu.all.length; ii++)
	{
		e = mnu.all(ii);
//		window.status = mnu.all.length;
//		if (e.tagName.toLowerCase() == 'td')
		if (e.tagName.toLowerCase() == 'tr')
		{
			e.className = 'moremenu';
			e.onmouseover = menuOver;
			e.onmouseout = menuOut;
		}
	}
	e = mnu.all(ii);
}
catch (e)
{
}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function cancelMenu(mnu)
{
//	window.status = window.event.keyCode;
	
	if (window.event.keyCode == 27)
	{
		mnu.style.display = 'none';
//		this.releaseCapture();
		this.onmouseover = null;
		this.onmouseout = null;
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function menuOver()
{
	this.className = 'moremenuActive';
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function menuOut()
{
	this.className = 'moremenu';
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function menuToggle(menu_btn, menu_id)
{
	var	mnu = document.getElementById(menu_id);
	
	if (mnu.style.display == 'none')
//	if (mnu.style.visibility == 'hidden')
	{
		mnu.style.display = 'inline';
//		mnu.style.visibility = 'visible';
		menu_btn.innerHTML = menu_btn.innerHTML.replace(/arrow-plus.gif/, 'arrow-minus.gif');
	}
	else
	{
		mnu.style.display = 'none';
//		mnu.style.visibility = 'hidden';
		menu_btn.innerHTML = menu_btn.innerHTML.replace(/arrow-minus.gif/, 'arrow-plus.gif');
	}
	
	return false;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function menuPost(item, btn_id, direct)
{
	var	btn = document.getElementById(btn_id);
	
	if (direct)
	{
		btn.value = item.id;
	}
	else
	{
		btn.value = item.value;
	}
	
	btn.click();
	
	return false;
}

//-----------------------------------------------------------------------------------------
// Works for IE, Firefox, and Opera, but sometimes off by a pixel or two.
// If relItem is specified, only include nodes that are not common ancestors of obj and relItem.
//-----------------------------------------------------------------------------------------
function getLeft(obj, relItem)
{
	var x = 0;
	var operaPre9 = IsOpera() && !IsOpera9();
	var clientAdjust = IsAppleWebKit();
	
	if (obj)
	{
		//--- Accumulate offsets up to root (traversing offsetParent).
		
		var node = obj;
		
		do
		{
			if (node.offsetLeft) x += node.offsetLeft;
			if (clientAdjust && node.clientLeft) x += node.clientLeft;	// Compensates for border width;
			if (operaPre9) x -= node.scrollLeft;
			node = node.offsetParent;
		} while (node && (!relItem || !IsParentOf(relItem, node)));
		
		//--- Accumulate scrolls up to root (traversing parentNode).

		if (!operaPre9)		// #3564 - Also for modern Opera.
		{
			node = obj;
			
			do
			{
				if (node.scrollLeft) x -= node.scrollLeft;
				node = node.parentNode;
			} while (node && (!relItem || !IsParentOf(relItem, node)));
		}
	}

	//--- For Firefox and (maybe) Opera, the scroll information above isn't
	//--- sufficient, we also have to look on the document body.  Oddly 
	//--- enough, we add rather than subtract the scroll.

	if (!relItem && document.body && document.body.scrollLeft) x += document.body.scrollLeft;		// #674 - No, #5421 - Yes, #5688 - May be problematic w/ relItem.
	
	return (x);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetStaticTopRecursive(obj, relItem)
{
	var y = 0;

	if (!obj)
	{
		null;	// Do nothing
	}
	else if (obj.staticTop)
	{
		y = obj.staticTop;
	}
	else
	{
		var operaPre9 = IsOpera() && !IsOpera9();
		
		//--- Accumulate offsets up to root (traversing offsetParent).
		
		var node = obj;
		var x = 0;

		if (node.offsetParent)// && (!relItem || !IsParentOf(relItem, node)))
		{
			y += GetStaticTop(node.offsetParent, relItem);
			x += node.offsetParent.staticLeft;
		}

		if (node.offsetTop) y += node.offsetTop;
		if (operaPre9) y -= node.scrollTop;
		
		node.staticTop = y;
		
		if (node.offsetLeft) x += node.offsetLeft;
		if (operaPre9) x -= node.scrollLeft;
		
		node.staticLeft = x;
	}
	
	//--- For Firefox and (maybe) Opera, the scroll information above isn't
	//--- sufficient, we also have to look on the document body.  Oddly 
	//--- enough, we add rather than subtract the scroll.

//	if (document.body && document.body.scrollTop) y += document.body.scrollTop;		// #674 - No.
	
	return (y);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetStaticTop(obj)
{
	var y = 0;

	if (obj)
	{
		var node = obj;
		var x = 0;
		//var operaPre9 = IsOpera() && !IsOpera9();
		
		//--- Find closest ancestor with calculated top.
		
		while (!node.staticTop && node.offsetParent)
		{
			node.offsetParent.backLink = node;
			node = node.offsetParent;
		}
		
		//--- Get/calculate top for starting ancestor.		
		
		if (node.staticTop)
		{
			y = node.staticTop;
			x = node.staticLeft;
		}
		else
		{
			if (node.offsetTop) y += node.offsetTop;
			if (node.offsetLeft) x += node.offsetLeft;

			node.staticTop = y;
			node.staticLeft = x;
		}
		
		//--- Move back through ancestors to original node calculating 
		//--- top and storing it on each node.
		
		while (node.backLink)
		{
			node = node.backLink;
			node.offsetParent.backLink = null;

			if (node.offsetTop) y += node.offsetTop;
			if (node.offsetLeft) x += node.offsetLeft;
			
			node.staticTop = y;
			node.staticLeft = x;
		}
	}
	
	//--- For Firefox and (maybe) Opera, the scroll information above isn't
	//--- sufficient, we also have to look on the document body.  Oddly 
	//--- enough, we add rather than subtract the scroll.

//	if (document.body && document.body.scrollTop) y += document.body.scrollTop;	// #674 - No.
	
	return (y);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetStaticLeft(obj, relItem)
{
	var x = 0;

	if (!obj)
	{
		null;	// Do nothing
	}
	else if (obj.staticLeft)
	{
		x = obj.staticLeft;
	}
	else
	{
		var operaPre9 = IsOpera() && !IsOpera9();

		//--- Accumulate offsets up to root (traversing offsetParent).
		
		var node = obj;
		
		if (node.offsetParent && (!relItem || !IsParentOf(relItem, node)))
		{
			x += GetStaticLeft(node.offsetParent, relItem);
		}
		
		if (node.offsetLeft) x += node.offsetLeft;
		if (operaPre9) x -= node.scrollLeft;
		
		node.staticLeft = x;
	}

	//--- For Firefox and (maybe) Opera, the scroll information above isn't
	//--- sufficient, we also have to look on the document body.  Oddly 
	//--- enough, we add rather than subtract the scroll.

	if (document.body && document.body.scrollLeft) x += document.body.scrollLeft;	// #674 - No, #5421 - Yes.
	
	return (x);
}

//-----------------------------------------------------------------------------------------
// Works for IE, Firefox, and Opera (with special code), but sometimes off by a pixel or two.
// If relItem is specified, only include nodes that are not common ancestors of obj and relItem.
//-----------------------------------------------------------------------------------------
function getTop(obj, relItem)
{
	var y = 0;
	var operaPre9 = IsOpera() && !IsOpera9();
	var clientAdjust = IsAppleWebKit();
	
	if (obj)
	{
		//--- Accumulate offsets up to root (traversing offsetParent).
		
		var node = obj;

		do
		{
			if (node.offsetTop) y += node.offsetTop;
			if (clientAdjust && node.clientTop) y += node.clientTop;	// Compensates for border width;
			if (operaPre9) y -= node.scrollTop;
			node = node.offsetParent;
		} while (node && (!relItem || !IsParentOf(relItem, node)));
		
		//--- Accumulate scrolls up to root (traversing parentNode).

		if (!operaPre9)		// #3564 - Also for modern Opera.
		{
			node = obj;
			
			do
			{
				if (node.scrollTop) y -= node.scrollTop;
				node = node.parentNode;
			} while (node && (!relItem || !IsParentOf(relItem, node)));
		}
	}
	
	//--- For Firefox and (maybe) Opera, the scroll information above isn't
	//--- sufficient, we also have to look on the document body.  Oddly 
	//--- enough, we add rather than subtract the scroll.

	if (!relItem && document.body && document.body.scrollTop) y += document.body.scrollTop;		// #674 - No, #5421 - Yes, #5688 - May be problematic w/ relItem.

	return (y);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetRight(ctrl)
{
	var right = getLeft(ctrl) + ctrl.offsetWidth;
	
	if (ctrl.childNodes)
	{
		var ii;

		for (ii=0; ii<ctrl.childNodes.length; ii++)
		{
			var nodeRight = GetRight(ctrl.childNodes[ii]);
			
			if (nodeRight > right) right = nodeRight;
		}
	}
	
	return (right);
}

// Modified from: http://forums.asp.net/p/1127738/1779505.aspx 
// Note ready for use as of 7/29/09.
function getCoord(obj, offsetLeft, offsetTop)
{
	var orig = obj;
	var left = 0;
	var top = 0;

	if (offsetLeft) left = offsetLeft;
	if (offsetTop) top = offsetTop;
	
	if (obj.offsetParent)
	{
		left += obj.offsetLeft;
		top += obj.offsetTop;
		while (obj = obj.offsetParent)
		{
			//left += (obj.offsetLeft - obj.scrollLeft + obj.clientLeft);
			//top += (obj.offsetTop - obj.scrollTop + obj.clientTop);
			left += (obj.offsetLeft - obj.scrollLeft);
			top += (obj.offsetTop - obj.scrollTop);
			
			if (IsAppleWebKit())
			{
				if (obj.clientLeft) left += obj.clientLeft;
				if (obj.clientTop) top += obj.clientTop;
			}
			
//			if (obj.scrollLeft) left += obj.scrollLeft;
//			if (obj.scrollTop) top += obj.scrollTop;
		}
	}

	return {left:left, top:top, width: orig.offsetWidth, height: orig.offsetHeight};
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetEventKey(evt)
{
	if (!evt) evt = window.event;

	if (evt)
	{
		var cCode = (evt.keyCode) ? evt.keyCode :		// Mozilla
				((evt.charCode) ? evt.charCode :		// IE
				((evt.which) ? evt.which : 0));			// Mozilla
		return cCode; 
	}
}

// #5596 - Detect FF edit keys.
function IsEditKeyPress(evt)
{
	if (!IsFirefox())
	{
		return false;
	}
	else
	{
		var key = evt.keyCode;
		
		return (key == 46 || key == 8 || (key >= 37 && key <= 40));
	}
}


//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function dumpAttrs(item)
{
	var	s = '';
	var ii;
	
	for (ii=0; ii<item.attributes.length; ii++)
	{
		s += item.attributes[ii].name + '=' + item.attributes[ii].value + ';   ';
	}
	
	alert(s);
}


//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function findFrame(name, win)
{
	var frm = null;
	
	if (!win)
	{
		frm = findFrame(name.toLowerCase(), window.top);
	}
	else
	{
		var	ii;
		
		for (ii=0; ii<win.frames.length; ii++)
		{
			if (win.frames[ii].name.toLowerCase() == name)
			{
				frm = win.frames[ii];
			}
			else
			{
				frm = findFrame(name, win.frames[ii]);
			}
			
			if (frm) break;
		}
	}
	
	return (frm);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function notifyMopChange(mop)
{
	var frm = findFrame('toolbar');
	
	if (frm && frm.updateTab)
	{
		frm.updateTab(mop);
	}
}

//-----------------------------------------------------------------------------------------
// Purpose:	Returns the tagName of an element, or if the tagName is "input", returns
//			the Type.  In either case the return value is forced to lower case.
//-----------------------------------------------------------------------------------------
function ElementType(item, extTypes)
{
	var tag = (item) ? item.tagName : '';
	
	if (tag) tag = tag.toLowerCase();
	if (tag && tag == 'input' && item.type) tag = item.type.toLowerCase();
	if (!extTypes && (tag == 'email' || tag == 'tel' || tag == 'url' || tag == 'number')) tag = 'text';	// #6042
	
	return (tag);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function InitDetailFocus(id)
{
	var item = null;
	
	if (window.parent.initSF) 
	{
		window.parent.initSF = false;	// Parent is initializing subform, don't set focus.
	}
	else if (window.bodyLoading)
	{
		window.delayedDetailFocus = function() { InitDetailFocus(id); };	// Never set focus while loading.
	}
	else if (id)
	{
		item = document.getElementById(id);
	}
	else // #3957 - Oddly expensive. Optimized.
	{
		var	ii;
		var ctrl;
		var els = GetFormElements();
		var minTab = 10000000;

		for (ii=0; ii<els.length; ii++)
		{
			ctrl = els[ii];

			if (ctrl.tabIndex != null && ctrl.tabIndex < minTab && !ctrl.getAttribute('nofocus') && CanGetFocus(ctrl))
			{
				item = ctrl;
				minTab = ctrl.tabIndex;
			}
		}
		
		//--- #4449 - Support focus to BndLkup.
		
		var tbls = document.getElementsByTagName('table');
		
		for (ii=0; ii<tbls.length; ii++)
		{
			ctrl = tbls[ii];
			
			ctrl = SetLkupFocus(ctrl);
			if (ctrl && ctrl.tabIndex != null && ctrl.tabIndex < minTab)
			{
				item = ctrl;
				minTab = ctrl.tabIndex;
			}
		}
	}
	
	if (item) 
	{
		SetFocus(item);		// #4602 - Simplified.
	}
}

//-----------------------------------------------------------------------------------------
// #4449 - Support focus to BndLkup.
function SetLkupFocus(tbl)
{
	var	item = null;
	
	if (IsBndLkup(tbl))
	{
		var txt = document.getElementById(bndLkupBase(tbl) + '_txt');
		var btn = document.getElementById(bndLkupBase(tbl) + '_btn');

		if (CanGetFocus(txt))
		{
			item = txt;
		}
		else if (btn)
		{
			item = btn;
		}
	}
	
	return (item);
}

//-----------------------------------------------------------------------------------------
function vsplitInit()
{
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function vsplitResize(id, width)
{
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function vsplitResizeStart(evt, vsplit, panel, pos)
{
	if (!evt) evt = window.event;

	vsplit.resizePanel = document.getElementById(panel);		// The panel we're resizing

	if (vsplit.resizePanel == null)
	{
		ThrowError(1001, 'EAPUtils::vsplitResizeStart', "VSplitter AssociatedControlID '" + panel + "' not found on page.");
	}
	
	vsplit.panelOrigWidth = vsplit.resizePanel.offsetWidth;		// The original width of the panel
	vsplit.startX = evt.screenX;								// Where the resize started
	window.vsplitter = vsplit;
	
	DragInit(vsplit, vsplitOnResize, vsplitOnResizeEnd, true);
	
	return CancelBubble(evt);									// Prevents text select on drag on Opera
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function vsplitOnResize(evt)
{
	if (!evt) evt = window.event;
	
	var vsplit = window.vsplitter;
	var nNewWidth = vsplit.panelOrigWidth + (evt.screenX - vsplit.startX);
	
	if (nNewWidth > 25 && nNewWidth < 100000)
	{
		vsplit.resizePanel.style.width = nNewWidth + 'px';	/* 4396 */
	}

	return CancelBubble(evt);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function vsplitOnResizeEnd(evt)
{
	var vsplit = window.vsplitter;

	DragTerm(vsplit, vsplitOnResize, vsplitOnResizeEnd, true);

	//--- Fire onresizeend event on item being resized.
	
//	if (vsplit.resizePanel.onresizeend) vsplit.resizePanel.onresizeend();

	//--- #3717 Persist width.

	var nm = vsplit.getAttribute('pref');
	var wid = vsplit.resizePanel.offsetWidth;

	if (nm && wid > 10) AjaxPrefSet(nm, wid);

	//--- Let the window know we've messed with stuff.
	
	if (window.resize) 
	{
		window.resize();
	}
	else if (window.onresize) 
	{
		window.onresize();
	}
}

// Clear the value for any type of editable element.
function ClearItem(item, clrLocked)
{
	//--- Figure out element type.

	item = GetElement(item);
	
	var elType = ElementType(item);
	
//	if (elType == 'table' && item.getAttribute('use') == 'bndlkup')
//	{
//	}

	//--- Clear element appropriately for its type.
	
	if (clrLocked || IsEnabled(item))
	{
		if (elType == 'text' || elType == 'select' || elType == 'hidden')
		{
			item.value = '';
		}
		else if (elType == 'checkbox')
		{
			item.checked = false;
		}
		else if (elType == 'img' && item.getAttribute('use') == 'tristate')
		{
			TriStateClear(item);
		}
	}	
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ClearNode(node, clrlck)
{
	if (!node) return;
	
	//--- Clear element.
	
	ClearItem(node, clrlck);
	
	//--- Recurse over children.
	
	var	ii;

	for (ii=0; ii<node.childNodes.length; ii++)
	{
		ClearNode(node.childNodes[ii], clrlck);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ClearChildren(parentID)
{
	var	parent = document.getElementById(parentID);
	
	if (parent)
	{
		ClearNode(parent);
	}
	else
	{
		ThrowError(1002, 'EAPUtils::ClearChildren', " parent node '" + parentID + "' not found on page.");
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function popupMenu(evt, divId)
{
	if (!evt) evt = window.event;

	var tgt = GetEventTarget(evt);
	var left = getLeft(tgt);
	var top = getTop(tgt) + tgt.offsetHeight;
	
	BubHideTooltip(evt);
	if (window.fwButtonHide) fwButtonHide();

	return (popupDiv(evt, divId, '', '', left, top));
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function popupDiv(evt, divID, cssClass, focusID, left, top)
{
	if (!evt) evt = window.event;
	
	var	pop = null;
	var div = document.getElementById(divID);
	var max = 18;
	var left;
	var top;
	var w;
	var h;

	if (!div) alert('div not found');
	
	//--- Note that only IE supports popups at this time. [10/19/05 CW]
	
	if (div && window.createPopup)
	{
		div.style.position = 'absolute';
		div.style.top = -5000;
		div.style.display = '';
	
		pop = window.createPopup();
		
		var doc = pop.document;
		
		window.pop = pop;
		
		//--- Generate the boilerplate content.
		
		doc.open();
		doc.writeln('<html>');
		
		doc.writeln('<head>');
		doc.writeln('<link rel="stylesheet" href="' + cssFile + '" />');
		if (window.cssCustom) doc.writeln('<link rel="stylesheet" href="' + window.cssCustom + '" />');
		// Do not add javascript file references.  These will cause IE to freeze.
		doc.writeln('</head>');
		
		doc.writeln('<body class="' + cssClass + '" style="overflow:hidden;border:none;margin:0">');
		doc.writeln('</body>');
		
		doc.writeln('</html>');
		doc.close();
		
		//--- Insert the meat.
		
		var body = doc.body;
		var content = div.innerHTML;
		
		body.innerHTML = '<div id="' + divID + '" class="' + cssClass + '">' + content + '</div>';
		
		//--- Show the popup and size it to the contents.
		
		if (left == 0 && top == 0)	 // If not provided by caller.
		{
			left = event.x;
			top = event.y;
		}
		
		div.style.display = 'inline';

		//--- Set menu height, restricting # of items visible (#2033).

		var popDiv = doc.getElementById(divID);
		var inner = popDiv.childNodes[0];

		var h = div.offsetHeight;
		var w = div.offsetWidth;
		
		if (div.childNodes[0].childNodes.length > max)
		{
			var ii;
			
			h = 0;
			
			for (ii=0; ii<max; ii++)
			{
				h += div.childNodes[0].childNodes[ii].offsetHeight;
			}
		
			w = w + 20;							// Allow for vscroller
			inner.style.overflow = 'auto';
			inner.style.height = h;
			inner.style.width = w;
		}

		//--- Popup w/ initial size of 1x1 pixel.  Then do async resize.
		
		pop.show(left, top, 1, 1, document.body);
	//	pop.show(left, top, w, h, document.body);
		window.popX = left;
		window.popY = top;
		
		//window.setTimeout('popupResize(\'' + divID + '\');', 1);
		window.setTimeout(function() { pop.show(left, top, w, h, document.body); }, 1);

		div.style.display = 'none';

		//--- Set initial focus if so specified.
		
		pop.document.opener = window;
	}
	else if (div)
	{
		div.style.display = 'inline';

		if (left == 0 && top == 0) // If not provided by caller.
		{
			left = evt.clientX;
			top = evt.clientY;
		}
		
		//--- Find inner div.
		
		var inner = div.childNodes[0];
		
		while (inner && (!inner.tagName || inner.tagName.toLowerCase() != 'div'))
		{
			inner = inner.nextSibling;
		}

		//--- Set up height and width;
		
		w = div.offsetWidth;
		h = 0;
		
		if (inner)
		{
			var n = 0;
			var item = inner.childNodes[0];
			
			//--- Count items and calc height of first n items.
			
			while (item)
			{
				if (item && item.tagName && item.tagName.toLowerCase() == 'div') 
				{
					if (n < max) h += item.offsetHeight;
					n++;
				}
				item = item.nextSibling;
			}
			
			//--- If too many items, set up scrolling. #2033
			
			if (n > max)
			{
				inner.style.height = h;
				inner.style.overflow = 'auto';
				if (!inner.style.width) inner.style.width = w + 20;	// Allow for vscroller (once).
			}
		}
		
		//--- If off the screen, fixup location.
		
		if (w > 600) w = 200;	// Over 600 is crazy and probably means that size is wrong.
		if (left + w > screen.availWidth) left = screen.availWidth - w - 5;
		
		//--- Position menu.
		
		div.style.left = left;
		div.style.top = top;
		
		div.onkeydown = PopupKey;
		div.onmouseover = PopupMouseMove;

		//--- For W3C-compliant browsers.
		
		if (document.body.addEventListener)
		{
			document.body.addEventListener('keydown', PopupKey, false);
			document.body.addEventListener('mouseover', PopupMouseMove, false);
		}
		
		//--- Only one pop-up div at a time.  We need to set this up
		//--- globally because W3C-compliant browsers will get the event
		//--- from the document body and we won't be able to tell who
		//--- the initiating div is.
		
		window.popDiv = div;
		window.popDivParent = GetEventTarget(evt);
	}
	
	return (pop);
}


//---------------------------------------------------------------------------------------------------------------
// Click on toolbar caption causes click on related toolbar button (icon).
//---------------------------------------------------------------------------------------------------------------
function ToolbarClick(item, suffix)
{
	var id = item.id.substr(0, item.id.length - suffix.length);
	var btn = document.getElementById(id);
	if (btn && btn.click) 
		btn.click();
	else if (btn && btn.onclick) 
		btn.onclick();
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function MenuClose(evt, divID)
{
	if (!window.createPopup)
	{
		var	div = document.getElementById(divID);
		
		if (div) div.style.display = 'none';
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function divmenuToggle(divInnerID, subInnerID)
{
	var win = (window.createPopup) ? window.pop : window;
	
	var sub = win.document.getElementById(subInnerID); 
	if (sub) 
	{ 
		var div = win.document.getElementById(divInnerID); 
		if (div) 
		{ 
			var sign = win.document.getElementById(subInnerID + 'sign');
			var hide = ('block' == sub.style.display);
			
			if (hide)
			{
				sub.style.display = 'none';
				if (sign) sign.src = 'images/plus.gif';
			}
			else
			{
				sub.style.display = 'block'; 
				if (sign) sign.src = 'images/minus.gif';
			}

			if (win.show)
			{
				win.show(window.popX, window.popY, div.offsetWidth, div.offsetHeight, window.document.body);
				win.show(window.popX, window.popY, div.offsetWidth, div.offsetHeight, window.document.body);
			}
		}
	}
}

// #3650 - Handle divmenu mouseover.
function divmenuAct(evt)
{
	if (!evt) evt = window.event;

	var tgt = FindParent(GetEventTarget(evt), 'div', true);
	
	if (tgt && !tgt.getAttribute('disabled') && !HasCssClass(tgt, 'divnocmd'))
	{
		window.parent.ReplaceCssClass(tgt,'x','divmenuact');
	}

	CancelBubble(evt);
}

// #3650 - Handle divmenu mouseout.
function divmenuDeact(evt)
{
	if (!evt) evt = window.event;

	var tgt = FindParent(GetEventTarget(evt), 'div', true);

	if (tgt && !tgt.getAttribute('disabled') && !HasCssClass(tgt, 'divnocmd'))
	{
		window.parent.RemoveCssClass(tgt,'divmenuact');
	}

	CancelBubble(evt);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function divmenuPost(item, btn_id, confirmMessage)
{
	var	btn = document.getElementById(btn_id);

	if (confirmMessage != null && confirmMessage.length > 0)
	{
		if (!confirm(confirmMessage))
			return false;
	}
	
	if (btn)
	{
		btn.value = item.getAttribute('command');
		OnClick(btn);
	}
	
	return false;
}

//-----------------------------------------------------------------------------------------
// #3393 - Added onload support.
function popupWindow(evt, divID, name, caption, focusID, js, selfClose, onload)
{
	var win = null;
	
try
{
	var div = document.getElementById(divID);
	div.style.position = 'absolute';
	div.style.top = -1000;				// Move widget out of sight
	div.style.left = -1000;
	div.style.display = '';				// Show widget.

	var opts = 'menubar=0,resizable=0,scrollbars=0,titlebar=0';
	var hgt = parseInt(div.offsetHeight, 10) + 20;
	var wid = div.offsetWidth;
	wid += 20;
//	alert(evt.pageY + ',' + evt.clientY);
//	alert(evt.x);
//	alert(getTop(evt.target));
	var left = evt.clientX; //(window.event) ? window.event.x : 100;// : getLeft(div.txt); //event.x;
	var top = evt.clientY; //(window.event) ? window.event.y : 100;// : getTop(div.txt); //event.y;

	//--- Calculate window size and position

	if (wid + left > screen.width)
	{
		left = screen.width - wid - 20;
	}
	
	if (hgt + top > screen.height)
	{
		top = screen.height - hgt - 10;
	}
	
	opts += ',height=' + hgt;
	opts += ',width=' + wid;
	opts += ',left=' + left;
	opts += ',top=' + top;

	//--- Open the window.
	
	var url = 'blank.htm';
	
	win = window.open(url, name, opts, true);
	
	//--- If the window is already open it might be the wrong size.  Closing and
	//--- opening a new window is the only way I can get the sizing right.

	if (win.inUse)
	{
		win.close();
		win = window.open(url, name, opts, true);
	}
	
	var doc = win.document;

	doc.open();
	
	doc.writeln('<html>');
	
	doc.writeln('<head>');
	doc.writeln('<link rel="stylesheet" href="' + cssFile + '" />');
	// Do not add javascript file references.  These will cause IE to freeze.
	if (caption) doc.writeln('<title>' + caption + '</title>');
	doc.writeln('</head>');
	
	if (onload)
		doc.writeln('<body onload="' + onload + '">');	// #3393 - Added onload support.
	else
		doc.writeln('<body>');
	// body.innerHTML = '<div id="' + widget.id + '" class="' + cssClass + '">' + content + '</div>';
	doc.write('<div id="' + div.id + '">' + div.innerHTML + '</div>');
	
	//--- If any script was provided, add it now.
	
	if (js)
	{
		doc.writeln('<script>');
		doc.writeln(js);
		doc.writeln('</script>');
	}
	
	//--- Add function to close popup if opener closes or moves.
	
	if (selfClose)
	{
		AddSelfCloseScript(doc);
	}
	
	doc.writeln('</body>');
	
	doc.writeln('</html>');

	doc.close();
	
	//--- Initialize self-closing.
	
	if (selfClose)
	{
		win.originalLoc = window.document.location.href;
		win.setInterval('CloseIfNoOpener();', 2000);
	}
	
	win.inUse = true;	// Marks window in use for next open.
	
	// win.setZOptions('alwaysRaised');
	
	//win.resizeTo(wid, hgt+40);
}
catch (e)
{
	alert('Problem in popupWindow(): ' + e.description);
}

	//--- Return the window.
	
	return (win);	
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function togglerToggle(evt, btn, panelID, attrs)
{
	if (!evt) evt = window.event;
	
	var	panel = document.getElementById(panelID);
	var state = document.getElementById(btn.id + "_state");
	var tbl = FindParent(btn, 'table');
	
	if (!panel)
	{
		ThrowError(1003, 'EAPUtils::togglerToggle', "Toggler AssociatedControlID '" + panelID + "' not found on page.");
	}
	
	CancelBubble(evt)
	
	var forceSz = (0 != (attrs & 1));
	var hideContainerOnOpen = (0 != (attrs & 2)); //--- for the toolbar description
	var isOpen = (forceSz) ? (panel.style.height != '1px' && panel.style.display != 'none') : (panel.style.display == '');
	
	if (isOpen)
	{
		if (panel.offsetHeight <= 0) forceSz = false;	// #5164 - If we can't determine height forceSz mechanism would never allow reopen.
		
		if (forceSz)
		{
			if (!panel.origHgt) panel.origHgt = panel.offsetHeight;
			// #5131 - Not in FF v3.0.13 -- if (IsFirefox()) panel.style.width = panel.offsetWidth + 'px';
			panel.style.height = '1px';
			panel.style.overflow = 'hidden';
		}
		else
		{
			panel.style.display = 'none';
			if (IsSafari()) panel.parentNode.style.width = 0;
		}
		
		btn.src = "images/plus.gif";
		ReplaceCssClass(tbl, 'x', 'np');    // #4312
		if (state) { state.value = '0'; }
	}
	else
	{
		if (forceSz && panel.origHgt)
		{
			panel.style.height = panel.origHgt + 'px';
		}
		else
		{
			if (IsSafari()) panel.parentNode.style.width = "100%";
			panel.style.display = '';
		}
			
		btn.src = "images/minus.gif";
		RemoveCssClass(tbl, 'np');          // #4312
		if (state) { state.value = '1'; }
	}
	
	if (panel.onresize) panel.onresize();	// #4655
		
	isOpen = !isOpen;
	
	//--- Persist state.
	
	var nm = btn.getAttribute('pref');
	
	if (nm)
	{
		AjaxPrefSet(nm, (isOpen) ? '1' : '0');
	}
	
	//--- Fire onresizeend event on item being resized.
	
	//if (panel.onresizeend) panel.onresizeend();
	if (false)
	{
		if (window.resize)
			window.resize();
		else if (window.onresize)
			window.onresize();
	}
	else
	{
		// Firefox needs this TWICE!
		
		window.setTimeout('if (window.resize) window.resize(); else if (window.onresize) window.onresize();', 10);
		window.setTimeout('if (window.resize) window.resize(); else if (window.onresize) window.onresize();', 100);
	}
	
	if (hideContainerOnOpen)
	{
	    var dv = FindParent(btn, 'div');
	    dv.style.display = 'none';
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function togglerInit(id)
{
	var	btn = document.getElementById(id);
	var state = document.getElementById(id + "_state");

	//--- Restore state by closing toggler.

	if (btn && state && state.value == '0')
	{
		if (btn.click)
			btn.click();
		else if (btn.onclick)
			btn.onclick();
		//window.status += 'closing in init';
	}
}

//-----------------------------------------------------------------------------------------
// Fix up the list of controls to validate based on the "virtualForm" of the control
// (presumably a button) used to initiate the submit.
//-----------------------------------------------------------------------------------------
function validationFixup()
{
	var ii;
	var	arr = new Array();
	var origValidators = window.orig_validators;
	
	//--- Get the "virtualForm" of the control (presumably a button)
	//--- originating the submit.
	
	var virtForm = event.srcElement.virtualForm;
	
	//--- Save off initial array of validators.
	
	if (!origValidators)
	{
		window.orig_validators = Page_Validators;
		origValidators = window.orig_validators;
	}
	
	//--- Build new list of validators including only those on
	//--- the same "virtualForm".  Note that if no virtualForm
	//--- was specified then it really means the main form.
	
	for (ii=0; ii<origValidators.length; ii++)
	{
		var ctrl = document.getElementById(origValidators[ii].controltovalidate);
		
		if (ctrl && ctrl.virtualForm == virtForm)
		{
			arr.push(origValidators[ii]);
		}
	}
	
	//--- Replace the list of validators that the Microsoft 
	//--- Page_ClientValidate in WebUIValidation.js will look at.
	
	Page_Validators = arr;
}

//-----------------------------------------------------------------------------------------
// Purpose:	Intercept calls to the standard Microsoft Page_ClientValidate() in
//			WebUIValidation.js.  In the intercept we fix-up the list of fields to
//			validate based on the field's "virtualForm" and that of the control
//			(presumably a button) initiating the submit.
//-----------------------------------------------------------------------------------------
function validationIntercept()
{
	if (typeof(Page_ClientValidate) == 'function') 
	{
		if (!window.orig_Page_ClientValidate) 
		{
			window.orig_Page_ClientValidate = Page_ClientValidate;
		}
		
		Page_ClientValidate = function () { validationFixup(); window.orig_Page_ClientValidate(); };
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function cloneWindow(winToClone, win, content)
{
	var doc = win.document;
	
	var ii;
	//var docToClone = winToClone.document;
	var head = '';
	
	//--- Build a document header with the original window's script references.

// I wish we could do this, but it seems that writing script file references in
// script hangs IE6SP2 under certain circumstances (e.g. across machines). [9/7/05 CW]

//	for (ii=0; ii<docToClone.scripts.length; ii++)
//	{
//		var	script = docToClone.scripts[ii];
//		
//		if (script.src)
//		{
//			head += '<script language="' + script.language + '" src="' + script.src + '" charset="' + script.charset + '"></script>\n';
//		}
//	}

	//--- Open the clone's document write the header.
	
	doc.open();
	
	doc.writeln('<head>');
	doc.writeln(head);
	doc.writeln('</head>');
	
	//--- Write the form from the original window in a invisible div and close.

	doc.writeln('<div style="display:none">');	
	
// We can't just copy the form's outerHTML because it calls script functions
// that require the .js files.  Instead copy just the form and the elements
// within it. [10/4/05 CW]

	//doc.writeln(winToClone.document.forms[0].outerHTML);
	
	var form = document.getElementsByTagName('form')[0];
	var sForm = '<form';
	
	sForm += ' id="' + form.id + '"';
	sForm += ' name="' + form.name + '"';
	sForm += ' method="' + form.method + '"';
	sForm += ' action="' + form.action+ '"';
	sForm += '>';
	doc.writeln(sForm);
	
	var items = winToClone.document.forms[0].elements;
	
	for (ii=0; ii<items.length; ii++)
	{
		if (ElementType(items[ii]) != 'fieldset')	// #1967
		{
			doc.writeln(OuterHTML(items[ii]));	// element.outerHTML is IE-specific!
		}
	}
	
	if (content)
	{
	    doc.writeln(content);
	}
	
	doc.writeln('</form>');
	
	doc.writeln('</div>');

	doc.close();
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function menuResponseToNewWin(menudiv, itemID, winFeatures, confirmMessage)
{
	//--- Create a new window and clone the original.
	
	if (confirmMessage != null && confirmMessage.length > 0)
	{
		if (!confirm(confirmMessage))
			return false;
	}

	var win = window.open('blank.htm', '_blank', winFeatures); 
	
	window.cloneWindow(window, win);
	
	//--- Trigger the menu item.
	
	var menu = win.document.getElementById(menudiv);
	
	menu.value = itemID;
	menu.click();
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function OffsetBottom(item)
{
	var height = 0;
	var	ctrl = GetElement(item);
	
	if (ctrl) height = getTop(ctrl) + ctrl.offsetHeight;

	return (height);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function OffsetRight(item)
{
	var width = 0;
	var	ctrl = GetElement(item);
	
	if (ctrl) width = getLeft(ctrl) + ctrl.offsetWidth;
	
	return (width);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function CalcHeight(item)
{
	return (item) ? (CalcBottom(item) - item.offsetTop) : 0;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function CalcBottom(item)
{
	var bot = 0;
	
	if (!item.childNodes || item.childNodes.length == 0)
	{
		bot = OffsetBottom(item);
	}
	else
	{
		var ii;
		
		for (ii=0; ii<item.childNodes.length; ii++)
		{
			var botItem = CalcBottom(item.childNodes[ii]);
			
			if (botItem > bot) bot = botItem;				
		}
	}
	
	return (bot);
}


//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function DelayedAlert(msg)
{
	//alert(msg);
	window.setTimeout("alert('" + msg + "');", 50);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function PressedCR(win, evt)
{
	if (!win) win = window;
	if (!evt) evt = win.event;

	return (evt.keyCode != null && evt.keyCode == 13);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function PressedEsc(win, evt)
{
	if (!win) win = window;
	if (!evt) evt = win.event;

	return (evt.keyCode == 27);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function HandleVirtualFormKey(evt, tbl, marked)
{
	if (!evt) evt = window.event;
	
	var ii;
	var subs;
	var item;
	
	//--- If key is a <cr>...
	
	if (evt.keyCode == 13)
	{
		var tgt = GetEventTarget(evt);
		
		//--- #3963 - Don't intercept key handling on TEXTAREA controls.

		if (ElementType(tgt) != 'textarea')
		{
			//--- Find the first submit button in the virtual form (that is, 
			//--- under the specified table) and click it.
			
			subs = document.getElementsByTagName('input');
			
			for (ii=0; ii<subs.length; ii++)
			{
				item = subs[ii];
				
				if (ElementType(item) == 'submit' && IsParentOf(item, tbl) && 
					(!marked || item.getAttribute('default')))
				{
					DoClick(item);
					CancelBubble(evt);
					break;
				}
			}
		
			return false;
		}
	}
	else if (evt.keyCode == 27)	// <esc>
	{
		//--- Find the first reset button in the virtual form (that is, 
		//--- under the specified table) and click it.
		
		subs = document.getElementsByTagName('input');
		
		for (ii=0; ii<subs.length; ii++)
		{
			item = subs[ii];
			
			if (ElementType(item) == 'reset' && IsParentOf(item, tbl) && 
				!marked || item.getAttribute('cancel'))
			{
				DoClick(item);
				evt.cancelBubble = true;
				if (evt.stopPropagation) evt.stopPropagation();
				break;
			}
		}
		
		return false;
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function CanGetFocus(ctrl)
{
	var tag = ElementType(ctrl);
	
	return ((tag == 'text' || tag == 'select' || tag == 'checkbox' || tag == 'textarea' ||
			 (tag == 'image' && IsBndLkup(ctrl))) &&			// #4449 - Support focus to BndLkup.
			IsVisibleAndEnabled(ctrl));
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function VerifyFunc(name)
{
	if (eval("window." + name) == null)
	{
		ThrowError(1004, 'EAPUtils::VerifyFunc', 'Expected function not found: ' + name);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ResizeWin(win, width, height, adjust)
{
	if (adjust)
	{
		win.resizeTo(width + (width - GetClientWidth(win)), height + (height - GetClientHeight(win)));
	}
	else
	{
		win.resizeTo(width, height);
		window.setTimeout(function() { ResizeWin(win, width, height, true); }, 33);	// # 4056 - Allow settle time.
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function SizeWinToCtrl(ctrlID, horizResize, win, phase, height, width)
{
	if (!win) win = window;
	
	var	ctrl = win.document.getElementById(ctrlID);
	
	if (!ctrl) return;
	
	//--- A multi-phase approach is required with a setTimeout called to reliquish
	//--- control and move on to the next phase. #3882.

	if (!phase)
	{
		//--- Mark window as in the process of being resized.  This is used by the
		//--- hsplitInit() method to know how to size things.
		
		win.sizingToFit = true;
		
		window.setTimeout(function() { SizeWinToCtrl(ctrlID, horizResize, win, 1); }, 1);
	}
	else if (phase == 1)
	{
		//--- Note that when resizing we can only get the window client
		//--- area dimensions, and only set by the outer dimensions so
		//--- we have to compensate for the non-client area.
		
		//--- Figure out necessary height.
	
		if (window.pageHeight)
		{
			height = window.pageHeight;					// #5839 - Explicitly sized.
		}
		else
		{
			height = OffsetBottom(ctrl.id) + 40;		// 40 is a guess at window chrome height
			height += 16;								// Account for horizontal scrollbar.

			if (IsAppleWebKit()) 
				height += 15;
			else if (!IsIE()) 
				height += 10;
		}
		
		//--- Figure out necessary width.
	
		if (window.pageWidth)
		{
			width = window.pageWidth;					// #5839 - Explicitly sized.
		}
		else
		{
			width = GetClientWidth(win) + 12;			// 12 accounts for window frame

			if (horizResize)
			{
				if (IsIE())
				{
					width = ctrl.offsetWidth + 20;
				}
				else // Seems that only IE gives you a decent width.  So, if not IE, calculate it ourselves.
				{
					width = FarRight(ctrl) + 20;	// #3957 - This can be expensive, optimized FarRight().
					width += 30;
				}
			}
		}
		
		//--- If size is taller or wider than screen, reduce accordingly.
		
		var reduced = false;
		
		if (height > screen.height - 50)
		{
			height = screen.height - 150;	// Seems safe for all browsers w/ Opera being the limiting factor.
			reduced = true;
		}
		
		if (width > screen.width - 50)
		{
			width = screen.width - 150;
			reduced = true;
		}
		
		//--- If reduced, Firefox & Opera put in scrollbars automatically, but need to add for IE.
		
		if (reduced && IsIE())
		{
			ctrl.style.overflow = 'auto';
			ctrl.style.height = GetClientHeight(win);
		}

		//--- If running off bottom of screen, move up.  IE and Safari (Mac) are the driving factors here.
		//--- IE will truncate the window, and Safari will refuse to resize.

		var b = WinTop(win) + height;
		var r = WinLeft(win) + width;
		
		if (b > screen.height || r > screen.width)
		{
			var deltaV = (b > screen.height) ? screen.height - b : 0;
			var deltaH = (r > screen.width) ? screen.width - r : 0;

			win.moveBy(deltaH, deltaV);
		}
		
		//--- Yield control so that any repositioning can take effect then move on to phase 2.
		
		window.setTimeout(function() { SizeWinToCtrl(ctrlID, horizResize, win, 2, height, width); }, 1);
	}
	else if (phase == 2)
	{
		//--- Do the initial resize then yield for it to take effect before moving on to phase 3.

		win.resizeTo(width, height);

		window.setTimeout(function() { SizeWinToCtrl(ctrlID, horizResize, win, 3, height, width); }, 1);
	}
	else if (phase == 3)
	{
		//--- Update for window dimensions differing from client area.
		
		try
		{
			var vMargin = height - GetClientHeight(win);
			
			//--- Now readjust to account for toolbars, statusbar, etc.
			
			var heightDiff;
			
			if (IsIE())
				heightDiff = vMargin - 40;
			else if (IsChrome())
				heightDiff = 0;
			else
				heightDiff = vMargin - 60;

			height += heightDiff;

			//--- Do the adjustment resize.
							
			if (heightDiff != 0) win.resizeTo(width, height);

			//--- Track original size.				

			win.origWidth = WindowWidth(win);
			win.origHeight = WindowHeight(win);
			
			//--- We're done sizing.  Mark window so.
			
			win.sizingToFit = false;
		}
		catch (e)
		{
			alert(e.description);
		}
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FarRight(ctrl, recursing)
{
	var right = 0;
	
	if (ctrl && IsVisible(ctrl))								// #3957 - Optimized: Ignore if not visible.
	{
		right = GetStaticLeft(ctrl) + ctrl.offsetWidth;			// #3957 - Optimized: Use GetStaticLeft() vs. getLeft().
		
		if (ElementType(ctrl) == 'a' && ctrl.offsetWidth > 100)	// #5839 - Anchor widths unreliable (so limit to arbitrary 100 pixels).
			right -= ctrl.offsetWidth + 100;
		
		if (ElementType(ctrl) != 'select')						// #3957 - Optimized: Ignore OPTIONs within SELECTs.
		{
			var ii;
			var childright;
			
			for (ii=0; ii<ctrl.childNodes.length; ii++)
			{
				childright = FarRight(ctrl.childNodes[ii], true);	
				if (childright > right) right = childright;
			}
		}
	}
	
	return (right);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FindForm(win)
{
	return document.forms[0];
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function AddHiddenInput(owner, name, value)
{
	var item = owner.ownerDocument.createElement('input');

	item.type = 'hidden';
	item.id = name;
	item.name = name;
	item.value = value;
	
	owner.appendChild(item);
	
	return (item);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function OpenWindow(name, opts, caption, content, focusID, selfClose)
{
	var	win = window.open('blank.htm', name, opts, true);
	//var		win = window.showModelessDialog('', opts, true);
	
	//--- Popup Blockers will cause problems w/ AJAX if we proceed w/out window.
	
	if (win)
	{
		//--- Put focus to the window.  This forces the window to the fore.
		
		win.focus();

		//--- If the window is already open it might be the wrong size.  Closing and
		//--- opening a new window is the only way I can get the sizing right.
		
	//	if (win.inUse)
	//2	if (name)
	//2	{
	//2		win.close();
	//2		win = window.open('blank.htm', name, opts, true);
	//2	}
		
	//	win.inUse = true;
		
		var doc = win.document;

		doc.open();
		doc.writeln('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >');
		doc.writeln('<html>');
		
		doc.writeln('<head>');
		doc.writeln('<link rel="stylesheet" href="' + cssFile + '" />');
		// Do not add javascript file references.  These will cause IE to freeze.
		if (caption) doc.writeln('<title>' + caption + '</title>');
		doc.writeln('</head>');
		
		//win.setTimeout('',0);
		
		// doc.writeln('<body class="' + cssClass + '" style="overflow:hidden;border:none;margin:0" onload="var item = document.getElementById(\'' + focusID + '\'); if (item) { item.focus(); }">');
		if (focusID)
		{
			doc.writeln('<body onload="InitDetailFocus(\'' + focusID + '\');">');
		}
		else
		{
			doc.writeln('<body>');
		}

		// doc.writeln('<body>');
		// body.innerHTML = '<div id="' + widget.id + '" class="' + cssClass + '">' + content + '</div>';
		//doc.write('<div id="' + div.id + '">' + div.innerHTML + '</div>');
		doc.write(content);
		
		//--- Add function to close popup if opener closes or moves.
		
		if (selfClose)
		{
			AddSelfCloseScript(doc);
		}

		doc.writeln('</body>');

		doc.writeln('</html>');

		doc.close();
		
		//--- Initialize self-closing.
		
		if (selfClose)
		{
			win.originalLoc = window.document.location.href;
			win.setInterval('CloseIfNoOpener();', 2000);
		}
	}
	
	return (win);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function PrettyPrompt(msg, def)
{
	if (parent.showModalDialog)
		return parent.showModalDialog('prettyprompt.htm', msg, 'dialogHeight:150px;status:0');
	else
		return parent.prompt(msg, def);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FormKeyHandler(cancelID, okID, win)
{
	if (!win) win = window;
	
	if (PressedEsc(win)) 
	{
		var cancel = win.document.getElementById(cancelID);
		if (cancel) cancel.click();
	}
	else if (PressedCR(win))
	{
		var ok = win.document.getElementById(okID);
		if (ok) ok.click();
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ManageList(ctrl, picklist_key, multisel)
{
	if (!multisel) RestoreValue(ctrl.id);
	
	//window.status += ".managelist";
	
	var features = 'menubar=0,resizable=1,scrollbars=0,titlebar=0,width=300,height=350';
	
	//if (event) features += ',left=' + event.x + ',top=' + event.y;
	features += ',left=' + getLeft(ctrl) + ',top=' + getTop(ctrl);
	
	var url = "ManagePicklist.aspx?pick=" + picklist_key + "&cbo=" + ctrl.id + "&multi=" + multisel;
	
	window.open(url, "managepick", features, true);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function RestoreValue(ctrlid)
{
	var	ctrl = document.getElementById(ctrlid);
	
	if (ctrl)
	{
		var	ii;
		var	lastValue = ctrl.lastValue;
		
		for (ii=0; ii<ctrl.options.length; ii++)
		{
			var	opt = ctrl.options[ii];
			
			if (opt.value == lastValue)
			{
				ctrl.selectedIndex = ii;
				break;
			}
		}
	}
}

//-----------------------------------------------------------------------------------------
// Script for enforcing maxlength on TextArea controls.
//-----------------------------------------------------------------------------------------
function TACheckLen(evt, ctrl, len) 
{
	if (!evt) evt = window.event;

	return (ctrl.value.length < len || IsEditKeyPress(evt));	// #5596 - Allow FF edit keys.
}

function TACheckPaste(ctrl, len)
{
	// Allow the paste to complete then let TAFixLen truncate.
	
	window.setTimeout('TAFixLen(\'' + ctrl.id + '\',' + len + ');', 20);
}

function TAFixLen(id, len)
{
	var ctrl = document.getElementById(id);
	if (ctrl.value.length > len)
		ctrl.value = ctrl.value.substring(0, len);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function OpenPopupWindow(url, options, target)
{
	if (!target || target == '') target = '_blank';
	window.open(url, target, options, false).focus();	
	if (window.event != null)
		window.event.cancelBubble = true;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetRowKey(win)
{
	return (win) ? win.rowKey : window.rowKey;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BtnLive(btn, backcolor, border)
{
	backcolor = 'e8e8e8';
	border = 'solid 1px gray'; //white';
	btn.origBackgroundColor = 'd0d0d0'; //btn.style.backgroundColor;
	btn.style.backgroundColor = backcolor; //'e8e8e8'; 
	btn.origBorder = 'solid 1px d0d0d0'; //btn.style.border;
	btn.style.border = border; //'solid 1px gray';
	btn.onmouseout = BtnDead;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BtnDead(btn)
{
	btn = window.event.srcElement;
	btn.style.backgroundColor = btn.origBackgroundColor; //'e0e0e0'; 
	btn.style.border = btn.origBorder; //'solid 1px c0c0c0';
}

//-----------------------------------------------------------------------------------------
// Purpose:	Find the tag of type tagName containing the specified coordinates.  Since there
//			may be multiple tags nested within one another all containing the point, find
//			the smallest one.
//-----------------------------------------------------------------------------------------
function FindCtrl(tagName, x, y)
{
	var	ctrl = null;
	var tds = document.getElementsByTagName(tagName);
	var	ii;
	var minWidth = 100000;
	var minHeight = 100000;
	
	for (ii=0; ii<tds.length; ii++)
	{
		var	td = tds[ii];
		var	top = getTop(td);
		var left = getLeft(td);
		var bottom = top + td.offsetHeight;
		var right = left + td.offsetWidth;
		
		if (x >= left && x <= right && y >= top && y <= bottom)
		{
			//--- Find smalled TD containing the point.
			
			if (td.offsetWidth < minWidth && td.offsetHeight < minHeight)
			{
				ctrl = td;
				minWidth = td.offsetWidth;
				minHeight = td.offsetHeight;
			}
		}
	}
	
	return (ctrl);
}

//-----------------------------------------------------------------------------------------
// Set a string in a "tagstring" of the form:
// ";<name1>=<val1>;<name2>=<val2>;...;<nameN>=<valN>;"
// To ensure that the ";" and "=" delimiters are unique, ";", "=", and "%" are encoded into
// their ASCII code in hex with a "%" prepended.  If the named item is not in the list then
// its name and value are appended to the list.  If it is already present in the list then
// its value is replaced with the new value.
//-----------------------------------------------------------------------------------------
function SetString(s, name, value)
{
	value = '' + value;
	value = value.replace(/%/g, '%25').replace(/=/g, '%3D').replace(/;/g, '%3B');
	
	if (!s || s.length < 1) s = ';';
	if (s.substr(0,1) != ';') s = ';' + s;
	
	if (s.indexOf(';' + name + '=') >= 0)
	{
		var replace = ';' + name + '=' + value + ';';
		var expr = 's.replace(/;' + name + '=[^;]*;/, replace)';
		return eval(expr);
	}
	else
	{
		return s + name + '=' + value + ';';
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FindParent(ctrl, tag, selfOk)
{
	if (ctrl && (!selfOk || !ctrl.tagName || ctrl.tagName.toLowerCase() != tag))
	{
		ctrl = ctrl.parentNode;
		tag = tag.toLowerCase();
		
		while (ctrl && ctrl.tagName && ctrl.tagName.toLowerCase() != tag)
		{
			ctrl = ctrl.parentNode;
		}
	}
	
	return (ctrl);
}


//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IsParentOf(ctrl, parent)
{
	while (ctrl != parent && ctrl && ctrl.parentNode != null)
	{
		ctrl = ctrl.parentNode;
	}
	
	return (ctrl == parent);
}


var _emptyTags = 
{
   'IMG':   true,
   'BR':    true,
   'INPUT': true,
   'META':  true,
   'LINK':  true,
   'PARAM': true,
   'HR':    true
};

//-----------------------------------------------------------------------------------------
// IE supports an innerHTML() method on elements, but Mozilla uses textContent.
//-----------------------------------------------------------------------------------------
function InnerHTML(item)
{
	var txt;

	if (item.innerText)
	{
		txt = item.innerText;	// IE
	}
	else if (item.textContent)
	{
		txt = item.textContent;	// Mozilla
	}
	
	return (txt);
}

//-----------------------------------------------------------------------------------------
// IE supports an outerHTML() property on elements, but Mozilla does not.
// Note: There is some oddness w/ Firefox where checkboxes don't have a "checked" attribute
// in the item's attributes collection.  This method includes special handling to handle
// this case.
// Note: Safari/Chrome have an outerHTML property, but it seems to be the page's original content
// without any user changes.  So, don't use outerHTML for them.
//-----------------------------------------------------------------------------------------
function OuterHTML(item)
{
	if (item.outerHTML && !IsAppleWebKit())	// #3819
	{
		return item.outerHTML;
	}
	else
	{
		var	attrs = item.attributes;
		var	str = '<' + item.tagName;
		var	ii;
		
		//--- For Firefox, look for case where item is a checkbox, and it is checked,
		//--- but the attributes collection doesn't have a "checked" item.  If so,
		//--- add it to the HTML below.
		
		var	bCheckNeeded = (ElementType(item) == 'checkbox');	

		for (ii=0; ii<attrs.length; ii++)
		{
			str += ' ' + attrs[ii].name + '="' + attrs[ii].value + '"';
			bCheckNeeded = (bCheckNeeded && attrs[ii].name.toLowerCase() != 'checked');
		}
		
		if (_emptyTags[item.tagName.toUpperCase()])
		{
			if (bCheckNeeded && item.checked) str += ' checked=""';
			str += ' />';
		}
		else
		{
			str += '>' + item.innerHTML + '</' + item.tagName + '>';
		}
		
		return (str);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function EventOffsetX(evt, ctrl)
{
	//return (evt.offsetX) ? evt.offsetX : evt.clientX - ctrl.offsetLeft);
	return (evt.offsetX) ? evt.offsetX : evt.pageX - getLeft(ctrl);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function EventOffsetY(evt, ctrl)
{
	//return (evt.offsetY) ? evt.offsetY : evt.clientY - ctrl.offsetTop);
	return (evt.offsetY) ? evt.offsetY : evt.pageY - getTop(ctrl);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetEventTarget(evt)
{
	var target = null;
	
	if (evt)
	{
		if (evt.srcElement)
		{
			target = evt.srcElement;	
		}
		else
		{
			target = evt.target;
		}
		
		//-- Workaround Safari bug where text in the node is considered the target!
		
		if (!target.tagName) target = target.parentNode; 
	}
		
	return (target);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function PopupKey(evt)
{
	if (!evt) evt = window.event;
	
	if (evt.keyCode == 27)	// <esc>
	{
		PopupClose(evt);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function PopupClose(evt)
{
	var pop = window.popDiv;
	
	if (pop)
	{
		pop.style.display = 'none';

		//--- For W3C-compliant browsers.
		
		if (document.body.removeEventListener)
		{
			document.body.removeEventListener('keydown', PopupKey, false);
			document.body.removeEventListener('mouseover', PopupMouseMove, false);
		}
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function PopupMouseMove(evt)
{
	var pop = window.popDiv;
	
	if (pop)
	{
		var target = GetEventTarget(evt);

		//--- If user moves off of menu itself or its opener button, close
		//--- the menu.
		
		if (target != window.popDivParent && !IsParentOf(target, pop))
		{
			PopupClose();
		}
		//window.status += evt.target.tagName + '(' + evt.clientX + ',' + evt.clientY + ')';
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetClientHeight(win)
{
	var h;
	
	if (!win) win = window;

	if (win.innerHeight) // all except Explorer
	{
		h = win.innerHeight;
	}
	else if (win.document && win.document.documentElement && win.document.documentElement.clientHeight)
	{
		// Explorer 6 Strict Mode
		h = win.document.documentElement.clientHeight;
	}
	else if (win.document && win.document.body) // other Explorers
	{
		h = win.document.body.clientHeight;
	}
	
	return (h);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetClientWidth(win)
{
	var h;
	
	if (!win) win = window;

	if (win.innerWidth) // all except Explorer
	{
		h = win.innerWidth;
	}
	else if (win.document && win.document.documentElement && win.document.documentElement.clientWidth)
	{
		// Explorer 6 Strict Mode
		h = win.document.documentElement.clientWidth;
	}
	else if (win.document && win.document.body) // other Explorers
	{
		h = win.document.body.clientWidth;
	}

	return (h);
}

// Get window bottom coordinate, with scrolling.
function GetClientBottom(win)		// #5421
{
	if (!win) win = window;

	var bottom = GetClientHeight(win);
	
	if (win.document.body && win.document.body.scrollTop) bottom += win.document.body.scrollTop;

	return (bottom);
}

// Get window right coordinate, with scrolling.
function GetClientRight(win)		// #5421
{
	if (!win) win = window;

	var right = GetClientWidth(win);
	
	if (win.document.body && win.document.body.scrollLeft) right += win.document.body.scrollLeft;

	return (right);
}

//-----------------------------------------------------------------------------------------
// Gets control's width excluding borders, padding, and margins
function CtrlClientWidth(ctrl)	// #818
{
	return (!ctrl) ? 0 : (ctrl.clientWidth) ? ctrl.clientWidth : ctrl.offsetWidth;
}

//-----------------------------------------------------------------------------------------
// Gets control's height excluding borders, padding, and margins
function CtrlClientHeight(ctrl)	// #818
{
	return (!ctrl) ? 0 : (ctrl.clientHeight) ? ctrl.clientHeight : ctrl.offsetHeight;
}

//-----------------------------------------------------------------------------------------
function WinTop(win)
{
	if (!win) win = window;
	
	if (win.screenTop)
		return (win.screenTop);
	else
		return (win.screenY);
}

//-----------------------------------------------------------------------------------------
function WinLeft(win)
{
	if (!win) win = window;

	if (win.screenLeft)
		return (win.screenLeft);
	else
		return (win.screenX);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function StrReplace(s, pattern, replace)
{
	var exp = new RegExp(pattern, 'g');
	
	return (s) ? s.replace(exp, replace) : s;
}

// #4964 - Convert certain Unicode chars to Ascii equivalents.
function DeUnicode(s)
{
	if (s)
	{
		s = StrReplace(s, String.fromCharCode(160), ' ');	// #4964 - Cvt nbsp to ascii space.
	}
	
	return (s);
}

//-----------------------------------------------------------------------------------------
// This function inserts text into a textarea or textbox at the cursor or replacing 
// highlighted text!
//-----------------------------------------------------------------------------------------
function CursorInsert(ctl, val, highlight) 
{
	var start;
	var end;
	
	if (ctl.setSelectionRange)// && ctl.selectionStart)
	{
//		window.status = 'Using setSelectionRange';	// Firefox & Opera
		
		//var frm = FindParent(ctl, 'form');
		start = ctl.selectionStart; //parseInt(frm.start.value);
		end = ctl.selectionEnd; //parseInt(frm.end.value);
		ctl.value = ctl.value.substring(0, start) + val + ctl.value.substring(end, ctl.value.length);
		
		if (highlight)
		{
			if (IsFirefox())
			{
				end = start + val.length;
				ctl.setSelectionRange(start, end);
				ctl.focus();
			}
			else
			{
				ctl.selectionStart = start;
				ctl.selectionEnd = start + val.length;
			}
		}
	}
	else if (ctl.selectionStart != null)
	{
//		window.status = 'Using selectionStart';
		
		start = ctl.selectionStart;
		end = ctl.selectionEnd;
		ctl.value = ctl.value.substring(0, start) + val + ctl.value.substring(end, ctl.value.length);
		if (highlight)
		{
			ctl.selectionStart = start;
			ctl.selectionEnd = start + val.length;
		}
	}
	else if (document.selection) 
	{
//		window.status = 'Using document.selection';		// IE (Win)
		
		ctl.focus();
		var sel = document.selection.createRange();
		sel.text = val;
		if (highlight)
		{
			sel.moveStart('character', -val.length);
			sel.select();
		}
	}
	else
	{
//		window.status = 'Using other';
		ctl.value += val;
	}
}

//-----------------------------------------------------------------------------------------
// Look up a string in an array and return the index if found, else -1.
//-----------------------------------------------------------------------------------------
function ArrayIndexOf(arr, s)
{
	var idx = -1;
	var ii;

	for (ii=0; ii<arr.length; ii++)
	{
		if (arr[ii] == s)
		{
			idx = ii;
			break;
		}
	}

	return (idx);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function StringToFloat(val, local)
{
	var dec = (local && local.length > 0) ? local.substr(0,1) : '.';	// Localized decimal point
	var sep = (local && local.length > 1) ? local.substr(1,1) : ',';	// Localized thousands separator
	
	sep = DeUnicode(sep);						// #4964 - Cvt nbsp to ascii space.
	val = DeUnicode(val);
	
	val = StrReplace(val, '\\' + sep, '');		// Remove thousands separator (no grouping validation!)
	val = StrReplace(val, '\\' + dec, '.');		// Change to unlocalized decimal point
	val = val.replace(/^\s*/, '');				// Remove leading whitespace
	val = val.replace(/\s*$/, '');				// Remove trailing whitespace
	
	if (val == null || val == '') val = 0.0;	// Empty/blank means zero
	
	return (val);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function StringToInt(val, local)
{
	var sep = (local && local.length > 1) ? local.substr(1,1) : ',';	// Localized thousands separator

	if (!val) val = '';
	
	val = StrReplace(val, '\\' + sep, '');		// Remove thousands separator (no grouping validation!)
	val = val.replace(/^\s*/, '');				// Remove leading whitespace
	val = val.replace(/\s*$/, '');				// Remove trailing whitespace
	
	//--- Convert negative numbers indicated with enclosing parentheses to
	//--- a format with leading negative sign, e.g.: "(100)" --> "-100"
	
	if (val && val.indexOf('(') == 0 && val.indexOf(')') == val.length-1)
	{
		val = '-' + val.substr(1, val.length-2);
	}

	//window.status = val;
	
	return (val);
}

function DaysInMonth(month, year)
{
	var days;
	var numdays = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
	
	if (month == 2 && year%4 == 0 && (year%100 != 0 || year%400 == 0))
	{
		days = 29;
	}
	else if (month >= 1 && month <= 12)
	{
		days = numdays[month-1];
	}
	
	return (days);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function StringToDate(val, local)
{
	var dt = null;
	
	if (val && IsString(val)) val = val.trim();

	if (!val || val == null || val == '') return val;
	
	var bDateOnly = false; //true;
	var bTimeOnly = false;
	var bDateFirst = true;
	var sDateFmt = 'MM/dd/yyyy';
	var sTimeFmt = 'HH:mm:ss';
	var sDateDelim = '/';
	var sTimeDelim = ':';
	var b24Hr = false;
	var bPm = false;
	var fmt = local;
	
	//--- #4625 - Detect and remove any date desc.
	
	var bDesc = (fmt.indexOf('+') >= 0);
	
	if (bDesc) 
	{
		fmt = fmt.replace(/\+/g, '');
		val = val.replace(/ \(.*/, '');
	}
	
	if (val && IsString(val) && val.length >= 10 && val.substr(0,10).match(/^\d{4}-\d\d-\d\d/))
	{
	    fmt = 'yyyy-MM-dd';
	}
	
	//window.status += 'val=' + val + ', local=' + local;
	
	if (fmt)
	{
		var nDateStart = fmt.search(/[Mdyg]/);
		var nTimeStart = fmt.search(/[hHmsfFtz]/);
		var nDateEnd = fmt.search(/[Mdyg][^Mdyg]*$/g);
		var nTimeEnd = fmt.search(/[hHmsfFtz][^hHmsfFtz]*$/g);
		
		//window.status = 'date(' + nDateStart + ',' + nDateEnd + '), time(' + nTimeStart + ',' + nTimeEnd + ')';
		
		bDateOnly = (nTimeStart < 0);
		bTimeOnly = (nDateStart < 0);
		
		bDateFirst = bDateOnly || (!bTimeOnly && (nDateStart < nTimeStart));
		
		if (!bTimeOnly)
		{
			sDateFmt = fmt.substring(nDateStart, nDateEnd+1);
			sDateDelim = sDateFmt.match(/[^Mdyg]/);
		}
		
		if (!bDateOnly)
		{
			sTimeFmt = fmt.substring(nTimeStart, nTimeEnd+1);
			sTimeDelim = sTimeFmt.match(/[^hHmsfFtz]/);
			b24Hr = TimeIs24Hr(fmt);
		}
	}
	
	//window.status += local + ' --> ' + sDateFmt + '(' + sDateDelim + ').' + sTimeFmt + '(' + sTimeDelim + ')';
	//window.status += (!b24Hr) ? 'p' : '^p';
	
	val = Trim(val, true, true);
	
	var sDate = '';
	var sTime = '';
		
	if (bDateOnly)
	{
		sDate = val;
	}
	else if (bTimeOnly)
	{
		var TimeSplit = val.split(' ');
		
		if (TimeSplit.length == 1)
		{
			sTime = val;
			bPm = (sTime.search(/[pP]/) >= 0);
		}
		else
		{
			sTime = TimeSplit[0];
			bPm = (TimeSplit[1].search(/[pP]/) >= 0);
		}
	}
	else
	{
		var DateAndTime = val.split(' ');
		
		if (DateAndTime.length == 2)
		{
			if (bDateFirst)
			{
				sDate = DateAndTime[0];
				sTime = DateAndTime[1];
			}
			else
			{
				sTime = DateAndTime[0];
				sDate = DateAndTime[1];
			}
		}
		else if (DateAndTime.length == 1)
		{
			// Presumably just a date (or maybe just a time?)
			sDate = DateAndTime[0];
		}
		else if (DateAndTime.length == 3 && !b24Hr) // Probably an am/pm pattern (t or tt).
		{
			if (bDateFirst)
			{
				sDate = DateAndTime[0];
				sTime = DateAndTime[1];
				bPm = (DateAndTime[2].search(/[pP]/) >= 0);
			}
			else
			{
				sTime = DateAndTime[0];
				bPm = (DateAndTime[1].search(/[pP]/) >= 0);
				sDate = DateAndTime[2];
			}
		}
//		else
//		{
//			// What?
//		}
			
		//window.status += ' date=' + sDate + ', time=' + sTime;
	}
	
	var day = 0;
	var month = 0;
	var year = 0;
	var hour = 0;
	var min = 0;
	var sec = 0;

	//--- Handle date part.

	var ok = true;

	if (sDate)
	{
		if (sDate.indexOf(sDateDelim) < 0)
		{
			var dpos = sDate.search(/[./-]/);	// #4782 - Find other delim.
			
			if (dpos > 0) sDateDelim = sDate.charAt(dpos);
		}

		var	dateParts = sDate.split(sDateDelim);
		
		var posMon = sDateFmt.indexOf('M');
		var posDay = sDateFmt.indexOf('d');
		var posYear = sDateFmt.indexOf('y');
		var iMon = 0;
		var iDay = 1;
		var iYear = 2;
		
		if (posDay < 0) posDay = 10;		// \
		if (posMon < 0) posMon = 10;		//  > #4901 - Handle fmt w/out year.
		if (posYear < 0) posYear = 10;		// /
		
		if (posMon < posDay)
		{
			iMon = (posMon < posYear) ? 0 : 1;
			iDay = (posDay < posYear) ? 1 : 2;
			iYear = (posYear < posMon) ? 0 : (posYear < posDay) ? 1 : 2;
		}
		else // iDay < iMon
		{
			iMon = (posMon < posYear) ? 1 : 2;
			iDay = (posDay < posYear) ? 0 : 1;
			iYear = (posYear < posDay) ? 0 : (posYear < posMon) ? 1 : 2;
		}

//		ok = ok && ValidateInt(dateParts[0]);	// \
//		ok = ok && ValidateInt(dateParts[1]);	//  > #4901 - No! fmt may include MMM or MMMM.
//		ok = ok && ValidateInt(dateParts[2]);	// /
		
		if (dateParts.length > iDay) day = parseInt(dateParts[iDay], 10);
		if (dateParts.length > iMon) month = ParseMonth(dateParts[iMon]);									// #4901 - Handle MMM or MMMM fmt.
		year = (dateParts.length > iYear) ? parseInt(dateParts[iYear], 10) : (new Date()).getFullYear();	// #4901 - Handle fmt w/out year.

		if (year < 50)
			year = parseInt(year, 10) + parseInt(2000, 10);
		else if (year < 100)
			year = parseInt(year, 10) + 1900;

		ok = ok && (year >= 1753 && year < 10000);
		ok = ok && (month >= 1 && month <= 12);
		ok = ok && (day >= 1 && day <= DaysInMonth(month, year));
	}
	
	//--- Handle time part.

	if (ok && sTime)
	{
		var	timeParts = sTime.split(sTimeDelim);
		
		ok = ok && ValidateInt(timeParts[0]);
		if (timeParts.length > 1)
		{
			timeParts[1] = timeParts[1].replace(/[aApPmM]/g, '');
			ok = ok && ValidateInt(timeParts[1]);
		}
		if (timeParts.length > 2) 
		{
			timeParts[2] = timeParts[2].replace(/[aApPmM]/g, '');
			ok = ok && ValidateInt(timeParts[2]);
		}
		
		//--- For now, assume hour always precedes minutes which precedes optional seconds

		if (ok)
		{
			//window.status += 'time split: ';
			
			hour = parseInt(timeParts[0], 10);
			min = parseInt(timeParts[1], 10);
			sec = (timeParts.length > 2) ? parseInt(timeParts[2], 10) : 0;
			
			if (!b24Hr)
			{
				if (hour == 12 && !bPm)
					hour = 0;
				else if (bPm && hour != 12)
					hour += 12;
			}
			else
			{
				if (hour == 24) hour = 0;
			}
			
			ok = ok && (hour >= 0 && hour < 24);
			ok = ok && (min >= 0 && min < 60);
			ok = ok && (sec >= 0 && sec < 60);
		}
	}
	
	//window.status += 'hour=' + hour + ', min=' + min + ', sec=' + sec;
	
	//--- Generate combined date/time in form "yyy-mm-dd hh:mm:ss" or time-only "hh:mm:ss".
	
	if (ok)
	{
		//window.status += 'formatting...';
	
		var tm;
		
		//--- Format date string as "yyyy-mm-dd".

		dt = '';

		if (!bTimeOnly)
		{
			month = FixDigits(month, 2);
			day = FixDigits(day, 2);
			dt = year + '-' + month + '-' + day;
		}
		
		//--- Format date string as "HH:mm:ss".

		if (!bDateOnly)
		{
			hour = FixDigits(hour, 2);
			min = FixDigits(min, 2);
			sec = FixDigits(sec, 2);
			tm = hour + ':' + min + ':' + sec;
		}
		
		if (bTimeOnly)
		{
			dt = tm;
		}
		else if (!bDateOnly)
		{
			dt = dt + ' ' + tm;
		}
		
		//window.status += dt;
	}
	else
	{
//		dt = val;
	}
	
//	if (typeof(dt) == 'undefined')
//	{
//		window.status += 'val=' + val + ', local=' + local; //'dt is undefined';
//	}
//	else
//	{
//		window.status += '[' + dt +']';
//	}

	return (dt);
}

// #4901 - Handle MMM and MMMM date formats.
function ParseMonth(mon)
{
	var nMon = parseInt(mon, 10);
	
	if (isNaN(nMon) && window.dt_months)
	{
		var ii;
	
		nMon = 0;	
		mon = mon.toLowerCase();
		
		for (ii=1; ii<dt_months.length; ii++)
		{
			if (dt_months[ii].toLowerCase().indexOf(mon) == 0)
			{
				nMon = (ii <= 12) ? ii : ii - 12;
				break;
			}
		}
	}
	
	return (nMon);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function CurrencyToFloat(val, local)
{
	var sym = (local && local.length > 2) ? local.substr(2,1) : '$';	// Localized currency symbol separator
	var pos = (local && local.length > 3) ? local.substr(3,1) : '+';	// Symbol location (+ means start, - means end)
	var neg = false;
	
	val = val.replace(/^\s*/, '');				// Remove leading whitespace
	val = val.replace(/\s*$/, '');				// Remove trailing whitespace

	//--- Remove leading negative sign, if any, and remember number was negative
	//--- so we can format appropriately below.
	
	if (val && val.indexOf('(') == 0 && val.indexOf(')') == val.length-1)
	{
		val = val.substr(1, val.length-2);
		neg = true;
	}
	
	//--- Strip out currency symbol.
	
	if (pos == '+' || pos == '0' || pos == '2')
	{
		var symPos = val.indexOf(sym);
		
		//--- Allow for values like "-$7.00" (vs. "$-7.00" which works withough special handling).
		
		if (symPos > 0 && val.match(/^-/))
		{
			val = val.substr(1);						// Skip leading minus
			val = val.replace(/^\s*/, '');				// Remove following whitespace
			symPos = val.indexOf(sym);					// Find currency symbol again
			neg = true;
		}
		
		if (symPos == 0)
		{
			val = val.substr(symPos + 1);				// Remove currency symbol prefix
			val = val.replace(/^\s*/, '');				// Remove following whitespace
		}
	}
	else
	{
		var n = val.lastIndexOf(sym);
		if (n == val.length - sym.length)
		{
			val = val.substring(0, n);					// Remove currency symbol suffix
			val = val.replace(/\s*$/, '');				// Remove preceding whitespace
		}
	}

	//--- Now indicate negative numbers w/ leading minus.
	
	if (neg) val = '-' + val;

	val = val.replace(/^\s*/, '');				// Remove following whitespace
	
	return StringToFloat(val, local);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function PercentToFloat(val, scale, local)
{
	val = val.replace(/\s*%$/g, '');	// Remove trailing percent sign (and its leading whitespace)
	val = parseFloat(StringToFloat(val, local));
	
	if (scale) val /= scale;
	
	return (val);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FloatToCurrency(val, local, fmt)
{
	var sym = (local && local.length > 2) ? local.substr(2,1) : '$';	// Localized currency symbol separator
	var pos = (local && local.length > 3) ? local.substr(3,1) : '+';	// Symbol location (+ means start, - means end)
	var digits = (fmt && fmt.match(/^[cC]\d$/)) ? fmt.substr(1,1) : '2'; //--- BugzID: 4813 - check for upper or lower C in format string

	//--- Convert the float to a well-formatted floating point string including 
	//--- appropriate thousands grouper and number of fractional digits.
	
	val = FloatToString(val, local, digits);

	//--- Remove leading negative sign, if any, and remember number was negative
	//--- so we can format appropriately below.
	
	var neg = false;
	
	if (val.match(/^-/))
	{
		val = val.substr(1);
		neg = true;
	}
	
	//--- Add currency symbol.
	
	if (pos == '-' || pos == '1' || pos == '3')
	{
		val = (pos == 3) ? val + ' ' + sym : val + sym;	// Trailing symbol (#5516 - w/ possible space between).
	}
	else
	{
		val = (pos == 2) ? sym + ' ' + val : sym + val;	// Leading symbol (#5516 - w/ possible space between).
	}
	
	//--- Negative currency indicated with enclosing parentheses.
	
	if (neg) val = '(' + val + ')';
	
	return (val);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function IntToString(val, local, fmt)
{
	var sep = (local && local.length > 1) ? local.substr(1,1) : ',';	// Localized thousands separator

    //--- #4297 - Only if non-null/blank val.

    if (val != null && val != '') 
    {
        val = parseInt(val);    // Convert to integer.
	    val = val.toString();   // Convert back to string (en-US format) and split up units and subunits.
    }
    
	//--- Add in thousands separators.

    if (fmt && fmt.indexOf('n') == 0)
    {
    	val = AddFloatGroupers(val, sep);
    }
    
    return (val);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FloatToString(val, local, fmt)
{
	var dec = (local && local.length > 0) ? local.substr(0,1) : '.';	// Localized decimal point
	var sep = (local && local.length > 1) ? local.substr(1,1) : ',';	// Localized thousands separator
	var digits = (fmt && fmt.match(/^\d$/)) ? parseInt(fmt, 10) : -1;
	
//	var scale = 1;
//	
//t	digits = -1;
	
//	//--- Generate a scale factor if fixed point.

//	if (digits > 0 && digits < 6)
//	{
//		var ii;
//		
//		for (ii=0; ii<digits; ii++)
//		{
//			scale *= 10;
//		}
//	}
	
	//--- Convert to number.

	val = parseFloat(val);
	
//	if (digits > 0 && digits < 6)
//	{
//		//--- We need to round to deal with calculations resulting in
//		//--- numbers like 19.99999996 which is really 20.00.

//		val = Math.round(val * scale) / scale;
//	}
	
	//--- Convert back to string (en-US format) and split up units and subunits.
	
	val = val.toString();
	
	var parts = val.split('.');
	var units = parts[0];
	var subunits = (parts.length > 1) ? parts[1] : '';
	
	//--- If fixed point, build subunits w/ fixed number of digits (zero padded right).
	//--- Note that now we don't truncate, only extend digits.
	
	if (digits > 0 && digits < 6)
	{
		if (digits > FractDigits(val)) subunits += '0000000000';
		subunits = subunits.substr(0, digits);	
	}
	
	//--- Add in thousands separators.

	units = AddFloatGroupers(units, sep);
	
	//--- Combine units and subunits.
	
	val = units;
	if (subunits) val += dec + subunits;
	
	return (val);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function AddFloatGroupers(units, sep)
{
	var separated = '';
	var group;
	
	while (units >= 1000)
	{
		group = '000' + (units % 1000);	
		separated = sep + group.substr(group.length-3) + separated;
		units = Math.floor(units / 1000);
	}
	
	return (units + separated);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FloatToPercent(val, local, fmt)
{
	val = FloatToString(val, local, fmt);
	
	val += ' %';
	
	return (val);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function DateToString(val, local)
{
	var s = val;

//	window.status += 'DateToString(' + val + ',' + local + ')';

	if (val && val != null && val != '')
	{
		//--- Generally assume val is in format: "yyyy-MM-dd HH:mm:ss"
		
		var timeOnly = (local && local.search(/[Mdyg]/) < 0 && local.search(/[hHmsfFtz]/) >= 0);

		var datetime = val.split(' ');
		var date = datetime[0].split('-');
		var day = parseInt(date[2], 10);
		var month = parseInt(date[1], 10);
		var year = parseInt(date[0], 10);
		
		var time = (timeOnly) ? datetime[0].split(':') : (datetime.length >= 2) ? datetime[1].split(':') : null;
		var hour = (time) ? parseInt(time[0].replace(/^0/,''), 10) : 0;
		var min = (time && time.length >= 2) ? parseInt(time[1], 10) : 0;
		var sec = (time && time.length >= 3) ? parseInt(time[2], 10) : 0;
		var hour24 = hour;
		
		if (local)
		{
			var	tt = 'am';
			
			local = local.replace(/\+/g, '');		// #4625 - Remove any date desc fmt.
	
			if (local.match(/t/))
			{
				if (hour == 0)
				{
					hour = 12;
				}
				else if (hour >= 12)
				{
					if (hour > 12) hour -= 12;
					tt = 'pm';
				}
			}
			s = local;
			s = s.replace(/yyyy/, year);
			s = s.replace(/yy/, FixDigits(year % 100, 2));
			s = s.replace(/dd/, FixDigits(day, 2));
			s = s.replace(/d/, day);
			s = s.replace(/hh/, FixDigits(hour, 2));
			s = s.replace(/h/, hour);
			s = s.replace(/HH/, FixDigits(hour24, 2));
			s = s.replace(/H/, hour24);
			s = s.replace(/mm/, FixDigits(min, 2));
			s = s.replace(/m/, min);
			s = s.replace(/ss/, FixDigits(sec, 2));
			s = s.replace(/s/, sec);
			s = s.replace(/tt/, tt);
			s = s.replace(/t/, tt.substr(0,1));

			if (s && s.indexOf('MMM') >= 0 && window.dt_months && month >= 1 && month <= 12)
			{
				s = s.replace(/MMMM/, dt_months[month]);	// Full
				s = s.replace(/MMM/, dt_months[month+12]);	// Abbrev.
			}
			else // #5626 - Don't subst digits if name resolveable else '1-5ay-2009' possible.
			{
				s = s.replace(/MM+/, FixDigits(month, 2));
				s = s.replace(/M/, month);
			}
		}
		else
		{
			s = month + '/' + day + '/' + year;
		}
	}
	else
	{
		s = ''; //null;	// #2217
	}
	
	return (s);
}

//-----------------------------------------------------------------------------------------
// Note:	Currently does NOT handle digits groupers (commas for thousands separators).
//-----------------------------------------------------------------------------------------
function ValidateInt(val, min, max, local)
{
	var bOK = true;
	
	if (val != null && val != '')
	{
		val = StringToInt(val, local);	// Delocalizes & strips leading and/or trailing whitepace
		
		bOK = val.match(/^[+-]?\d+$/);	// Optional sign followed by digits
	
		if (bOK && min)
		{
			bOK = parseInt(val, 10) >= parseInt(min, 10);
		}
		
		if (bOK && max)
		{
			bOK = parseInt(max, 10) >= parseInt(val, 10);
		}
	}
	
	return (bOK);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ValidateFloat(val, min, max, local)
{
	var	bOK = true;
	
	//--- Convert negative numbers indicated with enclosing parentheses to
	//--- a format with leading negative sign, e.g.: "(100)" --> "-100"
		
	if (val && val.indexOf('(') == 0 && val.indexOf(')') == val.length-1)
	{
		val = '-' + val.substr(1, val.length-2);
	}
	
	//---
	
	if (val != null && val != '')
	{
		val = StringToFloat(val, local);	// Delocalizes & strips leading and/or trailing whitepace
		
		//--- Optional leading sign, optional decimal point, digits
		
		var matchResults = val.match(/^(([+-]?\d+(\.\d*)?)|([+-]?(\d*\.)?\d+))$/);
		
		bOK = (matchResults != null && matchResults.length > 0 && matchResults[0].length > 0);
				
		if (bOK && min)
		{
			bOK = parseFloat(val) >= parseFloat(min);			
		}
		
		if (bOK && max)
		{
			bOK = parseFloat(max) >= parseFloat(val);
		}
	}
	
	return (bOK);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ValidatePercent(val, min, max, local)
{
	var	bOK = true;
	
	if (val != null && val != '')
	{
		val = val.replace(/\s*%$/g, '');	// Remove trailing percent sign (and its leading whitespace)
		
		bOK = ValidateFloat(val, min, max, local);
	
		if (bOK && min)
		{
			bOK = parseFloat(val) >= parseFloat(min);
		}
		
		if (bOK && max)
		{
			bOK = parseFloat(max) >= parseFloat(val);
		}
	}
		
	return (bOK);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ValidateDate(val, min, max, local)
{
	var bOk = true;

	if (val && val != null && val != '')
	{
		var dt = StringToDate(val, local);

		bOk = (dt != null && dt != '');
		
		if (bOk && min)
		{
			bOk = (dt >= StringToDate(min, local));
			//window.status += dt + '>=' + StringToDate(min) + ' (' + bOk + ')';
		}

		if (bOk && max)
		{
			bOk = (StringToDate(max, local) >= dt);
			//window.status += ', ' + StringToDate(max) + '>=' + dt + ' (' + bOk + ')';
		}
	}

	return (bOk);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ValidateCurrency(val, min, max, local)
{
    var f = CurrencyToFloat(val, local);
    
	var bOk = ValidateFloat(f);
	
	if (bOk && min)
	{
	    bOk = (parseFloat(f) >= CurrencyToFloat(min));	
	}

	if (bOk && max)
	{
		bOk = (CurrencyToFloat(max) >= parseFloat(f));
	}

	return (bOk);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ValidateEmail(addr, allowEmpty, allowMulti, allowName)
{
	if (allowMulti)
	{
		var ok = allowEmpty;
		//var addrs = addr.replace(/;/, ',').split(',');
		var addrs = addr.split(';');
		var ii;
		
		for (ii=0; ii<addrs.length; ii++)
		{
			if (!ValidateEmail(addrs[ii], allowEmpty, false, allowName))
			{
				ok = false;
				break;
			}
		}
		
		return (ok);
	}
	else if (addr == null || addr.length == 0)
	{
		return (allowEmpty);
	}
	else
	{
		addr = Trim(addr);
		
		if (allowName && addr.search(/^[^<]*<[^>]*>$/i) == 0)
		{
			addr = Trim(addr.substring(addr.indexOf('<')+1, addr.indexOf('>')));
		}
		
		//--- This expression has a very few outliers that it may reject,
		//--- e.g. john.doe@someplace.museum 
		//--- See http://www.regular-expressions.info/email.html
		//--- Modified for #3321, see http://www.faqs.org/rfcs/rfc2822.html
		//--- Gone back to http://www.regular-expressions.info/email.html  The last implementation of this regexp allowed the address
		//--- to have the format user@.lancashire.go.uk  The @. is certainly not allowed
		//--- this new expression plugs that gap in the last regex
		//--- partial fix for BugzID: 3800 RCA 8 Sep 08
		
		var expr = /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])$/i;
		
		return (0 == addr.search(expr));
	}
}

// Validate text min/max.
function ValidateText(val, min, max)		// #5887 - Support min/max on text.
{
	var bOK = true;
	
	if (val != null && val != '')
	{
		if (bOK && min)
		{
			bOK = (val >= min);
		}
		
		if (bOK && max)
		{
			bOK = (max >= val);
		}
	}
	
	return (bOK);
}

//-----------------------------------------------------------------------------------------
// Support per-row currency in editable list. #1235, improved w/ #5516.
function CurrencyLocale(ctrl, local)
{
	if (ctrl && ctrl.getAttribute)	// #2480 safety
	{
		var loc = ctrl.getAttribute('loc');
		
		if (loc)
		{
			local = loc;		// #5516 - Full locale spec.
		}
	}
	
	return (local);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ResolveExpr(fld, expr)
{
	var	rtn;
	
	if (expr.indexOf('[') < 0)
	{
		rtn = expr;
	}
	else
	{
		var clauses = expr.split('[');
		var ii;
		
		rtn = clauses[0];
		
		for (ii=1; ii<clauses.length; ii++)
		{
			var	end = clauses[ii].indexOf(']');
			var fieldId = clauses[ii].substring(0, end);
			//var sibling = GetSibling(fld, fieldId);

			//if (sibling)
			//{
			//	rtn += GetCellText(sibling); //sibling.value;
			//}
			rtn += GetSiblingValue(fld, fieldId);
			
			rtn += clauses[ii].substr(end+1);
		}
	}
	
	return (rtn);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetFieldKey(ctrl)
{
	var key = '';
	
	if (ctrl)
	{
		var lkup = ctrl.getAttribute('lkup');
		
		if (lkup)
		{
			key = lkup;
		}
		else if (ctrl.name)
		{
			var delim = ctrl.name.indexOf('$') > 0 ? '$' : ':';
			var parts = ctrl.name.split(delim);
			var iKey;

			iKey = parts.length - 1;
			key = parts[iKey];
		}
		else if (ctrl.getAttribute('use') == 'radio')
		{
			key = GetFieldKey(FindRadio(ctrl));		// #2241
		}
	}
	
	return (key);
}

// #2241 - Special handling for RadioButtons.
function FindRadio(ctrl)
{
	if (!ctrl || ElementType(ctrl) == 'radio')
		return (ctrl);
	else if (ctrl.childNodes.length < 1)
		return (null);
	else
	{
		var nodes = ctrl.childNodes;
		var ii;
		
		for (ii=0; ii<nodes.length; ii++)
		{
			ctrl = FindRadio(nodes[ii]);
			if (ctrl) break;
		}
	
		return (ctrl);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetFieldPrefix(ctrl)
{
	var prefix = '';
	
	if (!ctrl)
	{
	}
	else if (!ctrl.name && ctrl.getAttribute('use') == 'radio')
	{
		prefix = GetFieldPrefix(FindRadio(ctrl));		// #2241
	}
	else if (ctrl.name)
	{
		var delim = ctrl.name.indexOf('$') > 0 ? '$' : ':';
		var parts = ctrl.name.split(delim);
		var iKey;

		if (parts.length >= 2 && (parts[parts.length-1] == 'txt' || parts[parts.length-1] == 'btn' || parts[parts.length-1] == 'clr'))
		{
			iKey = parts.length - 2;	// Bndlkup
		}
		else
		{
			iKey = parts.length - 1;	// Everything else
		}

		//--- Reconstitute the NamingContainers prefix.
		
		for (var ii=0; ii<iKey; ii++)
		{
			prefix += parts[ii] + '_';
		}
	}
		
	return (prefix);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetDetailSibling(ctrl, fieldId)
{
	var sibling = null;
	//var key = GetFieldKey(ctrl);
	var prefix = GetFieldPrefix(ctrl);
	var siblingId = prefix + fieldId;
	
	//--- Find the sibling field.
	
	sibling = document.getElementById(siblingId);
	
	//--- If not found, maybe sibling is a BndLkup?
	
	if (!sibling)
	{
		sibling = document.getElementById(siblingId + '_txt');
	}
	
	return (sibling);
}

// Extract field reference flags.
function FieldRef(fieldId)		// #5887
{
	var ref = new Object();
	
	if (fieldId)
	{
		ref.flags = fieldId.match(/^[$'`#<&?@^+*]*/)[0];
		ref.id = fieldId.substr(ref.flags.length);
	}
	
	return (ref);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetDetailSiblingValue(ctrl, fieldId)
{
	var ref = FieldRef(fieldId);
	var sibling = GetDetailSibling(ctrl, ref.id);
	var val;
	
	if (sibling)
	{
		if (ref.flags && ref.flags.indexOf('$') >= 0 && ElementType(sibling) == 'select')
		{
			val = GetSelectText(sibling);		// #5887
		}
		else
		{
			val = sibling.value;
		}
	}
	
	return (val);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function AssociatedLabel(ctrl)
{
	var	lbl = null;
	var lbls = document.getElementsByTagName('label');
	var ii;
	var ctrlId = ctrl.id;
	
	//--- Special handling for BndLkup fields.
	
	if (IsBndLkup(ctrl))
	{
		ctrl = FindParent(ctrl, 'table');
		ctrlId = ctrl.id.replace(/_tbl$/, '');
	}
	
	//--- Find the label for this control.
	
	for (ii=0; ii<lbls.length; ii++)
	{
		if (lbls[ii].htmlFor == ctrlId)
		{
			lbl = lbls[ii];
			break;
		}
	}
	
	return (lbl);
}

//-----------------------------------------------------------------------------------------
// #2516 - Get owner window for specified DOM element.
function GetOwnerWin(ctrl)
{
	var doc = ctrl.ownerDocument;
    var win = doc.parentWindow;			// IE
    if (!win) win = doc.defaultView;	// Firefox, recent Safari

    if ((!win || win.screenTop == null) && IsSafari())		// Older Safari yields bogus win obj.
    {
		// No way to get win from doc w/ older Safari, but we fix that up.

		if (!doc.parWin)
		{
			// Safari-specific recursive func to add parent window ref from each doc obj.

			var fnWinRef = function(win)
						{
							win.document.parWin = win;
							for (var ii=0; ii<win.frames.length; ii++)
							{
								fnWinRef(win.frames[ii])
							}
						};

			fnWinRef(window.top);
		}
		
		win = doc.parWin;
    }
    
    return (win);
}

// From: http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256BF8004D72D6
function dumpProps(obj, parent) {
   // Go through all the properties of the passed-in object 
   for (var i in obj) {
      // if a parent (2nd parameter) was passed in, then use that to 
      // build the message. Message includes i (the object's property name) 
      // then the object's property value on a new line 
      if (parent) { var msg = parent + "." + i + "\n" + obj[i]; } else { var msg = i + "\n" + obj[i]; }
      // Display the message. If the user clicks "OK", then continue. If they 
      // click "CANCEL" then quit this level of recursion 
      if (!confirm(msg)) { return; }
      // If this property (i) is an object, then recursively process the object 
      if (typeof obj[i] == "object") { 
         if (parent) { dumpProps(obj[i], parent + "." + i); } else { dumpProps(obj[i], i); }
      }
   }
}

// Browser-specific extraction of an error description from an exception object.
function ErrorDesc(e)
{
	if (e.description)
	{
		return e.description;
	}
	else if (e.message && IsOpera())
	{
		var pos = e.message.indexOf('Backtrace:');
		
		return (pos >= 0) ? e.message.substr(0,pos) : e.message;
	}
	else if (e.message)
	{
		return e.message;
	}
}

// Validate a string with a regular expression capturing any errors.
// Returns false on match, else an error message on an exception, else a whitespace string on no match.
function RegExErr(s, exp, flags, opts)			// #5292
{
	try
	{
		return (!s) ? false : (s.match(exp, flags)) ? false : ' ';
	}
	catch (e)
	{
		return ((opts & 0x00000001) ? '\n\n' + ErrorDesc(e) : ErrorDesc(e));
	}
}

// Extract a field value for validation.
function GetValidationValue(ctrl)		// #4981 - Split out for reuse.
{
	var val;
	var ctrlType = ElementType(ctrl);
	//var isTextbox = (ctrlType == 'text');
	var isSelect = (ctrlType == 'select');
	var isList = (isSelect && ctrl.getAttribute('Multiple'));		// #5586
	var isCheckbox = (ctrlType == 'checkbox');
	var isRadio = (ctrlType == 'table' && ctrl.getAttribute('use') == 'radio');
	var isDuration = (ctrlType == 'span' && ctrl.getAttribute('use') == 'dur');
	
	//--- Get the control's value.
	
	if (ctrl == null)
	{
	    val = null;
	}
	else if (isList)	// #5586 multi-select handling.
	{
		val = GetListText(ctrl, false);
	}
	else if (isSelect)
	{
		var	iSel = ctrl.selectedIndex;
		
		if (iSel >= 0)
		{
			val = ctrl.options[iSel].value;
		}
	}
	else if (isRadio)
	{
		val = RadioButtonVal(ctrl);
	}
	else if (isDuration)
	{
		val = TimeDurationVal(ctrl);	// #599
	}
	else if (isCheckbox)
	{
		val = (ctrl.checked) ? 1 : 0;	// #3223
	}
	else
	{
		val = ctrl.value;
		
		//--- Handle watermark.
		
		var wm = ctrl.getAttribute('wm');
		
		if (wm && wm == ctrl.value)
		{
			val = '';
		}
	}
	
	return (val);
}

// Apply validation to the specified control.
function ApplyValidation(ctrl, msg, silent)		// #4981 - Split out for reuse.
{
    //--- BugzID: 5370 - Protect against missing control. RCA 1 Oct 09
    if (ctrl != null)
    {
	    var lbl = AssociatedLabel(ctrl);
    	
	    //--- If validation function returned a message then validation failed else succeeded.
    	
	    if (msg)
	    {
		    //--- Save initial tooltips since we'll be overwriting them.
    		
		    if (!ctrl.validInit)
		    {
			    ctrl.validInit = true;
			    ctrl.origTitle = ctrl.title;
			    if (lbl) lbl.origTitle = ctrl.title;
		    }

		    //--- Put control into error state.
    		
		    ReplaceCssClass(ctrl, 'detailerr', 'detailerr');
		    SetTip(ctrl, msg);

		    //--- Put label into error state.
    		
		    if (lbl)
		    {
			    SetTip(lbl, msg);
			    ReplaceCssClass(lbl, 'detailerr', 'detailerr');
		    }

		    //--- If not in silent mode, present error message to user.

		    if (!silent) 
		    {
			    window.setTimeout(function() { SetFocus(ctrl); alert(msg); }, 10);
		    }
	    }
	    else
	    {
		    //--- Restore control to non-error state.
    	
		    ReplaceCssClass(ctrl, 'detailerr', '');					// Restore class
		    SetTip(ctrl, ctrl.origTitle);							// Restore tooltip
    		
		    //--- Restore associated label to non-error state.
    	
		    if (lbl)
		    {
			    ReplaceCssClass(lbl, 'detailerr', '');				// Restore
			    SetTip(lbl, lbl.origTitle);							// Restore tooltip
		    }
	    }
    }
    	
	return (!msg);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function PerformValidation(evt, item, fnName, silent, full, virtForm)
{
	if (!evt) evt = window.event;
	
	var msg = '';
	var win = null;
	var fn = null;
	var ctrl = GetElement(item);			// Ctrl or its id passed

	if (!ctrl && IsString(item)) ctrl = document.getElementById(item + '_txt');	// BndLkup?
	
	//--- If we found a control, get its validation function and window.
	//--- Note that the control's window may NOT be the same as the current window!
	
	if (ctrl)
	{
		var	virtFormCtrl = ctrl.getAttribute('virtualForm');

		if (typeof virtForm == 'undefined' || !virtForm) virtForm = '';
		if (typeof virtFormCtrl == 'undefined' || !virtFormCtrl) virtFormCtrl = '';
		
		if (('' + virtForm) != ('' + virtFormCtrl))
		{
			null;	// Control is not on invoker's virtual form, don't validate it.
		}
		else
		{
			win = GetOwnerWin(ctrl);	// #2516
		}

		if (win)
		{
	    	fn = win.eval('window.' + fnName);
	    }
    }
	
	//--- If we found a validation function, use it.
	
	if (win && fn)
	{
		var val = GetValidationValue(ctrl);		// #4981 - Split out for reuse.
		
		//--- Call the field's validation function.
		
		msg = fn(ctrl, val, full);
		
		//--- If validation function returned a message then validation failed else succeeded.
		
		ApplyValidation(ctrl, msg, silent);		// #4981 - Split out for reuse.
	}
	
	//--- If there's a ValidateAll() and we're doing normal (non-silent) validation
	//--- Call ValidateAll() to validate all appropriate fields and possibly perform
	//--- row calculations.
	
	if (win && !silent && window.ValidateAll)
	{
		msg = win.ValidateAll();
		
		//win.status = msg;
		
		//--- If everything validated OK, perform the row calculation.
		
		if (!msg && win.RowCalc) win.RowCalc(GetFieldPrefix(ctrl));
	}
		
	return (msg);
}

//-----------------------------------------------------------------------------------------
function RadioButtonSel(tbl)
{
	tbl = GetElement(tbl);
	
	var rad = null;
	var inputs = window.document.getElementsByTagName('input');
	var ii;
	
	for (ii=0; ii<inputs.length; ii++)
	{
		var item = inputs[ii];
		
		if (item.type.toLowerCase() == 'radio' &&
			item.id.substr(0, tbl.id.length) == tbl.id &&
			item.checked)
		{
			rad = item;
			break;	
		}
	}
	
	return (rad);
}

// Extract value from RadioButton field.
function RadioButtonVal(tbl)
{
	var rad = RadioButtonSel(tbl);
	
	return (rad) ? rad.value : null;
}

// #3436 - Get text of selected RadioButton.
function RadioButtonText(tbl)
{
	var rad = RadioButtonSel(tbl);
	var txt;
	
	if (rad)
	{
		var lbl = FindLabelFor(rad);
			
		if (lbl) txt = GetCellText(lbl);
	}
	
	return (txt);
}

// #3436 - Set RadioButton item by its text.
function RadioSetByText(tbl, txt)
{
	tbl = GetElement(tbl);
	
	var items = document.getElementsByName(tbl.id);
	
	for (var ii = 0; ii<items.length; ii++)
	{
		var item = items[ii];
		
		if (ElementType(item) == 'radio')
		{
			var lbl = FindLabelFor(item);
			
			if (lbl && GetCellText(lbl) == txt)
			{
				item.checked = true;
				break;
			}
		}
	}
}

function RadioSetByValue(tbl, val, evt)
{
	tbl = GetElement(tbl);
	
	var items = document.getElementsByName(tbl.id);
	
	for (var ii = 0; ii<items.length; ii++)
	{
		var item = items[ii];
		
		if (ElementType(item) == 'radio' && item.value == val)
		{
			item.checked = true;
			OnChange(item, evt);
			OnClick(item);
			break;
		}
	}
}

// Extract platform radio button item options, if any.
function RadioItemOpts(tbl)	// #5886
{
	var rad = RadioButtonSel(tbl);
	var opts = (rad && rad.parentNode) ? rad.parentNode.getAttribute('itemopts') : '';
	
	return (opts) ? opts : '';
}

//-----------------------------------------------------------------------------------------
// #599 -- Extract value from TimeDuration field.
// #4236 - Duration localization.
function TimeDurationVal(ctrl)
{
	var val = '';
    var loc = ctrl.getAttribute('loc');				// #4236 - Get localization spec.
    var hrs = ctrl.firstChild;
    var elType = ElementType(hrs);
    
    if (elType == 'select')
    {
		var hr = hrs.value;
		var min = (hrs.nextSibling != null) ? hrs.nextSibling.value : 0;	// #5372 - If no minute sibling, default to 0.
		
		if ((hr != null && hr != '') || (min != null && min != ''))
		{
			hr = (hr != null && hr != '') ? parseInt(hr, 10) : 0;
			min = (min != null && min != '') ? parseInt(min, 10) : 0;

			val = hr + (min/60);
			val = FloatToString(val, loc, '2');     // #4236
		}
    }
    else if (elType == 'text')						// #5372 - Rendered as floating point hours in textbox when locked.
    {
		val = hrs.value;
    }
	
	return (val);
}

// Gets semi-colon-separate list of items from Multiple SELECT control.
function GetListText(ctrl, selectedOnly) // #5586 multi-select handling.
{
	var val = '';
	var ii;
	
	for (ii=0; ii<ctrl.options.length; ii++)
	{
		if (!selectedOnly || ctrl.options[ii].selected) val += ';' + ctrl.options[ii].text
	}
	
	return (val.length > 0) ? val.substr(1) : val;
	
	return (val);
}

//-----------------------------------------------------------------------------------------
function GetSelectText(ctrl)
{
	var txt;
	var iSel = ctrl.selectedIndex;
		
	if (iSel >= 0) txt = ctrl.options[iSel].text;
	
	return (txt);
}

//-----------------------------------------------------------------------------------------
function SetSelectText(ctrl, s)
{
	var ii;
	
	for (ii=0; ii<ctrl.options.length; ii++)
	{
		if (ctrl.options[ii].text == s)
		{
			ctrl.options[ii].selected = true;
			break;
		}
	}
}

function CboText(cbo)
{
	return cbo.options[cbo.selectedIndex].text;
}

function CboValue(cbo)
{
	return cbo.options[cbo.selectedIndex].value;
}

// #5015 - Clear all options & optgroups from a select control.
function ClearSelect(ctrl)
{
	ctrl.options.length = 0;					// Clear options
	while (ctrl.childNodes.length > 0) 
	{
		ctrl.removeChild(ctrl.childNodes[0]);	// Clear optgroups
	}
}

//-----------------------------------------------------------------------------------------
// #1711 -- Extract value from TimePicker field.
function TimePickerVal(ctrl)
{
	var hr = document.getElementById(ctrl.id.replace(/_tbl$/, '_hr'));
	var min = document.getElementById(ctrl.id.replace(/_tbl$/, '_min'));
	var val = '';
	
	hr = GetSelectText(hr);
	min = GetSelectText(min);
	
	if ((hr != null && hr != '') || (min != null && min != ''))
	{
		if (hr != null && hr != '' && (min == null || min == '')) min = '00';
		
		val = '' + hr + ':' + min;
	}
	
	return (val);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function SetFocus(item, sel, immed)
{
	//--- #4602 - Delay here.
	
	if (!immed)
	{
		window.setTimeout(function() { SetFocus(item, sel, 1); } , 1);
		return;
	}
	
	//--- After delay above, set focus.
	
	var ctrl = GetElement(item);

	if (ctrl && CanGetFocus(ctrl)) 
	{
		if (ctrl.focus)
			ctrl.focus();
		else if (ctrl.onfocus)
			ctrl.onfocus();
			
		if (sel)
		{
			if (ctrl.select) 
				ctrl.select();
			else if (ctrl.onselect) 
				ctrl.onselect();
		}
	}
}

// Set focus to the first child node that can take focus. #3928
function SetFocusFirst(item, sel, recurse)
{
	var ctrl = GetElement(item);
	
	if (ctrl)
	{
		var ii;
		
		for (ii=0; ii<ctrl.childNodes.length; ii++)
		{
			var node = ctrl.childNodes[ii];
			
			if (CanGetFocus(node))
			{
				SetFocus(node, sel);
				return (true);
			}
			else if (recurse && SetFocusFirst(node, sel, recurse))
			{
				return (true);
			}
		}
	}
	
	return (false);
}

//-----------------------------------------------------------------------------------------
// Get the text for a table cell (TD).
//-----------------------------------------------------------------------------------------
function GetCellText(cell)
{
	var txt = '';
	
	if (cell)
	{
		var elType = ElementType(cell);
		
		if (elType == 'checkbox')
		{
			txt = (cell.checked) ? '1' : '0';	// #1639
		}
		else if (elType == 'textbox' || elType == 'hidden')
		{
			txt = cell.value;		// #1673
		}
		else if (cell.innerText)
		{
			txt = cell.innerText;	// IE
		}
		else if (cell.textContent)
		{
			txt = cell.textContent;	// Mozilla
		}
		else
		{
			if (cell.childNodes && cell.childNodes.length > 0 && cell.childNodes[0].innerHTML)
			{
				txt = cell.childNodes[0].innerHTML;
			}
			else
			{
				txt = cell.innerHTML;
			}
		}
	}
	
	return (txt);
}

//-----------------------------------------------------------------------------------------
// Set the text for a table cell (TD).
//-----------------------------------------------------------------------------------------
function SetCellText(cell, val)
{
	if (cell)
	{
		if (cell.innerText)
		{
			cell.innerText = val;	// IE
		}
		else
		{
			if (cell.childNodes && cell.childNodes.length > 0 && cell.childNodes[0].innerHTML)
				cell.childNodes[0].innerHTML = val;
			else
				cell.innerHTML = val;
		}
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function InnerTextSet(item, val)
{
	if (item)
	{
		if (item.innerText)
		{
			item.innerText = val;		// IE
		}
		else if (item.textContent)
		{
			item.textContent = val;		// Mozilla
		}
		else // ???
		{
			if (item.childNodes && item.childNodes.length > 0 && item.childNodes[0].innerHTML)
			{
				item.childNodes[0].innerHTML = val;
			}
			else
			{
				item.innerHTML = val;
			}
		}
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function InnerTextGet(item)
{
	var txt;

	if (item.innerText)
	{
		txt = item.innerText;	// IE
	}
	else if (item.textContent)
	{
		txt = item.textContent;	// Mozilla
	}
	
	return (txt);
}

//-----------------------------------------------------------------------------------------
// Get the value for an element regardless of element type.
//-----------------------------------------------------------------------------------------
function GetValue(ctrl)
{
	var val;
	var elType = ElementType(ctrl);
	
	if (elType == 'text' || elType == 'hidden')		// #5433
	{
		val = ctrl.value;
	}
	else if (elType == 'select')
	{
		var iSel = ctrl.selectedIndex;
		
		if (iSel >= 0) val = ctrl.options[iSel].value;
	}
	else if (elType == 'td')
	{
		val = GetCellText(ctrl);
	}
	
	return (val);
}

//-----------------------------------------------------------------------------------------
// Get the text for an element regardless of element type.
//-----------------------------------------------------------------------------------------
function GetText(ctrl)
{
	var txt;
	var elType = ElementType(ctrl);
	
	if (elType == 'text')
	{
		txt = ctrl.value;
	}
	else if (elType == 'select')
	{
		var iSel = ctrl.selectedIndex;
		
		if (iSel >= 0) txt = ctrl.options[iSel].text;
	}
	else // #1673
	{
		txt = GetCellText(ctrl);
	}
	
	return (txt);
}

// Get the numeric value for an element regardless of element type (handles expression '#' modifier).
function GetNum(ctrl)	// #5671
{
	var n = GetText(ctrl);
	
	if (n == null || n == '')
		n = 0;
	else if (n.toLowerCase() == 'true')
		n = 1;
	else if (n.toLowerCase() == 'false')
		n = 0;
	
	return (n);
}

//-----------------------------------------------------------------------------------------
// Set the value for an element regardless of element type.
//-----------------------------------------------------------------------------------------
function SetValue(ctrl, val)
{
	var elType = ElementType(ctrl);
	
	if (elType == 'text')
	{
		ctrl.value = val;
	}
	else if (elType == 'select')
	{
		var ii;
		
		for (ii=0; ii<ctrl.options.length; ii++)
		{
			if (ctrl.options[ii].value == val)
			{
				ctrl.selectedIndex = ii;
				break;
			}
		}
	}
	else if (elType == 'td')
	{
		SetCellText(ctrl, val);
	}
}

//-----------------------------------------------------------------------------------------
// Determine if a control/cell value is set or not. #1981
//-----------------------------------------------------------------------------------------
function IsSet(cell)
{
	var isSet = false;
	
	if (cell)
	{
		var elType = ElementType(cell);
		
		if (elType == 'checkbox')
		{
			isSet = (cell.checked);
		}
		else if (elType == 'text' || elType == 'hidden')
		{
			isSet = (cell.value != null && cell.value != '');
		}
		else if (cell.innerText)
		{
			isSet = (cell.innerText && cell.innerText != null);	// IE
		}
		else if (cell.textContent)
		{
			isSet = (cell.textContent && cell.textContent != null);	// Mozilla
		}
		else
		{
			if (cell.childNodes && cell.childNodes.length > 0 && cell.childNodes[0].innerHTML)
			{
				isSet = (cell.childNodes[0].innerHTML && cell.childNodes[0].innerHTML != '');
			}
			else
			{
				isSet = (cell.innerHTML && cell.innerHTML != '');
			}
		}
	}
	
	return (isSet);
}


//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
var gBaseDt = new Date(2001, 00, 01, 00, 00, 00);
function Timestamp()
{
//	return Date().toString().replace(/[\s:\-\)\(]/g,'');
	return '' + (new Date() - gBaseDt);	// ms since 1/1/2001.
}

// Refresh current doc.
function RefreshDoc()
{
	var href = document.location.href.split('#');
	var url = href[0];

    //--- BugzID: 4633 - add link information
    url = UpsertUrl(url, 'act', 'rfsh');
    
	//--- #2044 - Force timestamp on refresh.

	url = UpsertUrl(url, 'uts', Timestamp());

	//--- #3768 - Add active subform, if any.
	
	if (window.ActiveSubform)
	{
		var actsub = window.ActiveSubform();
		
		if (actsub) url = UpsertUrl(url, 'asf', actsub);	// #3939 - Only if actsub.
	}
	
	//--- #3778 - Add active RowKey, if any.
	
	if (window.rowKey)
	{
		url = UpsertUrl(url, 'ark', window.rowKey);
	}

	//--- Restore href beyond hash.
		
	if (href.length > 1) url += '#' + href[1];
	
	document.location.replace(url);
}

// Add or replace item in url (for #3768).
function UpsertUrl(url, nm, val)
{
	var qpItem = '&' + nm + '=';
	var hkItem = '?' + nm + '=';
	
    //--- BugzID: 4633 - allow replacement right after the hook
	if (url.indexOf(hkItem) > 0)
	{
	    url = url.replace(new RegExp('\\' + hkItem + '[^&]*'), hkItem + val);
	}
	else
	{
	    if (url.indexOf(qpItem) > 0)
	    {
    		url = url.replace(new RegExp(qpItem + '[^&]*'), qpItem + val);
	    }
	    else
	    {
		    url += qpItem + val;
		}
	}
	
	return (url);
}

// Support posting back cmd.
function SetPgCmd(cmd)			// #5680
{
	var nm = 'eappgcmd';
	var cmdEl = GetElement(nm);
	
	if (!cmdEl)
	{
		var frm = document.forms[0];
		
		cmdEl = AddHiddenInput(frm, nm);
	}
	
	cmdEl.value = cmd;
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START discrim handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Called when a combo with discrim dependencies is changed to apply discrim to all dependent
// combos.
//-----------------------------------------------------------------------------------------
function DependencyCascade(evt, ctrl, msg)	// #4782
{
	var prefix = GetFieldPrefix(ctrl);
	var depends = ctrl.getAttribute('depends');
	var keys = depends.split(';');
	var ii;
	
	//--- Recursively clear all dependent fields.
	
	DependencyClear(ctrl);
	
	//--- Apply discrim to all dependent fields.
	
	for (ii=0; ii<keys.length; ii++)
	{
		var ctrlId = prefix + keys[ii];
		var ctrlDepend = document.getElementById(ctrlId);
		
		if (ctrlDepend) ApplyDiscrim(ctrlDepend, msg);		// #4782
	}
}

//-----------------------------------------------------------------------------------------
// Recursively clears all dependent fields.
//-----------------------------------------------------------------------------------------
function DependencyClear(cbo, clr)
{
	var prefix = GetFieldPrefix(cbo);
	var depends = cbo.getAttribute('depends');
	
	if (clr)
	{
		if (cbo.options)
		{
			cbo.options.length = 0;

			//--- #4494 - Remove any optgroup tags.
			
			while (cbo.childNodes.length > 0)
			{
				cbo.removeChild(cbo.childNodes[0]);
			}
		}

		cbo.value = '';	// #326 -- Always
		
		if (cbo.getAttribute("dynlock")) cbo.disabled = true;
	}
	
	if (depends)
	{
		var keys = depends.split(';');
		var ii;
		
		//--- Apply discrim to all dependent fields.
		
		for (ii=0; ii<keys.length; ii++)
		{
			var ctrlId = prefix + keys[ii];
			var ctrlDepend = document.getElementById(ctrlId);
			
			if (ctrlDepend) DependencyClear(ctrlDepend, true);
		}
	}
}

//-----------------------------------------------------------------------------------------
// Called when a combo that has discrim dependencies is changed using AJAX to update 
// the picklist.
function ApplyDiscrim(cbo, msg)
{
	var discrim = cbo.getAttribute('discrim');
	
	if (discrim)
	{
		discrim = ResolveExpr(cbo, discrim);
		
		//--- If we have a discrim, then go get the now-discrimmed-in picklist.
		
		if (discrim)
		{
			window.status = msg;	// #4782
			Discrim(cbo.getAttribute('pickid'), discrim, cbo, DiscrimReturned);
		}
	}
}

// Retrieve a discrimmed list.
function Discrim(pick, discrim, cbo, fn)
{
	var params = 'name=' + pick + '&discrim=' + discrim + '&ctrl=' + cbo.id;

	AjaxReq('discrim', params, fn);
}

//-----------------------------------------------------------------------------------------
// Called when an AJAX response is received with discrim-dependent picklist items.
//-----------------------------------------------------------------------------------------
function DiscrimReturned(rsp, s)
{
	var lst = rsp;
	var pos = lst.indexOf(';');
	var id = lst.substr(0, pos);
	var cbo = document.getElementById(id);
	
	//--- Remove leading value (the id of the field to update).
		
	lst = lst.substr(pos+1);
	window.status = '';
	if (cbo)
	{
		var ii;

		//--- Add a blank item and select it.
		
		AddOption(cbo, '', '');
		cbo.selectedIndex = 0;
		
		//--- Add the new items.
		
		var grps = new Array();
		var lastgrp = null;
		var pairs = lst.split(';');
		var opt;
		
		for (ii=0; ii<pairs.length; ii++)
		{
			var item = pairs[ii].split('=');
			var val = item[0];
			var txt = item[1];
			var grp = (val && val.indexOf(':') > 0) ? val.split(':')[0] : null;
			
			if (grp) 
				val = val.split(':')[1];	// Remove grp from val
			else
				grp = lastgrp;				// Use last grp (maybe none)
			
			if (!val || !txt)
			{
				opt = null;
			}
			else if (grp)					// #4494 - OK w/ Safari v2.0.4 and later (maybe older too).
			{
				var og = grps[grp];
				
				if (og == null)
				{
					og = document.createElement('optgroup');
					og.label = grp;
					grps[grp] = og;
					lastgrp = grp;
					cbo.appendChild(og);
				}
				
				opt = document.createElement('option');
				if (IsIE())
					opt.innerText = txt;
				else
					opt.text = txt;
				opt.value = val;
				og.appendChild(opt);
			} 
			else // No group
			{
				opt = AddOption(cbo, txt, val);
			}
			
			//--- #5015 - If match, select item.
			
			if (opt && txt == s)
			{
				opt.selected = true;
			}
		}
		
		//--- If the control is marked for dynamic locking, lock it now.
		
		if (cbo.getAttribute("dynlock")) cbo.disabled = false;
		
		//--- Cascade change.
		
// No? #677		if (cbo.onchange) cbo.onchange();
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END discrim handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START AutoSuggest handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

var asbMaxLen = 10;

// Look for <cr> or <backspace>
function asbOnKeyPress(evt)
{
	var key = GetEventKey(evt);
	//asbTRACE("asbOnKeyPress : " + asbGetKey(evt));
	return !((key == 13 && window.g_bCancelSubmit) || key == 27);
}

// Handle AutoSuggest control keys, left, right, up, down, <cr>, <esc>, etc.
function asbOnKeyDown(evt, divId) // sTextBoxID, sDiv)
{
	if (!evt) evt = window.event;
	
	//asbTRACE("asbOnKeyDown : " + asbGetKey(evt));
	var div = document.getElementById(divId);
	
	div.textBoxId = GetEventTarget(evt).id;	//sTextBoxID;
	
	//asbTRACE("asbOnKeyDown : old text box value='" + g_sOldTextBoxValue + "'");
	
	var nKey = GetEventKey(evt);
					
	//Detect if the user is using the down button
	if (nKey == 38) //Up arrow
	{
		asbMoveUp();
		return CancelBubble(evt);	// #4728
	}
	else if (nKey == 40) //Down arrow
	{
		asbMoveDown();
		return CancelBubble(evt);	// #4728
	}
	else if (nKey == 27)	// Esc
	{
		asbHideDiv(divId, 1);
		window.g_bCancelSubmit=false;
	}
	else if (nKey == 13) //Enter
	{
		//asbTRACE("asbOnKeyDown : asbIsVisibleDiv - " + asbIsVisibleDiv(sDiv));
		if (IsVisible(divId))
		{
			var applied = false;
		
			if (asbListLen(div) == 1)
			{
				asbApplyIfSingleEntry(div);
				applied = true;
			}
			else if (div.selected)
			{
				asbApplySelection(div.id, div.textBoxId, div.selected.id);
				applied = true;
			}
			
			if (applied)
			{
				CancelBubble(evt);
			}
				
			window.g_bCancelSubmit = true;
 		}
 		else
 		{
 			window.g_bCancelSubmit=true; //false;
 		}
	}
	else if (nKey == 9)	// Tab
	{
		asbApplyIfSingleEntry(div);
	}
	else
	{
		var txt = document.getElementById(div.textBoxId);
		
		txt.dirty = true;
		txt.found = false;
//		asbHideDiv(divId);
	}
			
	return true;
}

// Handle AutoSuggest non-control key (i.e. something to filter)
function asbOnKeyUp(evt, divId, mapper, key)	//sTextBoxID, sDiv, sDataType, evt)
{
	var div = document.getElementById(divId);

	div.textBoxId = GetEventTarget(evt).id;
	var txt = document.getElementById(div.textBoxId);
	
	var nKey = GetEventKey(evt);
	
	if (!IsVisible(txt)) return;	// #4728 Needed in ListEdit
	
//c	asbTRACE("asbOnKeyUp : " + nKey);
	
	
	//Skip up/down/enter/esc/tab
	if (nKey != 38 && nKey != 40 && nKey != 13 && nKey != 27 && nKey != 9)
	{
		var sNewValue = asbGetTextBoxValue(divId);
		
//c		asbTRACE("asbOnKeyUp : New text box value '" + sNewValue + "'");
			
		var requestNeeded = true;

		//--- If the new string is a refinement of the previous string
		//--- (that is, the user just typed more onto the end of the string),
		//--- try to filter out existing items w/out going back to the server.
		
		if (div.key == key && 
			div.lastText && sNewValue && sNewValue.indexOf(div.lastText) == 0)
		{
			//--- If there are more than 10 items it means the previous results
			//--- were truncated.  Therefore, the list is not complete and we 
			//--- need to go back to the server.  If not, we have the entire list
			//--- of potential matches, so weed out the non-matches.
			
			if (asbListLen(div) <= asbMaxLen)
			{
				var nVisible = asbFilterList(div, sNewValue);
				div.style.visibility = '';
				requestNeeded = (nVisible <= 0);
			}
		}
		
		//--- We need to go back to the server.
		
		if (requestNeeded)
		{
			if (div.suggestTimeout) window.clearTimeout(div.suggestTimeout);
			div.mapper = mapper;
			div.key = key;
			div.isActive = true;

			var picklist = txt.getAttribute('picklist');
			var pick = txt.getAttribute('pick');
			
			if (picklist)
			{
				//--- All client-side handling because list is in html, semi-colon separated.
				
				var sequence = (div.sequence) ? parseInt(div.sequence, 10) + 1 : 1;
	
				div.sequence = sequence;
				div.pick = picklist;
				div.suggestTimeout = window.setTimeout(function () { asbAutoSuggestPick(sequence, divId); }, 150);
			}
			else if (pick)
			{
				//--- Picklist identified, but have to hit server to get items.
				
				div.suggestTimeout = window.setTimeout(function () { asbAutoSuggest(divId, pick); }, 350);
			}
			else
			{
				//--- Other.
				
				div.suggestTimeout = window.setTimeout(function () { asbAutoSuggest(divId); }, 350);
			}
		}
		
		div.lastText = sNewValue;
	}
}

function asbAutoSuggest(divId, pick)
{
	var div = document.getElementById(divId);
	var val = asbGetTextBoxValue(divId);

	if (val && val.length > 0)
	{
		asbGetDataFromServer(val, divId, div.mapper, div.key, pick);
	}
	else
	{
		asbHideDiv(divId);
	}
}

// Get the text for the control that is using AutoSuggest.
function asbGetTextBoxValue(divId)
{
	var div = document.getElementById(divId);
	var txt = document.getElementById(div.textBoxId);

	return ((txt) ? txt.value : '');
}

function asbTRACE(txt)
{
	//var sMessage = window.document.forms[0].txtTRACE.value;
	//sMessage = sMessage + sText + "\n";;
	//window.document.forms[0].txtTRACE.value = sMessage;
	//window.status += txt;
}

// Issue AJAX request to the server to get the AutoSuggest list.
function asbGetDataFromServer(val, divId, mapper, key, pick)
{
	var conn = new XHConn();

	//--- If connection established, issue a request for the discrimmed picklist.
	//--- The response will be passed to the asbSuggestionReturned() method.
		    
	if (conn)
	{
		var div = document.getElementById(divId);
		var txt = document.getElementById(div.textBoxId);
		var params = 'req=suggest';
		var sequence = (div.sequence) ? parseInt(div.sequence, 10) + 1 : 1;
		
		params += '&div=' + divId;
		params += '&text=' + val;
		params += '&id=' + div.textBoxId;
		params += '&seq=' + sequence;
		
		var pss = txt.getAttribute('pss');		// #5212
		
		if (pss)
		{
			params += '&pss=' + encodeURI(pss);
			
			var db = txt.getAttribute('db');
			
			if (db) params += '&db=' + db;
		}
		else if (pick)
		{
			params += '&pick=' + encodeURI(txt.getAttribute('pick'));
		}
		else // Find asb
		{
			var findMap = txt.getAttribute('HostMap');			// #5719
			var findFltFlds = txt.getAttribute('FindFltFlds');	// #5719
			var hostKey = txt.getAttribute('HostKey');
			var hostFlv = txt.getAttribute('HostFlv');
			
			if (findMap) params += '&FindMap=' + findMap;
			if (hostKey) params += '&HostKey=' + hostKey;
			if (hostFlv) params += '&HostFlv=' + hostFlv;
			if (findFltFlds) params += '&FindFltVals=' + resolvePageInstanceValues(txt, findFltFlds);
		}
		
		div.sequence = sequence;

		conn.connect('Handler.ashx', 'GET', params, asbSuggestionReturned);
	}
}

//--- Handle AJAX AutoSuggest response.
function asbSuggestionReturned(rsp)
{
	asbHandleResponse(rsp.responseText);
}

//--- Handle an AutoSuggest list (from AJAX or script)
function asbHandleResponse(txt)
{
	var divId = 'asbMenu';
	
	if (txt && txt.length > 0)
	{
		var pos = txt.indexOf(";");
		var seq = txt.substr(0, pos);
		
		txt = txt.substr(pos+1);

		var div = document.getElementById(divId);

		//--- Only show if still active and this is the current request.
		//--- Since each request is given a sequence number which is returned
		//--- in the response, we use that to determine currency.
		
		if (div.sequence == seq && div.isActive)
		{
			asbShowDiv(divId, txt);
		}
	}				
	else
	{	
		asbHideDiv(divId);
	}
}

// Show the AutoSuggest list.
function asbShowDiv(divId, sDivContent)
{
	var divMenu = document.getElementById(divId);
	var txt = document.getElementById(divMenu.textBoxId);
	
	//divMenu.style.visibility = 'hidden';
	asbHideDiv(divId);

	divMenu.selected = null;
	
	var sInnerHtml;
	
	divMenu.style.visibility = 'hidden';	// #3878 - First hide,
	divMenu.style.display = '';				// #3878 - Now display (still hidden) for proper sizing.  We'll unhide below.

	//--- Build the content div.
	
	sInnerHtml = "<div id='" + divId + "_content' style='z-index:9050; position:absolute;'>";
	sInnerHtml += sDivContent;
	sInnerHtml += "</div>";

	if (IsIE())
	{
		//--- We use an iframe here so that we don't come up behind SELECT's in IE.

		sInnerHtml += "<iframe id='" + divId + "_iframe' src='blank.htm' frameborder='0' scrolling='no'></iframe>";
	}
	else
	{
		//--- We don't need an iframe in non-IE browsers, but to keep the list's DOM
		//--- model the same in all browsers, we use a div on other browsers.

		sInnerHtml += "<div id='" + divId + "_iframe'></div>";
	}
	
	divMenu.innerHTML = sInnerHtml;
	
	var divContent = document.getElementById(divId + "_content");
	var divIframe = document.getElementById(divId + "_iframe");
			
	SetCssClass(divContent, 'asbMenu');
	SetCssClass(divMenu, 'asbMenuBase');

	//--- Position the div.
		
	divMenu.style.top = (getTop(txt, divMenu) + txt.offsetHeight + 1) + 'px';
	divMenu.style.left = getLeft(txt, divMenu) + 'px';
	divContent.style.height = divContent.offsetHeight + 'px'; //a
	divIframe.style.height = divContent.offsetHeight + 'px';
	
	//--- And show it.
	
	divMenu.style.visibility = 'visible';
	
	var width;
	
	if (IsIE())
	{
		width = txt.offsetWidth;
	}
	else
	{	
		width = GetRight(divContent) - getLeft(divContent);
		
		if (width < txt.offsetWidth) 
		{
			width = txt.offsetWidth;
			
			var padLeft = GetStyle(divContent, 'padding-left').replace(/px/, '');
			var padRight = GetStyle(divContent, 'padding-right').replace(/px/, '');
			
			if (padLeft) width -= padLeft;
			if (padRight) width -= padRight;
		}
	}

	divMenu.style.width = width;
	divContent.style.width = width;
	divIframe.style.width = width;

	txt.menu = divMenu;
}

// Hide the AutoSuggest list.
function asbHideDiv(divId, delay)
{
	if (delay)
	{
		window.setTimeout(function() { asbHideDiv(divId); }, delay);
	}
	else
	{
		var div = document.getElementById(divId);
		
		div.style.width = null;
		div.style.display = 'none';	// #3878
	}
}

// Handle mouseover on the AutoSuggest list.
function asbOnMouseOver(divId, txtId, itemId)
{
	asbSelItem(divId, itemId);
}

// Select an item in the AutoSuggest list.
function asbSelItem(divId, itemId)
{
	if (itemId)
	{
		var item = document.getElementById(itemId);
		var div = document.getElementById(divId);
		
		if (div.selected) SetCssClass(div.selected, 'asbMenuItem');
		
		if (item)
		{
			SetCssClass(item, 'asbSelMenuItem');
			div.selected = item;
		}
	}
}

// Handle a mouse click in the AutoSuggest list.
function asbOnMouseClick(divId, txtId, itemId) //nMenuIndex, sTextBoxID, sDivID)
{
	asbApplySelection(divId, txtId, itemId);
}

// Apply the AutoSuggest list item selected by the user to the page.
function asbApplySelection(divId, txtId, itemId)
{
	var div = document.getElementById(divId);
	var txt = document.getElementById(txtId);
	var item = document.getElementById(itemId);

	//--- Copy other control values (if any) from selected item to 
	//--- corresponding controls on the page.
	
	var toCopy = item.getAttribute('toCopy');
	
	if (toCopy)
	{
		toCopy = toCopy.split(';');
		
		var ii;
		var prefix = GetFieldPrefix(txt);

		for (ii=0; ii<toCopy.length; ii++)
		{
			var dstId = toCopy[ii];
			var val = item.getAttribute('asb_' + dstId);
			
			dstId = prefix + dstId;
			
			var dst = document.getElementById(dstId); //GetElementById(dstId, true, 'input');
			
			if (dst)
			{
				asbSetValue(dst, val);
			}
		}
	}
	
	asbSetValue(txt, GetCellText(item));
	
	//--- Cancel any outstanding server request.
	
	if (div.suggestTimeout) window.clearTimeout(div.suggestTimeout);
	div.suggestTimeout = null;

	//--- Hide the suggestion list.
	
	//div.isActive = false;
	asbHideDiv(divId);
}

// Set a value from an AutoSuggest list selection to the current page.
function asbSetValue(ctrl, val)
{
	var	elType = ElementType(ctrl);
	var changed = false;
	
	if (elType == 'select')
	{
		var ii;
		var iBlank = -1;
		
		for (ii=0; ii<ctrl.options.length; ii++)
		{
			var txt = ctrl.options[ii].text;
			if (val && txt && val.toLowerCase() == txt.toLowerCase())
			{
				ctrl.value = val;
				changed = true;
				break;
			}
			else if (!txt || txt == '')
			{
				iBlank = ii;
			}
		}
		
		if (!changed && iBlank >= 0)
		{
			ctrl.selectedIndex = iBlank;
			changed = true;
		}
	}
	else if (elType == 'text' || elType == 'hidden')
	{
		ctrl.value = val;
		changed = true;
	}
	
	if (changed)
	{
		ctrl.found = true;		// Used by validation code to indicate that the control's value
								// was NOT just entered by hand.
		OnChange(ctrl);

		//--- #4728 - Handle editable datasheet.
		
		if (ctrl.cell)
		{
			var cell = ctrl.cell;
			
			ListEditDone2(ctrl, cell, false, false);
			window.setTimeout(function() { ListEditStart(cell, null); }, 1);
		}
	}
}

// Handle a downarrow in the AutoSuggest list.
function asbMoveDown()
{
	var divId = 'asbMenu';
	var div = document.getElementById(divId);
	var sel = div.selected;

	var item = null;
	
	if (sel)
	{
		item = sel.nextSibling;
	}
	else if (div.childNodes.length > 0) // Select 1st item.
	{
		item = div.childNodes[0].childNodes[0];
	}	
	
	if (item)
	{
		asbSelItem(divId, item.id);
	}
}

// Get the number of items in the AutoSuggest list.
function asbListLen(div)
{
	var	n = 0;
	
	if (div && div.childNodes && div.childNodes[0] && div.childNodes[0].childNodes)
	{	
		n = div.childNodes[0].childNodes.length;
	}
	
	return (n);
}

// Filter within current AutoSuggest list.
function asbFilterList(div, s)
{
	var nVisible = 0;
	
	if (div && div.childNodes && div.childNodes[0] && div.childNodes[0].childNodes)
	{
		var lst = div.childNodes[0].childNodes;
		var ii;
		
		s = s.toLowerCase();
		
		//--- Iterate backward through list since we're removing items!
		
		for (ii=lst.length-1; ii>=0; ii--)
		{
			var item = lst[ii];
			var itemText = GetCellText(item);
		
			//--- If item doesn't start with the string, remove it.
				
			if (itemText && itemText.toLowerCase().indexOf(s) != 0)
			{
				item.parentNode.removeChild(item);
			}
			else
			{
				nVisible++;
			}
		}
	}

	return (nVisible);
}

// Handle a uparrow in the AutoSuggest list.
function asbMoveUp()
{
	var divId = 'asbMenu';
	var div = document.getElementById(divId);
	var sel = div.selected;

	var item = null;
	
	if (sel)
	{
		item = sel.previousSibling;
	}
	
	if (item)
	{
		asbSelItem(divId, item.id);
	}
}

// Handle loss of focus on the control using the AutoSuggest list.
function asbOnBlur(divId)
{
	var div = document.getElementById(divId);
	
	div.isActive = false;

	asbHideDiv(divId, 200);
}

// If there's exactly one entry in the AutoSuggest list, apply it.
function asbApplyIfSingleEntry(div)
{
	if (asbListLen(div) == 1)
	{
		var valTyped = asbGetTextBoxValue(div.id);
		var item = div.childNodes[0].childNodes[0];
		var valList = GetCellText(item);
		
		if (valTyped.indexOf('?') == 0) valTyped = valTyped.substring(1);
		
		if (valTyped) valTyped = valTyped.toLowerCase();
		if (valList) valList = valList.toLowerCase();

		if (valTyped && valTyped.length > 0 && valList.indexOf(valTyped) == 0)
		{
			asbApplySelection(div.id, div.textBoxId, item.id);
		}
	}
}

// Generate an AutoSuggest response from a picklist specified on the client.
function asbAutoSuggestPick(seq, divId)
{
	var val = asbGetTextBoxValue(divId).toLowerCase();

	if (!val || val.length == 0)
	{
		asbHideDiv(divId);
		return;
	}

	var div = document.getElementById(divId);
	var items = div.pick.split(';');
	var ii;
	var txt = '';
	var arrSorted = new Array();
	var s;
	
	//--- Find matching items...
	
	if (val.indexOf('?') == 0) val = val.substring(1);
		
	for (ii=0; ii<items.length; ii++)
	{
		s = items[ii];
		
		//var len = val.length;
		
		//if (s && s.length > 0 && (s.toLowerCase().indexOf(val) == 0 || val == '?'))
		if (s && s.length > 0 && s.toLowerCase().indexOf(val) == 0)
		{
			arrSorted.push(s);
		}
	}
	
	//--- Sort them.
	
	arrSorted.sort(sortCaseInsensitive);
	
	//--- Add items to suggest list.
	
	for (ii=0; ii<arrSorted.length && ii < asbMaxLen; ii++)
	{
		txt += asbBuildSuggestionHtml(ii, divId, div.textBoxId, arrSorted[ii], 0, true);
	}
	
	//--- If too many, add more indicator.
	
	if (arrSorted.length > asbMaxLen)
	{
		txt += asbBuildSuggestionHtml(asbMaxLen, divId, div.textBoxId, '(more)', 0, false);
	}
	
	if (arrSorted.length > 0)
		txt = seq + ';' + txt;

	asbHandleResponse(txt);
}

// Build the AutoSuggest HTML for a single suggestion.
function asbBuildSuggestionHtml(index, div, id, s, sAttrs, selectable)
{
	var sSuggest = '';

	if (selectable)
	{
		var sId = 'asb_' + index;
		var sName = 'asb_' + index;
		var sClickJS = 'asbOnMouseClick(\'' + div + '\',\'' + id + '\',\'' + sId + '\');';
		var sOverJS = 'asbOnMouseOver(\'' + div + '\',\'' + id + '\',\'' + sId + '\');';

		sSuggest += '<div class="mapper asbMenuItem" id="' + sId + '"';
		sSuggest += ' name="' + sName + '"';
		sSuggest += ' onclick="' + sClickJS + '"';
		sSuggest += ' onmouseover="' + sOverJS + '"';
		sSuggest += '>' + s + '</div>';
	}
	else
	{
		sSuggest = '<div class="mapper asbMenuItem" style="cursor:auto">' + s + '</div>';
	}

	return (sSuggest);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END AutoSuggest handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function GetElementById(id, caseInsensitive, tagName)
{
	//--- First just try document.getElementById() which is case-insensitive in IE.
	
	var item = document.getElementById(id);
	
	//--- If we didn't find the element and we want a case-insensitive search,
	//--- and this isn't IE and a tagName was supplied, scan through all those elements!
	
	if (!item && caseInsensitive && !IsIE() && tagName)
	{
		var els = document.getElementsByTagName(tagName);
		var ii;
		
		id = id.toLowerCase();
		
		for (ii=0; ii<els.length; ii++)
		{
			if (els[ii].id && els[ii].id.toLowerCase() == id)
			{
				item = els[ii];
				break;
			}
		}
	}
	
	return (item);
}


//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START combo handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function CboTaInit(evt)
{
	if (!evt) evt = window.event;
	
	var cbo = GetEventTarget(evt);
	//window.status = 'clear:';
	
	cbo.keys = '';
	
	if (!cbo.taSetUp)
	{
		cbo.onkeydown = CboTaDown;
		cbo.onkeypress = CboTaPress;
		cbo.onkeyup = CboTaUp;
		cbo.onchange = CboTaChange;
		cbo.onblur = CboTaChange;
		cbo.taSetUp = true;
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function CboTaDown(evt, xcbo)
{
	if (!evt) evt = window.event;
	
	var key = GetEventKey(evt);
	var cbo = GetEventTarget(evt);
	var handled = false;

	//--- Handle backspace.
	
	if (key == 8)
	{
		var keys = cbo.keys;
		
		if (keys.length > 0)
		{
			cbo.keys = keys.substr(0, keys.length-1);
			//window.status = cbo.keys;
		}
		handled = true;
	}
	else if (key == 13)
	{
		OnChange(cbo);
		//handled = true;
	}
	
	//if (handled)
	if (false)
	{
		evt.cancelBubble = true;
		evt.returnValue = false;
		
		if (evt.stopPropagation) evt.stopPropagation();
		if (evt.preventDefault) evt.preventDefault();
	}

	return (!handled);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function CboTaPress(evt, xdynval)
{
	if (!evt) evt = window.event;
	
	var key = GetEventKey(evt);
	var cbo = GetEventTarget(evt);
	//var dynval = cbo.getAttribute('dynval');
	var handled = false;
	
	if (!cbo) alert('no cbo');
	
	//window.status += (key) ? String.fromCharCode(key) : '?';

	if (key == 8)	// Backspace
	{
		//if (cbo.keys && cbo.keys.length > 0)
		//{
		//	cbo.keys = cbo.keys.substr(0, cbo.keys.length-1);
		//}
		handled = true;
	}
	else if (!IsKeyCtrl(key))
	{
		cbo.keys += String.fromCharCode(key);
		handled = true;
	}

//	window.status = key + ':' + cbo.keys;
//	window.status += (handled) ? '+' : '-';
	//window.status = cbo.keys;

	//if (handled) handled = CboTaSelect(cbo, dynval);
//
	//window.status += (handled) ? '+' : '-';
	
	if (handled)
	{
		evt.cancelBubble = true;
		evt.returnValue = false;
		
		if (evt.stopPropagation) evt.stopPropagation();
		if (evt.preventDefault) evt.preventDefault();
	}
	
	return (!handled);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function CboTaUp(evt, xcbo, xdynval)
{
	if (!evt) evt = window.event;

	var key = GetEventKey(evt);
	var cbo = GetEventTarget(evt);
	var dynval = cbo.getAttribute('dynval');
	//var handled = false;

	if (!IsKeyCtrl(key) || key == 8)
	{
		//window.status += '(' +  String.fromCharCode(key) + ')';
		CboTaSelect(cbo, dynval);

		CancelBubble(evt);

		return (false);
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function CboTaChange(evt)
{
	if (!evt) evt = window.event;
	
	var cbo = GetEventTarget(evt);

	cbo.keys = '';
	
	if (cbo.selectedIndex != 0 && cbo.options.length > 1 && cbo.options[0].text.indexOf('*') == 0)
	{
		cbo.remove(0);
	}

	//window.status += '|';
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function CboTaSelect(cbo, dynval)
{
	var found = false;
	var ii;
	var selIndex = -1;

//	cbo.selectedIndex = -1;

	var keys = cbo.keys.toLowerCase();

	for (ii=0; ii<cbo.options.length; ii++)
	{
		if (cbo.options[ii].text.toLowerCase().indexOf(keys) == 0)
		{
			//window.status += '.';
			selIndex = ii;
			found = true;
			break;
		}
	}

	if (found)
	{
		var txt = cbo.options[selIndex].text;
		
		window.status = txt.substr(0, keys.length);
	}
	else if (dynval)
	{
		var opt = null;
		
		if (cbo.options.length > 0 && cbo.options[0].text.indexOf('*') == 0)
		{
			opt = cbo.options[0];
		}
		else
		{
			opt = AddOption(cbo, '', '', 0);
		}
		
		opt.text = '*' + cbo.keys;
		opt.value = opt.text;

		selIndex = 0;
		found = true;

		if (cbo.options.length > 1 && cbo.options[1].text.indexOf('*') == 0)
		{
			cbo.remove(1);
		}
	}
	
	if (found && selIndex != cbo.selectedIndex)
	{
//		var item = cbo.options[selIndex];
//		cbo.value = cbo.options[selIndex].value;
		cbo.selectedIndex = selIndex;
//		item.selected = true;
		//window.setTimeout('CboTaSet("' + cbo.id + '", ' + dynval + ');', 1);
	}
	
	return (found);
}

//function CboTaSet(id, dynval)
//{
//	var cbo = document.getElementById(id);
//	
//	if (cbo) CboTaSelect(cbo, dynval);
//}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END Combo handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START AJAX utilities
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function DevLog(msg, src, id, level, category)
{
	if (window.XHConn)
	{
		//--- Open asynchronous connection to server.
		
		var conn = new XHConn();

		//--- If connection established, issue a log request.
			    
		if (conn)
		{
			var params = 'req=devlog&msg=' + msg;
			
			if (id) params += "&src=" + src;
			if (id) params += "&id=" + id;
			if (id) params += "&lev=" + level;
			if (id) params += "&cat=" + category;
			
			conn.connect('Handler.ashx', 'GET', params, null);
		}
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function AjaxButtonClick(evt, ctrl, args)
{
	var handled = false;
	
	if (!evt) evt = window.event;
	
	if (window.XHConn)
	{
		//--- Open asynchronous connection to server.
		
		var conn = new XHConn();

		//--- If connection established, issue a log request.
			    
		if (conn)
		{
			var mop = ctrl.getAttribute('mop');
			var flavor = ctrl.getAttribute('flavor');
			var key = ctrl.getAttribute('key');
			var rowKey = ctrl.getAttribute('rowKey');

			if (!rowKey) rowKey = '' + GetOwnerWin(ctrl).rowKey;
			
			if (rowKey)
			{
			    //--- BugID: 4633 - add action
				var params = "act=abclk&req=btnclk";
				
				if (mop) params += '&mop=' + mop;
				if (flavor) params += '&flavor=' + flavor;
				if (rowKey) params += '&rowKey=' + rowKey;
				if (key) params += '&key=' + key;
				
				if (args) params += '&' + args;		// #2514
				
				params += '&ajaxdt=' + Timestamp();	// Force request to be unique to prevent cache hit.

				//--- If this is an ANCHOR tag (probably on a datasheet), give it a little
				//--- action to let user know click occurred.
				
				if (ElementType(ctrl) == 'a')
				{
					ctrl.style.paddingLeft = '2px';
					window.setTimeout("var c = document.getElementById('" + ctrl.id + "'); if (c) { c.style.paddingLeft = ''; }", 75);
				}
								
				conn.connect('Handler.ashx', 'GET', params, null);

				handled = true;
				
				if (evt)
				{
					evt.cancelBubble = true;
					evt.defaultValue = false;
					if (evt.stopPropagation) evt.stopPropagation();
					if (evt.preventDefault) evt.preventDefault();
				}
			}
		}
	}
	
	return (handled);
}

// #5728 - Fire AJAX event to mapper row.
function RowAjaxRequest(map, rk, name, params, fn)
{
	var p = 'reqnm=' + name + '&map=' + map + '&rowKey=' + rk;
	
	if (params) p += '&' + params;
	
	JsonReq('mapreq', p, fn, 0);
}

//---------------------------------------------------------------------------------------------------------------
// #2514 - Support AJAX sending of field values.
function AjaxValueFields(ctrl, sibList)
{
	var sArgs = '';
	
	if (sibList)
	{
		var sibs = sibList.split(';');
		var ii;
		
		for (ii=0; ii<sibList.length; ii++)
		{
			var key = sibs[ii];
			
			if (key)
			{
				sArgs += '&fld:' + key + '=' + encodeURIComponent(GetSiblingValue(ctrl, key));
			}
		}
	}
	
	return (sArgs);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function AjaxCommandClick(evt, ctrl, qsParams, fnResponse)
{
	var handled = false;

	if (!evt) evt = window.event;
	
	if (window.XHConn && ctrl)
	{
		//--- Open asynchronous connection to server.

		var conn = new XHConn();

		//--- If connection established, issue a log request.
			    
		if (conn)
		{
			var mop = ctrl.getAttribute('mop');
			var flavor = ctrl.getAttribute('flavor');
			var cmd = ctrl.getAttribute('cmd');
			var rowKey = ctrl.getAttribute('rowKey');

			if (!rowKey) rowKey = '' + window.rowKey;
			
			if (rowKey)
			{
			    //--- BugID: 4633 - add action
				var params = "act=acclk&req=cmdclk";
				
				if (mop) params += "&mop=" + mop;
				if (flavor) params += "&flavor=" + flavor;
				if (rowKey) params += "&rowKey=" + rowKey;
				if (cmd) params += "&cmd=" + cmd;
				
				if (qsParams) params += qsParams;
				
				params += "&ajaxdt=" + Timestamp();	// Force request to be unique to prevent cache hit.
//alert(params);
				//--- If this is an ANCHOR tag (probably on a datasheet), give it a little
				//--- action to let user know click occurred.
				
				if (ElementType(ctrl) == 'a')
				{
					ctrl.style.paddingLeft = '2px';
					window.setTimeout("var c = document.getElementById('" + ctrl.id + "'); if (c) { c.style.paddingLeft = ''; }", 75);
				}
								
				conn.connect('Handler.ashx', 'GET', params, fnResponse);

				handled = true;
				
				if (evt)
				{
					evt.cancelBubble = true;
					evt.defaultValue = false;
					if (evt.stopPropagation) evt.stopPropagation();
					if (evt.preventDefault) evt.preventDefault();
				}
			}
		}
	}
	
	return (handled);
}

//---------------------------------------------------------------------------------------------------------------
// Issue generic AJAX request.
function AjaxReq(req, params, fn)
{
	var conn = new XHConn();

	if (conn)
	{
	    //--- BugID: 4633 - add action
		var p = 'act=areq&req=' + req + '&ajaxdt=' + Timestamp();
		
		if (params && params != '') p += '&' + params;

		conn.getString('Handler.ashx', p, fn);
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function AjaxLookup(type, id, info, fn)
{
	AjaxReq('lkup', 'type=' + type + '&id=' + id + '&info=' + info, fn);
	window.status = "Retrieving information from server...";
}

//---------------------------------------------------------------------------------------------------------------
// Persist user preference state.
function AjaxPrefSet(nm, val, op, fn)
{
	var params = 'nm=' + nm + '&val=' + val;
	
	if (op) params += '&op=' + op;
	
	AjaxReq('setprf', params, fn);
}

function AjaxPrefOpSet(prf, item, op)
{
	if (op == '-')
		AjaxPrefSet(prf, '-' + item, 'add');	// Explicitly hide
	else
		AjaxPrefSet(prf, item, 'remove');		// Stop explicitly showing
}

//---------------------------------------------------------------------------------------------------------------
// Clear page cache.
function ClearCache(mop)
{
	AjaxReq('clrpg', 'mop=' + mop);
}

//---------------------------------------------------------------------------------------------------------------
// Issue generic JSON request.  If fn provided, it will be called with a JSON object.
function JsonReq(req, params, fn, flags)
{
	var conn = new XHConn();

	if (conn)
	{
		var p = 'req=' + req;
		
		if (0 == (flags & 0x00000001)) p += '&ajaxdt=' + Timestamp();
		if (params && params != '') p += '&' + params;

		conn.getObject('Handler.ashx', p, fn);
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END AJAX utilities
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function DebugKeyUp(evt)
{
	if (!evt) evt = window.event;
	
	var handled = false;
	var ctrl = GetEventTarget(evt);
	var key = GetEventKey(evt);
	
	if (key == 120 && IsOpera()) key = 119;		// F8 already used by Opera, map to F9
	
	if (ctrl && key == 119)		// F8
	{
		var msg = '';
		var cls = GetCssClass(ctrl);
		var lbl = FindLabelFor(ctrl);
		var cap = GetCellText(lbl).replace(/:/g, '');
		var fldKey = GetFieldKey(ctrl).replace(/^fbf_/, '');
		
		msg += 'id ----------> ' + ctrl.id;
		if (fldKey) msg += '\nkey ---------> ' + fldKey;
		msg += '\nlabel -------> ' + cap;
		msg += '\nclass -------> ' + cls;
		msg += '\ntag ---------> ' + ElementType(ctrl);
		
		var ii;
		
		for (ii=0; ii<ctrl.attributes.length; ii++)
		{
			var	attr = ctrl.attributes[ii];
			
			if (attr.name.match(/^dbg.*/i))
			{
				var nm =  attr.name.substr(3) + ' ';
				
				while (nm.length < 12) 
				{
					nm += '-';
				}
				
				msg += '\n' + nm + '> ' + attr.value;
			}
		}
		
		alert(msg);
		
		evt.cancelBubble = true;
		evt.defaultValue = false;
		if (evt.stopPropagation) evt.stopPropagation();
		if (evt.preventDefault) evt.preventDefault();
		
		handled = true;
	}
	
	return (handled);
}


//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function DebugPage(evt)
{
	if (!evt) evt = window.event;
	
	//var handled = false;
	var ctrl = GetEventTarget(evt);
	var key = GetEventKey(evt);
	var pageMOP = '';

	if (key == 120 && IsOpera()) key = 119;		// F8 already used by Opera, map to F9

	if (ctrl && key == 119)		// F8
	{
		var msg = '';
		var warns = '';
		var ii;
		
		msg += DebugFmtMsgHtml('DateTime', 'Page', new Date(), 0);	// #3604
		
		var infos = document.getElementsByTagName('dbginfo');
		
		for (ii=0; ii<infos.length; ii++)
		{
			var info = infos[ii];
			var name = info.getAttribute('name');
			var val = info.getAttribute('value');
			var cat = info.getAttribute('cat');
			var lev = info.getAttribute('lev');
			var list = info.getAttribute('list');

			if (lev && lev > 0)
			{
				warns += DebugFmtMsgHtml(name, cat, val, lev, list);
			}
			else
			{
				msg += DebugFmtMsgHtml(name, cat, val, lev, list);
			}
			
			if (name == 'MOP')
			{
			    pageMOP = val;			    
			}
		}
		
		//--- Add RowKey
		
		msg += DebugFmtMsgHtml('RowKey', 'Mapper', window.rowKey);
		
		//--- Set warnings apart.
		
		if (warns && warns.length > 0)
		{
			//msg = StrRepeat('----', 30) + '\n' + warns + StrRepeat('----', 30) + '\n' + msg;
			msg = '<div class=\"dbgwarn\">' + warns + '</div>\r\n' + msg;
		}
		
		//--- Show URL in parts (since it can be long).
		
		var url = window.document.location.href;
		var urlHalves = url.split('?');
		
		msg += DebugFmtMsgHtml('Page', 'URL', urlHalves[0]);
		
		if (urlHalves.length > 1)
		{
			var parts = urlHalves[1].split('&');
			
			for (ii=0; ii<parts.length; ii++)
			{
				var nameVal = parts[ii].split('=');
				name = nameVal[0];
				val = (nameVal.length > 1) ? nameVal[1] : '';
				msg += DebugFmtMsgHtml(name, 'URL', val);
			}
		}
		
//		msg += DebugFmtMsgHtml('URL', 'Page', window.document.location.href);
		
		//alert(msg);
		var win = window.open('blank.htm', '_blank', 'toolbar=no,scrollbars=yes');
		
		if (win != null)	// Probably due to popup blocker.
		{
			var doc = win.document;	
		    
			doc.open();
			doc.writeln('<html>\r\n<head><title>Debug Information: ' + pageMOP + '</title>\r\n<link href=\"' + cssFile + '\" rel=\"stylesheet\" type=\"text/css\" />\r\n</head>\r\n<body class="dbgwin" onkeydown="Esc(event);">\r\n');
			doc.writeln(msg);	
			doc.writeln('<script>function Esc(evt) { if (!evt) evt = window.event; if (evt.keyCode == 27) window.close(); }</script>');    
			doc.writeln('</body>\r\n</html>');
			doc.close();
	    }
	}
}

function DebugPane(evt, pane)
{
	if (!evt) evt = window.event;
	
	var handled = false;
	var ctrl = GetEventTarget(evt);
	var key = GetEventKey(evt);
	
	if (key == 120 && IsOpera()) key = 119;		// F8 already used by Opera, map to F9
	
	if (ctrl && key == 119)		// F8
	{
		var msg = '';
		var nm = FindParent(pane, 'table').getAttribute('pan');

		msg += 'Pane --------> ' + nm;

		var infos = document.getElementsByTagName('dbginfo');

		for (var ii=0; ii<infos.length; ii++)
		{
			var info = infos[ii];
			var name = info.getAttribute('name');
			var val = info.getAttribute('value');
			var cat = info.getAttribute('cat');
			var list = info.getAttribute('list');
			
			if (cat == 'Pane' && name == nm && list)
			{
				var items = list.split(';');

				msg += '\nCaption -----> ' + val;
				
				for (var jj=0; jj<items.length; jj++)
				{
					var parts = items[jj].split(':');
					msg += '\n' + parts[0] + ' --------> ' + parts[1];
				}

				break;
			}
		}

		alert(msg);
		
		CancelBubble(evt);
		
		handled = true;
	}
	
	return (handled);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function DebugFmtMsg(name, cat, val, lev, list)
{
	var arrow = '--';
	var s = '';
	
	if (cat) name = cat + ':' + name;
	
	//--- Line stuff up, more or less.
	
	var padLen = 20 - name.length;

	arrow += StrRepeat('-', padLen);

	//--- Output name and value.
	
	s += name + ' ' + arrow + '> ' + val + '\n';
	
	//--- Add sublist items (if any).
	
	if (list)
	{
		var items = list.split(';');
		var	ee;
		
		for (ee=0; ee<items.length; ee++)
		{
			s += '..... ' + Trim(items[ee], true, true) + '\n';
		}
	}
	
	if (lev && lev > 0)
	{
		var severity;
		
		if (lev >= 32)
			severity = "CRITICAL:";
		else if (lev >= 16)
			severity = "ERROR:";
		else if (lev >= 8)
			severity = "SEVERE WARNING:";
		else if (lev >= 4)
			severity = "WARNING:";
		else if (lev >= 2)
			severity = "MILD WARNING:";
		else if (lev >= 1)
			severity = "INFO:";

		s = severity + ' ' + s;
	}
	
	return (s);
}

function DebugFmtMsgHtml(name, cat, val, lev, list)
{
	var s = '';
	
	if (cat) name = cat + ':' + name;
	
	name = '<strong>' + name + ':&nbsp;</strong>';
	
	//--- Line stuff up, more or less.
	
	//var padLen = 20 - name.length;

	//--- Output name and value.
	
	if (cat == 'Timing')
	{
	    s += name + '<span style="color: Blue; font-weight: Bold">' + val + '</span>';
	}
	else
	{	
	    s += name + val;
	}	
		
	//--- Add sublist items (if any).
	
	if (list)
	{
		var items = list.split(';');
		var	ee;
		
		for (ee=0; ee<items.length; ee++)
		{
			s += '<br />..... ' + Trim(items[ee], true, true) + '\r\n';
		}
	}
	
	if (lev && lev > 0)
	{
		var severity;
		
		if (lev >= 32)
			severity = "CRITICAL:";
		else if (lev >= 16)
			severity = "ERROR:";
		else if (lev >= 8)
			severity = "SEVERE WARNING:";
		else if (lev >= 4)
			severity = "WARNING:";
		else if (lev >= 2)
			severity = "MILD WARNING:";
		else if (lev >= 1)
			severity = "INFO:";

		s = severity + ' ' + s;
	}
	
	return ('<div>' + s + '</div>');
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function StrRepeat(ch, n)
{
	var s = '';
	var ii;
	
	for (ii=0; ii<n; ii++) s += ch;
	
	return (s);
}


//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function FindLabelFor(ctrl)
{
	var lbl;

	ctrl = GetElement(ctrl);
	
	if (ctrl)
	{
		var lbls = document.body.getElementsByTagName('label');
		var id = ctrl.id;
		var ii;
		
		for (ii=0; ii<lbls.length; ii++)
		{
			if (id == lbls[ii].htmlFor)
			{
				lbl = lbls[ii];
				break;
			}
		}
	}
	
	return (lbl);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function DoClick(item, now, win)
{
    if (!win) win = window;
    
	if (now)
	{
		var btn = GetElement(item, win);
		
		if (btn)
		{
			if (btn.click)
				btn.click();
			else if (btn.onclick)
				btn.onclick();
		}
	}
	else if (item)
	{
		//--- Delay to allow current event to complete or else we get funny behaviour.
	
		win.setTimeout(function () { DoClick(item, true, win); }, 1);
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START Cookie handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function CookieGetVal(offset) 
{
	var endstr = document.cookie.indexOf (";", offset);
	if (endstr == -1)
		endstr = document.cookie.length;

	return decodeURIComponent(document.cookie.substring(offset, endstr));
}			

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function CookieGet(name) 
{
	var arg = name + "=";
	var alen = arg.length;
	var clen = document.cookie.length;
	var i = 0;

	while (i < clen) 
	{
		var j = i + alen;
		if (document.cookie.substring(i, j) == arg)
		return CookieGetVal(j);
		i = document.cookie.indexOf(" ", i) + 1;
		if (i == 0) break; 
	}
	
	return null;
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function CookieRemove(name)
{
	document.cookie = name + '=deleteMe; expires=Thu, 2 Aug 2001 20:47:11 UTC; path=/';
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END Cookie handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function CloseWhenOpenerCloses(closeOnOpenerLocChange)
{
	if (window.opener)
	{
		if (closeOnOpenerLocChange)
		{
			window.originalLoc = window.opener.document.location.href;
		}
		else
		{
			window.originalLoc = null;
		}

		window.setInterval('if (!OpenerOk()) window.close();', 2000);
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function OpenerOk()
{
	var ok = (window.opener && !window.opener.closed);
	
	if (ok)
	{
		try
		{
			var loc = window.opener.document.location.href;	// Throws if opener is gone (which is what we want).
			
			if (window.originalLoc && loc != window.originalLoc)
			{
				ok = false;
			}
		}
		catch(e)
		{
			ok = false;
		}
	}
	
	return (ok);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function AddSelfCloseScript(doc)
{
	doc.writeln('<script>');
	doc.writeln('function CloseIfNoOpener()');
	doc.writeln('{');
	doc.writeln('	if (!window.opener || window.opener.closed)');
	doc.writeln('	{');
	doc.writeln('		window.close();');
	doc.writeln('	}');
	doc.writeln('	else');
	doc.writeln('	{');
	doc.writeln('		try { if (window.originalLoc != window.opener.document.location.href) window.close(); } catch(e) { window.close(); }');
	doc.writeln('	}');
	doc.writeln('}');
	doc.writeln('</script>');
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function wmFocus(evt, ctrl)
{
	if (ctrl.value == ctrl.getAttribute('wm')) 
	{
		if (!ctrl.getAttribute('readonly'))
		{
			ctrl.value = '';
			ReplaceCssClass(ctrl, 'wm', '');
		}

		ctrl.onchange = wmChange;
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function wmChange(evt)
{
	wmBlur(null, this);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function wmBlur(evt, ctrl)
{
	if (IsBndLkup(ctrl))
	{
		if (ElementType(ctrl) == 'table')
			ctrl = document.getElementById(ctrl.id.replace(/_tbl$/, '_txt'));
		else
			ctrl = document.getElementById(ctrl.id.replace(/_btn$/, '_txt'));
	}
	
	if (!ctrl.value) 
	{
		ctrl.value = ctrl.getAttribute('wm');
		ReplaceCssClass(ctrl, 'wm', 'wm');
	}
	else if (ctrl.value != ctrl.getAttribute('wm'))
	{
		ReplaceCssClass(ctrl, 'wm', '');
	}
}

//---------------------------------------------------------------------------------------------------------------
// Open widget if user clicks on locked textbox or hits space or enter keys.
//---------------------------------------------------------------------------------------------------------------
function LockedWidgetOpener(evt, txt)
{
	if (txt && txt.getAttribute("readonly"))
	{
		var btnId = bndLkupBtnFromTxt(txt);
		
		if (!btnId)
		{
			null;	// Do nothing
		}
		else if (evt.type == 'click')
		{
			DoClick(document.getElementById(btnId));
		}
		else if (evt.type == 'keydown')
		{
			var key = GetEventKey(evt);
			
			if (key == 32 || key == 13)	// space or enter
			{
				DoClick(document.getElementById(btnId));
			}
		}
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START Mouse object
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

var Mouse = {};
Mouse.doc = document;
Mouse.MouseMoveHandler = function (evt) 
{
	if (!evt) evt = window.event;

	Mouse.x = ((Mouse.doc.body && Mouse.doc.body.scrollLeft) || 0) + evt.clientX;
	Mouse.y = ((Mouse.doc.body && Mouse.doc.body.scrollTop) || 0) + evt.clientY;
	Mouse.currentTarget = evt.target || evt.srcElement;
	return true;
};

if (Mouse.doc.attachEvent)
	Mouse.doc.attachEvent("onmousemove", Mouse.MouseMoveHandler);
else if (Mouse.doc.addEventListener)
	Mouse.doc.addEventListener("mousemove", Mouse.MouseMoveHandler, false);

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END Mouse object
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function AddOption(cbo, txt, val, index)
{
	var opt = null;
	
	if (index == null)
	{
		index = cbo.options.length;
	}
	
	if (IsSafari())
	{
		opt = new Option(txt, val);
		
		if (index != cbo.options.length)
		{
			//--- If you set the item on any existing index it will replace
			//--- the one there, so move existing ones down.
			
			var ii;
			
			for (ii=cbo.options.length; ii>index && ii>0; ii--)
			{
				var optMove = cbo.options[ii-1];
				cbo.options[ii-1] = opt;
				cbo.options[ii] = optMove;
			}
		}
		else
		{
			cbo.options[index] = opt;	// Appends
		}
	}
	else
	{
		opt = document.createElement('OPTION');
		opt.text = txt;
		opt.value = val;
		cbo.options.add(opt, index);
	}
	
	return (opt);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function RefreshParent(win)
{
	var winRefresh = null;
	
	//--- Try to find the parent window.
	
	if (window.opener)
	{
		winRefresh = window.opener;
	}
	else if (win.frameElement)
	{
		var doc = win.frameElement.ownerDocument;
		
		if (doc)
		{
			winRefresh = doc.parentWindow;					// IE
			if (!winRefresh) winRefresh = doc.defaultView;  // Firefox
		}
	}
	
	//--- If we found window and it has a RefresePage() method, refresh it.
	
	if (winRefresh && winRefresh.RefreshPage)
	{
		winRefresh.RefreshPage();
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function CancelBubble(evt)
{
	if (!evt) evt = window.event;
	
	if (evt)
	{
		evt.cancelBubble = true;						// IE
		evt.defaultValue = false;						// IE
		if (evt.stopPropagation) evt.stopPropagation();	// Mozilla
		if (evt.preventDefault) evt.preventDefault();	// Mozilla
	}
	
	return (false);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function IsPageDirty(show)
{
	var dirty = false;
	var ctrls = document.getElementsByTagName('input');
	var ii;
	
	//--- Check textboxes, checkboxes, etc.
	
	for (ii=0; ii<ctrls.length; ii++)
	{
		dirty = IsCtrlDirty(ctrls[ii], show) || dirty;
	}
	
	//--- Check textareas
	
	ctrls = document.getElementsByTagName('textarea');
	
	for (ii=0; ii<ctrls.length; ii++)
	{
		dirty = IsCtrlDirty(ctrls[ii], show) || dirty;
	}

	//--- Check selects
	
	ctrls = document.getElementsByTagName('select');
	
	for (ii=0; ii<ctrls.length; ii++)
	{
		dirty = IsCtrlDirty(ctrls[ii], show) || dirty;
	}

	return (dirty);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function IsCtrlDirty(ctrl, show)
{
	var dirty = false;
	var elType = ElementType(ctrl);
	var	origVal = ctrl.getAttribute('orig');
	var noDirty = ctrl.getAttribute('nodirty');

	//--- Special handling for atypical controls.

	if (origVal != null)
	{
		null;	// Got it.  No special handling.
	}
	else if (elType == 'checkbox')
	{
		origVal = ctrl.parentNode.getAttribute('orig');
		noDirty = ctrl.parentNode.getAttribute('nodirty');
	}
	else if (elType == 'radio')
	{
		var tbl = FindParent(ctrl, 'table');
		
		if (tbl) 
		{
			origVal = tbl.getAttribute('orig');
			noDirty = tbl.getAttribute('nodirty');
		}
	}
		
	//--- If we have an original value, compare.
		
	if (origVal != null && noDirty != '1')
	{
		if (elType == 'text')
		{
			dirty = (ctrl.value != origVal);
		}
		else if (elType == 'select')
		{
			dirty = (ctrl.value != origVal);
		}
		else if (elType == 'checkbox')
		{
			dirty = (origVal != '0' && !ctrl.checked) || (origVal == '0' && ctrl.checked);
		}
		else if (elType == 'textarea')
		{
			dirty = (ctrl.value != origVal);
		}
		else if (elType == 'radio' && ctrl.checked)
		{
			dirty = (ctrl.value != origVal);
			ctrl = FindParent(ctrl, 'table');
		}
		
		//--- If we're showing dirty fields, set style.
		
		if (show)
		{
			if (dirty)
			{
				ReplaceCssClass(ctrl, '', 'editedlist');
			}
			else
			{
				RemoveCssClass(ctrl, 'editedlist');
			}
		}
	}
	
	return (dirty);
}

//---------------------------------------------------------------------------------------------------------------
// Use for mapper fields use as navigation elements.
//---------------------------------------------------------------------------------------------------------------
function MapNav(evt, ctrl, msg)
{
	var ok = true;
	
	if (IsPageDirty(true) && !confirm(msg))
	{ 
		ok = false;
		
		if (ElementType(ctrl) == 'radio')
		{
			ResetRadio(ctrl);
		}
		else
		{
			ctrl.value = ctrl.getAttribute('orig');
		}
	}
	
	return (ok);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function ResetRadio(ctrl)
{
	var tab = FindParent(ctrl, 'table');
	
	if (tab)
	{
		var val = tab.getAttribute('orig');
		
		var rads = document.getElementsByTagName('input');
		var ii;
		
		for (ii=0; ii<rads.length; ii++)
		{
			var rad = rads[ii];
			
			if (ElementType(rad) == 'radio' &&
				IsParentOf(rad, tab) &&
				rad.value == val)
			{
				rad.checked = true;
			}
		}
	}
}

//---------------------------------------------------------------------------------------------------------------
// Case-insensitive sort for Array.sort()
//---------------------------------------------------------------------------------------------------------------
function sortCaseInsensitive(a, b) 
{ 
	a = '' + a.toLowerCase();
	b = '' + b.toLowerCase();
	
	if (a > b) 
		return 1;
	else if (a < b) 
		return -1;
    else
		return 0;
} 


//---------------------------------------------------------------------------------------------------------------
// Gets the rendered style for an element, browser-independent, e.g. GetStyle(obj, 'padding-left');
//---------------------------------------------------------------------------------------------------------------
function GetStyle(item, rule)
{
    var val = "";
    
    if (document.defaultView && document.defaultView.getComputedStyle)
    {
        val = document.defaultView.getComputedStyle(item, '').getPropertyValue(rule);
    }
    else if (item.currentStyle)
    {
        rule = rule.replace(/\-(\w)/g, function (strMatch, p1){
            return p1.toUpperCase();
        });
        val = item.currentStyle[rule];
    }
    return (val);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function OpenInNewWindow(evt, features, height, width)
{ 
	if (!evt) evt = window.event; 
	
	var ctrl = GetEventTarget(evt);

	// Abort if a modifier key is pressed 
	if (evt.shiftKey || evt.altKey || evt.ctrlKey || evt.metaKey) 
	{ 
		return true; 
	} 
	
	// If this isn't an anchor tag, find parent anchor.
	
	if (ElementType(ctrl) != 'a') ctrl = FindParent(ctrl, 'a');
	
	if (ctrl)
	{ 
		var opts = WindowOpenFeatures(features, height, width);
		var win = window.open(ctrl.getAttribute('href'), ctrl.getAttribute('target'), opts); 
		
		if (win) 
		{ 
			if (win.focus) win.focus(); 
			return false; 
		} 
		
		return true; 
	} 
} 

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function WindowOpenFeatures(options, height, width)
{
	var	sFeatures = '';
	//var sVCenter = '';
	//var sHCenter = '';
	var bTrailQuote = true;

	//--- Add boolean features.

	sFeatures += ",menubar=" + ((0 != (options & 0x00000004)) ? "1" : "0");
	sFeatures += ",resizable=" + ((0 != (options & 0x00000008)) ? "1" : "0");
	sFeatures += ",scrollbars=" + ((0 != (options & 0x00000010)) ? "1" : "0");
	sFeatures += ",status=" + ((0 != (options & 0x00000020)) ? "1" : "0");
	sFeatures += ",toolbar=" + ((0 != (options & 0x00000040)) ? "1" : "0");
	sFeatures += ",fullscreen=" + ((0 != (options & 0x00000080)) ? "1" : "0");

	//--- Add height & width features.

	if (height > 0)
	{
		sFeatures += ",height=" + height;
	}

	if (width > 0)
	{
		sFeatures += ",width=" + width;
	}

	//--- Add centering features.
	// ToDo: This code is IE-specific.

	if (0 != (options & 0x00000100))
	{
		sFeatures += ",top=' + window.event.y + ',left=' + window.event.x";
		bTrailQuote = false;
	}
	else
	{
		if (0 != (options & 0x00000001))
		{
			sFeatures += ",top=" + ((screen.height - height)/2);
		}

		if (0 != (options & 0x00000002))
		{
			sFeatures += ",left=" + ((screen.width - width)/2);
		}
		else if (0 != (options & 0x00000200))
		{
			sFeatures += ",left=" + ((screen.width - width));
		}
	}

	//--- Remove leading comma and enquote as appropriate.

	if (sFeatures.Length > 0) sFeatures = sFeatures.substring(1);
	sFeatures = "'" + sFeatures;
	if (bTrailQuote) sFeatures += "'";

	return (sFeatures);
}

//---------------------------------------------------------------------------------------------------------------
// Set a control's opacity (no effect in Opera, at least as of v8.5)
//---------------------------------------------------------------------------------------------------------------
function SetOpacity(el, percent)
{
	el.style.filter = 'alpha(opacity:' + percent + ')';
	el.style.KHTMLOpacity = percent/100;
	el.style.MozOpacity = percent/100;
	el.style.opacity = percent/100;
}

//---------------------------------------------------------------------------------------------------------------
// Get the document for rendering inside an IFrame
//---------------------------------------------------------------------------------------------------------------
function IFrameDoc(f)
{
	var d = f.contentWindow.document;
	if (!d) d = f.contentDocument;
	
	return (d);
}

//---------------------------------------------------------------------------------------------------------------
// Find a frame by name.
//---------------------------------------------------------------------------------------------------------------
function FindFrame(nm) 
{
	var frm = null;
	var win = window;
	
	while (frm == null && win != null)
	{
		var frms = win.frames;
		
		for (var ii=0; frms != null && ii<frms.length; ii++) 
		{
			if (frms[ii].name == nm)
			{
				frm = frms[ii];
				break;
			}
		}

		win = (win == win.parent) ? null : win.parent;
	}
	
	return (frm);
}

//---------------------------------------------------------------------------------------------------------------
// Get a stylesheet rule for the document, e.g. selectorText = 'img.myclass'
//---------------------------------------------------------------------------------------------------------------
function StyleRule(selectorText)
{
	var rule = null;
	
	if (document.styleSheets)
	{	
		var theRules;
		
		if (document.styleSheets[0].cssRules)
			theRules = document.styleSheets[0].cssRules;	// W3C
		else if (document.styleSheets[0].rules)
			theRules = document.styleSheets[0].rules;		// IE

		if (theRules)
		{			
			var ii;
			
			selectorText = selectorText.toLowerCase();
					
			for (ii=0; ii<theRules.length; ii++)
			{
				var r = theRules[ii];
				
				if (r.selectorText.toLowerCase() == selectorText)
				{
					rule = r;
					break;
				}
			}
		}
	}
	
	return (rule);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START InfoIcons handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BubAddInfoIcons(opts)
{
	var		nCount = 0;
	//var		start = new Date().getTime();
	var		items;
	var		nAdded = 0;
	
	items = document.getElementsByTagName('input');
	nCount += items.length;
	nAdded += BubAddInfoItems(items, opts);
	
	items = document.getElementsByTagName('a');
	nCount += items.length;
	nAdded += BubAddInfoItems(items, opts);
	
	items = document.getElementsByTagName('img');
	nCount += items.length;
	nAdded += BubAddInfoItems(items, opts);

	//var		end = new Date().getTime();
	
	//window.status += ' --> ' + nAdded + '/' + nCount + ' (' + (end-start) + 'ms)';
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BubAddInfoItems(items, opts)
{
	var		nCount = 0;
	//var		start = new Date().getTime();
	var		ii;
	
	//window.status = items.length;

	for (ii=0;ii<items.length;ii++)
	{
		var item = items[ii];
		
		//if (item.getAttribute('hlp') && IsVisibleAndEnabled(item) && BubAddInfo(item))
		if (item.getAttribute('hlp') && IsVisible(item) && BubAddInfo(item, opts))
		{
			nCount++;
			//window.status += '+';
		}
		else
		{
			//window.status += '-';
		}
    }
    
   	//var		end = new Date().getTime();

	//window.status += nCount + '(' + (end-start) + 'ms)';
    
    return (nCount);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BubAddInfo(item, opts)
{
	var		bAdded = false;
	
	var hlp = item.getAttribute('hlp');
	if (hlp == 't') hlp = item.title;
	//if (!hlp || hlp.length == 0) return (false);
	
	var img = BubCreateEl("img", '');
	
//	var left = getLeft(item) + 8;//item.offsetLeft + 8; //getLeft(item) + 8;
//	var top = OffsetBottom(item) + 0;//item.offsetTop + item.offsetWidth + 1; //OffsetBottom(item) + 2;
	var top = GetStaticTop(item) + item.offsetHeight;
	var left = GetStaticLeft(item) + 8;//item.offsetLeft + 8; //getLeft(item) + 8;
//return;
//+	var topAndLeft = GetStaticTopAndLeft(item);	
//+	var top = topAndLeft[1] + item.offsetHeight;
//+	var left = topAndLeft[0] + 8;

//if (left > screen.width) return (false);

//if (item.id == 'toolbar_refresh') alert(item.offsetHeight);
	
	//left = left - left%8;	// Align images
	top = top - top%4;		// Align images
	
	img.style.position = 'absolute';
	img.style.left = left;
	img.style.top = top;
	img.style.zIndex = 100000;//10000000;//10000;
	img.src = 'images/BubInfo.gif';
	AddDocEl(img);
	
	SetTip(img, hlp);
	
//	if (opts && opts.indexOf('t') >= 0)
//	{
//		BubPrepare(img);
//	}

	bAdded = true;
	
	return (bAdded);
}

//-----------------------------------------------------------------------------------------
function BubCreateEl(t,c,d)
{
	if (!d) d = document;
	
	var x = d.createElement(t);
	
	SetCssClass(x, c);
	x.style.display = 'block';
	
	return (x);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END InfoIcons handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

function CreateShim()	// Allows presentation on top of combos in IE.
{
	var	shim = document.createElement('iframe');

    shim.src = 'blank.htm';     // Needed to avoid the IE "secure and nonsecure" warning under https.
	SetCssClass(shim, 'shim');
	shim.role = 'shim';

	document.body.appendChild(shim);
	
	return (shim);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function WindowWidth(win)
{
	if (win.innerWidth)
		return (win.innerWidth);
	else if (win.document.body && win.document.body.offsetWidth)
		return (win.document.body.offsetWidth);
	else
		return (0);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function WindowHeight(win)
{
	if (win.innerHeight)
		return (win.innerHeight);
	else if (win.document.body && win.document.body.offsetHeight)
		return (win.document.body.offsetHeight);
	else
		return (0);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START BubbleTip handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BubEnableTooltips(id, opts, delayed)
{
	if (!delayed)
	{
		window.setTimeout(function() { BubEnableTooltips(id, opts, true); }, 1);
		return;
	}
	
	if (!document.getElementById || !document.getElementsByTagName) return;

	//--- Create the BubbleTipContainer
	
	var btc = BubCreate(200);
	
	btc.id = 'btc';
	btc.style.display = 'none'
	
	window.tipTextNode = document.createTextNode('tip');
	FindRole(btc, 'content').appendChild(window.tipTextNode);
	
	//--- Add bubble tips to appropriate elements.
	
	var		start = new Date().getTime();
	var		items;
	var		nAdded = 0;
	var		nScanned = 0;
	var		nTotalAdded = 0;
	var		nTotalScanned = 0;
	var		stats = '';

	items = document.getElementsByTagName('input');
	nScanned = items.length;
	nAdded = BubEnableItems(items, opts);
	nTotalScanned += nScanned;
	nTotalAdded += nAdded;
	stats += 'INPUT: ' + nAdded + '/' + nScanned;

	items = document.getElementsByTagName('a');
	nScanned = items.length;
	nAdded = BubEnableItems(items, opts);
	nTotalScanned += nScanned;
	nTotalAdded += nAdded;
	stats += ', A: ' + nAdded + '/' + nScanned;

	items = document.getElementsByTagName('img');
	nScanned = items.length;
	nAdded = BubEnableItems(items, opts);
	nTotalScanned += nScanned;
	nTotalAdded += nAdded;
	stats += ', IMG: ' + nAdded + '/' + nScanned;

	//--- #2750 - Handle TEXTAREAs.

	items = document.getElementsByTagName('textarea');
	nScanned = items.length;
	nAdded = BubEnableItems(items, opts);
	nTotalScanned += nScanned;
	nTotalAdded += nAdded;
	stats += ', TEXTAREA: ' + nAdded + '/' + nScanned;

	//--- #6045 - Handle SELECTs.

	items = document.getElementsByTagName('select');
	nScanned = items.length;
	nAdded = BubEnableItems(items, opts);
	nTotalScanned += nScanned;
	nTotalAdded += nAdded;
	stats += ', SELECT: ' + nAdded + '/' + nScanned;

	//--- Generate a dbginfo element to show up in page info (F8).
	
	var		end = new Date().getTime();
	
	stats += ' --> ' + nTotalAdded + '/' + nTotalScanned + ' (' + (end-start) + 'ms)';
	
	RegDebugInfo('BubbleTips', stats, 'Script');
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BubEnableItems(items, opts)
{
	var		nCount = 0;
	var		ii;

	for (ii=0;ii<items.length;ii++)
	{
		if (BubPrepare(items[ii], opts))
		{
			nCount++;
		}
    }

	return (nCount);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BubPrepare(el, opts)
{
	var bPrepared = false;
	var t = (opts && opts.indexOf('t') >= 0) ? el.getAttribute('tt') : el.getAttribute('title');	// #1209
	var elType = ElementType(el);
	
	//--- #2750 - Special handling for tricky elements.
	
	if (!t)
	{
		if (elType == 'checkbox')
		{
			//--- #2750 - Checkboxes have tip on containing span.
	
			el.parentNode.tipPos = el.nextSibling;			// But tip needs to point to label, not checkbox. 
			bPrepared = BubPrepare(el.parentNode, opts);
			RemoveTip(el.parentNode);
		}
		else if (elType == 'radio')
		{
			//--- #2750 - RadioButtons may have per-item tip, on just one tip.
	
			t = (opts && opts.indexOf('t') >= 0) ? el.parentNode.getAttribute('tt') : el.parentNode.getAttribute('title');
			
			if (t)
			{
				bPrepared = BubPrepare(el.parentNode, opts);			// Tip per RadioButton.
				RemoveTip(FindParent(el, 'table'));
				t = null;
			}
			else
			{
				bPrepared = BubPrepare(FindParent(el, 'table'), opts);	// One tip for list.
			}
		}
	}

	//--- If tip...

	if (t && t.length > 0)
	{
		//--- Note: Don't check for visibility or enabled status here, it's too expensive.
		//--- the check is done in the onmouseover handler.
		
		//--- Remove the title from the element so the browser doesn't pop up the
		//--- tooltip in the normal manner, and save the text on the element for use
		//--- by the bubble tip.
	
		RemoveTip(el);
		el.tipText = t;
		//el.ttt = 1;
		// Note: if the element is an IMG and has an ALT attr, that can cause a dupe tip. #4436
		
		//--- #3946 - In Safari/Chrome anchor text is in a span and anchor and span each have a tip.
		
		if (elType == 'a' && ElementType(el.firstChild) == 'span' && el.firstChild.getAttribute('title') == t)
		{
			RemoveTip(el.firstChild);
		}

		//--- Hook up events.

		if (el.onmouseover) el.omo = el.onmouseover;	// #4436 - We'll call through to existing mouseover event.
		el.onmouseover = BubShowTooltip;
		el.onmouseout = BubHideTooltip;

		bPrepared = true;
	}
	
	return (bPrepared);
}

function RemoveTip(el)
{
	el.removeAttribute('title');
	el.removeAttribute('tt');		// #1209
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BubShowTooltip(evt, item, delayed)
{
	if (!evt) evt = window.event;
	if (!item) item = this;
	
	if (!delayed)
	{
		if (item.omo && item.omo(evt) == false) return;		// #4436 - Call through to original mouseover event.
	
		if (window.bubOpen)
		{
			window.clearTimeout(window.bubOpen);
			window.bubOpen = null;
		}
		window.bubOpen = window.setTimeout(function () { BubShowTooltip(null, item, true); }, 250);

		return false;
	}
	
	//--- Get the BubbleTipContainer and set it up for this tip.
	
	var btc = document.getElementById('btc');
	
	if (btc)
	{
		//if (!evt) evt = window.event;
		
		//--- Check for visibility now.  The visibility check is pretty expensive so
		//--- don't do it when setting up the bubble tips, do it when invoked.  If
		//--- control isn't visible and enabled, restore normal title.
		
		//--- By default allow bubble tip on locked control, but support override. [10/7/09 CW]

		if (item)
		{
			var opts = '' + item.getAttribute('tipOpt');
			var noBub = (opts.indexOf('L') >= 0) ? !IsVisibleAndEnabled(item) : !IsVisible(item);

			if (noBub)
			{
				SetTip(item, item.tipText);
				return;
			}
		}
		
		//--- Replace the tip's text with the new element's text.

        var txt = (item && item.tipText) ? item.tipText : '';
        
		window.tipTextNode.data = txt;
		btc.style.left = 5000;					// Avoid flash by moving out of sight first.
		//btc.style.top = 5000;					/* No, 4678 */
		btc.style.display = '';
		
		if (window.bubClose) 
		{
			window.clearTimeout(window.bubClose);
			window.bubClose = null;
		}
		
		var secs = Math.max(txt.length/15,5);   // More time needed for long tips.
		
		window.bubClose = window.setTimeout(function() { btc.style.display = 'none'; }, secs * 1000); // Auto close in specified secs.

		//--- Position the tip.
		
		var relocate = BubLocate(item, btc);
		
		//--- If we had to relocate the tip, the bubble may need to go on top,
		//--- on left, or both.

		BubAdjust(btc, relocate);
	}
}

// Add a permanently visible bubble tip. #2040
function BubPerm(item, tipText)
{
	item = GetElement(item);

	if (item)
	{
		// IE - good, Firefox - OK, Safari - none, Opera - cut off.
		
		var btc = BubCreate(200);
		var content = FindRole(btc, 'content');
		
		btc.parentNode.removeChild(btc);
		item.appendChild(btc);
		item.style.whiteSpace = 'normal';			// In IE, td nowrap stops tip from wrapping.

		var txtNode = document.createTextNode((tipText) ? tipText : item.getAttribute('tipText'));
		content.appendChild(txtNode);
		
		btc.style.zIndex = 100001; //41;
		btc.style.position = 'absolute';
		btc.style.marginLeft = -38;
		btc.style.marginTop = item.offsetHeight - 5;
		btc.style.display = 'inline'; //'block';

		//--- Add close button.

		var img = BubCreateEl('img', '', document);
	
		img.src = 'images/del_x_icon.gif';
		img.style.display = 'inline';
		img.style.align = 'right';
		img.style.marginLeft = '5px';
		img.style.verticalAlign = 'bottom';
		img.onclick = function() { this.parentNode.parentNode.style.display = 'none'; };
		img.zIndex = 100000000;
		
		content.appendChild(img);
		
		var shim = FindRole(btc, 'shim');
		
		if (shim) shim.parentNode.removeChild(shim);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BubHideTooltip()
{
	var btc = document.getElementById('btc');

	if (window.bubOpen)
	{
		window.clearTimeout(window.bubOpen);
		window.bubOpen = null;
	}

	if (btc) btc.style.display = 'none';
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BubLocate(host, tip)
{
	if (host.tipPos) host = host.tipPos;		// #2750 - Support tip pointing to other element.
	
	var relocate = 0;
	var hostLeft = getLeft(host);				// #5421 - Not tip-relative.
	var hostTop = getTop(host);					// #5421 - Not tip-relative.
	var hostWidth = host.offsetWidth;
	var hostHeight = host.offsetHeight;
	var safAnch = (IsAppleWebKit() && ElementType(host) == 'a' && host.firstChild != null && hostWidth == 0);	// #3966
	
	//--- #3946 - Anchor tags in Safari/Chrome carry no size and have misleading position.
	//--- Instead get size and position from firstChild (normally the text).
	
	if (safAnch)
	{
		hostLeft = getLeft(host.firstChild);	// #5421 - Not tip-relative.
		hostTop = getTop(host.firstChild);		// #5421 - Not tip-relative.
		hostWidth = host.firstChild.offsetWidth;
		hostHeight = host.firstChild.offsetHeight;
	}
	
	//--- Handle missing width or height and special cases.
	
	if (hostWidth == 0)
	{
		hostWidth = host.parentNode.offsetWidth;
	} 
	else if (host.offsetParent.offsetWidth < hostWidth) // Unwrapped anchor tags in datasheet
	{
		hostWidth = host.offsetParent.offsetWidth;
	}

	if (hostHeight == 0) 
	{
		hostHeight = host.parentNode.offsetHeight;
	}
	else if (host.offsetParent.offsetHeight < hostHeight) // Unwrapped anchor tags in datasheet
	{
		hostHeight = host.offsetParent.offsetHeight;
	}
	
	//---
	
//	var coord = getCoord(host);
//	
//	hostLeft = coord.left;
//	hostTop = coord.top;
//	hostWidth = coord.width;
//	hostHeight = coord.height;
	
	//---
	
	var ieMenuTooltipFix = false && IsID();	// Work in progress.
	
	if (ieMenuTooltipFix)// && host.ownerDocument.parentWindow.popLeft)
	{
		hostTop += window.popY;
		tip.style.zIndex = 4000000000;
	}

	//--- Calculate normal position.

	var posx = hostLeft + hostWidth - 40;//hostLeft + wid/2 - 30;
	var posy = hostTop + hostHeight + 1;
	var winWidth = WindowWidth(window);
	var winHeight = WindowHeight(window);
	
	if (ieMenuTooltipFix)
	{
		hostLeft += window.popX;
		hostLeft += WindowWidth(window.pop);
		posx = hostLeft;
	}
	
	//--- Adjust x position when tip would be out of window.
	
	var xScroll = (document && document.body) ? document.body.scrollLeft : 0;	// #3564
	
	if (posx < 0)
	{
		posx = 1;
	}
	else if (posx + tip.offsetWidth - xScroll > winWidth)
	{
		posx = hostLeft - tip.offsetWidth + 40;
		
		if (posx + tip.offsetWidth > winWidth)
		{
			posx = winWidth - tip.offsetWidth - 1;
		}

		relocate |= 0x00000001;		// x adjustment
	}
		
	//--- Adjust y position when tip would be out of window.
	
	if (posy < 0)
	{
		posy = 1;
		relocate |= 0x00000002;		// y adjustment
	}
	else if (posy + tip.offsetHeight > winHeight && hostTop - tip.offsetHeight >= 0)
	{
		posy = hostTop - tip.offsetHeight;
		relocate |= 0x00000002;		// y adjustment
	}
	
	//--- Now actually position the tip.
	
	tip.style.left = posx + 'px';
	tip.style.top = posy + 'px';
	
	return (relocate);
}

//-----------------------------------------------------------------------------------------
function BubAdjust(tip, relocate)
{
	//--- If we had to relocate the tip, the bubble may need to go on top,
	//--- on left, or both.

	var cls = tip.baseCss;							// Assume no adjustment
	
	if ((relocate & 0x00000003) == 0x00000003)		// x & y adjustment
	{
		cls += 'fhv';
	}
	else if (relocate & 0x00000001)					// x adjustment
	{
		cls += 'fh';
	}
	else if (relocate & 0x00000002)					// y adjustment
	{
		cls += 'fv';
	}

	if (GetCssClass(tip) != cls)
	{
		SetCssClass(tip, cls);
	}
	
	//--- Position IE shim, if any.

	var shim = FindRole(tip, 'shim'); // tip.GetShim();

	if (shim)
	{
		shim.style.display = '';
		shim.style.height = tip.offsetHeight;
		shim.style.width = tip.offsetWidth;
	}
}

//-----------------------------------------------------------------------------------------
function BubCreate(wid)
{
	//--- Create outer div.
	
	var div = document.createElement('div');
	var widCh = (wid > 300) ? '4' : '2';
	
	AddDocEl(div, document);			// #3603 - Don't add elements to IE DOM until page load complete.
	SetCssClass(div, 'rp' + widCh);
	div.style.display = 'none';
	div.style.position = 'absolute';
	div.baseCss = 'tt' + widCh;

	//--- Create top, middle, bottom for bubble tip background image handling.
	
	var tooltip = BubCreateEl('span', div.baseCss, document);

	var t = BubCreateEl('span', 'top', document);
	tooltip.appendChild(t);

	var m = BubCreateEl('span', 'mid', document);
	m.role = 'content';
	tooltip.appendChild(m);
 
	var b = BubCreateEl('span', 'bottom', document);
	tooltip.appendChild(b);

	div.appendChild(tooltip);
	
	//--- For IE, add a shim IFrame to cover any SELECT windows.	

	if (IsIE())
	{
		var shim = CreateShim();
		
		shim.style.position = 'absolute';
		shim.style.left = 0;
		shim.style.top = 0;
		
		div.appendChild(shim);
	}

	return (div);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END BubbleTip handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
function AddDocEl(el, doc, retries)
{
	if (!doc) doc = document;
	
	if (IsIE() && doc.readyState != 'complete')
	{
		//--- If you try to add an element to the doc in IE and the document isn't 
		//--- complete you'll get a 'Internet Explorer cannot open the Internet site' ...
		//--- 'Operation aborted' error!
		
		var delay = 50;
		
		if (!retries)
		{
			retries = 0;
		}
		else
		{
			if (retries > 2)
			{
				delay = 1000;
			}
			else if (retries > 1)
			{
				delay = 500;
			}
			else if (retries > 0)
			{
				delay = 100;
			}
		}
		
		if (retries < 5) window.setTimeout(function() { AddDocEl(el, doc, retries+1); }, delay);
	}
	else
	{
		doc.getElementsByTagName('body')[0].appendChild(el);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function RegDebugInfo(name, val, cat, lev)
{
	var dbg = document.createElement('dbginfo');
	
	dbg.setAttribute('name', name);
	dbg.setAttribute('value', val);
	dbg.setAttribute('cat', cat);
	if (lev) dbg.setAttribute('lev', lev);
	
	AddDocEl(dbg);
}

// startignore
// eap:startheader
//--------------------------------------------------------------------
// XHConn - Simple XMLHTTP Interface - bfults@gmail.com - 2005-04-08
// Obtained from http://xkr.us/code/javascript/XHConn/
// Code licensed under Creative Commons Attribution-ShareAlike License
// http://creativecommons.org/licenses/by-sa/2.0/
//--------------------------------------------------------------------
// eap:endheader
// endignore
function XHConn()
{
	var xmlhttp, bComplete = false;
	
	try { xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); }
	catch (e) { try { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); }
	catch (e) { try { xmlhttp = new XMLHttpRequest(); }
	catch (e) { xmlhttp = false; }}}
	if (!xmlhttp) return null;
	
	// Define a basic request method.
	this.invoke = function(sURL, sMethod, sVars, fnDone, bSync)		// #5748
	{
		if (!xmlhttp) throw new Error(10001, 'No XMLHttp available.');
		
		var rsp = null;
		var	bAsync = (bSync == null || bSync != true);
		
		bComplete = false;
		sMethod = sMethod.toUpperCase();
		
		//--- Set up get vs. post.
		
		if (sMethod == "GET")
		{
			xmlhttp.open(sMethod, sURL+"?"+sVars, bAsync);
			sVars = "";
		}
		else
		{
			xmlhttp.open(sMethod, sURL, bAsync);
			xmlhttp.setRequestHeader("Method", "POST "+sURL+" HTTP/1.1");
			xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		}
		
		//--- Set up for async response.
		
		xmlhttp.onreadystatechange = function()
		{
			if (!bSync && xmlhttp.readyState == 4 && !bComplete && fnDone)
			{
				bComplete = true;
				fnDone(xmlhttp);
			}
		};
		
		//--- Send request.
		
		xmlhttp.send(sVars);
		
		//--- Handle synchronous response.
		
		if (bSync && fnDone) 
		{
			bComplete = true;
			rsp = fnDone(xmlhttp);   // #4251 - Handle rsp when sync.  #5748 - Return rsp when sync.
		}
	
		return (rsp);
	}
  
	// Define a "safe" request method catching errors and returning true if successful, else false.
	this.connect = function(sURL, sMethod, sVars, fnDone, bSync)
	{
		try 
		{
			this.invoke(sURL, sMethod, sVars, fnDone, bSync);	// #5748 - Split out invoke().
		}
		catch(z) 
		{ 
			return false; 
		}
		
		return true;
    };
    
	// Define a method to get a string.
    this.getString = function(sURL, sVars, fnDone)
    {
		if (!xmlhttp) return false;
		bComplete = false;

		try 
		{
			xmlhttp.open('GET', sURL+"?"+sVars, true);
			sVars = "";

			xmlhttp.onreadystatechange = function()
			{
				if (xmlhttp.readyState == 4 && !bComplete)
				{
					bComplete = true;
					if (fnDone) fnDone(xmlhttp.responseText);
				}
			};

		    xmlhttp.send(sVars);
		}
		catch(z) 
		{ 
			return false; 
		}
		
		return true;
	};
	
	// Define a method to get a JSON object.
    this.getObject = function(sURL, sVars, fnDone)
    {
		if (!xmlhttp) return false;
		bComplete = false;

		try 
		{
			xmlhttp.open('GET', sURL+"?"+sVars, true);
			sVars = "";

			xmlhttp.onreadystatechange = function()
			{
				if (xmlhttp.readyState == 4 && !bComplete)
				{
					bComplete = true;
					if (fnDone) fnDone(eval('(' + xmlhttp.responseText + ')'));
				}
			};

		    xmlhttp.send(sVars);
		}
		catch(z) 
		{ 
			return false; 
		}
		
		return true;
	};
	
  return this;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function Trace(msg)
{
	var loc = window.document.location;
	var reverseLog = true;
	
	//--- Build the text.
	
	if (reverseLog)
	{
		if (loc != window.top.logLastLoc)
		{
			msg += '\n-------------- ' + loc;
			window.top.logLastLoc = loc;
		}

		if (window.top.logMsg)
			window.top.logMsg = msg + '\n' + window.top.logMsg;
		else
			window.top.logMsg = msg;
	}
	else
	{
		if (window.top.logMsg)
		{
			window.top.logMsg += '\n';
		}

		if (loc != window.top.logLastLoc)
		{
			if (window.top.logMsg)
				window.top.logMsg += '-------------- ' + loc + '\n';
			else
				window.top.logMsg = '-------------- ' + loc + '\n';
			window.top.logLastLoc = loc;
		}

		window.top.logMsg = '' + window.top.logMsg + msg;
	}
		
	//---
	
	if (window.top.logTimeout)
	{
		window.top.clearTimeout(window.top.logTimeout);
	}
	window.top.logTimeout = window.top.setTimeout(function () { TraceUpdate(); }, 30);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function TraceUpdate()
{
	var wid = 400;
	var opts = WindowOpenFeatures(0x00000208, 600, wid);
	var winLog = window.top.open('blank.htm', 'logwin', opts, false);

	if (!winLog) { alert('no winLog'); return; }
	
	var txt = (winLog.document) ? winLog.document.getElementById('txt') : null;
	
	if (!txt)
	{
		var doc = winLog.document;
		
		doc.title = 'Trace';
		
		doc.open();
		doc.writeln('<html>');
		doc.writeln('<head>');
		doc.writeln('</head>');
		doc.writeln('<body style="overflow:hidden;border:none;margin:0">');
		doc.writeln('<input type="button" value="Clear" id="clr" onclick="document.getElementById(\'txt\').value = \'\'; opener.logMsg = \'\';" style="" />');
		doc.writeln('<br/><textarea id="txt" style="height:100%;width:100%;white-space:pre;overflow:scroll" wrap="off"></textarea>');
		doc.writeln('</body>');
		doc.writeln('</html>');
		doc.close();
		
		//---		
		
//		txt = doc.createElement('textarea'); //'input');
//		txt.id = 'txt';
//		txt.style.height = '100%'; //'550';
//		txt.style.width = '100%'; //'350';
		//txt.style.whiteSpace = 'noWrap';
		//txt.style.wrap = 'nowrap';
//		txt.style.whiteSpace = 'pre';
//		AddDocEl(txt, doc);

		txt = winLog.document.getElementById('txt');
	}

	//--- Update trace and bring trace window to foreground.

	if (txt)
	{
		txt.value = window.top.logMsg;
		winLog.focus();
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FieldIsReq(ctrl)
{
    var req = false;
    
    if (ctrl)
    {
        var lbl;
        var lkupId = ctrl.getAttribute('lkup');
        //var lkup = (lkupId) ? document.getElementById(lkupId + '_tbl') : null;
        
        if (lkupId)
        {
	        lbl = FindLabelFor(lkupId);
	        //alert(lkupId + ',' + (lbl == null));
	    }
        else
	        lbl = FindLabelFor(ctrl);
        
        if (lbl)
        {
	        req =  HasCssClass((ElementType(ctrl) == 'checkbox') ? lbl.parentNode : lbl, 'rqf');	// #3223 - .Net checkbox rendering.
        }
        else
        {
            req = HasCssClass(ctrl, 'rqf');
        }
    }
    
    return (req);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ReqFieldToggle(id)
{
    ReqFieldSet(id, !FieldIsReq(document.getElementById(id)));
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ReqFieldSet(id, req)
{
    var ctrl = document.getElementById(id);
    
    if (ctrl)
    {
        var lbl = FindLabelFor(ctrl);
        
        if (lbl)
        {
            if (req)
            {
                ReplaceCssClass(lbl, 'nrqf', 'rqf');
            }
            else
            {
                ReplaceCssClass(lbl, 'rqf', 'nrqf');
            }
        }
    }
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START Field AutoResize helpers
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function InitPosition(ctrl)
{
	if (ctrl)
	{
		ctrl.origLeft = getLeft(ctrl);
		ctrl.origTop = getTop(ctrl);
		ctrl.origHeight = ctrl.offsetHeight;
		ctrl.origWidth = ctrl.offsetWidth;
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function InitPositions(tagName)
{
	var els = document.getElementsByTagName(tagName);
	var ii;

	for (ii=0; ii<els.length; ii++)
	{
		var ctrl = els[ii];

		ctrl = PositionableItem(ctrl);

		InitPosition(ctrl);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function PositionableItem(ctrl)
{
	while (ctrl && ctrl.tagName != 'DIV' && (!ctrl.style || ctrl.style.position != 'absolute'))
	{
		ctrl = ctrl.parentNode;
	}

	return (ctrl);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function UpdatePosition(ctrl, left, top, deltaX, deltaY)
{
	if (ctrl && ctrl.origTop >= top)
	{
		var t = ctrl.origTop + deltaY;
		if (t < ctrl.origTop) t = ctrl.origTop;
		ctrl.style.top = t;
	}
}
			
//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function UpdatePositions(tagName, left, top, deltaX, deltaY)
{
	var els = document.getElementsByTagName(tagName);
	var ii;

	for (ii=0; ii<els.length; ii++)
	{
		var ctrl = els[ii];

		ctrl = PositionableItem(ctrl);

		UpdatePosition(ctrl, left, top, deltaX, deltaY);
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END Field AutoResize helpers
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
// Register an item to tell if it's been done before.
//---------------------------------------------------------------------------------------------------------------
function RegisterItem(id)
{
	try
	{
		var win = (window.opener) ? window.opener : window.top;
	    
		if (win.regItems && win.regItems.indexOf(';' + id + ';') >= 0)
		{
			return (false);                 // Item already registered.
		}
		else if (win.regItems)
		{
			win.regItems = ';' + id + win.regItems;
		}
		else
		{
			win.regItems = ';' + id + ';';  // First item.
		}
    }
    catch (e)
    {
		// #5061 - Ignore and continue.
    }
    
    return (true);                      // Item not previously registered.
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function CtrlContains(ctrlOut, ctrlIn)
{
	return (getLeft(ctrlIn) >= getLeft(ctrlOut) &&
			getTop(ctrlIn) >= getTop(ctrlOut) &&
			OffsetRight(ctrlIn) <= OffsetRight(ctrlOut) &&
			OffsetBottom(ctrlIn) <= OffsetBottom(ctrlOut));
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FractDigits(n)
{
    var digits = 0;
    var s = '' + n;

    if (s)
    {
	    s = s.replace(/0*$/,'');    // Remove trailing zeros
	    var dot = s.indexOf('.');

	    if (dot >= 0)
	    {
		    digits = s.length - dot - 1;
	    }
    }
    
    return (digits);
}

//-----------------------------------------------------------------------------------------
// e.g. 3.1 * 10001 = 31003.100000000002 --> 31003.1
//-----------------------------------------------------------------------------------------
function Mult(a, b)
{
	var c = '' + (a * b);
	var dot = c.indexOf('.');
	var cDigits = FractDigits(c);

	if (dot >= 0 && cDigits > 0)
	{
	    var aDigits = FractDigits(a);
	    var bDigits = FractDigits(b);
		var scale = Math.pow(10, aDigits + bDigits);
		
		c = Math.round(Number(c) * scale) / scale;
	}

	return (Number(c));
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function PopupPost(evt, btn, features)
{
	if (!evt) evt = window.event;
	
    var content;
    var width = 0;
    var height = 0;
	
	//--- #4611 - Initially size small for better size-to-content.
	
	if (features & 0x00000800)
	{
		width = 200;
		height = 100;
	}

	var opts = WindowOpenFeatures(features, height, width);
	var win = window.open('blank.htm', '_blank', opts);

    window.cloneWindow(window, win, content);
    
	if (ElementType(btn) == 'a' && btn && btn.href)
    {
        //--- Hijack the .Net __doPostBack() event.
        
        theForm = win.document.getElementById(theForm.id);
	    eval(btn.href);
        theForm = window.document.getElementById(theForm.id);
    }
    else
    {
	    var btnClone = win.document.getElementById(btn.id);
        DoClick(btnClone, false, win);
    }
    
    return CancelBubble(evt);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START PostIt handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
function PostItCreate(rowKey)
{
    var doc = document;
    var divOut = document.createElement('DIV');
    
	window.document.forms[0].appendChild(divOut);

	var shim = null;
	var edit = null;
	
    if (IsIE())
    {
        shim = CreateShim();
        shim.style.zIndex = -1;
		shim.style.position = 'absolute';
		shim.style.top = '-2'; //'-1'; //'0';
		shim.style.left = '-2'; //'-1';//   '0';
    }

	//--- Create editable area.
	    
	edit = doc.createElement('textarea');
	edit.onblur = window.PostItBlur;
	edit.setAttribute('nofocus', '1');
	edit.setAttribute('neverDirty', '1');
    SetCssClass(edit, 'postit');

	divOut.style.overflow = 'hidden';
	//edit.hideFocus = false;
	
	edit.txt = '';
	
    divOut.appendChild(edit);
	doc = edit.contentDocument;
	window.onresize = window.PostItResize;

	//---
	
	var divIn = null;

    //--- Create the delete button.
    
    var del = document.createElement('IMG');
    
    del.src = 'images/del_x_icon.gif';
	
	var tip = window.postitHideTip;		// #4782
	
    SetTip(del, (tip) ? tip : 'Click here to hide this note.');
    
    if (IsIE())
	    del.onclick = window.PostItHide;
	else
		del.addEventListener('click', window.PostItHide, false);
    SetCssClass(del, 'actimg');

    var delAnchor = document.createElement('A');
    delAnchor.href = '#';
    SetCssClass(delAnchor, 'actimg');

    delAnchor.appendChild(del);
    del = delAnchor;
    
    //--- Create the note banner.
    
    var banner = document.createElement('DIV');
    banner.appendChild(del);
    SetCssClass(banner, 'postitban');

	//--- Create the help button.

    var hlp = document.createElement('IMG');

    hlp.src = 'images/helpmini.gif';
    
    banner.appendChild(hlp);

	//--- Create the resize button.

    var rsz = document.createElement('IMG');

    rsz.src = 'images/corner.gif';
    rsz.style.zIndex = 1000;
	rsz.style.position = 'absolute';
	rsz.style.top = 60-12;
	rsz.style.left = 100-12;
    rsz.style.cursor = 'nw-resize';
    rsz.onmousedown = PostItSizeStart;
    
    var tip = window.postitResizeTip;	// #4782

	SetTip(rsz, (tip) ? tip : 'Click and drag here to resize this note.');
	
    divOut.appendChild(rsz);
    divOut.rsz = rsz;

	//---
	
	divOut.style.height = '60px';
    divOut.style.width = '100px';
    SetCssClass(divOut, 'postit');
    divOut.style.zIndex = 1000;
    
	divOut.style.display = 'none';
    
    banner.onmousedown = window.PostItMoveStart;
    
    divOut.onresize = PostItResize;
//    divIn.onresizeend = PostItResize;
    
 //   div.onkeypress = window.PostItKeyPress;
	 if (divIn) //shim)
		divIn.onkeydown = window.PostItKeyDown;
	 else
		edit.onkeydown = window.PostItKeyDown;
//    divOut.onblur = PostItBlur;

    if (shim)
    {
        divOut.appendChild(shim);
        divOut.shim = shim;
        shim.style.width = divOut.style.width;
        shim.style.height = divOut.style.height;
    }
    
	divOut.insertBefore(banner, edit);
	divOut.tip = hlp; //delAnchor;
    
    if (edit)
    {
		if (divIn)
		{
			divIn.style.zIndex = 100;
		}
    }
    else if (divIn)
    {
	    divOut.appendChild(divIn);
	}

    divOut.editor = (edit) ? edit : divIn;
    
    return (divOut);
}

//-----------------------------------------------------------------------------------------
function PostItNew(mop, flavor, cmd, id, top, left, height, width)
{
	var postit = PostItCreate(window.rowKey);
	
	if (postit)
	{
		var editor = postit.editor;
		
		editor.setAttribute('mop', mop);
		editor.setAttribute('flavor', flavor);
		editor.setAttribute('cmd', cmd);
		if (id) editor.setAttribute('postid', id);

		if (!top) top = Mouse.y + 20;
		if (!left) left = Mouse.x - 40;
		if (!height) height = 60;
		if (!width) width = 100;
		
		//alert(top + '+' + left + '+' + height + '+' + width);

		postit.style.top = top; // + 'px';
		postit.style.left = left; // + 'px';
		postit.style.height = parseInt(height) + 'px';
		postit.style.width = width; // + 'px';
		postit.style.display = 'block'; //'';
		
		editor.style.height = parseInt(height) + 'px';// - 18;
	}
	
	return (postit);
}

//-----------------------------------------------------------------------------------------
function PostItEnable(edit)
{
	// Firefox needs a delay before turning on designMode.

	edit.contentDocument.designMode = 'on';
	edit.contentWindow.focus();
	edit.contentDocument.addEventListener('blur', window.PostItBlur, false); //window.PostItBlur, false);
}

//-----------------------------------------------------------------------------------------
function PostItMoveStart(evt)
{
    if (!evt) evt = window.event;
    
   // this.focus();
	var div = this;
	div = this.parentNode;
	
    div.moving = true;
    div.xStart = evt.clientX;
    div.yStart = evt.clientY;
    div.leftStart = div.offsetLeft;
    div.topStart = div.offsetTop;
	if (IsIE()) div.setCapture();
	
    div.onmousemove = window.PostItMove;
    div.onmouseup = window.PostItMoveEnd;
}

//-----------------------------------------------------------------------------------------
function PostItMove(evt)
{
    if (!evt) evt = window.event;
    
    var div = this;
	//div = this.parentNode;

    if (div.moving)
    {
        div.style.left = (div.leftStart + (evt.clientX - div.xStart)) + 'px';
        div.style.top = (div.topStart + (evt.clientY - div.yStart)) + 'px';
       // window.status += '.';
    }
}

//-----------------------------------------------------------------------------------------
function PostItMoveEnd(evt)
{
    if (!evt) evt = window.event;
    
    this.moving = false;
    
    this.onmousemove = null;
    this.onmouseup =  null;
	if (IsIE()) this.releaseCapture();
	
	PostItSave(this.editor, 'move');
}

//-----------------------------------------------------------------------------------------
function PostItSizeStart(evt)
{
    if (!evt) evt = window.event;
    
   // this.focus();
	var rsz = this;
	var div = rsz.parentNode;
	
    rsz.resizing = true;
    rsz.xStart = evt.clientX;
    rsz.yStart = evt.clientY;
    rsz.leftStart = rsz.offsetLeft;
    rsz.topStart = rsz.offsetTop;
	if (IsIE()) rsz.setCapture();
	
    div.xStart = evt.clientX;
    div.yStart = evt.clientY;
    div.widthStart = div.offsetWidth;
    div.heightStart = div.offsetHeight;

    rsz.onmousemove = window.PostItSize;
    rsz.onmouseup = window.PostItSizeEnd;
}

//-----------------------------------------------------------------------------------------
function PostItSize(evt)
{
    if (!evt) evt = window.event;
    
    var rsz = this;
	var div = rsz.parentNode;

    if (rsz.resizing)
    {
        rsz.style.left = rsz.leftStart + (evt.clientX - rsz.xStart);
        rsz.style.top = rsz.topStart + (evt.clientY - rsz.yStart);

        div.style.width = div.widthStart + (evt.clientX - div.xStart);
        div.style.height = div.heightStart + (evt.clientY - div.yStart);

		//window.status += '.';
    }
}

//-----------------------------------------------------------------------------------------
function PostItSizeEnd(evt)
{
    if (!evt) evt = window.event;
    
    var rsz = this;
	var div = rsz.parentNode;

    this.resizing = false;
    
    this.onmousemove = null;
    this.onmouseup =  null;
	if (IsIE()) this.releaseCapture();

	PostItSave(div.editor, 'move');
}

//-----------------------------------------------------------------------------------------
function PostItKeyDown(evt)
{
    if (!evt) evt = window.event;

    var key = GetEventKey(evt);
    
    if (key == 27)
    {
		var editor = GetEventTarget(evt);

		PostItSetText(editor.parentNode, editor.txt);
		this.moving = false;
		if (IsIE()) this.releaseCapture();
        this.blur();
        return false;
    }
    else if (key == 13)
    {
		if (!evt.shiftKey) //ctrlKey)	// #701
		{
			this.blur();
			return false;
		}
    }
}

//-----------------------------------------------------------------------------------------
function PostItBlur(evt)
{
	if (this)
	{
		var txtOld = (this.tagName) ? this.txt : this.txt; //''; //IsIE() ? this.txt : '';
		var txtNew = (ElementType(this) == 'textarea') ? this.value : InnerTextGet(this);
		
		if (txtNew != txtOld && (txtOld || txtNew))
		{
			this.txt = txtNew;
			PostItSave(this, 'edit');
		}
	}
}

//-----------------------------------------------------------------------------------------
function PostItHide(evt)
{
   if (!evt) evt = window.event;
   
   var postit = this.parentNode.parentNode.parentNode;
   
   if (postit)
   {
	   postit.style.display = 'none';
	   PostItSave(postit.editor, 'hide');
	}
}

//-----------------------------------------------------------------------------------------
function PostItSave(editor, subcmd)
{
	var postit = editor.parentNode;
	var txt = editor.txt;
	
	if (!postit.id)
	{
		postit.id = 'p' + Timestamp();
	}
	
	var post_id = editor.getAttribute('postid');
	var params = '&pid=' + postit.id;
	
	if (post_id) params += '&id=' + encodeURIComponent(post_id);
	
	if (subcmd) params += '&subcmd=' + subcmd;
	
	params += '&txt=' + encodeURIComponent(txt);
	
	var top = getTop(postit); //editor);
	var left = getLeft(postit); //editor);
	
	var btn = document.getElementById('toolbar_toolbar'); //'toolbar_postit');
	
	if (btn)
	{
		top = top - getTop(btn);
		left = left - getLeft(btn);
	}

	params += '&top=' + top;
	params += '&left=' + left;
	params += '&width=' + postit.offsetWidth;
	params += '&height=' + postit.offsetHeight;
	
	if (subcmd == 'hide')
	{
		AjaxCommandClick(null, editor, params, null);
	}
	else
	{
		AjaxCommandClick(null, editor, params, PostItSaveRsp);
		PostItSizing(postit);
	}
}

//-----------------------------------------------------------------------------------------
function PostItSaveRsp(rsp)
{
	var txt = rsp.responseText;
	
	if (txt)
	{
		var parts = txt.split('|');
		var pid = parts[0];
		var id = parts[1];
		var postit = document.getElementById(pid);
		
		if (postit)
		{
			postit.editor.setAttribute('postid', id);
		}
	}
}

//-----------------------------------------------------------------------------------------
function PostItResize(evt)
{
	var postit = this; //(this.shim) ? this : this.parentNode;
	
    if (postit.shim)
    {
		//window.status += 'resize: h=' + postit.offsetHeight + 2 + 'px';
        postit.shim.style.width = postit.offsetWidth + 2 + 'px';
        postit.shim.style.height = postit.offsetHeight + 2 + 'px';
    }
    else if (postit.editor)
    {
//		postit.editor.height = '60px';
//		postit.editor.width = '100px';
    }
    else
    {
		//window.status += 'unhandled resize.';
    }
}

//-----------------------------------------------------------------------------------------
function PostItLoad(relId, mop, flavor, noteKey)
{
	var handled = false;

	if (window.XHConn && relId)
	{
		//--- Open asynchronous connection to server.

		var conn = new XHConn();

		//--- If connection established, issue a log request.
			    
		if (conn)
		{
			var params = 'req=postits';
			
			params += '&relid=' + relId;
			params += '&mop=' + mop;
			params += '&flavor=' + flavor;
			params += '&noteKey=' + noteKey;
			
			params += "&ajaxdt=" + Timestamp();	// Force request to be unique to prevent cache hit.
//alert(params);
							
			conn.connect('Handler.ashx', 'GET', params, PostItLoadRsp);

			handled = true;
		}
	}
	
	return (handled);
}

//-----------------------------------------------------------------------------------------
function PostItLoadRsp(rsp)
{
	var notesRsp = rsp.responseText;
	
	if (!notesRsp)
	{
	}
	else if (notesRsp.indexOf('!err!') == 0)
	{
		alert(notesRsp.substr(5));
	}
	else
	{
		var notes = notesRsp.split('|');
		var ii;
		var common = notes[0].split('~');
		var mop = common[0];
		var flavor = common[1];
		
		for (ii=1; ii<notes.length; ii++)
		{
			var note = notes[ii];
			
			if (note)
			{
				var parts = note.split('~');
				var note_id = parts[0];
				var note_text = parts[1];
				var settings = parts[2];
				var tip = parts[4];
				var top;
				var left;
				var width;
				var height;
				
				if (settings)
				{
					var settingParts = settings.split(',');
					
					if (settingParts.length >= 1) top = Number(settingParts[0]);
					if (settingParts.length >= 2) left = Number(settingParts[1]);
					if (settingParts.length >= 3) height = settingParts[2];
					if (settingParts.length >= 4) width = settingParts[3];
				}
				
				var btn = document.getElementById('toolbar_toolbar'); //toolbar_postit');
				
				if (btn)
				{
					top = getTop(btn) + top;
					left = getLeft(btn) + left;
				}
				
				var postit = PostItNew(mop, flavor, 'postit', note_id, top, left, height, width);
				
				PostItSetText(postit, UrlDecode(note_text)); //decodeURIComponent(note_text));
				
				if (tip)
					postit.tip.title = UrlDecode(tip);
				else
					postit.tip.style.display = 'none';
			}
		}
	}
}

//-----------------------------------------------------------------------------------------
function PostItSizing(postit)
{
	if (postit && postit.style.display != 'none')
	{
		var editor = postit.editor;
		
		if (editor && ElementType(editor) == 'textarea')
		{
			postit.style.height = (editor.scrollHeight + 20) + 'px'; // * (1 + 16/editor.scrollWidth);
			
			var hgt = postit.offsetHeight - 10;
			
			if (IsFirefox() || IsOpera()) hgt += 3;
			
			editor.style.height = hgt + 'px';
			
			var rsz = postit.rsz;
			
			if (rsz)
			{
				rsz.style.top = postit.offsetHeight - 12 + 'px';
				rsz.style.left = postit.offsetWidth - 12 + 'px';
			}
		}
	}
}

//-----------------------------------------------------------------------------------------
function PostItSetText(postit, txt)
{
	if (postit)
	{
		var editor = postit.editor;
		
		editor.txt = txt;
		
		if (ElementType(editor) == 'textarea')
		{
			editor.value = txt;
			PostItSizing(postit);
		}
		else if (postit.shim)
		{
			editor.innerHTML = txt;
//			if (postit.shim) window.setTimeout( function() { PostItShim(postit, 5); }, 1);
		}
		else
		{
			editor.value = txt;
		}
		
		if (postit.shim) window.setTimeout( function() { PostItShim(postit, 5); }, 1);
	}
}

//-----------------------------------------------------------------------------------------
function PostItShim(postit, tries)
{
	if (postit && postit.shim && postit.shim.offsetHeight != postit.offsetHeight + 2)
	{
		postit.shim.style.width = (postit.offsetWidth + 2) + 'px';
		postit.shim.style.height = (postit.offsetHeight + 2) + 'px';
		
		if (tries > 0)
		{
			window.setTimeout( function() { PostItShim(postit, tries-1); }, 100);
		}
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END PostIt handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
function NameFromPath(path, noExt)
{
	var nm = path.substr(Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'))+1);
	
	if (noExt && nm) nm = nm.substr(0, nm.lastIndexOf('.'));
	
	return (nm);
}

//---------------------------------------------------------------------------------------------------------------
// Used by FileWidget
function OnFileChg(file, noExt)
{
	var fdfId = file.getAttribute('fdf');
	var txtId = file.getAttribute('ftf');
	var txt = document.getElementById(txtId);
	
	if (fdfId)
	{
		var fdf = document.getElementById(fdfId);
		
		if (!txt.value || !fdf || fdf.value)
		{
			txt.value = NameFromPath(file.value, noExt);
		}
		
		if (fdf) fdf.value = NameFromPath(file.value);
	}
	else if (txt)
	{
		txt.value = NameFromPath(file.value);
	}
}

//---------------------------------------------------------------------------------------------------------------
function LogTiming(start)
{
	if (start)
	{
		var dt = new Date();
		RegDebugInfo('Browser', (dt.getTime() - start) + 'ms', 'Timing');
	}
}

function OnChange(ctrl, evt)
{
    if (ctrl.change)
	    ctrl.change(evt);		// IE
    else if (ctrl.onchange)
	    ctrl.onchange(evt);		// Firefox
}

function OnBlur(ctrl)
{
	if (ctrl)
	{
		if (ctrl.blur)
			ctrl.blur();
		else if (ctrl.onblur)
			ctrl.onblur();
	}
}

function OnClick(ctrl)
{
	if (ctrl)
	{
		if (ctrl.click) 
			ctrl.click();
		else if (ctrl.onclick)
			ctrl.onclick();
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START date/time format handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

function TimeSep(fmt)
{
	return (fmt) ? fmt.match(/[^hHmsfFtz]/) : ':';
}

function TimeIs24Hr(fmt)
{
	return (fmt) ? (fmt.search(/H/) >= 0) : false;
}

function TimeIsHrPadded(fmt)
{
	return (fmt) ? fmt.match(/hh/i) : false;
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END date/time format handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------------------------
function WinDepth()
{
    var p = window;
    var n = 0;
    
    while (p && p != p.parent && n<20)
    {
		n++;
		p = p.parent;
    }
    
    return (n);
}

//---------------------------------------------------------------------------------------------------------------
function SizeScrAbs(id, w, h)
{
	var item = document.getElementById(id);
	
	if (item)
	{
		item.style.width = w - window.screenLeft;
		item.style.height = h - window.screenTop;
		//item.setAttribute('title', '' + w + ' x ' + h);
	}
}

//---------------------------------------------------------------------------------------------------------------
function RateClk(evt, map, fld, rk)
{
	if (!evt) evt = window.event;

	var img = GetEventTarget(evt);
	
	var attrs = img.parentNode.getAttribute('attrs');
	
	attrs = (attrs) ? parseInt(attrs, 16) : 0;

	var bDualImg = (0 != (attrs & 0x00000001));
	var	srcOn;
	var srcOff;
	var cls;
	var fnIsOn;
	
	if (bDualImg)
	{
		if (img.src.match(/.*x.gif$/i)) 
		{
			srcOff = img.src;
			srcOn = srcOff.replace(/x.gif$/, '.gif');
		}
		else 
		{
			srcOn = img.src;
			srcOff = srcOn.replace(/.gif$/, 'x.gif');
		}
		fnIsOn = function(c) { return (!c.src.match(/.*x.gif$/i)); };
	}
	else
	{
		cls = 'rateoff';
		fnIsOn = function(c) { return(!HasCssClass(c, cls)); };
	}
	
	//--- Fixup client icons.
	
	var val = img.getAttribute('v');
	var off = img.nextSibling;
	
	if (img == img.parentNode.firstChild && (!off || !fnIsOn(off)))
	{
		//--- Special handling to toggle 1st item. #1862
	
		if (!fnIsOn(img))
		{
			if (srcOn) img.src = srcOn;
			if (cls) RemoveCssClass(img, cls);
		}
		else
		{
			if (srcOff) img.src = srcOff;
			if (cls) ReplaceCssClass(img, '', cls);
			val = '';
		}
	}
	else
	{
		while (off)
		{
			if (srcOff) off.src = srcOff;
			if (cls) ReplaceCssClass(off, '', cls);
			off = off.nextSibling;
		}
		
		while (img)
		{
			if (srcOn) img.src = srcOn;
			if (cls) RemoveCssClass(img, cls);
			img = img.previousSibling;
		}
	}
	
	//--- AJAX request to set val.
	
	var conn = new XHConn();

	if (conn)
	{
		var params = 'req=rate&map=' + map + '&rk=' + rk + '&fld=' + fld + '&val=' + val + '&ajaxdt' + Timestamp();;

		conn.getString('Handler.ashx', params, null);
		//window.status = "Retrieving information from server...";
	}
}

//---------------------------------------------------------------------------------------------------------------
function SetBlinker(item, css)
{
	item = IsString(item) ? window.document.getElementById(item) : item;
	
	KillBlinker(item);
	
	if (css)
	{
		item.blinker = window.setInterval(function()
			{
				if (HasCssClass(item, css))
					RemoveCssClass(item, css);
				else
					ReplaceCssClass(item, '', css);
			}, 500);
	}
	else
	{
		item.blinker = window.setInterval(function()
			{
				item.style.visibility = (item.style.visibility == '') ? 'hidden' : '';
			}, 500);
	}
}

//---------------------------------------------------------------------------------------------------------------
function KillBlinker(item)
{
	if (item && item.blinker) window.clearInterval(item.blinker);
}

//---------------------------------------------------------------------------------------------------------------
function StatusMsg(msg, opts, btn, win, delay)
{
	if (!win) win = window;
	
	//--- Handle delay. #2752
	
	if (delay)
	{
		window.setTimeout(function() { StatusMsg(msg, opts, btn, win); }, delay);
		return;
	}
	
	//--- Setup.
	
	var doc = win.document;
	var shim;
	var div;
	var icon = opts & 0x00000001;
	var lock = opts & 0x00000002;
	var blink = opts & 0x00000004;
	var fade = opts & 0x00000008;
	var src = 'images/AniProg.gif';
	
	var item = doc.getElementById('statmsg');
	
	//--- If no status div, create now.
	
	if (!item)
	{
		div = doc.createElement('div');

		div.style.position = 'absolute';
		
		if (doc.body)
			doc.body.appendChild(div);
		else
			doc.appendChild(div);
		
		var img = doc.createElement('img');
		div.appendChild(img);

		item = doc.createElement('nobr');
		item.id = 'statmsg';
		div.appendChild(item);
		item.img = img;
		
		SetCssClass(div, 'statmsg');
		
		if (IsIE() && doc.body)
		{
	        shim = CreateShim();
	        shim.style.position = 'absolute';
	        shim.style.top = -1;
	        shim.style.left = -1;
			shim.style.zIndex = -1;

			div.appendChild(shim);
			item.shim = shim;
		}
	}
	
	//--- Present msg in status div.
	
	if (item)
	{
		item.innerHTML = msg;
		item.style.visibility = '';
		
		item.img.src = src;
		item.img.style.display = (icon) ? '' : 'none';	// For sizing now

		div = item.parentNode;
		var w = div.offsetWidth;
		var h = div.offsetHeight;
		div.style.left = (WindowWidth(win) - w) / 2;
		div.style.top = (WindowHeight(win) - h) / 5;
		
		shim = item.shim;
		
		if (shim)
		{
			shim.style.height = h;
			shim.style.width = w;
		}
	}
	
	//--- Lock invoking button if so requested.
	
	if (item && lock && btn)
	{
		SetCssClass(btn, 'disimgx');
		window.setTimeout(function() { btn.disabled = true; }, 1);
		//window.setTimeout(function() { doc.body.disabled = true; }, 1);
	}

	//--- Blink if so requested.
	
	if (item && blink)
	{
		SetBlinker(item);
	}
	
	//--- Progress icon if so requested.
		
	if (item)
	{
		win.setTimeout(function() 
			{ 
				item.img.src = src;								// For Safari
				item.img.style.display = (icon) ? '' : 'none';	// For all but IE
			}, 1);
	}
	
	//--- Fade out the page contents.
	
	if (fade)
	{
		//--- Find highest parent div.

		var c = btn;
		var d = null;
		
		while (c && c != c.parentNode)
		{
			if (ElementType(c) == 'div') d = c;
			c = c.parentNode;
		}

		//--- Fade out div.

		if (d)
		{
			if (IsIE())
			{
				var ii;
				
				for (ii=0; ii<d.childNodes.length; ii++)
				{
					SetOpacity(d.childNodes[ii], 50);
				}
			}
			else
			{
				SetOpacity(d, 50);
			}
		}
	}
}

//---------------------------------------------------------------------------------------------------------------
function OpenWithStatusText(url, features, txt)
{
	var win = open('blank.htm', '_blank', features);
	var doc = win.document;
	
	doc.writeln('<head>');
	doc.writeln('<link rel="stylesheet" href="' + cssFile + '" />');
	if (txt) doc.writeln('<title>' + txt + '</title>');
	doc.writeln('</head>');
	
	doc.writeln('<body>');
	if (txt)
	{
		doc.writeln('<table align="center" style="height: 60%;"><tr><td>');
		doc.writeln('<div class="statmsg" xstyle="margin: auto; text-align: center;">');
		doc.writeln('<img src="images/AniProg.gif" /><nobr>' + txt + '</nobr>');
		doc.writeln('</div>');
		doc.writeln('</td></tr></table>');
	}
	doc.writeln('</body>');
	doc.writeln('</html>');
	doc.close();

	win.setTimeout(function() { doc.location = url; }, 50);
}

//---------------------------------------------------------------------------------------------------------------
function FindContentFrame(win)
{
	var f = findFrame('content', win);
	
	if (!f && win.parent != win)
	{
		f = FindContentFrame(win.parent);
	}
	
	return (f);
}

//---------------------------------------------------------------------------------------------------------------
// Breadcrumbs
//---------------------------------------------------------------------------------------------------------------

function CrumbSet(loc, flags)//, singleFrame)
{
    if (0 != (flags & 0x00000002))
    {
		//CrumbReg(window, flags);	// #4943 - SingleFrameMaster model.
    }
    else if (top.Crumbs && FindContentFrame(window) == window)
	{
		top.Crumbs(window, flags);	// MultiFrameMaster model.
	}
}

// Create breadcrumb object.
function breadcrumb(lnk, txt, win)
{
	this.href = lnk;
	this.text = txt;
	this.pg = lnk.match(/^[^?]*/)[0];					// Page only
	this.qps = new Object();
	
	var params = lnk.match(/[^?]*$/)[0].split('&');		// Params only
	var ii;
	var sig = '|';
	
	for (ii=0; ii<params.length; ii++)
	{
		if (params[ii])
		{
			var nmval = params[ii].split('=');
			
			if (nmval[0] != 'uts' &&					// #2228 - Ignore timestamp. 
				nmval[0] != 'act' &&					// #5263 - Ignore action.
			    nmval[0] != 'asf' && nmval[0] != 'ark') // #4376 - Ignore ActiveSubform and ActiveRowKey.
			{
				this.qps[nmval[0]] = nmval[1];
				sig += params[ii] + '|';
			}
		}
	}

	if (win && win.RegDebugInfo) win.RegDebugInfo('Signature', sig, 'Breadcrumb', 0);
	
	this.matches = function(crumb)
	{
		if (crumb.text != this.text) return (false);
		//if (crumb.pg != this.pg) return (false);		// #680 - Ignore page.
		
		for (var s in this.qps)
		{
			if (crumb.qps[s] != this.qps[s]) return (false);
		}
		
		return (true);
	};
}

// #4943 - Register crumb in SingleFrameMaster mode.
function CrumbReg(win, flags)
{
	var ctl = win.document.getElementById('crumb');
	
	if (ctl)
	{
		var params = '';
		
		params += 'lnk=' + encodeURIComponent(ctl.href);
		params += '&txt=' + encodeURIComponent(GetCellText(ctl));
		params += '&flags=' + flags;
		
		JsonReq('crumb', params, CrumbRsp);	// #4934 - Register this page & get history.
	}
}

// #4943 - Receive crumbs in SingleFrameMaster mode.
function CrumbRsp(rsp)
{
	var ii;
	var lnk;
	var txt;
	
	//--- Array of breadcrumbs, created if none.
	
	var crumbs = CrumbsGet();
	
	//--- Populate arry from response with arbitrary limit of 20.
	
	for (ii=0; ii<rsp.lnks.length && ii<20; ii++)
	{
	    //--- BugzID: 4633 add action
		var lnk = UpsertUrl(rsp.lnks[ii], 'act', 'crm' + ii);
		var txt = rsp.txts[ii];
		
		if (!lnk || !txt) break;
		
		crumbs.push(new breadcrumb(lnk, txt));
	}
	
	//--- Apply crumbs to page.
	
	CrumbsApply(window, 0);
}


// Gets breadcrumbs, creates if none.
function CrumbsGet()
{
	if (!window.breadcrumbs2) window.breadcrumbs2 = new Array();
	return (window.breadcrumbs2);
}

// Apply crumbs to page.  Designed to work with SingleFrameMaster or (when called from main.htm) MultiFrameMaster.
function CrumbsApply(win, flags)
{
	//--- Array of breadcrumbs, created if none.
	
	var crumbs = CrumbsGet();
	
	//--- Truncate crumb array if so specified.
	
	if (flags & 0x00000001)
	{
		crumbs.length = 0;
	}

	//--- If pg participates in breadcrumbs, update now.
	
	var ctl = win.document.getElementById('crumb');
	
	if (ctl)
	{
		var crumb = new breadcrumb(ctl.href, GetCellText(ctl), win);
		var ii;
		
		//--- Prune.
		
		for (ii=0; ii<crumbs.length; ii++)
		{
			if (crumb.matches(crumbs[ii]))
			{
				crumbs.length = ii;
				break;
			}
		}
		
		//--- Apply to caption.
		
		for (ii=0; ii<crumbs.length; ii++)
		{
			CrumbAddToCap(win, crumbs[ii], ii);
		}

		crumbs.push(crumb);
	}
}
		
// Add crumb to caption.
function CrumbAddToCap(win, crumb, indx)
{
	var link = win.document.createElement('a');
	var cap = win.document.getElementById('pageCaption');
	
	if (cap && crumb.href && crumb.text)
	{
	    //--- BugzID: 4633 - add action
		link.href = UpsertUrl(crumb.href, 'act', 'crm' + indx);
		SetCellText(link, crumb.text);
		
		cap.parentNode.insertBefore(link, cap);
		
		var sep = win.document.createElement('img');
		
		sep.src = 'images/CapSep.gif';
		cap.parentNode.insertBefore(sep, cap);
		SetCssClass(sep, 'capsep');
	}
}


//---------------------------------------------------------------------------------------------------------------
// Contents from EAPDatasheet.js merged. #665
//---------------------------------------------------------------------------------------------------------------

window.EAPDatasheetJSVer = 1;

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ClearFBF(evt, btn)
{
	if (btn)
	{
		var node = FindParent(btn, 'tr');
		
		if (node) ClearNode(node);	// Clear nodes belonging to the FBF row.
	}
}


//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function SelectAll(masterSel, sels)	// #4947
{
	var	items = (sels) ? sels : document.getElementsByTagName('input');
	
	for (var ii=0; ii<items.length; ii++)
	{
		var e = GetElement(items[ii]);
		var tag = e.type.toLowerCase();
		
		if (sels || (tag == 'checkbox' && e.name.indexOf('_sel_') == 0))
		{
			e.checked = masterSel.checked;
		}
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function SelectCount()
{
	var count = 0;
	var	items = document.getElementsByTagName('input');
	
	for (var ii=0; ii<items.length; ii++)
	{
		var e = items[ii];
		var tag = e.type.toLowerCase();

		if (tag == 'checkbox' && e.name.indexOf('_sel_') == 0)
		{
			if (e.checked) count++;
		}
	}

	return (count);
}


//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FilterWidget(path, mapper, fld, height, width)
{
	var	sPath;
	var sName = event.srcElement.name;
	
	sName = sName.substring(0,sName.length-3) + "txt";
	
	var sVal = event.srcElement.parentElement.parentElement.all[sName].value;

	sPath = path + "/Handler.ashx?req=fw&dm=" + mapper + "&fld=" + fld + '&nm=' + sName + '&val=' + sVal;
	
//	parent.window.open(sPath, '_blank', 'toolbar=no,scrollbars=no,resizable=yes,width=' + width + ',height=' + height + ',left=' + (screen.width - width)/2 + ',top=' + (screen.height - height)/2); 
	window.open(sPath, '_blank', 'toolbar=no,scrollbars=no,resizable=yes,width=' + width + ',height=' + height + ',left=' + (screen.width - width)/2 + ',top=' + (screen.height - height)/2); 
	
	//void(0);
	
	event.returnValue = false;
	event.cancelBubble = true;
}


//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function InitButton(btn, fltr)
{
	//btn.style.filter = fltr;
	//btn.oldFilter = fltr;
	//btn.onmouseover = UnfilterButton;
	//btn.onmouseout = FilterButton;
//d	btn.btnFlt = fltr;
//d	btn.onmousedown = LivenButton;
//d	btn.onmouseup = DeadenButton;
//d	btn.onmouseout = DeadenButton;
	//btn.onmouseenter = BlinkButton;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function BlinkButton()
{
	if (IsIE())
	{
		window.event.srcElement.style.filter = window.event.srcElement.btnFlt; //'xray';
		//window.setTimeout('UnblinkButton(\'' + window.event.srcElement.id + '\');', 200);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function UnblinkButton(id)
{
	if (IsIE())
	{
		var btn = document.getElementById(id);
		if (btn) btn.style.filter = '';
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FilterButton()
{
	if (IsIE())
	{
		window.event.srcElement.style.filter = window.event.srcElement.oldFilter;
			//window.event.srcElement.style.top += 1;
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function UnfilterButton()
{
	if (IsIE())
	{
		window.event.srcElement.oldFilter = window.event.srcElement.style.filter;
		window.event.srcElement.style.filter = '';
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function LivenButton()
{
	if (IsIE())
	{
	//	window.event.srcElement.style.top -= 1;
	//	window.event.srcElement.border = '1';
	//	window.event.srcElement.style.filter = "progid:DXImageTransform.Microsoft.DropShadow(offX=1,offY=1);"
		window.event.srcElement.style.filter = window.event.srcElement.btnFlt; //'xray';
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function DeadenButton()
{
	if (IsIE())
	{
	//	window.event.srcElement.style.top += 1;
		window.event.srcElement.style.filter = '';
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function resizeItem(id, height)
{
	var ctl = document.getElementById(id);
	
	ctl.style.height = height;
}


//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function hsplitInit(hspid, hsplitpos, panel, pref)
{
	var hsp = document.getElementById(hspid);
	var pos = document.getElementById(hsplitpos);
	var p = document.getElementById(panel);
	
	if (p == null)
	{
		ThrowError(2001, 'EAPDatasheet::hsplitInit', "HorizontalSplitter AssociatedControlID '" + panel + "' not found on page.");
	}
	
	hsp.resizePanel = p;		// The panel we're resizing
	
	hsp.pref = pref;
	
	//--- Handle four cases of hsplit top panel sizing...
	//--- 1) The size of the top panel is specified, use it,
	//--- 2) else, we're in the middle of resizing window to fit contents, don't set height,
	//--- 3) else, we have room for top panel and at least a minimum amount of bottom, don't set height,
	//--- 4) else, we don't have enough room for entire top without pushing bottom panel out of
	//---		view, so limit top panel to 60% of window height.
	//--- Note that if we DON'T set the top panel height here, the browser will size it per
	//--- its contents and the hsplit will naturally be positioned below it.
	
	var sizeMethod = 'none';
	
	if (pos.value)
	{
		p.style.height = pos.value;
		sizeMethod = 'known: ' + pos.value;
	}
	else if (window.sizingToFit)
	{
		sizeMethod = 'sizingToFit';
	}
	else
	{
		var clientHeight = GetClientHeight();
		var minSubHeight = screen.height / 4; //200; //80;
		
		if (minSubHeight < 80) minSubHeight = 80;
		
		if (clientHeight - minSubHeight < p.offsetHeight)
		{
			p.style.height = clientHeight * 0.6;
			sizeMethod = '60%';
		}
	}

	//--- In Safari track that vscroll is needed.

	if (IsSafari()) window.vScroll = true;	// #1415
	
	//alert(sizeMethod);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function hsplitResizeStart(evt, hsplit, panel, pos)
{
	if (!evt) evt = window.event;
	
	if (hsplit.resizePanel == null)
	{
		ThrowError(2002, 'EAPDatasheet::hsplitResizeStart', "HorizontalSplitter AssociatedControlID '" + panel + "' not found on page.");
	}
	
	hsplit.posHolder = document.getElementById(pos);			// The hidden positioning ctrl
	hsplit.panelOrigHeight = hsplit.resizePanel.offsetHeight;	// The original height of the panel
	hsplit.startY = evt.screenY;								// #1402
	window.hsplitter = hsplit;

	if (IsIE())
	{
		hsplit.onmousemove = hsplitOnResize;
		hsplit.onmouseup = hsplitOnResizeEnd;
		hsplit.setCapture();
	}
	else
	{
		if (document.body.addEventListener)
		{
			document.body.addEventListener('mousemove', hsplitOnResize, false);
			document.body.addEventListener('mouseup', hsplitOnResizeEnd, false);

			//--- Also need to capture mouse on this window's iframes (at least for Firefox).
			
			var ii;

			for (ii=0; ii<window.frames.length; ii++)
			{
				window.frames[ii].document.body.addEventListener('mousemove', hsplitOnResize, false);
				window.frames[ii].document.body.addEventListener('mouseup', hsplitOnResizeEnd, false);
			}
		}
	}

	CancelBubble(evt);	// Prevents text select on drag on Opera

	return false;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function hsplitOnResize(evt)
{
	if (!evt) evt = window.event;
	
	var hsplit = window.hsplitter;
	
	var nNewHeight = hsplit.panelOrigHeight + (evt.screenY - hsplit.startY);
	var nClientHeight = GetClientHeight();
	var minBottom = 80;
	
	//--- Don't let user resize too large.
	
	if (nNewHeight > nClientHeight - minBottom) nNewHeight = nClientHeight - minBottom;

	//--- Adjust top pane height.

	if (nNewHeight > 25 && nNewHeight < 100000)
	{
		hsplit.resizePanel.style.height = nNewHeight;
	}
	
	return CancelBubble(evt);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function hsplitOnResizeEnd(evt)
{
	var hsplit = window.hsplitter;
	
	//--- Force one last resize
	
	//hsplitOnResize(evt);
	
	//---

//	var nNewHeight = hsplit.panelOrigHeight + (evt.clientY - hsplit.startY);
//	
//	if (nNewHeight > 25 && nNewHeight < 100000)
//	{
//		hsplit.resizePanel.style.height = nNewHeight;
//		hsplit.posHolder.value = hsplit.resizePanel.offsetHeight; //hsplit.resizePanel.style.height;
//	}

	hsplit.posHolder.value = hsplit.resizePanel.offsetHeight; //hsplit.resizePanel.style.height;

	if (IsIE())
	{
		hsplit.onmousemove = null;
		hsplit.onmouseup = null;
		hsplit.releaseCapture();
	}
	else
	{
//		document.onmousemove = null;
//		document.onmouseup = null;
		if (document.body.removeEventListener)
		{
			document.body.removeEventListener('mousemove', hsplitOnResize, false);
			document.body.removeEventListener('mouseup', hsplitOnResizeEnd, false);
			
			//---
			
			var ii;

			for (ii=0; ii<window.frames.length; ii++)
			{
				window.frames[ii].document.body.removeEventListener('mousemove', hsplitOnResize, false);
				window.frames[ii].document.body.removeEventListener('mouseup', hsplitOnResizeEnd, false);
			}
		}
	}

	//--- Perform some post-split handling.
	
	hsplitPostSplit(hsplit);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function hsplitMinMax(evt, btn)
{
	var hsplit = window.hsplitter;
	
	if (!hsplit) hsplit = document.getElementById('hsplit');

	var bar = FindParent(btn, 'table');
	var barHeight = bar.offsetHeight;
	var minBottom = barHeight + 60;		// #1916
	var minHeight = 30;
	var nNewHeight = minHeight;
	var nClientHeight = GetClientHeight();
	
	window.status = barHeight;
	
	//--- If top pane is already minimized, maximize it.

	if (hsplit.resizePanel.offsetHeight < 50)
	{
		nNewHeight = nClientHeight - minBottom;
	}
	
	//--- Do the resize.
	
	if (nNewHeight > 25 && nNewHeight < 100000)
	{
		hsplit.resizePanel.style.height = nNewHeight;
		hsplitPostSplit(hsplit);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function hsplitPostSplit(hsplit)
{
	//--- Let the window know we've messed with stuff.
	
	if (window.resize) 
	{
		window.resize();
		//window.setTimeout('window.resize();', 1000);
		//window.status = 'resize';
	}
	else if (window.onresize) 
	{
		window.onresize();
		//window.setTimeout('window.onresize();', 1000);
		//window.status = 'onresize';
		//resizeContent();
	}
	
	//--- Persist new position.
	
	var conn = new XHConn();

	if (conn)
	{
		var pref = hsplit.pref;
		var h = hsplit.resizePanel.offsetHeight;

		if (pref)
		{	
			//var params = 'req=hspilt&mop=' + mop + '&h=' + h + '&ajaxdt' + Timestamp();
			var params = 'req=setprf&nm=' + pref + '&val=' + h + '&ajaxdt' + Timestamp();

			conn.getString('Handler.ashx', params, null);
		}
	}
}

//-----------------------------------------------------------------------------------------
// Purpose:	Used by lstArrow() to determine the target control.
// Remarks:	Expects a control id of the form <moniker>_<index>[_<subcontrol>]
// Example: "_ctl0_r1_spr_num" or composite control "_ctl0_r1_prod_nm_txt"
//-----------------------------------------------------------------------------------------
function lstTarget(fld, movement)
{
	var pattern = /(.+_r)(\d+)(_.*)$/;
	var arr = fld.id.replace(pattern, '$1@$2@$3').split('@');
	var target_id = arr[0] + (parseInt(arr[1],10) + movement) + arr[2];
	
	return document.getElementById(target_id);
}

//-----------------------------------------------------------------------------------------
// Purpose:	Used by MapperEditList to move vertically between cells.
//-----------------------------------------------------------------------------------------
function lstArrow(fld)
{
	var target = null;
	
	if (window.event.keyCode == 38) // uparrow
	{
		target = lstTarget(fld, -1);
	}
	else if (window.event.keyCode == 40) // downarrow
	{
		target = lstTarget(fld, 1);
	}
//	else if (window.event.keyCode == 37) // rightarrow
//	{
//	}
//	else if (window.event.keyCode == 39) // leftarrow
//	{
//	}

	if (target) target.focus();
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function InitFBFFocus(btn)
{
	var ii;
	var jj;
	var found = false;
	
	//--- Find FBF row.
	
	var tr = FindParent(btn.parentNode, 'tr');

	//--- Find first appropriate control in FBF and give it focus.
	
	for (ii=0; !found && ii<tr.cells.length; ii++)
	{
		var td = tr.cells[ii];
		
		for (jj=0; !found && jj<td.childNodes.length; jj++)
		{
			var item = td.childNodes[jj];
			
			if (CanGetFocus(item))
			{
				if (item.focus) item.focus();
				found = true;
			}
		}
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ImagePopup(img)
{
	//--- Determine target position.

	var posX = img.offsetLeft; // + 20; //event.x;
	var posY = img.offsetTop; //event.y;
	
	//--- Create the popup and save object on parent window for use elsewhere.
	
	var	pop = window.createPopup();
	var doc = pop.document;
	
	window.pop = pop;
	
	//--- Save the rectangle of the original image cell in parent.
	//--- This is used to detect when user moves out of original image.
	
	window.popTop = img.offsetTop;
	window.popLeft = img.offsetLeft;
	window.popBottom = img.offsetTop + img.parentElement.offsetHeight;
	window.popRight = img.offsetLeft + img.parentElement.offsetWidth;
	
	//--- Create the empty popup.
	
	doc.open();
	doc.writeln('<html>');
	
	doc.writeln('<head>');
	doc.writeln('<link rel="stylesheet" href="' + cssFile + '" />');
	// Do not add javascript file references.  These will cause IE to freeze.
	doc.writeln('</head>');
	
	doc.writeln('<body style="overflow:hidden;border:none;margin:0" onmouseleave="parent.ImageDelayedClose(event);" onmouseout="parent.ImageDelayedClose(event);" onmousemove="parent.ImageOnMove(event);">');
	doc.writeln('</body>');
	
	doc.writeln('</html>');
	doc.close();
	
	//--- Put the image in the popup.

	doc.body.innerHTML = '<img src="' + img.src + '" align="left" valign="top" />';

	//--- Show the popup.

	pop.show(posX, posY, 1, 1, document.body);
	pop.show(posX, posY, img.offsetWidth, img.offsetHeight, img);
	window.popX = posX;
	window.popY = posY;
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ImageDelayedClose()
{
	window.setTimeout('window.pop.hide();', 50);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ImageOnMove(e)
{
	//--- If user moved out of original image rectangle, close popup.
	
	if (e.x < window.popLeft-1 || e.x > window.popRight+1 || e.y < window.popTop-1 || e.y > window.popBottom+1)
	{
		window.pop.hide();
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function TryRowMove(evt)
{
	if (!evt) evt = window.event;
	
	var key = GetEventKey(evt);
	
	if (key == 38 || key == 40)		// uparrow or downarrow
	{
		var trId = window.last_tr.id;
		var sep = trId.lastIndexOf('_');
		var base = trId.substr(0,sep);
		var row = parseInt(trId.substr(sep+2),10);
		
		if (key == 40)				// downarrow
			row += 1;
		else if (key == 38)			// uparrow
			row -= 1;

		var newTrId = base + '_' + 'r' + (row);
		var tr = document.getElementById(newTrId);
		
		//--- #2567 - Handle case where target row is scrolled out of view.
		
		var pardiv = FindParent(tr, 'div');
		var scrolldiv = FindParent(pardiv, 'div');
		
		if (pardiv && scrolldiv)
		{
			if (getTop(tr) < getTop(pardiv) + scrolldiv.scrollTop + tr.offsetHeight)//15)
			{
				scrolldiv.scrollTop -= tr.offsetHeight;
			}
			else if (getTop(tr) + tr.offsetHeight > getTop(scrolldiv) + scrolldiv.offsetHeight + scrolldiv.scrollTop - tr.offsetHeight)//15)
			{
				scrolldiv.scrollTop += tr.offsetHeight;
			}
		}

		//--- Select the row.
		
		if (tr)
		{
			tr.withDelay = 400;
			DoClick(tr);
		}
		
		//--- Prevent normal scroll.
		
		CancelBubble(evt);
		return (false);
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function RowSel(trIn, rowKey, rowDigest, checkRow, rowDesc, gridPre)
{
	tr = GetElement(trIn);
	if (window.last_tr) RemoveCssClass(window.last_tr, 'rowcur');
	ReplaceCssClass(tr, '', 'rowcur');
	
	window.initSF = true;
	
	//--- Handle up/down arrow row movement - #2567 - All browsers.
	
	if (!tr.trm)
	{
		if (IsAppleWebKit())//IsSafari())
			AddListener(document, 'keydown', function() { var item = GetEventTarget(event); if (item && ElementType(item) == 'body') TryRowMove(event); });
		else if (IsOpera())
			AddListener(tr, 'keypress', TryRowMove);
		else
			AddListener(tr, 'keydown', TryRowMove);
		tr.trm = true;
	}
	
	//--- Set up current row.
	
	window.rowKey = rowKey;
	window.rowDesc = rowDesc;
	window.rowDigest = rowDigest;
	window.last_tr = tr;
	
	//--- #3778 - Track active RowKey.
	
	var ark = document.getElementById(gridPre + 'ark');
	
	if (ark) ark.value = rowKey;
	
	//--- Subform requery w/ possible delay.
	
	if (window.NewRow)
	{
		if (window.subTimer)
		{
			window.clearTimeout(window.subTimer);
			window.subTimer = 0;
		}
		
		if (tr.withDelay)
		{
			window.subTimer = window.setTimeout(function() { NewRow(rowKey, rowDigest); window.subTimer = 0; }, tr.withDelay);
			tr.withDelay = 0;
		}
		else
		{
			NewRow(rowKey, rowDigest);
		}
		
		if (window.EnableSubTabs) window.EnableSubTabs(tr);		// #681
	}
	
	if (checkRow)
	{
		SelectAll(false);
		
		var chk = document.getElementById('_sel_' + rowKey);
		if (chk)
		{
			chk.checked = true;
		}
	}
}

//-----------------------------------------------------------------------------------------
// Purpose:	Handle event to initiate cell editing in a datasheet.
//-----------------------------------------------------------------------------------------
function ListEdit(evt, cell, discrim)
{
	var oldEditor = GetEventTarget(evt);
	
	cell.discrim = discrim;
	ListEditStart(cell, oldEditor);
		
	//--- Don't let click bubble up.
	
	if (evt) CancelBubble(evt);
}

//-----------------------------------------------------------------------------------------
// Purpose:	Initiate cell editing in a datasheet.
// #3919 - Modified to be callable outside event.
// #4236 - Duration localization.
//-----------------------------------------------------------------------------------------
function ListEditStart(cell, oldEditor)
{
	//--- Find the edit div.
	
	var key = cell.getAttribute('editkey');					// #5068 - Get key from cell.
	var div = document.getElementById('divedit_' + key);
	var editor = document.getElementById('edit_' + key);
	
	if (!editor) editor = document.getElementById('edit_' + key + '_tbl');	// #1711
	
	if (div && editor)
	{
		editor.key = key;
	
	    var tr = FindParent(cell, 'tr');
		var ctrlType = ElementType(editor);
		var isTextbox = (ctrlType == 'text') || (ctrlType == 'textarea');	// #2813
		var isSelect = (ctrlType == 'select');
		var isCheckbox = (ctrlType == 'checkbox');
		var isDuration = (ctrlType == 'span' && editor.getAttribute('use') == 'dur');
		var isTimePick = (ctrlType == 'table' && editor.getAttribute('use') == 'time');	// #1711
		var isRadio = (ctrlType == 'table' && editor.getAttribute('use') == 'radio');	// #3436
		var isDatePick = (false && ctrlType == 'table' && editor.getAttribute('use') == 'bndlkup');	// #5565
		
		SetCssClass(editor, GetCssClass(cell));	// Set class before making visible!
		
		var top = getTop(cell);				// #5688, not editor-relative
		var left = getLeft(cell);			// #5688, not editor-relative
		var height = cell.offsetHeight;
		var width = cell.offsetWidth;
		
		//--- Browser-specific control position tweaks determined by 
		//--- trial and error.
				
		if (IsIE())
		{
			if (isTextbox)
			{
				top -= 1;
				editor.style.paddingTop = '1px'; //'4px';
				height -= 1;
			}
			else if (isSelect)
			{
				null;	// Nothing, for now.
			}
			else if (isCheckbox)
			{
				//--- #5688 - Special checkbox positioning below.
			}
		}
		else if (IsFirefox())
		{
			if (isTextbox)
			{
				top -= 1;
				left -= 1;
				height += 1;
				width += 1;
				editor.style.paddingTop = '3px';
				editor.style.paddingLeft = '1px';
			}
			else if (isSelect || isDuration)
			{
				top -= 1;
				height -= 2; //1;
				left -= 1;
				//width += 1;
				if (!isDuration) editor.style.paddingTop = '1px';
			}
			else if (isCheckbox)
			{
				//--- #5688 - Special checkbox positioning below.
			}
		}
		else if (IsSafari())
		{
			if (isCheckbox)
			{
				//--- #5688 - Special checkbox positioning below.
			}
			else if (!IsSafariPre5() || !isSelect)
			{
				if (tr) top = getTop(tr);	// #5688, not editor-relative
				width += 1;
			}
		}
		else if (IsChrome())
		{
			if (isCheckbox)
			{
				//--- #5688 - Special checkbox positioning below.
			}
			else
			{
                if (tr) top = getTop(tr);	// #5688, not editor-relative
			}
		}
		else if (IsOpera())
		{
			div.style.paddingTop = '1px';
			if (isCheckbox)
			{
				//--- #5688 - Special checkbox positioning below.
			}
			else
			{
				left -= 1;
				top -= 1;
				if (!isDuration) 
				{
					height += 2;
				}
				width += 3;
			}
		}

		//--- Position the div over the cell and make it visible.
		
		div.style.visibility = 'hidden';
		div.style.display = 'block';

		div.style.top = top + 'px';
		div.style.left = left + 'px';
		div.style.height = height + 'px';
		div.style.width = width + 'px';
		
		div.style.visibility = 'visible';

		//--- Initialize the value of the edit control from the cell.
		
		var itemId = cell.id;

		if (isTextbox) 
		{
			editor.value = GetCellText(cell);
			cell.editedClass = 'editedlist';
			editor.setAttribute('autoComplete', 'off');	// Firefox (see https://bugzilla.mozilla.org/show_bug.cgi?id=236791)
		}
		else if (isCheckbox)
		{
			var chk = cell.childNodes[0].childNodes[0];

			itemId = chk.id;	// #2042
			if (!chk.origStateSaved)
			{
				var tagName = ElementType(oldEditor);

				//--- If user clicked directly on checkbox it will have changed
				//--- state by time we get this event, so compensate.  If user
				//--- clicked on TD instead, checkbox will still be in original state.
	
				chk.origState = (tagName == 'checkbox') ? !chk.checked : chk.checked;
				chk.origStateSaved = true;
			}
			
			//--- #5688 - Position just checkbox, not entire div, over existing checkbox.
			
			left = getLeft(chk) - getLeft(div);
			top = getTop(chk) - getTop(div);

			if (IsIE())
			{
				ReplaceCssClass(editor, 'xxx', 'ieeditchk');
			}
			else if (!IsOpera())
			{
				left -= 4;
				top -= 3;
			}

			editor.style.position = 'absolute';
			editor.style.top = top + 'px';
			editor.style.left = left + 'px';

			//---
			
			editor.checked = chk.checked;
			cell.editedClass = GetCssClass(cell);
		}
		else if (isSelect)
		{
			cell.editedClass = 'editedlist';

			var s = Trim(GetCellText(cell), false, true); // Option will have trimmed trailing spaces!
			
			//--- Vertically center select.
			
			if (IsIE() || IsFirefox())
			{
				editor.style.height = '';
				editor.style.position = 'relative';
				editor.style.top = ((height - editor.offsetHeight) / 2) + 'px';
			}

			//--- Populate select.

			editor.selectedIndex = null;	// Assume no match
			
			if (cell.discrim)
			{
				Discrim(editor.getAttribute('pickid'), cell.discrim, editor, function(rsp) { ListDiscrim(rsp, editor, s); } );	// #5015, AJAX discrim handling.
			}
			else
			{
				SetSelectText(editor, s);	// No discrim
			}
		}
		else if (isDuration)
		{
			SetFocusFirst(editor);
			
			var s = Trim(GetCellText(cell), false, true); // Option will have trimmed trailing spaces!
			var hrLst = editor.firstChild;
			var minLst = editor.firstChild.nextSibling;
			
			if (s == null || s == '')
			{
				hrLst.value = '';
				minLst.value = '';
			}
			else
			{
			    var loc = editor.getAttribute('loc');        // #4236
				var f = StringToFloat(s, loc);
				var hrs = Math.floor(f);
				var mins = f - hrs;

				hrLst.value = Math.floor(f);
				
				var minDiff = 100;
				var minIndex = -1;
				
				for (var ii=0; ii<minLst.options.length; ii++)
				{
					var dif = Math.abs(mins - parseInt(minLst.options[ii].value)/60);
					
					if (dif < minDiff)
					{
						minDiff = dif;
						minIndex = ii;
					}
				}
				
				if (minIndex >= 0) minLst.options[minIndex].selected = true;
			}
			
			SetupListEditEnd(editor, cell);
		}
		else if (isTimePick)	// #1711
		{
			SetFocusFirst(editor);
			
			var s = Trim(GetCellText(cell), false, true); // Option will have trimmed trailing spaces!
			var hrLst = document.getElementById(editor.id.replace(/_tbl$/, '_hr'));
			var minLst = document.getElementById(editor.id.replace(/_tbl$/, '_min'));
			
			if (s == null || s == '')
			{
				hrLst.value = '';
				minLst.value = '';
			}
			else
			{
				var parts = s.split(':');
				
				if (parts.length >= 2)
				{
					SetSelectText(hrLst, parts[0]);
					SetSelectText(minLst, parts[1]);
				}
			}

			SetupListEditEnd(editor, cell);
		}
		else if (isRadio)	// #3436
		{
			RadioSetByText(editor, GetCellText(cell));
			SetupListEditEnd(editor, cell, true);
		}
		else if (isDatePick)	// #5565
		{
			var txt = GetElement(editor.id.replace(/_tbl$/, '_txt'));
			
			if (false && !txt.cell)
			{
				txt.onchange = function() { InnerTextSet(this.cell, this.value); }
			}
			txt.cell = cell;

			txt.value = GetCellText(cell);
//			SetupListEditEnd(editor, cell, false); //true); //false);
			SetupListEditEnd(txt, cell, false); //true); //false);
		}

		//--- Perform per-row setup.
		
		CopyAttr(cell, editor, 'loc');		// #5516 - Full locale spec (replaces #1235 code).
		
		//--- On first use, set up the onblur and onkeydown events.
		
		if (!editor.init)
		{ 
			editor.init = true;
			AddListener(editor, 'keydown', ListKeyDown);
		}

		AddListener(editor, 'blur', ListEditDone);	// #3919 - Add & clear every time.

		if (document.body.addEventListener)
		{
			document.body.addEventListener('scroll', ListEditDone, false);
		}

		if (window.listEditor)
		{
			ListEditDone(null);
		}
		
		window.listEditor = editor; 
		
		//--- Point edit control to current cell and give it focus (and select the text).
					
		editor.cell = cell;
		editor.itemId = itemId;
		editor.key = key;
		editor.div = div;
		
		if (editor.focus && !isDuration) editor.focus();
		if (isTextbox)
		{
			if (editor.select) 
				editor.select();
		}
	}
}

// Copy specified attribute, if present from source element to target element.
function CopyAttr(src, tgt, attr)	// #5516
{
	if (src.getAttribute(attr))
	{
		tgt.setAttribute(attr, src.getAttribute(attr));
	}
}

// #5105 - Handle EditInList discrim handling response.
function ListDiscrim(rsp, cbo, s)
{
	ClearSelect(cbo);			// Clear old items.
	DiscrimReturned(rsp, s);	// Apply AJAX picklist.
}

//-----------------------------------------------------------------------------------------
// #1711 - Set up composite control for ListEditDone() handling.
// #3919 - Modified to be callable outside event.
function SetupListEditEnd(editor, cell, onclick)
{
	if (document.fn) RemoveListener(document, 'focus', document.fn);
	if (document.fno) RemoveListener(document, 'mousedown', document.fno);

	var fn = function(evt) 
	{
		if (!evt) evt = window.event;
		
		if (!window.IsParentOf(GetEventTarget(evt), editor))
		{ 
			RemoveListener(document, 'focus', document.fn);
			document.fn = null; 
			if (document.fno)
			{
				RemoveListener(document, 'mousedown', document.fno);
				document.fno = null; 
			}
			
			ListEditDone2(editor, cell, false, true);
		} 
	};
	document.fn = fn;
	AddListener(document, 'focus', fn);
	if (IsOpera() || IsAppleWebKit()) 
	{
		document.fno = fn;
		AddListener(document, 'mousedown', fn);
	}
	
	// #3436 - If click ends edit.
	
	if (onclick && !editor.fnc)
	{
		editor.fnc = true;
		AddListener(editor, 'click', function() { ListEditDone2(editor, cell, false, true); } );
	}
}

//-----------------------------------------------------------------------------------------
// Purpose:	When editing in the datasheet, handle some special keys.
//-----------------------------------------------------------------------------------------
function ListKeyDown(evt)
{
	if (!evt) evt = window.event;
	
	var key = evt.keyCode;
	var shift = evt.shiftKey;

	//--- #2525 - Handle shift-tab and other non-standard chars to prevent older Safari browsers from crashing!

	if (evt.keyCode == 0)
	{
		if (evt.charCode == 25)
		{
			key = 9;
		}
		else if (IsSafariPre5())
		{
			return CancelBubble(evt);	// Ouch! If we don't do this Safari might crash!
		}
	}
	
	//--- Handle special chars that affect editing.
	
	var editor = GetEventTarget(evt);
	var autoSuggest = (editor && editor.menu && IsVisible(editor.menu));	// #4728 - AutoSuggest in use.
	
	if (key == 13)			// <cr> means finish editing the cell.
	{
		if (autoSuggest) { return false; }	// #4728 - AutoSuggest in use.
		
		OnBlur(editor);
		
		return CancelBubble(evt);
	}
	else if (key == 27)		// <esc> means cancel.
	{
		if (!autoSuggest) ListEditDone(null, true);

		return false;
	}
	else if (key == 40 ||	// <downarrow>
		key == 38 ||		// <uparrow>
		key == 9)			// <tab>
	{
		if (autoSuggest) return false;

		//--- An uparrow or downarrow means to store the current edit value, move to the previous 
		//--- or next cell in the column and edit it.
		
		var newCell = null;
		
		//--- Try to find control on next/prev row based on control name.
		//--- This is fast, but assumes td's are named like <grid>_r<row>_<key>,
		//--- e.g. the_list_r5_price.
		
		var right = 0;
		var down = 0;
		
		if (key == 9)
			right = (shift) ? -1 : 1;		// shift-tab/tab
		else
			down = (key == 38) ? -1 : 1;	// downarrow/uparrow
		
		if (editor && editor.cell)
		{
			var newId = ListMove(editor.itemId, editor.key, right, down);

			if (newId) 
			{
				newCell = document.getElementById(newId);
				if (newCell && ElementType(newCell) != 'td') newCell = FindParent(newCell, 'td');	// #2042
			}
		}
		
		//--- Handle case where cell to edit is scrolled out of view.
		
		if (!newCell || !IsVisible(newCell)) 
			newCell = null;
		else
		{
			var pardiv = FindParent(newCell, 'div');
			var scrolldiv = FindParent(pardiv, 'div');
			
			if (pardiv && scrolldiv)
			{
				if (getTop(newCell) < getTop(pardiv) + scrolldiv.scrollTop + 15)
				{
					scrolldiv.scrollTop -= newCell.offsetHeight;
				}
				else if (getTop(newCell) + newCell.offsetHeight > getTop(scrolldiv) + scrolldiv.offsetHeight + scrolldiv.scrollTop - 15)
				{
					scrolldiv.scrollTop += newCell.offsetHeight;
				}
			}
			else
			{
				window.status += '=';
			}
		}

		//--- If found, finish up here and move to new cell.
		
		if (newCell) 
		{ 
			ListEditDone(null);

			//--- Hack for Firefox.  It seems that Firefox ignores attempts to set 
			//--- focus or select text during a keydown event.
			//--- #3919 - Modified for similar requirement in Safari & Chrome.

			window.setTimeout(function() { ListEditStart(newCell, editor); }, 1);
				
			return CancelBubble(evt);
		}
	}
}

//-----------------------------------------------------------------------------------------
// Hack for Firefox.  It seems that Firefox ignores attempts to set focus or select text
// during a keydown event.
//-----------------------------------------------------------------------------------------
function SelectAndFocus(id)
{
	var ctrl = document.getElementById(id);
	
	if (ctrl)
	{
		if (ctrl.focus) ctrl.focus();
		if (ctrl.select) ctrl.select();
	}
}


//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function FindEditTarget(editor, down)
{
	var ctrl = null;

	//--- Look for prev/next row, same column.
	//--- Normally it should be named like 'top_list_grid_r2_role'	

	//window.status = 'txt.id=' + txt.id + ',';
	//window.status += 'txt.cell.id=' + txt.cell.id + ',';
	//window.status += 'txt.key=' + txt.key + ',';
	var tr = FindParent(editor.cell, 'tr');
	var tr_id = tr.id;
	var td_id = null;
	
	//window.status += 'tr_id=' + tr_id + ',';
	var numbers = tr_id.match(/\d+$/);
	
	if (numbers && numbers.length > 0)
	{
		var n = numbers[numbers.length-1];
		var nNew = (down) ? parseInt(n) + 1 : parseInt(n) - 1;
		
		td_id = StrReplace(tr_id, '_r' + n, '_r' + nNew) + '_' + editor.key;

		//window.status += 'td_id=' + td_id + ',';
	
		ctrl = document.getElementById(td_id);
	}
	
	return (ctrl);
}

//-----------------------------------------------------------------------------------------
// Purpose:	Complete the edit of a cell in the datasheet.
//-----------------------------------------------------------------------------------------
function ListEditDone(evt, cancel)
{
	if (!evt) evt = window.event;
	
	var editor = window.listEditor;
	
	if (evt && GetEventTarget(evt) == editor && evt.type == 'scroll')
	{
	    //--- #4357 - Ignore extraneous Chrome textarea scroll event.
	}
	else if (editor && editor.cell)
	{
		var cell = editor.cell;
		
		window.listEditor = null;

		RemoveListener(editor, 'blur', ListEditDone);	// #3919 - Add & clear every time.
	
		ListEditDone2(editor, cell, cancel, false);
	}
}

//-----------------------------------------------------------------------------------------
// Purpose:	Complete the edit of a cell in the datasheet.
//-----------------------------------------------------------------------------------------
function ListEditDone2(editor, cell, cancel, special)
{
	if (editor && cell)
	{
		var div = document.getElementById('div' + editor.id);
		var changed = false;
		var newVal;
		var newText;
		var s;
		
		if (!div) div = document.getElementById('div' + editor.id.replace(/_tbl$/,''));	// #1711

		//--- Per control type, copy the edited value from the edit control
		//--- to the cell and store the new value for posting back to the
		//--- server to be saved.
		
		var ctrlType = ElementType(editor);
		var isTextbox = (ctrlType == 'text' || ctrlType == 'textarea');	// #2813
		var isSelect = (ctrlType == 'select');
		var isCheckbox = (ctrlType == 'checkbox');
		var isDuration = (ctrlType == 'span' && editor.getAttribute('use') == 'dur');
		var isTimePick = (ctrlType == 'table' && editor.getAttribute('use') == 'time');	// #1711
		var isRadio = (ctrlType == 'table' && editor.getAttribute('use') == 'radio');	// #3436
		var isDatePick = (false && ctrlType == 'table' && editor.getAttribute('use') == 'bndlkup');	// #5565

		//--- Extract new value and determine if value changed.
		
		if (cancel)
		{
			if (document.fn) RemoveListener(document, 'focus', document.fn);		// #1239
			if (document.fno) RemoveListener(document, 'mousedown', document.fno);
			null;	// Abandon any changes.
		}
		else if (isTextbox)
		{
			s = GetCellText(cell);

			if (s != editor.value)
			{
				//--- Force formatting code to fire.
		
				OnChange(editor);
				changed = true;
				newVal = editor.value;
				
				newText = (newVal == null) ? '' : newVal;
			}
		}
		else if (isCheckbox)
		{
			var chk = (cell.childNodes.length > 0) ? cell.childNodes[0].childNodes[0] : cell;

			if (chk.origState != editor.checked || chk.changed)
			{
				changed = true;
				chk.changed = true;
				newVal = (editor.checked) ? "1" : "0";
			}

			chk.checked = editor.checked;
		}
		else if (isSelect)
		{
			s = GetCellText(cell);
			
			if (editor.selectedIndex >= 0 && s != editor.options[editor.selectedIndex].text)
			{
				changed = true;
				newVal = editor.options[editor.selectedIndex].value;
				newText = editor.options[editor.selectedIndex].text;
			}
		}
		else if (isDuration)
		{
			if (!special) return;
			
			var newVal = TimeDurationVal(editor);	// #599
			
			if (newVal != GetCellText(cell))
			{
				newText = newVal;
				changed = true;
			}
		}
		else if (isTimePick)
		{
			if (!special) return;
			
			var newVal = TimePickerVal(editor);		// #1711
			
			if (newVal != GetCellText(cell))
			{
				newText = newVal;
				changed = true;
			}
		}
		else if (isRadio)	// #3436
		{
			if (!special) return;
			
			newText = RadioButtonText(editor);

			if (newText != GetCellText(cell))
			{
				newVal = RadioButtonVal(editor);//newVal;
				changed = true;
			}
		}
		else if (isDatePick)	// #5565
		{
			var txt = GetElement(editor.id.replace(/_tbl$/, '_txt'));

			newVal = txt.value;

			if (newVal != GetCellText(cell))
			{
				newText = newVal;
				changed = true;
			}
		}
		
		//--- If anything changed, perform CalculatedValues calculations.

		if (changed)
		{
			var msg;
			
			//--- Validate the value if there's a validation function for the field.

			var fn = eval("window.validate_" + editor.key);

			if (fn)
			{
				msg = fn(cell, newText, true);	// #1160 -- Do full.
			}
			
			if (msg)	// Validation failed!
			{
				alert(msg);
			}
			else		// Validation succeeded, set value.
			{
				if (ctrlType != 'checkbox')
				{
					SetCellText(cell, newText);
				}
				ListEditStore(cell, div.getAttribute('key'), newVal);
				ListEditCalc(cell);
				window.isDirty = true;	// Currently hidden controls not check for dirtiness, so mark page dirty. #3892
			}
		}

		//--- If we're not moving to a new cell to edit, hide the edit control.

		if (div)
		{
			div.style.display = 'none';
		}
	}
}

//-----------------------------------------------------------------------------------------
// Purpose	Store a datasheet edit for posting back to the server to be saved.
//-----------------------------------------------------------------------------------------
function ListEditStore(cell, key, val)
{
	//--- Each row has ONE hidden field.  That field contains the name=value sets of edited
	//--- fields for the row.  That's what is posted back to the server.  The server will
	//--- decompose this and set fields accordingly.
	
	var tr = FindParent(cell, 'tr');
	var rowKey = tr.getAttribute('rowKey');
	var	store = document.getElementById('edit_' + rowKey);
	
	if (store)
	{
		//--- Save the name/value pair.
		
		store.value = SetString(store.value, key, val);
		
		//--- There's also ONE hidden control per datasheet identifying the RowKey's of the
		//--- edited rows.  Add this row's RowKey to it.
		
		var	edited = document.getElementById('edited_rowkeys');
		
		if (edited)
		{
			if (!edited.value) edited.value = ';';
			if (edited.value.indexOf(';' + rowKey + ';') < 0) edited.value += rowKey + ';';
			//SetCssClass(cell, cell.editedClass);
			ReplaceCssClass(cell, 'editlist', 'editedlist');
		}
	}
}

//-----------------------------------------------------------------------------------------
// Perform CalculatedValues calculations.  The RowCalc() method is generated by the mapper.
//-----------------------------------------------------------------------------------------
function ListEditCalc(cell)
{
	var	tr = ParentRow(cell);
	
	if (tr)
	{
		RowCalc(tr.id + '_');
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ParentRow(ctl)
{
	var c = ctl;
	
	while (c && ElementType(c) != 'tr')
	{
		c = c.parentNode;
	}
	
	return (c);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START sizer handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

function MouseX(evt)		// #5696
{
	var x = evt.clientX;
	
	if (document.body && document.body.scrollLeft) x += document.body.scrollLeft;
	
	return (x);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function SizerDrag(evt)
{
	if (!evt) evt = window.event;
	
	var div = window.resizingDiv;
	var td = div.td;
	var x = MouseX(evt);	// #5696
	
	div.style.left = x;

	var wid = x - getLeft(td);

	if (wid > 3) 
	{
		td.style.width = wid;
	}
	
	return CancelBubble(evt);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function SizerDragEnd(evt)
{
	if (!evt) evt = window.event;
	
	var bar = window.resizingDiv;
	
	//--- Remove listeners and release the mouse.
	
	DragTerm(bar, SizerDrag, SizerDragEnd);

	//--- Hide the resizer.
	
	bar.style.display = 'none';
	bar.td.style.cursor = '';
	
	//--- AJAX request to persist new col width.
	
	var conn = new XHConn();

	if (conn)
	{
		var fld = bar.td.getAttribute('key');
		var map = bar.td.map;
		var params = 'req=colsz&map=' + map + '&fld=' + fld + '&wid=' + bar.td.offsetWidth + '&ajaxdt' + Timestamp();
		
		if (bar.td.purp) params += '&purp=' + bar.td.purp;	// #4538

		conn.getString('Handler.ashx', params, null);
	}
	
	return CancelBubble(evt);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function SizerInit(evt)
{
	if (!evt) evt = window.event;
	
	var td = (evt.srcElement) ? evt.srcElement : evt.target;

	//--- If event occurs over the column resizer area...

	if (td.style.cursor != '')
	{
		var bar = document.getElementById('resizer');

		//--- Position the resizing bar over the column separator.
		
		if (bar)
		{
			bar.style.display = '';
			bar.style.left = getLeft(td) + td.offsetWidth;
			bar.style.top = getTop(td);
			bar.style.height = td.offsetHeight;
			bar.td = td;
			bar.setAttribute('key', td.getAttribute('key'));
			
			window.resizingDiv = bar;
			
			//--- Add listeners to appropriate events and capture the mouse.

			DragInit(bar, SizerDrag, SizerDragEnd);
			
			return CancelBubble(evt);
		}
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function SizerTrack(evt, td, key)
{
	//--- Initialize the TD for resizing.
	
	if (!td.getAttribute('sizerSetup'))
	{
		td.onmousedown = SizerInit;
		//td.setAttribute('key', key);
		td.setAttribute('sizerSetup', 1);
		
		var tbl = FindParent(td, 'table');
		
		if (tbl)
		{
			td.map = tbl.getAttribute('map');
			td.purp = tbl.getAttribute('purp');	// #4538
		}
	}
	
	//--- If mouse is over the resizing area, use resize cursor, else default.
	
	var x = MouseX(evt);	// #5696
	
	if (x > (getLeft(td) + td.offsetWidth) - 7 &&
		x <= getLeft(td) + td.offsetWidth)
	{
		if (td.style.cursor == '') td.style.cursor = 'w-resize';// 'col-resize';
	}
	else
	{
		if (td.style.cursor != '') td.style.cursor = '';
	}
	
	return CancelBubble(evt);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END sizer handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function ListMove(id, key, right, down)
{
	var target = null;
	var n = id.lastIndexOf('_' + key);

	if (n > 0)
	{
		var keys = listkeys;	// From a global var set up by datasheet.
		var rows = listrows;	// From a global var set up by datasheet.
		
		var tr = id.substring(0, n);
		n = tr.lastIndexOf('_');
		var prefix = tr.substring(0, n);
		var row = tr.substring(n+1);
		var iKey = ArrayIndexOf(keys, key);
		var iRow = ArrayIndexOf(rows, row);
		
		if (iKey >= 0 && iRow >= 0)
		{
			//--- #2525 - Calc target cell.
			
			if (right)
			{
				iKey += right;
				
				if (iKey < 0)
				{
					iRow--;
					iKey = keys.length - 1;
					if (iRow < 0) iRow = rows.length - 1;
				}
				else if (iKey >= keys.length)
				{
					iRow++;
					iKey = 0;
					if (iRow >= rows.length) iRow = 0;
				}
			}
			else if (down)
			{
				iRow += down;
				
				if (iRow < 0)
					iRow = 0;
				else if (iRow >= rows.length)
					iRow = rows.length -1;
			}

			//--- #2525 - Should NEVER happen, but prevents Safari Mac crash if it DOES.
			
			if (iKey >= keys.length)
				{ alert('key too big'); return null; }
			else if (iKey < 0)
				{ alert('key neg'); return null; }
			else if (iRow >= rows.length)
				{ alert('row too big'); return null; }
			else if (iRow >= rows.length)
				{ alert('row neg'); return null; }
				
			key = keys[iKey];
			row = rows[iRow];
			target = prefix + '_' + row + '_' + key;
		}
	}

	return (target);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetDatasheetSibling(fld, fieldId)
{
	var sibling = null;
	var tr = FindParent(fld, 'tr');
	var id = tr.id + '_' + fieldId;
	
	sibling = document.getElementById(id);
	
	return (sibling);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function GetDatasheetSiblingValue(fld, fieldId)
{
	var val = null;
	var sibling = GetDatasheetSibling(fld, fieldId);
	
	if (sibling) val = GetCellText(sibling);
	
	return (val);
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function DatasheetFillDown(gridId)
{
	var fbfId = gridId + '_fbf';

	var kk;
	var rr;
	
	//--- For each editable column...
	
	for (kk=0; kk<listkeys.length; kk++)
	{
		var key = listkeys[kk];
		var fbf = GetElement(fbfId + '_fbf_' + key);
		
		if (!fbf) fbf = GetElement(fbfId + '_fbf_' + key + '_txt');		// #5896 - BndLkup
		
		if (!fbf)
		{
			alert('No FBF row called ' + fbfId + '_fbf_' + key);
		}

		var val = fbf.value;
		
		//--- If there's a value to propagate...
		
		if (val && val != '')
		{
			var fnValidator = eval('window.validate_' + key);
			var editor = document.getElementById('edit_' + key);
			var editorType = ElementType(editor);
			var msg = null;
			
			//--- For each row...
			
			for (rr=0; rr<listrows.length; rr++)
			{
				var row = listrows[rr];
				var cell = document.getElementById(gridId + '_' + row + '_' + key);

				//--- If this column has a validator, validate the value.
				
				if (fnValidator) msg = fnValidator(cell, val);

				//--- If no validation error, set the value.
				
				if (!msg)
				{
					window.listEditor = editor;
					editor.cell = cell;

					if (editorType == 'text')
					{
						editor.value = val;
						ListEditDone(null, false);
					}
					else if (editorType == 'select')
					{
						var ii;
						
						val = val.toLowerCase();	// Case-insensitive
			
						//--- Find the value matching the fill text...
						
						for (ii=0; ii<editor.options.length; ii++)
						{
							if (editor.options[ii].text.toLowerCase() == val)
							{
								editor.selectedIndex = ii;
								ListEditDone(null, false);
								break;
							}
						}
					}
					else if (editorType == 'checkbox')
					{
						//editor.checked = fbf.checked;
						if (fbf.value == '1')
							editor.checked = true;
						else if (fbf.value = '0')
							editor.checked = false;
						ListEditDone(null, false);
					}
				}
			}
		}
	}

	//--- Perform the RowCalc for each row.
	
//	for (rr=0; rr<listrows.length; rr++)
//	{
//		var row = listrows[rr];
//		
//		RowCalc(gridId + '_' + row + '_');			
//	}

//	evt.cancelBubble = true;
//	if (evt.stopPropagation) evt.stopPropagation();
}

//-----------------------------------------------------------------------------------------
function UpdateRowCount(ctl, query)
{
	var spn = document.getElementById('ds_ajax_count');
	
	if (!spn.cnt)
	{
		spn.cnt = -1;
		spn.style.cursor = 'wait';
		AjaxLookup('lstcnt', '', encodeURIComponent(query), RowCountResult);	// #5984
	}
}

//-----------------------------------------------------------------------------------------
function RowCountResult(cnt)
{
	var spn = document.getElementById('ds_ajax_count');
	
	if (cnt && spn)
	{
		spn.style.cursor = '';
		
		if (cnt.indexOf('!') == 0)	// Indicates err msg returned.
		{
			var msg = cnt.substr(1);
			
			spn.cnt = '';
			spn.title = msg;
			alert(msg);
		}
		else
		{
			spn.cnt = cnt;
			spn.title = '';
			SetCellText(spn, cnt);
		}
	}
	
	window.status = '';
}

function IsTextNode(node)
{
	return (node && node.nodeType == 3);
}

// No inherent way to get width of TextNode.
function CalcTextNodeWid(node)
{
	var par = node.parentNode;
	var span = document.createElement('span');
	
	par.removeChild(node);
	span.appendChild(node);
	par.appendChild(span);
	
	var wid = span.offsetWidth;
	
	span.removeChild(node);
	par.removeChild(span);
	par.insertBefore(node, par.firstChild);
	
	return (wid);
}

function NodeWidth(node)
{
	return (!node) ?  0 : (IsTextNode(node)) ? CalcTextNodeWid(node) : node.offsetWidth;
}

//-----------------------------------------------------------------------------------------
// Auto tooltip on datasheets when cell text is truncated due to col width.
function InitTip(evt)
{
	if (!evt) evt = window.event;

	var cell = GetEventTarget(evt);

	if (cell && !cell.ttt && !cell.title && ElementType(cell) == 'td')
	{
		cell.ttt = 1;	// Is now set up.  Note that if column is resized we should really recalc.
		
		if (cell.firstChild && NodeWidth(cell.firstChild) > cell.offsetWidth && 
			(IsTextNode(cell.firstChild) || IsVisible(cell.firstChild)))			// #4456
		{
			cell.title = GetCellText(cell);
		}
	}
}

//-----------------------------------------------------------------------------------------
// Sticky bucket click handling.
function ToggleStar(evt, ctrl, mop, rk)
{
	var img = ctrl;//ctrl.children[0];
	var sel = HasCssClass(img, 'unpin') ? 1 : 0;
	
	if (sel)
		RemoveCssClass(img, 'unpin');
	else
		SetCssClass(img, 'unpin');
	
	var conn = new XHConn();

	if (conn)
	{
		var params = 'req=togbkt&mop=' + mop + '&rk=' + rk + '&sel=' + sel + '&ajaxdt' + Timestamp();

		conn.getString('Handler.ashx', params, StarRsp);
//		window.status = 'Selecting/unselecting item...';	// #4782, I18N - don't set status.
	}
	
	return CancelBubble(evt);
}

//-----------------------------------------------------------------------------------------
function StarRsp(s)
{
	window.status = '';
}

//-----------------------------------------------------------------------------------------
function StarClrAll(mop)
{
	var imgs = document.getElementsByTagName('img');
	var ii;
	
	//--- Fixup icons on page.
	
	for (ii=0; ii<imgs.length; ii++)
	{
		var img = imgs[ii];
		
		if (img.src && img.src.indexOf('/Sticky16.gif') >= 0)
		{
			var css = GetCssClass(img);
			var sel = (css && css.indexOf('unpin') >= 0) ? 1 : 0;

			if (!sel)
				SetCssClass(img, 'unpin');
		}
	}
	
	//--- AJAX call to clear items.
	
	var conn = new XHConn();

	if (conn)
	{
		var params = 'req=clrbkt&mop=' + mop + '&ajaxdt' + Timestamp();

		conn.getString('Handler.ashx', params, StarRsp);
//		window.status = 'Unselecting all items...';			// #4782, I18N - don't set status.
	}
}

//-----------------------------------------------------------------------------------------
function TriStateTog(evt, img)
{
	var owner = document.getElementById(img.getAttribute('owner'));
	
	if (owner)
	{
		if (owner.value == '1')
		{
			img.src = 'images/trino.gif';
			owner.value = '0';
		}
		else if (owner.value == '0')
		{
			img.src = 'images/trimaybe.gif';
			owner.value = '';
		}
		else
		{
			img.src = 'images/triyes.gif';
			owner.value = '1';
		}
	}
}

//-----------------------------------------------------------------------------------------
function TriStateClear(img)
{
	var owner = document.getElementById(img.getAttribute('owner'));
	
	if (owner)
	{
		img.src = 'images/trimaybe.gif';
		owner.value = '';
	}
}

//---------------------------------------------------------------------------------------------------------------
// Contents from FilterWidget.js merged. #665
//---------------------------------------------------------------------------------------------------------------

/*jsl:import .\EAPUtils.js */

var usePopup = 1;

//-----------------------------------------------------------------------------------------
// Purpose:	Toggle the visibility of the appropriate FilterWidget div.
//-----------------------------------------------------------------------------------------
function fwToggle(evt, fld)
{
	//--- If this is a different cell, close whatever widget might be open.
	
	if (!usePopup || fld.id != window.fwShowing)
	{
		fwHide();
	}
	
	//--- Toggle the state of the appropriate widget.
	
	var wid = fld.getAttribute('wid');
	
	if ((fld.getAttribute('picklist') || fld.getAttribute('pick')) && wid != 'txt')	// #1075, #2575
	{
		var cap = fld.getAttribute('caption');
		
		if (fld.getAttribute('pick'))
			fwrsToggleDiv(evt, fld, fld.getAttribute('pick'), cap);		// #4782 - New div widget.
		else
			fwrsToggle(evt, fld, fld.getAttribute('picklist'), cap);
	}
	else if (wid && wid != 'txt') // #2350 - any specific widget.  #5951 - 'txt' means 'fwdiv'
	{
		FltWidget(evt, wid, fld, fld.getAttribute('caption'));
	}
	else
	{
		//fwtxtToggleDiv(evt, fld, fld.getAttribute('caption'));			// #4782 - New div widget.
		FltWidget(evt, 'fwdiv', fld, fld.getAttribute('caption'));
	}

	//--- Remember the widget we just handled.
		
	window.fwShowing = fld.id;
//	event.cancelBubble = true;
}

//-----------------------------------------------------------------------------------------
// Purpose:	Hide whatever FilterWidget might be open.
//-----------------------------------------------------------------------------------------
function fwHide()
{
	fwrsHide(0);	// Hide the RowSource FilterWidget
	fwtxtHide(0);	// Hide the Text FitlerWidget
}


//-----------------------------------------------------------------------------------------
// Purpose:	Toggle the visibility of the RowSource FilterWidget.
//-----------------------------------------------------------------------------------------
function fwrsToggle(evt, btn, values, caption)
{
	if (!evt) evt = window.event;
	
	var	widget = document.getElementById('fwrswidget');

	//--- Fill in the contents of the widget (1st time only).
	
	fwrsInit(widget, values);
	
	//--- Now hide or show the widget.
	
	if (widget.style.display == '')
	{
		fwrsHide(0);
	}
	else
	{
		var	list = document.getElementById('fwrslist');
		var txt = btn;
		var cap = document.getElementById('fwrscaption');
		//var delim = widget.getAttribute('delim');
		//var	arr = (values) ? values.split(delim) : null;
//e		var conj = widget.getAttribute('conj');
//e		var clause = conj + txt.value + conj;
//e		var clauseUC = clause.toUpperCase();
		
		//--- Clear the list which will the be populate asynchronously to allow user to cancel.
		
		list.options.length = 0;	// Clear list
		
		//--- Finish up and make visible.

		cap.innerHTML = '&nbsp;' + caption + '<span id="fillstat"></span>';		// Set widget caption.
		
		widget.txt_ctrl = txt;
		
		//--- Set focus to list.  Among other things, this enables <esc> and <enter> handling.

		if (usePopup)
		{
			//--- Opera won't pick up script from template div.  We have to add here.
			
			var	s = '<!-- Created by fwrsToggle() in FiterWidget.js -->\n';
			
			s += 'function ShowInfo(evt, sel)\n';
			s += '{\n';
			s += '    var key = opener.GetEventKey(evt);\n';
			s += '    if (key == 119)\n';
			s += '    {\n';
			s += '        var msg = "Creator --------> FilterWidget.js::fwrsInit\\n";\n';
			s += '        msg += "Elements -------> " + sel.options.length + "\\n";\n';
			s += '        alert(msg);\n';
			s += '    }\n';
			s += '}\n';
			s += 'function FillWidget(id)\n';
			s += '{\n';
			s += '   window.txtId = id;\n';
			s += '   opener.WidgetFill(window, document.getElementById("fwrslist"), id);\n';
			s += '}\n';
			s += 'function CreateOpt(s)\n';
			s += '{\n';
			s += '   return new Option(s, s);\n';
			s += '}\n';
			s += 'function PauseFill(id)\n';
			s += '{\n';
			s += '    if (window.filler)\n';
			s += '        { clearTimeout(window.filler); window.filler = null; }\n';
			s += '    else\n';
			s += '	     opener.WidgetResumeFill(window, document.getElementById("fwrslist"), id);\n';
			s += '}\n';
			s += 'function FilterFill(txt, tim)\n';	// #1075
			s += '{\n';
			s += '   if (tim)\n';
			s += '   {\n';
			s += '      opener.WidgetFill(window, document.getElementById("fwrslist"), window.txtId, txt.value);\n';
			s += '   }\n';
			s += '   else\n';
			s += '   {\n';
			s += '      if (txt.req) window.clearTimeout(txt.req);\n';
			s += '      if (window.filler) window.clearTimeout(window.filler);\n';
			s += '      txt.req = window.setTimeout(function() { FilterFill(txt, true); }, 350);\n';
			s += '   }\n';
			s += '}\n';

			var w = popupWindow(evt, widget.id, 'filterwidget', caption, 'fwrslist', s, true, 'FillWidget(\'' + btn.id + '\');');	// #3393 - Added onload.
			
			if (w && w.focus) SetFocus(w, false);
			
			w.fillId = btn.id;
			w.arrValues = null;
			w.fillDone = false;
		}
		else
		{
			widget.style.left = evt.clientX; //event.x;	// Position widget horizontally.
			widget.style.top = evt.clientY; //event.y;		// Position widget vertically.
			widget.style.display = '';		// Show widget.
			list.focus();					// Set focus to the list.
		}
	}	
}

//-----------------------------------------------------------------------------------------
// Get picklist values either from item, or using AJAX. #1075
function PickGet(win, sel, id, txt, delim, flt)
{
	var values = txt.getAttribute('picklist');	// Inplace picklist
	
	if (values) 
	{
		win.arrValues = values.split(delim);
	}
	else if (!win.arrValues || flt != txt.flt)
	{
		var pick = txt.getAttribute('pick');	// picklist_id to get w/ AJAX
		
		if (pick)
		{
			txt.seq = (txt.seq) ? 1 + txt.seq : 1;
			var params = 'pick=' + pick + '&seq=' + txt.seq + '&lim=250';
			
			if (flt) params += '&text=' + encodeURIComponent(flt);
			
			win.arrValues = null;
			AjaxReq('pick', params, function(rsptxt) 
				{ 
					var semi = rsptxt.indexOf(';');
					if (semi < 0) semi = rsptxt.length;
					var seq = rsptxt.substr(0, semi);
					if (seq == txt.seq)	// Ignore old requests.
					{
						win.arrValues = rsptxt.substr(semi).split(delim); 
						WidgetPickFill(win, sel, win.arrValues, 0, txt, flt); 
					}
				} );
		}
	}
	
	return (win.arrValues);
}

//-----------------------------------------------------------------------------------------
// Fills the next chunk of options in the widget's select.
//-----------------------------------------------------------------------------------------
function WidgetFill(win, list, id, flt)
{
	var txt = document.getElementById(id);
	var	widget = document.getElementById('fwrswidget');
	var delim = widget.getAttribute('delim');
	
	//--- Get values, may use AJAX and return null. #1075
	
	var arr = PickGet(win, list, id, txt, delim, flt);
	
	//--- If we're starting fill, add an icon user can click to pause/continue filling.

	var filler = win.document.getElementById('filler');

	if (filler)
	{
		filler.innerHTML = '<input type="image" src="images/fill.gif" border="0" onclick="PauseFill(\'' + id + '\');" title="Click here to pause or continue filling the list." />';
	}
	
	//--- If getting picklist using AJAX then arr will be null and we'll get a callback upon response. #1075
	
	if (arr)
	{
		WidgetPickFill(win, list, arr, 0, txt, flt);
	}
}

//-----------------------------------------------------------------------------------------
// Resume a paused fill.
function WidgetResumeFill(win, list, id)
{
	var txt = document.getElementById(id);

	WidgetPickFill(win, list, win.arrValues, list.options.length, txt, txt.flt);
}

//-----------------------------------------------------------------------------------------
// Fill the list with the next batch of items.
function WidgetPickFill(win, list, arr, nStart, txt, flt)
{
	if (arr)
	{
		var	widget = document.getElementById('fwrswidget');
		var stat = win.document.getElementById('fillstat');
		var filler = win.document.getElementById('filler');
		
		//--- If starting a new fill, show filler icon & status.
		
		if (nStart == 0)
		{
			stat.innerHTML = '';
			stat.style.display = '';
			filler.style.display = '';
		}

		//--- Set up for detecting selected items as we add options.
		
		var val = txt.value;
		var conj = widget.getAttribute('conj');
		var clause = conj + val + conj;
		var clauseUC = clause.toUpperCase();
		
		//--- Add the next chunk of options...
		
		txt.flt = flt;
		
		if (nStart == 0) 
		{
			if (list.options.length > 0) list.value = list.options[0].value;	// #5598 - Fix for Chrome painting issue.
			list.options.length = 0;
		}
		
		for (var ii=nStart; ii<arr.length; ii++)
		{
			var s = arr[ii];
			
			//--- Add the option to the select.
			
			var opt = win.CreateOpt(s);					// Works w/ all browsers
			
			list.options[ii] = opt;						// Works w/ all browsers
			opt.removeAttribute('selected');			// Opera seems to default to selected!
			
			//--- See if this option is selected.
			
			if (val != '' && s != '')
			{
				var itemUC = (conj + s + conj).toUpperCase();
				if (clauseUC.indexOf(itemUC) >= 0) 
				{
					opt.selected = '1';
				}
			}
		
			//--- If we've finished this chunk, update status text, set a 
			//--- timeout, and stop filling.  The timeout allows the window
			//--- to update and handle events.
			
			if ((ii+1) % 50 == 0)
			{
				stat.innerHTML = '&nbsp;(' + (ii+1) + ' of ' + arr.length + ')';
				win.filler = win.setTimeout(function() { WidgetPickFill(win, list, arr, ii+1, txt, flt); }, 10);
				break;
			}
		}
		
		//--- If all options have been added, hide the status text and icon.
			
		if (ii >= arr.length)
		{
			stat.style.display = 'none';
			filler.style.display = 'none';
			
			if (!IsIE() && !win.resized)
			{
				ResizeWin(win, list.offsetWidth + 16, GetClientHeight(win));
				win.resized = true;
			}
		}
	}
}

//-----------------------------------------------------------------------------------------
// Purpose:	Hide the RowSource FilterWidget saving filter clause if so specified.
//-----------------------------------------------------------------------------------------
function fwrsHide(save, win)
{
	var	widget = null;
	
	if (!win) win = window;
	
	if (usePopup && window.name == 'filterwidget')
	{
		widget = document.getElementById('fwrswidget');
	}
	else
	{
		widget = document.getElementById('fwrswidget');
	}
	
	//--- If desired, save the value to the text box.
	
	if (widget && save)
	{
		var	list = win.document.getElementById('fwrslist');
		var ii;
		var clause = '';
		var conj = widget.getAttribute('conj');

		//--- Build the clause by joining the selected items.
		
		for (ii=0; ii<list.options.length; ii++)
		{
			if (list.options[ii].selected)
			{
				clause += conj + list.options[ii].value;
			}
		}
		
		//--- Trim extra leading conjunction and set to text box.
		
		if (clause.length > 0) clause = clause.substr(conj.length);
		
		widget.txt_ctrl.value = clause;
	}
	
	//--- Now set focus to the filter field.
	
	if (widget && widget.txt_ctrl) 
	{
		SetFocus(widget.txt_ctrl, false);
	}

	//--- Hide the widget.

	if (widget) widget.style.display = 'none';	

	if (usePopup && win.name == 'filterwidget')
	{
		win.close();
	}
}

//-----------------------------------------------------------------------------------------
// Purpose:	Generate the HTML content of the RowSource FilterWidget.
// Remarks:	The widget content is generated programmatically to minimize page size.
//			This way the host page just needs an empty div.  Note that the empty div
//			also provides the localized text.
//-----------------------------------------------------------------------------------------
function fwrsInit(widget, values)
{
	if (!widget.initialized)
	{
		var	s = '<!-- Created by fwrsInit() in FiterWidget.js -->\n';
		
		s += '<table cellspacing="0" cellpadding="0" border="0" width="100%">\n';
		s += '<tr><td>\n';
		s += '<div class="fwcaption">\n';
		s += '<table cellspacing="0" cellpadding="0" border="0" class="fwwidget" style="width:100%"><tr style="width:100%;height:100%">\n';
		s += '<td width="100%"><div id="fwrscaption" class="fwcaption"></div></td>\n';
		if (!usePopup)
		{
			s += '<td style="align:right;color:white;width:1em;xbackground-color:olive;font-size:12;cursor:hand" onclick="fwrsHide(0);"><b>X</b></td>';
		}
		s += '<td id="filler" style="height:100%"></td><td>&nbsp</td>\n';
		s += '</tr></table>\n';
		s += '</div>\n';
		s += '</td></tr>\n';
		
		s += '<tr><td>\n';
		if (usePopup)
		{
			s += '<table>\n';
		}
		else
		{
			s += '<table onkeypress="fwrsKey(\'' + widget.id + '\');">';
		}
		
		//--- Add filtering for big lists w/ AJAX. #1075
		
		s += '<tr id="fwrsflt"><td colspan="2" width="100%">\n';
		s += '<table><tr>\n';
		s += '<td><nobr><span class="hint">Starts With:</span></nobr></td>';
		s += '<td style="width:100%"><input type="textbox" id="fwrstxt" style="width:100%" onkeyup="FilterFill(this);"/></td>\n';
		s += '</tr></table>\n';
		s += '</td></tr>\n';
		
		//--- Add the list.
		
		s += '<tr>';
		s += '<td colspan="2"><select id="fwrslist" onkeydown="ShowInfo(event, this);" class="mapper" size="12" multiple="true" style="width:100%"></select></td>';
		s += '</tr>\n';
		s += '<tr>';
		if (usePopup)
		{
			s += '<td width="50%"><input type="submit" class="mapper" onclick="opener.fwrsHide(1, window);" value="OK" style="width:100%" /></td>';
			s += '<td width="50%"><input type="reset" class="mapper" onclick="opener.fwrsHide(0, window);" value="Cancel" style="width:100%" /></td>';
		}
		else
		{
			s += '<td width="50%"><input type="button" class="mapper" onclick="fwrsHide(1);" value="OK" style="width:100%" /></td>';
			s += '<td width="50%"><input type="button" class="mapper" onclick="fwrsHide(0);" value="Cancel" style="width:100%" /></td>';
		}
		s += '</tr>\n';
		s += '<tr>';
		s += '<td colspan="2" class="hint" style="width:100%">' + widget.getAttribute('hint') + '</td>';
		s += '</tr>\n';
		s += '</table>\n';
		s += '</td></tr>\n';
		s += '</table>\n';
		
		widget.innerHTML = s;

		widget.initialized = true;
	}
	
	//--- Show filtering for AJAX lists only. #1075
	
	var flt = document.getElementById('fwrsflt');
	
	flt.style.display = (values) ? 'none' : '';
}


//-----------------------------------------------------------------------------------------
// Purpose:	Handle <esc> and <cr> keys.
//-----------------------------------------------------------------------------------------
function fwrsKey(widget)
{
	var	rtn = true;
	
	if (window.event.keyCode == 27)
	{
		fwrsHide(0);	// <esc> enterred, cancel.
	}
	else if (window.event.keyCode == 13)
	{
		fwrsHide(1);	// <cr> enterred, save.
		rtn = false;
	}
	
	return (rtn);
}


//-----------------------------------------------------------------------------------------
// Purpose:	Toggle the visibility of the Text FilterWidget.
// History:	10/13/05	CW	Fix for Firefox which doesn't clone input values it seems.
//-----------------------------------------------------------------------------------------
function fwtxtToggle(evt, txt, caption)
{
	if (!evt) evt = window.event;

	var widget = document.getElementById('fwtxtwidget');
	
	//--- Fill in the contents of the widget (1st time only).

	fwtxtInit(widget);

	//--- Now hide or show the widget.
	
//	if (widget.style.display == '')
//	{
//		fwtxtHide(0);
//	}
//	else
//	{
		var cap = document.getElementById('fwtxtcaption');
		
		widget.txt = txt;

		cap.innerHTML = '&nbsp;' + caption;

		var val = document.getElementById('fwtxtvalue');
		var v = '' + txt.value;
		var index = 0;

		//--- Split filter keyword from text.
	
		var	valUC = v.toUpperCase();	// Case-insensitive search

		if (valUC.indexOf('STARTS WITH ') == 0)
		{
			v = v.substr(12);
			index = 0;
		}
		else if (valUC.indexOf('=') == 0)
		{
			v = v.substr(1);
			index = 1;
		}
		else if (valUC.indexOf('CONTAINS ') == 0)
		{
			v = v.substr(9);
			index = 2;
		}
		else if (valUC.indexOf('ENDS WITH ') == 0)
		{
			v = v.substr(10);
			index = 3;
		}
		else // #3718
		{
			var sDefFlt = txt.getAttribute('fltdef');
			
			if (sDefFlt && sDefFlt == 'CONTAINS')
			{
				index = 2;
			}
		}

		val.value = v;			// For IE
		val.defaultValue = v;	// For Firefox
	
		//---
		
		if (usePopup)
		{
			var chks = document.getElementsByName('searchtype');
			var ii;
			
			for (ii=0; ii<chks.length; ii++)
			{
				chks[ii].checked = (ii == index);			// For IE
				chks[ii].defaultChecked = (ii == index);	// For Firefox
			}
			
			popupWindow(evt, widget.id, 'filterwidget', caption, val.id, '', true);
		}
		else
		{
			widget.style.left = event.x;
			widget.style.top = event.y;
			widget.style.display = '';
			val.focus();
		}
//	}
}

//-----------------------------------------------------------------------------------------
// Purpose:	Hide the Text FilterWidget saving filter clause if so specified.
//-----------------------------------------------------------------------------------------
function fwtxtHide(save, win)
{
	var widget = null;
	
	if (!win) win = window;

	if (usePopup && window.name == 'filterwidget')
	{
		widget = document.getElementById('fwtxtwidget');
	}
	else
	{
		widget = document.getElementById('fwtxtwidget');
	}
	
	var txt = (widget) ? widget.txt : null;
	
	//--- If desired, save the value to the text box.

	if (widget && save)
	{
		var clause = '';
		var val = win.document.getElementById('fwtxtvalue');
		
		//--- Start with filter keyword.
		
		var searchType = (usePopup) ? win.document.getElementsByName('searchtype') : document.getElementsByName('searchtype');
		
		if (searchType[0].checked)
			clause = 'STARTS WITH';
		else if (searchType[1].checked)
			clause = '=';
		else if (searchType[2].checked)
			clause = 'CONTAINS';
		else if (searchType[3].checked)
			clause = 'ENDS WITH';
		else
			alert('none checked');
		
		//--- Build clause.
		
		var sDefFlt = txt.getAttribute('fltdef');
		
		if (!sDefFlt) sDefFlt = 'STARTS WITH';	// #3718
			
		clause = (sDefFlt == clause) ? val.value : clause + ' ' + val.value;

		//--- Append filter text.
		
		txt.value = clause;
	}
	
	//--- Now set focus to the filter field.
	
	if (txt) SetFocus(txt, false);

	//--- Hide the widget.
	
	if (widget) widget.style.display = 'none';

	if (usePopup && win.name == 'filterwidget')
	{
		win.close();
	}
}

//-----------------------------------------------------------------------------------------
// Purpose:	Generate the HTML content of the Text FilterWidget.
// Remarks:	The widget content is generated programmatically to minimize page size.
//			This way the host page just needs an empty div.  Note that the empty div
//			also provides the localized text.
//-----------------------------------------------------------------------------------------
function fwtxtInit(widget)
{
	if (!widget.initialized)
	{
		widget.initialized = true;
		
		var	s = '<!-- Created by fwtxtInit() in FiterWidget.js -->\n';
		
		s += '<div>';
		if (IsSafari()) s += '<form id="theform">';		// Safari needs radio buttons to be in a form!
														// but, IE doesn't like it!
		if (usePopup)
		{
//			s += '<table cellspacing="0" cellpadding="0" class="fwwidget" style="width:100%" ID="Table1"><tr style="width:100%"><td><div id="fwtxtcaption" class="fwcaption"></div></td><td style="align:right;color:white;width:1em;xbackground-color:olive;font-size:12;cursor:hand" onclick="opener.fwtxtHide(0, window);"><b>X</b></td></tr></table>';
			s += '<table cellspacing="0" cellpadding="0" class="fwwidget" style="width:100%" ID="Table1"><tr style="width:100%"><td><div id="fwtxtcaption" class="fwcaption"></div></td></tr></table>';
			s += '<table class="fwwidget">';
		}
		else
		{
			s += '<table cellspacing="0" cellpadding="0" class="fwwidget" style="width:100%" ID="Table1"><tr style="width:100%"><td><div id="fwtxtcaption" class="fwcaption"></div></td><td style="align:right;color:white;width:1em;xbackground-color:olive;font-size:12;cursor:hand" onclick="fwtxtHide(0);"><b>X</b></td></tr></table>';
			s += '<table class="fwwidget" onkeypress="return fwtxtKey(\'fwtxtwidget\');">';
		}
		s += '<tr><td colspan="8"><input id="fwtxtvalue" autoComplete="false" name="fwtxtvalue" type="text" style="width:100%" /></td></tr>';
		s += '<tr>';
		s += '<td class="fwwidget"><input style="width:20px" type="radio" name="searchtype" checked="checked" ID="Radio1" VALUE="Radio1" /></td><td style="width:20%">Starts With</td>';
		s += '<td class="fwwidget"><input style="width:20px" type="radio" name="searchtype" ID="Radio2" VALUE="Radio2" /></td><td style="width:20%">Exact Match</td>';
		s += '<td class="fwwidget"><input style="width:20px" type="radio" name="searchtype" ID="Radio3" VALUE="Radio3" /></td><td style="width:20%">Contains</td>';
		s += '<td class="fwwidget"><input style="width:20px" type="radio" name="searchtype" ID="Radio4" VALUE="Radio3" /></td><td style="width:20%">Ends With</td>';
		s += '</tr>';
		s += '<tr>';
		if (usePopup)
		{
			s += '<td colspan="2" style="xwidth:20%"><input type="submit" class="mapper" onclick="opener.fwtxtHide(1, window);" value="OK" ID="Button2" NAME="Button2" style="width:100%"/></td>';
			s += '<td colspan="2" style="xwidth:20%"><input type="reset" class="mapper" onclick="opener.fwtxtHide(0, window);" value="Cancel" ID="Button3" NAME="Button3" style="width:100%"/></td>';
		}
		else
		{
			s += '<td colspan="2" style="width:20%"><input type="button" class="mapper" onclick="fwtxtHide(1);" value="OK" ID="Button2" NAME="Button2" style="width:100%" /></td>';
			s += '<td colspan="2" style="width:20%"><input type="button" class="mapper" onclick="fwtxtHide(0);" value="Cancel" ID="Button3" NAME="Button3" style="width:100%"/></td>';
		}
		s += '</tr>';
		s += '</table>';
		if (IsSafari()) s += '</form>';
		s += '</div>';
		
		widget.innerHTML = s;

		widget.initialized = true;
	}
}

//-----------------------------------------------------------------------------------------
// Purpose:	Handle <esc> and <cr> keys.
//-----------------------------------------------------------------------------------------
function fwtxtKey(widget)
{
	var	rtn = true;
	
	if (window.event.keyCode == 27)
	{
		fwtxtHide(0);	// <esc> enterred, cancel.
	}
	else if (window.event.keyCode == 13)
	{
		fwtxtHide(1);	// <cr> enterred, save.
		rtn = false;
	}
	
	return (rtn);
}

//-----------------------------------------------------------------------------------------
// Purpose:	Show the FilterWidget button on the current FBF cell.
//-----------------------------------------------------------------------------------------
function fwButtonShow(evt, txt)
{
	if (!evt) evt = window.event;

	var	btn = document.getElementById('fwbutton');
	
	if (btn && txt && (btn.txt != txt || btn.style.display != ''))
	{
		var left = getLeft(txt, btn) + txt.offsetWidth;
		var top = getTop(txt, btn);

		btn.style.zIndex = 1000;
		btn.style.left = left;
		btn.style.top = top;
		btn.style.display = '';
		btn.style.left = left - btn.offsetWidth; // Now that button is visible, offset by width
		btn.txt = txt;
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function fwButtonHide()
{
	var	btn = document.getElementById('fwbutton');
	
	if (btn) btn.style.display = 'none';
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function fwKeys(evt)
{
	if (!evt) evt = window.event;
	
	var	rtn = true;
	var key = GetEventKey(evt);
	
	if (key == 13)									// <CR>
	{ 
		var fbf = window.fbfbutton;
		
		//--- Safari hack.
		
		if (!fbf)
		{
			var tr = FindDSRow(GetEventTarget(evt));
			
			if (tr) fbf = document.getElementById(tr.id + '_FBF1');
			if (!fbf) fbf = document.getElementById(tr.id + '_FBF2');
		}
		
		if (fbf) 
		{
			if (!DoClick(fbf) && IsSafari())
			{
				fbf.click();	// Safari hack
			}
		}

		rtn = false; 
		CancelBubble(evt);
	}
	else if (key == 116 && evt.shiftKey)	// Shift-F5
	{
		fwToggle(evt, (evt.srcElement) ? evt.srcElement : evt.target);
		evt.cancelBubble = true;
	}
	
	return (rtn);
}

// Find datasheet row for this item which could include nested table(s).
function FindDSRow(item)	// For #5548
{
	var tr = FindParent(item, 'tr');
	
	if (tr)
	{
		var tbl = FindParent(tr, 'table');
		
		if (tbl && tbl.getAttribute('use') != 'ds')
		{
			tr = FindDSRow(tbl);
		}
	}
	
	return (tr);
}

//-----------------------------------------------------------------------------------------
// Remarks: If bCheckboxes is specified then the widget is built to use a set of checkboxes
//			instead of a multi-select.  The checkboxes are generated from the multi-select
//			by the multiselect.js script.
//-----------------------------------------------------------------------------------------
function MultiSelect(evt, ctrl, opts, pick)
{
	//MultiSelWin(evt, ctrl, opts, pick);
	MultiSelDiv(evt, ctrl, opts, pick);	// #4957
}

function MultiSelWin(evt, ctrl, opts, pick)
{
	var csCheckboxWidget = 'c';
	var csSizeToList = 'z';
	var csSingleSelect = 's';
	var csEditable = 'e';
	
	var	s = '<!-- Created by MultiSelect() in FiterWidget.js -->\n';
	var lkup = bndLkupTable(ctrl);
	var sHint = lkup.getAttribute('hint');
	var sDelim =  lkup.getAttribute('delim');
	var bCheckboxes = (opts.indexOf(csCheckboxWidget) >= 0);
	var bSizeToList = (opts.indexOf(csSizeToList) >= 0);
	var bSingleSelect = (opts.indexOf(csSingleSelect) >= 0);
	var bEditable = (opts.indexOf(csEditable) >= 0);

	if (!sDelim) sDelim = ';';
	if (!sHint) sHint = 'Click while holding down the shift or control keys to select multiple items.';

	// Do not add javascript file references.  These will cause IE to freeze.
	//bCheckboxes = false;

	//---
	
	s += '<div id="outerContent" style="width="300px">\n';
	//s += '<table width="300px" height="300px">\n';
	s += '<table width="100%" onkeydown="ShowInfo(event);">\n';
	s += '<tr>\n';
	
	//--- Build the options.
	
	var sStyle = '';
	//var bSizeToList = false;
	
	if (bSizeToList)
	{
		sStyle = ' style="width:250px;height=200px"';
	}

//	s += '<td colspan="2"><select id="list" size="8" onkeydown="if (PressedEsc()) document.getElementById(\'cancel\').click(); else if (PressedCR()) document.getElementById(\'ok\').click();" multiple="true" style="width:100%">\n';
	if (bEditable)
	{
		s += '<td colspan="3" width="100%">\n';
	}
	else
	{
		s += '<td colspan="2" width="100%">\n';
	}
	
	//---
		
	var picklist = bndLkupTable(ctrl).getAttribute('picklist');
	var	arr = picklist.split(';');
	var txt = document.getElementById(bndLkupTxtFromBtn(ctrl));
	
	if (bCheckboxes)
	{
		//--- Since we can't seem to use multiselect.js safely, build the
		//--- checkboxes manually.

		s += '<div class="mapper" style="height:195px;width:100%;border-style:solid;border-width:1px;overflow:auto">\n';
		s += '<table class="mapper">\n';
		
		var current = sDelim + txt.value + sDelim;
		var ii;
		var val;
		
		//--- Add picklist items.
		
		current = current.toUpperCase();

		for (ii=0; ii<arr.length; ii++)
		{
			val = arr[ii];

			if (val && val.length > 0)		
			{
				var cbid = 'wcb' + ii;
				
				s += '<tr><td width="100%"><input type="checkbox" value="' + val + '" id="' + cbid + '"';
				if (val.length > 0 && current.indexOf(sDelim + val.toUpperCase() + sDelim) >= 0)
				{
					s += ' checked="checked"';
				}
				s += ' />';
				s += '<label for="' + cbid + '"><nobr>' + val + '</nobr></label>';
				s += '</td></tr>\n';
			}
		}
		
		//--- Add missing items, if any.
		
		val = txt.value;

		if (val)
		{
			var itemList = ';' + picklist.toUpperCase() + ';';
			var wm = txt.getAttribute('wm');
			
			arr = val.split(sDelim);
			
			for (ii=0; ii<arr.length; ii++)
			{
				val = arr[ii];

				if (val && val.length > 0 && val != wm && itemList.indexOf(sDelim + val.toUpperCase() + sDelim) < 0)
				{
					var cbid = 'wcbmiss' + ii;
					
					s += '<tr><td width="100%"><input type="checkbox" value="' + val + '" id="' + cbid + '"';
					s += ' checked="checked"';
					s += ' />';
					s += '<label for="' + cbid + '"><nobr><span class="disabled">' + val + '</span></nobr></label>';
					s += '</td></tr>\n';
				}
			}
		}
		
		s += '</table></div></td>\n';
	}
	else
	{
		//--- Build the select manually.
		
		s += '<select' + sStyle + ' id="list" class="mapper" size="8" onkeydown="opener.FormKeyHandler(\'cancel\',\'ok\',window);"';
		if (!bSingleSelect)
		{
			s += ' multiple="true"';
		}
		s += ' style="width:100%">\n';

		//r var t = bndLkupTable(ctrl);
		var current = sDelim + txt.value + sDelim;
		
		//--- Add picklist items.
		
		current = current.toUpperCase();

		for (var ii=0; ii<arr.length; ii++)
		{
			var val = arr[ii];

			if (val && val.length > 0)		
			{
				s += '<option value="' + val + '"';
				if (val.length > 0 && current.indexOf(sDelim + val.toUpperCase() + sDelim) >= 0)
				{
					s += ' selected="selected"';
				}
				s += '>' + val + '</option>\n';
			}
		}

		s += '</select></td>\n';
	}

	//---
	
	var	sBtnWidth = (bEditable) ? "33%" : "50%";
	
	s += '</tr>\n';
	s += '<tr>\n';
	s += '<td width="' + sBtnWidth + '"><input class="mapper" style="width:100%" type="submit" onclick="SetValue(\'' + ctrl.id + '\',\'' + sDelim + '\'); window.close();" value="OK" name="ok" /></td>\n';
	s += '<td width="' + sBtnWidth + '"><input class="mapper" style="width:100%" type="reset" onclick="window.close();" value="Cancel" name="cancel" /></td>\n';
	if (bEditable)
	{
		s += '<td width="' + sBtnWidth + '"><input class="mapper" style="width:100%" type="button" onclick="opener.ManageList(opener.document.getElementById(\'' + ctrl.id + '\'), \'' + pick + '\', 1);" value="Edit" name="edit" /></td>\n';
	}
	s += '</tr>\n';
	if (!bCheckboxes && !bSingleSelect)
	{
		var colspan = (bEditable) ? '3' : '2';
		
		s += '<tr>';
		s += '<td colspan="' + colspan + '" class="hint" style="width:100%">' + sHint + '</td>';
		s += '</tr>\n';
	}
	s += '</table>\n';
	s += '</div>\n';

	//--- Build extraction code for select or checkboxes as appropriate.

	s += '\n<script><!--\n';
	s += 'function ShowInfo(evt)\n';
	s += '{\n';
	s += '    var key = opener.GetEventKey(evt);\n';
	s += '    if (key == 119)\n';
	s += '    {\n';
	s += '        var msg = "Creator --------> FilterWidget.js::MultiSelect\\n";\n';
	s += '        msg += "Elements -------> ' + arr.length + '\\n";\n';
	s += '        msg += "Options --------> ' + opts + '\\n";\n';
	s += '        alert(msg);\n';
	s += '    }\n';
	s += '}\n';
	if (bCheckboxes)
	{
		s += 'function SetValue(id, delim)\n';
		s += '{\n';
		s += '   var clause = \'\';\n';
		s += '   var els = document.getElementsByTagName(\'input\');\n';
		s += '   for(var ii=0; ii<els.length; ii++)\n';
		s += '   {\n';
		s += '      if (els[ii].type.toLowerCase() == \'checkbox\' && els[ii].checked)\n';
		s += '      {\n';
		s += '         clause += delim + els[ii].value;\n';
		s += '      }\n';
		s += '   }\n';
		s += '\n';
		s += '   if (clause.length > 0) clause = clause.substr(1);\n';
		s += '   var btn = opener.document.getElementById(id);\n';
		s += '   var txtID = opener.bndLkupTxtFromBtn(btn);\n';
		s += '   var txt = opener.document.getElementById(txtID);\n';
		s += '   txt.value = clause;\n';
		s += '   if (txt.change)\n';
		s += '      txt.change();\n';
		s += '   else if (txt.onchange)\n';
		s += '      txt.onchange();\n';
		s += '}\n';
	}
	else
	{
		s += 'function SetValue(id, delim)\n';
		s += '{\n';
		s += '   var list = document.getElementById(\'list\');\n';
		s += '   var clause = \'\';\n';
		s += '\n';
		s += '   for (ii=0; ii<list.options.length; ii++)\n';
		s += '   {\n';
		s += '      if (list.options[ii].selected)\n';
		s += '      {\n';
		s += '         clause += delim + list.options[ii].value;\n';
		s += '      }\n';
		s += '   }\n';
		s += '\n';
		s += '   if (clause.length > 0) clause = clause.substr(1);\n';
		s += '   var btn = opener.document.getElementById(id);\n';
		s += '   var txtID = opener.bndLkupTxtFromBtn(btn);\n';
		s += '   var txt = opener.document.getElementById(txtID);\n';
		s += '   txt.value = clause;\n';
		s += '   if (txt.change)\n';
		s += '      txt.change();\n';
		s += '   else if (txt.onchange)\n';
		s += '      txt.onchange();\n';
		s += '}\n';
	}
	s += '--></script>\n';
	
	//--- Add code to resize widget to content.

	if (!bCheckboxes)
	{
		// Note 23 and 40 were determined by trial and error to keep the window the same size
		// on multiple redisplays with IE.  Same with 17 and 65 for Firefox.
		
		var x = (IsIE()) ? 23 : 17;
		var y = (IsIE()) ? 40 : 65;
		
		s += '\r\n\r\n<script>\r\n';
		
		//--- It seems Firefox needs a little delay to layout before determining
		//--- div size.  100ms seems to be enough.
		
//		s += '  var div = document.getElementById(\'outerContent\');\r\n';
//		s += '  window.resizeTo(div.offsetWidth + 23, div.offsetHeight + 40);\r\n';		
		s += '  window.setTimeout(\'var div=document.getElementById("outerContent"); window.resizeTo(div.offsetWidth+' + x + ', div.offsetHeight+' + y + ');\', 100);';
		s += '  document.getElementById(\'list\').focus();';
		s += '</script>\r\n';
	}
		
	//---
	
	var features;
	var width;
	var height;
	
	if (bCheckboxes)
	{
		width = 260;
		height = 240;
	}
	else
	{
		width = 250;
		height = 30;
	}
	
	//--- Make sure widget isn't off the screen.
	
	var	left = evt.clientX; //event.x;
	var top = evt.clientY; //event.y;
	
	if (left + width > screen.width) 
		left = screen.width - width - 20;
	else if (top + height > screen.height)
		top = screen.height - height - 20;

	//--- If we didn't get a position, use current mouse location.
		
	if (left == 0 && top == 0)
	{
		left = Mouse.x;
		top = Mouse.y;
	}
	
	features = 'menubar=0,resizable=1,scrollbars=0,titlebar=0,width=' + width + ',height=' + height;
	features += ',left=' + left + ',top=' + top;

	var	win = OpenWindow('mselwidget', features, bndLkupTable(ctrl).caption, s, null, true);
	//var	div = win.document.getElementById('outerContent');
	//var	nWidth = (bCheckboxes) ? 12 : 0;	
	//win.resizeTo(div.offsetWidth + 12, div.offsetHeight + 40);
	
	//win.setActive();	
	
	window.multiwin = win;
}

//---------------------------------------------------------------------------------------------------------------
// Contents from EAPSubform.js merged. #665
//---------------------------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function sfOver(evt, item)
{
	SetCssClass(item, 'subformbarActive');
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function sfOut(evt, item)
{
	if (!item.active) RemoveCssClass(item, 'subformbarActive');
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function sfShow(evt, btn, persist_id, force, addFK)
{
	var persistCtrl = document.getElementById(persist_id);
	var idActive = persistCtrl.value;
	var	ctl;
	var id = btn.getAttribute('sf');
	
	CancelBubble(evt);	// #715 - Else error on Opera when tooltip on tab.
	
	//--- If there's an active item, deactive it.

	if (idActive && idActive != id)
	{
		ctl = document.getElementById(idActive);
		if (ctl) 
		{
			ctl.style.display = 'none';		// #3929. Safety.
			
			if (ctl.btn) 
			{
				SetCssClass(ctl.btn, '');
				ctl.btn.active = false;
			}
		}
		
		//--- Seems we have to force a requery on Safari every time -- too bad.
				
		if (IsSafariPre5()) force = 1;	// Needed on Safari v2, but not v3.
	}

	//--- Get new item.
	
	ctl = document.getElementById(id);
	
	if (!btn.hid)	// Don't show if explicitly hidden. #998
	{
		//--- If the rowKey has changed, force a subform requery.
		
		if (addFK && window.rowKey != ctl.rowKey)
		{
			force = 1;
		}
		
		//---- Build the url w/ the row key.
		
		var url = sfTabBuildUrl(btn, addFK, true);
		
		//--- Set URL for item if not already set (or if refresh is forced). 
		
		if (!ctl.getAttribute('lasturl') || force)
		{
			UpdateUrl(ctl.id, url);		// Update URL preserving browser forward/back navigation
		}
		
		//--- Show new item.  Note the hack for Firefox.  IE, Opera and Safari
		//--- all work well just setting display to '', but Firefox needs to be
		//--- set to block then, in a timeout, to ''.

		if (IsFirefox())
		{
			ctl.style.display = 'block'; //'';
			window.setTimeout('ForceVisibility("' + id + '");', 1);	
		}
		else
		{
			ctl.style.display = '';
		}
		
		//--- Make button active.

		SetCssClass(btn, 'subformbarActive');
		btn.active = true;
		ctl.btn = btn;
		
		//--- Save id of new active item.  This will post back.

		window.setTimeout(function() { persistCtrl.value = id; }, 1);
	}
	
	return (false);	// #2044
}

//-----------------------------------------------------------------------------------------
function sfTabBuildUrl(tab, addFK, updateFrame, url)
{
	var frameId = tab.getAttribute('sf');
	var frm = document.getElementById(frameId);
	
	//--- Set up base URL.
	
	if (!url) url = tab.getAttribute('baseurl');
	
	//--- Add a foreign key for the current top item.
	
	if (addFK)
	{
		var	rowKey = window.rowKey;

		if (window.rowKey) 
		{
			url += '&if=' + frameId;
			if (updateFrame) frm.urlbase = url;
			url += '&rk=' + rowKey;
			if (updateFrame) frm.rowKey = rowKey;
			url += '&parval=' + window.rowDigest;
			if (updateFrame) frm.rowDigest = window.rowDigest;
			if (window.rowDesc) url += '&rd=' + encodeURIComponent(window.rowDesc);
		}
	}
	
	return (url);
}

//-----------------------------------------------------------------------------------------
// Hack for Firefox.  This seems to be necessary, but only on the first subform click.
//-----------------------------------------------------------------------------------------
function ForceVisibility(id, show)
{
	var ctl = document.getElementById(id);
	if (ctl) ctl.style.display = '';
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function sfScroll(evt, btn_id_base, nScroll, nBtnCount)
{
	var		iBtn = 0;
	var		btn = document.getElementById(btn_id_base + iBtn);
	var		tabSig = '';
	var		btns = new Array();
	
	//--- Build array of allowed tabs. #1596
	
	while (btn)
	{
		if (!btn.hid) 
		{
			tabSig += ';' + iBtn;
			btns.push(btn);
		}
		
		iBtn++;
		btn = document.getElementById(btn_id_base + iBtn);
	}
	
	//--- Hide/show tabs from among allowed tabs.
	
	var iCurrent = (tabSig != window.tabSig) ? 0 : window.tabFirst;
	var ii;
	var iFirst = iCurrent + nScroll;
	var min = 4;

	if (btns.length - iFirst < min) 
		iFirst = btns.length - min;
	else if (iFirst < 0)
		iFirst = 0;
	
	for (ii=0; ii<btns.length; ii++)
	{
		btns[ii].style.display = (ii < iFirst) ? 'none' : '';
	}
	
	//--- Save state.
	
	window.tabSig = tabSig;
	window.tabFirst = iFirst;
	
	return (false);	// #2044
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function sfToggleOpen(btn, panelID)
{
	var	panel = document.getElementById(panelID);
	
	if (!panel)
	{
		ThrowError(3001, 'EAPSubform::sfToggleOpen', "Toggler AssociatedControlID '" + panelID + "' not found on page.");
	}
	
	if (panel.style.display == '')
	{
		panel.style.display = 'none';
		btn.src = "images/plus.gif";
	}
	else
	{
		panel.style.display = '';
		btn.src = "images/minus.gif";
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function sfTabRequery(persist_id)
{
	var persistCtrl = document.getElementById(persist_id);

	//--- We might not have a subform, check first.
	
	if (persistCtrl)
	{
		var idActive = persistCtrl.value;
		var url;
		var force = 0;
		
		//--- If there's an active item, deactive it.

		if (idActive)
		{
			var ctl = document.getElementById(idActive);

			if (ctl)
			{
				var	rowKey = window.rowKey;

				if (rowKey != ctl.rowKey) force = 1;
						
				if (ctl.urlbase) 
				{
					url = ctl.urlbase;
					
					if (window.rowKey)
					{
						url += '&rk=' + window.rowKey;
						ctl.rowKey = rowKey;
					}
					
					if (window.rowDigest)
					{
						url += '&parval=' + window.rowDigest;
					}
					
					if (window.rowDesc)
					{
						url += '&rd=' + encodeURIComponent(window.rowDesc);
					}
				}

				//--- Set URL for item if not already set (or if refresh is forced). 
		
				if (!ctl.getAttribute('lasturl') || force)
				{
					UpdateUrl(ctl.id, url);
				}
			}
		}
	}
}

//-----------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------
function sfExpRequery(id, rowKey, rowDigest, urlbase)
{
	var	frame = document.getElementById(id);
	
	if (frame != null)
	{
	    if (urlbase) 
	    {
		    frame.urlbase = urlbase;
	    }
	    else
	    {
		    urlbase = frame.urlbase;
	    }
    	
	    if (frame.rowKey != rowKey)
	    {
		    var url = urlbase + "&rk=" + rowKey + "&parval=" + rowDigest;
    		
		    frame.rowKey = rowKey;
    		
		    UpdateUrl(id, url);		// Update URL preserving browser forward/back navigation
	    }
	}
}

//-----------------------------------------------------------------------------------------
// Find the frame and do a location.replace instead of setting href.
// This is necessary to have browser back/forward navigation work properly.
//-----------------------------------------------------------------------------------------
function UpdateUrl(id, url, delayed)
{
	var ii;
	var found = false;
	
	if (url)
	{
		//--- Find the frame and do a location.replace instead of setting href.
		//--- This is necessary to have browser back/forward navigation work properly.
		
		for (ii=0; ii<window.frames.length; ii++)
		{
			var el = window.frames[ii].frameElement;	// el might be null on Safari due to timing
			
			if (el != null && el.id.toLowerCase() == id.toLowerCase())
			{
				var f = window.frames[ii];
			
				f.document.location.replace(url);				// Update the frame's URL
				f.frameElement.setAttribute('lasturl', url);	// Track last URL used.
				found = true;
				break;
			}
		}
		
		//--- Safari seems to take a while to load the iframes so when we first look,
		//--- they aren't there yet!  Try again in 800ms if none found.
		
		if (!found && !delayed)
		{
			if (window.subTimeoutID) window.clearTimeout(window.subTimeoutID);
			
			window.subTimeoutID = window.setTimeout(function() 
				{
					UpdateUrl(id, url, true);
				}, 800);
		}
	}
}

//-----------------------------------------------------------------------------------------
// Requery the specified subform.
//-----------------------------------------------------------------------------------------
function sfRequery(id)
{
	var	sf = document.getElementById(id);
	
	if (sf) UpdateUrl(id, sf.getAttribute('lasturl'));
}

//-----------------------------------------------------------------------------------------
// It seems you can't programmatically click the anchor tag in Firefox so we load the 
// page into the correct frame explicitly.
//-----------------------------------------------------------------------------------------
function sfTabExplicit(link)
{
	var href = link.href;
	var target = link.target;
	
	//window.status = href + ' --> ' + target;
	//window.status += window.parent.frames.length;
	
	var frame = window.parent.frames[target];
	
	if (frame)
	{
		frame.document.location = href;
	}
}

//-----------------------------------------------------------------------------------------
// Moves the content of a subform to the top pane.
//-----------------------------------------------------------------------------------------
function sfTabMoveUp(evt, btn, tagName)
{
	if (!evt) evt = window.event;
	
	CancelBubble(evt);
	
	if (!tagName) tagName = 'td';
		
	var tab = FindParent(btn, tagName);
	var url = sfTabBuildUrl(tab, true, false);
	
	if (url)
	{
		url = url.replace(/&sub=/, '&fromsub=');	// Unmark as subform
		url = url.replace(/&sda=/, '&xxsda=');		// Don't provide SubformDisplayAttributes
		//--- BugzID: 4633 - Add link action
		url = UpsertUrl(url, 'act', 'sfmu');
		window.document.location.href = url;
	}
}

//-----------------------------------------------------------------------------------------
// Opens first subform.
//-----------------------------------------------------------------------------------------
function sfOpenFirst(btn, persist_id)
{
	var sftb = document.getElementById(btn);
	
	if (sftb) 
	{
		window.initSF = true; 
//		DoClick(sftb);
		sfShow(null, sftb, persist_id, 0, 1);
	}
}

//-----------------------------------------------------------------------------------------
// Dynamically hide/show/enable/disable subform.
//-----------------------------------------------------------------------------------------
function sfEnableTab(btnId, enable, persist_id, flags)
{
	var tab = document.getElementById(btnId);
	
	if (tab)
	{
		if (flags & 0x00000001)
			tab.disabled = !enable;						// enable/disable
		else
		{
			tab.style.display = (enable) ? '' : 'none';	// show/hide
			tab.hid = !enable;							// Mark explicity hidden. #998
		}

		//--- Handle when this is current tab.
		
		var sf = tab.getAttribute('sf');
		var persistCtrl = document.getElementById(persist_id);

		if (persistCtrl.value == sf)
		{
			sf = document.getElementById(sf);
			
			if (sf)
			{
				var dsp = (enable) ? '' : 'none';
				
				if (dsp != sf.style.display) sf.style.display = (enable) ? '' : 'none';
			}
		}
	}
}

//-----------------------------------------------------------------------------------------
function LockField(sibling, id, lock)	// For #1049
{
	var fld = GetDetailSibling(sibling, id);
	
	if (!fld) fld = GetDetailSibling(sibling, id + '_txt');		// #1981 might be lkup.
	
	if (fld)
	{
		var lkup = fld.getAttribute('lkup');
		var btn = null;
		var isSelect = (ElementType(fld) == 'select');
		var clr = null;
				
		if (lkup)
		{
			btn = GetDetailSibling(sibling, lkup + '_btn');
			if (btn) clr = GetDetailSibling(sibling, lkup + '_clr');
		}
		
		if (lock)
		{
			ReplaceCssClass(fld, '', 'lock');
			ReplaceCssClass(fld, '', 'tnb');
			if (isSelect)
				fld.disabled = true;			// #2241
			else
				fld.readOnly = true;
			
			if (btn)
			{
				btn.disabled = true;			// #2241
				if (clr) clr.disabled = true;	// #2241
			}
		}
		else
		{
			RemoveCssClass(fld, 'tnb');
			
			if (btn) // bndlkup handling
			{
				btn.disabled = false;
				if (clr) clr.disabled = false;	// #2241
				
				var oc = btn.getAttribute('oc');
				
				if (oc) btn.onclick = new Function(oc);
				
				var tr = FindParent(btn, 'tr');
				var ii;

				for (ii=0; ii<tr.childNodes.length; ii++)
				{
					if (tr.childNodes[ii].style)
						tr.childNodes[ii].style.display = '';
				}
				
				lock = true;
			}
			
			if (!lock)
			{
				RemoveCssClass(fld, 'lock');
				
				if (isSelect)
					fld.disabled = false;		// #2241
				else
					fld.readOnly = false;
			}
		}
	}
}

//-----------------------------------------------------------------------------------------
// Support AJAX delete of saved filter from Filters menu.
function DelFilter(evt, btn, fltId, msg)	// #942
{
	var delId = btn.id;
	
	setTimeout(function() 
		{ 
			if (confirm((msg) ? msg : 'Are you sure you want to delete this filter?')) 
			{
				AjaxReq('delflt', 'fltid=' + fltId);
			
				if (window.createPopup) btn = document.getElementById(delId);
				
				var mnu = FindParent(btn, 'div');

				if (mnu) mnu.style.display = 'none';
			} 
		}, 1);
		
	CancelBubble(evt); 
	
	return (false);
}

//-----------------------------------------------------------------------------------------
// Init alert scanning. #1737
function AlertInit(ping, checkingMsg, noAlertMsg, popProbMsg)	// #4782 - msg params.
{
	if (ping >= 15)
	{
		window.alrt_none = noAlertMsg;		// #4782
		window.alrt_popProb = popProbMsg;	// #4782
		
		window.setTimeout(function () 
		{ 
			window.status = checkingMsg;	// #4782
			AjaxReq('alrtscn', null, AlertRsp);  
			window.setInterval(function () { window.status = checkingMsg; AjaxReq('alrtscn', null, AlertRsp); }, ping * 1000); 
		}, 3000);
	}
}

//-----------------------------------------------------------------------------------------
// Handle alert scan response. #1737
function AlertRsp(keys)
{
	window.status = '';
	
	if (!keys || keys == '' || keys == ' ')
	{
		window.status = window.alrt_none;	// #4782
	}
	else if (keys.match(/^[0123456789abcdef;]+/i))
	{
		var key = keys.split(';');
		var opts = WindowOpenFeatures(0x00000018, 250, 500);
		var top = 100;
		var left = 100;
		var ii;
		var opened = 0;
		
		for (ii=0; ii<key.length; ii++)
		{
			if (window.open('Handler.ashx?req=nav&pop=0x00000001&mop=alerts!popup&pk=' + key[ii], 'alert_' + key[ii], opts + ',left=' + left + ',top=' + top, true))
			{
				opened++;
				left += 20;
				top += 20;
			}
		}
		
		if (opened == 0 && key.length > 0)
		{
			window.status = window.alrt_popProb.replace(/\{0\}/, key.length - opened);	// #4782
		}
	}
	else if (keys.match(/^!err!/))
	{
	    alert(keys.replace(/^!err!/, ''));
	    //window.status = keys.replace(/^!err!/, '');
	}
	else
	{
	    //alert('There was an unexpected error searching for alerts.');
	}
}

//-----------------------------------------------------------------------------------------
// Tick ticker-tape. #1771
function tickInit(ticker, msec)
{
	ticker = GetElement(ticker);
	
	if (ticker)
	{
		if (ticker.timer) window.clearTimeout(ticker.timer);
		ticker.timer = window.setInterval(function() { tickTock(ticker); }, msec);
	}
}

function tickAddDelim(ticker, space)
{
//	if (space)
//	{
//		ticker.appendChild(document.createTextNode('\u00A0'));
//	}
//	else
	{
		ticker.appendChild(document.createTextNode('\u00A0'));
		ticker.appendChild(document.createTextNode('.'));
		ticker.appendChild(document.createTextNode('.'));
		ticker.appendChild(document.createTextNode('.'));
		ticker.appendChild(document.createTextNode('\u00A0'));
	}
}

function tickTock(ticker)
{
	var item = ticker.childNodes[0];
	var txt = (item) ? GetCellText(item) : null;
	
	if (ticker.clearAll)
	{
		while (ticker.childNodes.length > 0)
		{
			ticker.removeChild(ticker.childNodes[0]);
		}
		
		ticker.cur = '';
		ticker.clearAll = false;
		tickAddDelim(ticker, false);
		
		while (ticker.toAdd && ticker.toAdd.length > 0)
		{
			ticker.appendChild(ticker.toAdd.shift());
			tickAddDelim(ticker, true);
		}
	}
	else if (item && ElementType(item) != 'a') 
	{
		ticker.removeChild(item);
	}
	else if (!item)
	{
		if (ticker.toAdd && ticker.toAdd.length > 0)
		{
			ticker.appendChild(ticker.toAdd.shift());
			tickAddDelim(ticker, true);
		}
	}
	else if (!txt || txt.length == 0)
	{
		ticker.removeChild(item);
		ticker.appendChild(item);
		SetCellText(item, ticker.cur);
		ticker.cur = '';
		item = ticker.childNodes[0];
		if (ElementType(item) != 'a') 
		{
			ticker.removeChild(item);
		}
		tickAddDelim(ticker, true);
		
		if (ticker.toAdd && ticker.toAdd.length > 0)
		{
			ticker.appendChild(ticker.toAdd.shift());
			tickAddDelim(ticker, true);
		}
	}
	else
	{
		ticker.cur = (ticker.cur) ? ticker.cur + txt.substr(0,1) : txt.substr(0,1);
		SetCellText(item, txt.substr(1));
	}
}

function tickAdd(ticker, txt, lnk)
{
	if (!ticker.toAdd) ticker.toAdd = new Array();

	var anch = window.document.createElement('a');

	if (lnk && lnk.length > 0)
	{
		anch.href = lnk;
	}
	else
	{
		anch.onclick = function() { return false; };
		anch.href = '#';
	}
	anch.href = lnk;
	if (txt) SetCellText(anch, txt.replace(/\s/g, '&nbsp;'));

	ticker.toAdd.push(anch);
}

function tickReset(ticker, lstTxt)
{
	ticker = GetElement(ticker);

	if (lstTxt && lstTxt.length > 0)
	{
		var items = lstTxt.split(';');
		var ii;
		
		for (ii=0; ii<items.length; ii++)
		{
			tickAdd(ticker, items[ii], null);
		}
	}
	
	ticker.clearAll = true;
}

// Clear Find fields. #1005
function ClearFind(ctrl, keys)
{
	var ii;
	
	keys = keys.split(';');
	
	for (ii=0; ii<keys.length; ii++)
	{
		var key = keys[ii];
		
		if (key && key.length > 0)
		{
			var fld = GetDetailSibling(ctrl, key);
			
			if (fld)
			{
				ClearNode(fld, true);
				OnChange(fld);
			}
		}
	}
}

//----------------------------- Console panel movement

function panMoveStart(evt, ctrl, pernm)
{
	ctrl = FindParent(ctrl, 'table');	// #2050
	
	if (panCanMove(ctrl))
	{
		var clientX = evt.clientX;
		var clientY = evt.clientY;
		
		//--- #5102 - Handle scrolling.
		
		clientX += document.body.scrollLeft;
		clientY += document.body.scrollTop;
		
		window.pan = ctrl;
		ctrl.pernm = pernm;

		if (IsIE()) ctrl.setCapture();

		//--- Delay for toggler, links.
		
		window.panTimer = window.setTimeout(function() { panMoveStartDelay(ctrl, clientX, clientY); }, 200);
		ctrl.onmouseup = panCancel;
		
		CancelBubble(evt);	// Prevents text select on drag on Opera
	}
}

// Cancel panel movement start if mousebutton released too soon.
function panCancel(evt)
{
	if (window.panTimer)
	{
		if (IsIE() && window.pan) window.pan.releaseCapture();
		window.clearTimeout(window.panTimer);
		window.panTimer = null;
		window.pan = null;
	}
}

// Determine if panel can be moved.
function panCanMove(ctrl)
{
	var td = FindParent(ctrl, 'td');
	
	return (td && (td.childNodes.length/2) > 1);	// Not if only pane in column.
}

// Start panel movement.
function panMoveStartDelay(ctrl, clientX, clientY)
{
	window.panTimer = null;
	ctrl.onmouseup = null;
	
	window.pan = ctrl;
	ctrl.style.cursor = 'move';

	var div = FindParent(ctrl, 'div');

	if (IsIE())
	{
		div.disabled = true;
	}
	else
	{
		SetOpacity(div, 30);
	}

	if (IsIE())
	{
		ctrl.onmousemove = panMove;
		ctrl.onmouseup = panMoveEnd;
		ctrl.setCapture();
	}
	else
	{
		document.onmousemove = panMove;
		document.onmouseup = panMoveEnd;
	}
	
	var mvr = document.createElement('DIV');
	mvr.style.width = '80px';
	mvr.style.height = '40px';
	mvr.style.top = clientY - 20;
	mvr.style.left = clientX - 40;
	document.body.appendChild(mvr);
	SetCssClass(mvr, 'cnsm');
	ctrl.mvr = mvr;
	
//	CancelBubble(evt);
}

// Track panel movement.
function panMove(evt)
{
	if (!evt) evt = window.event;
	
	//--- Move tracking box.
	
	if (window.pan && window.pan.mvr)
	{
		window.pan.mvr.style.top = evt.clientY - 20 + document.body.scrollTop;		// #5102 - Handle scrolling.
		window.pan.mvr.style.left = evt.clientX - 40 + document.body.scrollLeft;	// #5102 - Handle scrolling.
	}
	
	//--- Activate/deactivate valid drop targets.
		
	var ctrl = panGetDropTgt(evt.clientX, evt.clientY);
	
	if (!ctrl)
	{
		panTargetChg(false);
	}
	else if (window.cnsp != ctrl)
	{
		window.cnsp = ctrl;
		ReplaceCssClass(ctrl, '', 'cnspd');
	}
}

// Panel movement complete.
function panMoveEnd(evt)
{
	var ctrl = window.pan;
	var div = FindParent(ctrl, 'DIV');

	ctrl.style.cursor = null;
	
	if (IsIE())
	{
		div.disabled = false;
		ctrl.onmousemove = null;
		ctrl.onmouseup = null;
		ctrl.releaseCapture();
	}
	else
	{
		SetOpacity(div, 100);
		document.onmousemove = null;
		document.onmouseup = null;
	}
	
	if (window.cnsp)
	{
		panDrop(window.pan, window.cnsp);
	}
	
	window.dropPos = null;		// #5975 - Drop target positions may change due to drop or scroll.

	panTargetChg(true);
}

// Determine if we're over a drop target and if so, return it.
function panGetDropTgt(x, y)
{
	var tgt = null;
	var ii;
	var div;

	//--- Find drop targets 1st time.

	if (!window.drops)
	{
		var divs = document.getElementsByTagName('div');

		window.drops = new Array();
		
		for (ii=0; ii<divs.length; ii++)
		{
			div = divs[ii];
			
			var cls = GetCssClass(div);
			
			if (cls && cls.match(/cnsp/))
			{
				window.drops.push(div);
			}
		}
	}

	//--- Determine target positions (recalc after any pane move).
	
	if (!window.dropPos)
	{
		for (ii=0; ii<window.drops.length; ii++)
		{
			div = window.drops[ii];
			
			div.top = getTop(div) - document.body.scrollTop;	// #5975 - Must adjust for scroll.
			div.left = getLeft(div) - document.body.scrollLeft;	// #5975 - Must adjust for scroll.
			div.bottom = div.top + div.offsetHeight;
			div.right = div.left + div.offsetWidth;
		}
		
		window.dropPos = true;
	}
	
	//--- Find target we're over, if any.
	
	for (ii=0; ii<window.drops.length; ii++)
	{
		div = window.drops[ii];
		
		if (x >= div.left && x <= div.right && y >= div.top && y <= div.bottom)
		{
			tgt = div;
			break;
		}
	}
	
	return (tgt);
}

// Change/eliminate drop target.
function panTargetChg(done)
{
	if (window.cnsp) RemoveCssClass(window.cnsp, 'cnspd');
	window.cnsp = null;
	
	if (done && window.pan) 
	{
		if (window.pan.mvr) 
		{
			document.body.removeChild(window.pan.mvr);
			window.pan.mvr = null;
		}
	
		window.pan = null;
	}
}

// Handle the drop.
function panDrop(ctrl, tgt)
{
	var div = ctrl.parentNode;
	var par = div.parentNode;
	var spacer = div.nextSibling;
	
	while (spacer && ElementType(spacer) != 'div')
	{
		spacer = spacer.nextSibling;
	}
	
	if (spacer != tgt)
	{	
		par.removeChild(div);
		if (spacer) par.removeChild(spacer);
		
		if (tgt.nextSibling)
		{
			tgt = tgt.nextSibling;
			
			tgt.parentNode.insertBefore(div, tgt);
			if (spacer) tgt.parentNode.insertBefore(spacer, tgt);
		}
		else
		{
			tgt.parentNode.appendChild(div);
			tgt.parentNode.appendChild(spacer);
		}
		
		if (ctrl.pernm)
		{
			panPersist(ctrl.pernm);
		}
	}
}

// Determine row number for the div in the td.
function panRowNum(div, td)
{
	var row = -1;
	var ii;
	
	for (ii=0; ii<td.childNodes.length; ii++)
	{
		if (td.childNodes[ii] == div) 
		{
			row = Math.ceil(ii/2);
			break;
		}
	}
	
	return (row);
}

// Persist the pane positions as a preference.
function panPersist(pernm)
{
	var tbls = document.getElementsByTagName('table');
	var ii;
	var s = '';
	
	for (ii=0; ii<tbls.length; ii++)
	{
		var tbl = tbls[ii];
		var pan = tbl.getAttribute('pan');
		
		if (pan)
		{
			var td = FindParent(tbl, 'td');
			var div = tbl.parentNode;
			var col = td.cellIndex;
			var row = panRowNum(div, td);
	
			s += pan + '@' + col + ',' + row + ';';
		}
	}
	
	AjaxPrefSet(pernm, s);
}

// Support hiding/unhiding groups in datasheet. #1921
function togRows(event, btn, grp, pernm)
{
	var row = FindParent(btn, 'tr').nextSibling;
	var hide = (row && row.style.display != 'none');
	
	btn.src = (hide) ? 'images/plus.gif' : 'images/minus.gif';
	
	while (row && 
			(HasCssClass(row, 'mapper') || HasCssClass(row, 'mapperalt') || HasCssClass(row, 'ftr')) &&
			!HasCssClass(row, 'agg'))	// #4526 - Not agg rows.
	{
		row.style.display = (hide) ? 'none' : '';
		row = row.nextSibling;
	}

	AjaxPrefSet(pernm, grp, (hide) ? 'add' : 'remove');
}

function OpenPrintableView()
{
    var html = '<html>\n<head>\n';

    if (document.getElementsByTagName != null)
    {
      var headTags = document.getElementsByTagName("head");
      if (headTags.length > 0)
          html += headTags[0].innerHTML;
    }
    
    //--- print css
    html += '<link href=\"styles/EAPPrint.css\" rel=\"stylesheet\" type=\"text/css\" />';

    html += '\n</head>\n<body>';

    html += document.body.innerHTML;

    html += '\n</body>\n</html>';

    var printWin = window.open("", "_blank");
    printWin.document.open();
    printWin.document.write(html);
    printWin.document.close();

    printWin.isPrintView = true;
}

function ShowPrintable()
{
    if (window.isPrintView && window.isPrintView == true)
        window.print();
    else
        OpenPrintableView();
}

// Register handler to warn if page is dirty. #2439
function InitDirtyCheck(msg)
{
	window.onbeforeunload = function() { if (!window.noDirtyCheck && IsWinDirty()) return msg; };
}

// Determine if window is dirty. #2439
function IsWinDirty(win)
{
	if (!win) win = window;

	if (!win.isSaving)
	{
		var ctrls = win.document.getElementsByTagName('input');
		var ii;
		
		if (window.isDirty) return true;		// Page explicitly marked dirty. #3892
		
		for (ii=0; ii<ctrls.length; ii++)
		{
			if (IsDirty(ctrls[ii])) return true;
		}
		
		ctrls = win.document.getElementsByTagName('option');
		
		for (ii=0; ii<ctrls.length; ii++)
		{
			if (IsDirty(ctrls[ii])) return true;
		}

		ctrls = win.document.getElementsByTagName('textarea');
		
		for (ii=0; ii<ctrls.length; ii++)
		{
			if (IsDirty(ctrls[ii])) return true;
		}
	}
	
	return false;
}

// Determine if ctrl is dirty. #2439
function IsDirty(ctrl)
{
	var dirty = false;
	var typ = ElementType(ctrl);
	
	if (ctrl.getAttribute('neverDirty') || (ctrl && ctrl.parentNode && ctrl.parentNode.getAttribute('neverDirty')))	// #3928 - Check parent too.
	{
		dirty = false;		// If explictly marked as not affecting page dirty state. #3892
	}
	else if (typ == 'text') // not currently checking hidden
	{
		dirty = (ctrl.defaultValue != ctrl.value);
	}
	else if (typ == 'checkbox' || typ == 'radio')
	{
		dirty = (ctrl.defaultChecked != ctrl.checked);
	}
	else if (typ == 'select')
	{
		dirty = (ctrl.defaultSelected != ctrl.selected);
	}
	else if (typ == 'option')
	{
		if (ctrl && ctrl.parentNode && ctrl.parentNode.parentNode && ctrl.parentNode.parentNode.getAttribute('neverDirty'))
			dirty = false;	// #3928, #3892 - In general we check parent above, for options need to check grandparent too.
		else
			dirty = (ctrl.defaultSelected != ctrl.selected);
	}
	else if (typ == 'textarea')
	{
		dirty = (ctrl.defaultValue != ctrl.value) ||  IsHtmlEditorDirty(ctrl);	// #5912
	}
	
	//--- Add dirty field info to F8 page info.
	
	if (dirty) 
	{
		var dirtyId = (typ == 'option') ? ctrl.parentNode.id : ctrl.id;
		RegDebugInfo('DirtyField', dirtyId, 'Script', 1);
	}
	
	return (dirty);
}

// #3386 - Apply access keys to radio buttons.
function AccessKeys()
{
	subs = document.getElementsByTagName('input');
	
	for (var ii=0; ii<subs.length; ii++)
	{
		var item = subs[ii];
		
		if (ElementType(item) == 'radio')
		{
			var par = item.parentNode;
			
			if (ElementType(par) == 'span' && par.getAttribute('accessKey'))
			{
				item.setAttribute('accessKey', par.getAttribute('accessKey'));
				par.removeAttribute('accessKey');
			}
		}
	}
}

// Navigate link if space or <CR> key pressed.
function LinkKeyPress(evt)
{
	if (!evt) evt = window.event;
	
	var key = GetEventKey(evt);
	
	if (key == 32 || key == 13)	// space or <CR>
	{
		var tgt = GetEventTarget(evt);
		
		if (tgt) DoClick(tgt);
	}
}

// Add keyboard handling to all anchors in IE.
function FixupAnchors()
{
	if (IsIE())
	{
		var anch = document.getElementsByTagName('a');
		
		for (var ii=0; ii<anch.length; ii++)
		{
			AddListener(anch[ii], "keypress", LinkKeyPress);
		}
	}
}

// #3513 - Tricky LinkButton locking.
function LinkBtnDis(btn)
{
	var ctl = GetElement(btn);
	
	if (ctl) ctl.removeAttribute('href');
}

function FindRole(item, role)
{
	var el = null;
	var ii; 
	
	if (item && item.childNodes)
	{
		for (ii=0; ii<item.childNodes.length; ii++) 
		{ 
			if (item.childNodes[ii].role == role)
			{
				el = item.childNodes[ii];
				break;
			}
			
			el = FindRole(item.childNodes[ii], role);
			if (el) break;
		} 
	}
	
	return (el);
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// START HoverSummary handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

function HovSmry(evt, mop, rk)
{
	if (!evt) evt = window.event;
	
	if (window.hovSmry)
	{
		window.clearTimeout(window.relHov);
		window.hovSmry = null;
	}
	
	//---
	
	var tgt = GetEventTarget(evt);

	if (tgt) 
	{
		tgt.ttt = 1;
		tgt.removeAttribute('title');
	}
	
	window.hovSmry = window.setTimeout(function () { HovSmryEnd(evt); HovSmryPop(tgt, mop, rk); }, 500);
	tgt.onmouseout = HovSmryEnd;
	
	//---
	
	var pop = document.getElementById('hovsmry');
	
	if (!pop)
	{
		pop = BubCreate(400);
		
		pop.id = 'hovsmry';
		pop.name = 'hovsmry';
		pop.seq = 0;				// #3875
	}

	return false;
}

function HovSmryEnd()
{
	if (window.hovSmry)
	{
		window.clearTimeout(window.hovSmry);
		window.hovSmry = null;
	}
	
	if (window.hovEnd)	// #4141
	{
		window.clearTimeout(window.hovEnd);
		window.hovEnd = null;
	}
	
	var pop = document.getElementById('hovsmry');
	
	if (pop)
	{
		pop.style.display = 'none';
	}
}

function HovSmryCancelAll()
{
	HovSmryEnd();

	var pop = document.getElementById('hovsmry');
	
	if (pop) pop.seq++;		// #3875 - Invalidate existing req.
}

function HovSmryPop(tgt, mop, rk)
{
	var pop = document.getElementById('hovsmry');

	if (pop)
	{
		pop.tgt = tgt;
		pop.seq++;				// #3875
		
		if (tgt.hoverSmry)
			HovSmryRsp('' + pop.seq + ';' + tgt.hoverSmry);	// Use cached response.
		else
			AjaxReq('pgsum', 'mop=' + mop + '&type=hov&pk=' + rk + '&seq=' + pop.seq, HovSmryRsp);
	}
}

function HovSmryRsp(txt)
{
	if (txt && txt.length > 0)
	{
		var semi = txt.indexOf(';');
		var seq = (semi > 0) ? parseInt(txt.substr(0, semi), 10) : -1;
		var pop = document.getElementById('hovsmry');
		
		//--- #3875 - Show only if in response to latest request.
		
		if (seq == pop.seq)
		{
			//--- #4141 - Close hover after 20 secs.
			
			if (window.hovEnd) window.clearTimeout(window.hovEnd);
			window.hovEnd = window.setTimeout(HovSmryEnd, 20000);
		
			var content = FindRole(pop, 'content');
			
			txt = txt.substr(semi+1);
		
			if (!pop.tgt.hoverSmry) pop.tgt.hoverSmry = txt;	// Cache response.
			
			content.innerHTML = txt;
			
			pop.style.left = 5000;					// Avoid flash by moving out of sight first.
			pop.style.top = 5000;
			pop.style.display = 'block';			// Now show
			
			var relocate = BubLocate(pop.tgt, pop);	// Position properly
			BubAdjust(pop, relocate);				// Adjust background
		}
	}
}

//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------
// END HoverSummary handling
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------------

// Experiment for #5542
function ColFocus(item)
{
	item = GetElement(item);
	
	if (item)
	{
		//alert(item.id);
		item.focus();//SetFocus(item);
		item.style.backgroundColor = '#ffff00';
		window.setTimeout(function() { item.style.backgroundColor = ''; }, 3000);
	}	
}

// Create a label element.
function CreateLabel(txt, assoc)
{
	var lbl = document.createElement('label');
			
	SetCellText(lbl, txt);
	
	if (assoc)
	{
		var assoc = GetElement(assoc);
		
		if (assoc && assoc.id) lbl.htmlFor = assoc.id;
	}
	
	return (lbl);
}

// Create a checkbox element.
function CreateCheckbox(id, checked)
{
	var chk = document.createElement('input');
	
	chk.type = 'checkbox';
	if (id) chk.id = id;
	//chk.checked = checked;
	chk.defaultChecked = checked;	// Only way to check checkbox in IE before element attached to doc.
	
	return (chk);
}

// Create a textbox element.
function CreateTextbox(id, s)
{
	var txt = document.createElement('input');
	
	txt.type = 'text';
	if (id) txt.id = id;
	if (id) txt.name = id;
	if (s) txt.value = s;
	
	return (txt);
}

// Create a button element.
function CreateButton(txt, onclick)
{
	var btn = document.createElement('input');
	
	btn.type = 'button';
	btn.value = txt;
	if (onclick) btn.onclick = onclick;
	
	return (btn);
}

// Explicitly remove all subnodes, recursively, from the specified node.
function ClearNodes(node)
{
	var ii;
	
	for (ii=0; node.childNodes && ii<node.childNodes.Length; ii++)
	{
		ClearNodes(node.childNodes[ii]);
	}
	
	while (node.childNodes && node.childNodes.length > 0)
	{
		node.removeChild(node.childNodes[0]);
	}
}

// Create a widget in a div element.
function CreateDivWidget(id, cap)
{
	var widget = document.getElementById(id);
	
	if (widget != null)
	{
		//--- Clear old content
		
		ClearNodes(widget.content);
		SetCellText(widget.caption, cap);
	}
	else
	{
		//--- Create widget div;

		widget = document.createElement('div');
		
		//AddDocEl(div, document);			// #3603 - Don't add elements to IE DOM until page load complete.
		widget.id = id;
		document.body.appendChild(widget);
		SetCssClass(widget, 'divwig');
		
		//--- Add banner.
		
		var ban = document.createElement('div');
		
		widget.appendChild(ban);
		SetCssClass(ban, 'wigban');
		
	    ban.onmousedown = DivWidMoveStart;
	    
		//--- Add close icon button and caption to banner.
		
		var caption = document.createElement('span');
		var tip = 'Click here to close';	// Caller's responsibility to localized using widget.btnClose
		var btn = CreateImgBtn('images/del16.gif', tip, function(evt) { widget.style.display = 'none'; return CancelBubble(evt); });

		SetCellText(caption, cap);
		SetCssClass(caption, 'wigcap');

		var tbl = document.createElement('table');
		var tr = tbl.insertRow(-1);
		var td = tr.insertCell(-1);
		
		td.appendChild(caption);
		td.style.width = '100%';
		tr.style.width = '100%';
		td.style.textAlign = 'center';
		
		td = tr.insertCell(-1);
		td.style.width = '100%';

		td.appendChild(btn);
		td.style.width = '20px';
		
		ban.appendChild(tbl);
		ban.style.width  = '100%';
		
		//--- Add shim for IE.
		
		if (IsIE())
		{
			var shim = CreateShim();
			
			shim.style.position = 'absolute';
			shim.style.left = -2;
			shim.style.top = -2;
			shim.style.zIndex = -1;
			shim.style.height = '100%';
			shim.style.width = '100%';
	        
			window.setTimeout(function() { shim.style.height = widget.offsetHeight; shim.style.width = widget.offsetWidth; }, 1);
			AddListener(widget, 'resize', function() { shim.style.height = widget.offsetHeight; shim.style.width = widget.offsetWidth; });	// #5554

			widget.insertBefore(shim, null);
		}
		
		//--- Add the content div where custom content will be injected.
		
		var content = document.createElement('div');
		
		content.style.width = '100%';

		var outer = document.createElement('div');	// Provides content padding.
		
		outer.appendChild(content);
		SetCssClass(outer, 'wigcon');

		widget.appendChild(outer);
		
		//---
		
		widget.content = content;
		widget.banner = ban;
		widget.caption = caption;
		widget.btnClose = btn;
	}

	return (widget);
}

// Handle start of DivWidget move.
function DivWidMoveStart(evt)
{
	if (!evt) evt = window.event;

	var widget = this.parentNode;
	
    widget.xStart = evt.clientX;
    widget.yStart = evt.clientY;
    widget.leftStart = widget.offsetLeft;
    widget.topStart = widget.offsetTop;
	if (IsIE()) widget.setCapture();
	
	window.divwid = widget;
		
    AddListener(widget, 'mousemove', DivWidMove);
    AddListener(widget, 'mouseup', DivWidMoveEnd);
    
    //--- For W3C-compliant browsers.
	
	if (document.body.addEventListener)
	{
		AddListener(document.body, 'mousemove', DivWidMove);
	}
	
// #5554 work in progress	
//	if (window.frameElement)
//	{
//		AddListener(window.frameElement, 'mousemove', DivWidMove);
//		AddListener(window.frameElement, 'mouseup', DivWidMoveEnd);
//	}
	
	return CancelBubble(evt);
}

// Handle DivWidget move.
function DivWidMove(evt)
{
    if (!evt) evt = window.event;
    
    var widget = window.divwid; //this;
    
    var left = widget.leftStart + (evt.clientX - widget.xStart);
    var top = widget.topStart + (evt.clientY - widget.yStart);
    
    if (left < 0) left = 0;		// #5076
    if (top < 0) top = 0;		// #5076
    
	widget.style.left = left + 'px';
	widget.style.top = top + 'px';
		
	if (widget.onMove) widget.onMove();			// #3217 - Call custom onmove handler, if any.
	
	return CancelBubble(evt);
}

// Handle end of DivWidget move.
function DivWidMoveEnd(evt)
{
    if (!evt) evt = window.event;

    var widget = window.divwid; //this;
    
	RemoveListener(widget, 'mousemove', DivWidMove);
	RemoveListener(widget, 'mouseup', DivWidMoveEnd);
    
    //--- For W3C-compliant browsers.
	
   	if (document.body.addEventListener)
	{
		RemoveListener(document.body, 'mousemove', DivWidMove);
	}

	if (IsIE()) widget.releaseCapture();
	
	if (widget.onMoveEnd) widget.onMoveEnd();	// #3217 - Call custom onmoveend handler, if any.
	
	return CancelBubble(evt);
}

// Create an img to use as a button element.
function CreateImgBtn(icon, tip, clickFn)
{
    var btn = document.createElement('IMG');
    
    btn.src = icon;
    //SetTip(btn, tip);
    SetCssClass(btn, 'actimg');
	//AddListener(btn, 'click', clickFn);

    var anch = document.createElement('A');

   	AddListener(anch, 'click', clickFn);	// Opera ignores this if on btn.
    anch.href = '#';
    SetCssClass(anch, 'actimg');
    SetTip(anch, tip);

    anch.appendChild(btn);
    btn = anch;
    
    return (btn);
}

// #3855 - Close the specified optional column in a datasheet and persist the new state.
function CloseCol(btn, key, mop, op)
{
	btn.parentNode.style.width = '0';			// This is enough for IE.
	if (op == '-')
		AjaxPrefSet('optfld:' + mop, '-' + key, 'add');	// #4858 - Explicitly hide
	else
		AjaxPrefSet('optfld:' + mop, key, 'remove');	// #4858 - Stop explicitly showing
	
	if (!IsIE())
	{
		var th = FindParent(btn, 'th', true);
		var tbl = FindParent(th, 'table', true);
		var iCol = th.cellIndex;
		var	ii;
		
		SetCssClass(th, 'dshide');					// Seems needed on Safari (Mac)
		
		for (ii=0; ii<tbl.rows.length; ii++)
		{
			var cell = tbl.rows[ii].cells[iCol];
			
			if (cell) SetCssClass(cell, 'dshide');	// Other browsers need this.
		}
	}
	
	return false;
}

// #3917 - Disable control.
function DisableCtrl(c)
{
	var elType = ElementType(c);
	
	if (elType == 'a')
	{
		c.onclick = function () { return false; };
		window.setTimeout(function() { c.style.color = 'silver'; }, 1);
	}
}

// Set up events for dragging a control.
function DragInit(ctrl, fnMouseMove, fnMouseUp, subCapture)
{
	AddListener(ctrl, 'mousemove', fnMouseMove);
	AddListener(ctrl, 'mouseup', fnMouseUp);
	
	if (IsIE())
	{
		ctrl.setCapture();
	}
	else if (document.body.addEventListener)
	{
		AddListener(document.body, 'mousemove', fnMouseMove);
		AddListener(document.body, 'mouseup', fnMouseUp);
		
		//--- Also need to capture mouse on this window's iframes (at least for Firefox).
		
		if (subCapture && window.frames)
		{
			var ii;

			for (ii=0; ii<window.frames.length; ii++)
			{
				var bdy = window.frames[ii].document.body;
				
				AddListener(bdy, 'mousemove', fnMouseMove);
				AddListener(bdy, 'mouseup', fnMouseUp);
			}
		}
	}
}

// Clean up events for dragging a control.
function DragTerm(ctrl, fnMouseMove, fnMouseUp, subCapture)
{
	RemoveListener(ctrl, 'mousemove', fnMouseMove);
	RemoveListener(ctrl, 'mouseup', fnMouseUp);
	
	if (IsIE())
	{
		ctrl.releaseCapture();
	}
	else if (document.body.addEventListener)
	{
		RemoveListener(document.body, 'mousemove', fnMouseMove);
		RemoveListener(document.body, 'mouseup', fnMouseUp);
		
		//--- Also need to capture mouse on this window's iframes (at least for Firefox).
		
		if (subCapture)
		{
			var ii;

			for (ii=0; ii<window.frames.length; ii++)
			{
				var bdy = window.frames[ii].document.body;
				
				RemoveListener(bdy, 'mousemove', fnMouseMove);
				RemoveListener(bdy, 'mouseup', fnMouseUp);
			}
		}
	}
}

// Wizard summary resizing handler needed in IE6 because it doesn't support max-height.
function WizSumResize(pan)	// #4655
{
	var max = pan.style.getAttribute('max-height');	// Style not supported by IE6.
	
	if (max)
	{
		var ii;
		var h = 0;
		
		max = max.replace(/px/,'');
		
		for (ii=0; ii<pan.childNodes.length; ii++)
		{	
			h += pan.childNodes[ii].offsetHeight;
		}
		
		if (h > max)
			pan.style.setAttribute('height', max);
		else
			pan.style.height = null;//0;//pan.style.removeAttribute('height');
	}
}

// Console Pane max-height implemention needed in IE6 because it doesn't support max-height.
function PaneMaxHeight(pane)	// #5131
{
	if (MaxHeight(pane))
	{
		RepaintConsole();
	}
}

// Element max-height implemention needed in IE6 because it doesn't support max-height.
function MaxHeight(ctl)
{
	var applied = false;
	var max = ctl.style.getAttribute('max-height');	// Style not supported by IE.
	
	if (max)
	{
		var h = ctl.offsetHeight;
	
		max = parseInt(max.replace(/px/,''));
	
		if (h > max)
		{
			ctl.style.height = max;
			applied = true;
		}
		else
		{
			ctl.style.height = null;
		}
	}
	
	return (applied);
}

// Repaint console page content.
function RepaintConsole()
{
	Repaint(GetElement('contentTable'));	// Console content root
}

// Repaint a control.
function Repaint(ctl)
{
	ctl.style.display = 'none';
	ctl.style.display = '';
}

// Hide item
function DisplayNone(item)
{
	item = GetElement(item);
	if (item) item.style.display = 'none';
}

// Enable/disable item
function ElementEnable(item, b)		// #4903 helper
{
	item = GetElement(item);
	if (item) item.disabled = !b;
}

//------------------------- Div FilterWidgets ---------------------------

//function fwtxtToggleDiv(evt, txt, caption)
//{
//	FltWidget(evt, txt, caption);
//}

// #4782 - Request FilterWidgetText content.
function FltWidget(evt, req, txt, caption)
{
	var params = '';
	var wid = 'fw';
	
	//--- #5971 - Custom filter widget.
	
	if (req.indexOf(':'))
	{
		var parts = req.split(':');
		
		req = parts[0];
		wid = parts[1];
	}
	
	params += 'id=' + txt.id;
	params += '&txt=' + encodeURIComponent(txt.value);
	params += '&cap=' + encodeURIComponent(caption);
	params += '&wid=' + wid;
	params += '&x=' + evt.clientX + '&y=' + evt.clientY;

	JsonReq(req, params, FltWidgetContent);
}

// #4782 - Receive FilterWidgetText response and create widget.
function FltWidgetContent(widObj)
{
	if (widObj.__type == 'error')
	{
		alert(widObj.message);
	}
	else
	{
		var widget = CreateDivWidget(widObj.WidgetId, 'Filter');
		var html = widObj.Content;
		
		SetCellText(widget.caption, widObj.Caption);
		widget.content.innerHTML = html;
		SetTip(widget.btnClose, widObj.CloseTip);

		widget.style.width = (widObj.width) ? widObj.width : 300;

		PositionDiv(widget, widObj.x, widObj.y);
		
		SetFocusFirst(widget.content, true, true);
	}
}

// Position an element adjusting top and left so that it fits on screen.
function PositionDiv(div, x, y)
{
	div.style.visibility = 'hidden';	// Must not be display=none for offsetWidth & offsetHeight to be non-zero.
	div.style.display = 'block';		//   so set visibility to hide then display to block.
	div.style.top = 1 + 'px';			// Position top left of window.
	div.style.left = 1 + 'px';

	var l = x;
	var t = y;
	var w = div.offsetWidth;
	var h = div.offsetHeight;
	
	if (l + w > GetClientWidth())
		l = GetClientWidth() - w;		// Adjust left if otherwise it would run off window to right.
	if (document.body && document.body.scrollLeft) l += document.body.scrollLeft;	// #5421 - Adjust coords.
	if (t + h > GetClientHeight())
		t = GetClientHeight() - h;		// Adjust top if otherwise it would run off window to bottom.
	if (document.body && document.body.scrollTop) t += document.body.scrollTop;		// #5421 - Adjust coords.

	if (t < 0) t = 0;
	if (l < 0) l = 0;

	div.style.left = l;
	div.style.top = t;

	div.style.visibility = 'visible';	// Now make it visible.
}

function fwrsToggleDiv(evt, txt, pick, cap)
{
	var params = '';
	
	params += 'id=' + txt.id;
	params += '&txt=' + encodeURIComponent(txt.value);
	params += '&pick=' + pick;
	params += '&cap=' + encodeURIComponent(cap);
	params += '&wid=' + 'fw';
	params += '&x=' + evt.clientX + '&y=' + evt.clientY;

	var opts = txt.getAttribute('widopt');
	
	if (opts) params += '&opts=' + opts;	// #5466

	JsonReq('fwpick', params, FltWidgetContent);
}

function FltWidgetPickContent(widObj)
{
}

function FWKeyUp(txt, lst, pick)
{
	lst = GetElement(lst);
	
	var last = (lst.last && lst.last != '') ? lst.last : txt.defaultValue;
	var cur = txt.value;
	
	if (last) last = last.toLowerCase();
	if (cur) cur = cur.toLowerCase();
	
	var cnt = lst.options.length;
	var more = (cnt > 0 && lst.options[cnt-1].value.match(/^!more!*/));	// #5598 - If list not complete, always fetch.

	if (last && last != '' && cur.indexOf(last) == 0 && !more) // a refinement of existing search
	{
		var ii;
		
		for (ii=lst.options.length-1; ii>=0; ii--)	// Backwards since we're removing.
		{
			var opt = lst.options[ii];
			
			if (opt.text.toLowerCase().indexOf(cur) != 0)
			{
				lst.removeChild(opt);
			}
		}
	}
	else // need to fetch
	{
		var seq = (lst.seq) ? lst.seq + 1 : 1;
		
		lst.seq = seq;
		if (lst.req) window.clearTimeout(lst.req);
		lst.req = window.setTimeout(function() { AjaxReq('pick', 'ver=3&pick=' + pick + '&text=' + cur + '&lim=100&seq=' + seq + '&lst=' + lst.id, FWPick); }, 250);	// #5598 - v3
	}
	
	lst.last = cur;
}

function FWPick(txt)
{
	var parts = txt.split('|');
	var prefix = parts[0].split(';');
	var seq = prefix[1];
	var lst = GetElement(prefix[2]);
	var flags = prefix[3];				// #5598
	
	if (seq == lst.seq)
	{
		var items = parts[1].split(';');
		var ii;

		if (lst.options.length > 0)
		{
			lst.value = lst.options[0].value;	// #5598 - Fix for Chrome painting issue.
			lst.options.length = 0;
		}

		for (ii=0; ii<items.length; ii++)
		{
			AddOption(lst, items[ii]);
		}

		//--- #5598 - Handle "more" flag.

		if (flags && flags.indexOf('m') >= 0 && lst.options.length > 0)
		{
			lst.options[lst.options.length-1].value = '!more!';
		}
	}
}

function FWSet(lst, conj)
{
	var ii;
	var s = '';
	
	conj = ' ' + conj + ' ';
	
	for (ii=0; ii<lst.options.length; ii++)
	{
		if (lst.options[ii].selected)
		{
			s += conj + lst.options[ii].text;
		}
	}
	
	if (s.length > 0) s = s.substring(conj.length);
	
	return (s);
}

// #5598 - Handle click on (more) item in picklist filter widget.
function FWMore(evt, lst)
{
	//--- #5598 - Handle click on list (IE doesn't fire click on option item itself).
	//--- Also, IE requires a delay so the selection can take effect before we retrieve
	//--- it to determine of (more) was clicked.
	
	window.setTimeout(function() 
	{
		if (lst.value.match(/^!more!*/))
		{
			lst.style.cursor = 'wait';
			
			var params = 'id=' + lst.id;
			
			params += '&pick=' + lst.getAttribute('pick');
			params += '&skip=' + lst.options.length;
			if (lst.last) params += '&text=' + lst.last;
			
			JsonReq('fwpickmore', params, FWMoreRsp);
		}
	}, 1);
}

// #5598 - Handle AJAX response to click on (more) item in picklist filter widget.
function FWMoreRsp(rsp)
{
	if (rsp.count)
	{
		var cbo = GetElement(rsp.id);
		var ii;
		
		cbo.options.length--;	// Remove old (more) item.
		
		for (ii=0; ii<rsp.count; ii++)
		{
			AddOption(cbo, rsp.txts[ii], rsp.vals[ii]);
		}
	}

	cbo.style.cursor = '';
}

// #4957
function MultiSelDiv(evt, ctrl, opts, pick)
{
	var cap = bndLkupTable(ctrl).getAttribute('caption');
	var txt = document.getElementById(bndLkupTxtFromBtn(ctrl));
	var wm = txt.getAttribute('wm');

	var lkup = bndLkupTable(ctrl);
	var delim =  lkup.getAttribute('delim');				// #5338
	
	var params = '';
	
	params += 'id=' + txt.id;
	params += '&txt=' + encodeURIComponent(txt.value);
	params += '&pick=' + pick;
	params += '&opts=' + opts;
	params += '&cap=' + encodeURIComponent(cap);
	params += '&wid=' + 'msw';
	params += '&x=' + evt.clientX + '&y=' + evt.clientY;
	params += '&width=225px';
	if (delim) params += '&delim=' + delim;					// #5338
	if (wm) params += '&wm=' + encodeURIComponent(wm);

	JsonReq('msw', params, FltWidgetContent);
}

function MultiSelSet(chkbase, delim, txt, checks)
{
	var clause = '';
	var chk;
	var ii;

	if (checks)
	{
		for (ii=0; ii<1000; ii++)
		{
			chk = document.getElementById(chkbase + ii);
			
			if (!chk) break;
			
			if (chk.checked)
			{
				clause += delim + chk.value;
				//clause += delim + InnerHTML(FindLabelFor(chk));
			}
		}
	}
	else
	{
		var lst = document.getElementById(chkbase);
		
		for (ii=0; ii<lst.options.length; ii++)
		{
			if (lst.options[ii].selected)
			{
				clause += delim + lst.options[ii].value;
			}
		}
	}

	if (clause.length > 0) clause = clause.substr(1);

	txt = GetElement(txt);

	if (txt.value != clause)
	{
		txt.value = clause;
		OnChange(txt);
	}
}

// Called by DateFilterWidget (#5269)
function DateWidSet(btn, fbf)
{
	var rad = RadioButtonSel('dtflttype');
	
	if (rad)
	{
		var val = rad.value;
		var fbf = GetElement(fbf);
		
		if (val == 'on')
		{
			fbf.value = GetElement('dtfw_dt_txt').value;
		}
		else if (val == 'range')
		{
			var pat = rad.parentNode.getAttribute('pattern');
			
			fbf.value = pat.replace(/%1/, GetElement('dtfw_from_txt').value).replace(/%2/, GetElement('dtfw_to_txt').value);
		}
		else if (val == 'count')
		{
			var ln = GetElement('dtflt_ln');
			var cnt = GetElement('dtflt_cnt');
			var per = GetElement('dtflt_per');

			fbf.value = CboText(ln) + ' ' + CboText(cnt) + ' ' + CboText(per);
		}
		else if (val == 'monyr')
		{
			fbf.value = CboValue(GetElement('dtflt_mon')) + ' ' + CboText(GetElement('dtflt_yr'));
		}
		else
		{
			fbf.value = val;
		}
		
		OnChange(fbf);
	}
}

// Called by NumberFilterWidget (#2350)
function NumWidSet(btn, fbf)
{
	var rad = RadioButtonSel('numflttype');
	
	if (rad)
	{
		var val = rad.value;
		var fbf = GetElement(fbf);
		var pat = rad.parentNode.getAttribute('pattern');
		
		if (val == '=')
		{
			fbf.value = GetElement('numfw_exact').value;
		}
		else if (val == 'op')
		{
			fbf.value = CboValue(GetElement('numfw_op')) + ' ' + GetElement('numfw_comp').value;
		}
		else if (val == 'range')
		{
			fbf.value = pat.replace(/%1/, GetElement('numfw_from').value).replace(/%2/, GetElement('numfw_to').value);
		}
		else if (val == '<>')
		{
			fbf.value = '<> ' + GetElement('numfw_not').value;
		}
		else if (val == 'approx')
		{
			fbf.value = GetElement('numfw_approx').value + ' +/- ' + GetElement('numfw_margin').value + CboValue(GetElement('numfw_percent'));
		}
		else if (val == 'notnull')
		{
			fbf.value = pat;
		}
		else if (val == 'null')
		{
			fbf.value = pat;
		}
		else
		{
			fbf.value = val;
		}
		
		OnChange(fbf);
	}
}

// Open a url in a DivWidget 
function OpenIWin(url, tgt, cap)	// #5554
{
	var widget = CreateDivWidget(tgt, cap);
	var content = widget.content;

	widget.style.top = Mouse.y - 20;
	widget.style.left = Mouse.x - 20;
	widget.style.width = 300;
	widget.style.display = 'block';
	
	widget.style.height = 200;
	
	var iframe = document.createElement('iframe');

	iframe.frameBorder = '0';

	content.appendChild(iframe);
	iframe.style.width = '100%';
	if (!IsIE()) iframe.style.height = '100%';
	iframe.scrolling = 'no';
	iframe.name = tgt;
	iframe.src = url + '&div=0x00000001';
	
	iframe.widget = widget;
	//widget.iframe = iframe;
}

function CloseIWin()				// #5554
{
	window.frameElement.widget.style.display = 'none';
}

function SizeIWinToCtrl(ctrlID)		// #5554
{
//	//--- Need handling in non-IE when cursor strays into iframe content during move.
//	if (document.body.addEventListener)
//	{
//		window.divwid = window.frameElement.widget;
//		AddListener(document.body, 'mousemove', DivWidMove2);
//	    AddListener(document.body, 'mouseup', DivWidMoveEnd2);
//	}

	window.sizingToFit = true;			// Gets hsplit in correct spot.
	ResizeIWin(GetElement(ctrlID));
}

function ResizeIWin(ctrl, win)			// #5554
{
	var width = /*(IsIE()) ? ctrl.offsetWidth + 40 :*/ FarRight(ctrl) + 30;
	var height = OffsetBottom(ctrl.id);// + 25;
	
	if (!win) win = window;
	//ctrl.style.height = ctrl.offsetHeight + 10;
	
	if (!IsIE()) 
		height += 0;//40;
//	else
//		height -= 20;
//	
	if (height > screen.height - 50)
	{
		height = screen.height - 150;	// Seems safe for all browsers w/ Opera being the limiting factor.
	}
	
//	alert(screen.width);
//	alert(width);
	if (width > screen.width/2)
	{
		width = screen.width/2;
	}
	
	var iframe = win.frameElement;
	var widget = iframe.widget;
	
	//widget.content.style.backgroundColor = 'pink';

//alert(widget.banner.offsetHeight);
//alert(height + widget.banner.offsetHeight);
	widget.style.width = width + 'px'; //FarRight(ctrl) + 50; //window.origWidth; //WindowWidth(window) + 'px'; //800;
	widget.style.height = (height + widget.banner.offsetHeight + 5);// + 'px';// + 10; //OffsetBottom(ctrl.id) + 40; //GetClientHeight(window); //window.origHeight; //WindowHeight(window) + 'px';//600;
	
	if (IsIE())
	{
		//iframe.style.width = '100%';//width-10; //'100%'; //width; //'100%';
		iframe.style.height = height + 0;//40;// + 30;//+40;// + 10; //'100%';
	}
	else if (IsSafari() || IsOpera())
	{
		iframe.style.height = height;// + 30;//+40;// + 10; //'100%';
	}
	else
	{
		// Verified on FF v3.0, and Chrome v2.0
//	//	iframe.style.width = '100%'; //width; //'100%';
		iframe.style.height = (height + 0) + 'px';//'100%'; //height; //'100%';
		//iframe.style.height = (height - 20) + 'px';// + 30;//+40;// + 10; //'100%';
	}

//	window.setTimeout(function() { widget.content.style.left = '1'; }, 1);	// IE doesn't show border otherwise!
	//SetCellText(widget.caption, widget.caption = 'w=' + width + ',h=' + height);
}

// #5554 work in progress, need to handle div move when mouse strays into iframe on non-IE browsers.
function DivWidMove2(evt)
{
    if (!evt) evt = window.event;
    
    var widget = window.divwid; //this;
    
    var left = widget.leftStart + ((evt.clientX + getLeft(widget)) - widget.xStart);
    var top = widget.topStart + ((evt.clientY + getTop(widget)) - widget.yStart);
    
    if (left < 0) left = 0;		// #5076
    if (top < 0) top = 0;		// #5076
    
	widget.style.left = left + 'px';
	widget.style.top = top + 'px';
		
	if (widget.onMove) widget.onMove();			// #3217 - Call custom onmove handler, if any.
	
	return CancelBubble(evt);
}

// #5554 work in progress, need to handle div move when mouse strays into iframe on non-IE browsers.
function DivWidMoveEnd2(evt)
{
    if (!evt) evt = window.event;

    var widget = window.divwid; //this;
    
	RemoveListener(widget, 'mousemove', parent.DivWidMove);
	RemoveListener(widget, 'mouseup', parent.DivWidMoveEnd);
    
    //--- For W3C-compliant browsers.
	
   	if (document.body.addEventListener)
	{
		RemoveListener(parent.document.body, 'mousemove', parent.DivWidMove);
		RemoveListener(parent.document.body, 'mouseup', parent.DivWidMoveEnd);
		RemoveListener(document.body, 'mousemove', DivWidMove2);
		RemoveListener(document.body, 'mouseup', DivWidMoveEnd2);
	}

	if (IsIE()) widget.releaseCapture();
	
	if (widget.onMoveEnd) widget.onMoveEnd();	// #3217 - Call custom onmoveend handler, if any.
	
	return CancelBubble(evt);
}

// Append a css file to the current document. #5575
function appendCss(path)
{
	var css = document.createElement('link');
	
	css.setAttribute('rel', 'stylesheet');
	css.setAttribute('type', 'text/css');
	css.setAttribute('href', path);

	document.getElementsByTagName('head')[0].appendChild(css)
}

function FindDatasheet()
{
	var tbls = document.getElementsByTagName('table');
	var ii;
	
	for (ii=0; ii<tbls.length; ii++)
	{
		if (tbls[ii].getAttribute('use') == 'ds') return tbls[ii];
	}
}

function DatasheetFields()
{
	var ds = FindDatasheet(); //GetElement('list_grid_ctlcont000041');
	var tr = (!IsIE()) ? ds.rows[0] : ds.firstChild;
	var th;
	var ii;
	//var s = '';
	var cap;
	var key;
	var arr = new Array();
	var fld;
	
	if (ElementType(tr) != 'tr') tr = tr.firstChild;
	
	var fbf = (!IsIE()) ? tr.nextSibling : tr.nextSibling.nextSibling;
	var cnt = (!IsIE()) ? tr.cells.length : tr.childNodes.length;
	
	for (ii=0; ii<cnt; ii++)
	{
		th = (!IsIE()) ? tr.cells[ii] : tr.childNodes[ii];
		
		key = th.getAttribute('key');
		cap = InnerHTML(th);
		
		if (cap && cap.search(/\S/) >= 0 && key && key.length > 0)
		{
		//	s += ';' + cap;
		//	s += '=' + key;
			fld = new Object();
			fld.caption = cap;
			fld.key = key;
			//fld.id = th.id;
			fld.sortId = (ElementType(th.firstChild) == 'a') ? th.firstChild.id : null;
			fld.idx = ii;
			fld.fbfId = (!IsIE()) ? fbf.cells[ii].firstChild.id : fbf.childNodes[ii].firstChild.id;
			//if (ii == 10) alert(fld.fbfId);
			
			arr.push(fld);
		}
	}
	
	arr.sort(captionSort);
	
//	return (s);
	return (arr);
}

function ColFocus2(a, fld, widget)
{
	//a.onclick = function() { ColFocus(fld.sortId); widget.style.display = 'none'; return false; }
	//a.onclick = function() { alert(fld.fbfId); }
	var tgt = (fld.fbfId) ? fld.fbfId : fld.sortId;
	
	a.onclick = function() { ColFocus(tgt); widget.style.display = 'none'; return false; }
}

function PopFlt2(img, fbfId)
{
	img.onclick = function(evt) { if (!evt) evt = event; fwToggle(evt, GetElement(fbfId)); }
	
	var el = GetElement(fbfId);
	
	if (el)
	{
		//AddListener(el, 'change', function() { UpdateFlt(fbfId); } );
		el.onchange = function() { UpdateFlt(fbfId); };
	}
}

function UpdateFlt(id)
{
	var src = GetElement(id);
	var dst = GetElement(id + '_xx');
	
	if (src && dst)
	{
		dst.value = src.value;
	}
}

function captionSort(a, b) 
{
	return sortCaseInsensitive(a.caption, b.caption);
} 

// Ajax call to clear app-wide navbars.
function FlushNavBar()	// #5786
{
	AjaxReq('clrnb');
}

// Start immediate save.
function ImmedSave(item, sig, val)		// #5811
{
	ReplaceCssClass(item, '', 'immedsv');
	
	var seq = (item.seq) ? item.seq + 1 : 1;
	
	item.seq = seq;
	if (item.req) window.clearTimeout(item.req);

	item.req = window.setTimeout(function() { AjaxReq('immedsv', 'sig=' + sig + '&val=' + val, function(rsp) { ImmedSaveRsp(rsp, item, seq); }); }, 1000);
}

// Receive response to immediate save request.
function ImmedSaveRsp(rsp, item, seq)		// #5811
{
	if (rsp && rsp.indexOf('!err!') == 0)
	{
		alert(rsp.replace(/!err!/,''));
	}
	else if (seq == item.seq)
	{
		ReplaceCssClass(item, 'immedsv', '');
	}
}

// Immediate save of rolling picklist field change.
function ImmedRoll(evt, item, sig)		// #5811
{
	var cv = item.getAttribute('cv');
	var pick = item.getAttribute('pick');
	var items = pick.split(';');
	var ii;
	var idx = -1;
	
	for (ii=0; ii<items.length; ii++)
	{
		if (items[ii].indexOf(cv + '=') == 0)
		{
			idx = (ii+1 < items.length) ? idx = ii+1 : 0;
			break;
		}
	}
	
	if (idx >= 0)
	{
		InnerTextSet(item, items[idx].split('=')[1]);
		
		var val = items[idx].split('=')[0];
		
		item.setAttribute('cv', val);
		ImmedSave(item, sig, val);
	}
}

// Immediate save of date field change.
function ImmedDate(evt, item, sig, fmt, strs, cul, cap)		// #5811
{
	var hid = GetElement('idphtb');
	var notSet = item.getAttribute('notset');
	
	if (!hid) 
	{
		hid = AddHiddenInput(item, 'idphtb', '');
	//	hid.type = 'text';
	}
	
	hid.value = InnerTextGet(item);
	hid.onchange = function() { InnerTextSet(item, (!hid.value || hid.value == '') ? notSet : hid.value); ImmedSave(item, sig, hid.value); };

	bndLkupCal(evt, hid, fmt, strs, cul, cap);
}

// Bind NavBar to persist node expand/collapse state.
function NavBarBind(delay)	// #5830
{
	if (delay)
	{
		window.setTimeout(function() { NavBarBind(0); }, delay);
		return;
	}
	
	if (nbexpids)
	{
		var ii;
	
		for (ii=0; ii<nbexpids.length; ii++)
		{
			var exp = GetElement(nbexpids[ii]);
			if (exp) exp = FindParent(exp, 'table');
			if (exp)
			{
				var handlerCreator = function(tbl) { return function() { NavBarExpTog(tbl); } };
				
				exp.setAttribute('prf', nbexpids[ii].replace(/_/g, ':'));
				AddListener(exp, 'click', handlerCreator(exp));
			}
		}
	}
}

// Persist NavBar node expand/collapse state.
function NavBarExpTog(tbl)	// #5830
{
	var div = tbl.nextSibling;
	var closing = (div && ElementType(div) == 'div' && div.style.display != 'none');
	var prf = tbl.getAttribute('prf');

	AjaxPrefSet(prf, (closing) ? '0' : '1');
}

//---- RadEditor utility code

// Determine dirty status of HtmlEditor.
function IsHtmlEditorDirty(ctrl) // #5912
{
	var editor = (window.$find) ? window.$find(ctrl.id) : null;		// $find() will exist only if Telerik is loaded.
	var cmdMgr = (editor) ? editor.get_commandsManager() : null;
	
	return (cmdMgr && cmdMgr.getCommandsToUndo && cmdMgr.getCommandsToUndo().length > 0);
}

// Check if HtmlEditor html is too long.
function HtmlEditorTooLong(ctrl, len)		// #5599
{
	var editor = (window.$find) ? window.$find(ctrl.id) : null;		// $find() will exist only if Telerik is loaded.
	
	return (editor && editor.get_html().length > len);
}

function HtmlEditorLoad(id, html)
{
	var editor = (window.$find) ? window.$find(id) : null;			// $find() will exist only if Telerik is loaded.

	if (editor) editor.set_html(html);
}

//------------

//function EscCrHandler(evt, widget)
//{
//	var	rtn = true;
//
//	if (!evt) evt = window.event;
//	
//	if (evt.keyCode == 27)
//	{
//		//fwrsHide(0);	// <esc> enterred, cancel.
//		alert('escape');
//	}
//	else if (evt.keyCode == 13)
//	{
//		//fwrsHide(1);	// <cr> enterred, save.
//		alert('cr');
//		rtn = false;
//	}
//	
//	return (rtn);
//}

// Position an item in the window.
function PosInWin(item)
{
	//--- Adjust x position when widget would be out of window.
	
	var xScroll = (document && document.body) ? document.body.scrollLeft : 0;	// #3564
	var posx = item.offsetLeft;
	var posy = item.offsetTop;
	var winWidth = WindowWidth(window);
	var winHeight = WindowHeight(window);
	
//	winHeight = GetClientHeight(window);
//	winWidth = GetClientWidth(window);
	
	if (posx < 0)
	{
		posx = 0;
	}
	else if (posx + item.offsetWidth - xScroll > winWidth && winWidth - item.offsetWidth >= 0)
	{
		posx = winWidth - item.offsetWidth;
		
//		if (posx + item.offsetWidth > winWidth)
//		{
//			posx = winWidth - item.offsetWidth - 1;
//		}
	}
		
	//--- Adjust y position when tip would be out of window.
	
	if (posy < 0)
	{
		posy = 0;
	}
	else if (posy + item.offsetHeight > winHeight && winHeight - item.offsetHeight >= 0)
	{
		posy = winHeight - item.offsetHeight;
		
	}
	
	//--- Now actually position the tip.
	
	if (posx != item.offsetLeft) item.style.left = posx + 'px';
	if (posy != item.offsetTop) item.style.top = posy + 'px';
}

//------------- #6012 - User-configurable optional element handling.

// Ajax request for optional element management widget (originally console panes, now other elements as well).
function ConOpts(req, args, win)
{
	HovSmryCancelAll();
	JsonReq(req, args + '&ver=1', function(rsp) { ConOptRsp(rsp, win); }, 0);
}

// Present console optional element management widget.
function ConOptRsp(rsp, win)	// #6012
{
	//--- Parse JSON response.
	
	var ver = rsp.ver;
	var cap = rsp.caption;
	var okCap = rsp.ok;
	var closeTip = rsp.close;
	var mop = rsp.mop;
	var items = rsp.items;

	//---
	
	var widget = CreateDivWidget('optpanes', cap);
	var content = widget.content;
	SetTip(widget.btnClose, closeTip);

	widget.style.top = Mouse.y - 20;
	widget.style.left = Mouse.x - 20;
	widget.style.width = 250;
	widget.style.display = 'block';
	
	window.setTimeout(function() { content.style.left = '1'; }, 1);	// IE doesn't show border otherwise!
	
	//--- #3854 - Put content in fixed height div for scrolling on large sets.
	
	var div = document.createElement('div');
	
	div.style.height = 200;
	div.style.overflow = 'auto';
	div.style.margin = '0 0 5px 0';
	
	content.appendChild(div);
	
	//--- Add content.
	
	var ii;
	var chks = new Array();
	
	var tbl = document.createElement('table');
	div.appendChild(tbl);

	for (ii=0; ii<items.length; ii++)
	{
		var pane = items[ii];
		
		if (pane)
		{
			var parts = pane.split('|');
			var key = parts[0];
			var caption = (parts.length > 1) ? parts[1] : key;
			var flags = (parts.length > 2) ? parseInt(parts[2]) : 0;
			var on = (0 != (flags & 0x00000001));
			var tr = tbl.insertRow(-1);
			var td = tr.insertCell(-1);
			
			var chk = CreateCheckbox('itemchk_' + key, on);
			chk.key = key;
			chk.flags = flags;		// #4858 - Identifies as hidden or shown by default.
			td.appendChild(chk);
			
			td = tr.insertCell(-1);
			td.appendChild(CreateLabel(caption, chk));
						
			chks.push(chk);
		}
	}
	
	//---
	
	if (rsp.deviceFlags && rsp.deviceFlags.indexOf('s') >= 0 && tbl.offsetHeight > div.offsetHeight)
	{
		SetCssClass(div, 'ovflwind');
	}
	
	//---
		
	HovSmryCancelAll();			// #3875

	div = document.createElement('div');

	var btn = CreateButton((okCap) ? okCap : 'OK', function() { ConOptSave(rsp.pref, chks, win); widget.style.display = 'none'; });
	
	SetCssClass(btn, 'mapper');
	btn.style.width = '33%';
	div.style.margin = '5px';
	
	div.appendChild(btn);

	btn = CreateButton((rsp.cancel) ? rsp.cancel : 'Cancel', function() { widget.style.display = 'none'; });
	btn.title = closeTip;
	
	SetCssClass(btn, 'mapper');
	btn.style.width = '33%';
	btn.style.marginLeft = '5px';
	
	div.style.margin = '5px';
	div.appendChild(btn);

	content.appendChild(div);
	
	//---
	
	if (rsp.hint)
	{
		div = document.createElement('div');
		var span = document.createElement('span');
		SetCssClass(span, 'hint');
		div.style.margin = '5px';

		span.appendChild(document.createTextNode(rsp.hint));
		div.appendChild(span);
		content.appendChild(div);
	}
	
	//---
	
	PosInWin(widget);
}

// Save settings from console optional element management widget.
function ConOptSave(prefNm, chks, win)		// #6012
{
	var pref = '';
	var ii;
	
	if (!win) win = window;	// Window passed in when widget presented on top pane, but bottom pane should be refreshed.
	
	for (ii=0; ii<chks.length; ii++)
	{
		if (chks[ii].flags < 2 && chks[ii].checked)
			pref += chks[ii].key + ';';						// Explicitly shown
		else if (chks[ii].flags >= 2 && !chks[ii].checked)
			pref += '-' + chks[ii].key + ';';				// Explicitly hidden
	}
	
	AjaxPrefSet(prefNm, pref, null, win.ConOptRefresh);
}

// Refresh page after applying optional element changes.
function ConOptRefresh()
{
	if (window.RefreshPage) window.RefreshPage();
}

// Hide Navigation Element.
function PaneNavEl(evt, ctl, prf, item, op)	// #6031
{
	if (!evt) evt = window.event;

	var li = FindParent(ctl, 'li');
	
	if (li) 
	{
		li.style.display = 'none'; 
		AjaxPrefOpSet(prf, item, op);
	}
	
	return false;
}

// Hide console pane.
function PaneHide(evt, ctl, pane, mop, op)	// #6012
{
	if (!evt) evt = window.event;

	var hdr = FindParent(ctl, 'div');
	
	if (hdr) 
	{
		hdr.style.display = 'none'; 
		hdr = hdr.nextSibling;
		if (hdr && HasCssClass(hdr, 'cnsp')) hdr.style.display = 'none';	// Hide following spacer.
		
		AjaxPrefOpSet('optpane:' + mop, pane, op);
	}
	
	return false;
}

// Hide subform tab. #6011
function TabHide(evt, btnId, mop, tab, op)
{
	if (!evt) evt = window.event;
	
	var btn = GetElement(btnId);
	
	if (btn)
	{
		btn.style.display = 'none';
		
		var sf = GetElement(btn.getAttribute('sf'));

		if (sf)
		{
			sf.style.display = 'none';
		}

		AjaxPrefOpSet('opttab:' + mop, tab, op);
	}

	return CancelBubble(evt);
}