// constants
var GUID_EMPTY = "00000000-0000-0000-0000-000000000000";
var GUID_REGEX = "^(\{){0,1}[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}(\}){0,1}$";
var ATTRIB_ALLOW_EMPTY_GUID = "AllowEmptyGuid";

var ATTRIB_VALUE_FALSE = "false";
var ATTRIB_VALUE_TRUE = "true";

var NONE_SELECTED = "-1";

var agt = navigator.userAgent.toLowerCase();
var isNav = ((agt.indexOf('mozilla')!=-1)&&((agt.indexOf('spoofer')==-1) && (agt.indexOf('compatible')==-1)));
var isIE = (agt.indexOf("msie")!=-1);

var ATTRIB_ENTITY_FIELD = "EntityField";
var ATTRIB_DATAROWINDEX_FIELD = "DataRowIndex";
var ATTRIB_LOWVAL_FIELD = "LowValue";
var ATTRIB_HIGHVAL_FIELD = "HighValue";
var ATTRIB_INFO_FIELD = "Info";

// shorthand
function GET$(id) {
  var elements = new Array();

  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);

    if (arguments.length == 1)
      return element;

    elements.push(element);
  }

  return elements;
//    return document.getElementById(id);
}

function GetKeyCode(e){ return(e.keyCode?e.keyCode:e.which);}

function FocusOnElemId(controlId)
{
    var elem = GET$(controlId);
    FocusOnElem(elem);
}

function FocusOnElem(elem)
{  
    if(elem!=null)
        elem.focus();            
}            

// Get the top level windows
function GetTopmostWindow()
{
	var modal = (window.dialogArguments != null);
	var win;
	if (modal) 
		win = window.dialogArguments.window;
	else 
		win = window;
		
	return win.top;
}

// Returns TRUE if the current window is a popup window
function IsPopupWindow()
{
	return (window.dialogArguments != null);
}

// Forces a resize for those elements with an Onresize event
function ForceResize(theWindow)
{
	var win = theWindow;
	if(win==null)
		win = window;
	if(win.onresize!=null)
		win.onresize();
	return;
}

// Retrieve all objects with the given attribute
var _arrayOfEls = null;
var _attributeName = null;

// Returns an array of elements that have the given attribute
// Note: This is meant for use with CUSTOM attributes
function GetElementsByAttribute(attributeName,theWindow,parent,value)
{
	var win = theWindow;
	if(win==null)
		win = window;

	_arrayOfEls = new Array();
	_attributeName = attributeName;
	if(parent==null)
		parent = win.document.getElementsByTagName('body')[0];
	_getElementsByAttrib(parent,value);
	
	return _arrayOfEls;	
}

// internal recursive method
function _getElementsByAttrib(thisNode,value)
{
	for(var i=0;i<thisNode.childNodes.length;i++)
		_getElementsByAttrib(thisNode.childNodes[i],value);	

	if(thisNode.attributes && thisNode.attributes[_attributeName]!=null && (value==null||thisNode.attributes[_attributeName].nodeValue==value))
		_arrayOfEls.push(thisNode);
}

// Generic toggling of an element's display
function IsElementHidden(elementId, theWindow)
{
	var win = theWindow;
	if(win==null)
		win = window;

	var element = win.document.getElementById(elementId);
	return (element.style.display == "none");
}

function IsElementShowing(elementId, theWindow)
{
	var win = theWindow;
	if(win==null)
		win = window;

	var element = win.document.getElementById(elementId);
	if(element==null)
		alert('invalid element: ' + elementId);
	return  (element.style.display != "none");
}

function ToggleElementDisplay(elementId, theWindow)
{
	if(IsElementHidden(elementId,theWindow))
		ShowElement(elementId,theWindow);
	else
		HideElement(elementId,theWindow);
}

// Generic hiding of an element
function HideElement(elementId, theWindow)
{
	var win = theWindow;
	if(win==null)
		win = window;

	if(!IsElementHidden(elementId,theWindow))
	{
		var div = win.document.getElementById(elementId).style;
		div.display = "none";
	}
}

// Generic showing of an element
function ShowElement(elementId, theWindow)
{
	var win = theWindow;
	if(win==null)
		win = window;

	if(!IsElementShowing(elementId,win))
	{
		var div = win.document.getElementById(elementId).style;
		div.display = "";
	}
}

// Shows a single DIV in a collection of DIVS.
// Only 1 DIV is visible at any given time
function ShowSingleDiv(containerElem, divToShowId)
{
    ShowSingleElem(containerElem,divToShowId,"DIV");
}

// Shows a single Element in a collection of elements 
// with the given tagName.
// Only 1 element is visible at any given time
function ShowSingleElem(containerElem, elemToShowId, tagName)
{
    var container = document.getElementById(containerElem);            
    var childNode = container.firstChild;
    while(childNode!=null)
    {
        if(childNode.tagName==tagName)
        {
            if(childNode.id == elemToShowId)
                ShowElement(elemToShowId);
            else
                HideElement(childNode.id);
        }
        childNode = childNode.nextSibling;
    }
}


// Scroll a div to the given top position
function RestoreScrollPosition(elementId,top,left)
{
	var elem = document.getElementById(elementId);
	if(elem==null)
		return;
	if(top!=null)
		elem.scrollTop = top;	
	if(left!=null)
		elem.scrollLeft = left;	
}

// Chains a new function to execute into the window.onload event
function AddLoadEvent(func) 
{
	ChainEvent(window,"onload",func);
}

// Chains a new function to execute into the window.onresize event
function AddResizeEvent(func) 
{
	ChainEvent(window,"onresize",func);
}


// Chains a new function to execute to an existing event. You can call this multiple
// times for a given event, and when the event fires the functions will be executed
// in the order they were chained.
function ChainEvent(objectName, eventName, functionToAdd)
{
	var oldEvent = objectName[eventName];

	if (typeof objectName[eventName] != 'function') 
	{
		objectName[eventName] = functionToAdd;
	} 
	else 
	{
		objectName[eventName] = function() 
			{
				oldEvent();
				functionToAdd();
			}
	}
}

// Generic convenience object used to calculate position
// information of a given html element
function positionInfo(element) 
{
	this.getElementLeft = function () 
	{
		var x = 0;
		var elm;
		if(typeof(element) == "object")
			elm = element;
		else 
			elm = document.getElementById(element);
		while (elm != null) 
		{
			x+= elm.offsetLeft;
			elm = elm.offsetParent;
		}
		return parseInt(x);
	}

	this.getElementWidth = function ()
	{
		var elm;
		if(typeof(element) == "object")
			elm = element;
		else 
			elm = document.getElementById(element);
		return parseInt(elm.offsetWidth);
	}

	this.getElementRight = function ()
	{
		return this.getElementLeft() + this.getElementWidth();
	}

	this.getElementTop = function () 
	{
		var y = 0;
		var elm;
		if(typeof(element) == "object")
			elm = element;
		else 
			elm = document.getElementById(element);

		while (elm != null) 
		{
			y+= elm.offsetTop;
			elm = elm.offsetParent;
		}
		return parseInt(y);
	}

	this.getElementHeight = function ()
	{
		var elm;
		if(typeof(element) == "object")
			elm = element;
		else
			elm = document.getElementById(element);
		return parseInt(elm.offsetHeight);
	}

	this.getElementBottom = function ()
	{
		return this.getElementTop() + this.getElementHeight();
	}
	
	this.display = function()
		{
			alert("Left:" + this.getElementLeft() + "  Top:" + this.getElementTop() + 
				"  Right:" + this.getElementRight() + "  Bottom:" + this.getElementBottom());
		}
}

// Convenience object/methods to obtain the browser's  screen dimensions.
var viewport = {
	getWinWidth: function () {
		this.width = 0;
		if (window.innerWidth) this.width = window.innerWidth-18;
		else if (document.documentElement && document.documentElement.clientWidth) 
  			this.width = document.documentElement.clientWidth;
		else if (document.body && document.body.clientWidth) 
  			this.width = document.body.clientWidth;
	},
		
	getWinHeight: function () {
		this.height = 0;
		if (window.innerHeight) this.height = window.innerHeight -18;
  		else if (document.documentElement && document.documentElement.clientHeight) 
  			this.height = document.documentElement.clientHeight;
  		else if (document.body && document.body.clientHeight) 
  			this.height = document.body.clientHeight;
	},
		
	getScrollX: function () {
		this.scrollX = 0;
  		if (typeof window.pageXOffset == "number") this.scrollX = window.pageXOffset;
  		else if (document.documentElement && document.documentElement.scrollLeft)
  			this.scrollX = document.documentElement.scrollLeft;
  		else if (document.body && document.body.scrollLeft) 
  			this.scrollX = document.body.scrollLeft; 
  		else if (window.scrollX) this.scrollX = window.scrollX;
	},
		
	getScrollY: function () {
		this.scrollY = 0;    
		if (typeof window.pageYOffset == "number") this.scrollY = window.pageYOffset;
		else if (document.documentElement && document.documentElement.scrollTop)
  			this.scrollY = document.documentElement.scrollTop;
  		else if (document.body && document.body.scrollTop) 
  			this.scrollY = document.body.scrollTop; 
  		else if (window.scrollY) this.scrollY = window.scrollY;
	},
		
	getAll: function () {
		this.getWinWidth(); this.getWinHeight();
		this.getScrollX();  this.getScrollY();
	}
	
}	

// Generic debugging routine used to examine all properties
// of any javascript object.
function examineObject(obj,includeFunctions)
{
	var props = "";
	var x = 0;
	for(propval in obj)
	{
		if(!includeFunctions && typeof  obj[propval] == "function")
			props += propval + "= [FUNCTION]    ";
		else
			props += propval + "=" + obj[propval] + "    ";
		x += 1;
		if(x == 6)
		{
			props += "\r\n";
			x = 0;
		}
	}
	alert(props);
}  


// Center a fixed sized element on the screen
function CenterOnScreen(elementId, yOffset, xOffset)
{
    var elem = document.getElementById(elementId);
    if(elem==null)
        return;
    
    if(elem.style.position != "absolute")
        elem.style.position = "absolute";
    
    var xOff = xOffset==null?0:xOffset;
    var yOff = yOffset==null?0:yOffset;
    
    viewport.getAll();
    
    elem.style.left = ((parseInt(viewport.width) - parseInt(elem.offsetWidth))/2 + xOff) + "px";
    elem.style.top = ((parseInt(viewport.height) - parseInt(elem.offsetHeight))/2 + yOff) + "px";
}

// Methods used for dynamically resizing element heights relative to the total
// browser screen-size.

function ResizeToScreenHeight(elementId,reservedYPixels,minimumHeight,unhide,theWindow)
{
	var win = theWindow;
	if(win==null)
		win = window;

	reservedYPixels = reservedYPixels?reservedYPixels:0;
	minimumHeight = minimumHeight?minimumHeight:0;
	
	if(!document.all && unhide)
		ShowElement(elementId,win);

	viewport.getWinHeight();
	var theElement = win.document.getElementById(elementId);
	theElement.style.height = Math.max(viewport.height-reservedYPixels-1,minimumHeight) + "px";

	if(win.document.all && unhide)
		ShowElement(elementId,win);
		
	return theElement.style.height;
}

function ResizeToBottomOfScreen(elementId,reservedYPixels,minimumHeight,unhide,theWindow)
{
	var win = theWindow;
	if(win==null)
		win = window;

	if(!win.document.all && unhide)
		ShowElement(elementId,win);

	viewport.getAll();							
	var theElement = win.document.getElementById(elementId);
	var elementPos = new positionInfo(theElement);
	theElement.style.height = Math.max(viewport.height-elementPos.getElementTop()-reservedYPixels-1,minimumHeight) + "px";

	if(win.document.all && unhide)
		ShowElement(elementId,win);
		
    return theElement.style.height;
}

function ResizeToParentElement(elementId,theWindow)
{
	var win = theWindow;
	if(win==null)
		win = window;

	var theElement = win.document.getElementById(elementId);
	var theParent = theElement.parentElement;
	var parentInfo = new positionInfo(theParent);
	theElement.style.height = parentInfo.getElementHeight()-1;
	return theElement.style.height;
}

function ResizeToElement(elem, elemToResize, includeScroll)
{
	if(elem==null || elemToResize==null)
	    return;

    var body = document.getElementsByTagName("body")[0];
    var isFullBody = elem==body;
    var sizeInfo = new positionInfo(elem);	

    var scrollTop = 0;
    var scrollLeft = 0;
    if(includeScroll)
    {
        var scrollOff = new ScrollOfffsets(elem);
        scrollTop = scrollOff.scrollTop;
        scrollLeft = scrollOff.scrollLeft;
    }
    
    if(isFullBody)
    {
        // if disabling the body, disable the entire viewport, not just
        // the rendered portion of the screen.
	    viewport.getAll();
	    elemToResize.style.height = viewport.height;
	    elemToResize.style.top = _getSizeInPX(sizeInfo.getElementTop());
	    elemToResize.style.left = _getSizeInPX(sizeInfo.getElementLeft());	    
	    elemToResize.style.width = _getSizeInPX(sizeInfo.getElementWidth());
    }
    else
    {
	    elemToResize.style.top = _getSizeInPX(sizeInfo.getElementTop() + scrollTop);
	    elemToResize.style.left = _getSizeInPX(sizeInfo.getElementLeft()  + scrollLeft);
	    elemToResize.style.height = _getSizeInPX(sizeInfo.getElementHeight());
	    elemToResize.style.width = _getSizeInPX(sizeInfo.getElementWidth());
	}
}

function CenterElements(elem, elemToCenter, offsetX, offsetY, includeScroll)
{
	if(elem==null || elemToCenter==null)
	    return;

    var body = document.getElementsByTagName("body")[0];
    var isFullBody = elem==body;
    var sizeInfo = new positionInfo(elem);	
    var centerSizeInfo = new positionInfo(elemToCenter);	
    var offX = offsetX!=null?offsetX:0;
    var offY = offsetY!=null?offsetY:0;

    var scrollTop = 0;
    var scrollLeft = 0;
    if(includeScroll)
    {
        var scrollOff = new ScrollOfffsets(elem);
        scrollTop = scrollOff.scrollTop;
        scrollLeft = scrollOff.scrollLeft;
    }

    if(isFullBody)
    {
        // if disabling the body, disable the entire viewport, not just
        // the rendered portion of the screen.
	    viewport.getAll();
	    elemToCenter.style.top = _getSizeInPX(sizeInfo.getElementTop() + offY + ( (viewport.height-centerSizeInfo.getElementHeight())/2));
	    elemToCenter.style.left = _getSizeInPX(sizeInfo.getElementLeft() + offX+ ((viewport.width-centerSizeInfo.getElementWidth())/2));	    
    }
    else
    {
	    elemToCenter.style.top = _getSizeInPX(sizeInfo.getElementTop() + scrollTop + offY +((sizeInfo.getElementHeight()-centerSizeInfo.getElementHeight())/2));
	    elemToCenter.style.left = _getSizeInPX(sizeInfo.getElementLeft() + scrollLeft + offX + ((sizeInfo.getElementWidth()-centerSizeInfo.getElementWidth())/2));
	}
}

function ScrollOfffsets(elem)
{
	this.scrollTop = 0;
	this.scrollLeft = 0;
    this.elem = typeof(elem)=="string"?GET$(elem):elem;
	if(this.elem!=null)
	{
	    var parent = this.elem;
	    while( (parent = parent.parentNode) != document.body)
	    {
	        if(parent!=null)
	        {
		        if( parent.scrollTop)
			        this.scrollTop -= parent.scrollTop;
                if( parent.scrollLeft)
                    this.scrollLeft += parent.scrollLeft;				
            }
	    }
	}							
}

function _getSizeInPX(existingSize)
{
    if(typeof(existingSize)=="string")
    {
        if(existingSize.indexOf("px")<0)
            return existingSize + "px";
        else
            return existingSize;
    }
    return existingSize + "px";
}


/* Cookie */
/**
 * Sets a Cookie with the given name and value.
 *
 * name       Name of the cookie
 * value      Value of the cookie
 * [expires]  Expiration date of the cookie (default: end of current session)
 * [path]     Path where the cookie is valid (default: path of calling document)
 * [domain]   Domain where the cookie is valid
 *              (default: domain of calling document)
 * [secure]   Boolean value indicating if the cookie transmission requires a
 *              secure transmission
 */
function setCookie(name, value, expires, path, domain, secure)
{
    document.cookie= name + "=" + escape(value) +
        ((expires) ? "; expires=" + expires.toGMTString() : "") +
        ((path) ? "; path=" + path : "") +
        ((domain) ? "; domain=" + domain : "") +
        ((secure) ? "; secure" : "");
}

/**
 * Gets the value of the specified cookie.
 *
 * name  Name of the desired cookie.
 *
 * Returns a string containing value of specified cookie,
 *   or null if cookie does not exist.
 */
function getCookie(name)
{
    var dc = document.cookie;
    var prefix = name + "=";
    var begin = dc.indexOf("; " + prefix);
    if (begin == -1)
    {
        begin = dc.indexOf(prefix);
        if (begin != 0) return null;
    }
    else
    {
        begin += 2;
    }
    var end = document.cookie.indexOf(";", begin);
    if (end == -1)
    {
        end = dc.length;
    }
    return unescape(dc.substring(begin + prefix.length, end));
}

/**
 * Deletes the specified cookie.
 *
 * name      name of the cookie
 * [path]    path of the cookie (must be same as path used to create cookie)
 * [domain]  domain of the cookie (must be same as domain used to create cookie)
 */
function deleteCookie(name, path, domain)
{
    if (getCookie(name))
    {
        document.cookie = name + "=" + 
            ((path) ? "; path=" + path : "") +
            ((domain) ? "; domain=" + domain : "") +
            "; expires=Thu, 01-Jan-70 00:00:01 GMT";
    }
}

function FormatSecondsAsTime(seconds, timeFormat)
{
    seconds = parseInt(seconds);
    var secondsPerDay = 86400;
    var secondsPerHour = 3600;
    var secondsPerMinute = 60;
    
    var days = parseInt(seconds/secondsPerDay);
    var remaining = seconds - days*secondsPerDay; 
    var hours = parseInt(remaining/secondsPerHour);
    remaining = remaining - hours*secondsPerHour;
    var minutes = parseInt(remaining/secondsPerMinute);
    remaining = remaining - minutes*secondsPerMinute;

    var format = (timeFormat==null||Trim(timeFormat)=="")?"{mm}:{ss}":timeFormat;    
    var result = _FormatStringWithCode(format,"d",days,2);
    result = _FormatStringWithCode(result,"h",hours,2);
    result = _FormatStringWithCode(result,"m",minutes,2);
    result = _FormatStringWithCode(result,"s",remaining,2);
           
    return result;
}

function _FormatStringWithCode(text, charCode, value, maxDepth, padCharacter)
{
    if(text==null)
        return text;
    
    var newtext = text;
    var isZero = (value==null || value==0);

    var codes = charCode;
    for(var i=0;i<maxDepth;i++)
    {
        newtext = newtext.replace("["+codes+"]",isZero?"":"{"+codes+"}");
        codes += charCode;
    }
    
    codes = charCode;
    for(var i=0;i<maxDepth;i++)
    {
        newtext = newtext.replace("{"+codes+"}",PadDigits(value,i+1,padCharacter));
        codes += charCode;
    }
        
    return newtext;
}

function PadDigits(n, totalDigits, padCharacter) 
{ 
    n = n.toString(); 
    var pd = ''; 
    var padChar = padCharacter!=null?padCharacter:'0';
    if (totalDigits > n.length) 
    { 
        for (i=0; i < (totalDigits-n.length); i++) 
            pd += padChar; 
    } 
    return pd + n.toString(); 
} 


function CommaFormatted(number)
{
    var amount = number + "";
    var delimiter = ","; // replace comma if desired
    var a = amount.split('.',2)
    var d = a[1];
    var i = parseInt(a[0]);
    if(isNaN(i)) { return ''; }
    var minus = '';
    if(i < 0) { minus = '-'; }
    i = Math.abs(i);
    var n = new String(i);
    var a = [];
    while(n.length > 3)
    {
        var nn = n.substr(n.length-3);
        a.unshift(nn);
        n = n.substr(0,n.length-3);
    }
    if(n.length > 0) { a.unshift(n); }
    n = a.join(delimiter);
    if(d==null || d.length < 1) { amount = n; }
    else { amount = n + '.' + d; }
    amount = minus + amount;
    return amount;
}

function StripHTML(message)
{
    return message.replace(/(<([^>]+)>)/ig,""); 
}

function StripCharacters(str,filter)
{
    var i,curChar;
    var retStr = '';
    var len = str.length;
    for(i=0; i<len; i++)
    {
     curChar = str.charAt(i);
     if(filter.indexOf(curChar)<0) 
       //not in filter, keep it
        retStr += curChar;
    }
    return retStr;
}

function StripAnyCharactersExcept(str,allowedCharacters)
{
    var i,curChar;
    var retStr = '';
    var len = str.length;
    for(i=0; i<len; i++)
    {
        curChar = str.charAt(i);
        if(allowedCharacters.indexOf(curChar)>=0) 
            retStr += curChar;
    }
    return retStr;
}


function HandleNumericTextKey(e,allowDecimal,allowNegative)
{
	var code = (e.keyCode?e.keyCode:e.which);
	var result = true;
	result = IsKeyDigit(code) || (code==46&&allowDecimal) || (code==45&&allowNegative&&Trim(e.srcElement.value)=="");
			
	if(e.keyCode)
		e.returnValue = result;
		
	return result;
}

function HandleDateKey(e,separatorCode)
{
	var code = (e.keyCode?e.keyCode:e.which);
	var result = true;
	result = IsKeyDigit(code) || (separatorCode!=null && code==separatorCode);
			
	if(e.keyCode)
		e.returnValue = result;
		
	return result;
}

function IsKeyDigit(keycode)
{
	return (keycode>=48 && keycode<=57);
}

function IsKeyAlpha(keycode)
{
	return (keycode>=97 && keycode<=122) || (keycode>=65 && keycode<=90);
}

function IsKeySymbol(keycode)
{
	return !IsKeyDigit(keycode)&&!IsKeyAlpha(keycode);
}

function IsKeyUppercase(keycode)
{
	return (keycode>=65 && keycode<=90);
}

function IsKeyLowercase(keycode)
{
	return (keycode>=97 && keycode<=122);
}

function CheckTextLength(ctrl, e, maxLen, showMsg, msg)
{
	if(ctrl.value.length>maxLen)
	{
		if(showMsg!=null && showMsg)
		{
			if(msg!=null)
				alert(msg)
			else
				alert('This field can only hold ' + maxLen + ' characters. The text you entered will be truncated.');
		}
		ctrl.value=ctrl.value.substring(0,maxLen);
		return false;
	}
	return true;
}

function HandleTextKey(e,allowNumeric,allowSymbol,isUpperCased,maxLength)
{
	var code = (e.keyCode?e.keyCode:e.which);
	var result = true;
	
	var isDigit = IsKeyDigit(code);
	if((!allowNumeric && isDigit) || (!allowSymbol && !isDigit && !IsKeyAlpha(code) ))
		result = false;	
	
	if(isUpperCased==true && IsKeyLowercase(code))
		code -= 32;
	else if(isUpperCased==false && IsKeyUppercase(code))
		code += 32;
	
	if(e.keyCode)
		e.keyCode = code;
	else if(e.which && code!=e.which)
	{
		// need to cancel and replace current selection for Mozilla-based
		// (cant just change the key)
		if(e.preventDefault)
			e.preventDefault();
			
		var textControl = e.currentTarget;
		var oldSelectionStart = textControl.selectionStart;
		var oldSelectionEnd = textControl.selectionEnd;
		var selectedText = textControl.value.substring(oldSelectionStart,
														oldSelectionEnd);
		var newText = String.fromCharCode(code);
		
		textControl.value = 
			textControl.value.substring(0, oldSelectionStart) +
			newText +
			textControl.value.substring(oldSelectionEnd);
		textControl.setSelectionRange(oldSelectionStart + newText.length,
										oldSelectionStart + newText.length);
		return false;	
	}
	
	result = result & CanAcceptKey(code,e.currentTarget?e.currentTarget:e.srcElement,maxLength);
		
	if(e.keyCode)
		e.returnValue = result;

	return result;
}

function CanAcceptKey(keyCode,element,maxLength) 
{
	if(maxLength==null||maxLength<0)
		return true;
		
	switch(keyCode) 
	{
		case 37: // left
		return true;
		case 38: // up
		return true;
		case 39: // right
		return true;
		case 40: // down
		return true;
		case 8: // backspace
		return true;
		case 46: // delete
		return true;
	}
	return (element.value.length<maxLength);
}

function DisableControls(parentNode,disable)
{
	var parent = parentNode?parentNode:document;
	var elems = parent.getElementsByTagName('input');
	for(var i=0;i<elems.length;i++)
		elems[i].disabled = disable;	
}

function Trim(text)
{
	if(text==null)
		return null;
	return text.replace(/^\s*|\s*$/g,"");
}

function EndsWith(str, s)
{
	var reg = new RegExp (s + "$");
	return reg.test(str);
}

function StartsWith(str, s)
{
	var reg = new RegExp("^" + s);
	return reg.test(str);
}

// returns a short date string for the given date object
function ShortDateString(date)
{
	var fullDateString = date.toString();
	
	var re = new RegExp("\\b00:00:00\\s[A-Z]+\\b","g");
	return fullDateString.replace(re,"");
}

function PromptAndStore(promptText,defaultValue, storeInElement, invalidMsg)
{
	var value = prompt(promptText,defaultValue); 
	if(value==null)
		return false;
	else if(Trim(value).length==0)
	{
		if(invalidMsg && invalidMsg.length>0) 
			alert(invalidMsg);
		else
			alert("The value you entered was invalid. Please try again.");
		return false;
	}
	else if(storeInElement!=null)
		storeInElement.value = Trim(value);
	return true;
}

function IsValidGuid(text, allowEmpty)
{
	if(text==null || Trim(text).length==0)
		return false;
	if(allowEmpty==null)
		allowEmpty = true;
	if(!allowEmpty && text.indexOf(GUID_EMPTY)>=0)
		return false;
	return text.match(GUID_REGEX)!=null;	
}

function ValidateGuid(source,args)
{
	args.IsValid = IsValidGuid(args.Value,source.getAttribute(ATTRIB_ALLOW_EMPTY_GUID)==ATTRIB_VALUE_TRUE);
}

function IsValidEmailAddress(email) 
{
     var emailReg = " *\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)* *";
     var regex = new RegExp(emailReg);
     return regex.test(email);
}

function ValidateEmailList(source, args)
{
    var sourceControl = document.getElementById(source.controltovalidate);
    var allowMultiple = source.getAttribute("allowmultiple")=="1";
    var allowEmpty = source.getAttribute("allowempty")=="1";
    var autoMsg = source.getAttribute("automessage")=="1";
    var delim = source.getAttribute("delim");
    if(delim==null || delim.length==0)
        delim = ";";
    
    source.setAttribute("invalidpos","");
    source.setAttribute("invalidemail","");
    
    if(!allowEmpty && (args.Value==null || Trim(args.Value)==""))
    {
        if(autoMsg)
            source.innerHTML = "Email address is required.";
        args.IsValid = false;
        return;
    }
    
    if(!allowMultiple) 
    {   
        args.IsValid = IsValidEmailAddress(args.Value);
        return;
    }
    else if(args.Value!=null)
    {
        var addresses = args.Value.split(delim);
        for(var i=0;i<addresses.length;i++)
        {
            var email = addresses[i];
            if(Trim(email)!="")
            {
                if(!IsValidEmailAddress(email))
                {
                    source.setAttribute("invalidpos",i);
                    source.setAttribute("invalidemail",email);
                    if(autoMsg && addresses.length>1)
                        source.innerHTML = "The address [<b>" + email + "</b>] at position <b>" + (i+1) + "</b> is invalid.";
                    args.IsValid = false;
                    return;
                }
            }
        }
    }
    
    args.IsValid = true;
}


function GetURLParameters() 
{
	var sURL = window.document.URL.toString();
	var params = new Object();

	if (sURL.indexOf("?") > 0)
	{
		var arrParams = sURL.split("?");			
		var arrURLParams = arrParams[1].split("&");
				
		for (var i=0;i<arrURLParams.length;i++)
		{
			var sParam =  arrURLParams[i].split("=");
			params[sParam[0]] = sParam[1];
		}
	}
	return params;
}

/* ************************************************* */
// A popup div that handles anchoring to another element
// and properly displaying OVER comboboxes
function popupDiv(id,anchorElement, width, height)
{	
	this.createDiv = function(id)
		{
			var theDiv;
			if(this.popup)
			{
				// make the div inside the popup
				theDiv = this.popup.document.createElement('DIV');
				// make sure we are using the same styles
				for(var i=0; i<document.styleSheets.length; i++)
				{
					var sheet = document.styleSheets[i];
					if(sheet.href.length>0)
						this.popup.document.createStyleSheet(sheet.href);
					else if(sheet.cssText.length>0)
						this.popup.document.body.style.cssText += sheet.cssText;
				}
			}
			else
				theDiv = document.createElement('DIV');
			theDiv.id = id;
			theDiv.style.position = "absolute";
			return theDiv;
		}
	
	this.setAnchor = function(anchorElement)
		{
			if(anchorElement==null)
				return;

			if(this.popup)
				this.popup.document.body.appendChild(this.div)
			else
				document.body.appendChild(this.div);
			this.positionTo(anchorElement);
		}	
		
	this.positionTo = function(element)
		{
			if(this.popup)
			{
				this.popup.show(0,element.offsetHeight,this.width,this.height,element);
			}
			else
			{					
				var left =  this.getLeftPos(element);
				var right = left + this.div.offsetWidth;
				var top = this.getTopPos(element) + element.offsetHeight;
				var bottom = top + this.div.offsetHeight;
				
				viewport.getAll();

				if(viewport.width<right)
					left -= (this.div.offsetWidth-element.offsetWidth);
				if(viewport.height<bottom)
					top -= (this.div.offsetHeight+element.offsetHeight);
				this.div.style.left = left;
				this.div.style.top = top;
			}
		}	
		
	this.getTopPos = function (element)
		{			
			var top = element.offsetTop;
			
			if(isNav)
			{
				var parent = element;
				while( (parent = parent.parentNode) != document.body)
				{
					if( parent.scrollTop)
						top -= parent.scrollTop;
				}							
			}	
								
			while( (element = element.offsetParent) != document.body)
				top += element.offsetTop - (element==document.body?0:element.scrollTop);
			return top;
		}
	this.getLeftPos = function (element)
		{
			var left = element.offsetLeft;

			if(isNav)
			{
				var parent = element;
				while( (parent = parent.parentNode) != document.body)
				{
					if( parent.scrollLeft)
						left -= parent.scrollLeft;
				}							
			}	
									
			while( (element = element.offsetParent) != null)
				left += element.offsetLeft - (element.offsetParent==null?0:element.scrollLeft);
			return left;
		}
				
	this.width = width;
	this.height = height;	
	this.popup = (isIE?window.createPopup():null);		
	this.div = this.createDiv(id);
	this.setAnchor(anchorElement);					
}

function divPositionInfo(element)
{
	this.getTopPos = function (element)
		{			
			var top = element.offsetTop;
			
			if(isNav)
			{
				var parent = element;
				while( (parent = parent.parentNode) != document.body && element!=null)
				{
					if( parent.scrollTop)
						top -= parent.scrollTop;
				}							
			}	
								
			while( (element = element.offsetParent) != document.body && element!=null)
				top += element.offsetTop - (element==document.body?0:element.scrollTop);
			return top;
		}
	this.getLeftPos = function (element)
		{
			var left = element.offsetLeft;

			if(isNav)
			{
				var parent = element;
				while( (parent = parent.parentNode) != document.body && element!=null)
				{
					if( parent.scrollLeft)
						left -= parent.scrollLeft;
				}							
			}	
									
			while( (element = element.offsetParent) != null && element!=null)
				left += element.offsetLeft - (element.offsetParent==null?0:element.scrollLeft);
			return left;
		}
		
	this.element = element;
	this.left = this.getLeftPos(element);
	this.top = this.getTopPos(element);
}

/* TABS */
function OnTabOver(tabItem)
{
    if(TabIsSelected(tabItem))
        return;
    tabItem.className = tabItem.getAttribute("tabHover");
}
function OnTabOut(tabItem)
{
    if(TabIsSelected(tabItem))
        return;
    tabItem.className = tabItem.getAttribute("tabNormal");
}

function OnTabClick(tabItem)
{
    if(TabIsSelected(tabItem))
        return;
        
    var container = TabGetContainer(tabItem);
    var currentSelection = TabSelectedTab(container);
    
    if(typeof(OnTabValidate) != "undefined")
    {
        // OnTabValidate(newIndex, newTabItem, currentIndex, currentTabItem, container)
        var res = OnTabValidate(tabItem.tabIndex, tabItem,currentSelection.tabIndex,currentSelection,container);
        if(res==false)
            return;
    }
    
    if(currentSelection!=null)
    {
        currentSelection.className = currentSelection.getAttribute("tabNormal");
        TabShowContent(currentSelection,false);
    }
        
    tabItem.className = tabItem.getAttribute("tabSelected");
    container.setAttribute("selectedTab",tabItem.id);
    var postbackElemId = container.getAttribute("postbackElem");
    var postbackElem = document.getElementById(postbackElemId);
    if(postbackElem!=null)
        postbackElem.value = tabItem.getAttribute("tabindex");
    TabShowContent(tabItem,true);
}

function TabShowContent(tabItem, show)
{
    var contentElemId = tabItem.getAttribute("contentElemId");

    if(tabItem==null || contentElemId==null)
        return true;
    
    if(show)
        ShowElement(contentElemId);
    else
        HideElement(contentElemId); 
}

function TabIsSelected(tabItem)
{
    var container = TabGetContainer(tabItem);
    var selTabId = container.getAttribute("selectedTab");
    return (selTabId==null)?tabItem.getAttribute("selectedTab")=="1":(selTabId == tabItem.id);
}

function TabGetContainer(tabItem)
{
    if(tabItem==null)
        return null;
        
    var id = tabItem.getAttribute("tabContainer")    
    return document.getElementById(id);
}

function TabSelectedTab(tabContainer)
{
    var selTabId = tabContainer.getAttribute("selectedTab");
    
    if(selTabId!=null)
        return document.getElementById(selTabId);
    
    selTabId = tabContainer.getAttribute("intialSelectionId");
    tabContainer.setAttribute("selectedTab",selTabId);
    return document.getElementById(selTabId);
}

/////////////////////////
/* BINDING TO ENTITIES */
/////////////////////////
function BindContainerToEntity(container,entity)
{
    var elems = GetElementsByAttribute(ATTRIB_ENTITY_FIELD,null,container);
    BindElemsToEntity(elems,entity);
}

function BindElemsToEntity(elems, entity)
{
    if(elems==null || entity==null)
        return;
    
    for(var i=0;i<elems.length;i++)
    {
        var elem = elems[i];
        var fieldName = elem.getAttribute(ATTRIB_ENTITY_FIELD);
        var fieldIsValid = fieldName!=null && (typeof entity[fieldName] != "undefined");
        if(fieldIsValid)
        {
            var fieldVal = entity[fieldName];
            if(elem.tagName=="A")
            {
                elem.innerHTML = fieldVal;
                var linkFieldName = fieldName + "_href";
                if(typeof entity[linkFieldName] != "undefined")
                {
                    var linkValue = entity[linkFieldName];
                    elem.href = linkValue==null||linkValue==""?"#":linkValue;
                }
            }
            else if(elem.tagName=="IMG")
                elem.src = fieldVal;
            else if(elem.tagName=="INPUT")
            {
                if(elem.type=="checkbox")
                    elem.checked = !(fieldVal==null || fieldVal==false || fieldVal==0 || (typeof(fieldVal)=="string" && (fieldVal.toUpperCase()=="NO" || fieldVal.toUpperCase()=="N")));
                else
                    elem.value = fieldVal==null?"":fieldVal;
            }
            else if(elem.tagName=="SELECT")
            {   
                var indexToSelect = -1;
                for(var j=0;j<elem.options.length;j++)
                {
                    if(elem.options[j].value==fieldVal)
                    {
                        indexToSelect = j;
                        break;
                    }
                }
                if(indexToSelect>=0)
                    elem.options.selectedIndex = indexToSelect;
            }
            else if(elem.tagName=="SPAN")
                elem.innerHTML = fieldVal==null?"":fieldVal;
            else if(elem.tagName=="DIV" && elem.getAttribute("RichEditId")!=null)
            {   // special case for rich edit control which needs api call
                var txtElem = GET$(elem.getAttribute("RichEditId"));
                if(txtElem!=null && txtElem.tagName=="TEXTAREA")
                {
                    if(typeof(tinyMCE)!="undefined")
                    {                    
                        var mce = tinyMCE.get(txtElem.id);
                        if(mce!=null)
                            mce.setContent(fieldVal);
                        else
                            txtElem.value = fieldVal;
                    }
                    else
                        txtElem.value = fieldVal;
                }
                else if(typeof(FTB_API)=="undefined")
                    alert("Could not bind field [" + fieldName + "] to RichEdit. The control API is missing.");
                else
                {
                    var richEditBox = FTB_API[elem.getAttribute("RichEditId")];
                    if(richEditBox==null || typeof(richEditBox.SetHtml)=="undefined")
                        alert("Could not bind field [" + fieldName + "] to RichEdit. The control is either missing or of an unexpected type.");
                    else
                        richEditBox.SetHtml(fieldVal);
                }
            }
             
        }		        
    }
} 


/////////////////////
// Validation
function IsPageValid(validationGroup)
{
	// if asp.net validations not supported, then return
	// that the page is valid
	if(typeof(Page_ClientValidate)!="function")
		return true;	
	Page_ClientValidate(validationGroup);
	return Page_IsValid;		
}

function PageErrorCount() 
{
	if(typeof(Page_ClientValidate)!="function")
		return 0;		
	var count = 0;
    var i;
    for (i = 0; i < Page_Validators.length; i++) 
        count += (Page_Validators[i].isvalid?0:1) 
	return count;
}

function _valtraverseTree(status, control)
{
	if(control == null)
	{
		for(var i = 0; i < Page_Validators.length; i++)
		{
			Page_Validators[i].enabled = status;
			Page_Validators[i].style.display = status ? 'inline' : 'none';						
		}	
	}
	else	
	{	
		//this is a way to check that the control is a validation control
		if(control.evaluationfunction != null)
		{
			control.enabled = status;
			control.style.display = status ? 'inline' : 'none';		
		}
		for( var i=0; i < control.childNodes.length; i++)
		{
			_valtraverseTree(status, control.childNodes[i]);
		}
	}
	
}

function EnableValidators(enable, containerID)
{
	var control;
	if(containerID == null)
	{
		control = null;					
	}
	else
	{
		control = document.getElementById(containerID);		
	}	
	if( containerID == null || control != null )
		_valtraverseTree(enable,  control);	
}

///////////////////////////
function DisableChildren(elemId,disable)
{
    var elem = GET$(elemId);
    DisableChild(elem,disable,true);                
}   

function DisableChild(elem,disable,recursive)
{
    if(elem==null)
        return;

	for(var i=0;i<elem.childNodes.length;i++)
		DisableChild(elem.childNodes[i],disable,recursive);	

	if(elem.tagName=="INPUT" || elem.tagName=="SELECT")
	{
	    if(disable)
	    {
	        if(elem.ondisable!=null)
	        {
	            if(typeof(elem.ondisable)=="function")
	                elem.ondisable();
	            else
	            {
	                var script = elem.ondisable.replace("this.","elem.");
	                try{ eval(script); } catch(e){}
	            }
	        }	        	        
            if(elem.disabled!=disable)
    	        elem.setAttribute("last_sel",elem.disabled);
	        elem.disabled = disable;
        }
        else
        {
	        if(elem.ondisable!=null && elem.onmouseout!=null)
	        {
	            if(typeof(elem.onmouseout)=="function")
	                elem.onmouseout();
	            else
	            {
	                var script = elem.onmouseout.replace("this.","elem.");
	                try{ eval(script); } catch(e){}
	            }
	        }	        	                
            var last = elem.getAttribute("last_sel");
            if(last!=null)
            {
    	        elem.disabled = last;
                elem.setAttribute("last_sel",last);
    	        elem.setAttribute("last_sel",null);
            }
            else
                elem.disabled = false;
        }	        
    }
}

var ACTIVE_LOCKED_OUT_ELEMS = null;
function ResizeDisabedAreas()
{
    if(ACTIVE_LOCKED_OUT_ELEMS==null)
        return;
	for(elemId in ACTIVE_LOCKED_OUT_ELEMS)
	{
	    if(elemId!=null)
	    {
	        var elem = GET$(elemId);
	        var lockoutElem = ACTIVE_LOCKED_OUT_ELEMS[elemId];
	        if(elem!=null && lockoutElem!=null)
                ResizeToElement(elem,lockoutElem);
        }
	}
}

function DisableArea(elemToDisable, disable, cssToApply)
{
    if(elemToDisable==null)
        return;
            
    if(elemToDisable.id==null)
    {
        alert("Unable to disable an area that does not contain an id attribute.");
        return;
    }
    var body = document.getElementsByTagName("body")[0];    
    var lockoutElem = (ACTIVE_LOCKED_OUT_ELEMS!=null)?ACTIVE_LOCKED_OUT_ELEMS[elemToDisable.id]:null;
    if(disable)
    {
        var lockoutWasCreated = lockoutElem==null;
        if(lockoutWasCreated)
            lockoutElem = document.createElement("div");
        lockoutElem.id = elemToDisable.id + "_lockout";
        lockoutElem.className = cssToApply==null?"disabledArea":cssToApply;
        lockoutElem.style.position = "absolute";
        lockoutElem.zIndex = elemToDisable.zIndex==null?1:elemToDisable.zIndex+1;
        lockoutElem.setAttribute("elemToLockout",elemToDisable.id);
                
        ResizeToElement(elemToDisable,lockoutElem);
        if(ACTIVE_LOCKED_OUT_ELEMS==null)
            ACTIVE_LOCKED_OUT_ELEMS = new Object();
        ACTIVE_LOCKED_OUT_ELEMS[elemToDisable.id] = lockoutElem;
        if(lockoutWasCreated)
            body.insertBefore(lockoutElem,null);   
        return lockoutElem;                
    }
    else
        RemoveLockoutElem(elemToDisable.id, lockoutElem);
    
    return null;
}

function RemoveLockoutElem(elemId, lockoutElem)
{
    if(lockoutElem==null)
        return;
    var body = document.getElementsByTagName("body")[0];
    body.removeChild(lockoutElem);
    ACTIVE_LOCKED_OUT_ELEMS[elemId] = null;            
}

function TextBoxLengthValidatorIsValid(val) 
{ 
    var value = ValidatorGetValue(val.controltovalidate); 
    if (ValidatorTrim(value).length == 0) return true; 
    if (val.minimumlength < 0) return true; 
    return (value.length >= val.minimumlength);
}

function AttachEvent(elem, eventName, callBackFunc)
{
    if(elem==null)
        return;
        
    if(typeof(elem.addEventListener)=="function")
    {
        if(eventName.indexOf("on")==0)
            eventName = eventName.substring(2);
        elem.addEventListener(eventName,callBackFunc,false);
    }
    else
        elem.attachEvent(eventName,callBackFunc);
}

function DetachEvent(elem, eventName, callBackFunc)
{
    if(elem==null)
        return;
        
    if(typeof(elem.removeEventListener)=="function")
    {
        if(eventName.indexOf("on")==0)
            eventName = eventName.substring(2);
        elem.removeEventListener(eventName,callBackFunc,false);
    }
    else
        elem.detachEvent(eventName,callBackFunc);
}

function CancelBubble(event)
{
    if(event.stopPropagation)
        event.stopPropagation();
    else            
        event.cancelBubble = true;
    if(event.preventDefault)
        event.preventDefault();
    else
        event.returnValue = false;
}

/* ********************* */
/* Heartbeat             */
/* ********************* */
var _hb_timeoutInMilliseconds = null;
var _hb_timerId = null;
var _hb_timeoutScript = null;
var _hb_timeoutDisplay = null;
var _hb_useAjax = false;
var _hb_lastPingTime = new Date();;
var _hb_firstPingTime = _hb_lastPingTime;
var _hb_commandQueue = null;
var _hb_numAllowedSkips = 18;
var _hb_numSkipped = 0;
var _hb_lastLogoutUrl = null;
var _hb_CommandHandlers = null;

function DfHeartbeat_IsInit()
{
    return (_hb_timerId!=null);
    
}
function DfHeartbeat_Init(timeoutMilli, timeoutScript, displayId, numAllowedSkips)
{
    _hb_useAjax = (typeof(PageMethods)!="undefined" && typeof(PageMethods.GetPingCommands)!="undefined");

    if(timeoutMilli!=null)
        _hb_timeoutInMilliseconds = timeoutMilli;
    if(timeoutScript!=null)
        _hb_timeoutScript = timeoutScript;
    if(displayId!=null)
        _hb_timeoutDisplay = displayId;
    if(numAllowedSkips!=null)
        _hb_numAllowedSkips = numAllowedSkips;
     _hb_numSkipped = 0;
        
     DfHeartbeat_DisplayStatusMsg("Beat: initalized");
     DfHeartbeat_Start();
}

function DfHeartbeat_Start()
{
    _hb_timerId = setTimeout(" DfHeartbeat_Execute()",_hb_timeoutInMilliseconds);
}

function DfHeartbeat_ForceBeat()
{
    if(_hb_timerId!=null)   
        clearTimeout(_hb_timerId);
    DfHeartbeat_Execute();
}

function DfHeartbeat_QueueCommand(cmd)
{
    if(cmd.Id==null) 
    {
        alert("All heartbeat commands must specify an Id");   
        return;
    }   
    if(_hb_commandQueue==null)
        _hb_commandQueue = new Object();        
    _hb_commandQueue[cmd.Id.toString()] = cmd;
}

function DfHeartbeat_GetQueuedCommand(id)
{
    if(_hb_commandQueue==null)
        return null;
    return _hb_commandQueue[id.toString()];                
}

function DfHeartbeat_AddHandler(handlerId, handler)
{
    if(_hb_CommandHandlers==null)
        _hb_CommandHandlers = new Object();
    if(handler==null || typeof(handler.execute)=="undefined")
    {
        alert("Invalid heartbeat command handler. Execute method not found.");
        return;
    }
    _hb_CommandHandlers[handlerId] = handler;        
}

function DfHeartbeat_RemoveHandler(handlerId)
{
    if(_hb_CommandHandlers==null)
        return;
    _hb_CommandHandlers[handlerId] = null;        
}

function DfHeartbeat_Execute()
{
    try
    {
        if(_hb_useAjax)
        {
            if(AjaxWaiting!=true)
            {
                var outgoingCommands = new Array();
                for(id in _hb_commandQueue)
                {
                    var command = _hb_commandQueue[id];
                    if(command!=null)
                    {
                        command.PageUrl = document.URL;
                        outgoingCommands.push(command);
                    }
                }
                _hb_commandQueue = null;
                PageMethods.GetPingCommands(_hb_firstPingTime, _hb_lastPingTime, window.location.href, outgoingCommands, DfHeartbeat_OnCommands, DfHeartbeat_OnCommandFailed);
            }
            else
                 DfHeartbeat_DisplayStatusMsg("Beat: Line is busy...");
        }
        else
        {
            if(_hb_timeoutScript!=null)
                eval(_hb_timeoutScript);
        }
    }
    catch (e) 
    {
        alert(e.message);
        var errMsg = "A fatal error occurred in the client-side heartbeat. This means your connection to the server " +
                "was disrupted, and you will need to refresh your page and possibly login again.";
        if(typeof(ShowCommonDialog)!="undefined")
            ShowCommonDialog("Heartbeat Error","The client-side heartbeat encountered an error",errMsg,DIALOG_TYPE_HAND)
        else
            alert("The client-side heartbeat encountered an error.  " + errMsg);
    }

    if(!_hb_useAjax || (_hb_useAjax && AjaxWaiting==true))
         DfHeartbeat_Start();

    if(!_hb_useAjax)
    {
        var dt = new Date();
        var hours = dt.getHours();
        var ampm = "am";
        if(hours>12)
        {
            hours = hours - 12;
            ampm = "pm";
        }
                
         DfHeartbeat_DisplayStatusMsg("Beat: " + hours + ":" + (dt.getMinutes()<10?"0":"") + dt.getMinutes() + ":" + 
                (dt.getSeconds()<10?"0":"") + dt.getSeconds() + " " + ampm + "...");
    }
}

function DfHeartbeat_OnCommandFailed(ex,ctx,methodName)
{  
    try
    {  
        AjaxWaiting = false;
        if(!_hb_lasLoggedInState || _hb_numAllowedSkips<0)
        {
            DfHeartbeat_DisplayStatusMsg("Beat: Skipping (" + ((_hb_numAllowedSkips<0)?"":(_hb_numSkipped + "/" + _hb_numAllowedSkips)) + ")");
            DfHeartbeat_Start();
            return;
        }        
        
        _hb_numSkipped += 1;
        if(_hb_numAllowedSkips<0 || _hb_numSkipped<_hb_numAllowedSkips)
        {
            DfHeartbeat_DisplayStatusMsg("Beat: Skipping (" + _hb_numSkipped + "/" + _hb_numAllowedSkips + ")  Comm error - " + ex.get_message());
            DfHeartbeat_Start();
        }
        else
        {
            DfHeartbeat_DoLogout("Connectivity Loss", "Your connection to the server has been disrupted.", 
                "Your connection to the server has been disrupted. This can be caused by a failure in your " + 
                "internet connection, or a communication loss from the server. As a result, your session has " + 
                "been ended and you must login again.", DIALOG_TYPE_NOIMAGE, _hb_lastLogoutUrl);
        }
    }catch(e){ }
}

var _hb_lasLoggedInState = false;
function DfHeartbeat_OnCommands(commands)
{
    _hb_numSkipped = 0;
    AjaxWaiting = false;
    try
    {
        _hb_lastPingTime = new Date();
    
        if(commands!=null)
        {
            for(var i=0;i<commands.length;i++)
            {
                try { DfHeartbeat_OnCommandExec(commands[i]);}
                catch(cmdEx){}
            }
        }
    }
    catch(e){}
    
    DfHeartbeat_Start();
}

function DfHeartbeat_OnCommandExec(command)
{
    if(command.Message!=null && command.HandlerId<0)
        DfHeartbeat_DisplayStatusMsg(command.Message);
        
    if(command.LoginInfoValid==true)
    {
        _hb_lastLogoutUrl = command.LogoutUrl;
        var wasLoggedOut = command.LoggedIn==false && _hb_lasLoggedInState==true;
        _hb_lasLoggedInState = command.LoggedIn;
        if(wasLoggedOut)
        {
            DfHeartbeat_DoLogout("Session Ended","Your user session has ended.",
                    "Your session has either timed-out due to inactivity, or there has been a communication disruption " +
                    "between you and the server. We are very sorry for this inconvience. Please login again.",
                    DIALOG_TYPE_COMMERR, command.LogoutUrl);                    
            return;
        }
    }
    if(command.ClientScript!=null)
    {
        try { eval(command.ClientScript);}
        catch(e){}
    }
    if( (command.PopupMessageTitle!=null && Trim(command.PopupMessageTitle)!="") ||
            (command.PopupMessageDetails!=null && Trim(command.PopupMessageDetails)!="") )
    {
        if(typeof(ShowCommonDialog)!="undefined")
        {
            ShowCommonDialog("Server Message",command.PopupMessageTitle,command.PopupMessageDetails,
                command.PopupMessageIcon,null,command.PopupMessageOnOkScript)
        }
        else
        {
            alert(command.PopupMessageTitle!=null?command.PopupMessageTitle:command.PopupMessageDetails);
            if(command.PopupMessageOnOkScript!=null)
            {
                try { eval(command.PopupMessageOnOkScript);}
                catch(e){}
            }
        }
    }
              
    if(command.HandlerId!=null && command.HandlerId>0)
    {
        try
        {
            if(_hb_CommandHandlers[command.HandlerId]!=null)
                _hb_CommandHandlers[command.HandlerId].execute(command);
        }
        catch(e){}
    }
}

function DfHeartbeat_DoLogout(title, msg, description, type, logoutUrl)
{
    if(typeof(ShowCommonDialog)!="undefined")
    {
        DisableArea(document.getElementsByTagName('body')[0],true,'disabledArea');
        ShowCommonDialog(title,msg,description, type,null,"window.location = '" + logoutUrl + "';")
    }
    else
    {
        alert("Your session has has ended due to inactivity or a communication disruption. You will need to log in again.");
        window.location = logoutUrl;
    }
}

function DfHeartbeat_DisplayStatusMsg(info)
{
    var showElem = GET$(_hb_timeoutDisplay);
    if(showElem!=null)
        showElem.innerHTML = info;
}

function DF_CreateMenu(anchorItem, tag, cssClass, parentElem)
{  
    var menuElement = document.createElement("div");
    menuElement.className = cssClass;
    menuElement.style.display = "none";
    menuElement.style.position = "absolute";
    if(parentElem!=null)
        parentElem.appendChild(menuElement);
    else        
        document.body.appendChild(menuElement);

    menuElement.currentItem = tag;
    DF_AnchorMenu(anchorItem,menuElement);
    
    return menuElement;    
}   

function DF_AnchorMenu(anchorItem, menuElement)
{
    if(anchorItem==null)
        return;
            
    var elementPos = new positionInfo(anchorItem);

    var scrollX = 0;
    var scrollY = 0;
    var elm = anchorItem;
    while(elm!=null)
    {
        if(elm.parentElement!=null)
        {
            scrollX += elm.scrollLeft;
            scrollY += elm.scrollTop;
        }
        elm = elm.parentElement;
    }
    menuElement.style.left = (elementPos.getElementLeft()-scrollX) + "px";
    menuElement.style.top = (elementPos.getElementBottom() - scrollY) + "px";
}

function DF_PopupPromptDialog(parent,cssBlackout, cssContainer, itemTemplate)
{
    this.parent = typeof(parent)=="string"?GET$(parent):parent;    
    this.created = false;
    this.cssPromptBlackout = cssBlackout==null?"folderPromptBlackout":cssBlackout;
    this.cssPromptContainer = cssContainer==null?"folderPromptContainer":cssContainer;
    this.tag = null;
    this.itemTemplate = itemTemplate;
    this.maxLength = 255;
    
    this.ensureCreated = function()
    {
        if(this.created==false)
        {
            this.create();
            this.created = true;
        }            
    }
    
    this.create = function()
    {   
        this.blackout = document.createElement("div");
        this.blackout.className = this.cssPromptBlackout;
        this.blackout.style.display = "none";
        this.blackout.style.position = "absolute";
        this.parent.appendChild(this.blackout);

        this.container = document.createElement("div");
        this.container.className = this.cssPromptContainer;
        this.container.style.display = "none";
        this.container.style.position = "absolute";
        this.parent.appendChild(this.container);
        
        this.dialog = document.createElement("div");
        this.dialog.className = "dialog";
        this.container.appendChild(this.dialog);                   
        
        if(this.itemTemplate!=null && typeof(this.itemTemplate)=="function")
            this.itemTemplate(this,this.dialog);
        else
        {
            this.title = document.createElement("div");
            this.title.className = "title";
            this.dialog.appendChild(this.title);                   

            this.description = document.createElement("div");
            this.description.className = "description";
            this.dialog.appendChild(this.description);                   
            
            this.text = document.createElement("input");
            this.text.type = "text";
            this.text.style.width = "100%";
            this.dialog.appendChild(this.text); 
            this.text.handler = this;
            AttachEvent(this.text,"onkeydown",this.keyUpEvent);                  
            
            this.commands = document.createElement("div");
            this.commands.className = "commands";
            this.dialog.appendChild(this.commands);                   

            this.ok = document.createElement("input");
            this.ok.type = "button";
            this.ok.value = "  OK  ";
            this.commands.appendChild(this.ok);                   
            
            this.cancel = document.createElement("input");
            this.cancel.type = "button";
            this.cancel.value = "Cancel";
            this.cancel.defaultText = "Cancel";

            this.commands.appendChild(this.cancel);  
        }
        if(this.cancel!=null)
        {
            this.cancel.handler = this;
            AttachEvent(this.cancel,"onclick",this._cancelEvent);
        }
        if(this.ok!=null)
        {
            this.ok.handler = this;         
            AttachEvent(this.ok,"onclick",this._okEvent); 
        }       
   }
   
    this.keyUpEvent = function(event)
    {
        var target = event.target!=null?event.target:event.srcElement;
        var handler = target.handler;
        if(handler==null)
            return;
        
        var result = true;    
	    var code = (event.keyCode?event.keyCode:event.which);
	    if(code==13)
	    {
	        result = false;
	        handler._handleOK();
        }	        
	    if(event.keyCode)
		    event.returnValue = result;
	    return result;
    }   
                         
    this.show = function(title, description, value, onOk, onCancel, okText, cancelText, tag, autoClose, maxTextLen, disableCenter)
    {
        this.ensureCreated();
        this.autoClose = autoClose!=false;
        this.onCancel = onCancel;
        this.onOk = onOk;
        this.tag = tag;
        
        if(maxTextLen!=null)
            this.maxLength = maxTextLen;
        
        if(this.text!=null)
        {
            if(this.maxLength<=0)
                this.text.setAttribute("maxLength","");
            else                 
                this.text.setAttribute("maxLength",this.maxLength);
        }
        
        if(this.title!=null)                       
            this.title.innerHTML = title==null?"":title;
        if(this.description!=null)
            this.description.innerHTML = description==null?"":description;
        if(this.ok!=null)
            this.ok.value = okText==null||Trim(okText)==""?"  OK  ":okText;
        if(this.cancel!=null)
            this.cancel.value = cancelText==null||Trim(cancelText)==""?(this.cancel.defaultText==null?"Cancel":this.cancel.defaultText):cancelText;
        
        if(this.text!=null)
            this.text.value = value==null?"":value;
        this.resize();
        this.onUpdateUI();
                
        if(this.blackout!=null)
            this.blackout.style.display = ""; 
        this.container.style.display = ""; 
        
        if(disableCenter!=true)
        {
            if(this.container.style.position!="absolute")
                this.container.style.position = "absolute";
            CenterElements(this.blackout,this.container);
        }
        else
            ResizeToElement(this.parent,this.container,true);
        
        if(this.text!=null)
            this.text.focus();                                           
    } 
    
    this.onUpdateUI = function()
    {
    }
    
    this.resize = function()
    {
        if(this.blackout!=null)
            ResizeToElement(this.parent,this.blackout,true);
    }
          
    this.hide = function()
    {
        this.container.style.display = "none";                                
        this.blackout.style.display = "none"; 
    } 
                
    this._cancelEvent = function(event)
    {
        var target = event.target!=null?event.target:event.srcElement;
        if(target==null ||  target.handler==null)
            return;
        var handler = target.handler;                      
        if(handler.autoClose)
            handler.hide();      
        if(handler.onCancel!=null)
        {
            if(typeof(handler.onCancel)=="function")
                handler.onCancel(handler.tag,handler);
            else    
                eval(handler.onCancel);                        
        }                                                                  
    }
    
    this._okEvent = function(event)
    {
        var target = event.target!=null?event.target:event.srcElement;
        if(target==null ||  target.handler==null)
            return;
        var handler = target.handler;
        handler._handleOK();
    }                                                              
    
    this._handleOK = function()
    {
        var res = true;                      
        if(this.onOk!=null)
        {
            if(typeof(this.onOk)=="function")
                res = this.onOk(this.getNotificationObject(),this.tag,this);
            else    
                res = eval(this.onOk);                        
        }                                                                  
        if(res!=false && this.autoClose)
            this.hide();      
    }
    
    this.getNotificationObject = function()
    {
        return this.text==null?null:this.text.value;
    }            
}

function DF_PopupMessageDialog(parent,cssBlackout, cssContainer, itemTemplate)
{
    var dlg = new DF_PopupPromptDialog(parent,cssBlackout, cssContainer, DF_PopupMessageTemplate);   
    return dlg;
}

function DF_PopupMessageTemplate(parent, dialog)
{
    parent.title = document.createElement("div");
    parent.title.className = "title";
    dialog.appendChild(parent.title);                   

    parent.description = document.createElement("div");
    parent.description.className = "description";
    dialog.appendChild(parent.description);                   
        
    parent.commands = document.createElement("div");
    parent.commands.className = "commands";
    dialog.appendChild(parent.commands);                   
    
    parent.cancel = document.createElement("input");
    parent.cancel.type = "button";
    parent.cancel.defaultText = "  OK  ";
    parent.commands.appendChild(parent.cancel);  
}

function DF_PopupConfirmDialog(parent,cssBlackout, cssContainer, itemTemplate)
{
    var dlg = new DF_PopupPromptDialog(parent,cssBlackout, cssContainer, DF_PopupConfirmTemplate);     
    return dlg;
}

function DF_PopupConfirmTemplate(parent, dialog)
{
    parent.title = document.createElement("div");
    parent.title.className = "title";
    dialog.appendChild(parent.title);                   

    parent.description = document.createElement("div");
    parent.description.className = "description";
    dialog.appendChild(parent.description);                   
                
    parent.commands = document.createElement("div");
    parent.commands.className = "commands";
    dialog.appendChild(parent.commands);                   
    
    parent.ok = document.createElement("input");
    parent.ok.type = "button";
    parent.ok.defaultText = "  OK  ";
    parent.commands.appendChild(parent.ok);  

    parent.cancel = document.createElement("input");
    parent.cancel.type = "button";
    parent.cancel.defaultText = "Cancel";
    parent.commands.appendChild(parent.cancel);  
}

function DF_PopupOptSelectDialog(parent, requireValue,cssBlackout, cssContainer, itemTemplate)
{
    var dlg = new DF_PopupPromptDialog(parent,cssBlackout, cssContainer, DF_PopupOptSelectTemplate);   
    dlg.requireValue = requireValue;
    
    dlg.onUpdateUI = function()
    {
        if(!this.requireValue)
            return;
        
        var hasValue = dlg.getSelectedValue()!=null;    
        if(this.ok!=null)
            this.ok.disabled = !hasValue;
    }
    
    dlg.getSelectedValue = function()
    {
        if(this.select==null || this.select.options.selectedIndex<0)
            return null;
        var val = this.select.options[this.select.options.selectedIndex].value;            
        return (val==null||val=="")?null:val;
    }

    dlg.loadOptions = function(nameAndValues, selectedValue)    
    {
        this.ensureCreated();
        if(this.select==null)
            return;

        var sel = selectedValue==null?"":selectedValue;
        this.select.options.length=0;
        var selIndex = 0;
        for(var i=0;i<nameAndValues.length;i++)
        {
            this.select.options[i] = new Option(nameAndValues[i].Name,nameAndValues[i].Value==null?"":nameAndValues[i].Value);
            if(nameAndValues[i].Value == sel && selIndex<=0)
                selIndex = i;
        } 
        if(this.select.options.length>selIndex)
            this.select.options.selectedIndex = selIndex;           
    }
    
    dlg.getNotificationObject = function()
    {
        if(this.select==null || this.select.options.selectedIndex<0)
            return null;
        return this.select.options[this.select.options.selectedIndex].value;
    }            
    
    return dlg;
}

function DF_PopupOptSelectTemplate(parent, dialog)
{
    parent.title = document.createElement("div");
    parent.title.className = "title";
    dialog.appendChild(parent.title);                   

    parent.description = document.createElement("div");
    parent.description.className = "description";
    dialog.appendChild(parent.description);                   

    parent.select = document.createElement("select");
    parent.select.handler = parent;
    dialog.appendChild(parent.select);
    AttachEvent(parent.select,"onchange",
            function(event)
            {
                var target = event.target!=null?event.target:event.srcElement;
                if(target.handler!=null && typeof(target.handler.onUpdateUI)=="function")
                    target.handler.onUpdateUI();
            }
        );
        
    parent.commands = document.createElement("div");
    parent.commands.className = "commands";
    dialog.appendChild(parent.commands);                   
    
    parent.ok = document.createElement("input");
    parent.ok.type = "button";
    parent.ok.defaultText = "  OK  ";
    parent.commands.appendChild(parent.ok);  

    parent.cancel = document.createElement("input");
    parent.cancel.type = "button";
    parent.cancel.defaultText = "Cancel";
    parent.commands.appendChild(parent.cancel);  
}

function DF_BlackoutShow(areaToCover, blackoutElem, blackoutContent,show)
{
    var parent = typeof(areaToCover)=="string"?GET$(areaToCover):areaToCover;
    var blackout = typeof(blackoutElem)=="string"?GET$(blackoutElem):blackoutElem;
    var content = typeof(blackoutContent)=="string"?GET$(blackoutContent):blackoutContent;
    
    if(blackout!=null)
        ResizeToElement(areaToCover,blackout,true);
    
    if(blackout!=null)
        blackout.style.display=show?"":"none";
    if(content!=null)
        content.style.display=show?"":"none";
    if(content!=null)
        CenterElements(blackout,content,0,0,true);
}