// ##############################################
// This section runs everytime a page is loaded 
// ##############################################

var isScriptCapable = (document.getElementById) ? 1 : 0;
var isBeingRemoved = false;

if (!isScriptCapable) {
	alert("Your browser is not supported as it does not adequately process " +
		"current standards of Javascript. Please upgrade to a more recent " +
		"version or try a different browser.");

	top.location.href = "/logout.cfm";
}

// Convert auto function call from VB to Javascript
var isEventCapable = (window.Event) ? 1 : 0;

if (!isEventCapable) {
	document.onkeypress = document_onKeyPressIE;
}

// ##############################################
// END of This section runs everytime a page is loaded 
// ##############################################

function document_onKeyPressIE () {
// Used to force ALL CAPS on text entry.
// Can be overriden by using the following syntax 
// inside of INPUT or TEXTAREA objects:
//    onkeypress="window.event.cancelBubble=true;"
	var iKey, objTarget;

	iKey = event.keyCode;
	objTarget = event.srcElement;

	if (iKey >= 97 && iKey <= 122) {
		iKey = iKey - 32;
	}

	SubmitFormOnEnter (event);

	event.keyCode = iKey;
}

function SubmitFormOnEnter (e) {
	var iKey, objTarget;

	if (isEventCapable) {
		// Non-IE
		iKey = e.which;
		objTarget = e.target;
	} else {
		// IE
		iKey = e.keyCode;
		objTarget = e.srcElement;
	}

	// Submit form on ENTER
	if (objTarget.type != null) {
		if ((objTarget.type.toUpperCase() == "TEXT"
		|| objTarget.type.toUpperCase() == "PASSWORD")
		&& iKey == 13) {
			ManualFormSubmit (objTarget.form);
		}
	}
}

function ManualFormSubmit (objForm) {

	// Capitalize input boxes for non-IE browsers
//	if (isEventCapable) {
//		FormatInputData(objForm);
//	}

	// Check size of Textareas
	if (!CheckTextareaLength(objForm)) {
		return false;
	}

	// Capitalize input boxes for ALL browsers
	FormatInputData(objForm);

	if (!objForm.onsubmit) {
		objForm.submit();
		return true;
	} else {
		if (objForm.onsubmit()) {
			objForm.submit();
			return true;
		} else {
			return false;
		}
	}
}

function EventCancelBubble (e) {
// Used to cancel event bubbling in diff browser versions

	// Cancel bubble
	if (!isEventCapable) {
		window.event.cancelBubble=true;
//	} else {
// Do not run in NON-IE browsers
//		e.stopPropagation();
	}
}

function FormatInputData (objForm) {
// Capitalizes all input fields on a form unless designated otherwise
// in attribute
// objFrame: The frame containing the objects to set focus to
	var iPosSelect, iPosInput, objElements, i, iPosChar1, iPosChar2;

	objElements = objForm.elements;

	for (i=0;i<objElements.length;i++) {
		if (objElements[i].type.toUpperCase() == "TEXT") {
			if (GetAttributeValue(objElements[i], "noUCase") == 2) {
				iPosChar1 = objElements[i].value.indexOf("&");
				iPosChar2 = objElements[i].value.indexOf(";");

				if (!(iPosChar1 >= 0 && iPosChar2 > iPosChar1)) {
					objElements[i].value = objElements[i].value.toUpperCase();
				}
			} else if (GetAttributeValue(objElements[i], "noUCase") != 1) {
				objElements[i].value = objElements[i].value.toUpperCase();
			}
		}
	}
}

function CheckTextareaLength (objForm) {
// Capitalizes all input fields on a form unless designated otherwise
// in attribute
// objFrame: The frame containing the objects to set focus to
	var iPosSelect, iPosInput, objElements, i, iPosChar1, iPosChar2,
		strFunction, strLength, strMsg;

	objElements = objForm.elements;

	for (i=0;i<objElements.length;i++) {
		if (objElements[i].type.toUpperCase() == "TEXTAREA") {
			strFunction = GetAttributeValue(objElements[i], "onkeypress").toUpperCase();

			if (strFunction != '') {
				iPosChar1 = strFunction.indexOf("TEXTAREALENGTH");

				if (iPosChar1 >= 0) {
					iPosChar1 = strFunction.indexOf(",");
					iPosChar2 = strFunction.indexOf(")", iPosChar1);

					if (iPosChar2 >= 0) {
						strLength = js_Trim(strFunction.substring(iPosChar1 + 1, iPosChar2));

						if (js_IsNumeric(strLength)) {
							if (objElements[i].value.length > parseInt(strLength)) {
								strMsg = 'You have exceeded the maximum length of ' +
									'an input textarea. The maximum length allowed ' +
									'is ' + strLength + ' characters and the current ' +
									'content is ' + objElements[i].value.length + ' characters.' +
									'\n\nPlease shorten the text of the field that begins ' +
									'with "' + js_Trim(objElements[i].value.substr(0, 50)) + '".';

								alert(strMsg);
								return false;
							}
						}
					}
				}
			}
		}
	}

	return true;
}

function TextAreaLength(e, maxLength) {
// Acts as a MAXLENGTH=X tag for TEXTAREA objects.
// Doesn't return a message, but cancels the key press when the 
// length of the text in the TEXTAREA object exceeds the allowed length
// maxLength: Maximum length allowed in TEXTAREA
	var str, iKey;

	// Cancel bubble
	EventCancelBubble(e);

	if (isEventCapable) {
		// Stop key if over limit
		str = e.target.value;
		iKey = e.which;

		// Only prevent printable characters
		if ((str.length >= maxLength) &&
		(iKey >= 32 && iKey <= 127)) {
			e.preventDefault();
		}
	} else {
		// Stop key if over limit
		str = e.srcElement.value;

		if (str.length >= maxLength) {
			e.keyCode = 0;
		}
	}
}

function SetFormFocus (objFrame) {
// Sets focus to the first applicable object on a page
// objFrame: The frame containing the objects to set focus to
	var iPosSelect, iPosInput, objForm, objElements, i;

	// No forms exist, exit
	if (objFrame.document.forms.length == 0) {
		return;
	}

	objForm = objFrame.document.forms[0];
	objElements = objForm.elements;

	for (i=0;i<objElements.length;i++) {
		if (objElements[i].style.visibility != "hidden"
		&& objElements[i].type.toUpperCase() != "HIDDEN"
		&& !objElements[i].disabled
		&& !objElements[i].readOnly) {
			if (objElements[i].type.toUpperCase() == "RADIO") {
				if (objElements[i].checked) {
					try
					{
						objElements[i].focus();
						break;
					}
					catch(err)
					{}
				}
			} else {
				try
				{
					if (objElements[i].type.toUpperCase().indexOf("SELECT") < 0) {
						objElements[i].focus();
					}
					break;
				}
				catch(err)
				{}
			}
		}
	}
}

function doSubmitForm () {
	if (FindRemoveObject()) {
		if (ConfirmDelete('remove')) {
			isBeingRemoved = true;
			return true;
		} else {
			return false;
		}
	} else {
		return true;
	}

	return false;
}

function FindRemoveObject () {
// Verifies desire to remove an object
	var obj;

	if (document.getElementsByName("remove").length == 0)
		return false;
	else {
		obj = document.getElementsByName("remove");

		if (obj[0].checked)
			return true;
		else 
			return false;
	}
}

function ConfirmDelete (strObject) {
	var answer, obj, strType, i;

	if (strObject != "") {
		obj = document.getElementsByName(strObject);

		strType = GetAttributeValue(obj[0], "strType");

		if (strType == null) {
			strType = "";
		}
	} else {
		strType = "";
	}

	if (strType != "") {
		answer = confirm("Are you sure you want to permanently remove this " +
			strType + "?");
	} else {
		answer = confirm("Are you sure you want to permanently remove this object?");
	}

	if (answer) {
		return true;
	}

	return false;
}

function RemoveUserObject () {
// Verifies desire to remove an object

	var obj;

	if (document.getElementsByName("removeUser").length == 0)
		return false;
	else {
		obj = document.getElementsByName("removeUser");

		if (obj[0].checked)
			return true;
		else 
			return false;
	}
}

function ToggleAssessmentDetails (objLink, strName, doShow) {
// Hides or shows the inline explanation of assessment criteria
	var i, obj;

	obj = document.getElementsByName(strName);

	for (i=0;i<obj.length;i++) {
		obj[i].style.display = doShow ? "inline" : "none";
	}
}

function doA3Link (iTime) {
	if (document.getElementsByName('a3Timeout').length >= 1) {
		if (document.getElementById('a3Timeout').value == 1) {
			if (confirm('The Attachment links have timed out. ' +
			'Would you like to reload this page to reset the links?' +
			'\n\nNotes: The attachment links time out after ' +
			iTime + ' minutes to prevent unauthorized access.')) {
				location.reload();
			}

			return false;
		}
	}

	return true;
}

function ExpireA3Links () {
	if (document.getElementsByName('a3Timeout').length >= 1) {
		document.getElementById('a3Timeout').value = 1;
	}
}

function SelfAssign (strType, gameID, iPos, iPrevID) {
	if (strType.toLowerCase() == 'ref') {
		if (confirm("You are about to assign yourself to this game. This will " +
		"set you as Accepted in the position you selected and will automatically replace " +
		"any existing Official that may be in that position." +
		"\n\nOnce this is done, you will need to contact your assignor " +
		"to make any further changes." +
		"\n\nAre you sure you want to continue?")) {
			location.href = "/game/gameRefSelfAssign_action.cfm?gameID=" + gameID +
				"&iPos=" + iPos + "&iPrevID=" + iPrevID;
		}
	} else if (strType.toLowerCase() == 'assessor') {
		if (confirm("You are about to assign yourself to this game. This will " +
		"set you as Accepted on the game you selected and will automatically replace " +
		"the primary Assessor on the game (if applicable)." +
		"\n\nOnce this is done, you will need to contact your assignor " +
		"to make any further changes." +
		"\n\nAre you sure you want to continue?")) {
			location.href = "/game/gameAssessorSelfAssign_action.cfm?gameID=" + gameID +
				"&iPos=" + iPos + "&iPrevID=" + iPrevID;
		}
	} else {
		alert("One or more of the options needed to Self-Assign are missing. " +
			"Please reload the page and try again or contact your " +
			"group administrator for further assistance.");
	}
}

function ToggleLoginFrame (isVisible) {
	if (top.document.getElementsByName("objMainFrameLayout").length == 1) {
		top.document.getElementById("objMainFrameLayout").rows =
			isVisible ? "35,*" : "1,*";
	}

	return false;
}

function ToggleTOC () {
	if (top.document.getElementById("objFrameLayout") == null) {
		alert("This feature was recently added and you will " +
			"need to log in again to use it.");
		return false;
	}

	if (top.document.getElementById("objFrameLayout").cols == "115,*") {
		top.document.getElementById("objFrameLayout").cols = "1,*";
		document.getElementById("objHideTOC").innerHTML = '<img src="/images/plain_arrow_bl_rt.gif" ' +
			'width=7 height=7 border=0 align=middle> ' +
			'Show Menu';
	} else {
		top.document.getElementById("objFrameLayout").cols = "115,*";
		document.getElementById("objHideTOC").innerHTML = '<img src="/images/plain_arrow_bl_lf.gif" ' +
			'width=7 height=7 border=0 align=middle> ' +
			'Hide Menu';
	}

	return false;
}

var tTrans;

function doImageGrow (obj, isOver, iSize, isStart) {
	var iWidth = obj.clientWidth;
	var iHeight = obj.clientHeight;
	var isEnd = true;

	if (isStart)
		clearTimeout(tTrans);

	obj.style.cursor = 'wait';

	if (iWidth == 0 || iSize == 0)
		return false;

	if (isOver && iWidth < iSize) {
		iWidth = iWidth + 20;

		if (iWidth >= iSize) {
			iWidth = iSize;
		}

		isEnd = false;
	} else if (!isOver && iWidth > iSize) {
		iWidth = iWidth - 20;

		if (iWidth <= iSize) {
			iWidth = iSize;
		}

		isEnd = false;
	}

	if (!isEnd) {
		if (iWidth <= 60) {
			obj.style.borderTop = '1px solid gray';
			obj.style.borderRight = '2px solid dimgray';
			obj.style.borderBottom = '2px solid dimgray';
			obj.style.borderLeft = '1px solid gray';
		} else if (iWidth <= 90) {
			obj.style.borderTop = '2px solid silver';
			obj.style.borderRight = '3px solid dimgray';
			obj.style.borderBottom = '3px solid dimgray';
			obj.style.borderLeft = '2px solid silver';
		} else if (iWidth <= 120) {
			obj.style.borderTop = '3px solid silver';
			obj.style.borderRight = '5px solid dimgray';
			obj.style.borderBottom = '5px solid dimgray';
			obj.style.borderLeft = '3px solid silver';
		} else {
			obj.style.borderTop = '4px solid silver';
			obj.style.borderRight = '6px solid dimgray';
			obj.style.borderBottom = '6px solid dimgray';
			obj.style.borderLeft = '4px solid silver';
		}

		obj.width = iWidth;

		tTrans = setTimeout(function() {doImageGrow(obj, isOver, iSize, false)}, 50);
	} else {
		obj.style.cursor = 'auto';
	}
}

function ObjLength( obj ) {
// Returns the number of elements in a collection or 1 if not a collection
// obj: Object being checked

	if ( obj != null ) {
		if ( obj.length != null ) {
			if ( obj.type != null ) {
				return 1;
			} else {
				return obj.length;
			}
		} else {
			return 1;
		};
	} else {
		return 0;
	};
}

function BatchSelect (obj, isChecked) {
	var i, iLen, attName, attValue;

	attName = (arguments.length >= 3) ? arguments[2] : '';
	attValue = (arguments.length >= 4) ? arguments[3] : '';

	iLen = ObjLength(obj);

	if (obj != null) {
		for (i=0; i<iLen; i++) {
			if (attName != '') {
				if (obj[i].type.toUpperCase() == 'CHECKBOX') {
					if (obj[i].checked != isChecked) {
						if (GetAttributeValue(obj[i], attName) == attValue) {
							obj[i].click();
						}
					}
				}
			} else {
				if (obj[i].checked != isChecked) {
					obj[i].click();
				}
			}
		}
	}
}

function BatchSelect_Old (obj, isChecked) {
	var i, iLen, attName, attValue;

	attName = (arguments.length >= 3) ? arguments[2] : '';
	attValue = (arguments.length >= 4) ? arguments[3] : '';

	iLen = ObjLength(obj);

	if (obj != null) {
		for (i=0; i<iLen; i++) {
			if (attName != '') {
				if (obj[i].checked != isChecked) {
					if (GetAttributeValue(obj[i], attName) == attValue) {
						obj[i].click();
					}
				}
			} else {
				if (obj[i].checked != isChecked) {
					obj[i].click();
				}
			}
		}
	}
}

function ValidateEmailAddresses (iCount) {
	var i, iLoopCount, strName, strValue, strMsg;

	if (iCount == 0) {
		iLoopCount = 1;
	} else {
		iLoopCount = iCount;
	}

	for (i=1;i<=iLoopCount;i++) {
		if (iCount == 0) {
			strName = "email";
		} else {
			strName = "email" + i;
		}

		if (document.getElementsByName(strName).length == 1) {
			strValue = document.getElementById(strName).value;

			if (strValue == "")
				continue;

			if (!IsValidEmail(strValue, false)) {
				if (iCount == 0) {
					strMsg = "The Email Address does not appear to be valid.";
				} else {
					strMsg = "Email " + i + " does not appear to be a valid address.";
				}
				alert(strMsg + "\nPlease enter a complete email address in the following " +
					"format:\n   username@domain.com");
				return false;
			}
		}
	}

	return true;
}

function ValidateState (str) {
	str = str.toUpperCase();

	if (js_Trim(str) != '' && !IsValidState(str)) {
		if (!confirm('It appears that the value in the State field (' + str + ') ' +
		'is not a valid state/province. If you are sure this value is correct, ' +
		'please click "OK."  Otherwise, please correct the value before continuing.')) {
			return false;
		}
	}

	return true;
}

function QuickGameSearch (strGame) {
	strGame = js_Trim(strGame);

	if (strGame.length < 2) {
		alert("You must enter a valid game number to find");
		return false;
	}

	return true;
}

function CopyToBillingInfo (strName) {
	if (strName != "") {
		document.getElementById('billToName').value = strName;
	}

	document.getElementById('billingAddress1').value =
		document.getElementById('address1').value;

	document.getElementById('billingAddress2').value =
		document.getElementById('address2').value;

	document.getElementById('billingCity').value =
		document.getElementById('city').value;

	document.getElementById('billingState').value =
		document.getElementById('state').value;

	document.getElementById('billingZip').value =
		document.getElementById('zip').value;
}

function UpdateDOW(obj) {
	var objDOW, strValue;
	var arWeekday = new Array(7);
	arWeekday[0]="Sunday";
	arWeekday[1]="Monday";
	arWeekday[2]="Tuesday";
	arWeekday[3]="Wednesday";
	arWeekday[4]="Thursday";
	arWeekday[5]="Friday";
	arWeekday[6]="Saturday";

	objDOW = document.getElementsByName(obj.name + 'DOW');

	if (objDOW.length >= 1) {
		try
		{
			strValue = new Date(obj.value);
			objDOW[0].innerHTML = "(" + arWeekday[strValue.getDay()].substr(0,3) + ")";
			return true;
		}
		catch(err)
		{}

		objDOW[0].innerHTML = "(TBD)";
	}
}

function IncrementDate(obj, iValue) {
	var strValue, strNewValue;

	try
	{
		strValue = obj.value;
		if (strValue == "") {
			strNewValue = new Date();
		} else {
			strNewValue = new Date(strValue);
		}
		if (!isNaN(strNewValue.getFullYear())) {
			strNewValue = new Date(strNewValue.getFullYear(), strNewValue.getMonth(),
				strNewValue.getDate()-0+iValue);
			obj.value = (strNewValue.getMonth() + 1) + '/' + strNewValue.getDate() +
				'/' + strNewValue.getFullYear();
		}
	}
	catch(err)
	{}
}

function FormatTimeValue (timeObject) {
// Used to allow users to enter military or time without ":"
// timeObject: Physical "INPUT TYPE=text" object to reformat
	var i, strValue, strNewTime, iPos, listValidChar, tmpStr;

	listValidChar = "0123456789:";
	strValue = js_Trim(timeObject.value + "");
	strNewTime = "";

	/* Replace periods with colons */
	strValue = js_Replace(strValue, ".", ":", "ONE");

	for (i=0;i<strValue.length;i++) {
		tmpStr = strValue.charAt(i);

		if (listValidChar.indexOf(tmpStr) < 0) {
			return false;
		}
	}

	// Get position of ":" in string
	iPos = strValue.indexOf(":");

	// Add "/" to string if appropriate number of digits are present and
	// no current slashes exist
	if (iPos < 0) {
		if ((strValue.length == 1) || (strValue.length == 2)) {
			strNewTime = strValue + ":00";
		} else if (strValue.length == 3) {
			strNewTime = strValue.substr(0, 1) + ":" + strValue.substr(1, 2)
		} else if (strValue.length == 4) {
			strNewTime = strValue.substr(0, 2) + ":" + strValue.substr(2, 2)
		}
	} else {
		strNewTime = strValue;
	}

	timeObject.value = strNewTime;
}

function FormatTimeValueAMPM (timeObject, strAMPMObject) {
// Used to allow users to enter military or time without ":"
// timeObject: Physical "INPUT TYPE=text" object to reformat
	var i, strValue, strNewTime, iPos, listValidChar, tmpStr,
		strAMPM, strHour, strMin;

	listValidChar = "0123456789:apAP";
	strValue = js_Trim(timeObject.value + "");
	strNewTime = "";
	strAMPM = "";

	/* Replace periods with colons, and remove M's from AM/PM */
	strValue = js_Replace(strValue, ".", ":", "ONE");
	strValue = js_Replace(strValue, "M", "", "ALL");

	for (i=0;i<strValue.length;i++) {
		tmpStr = strValue.charAt(i);

		if (listValidChar.indexOf(tmpStr) < 0) {
			return false;
		}
	}

	/* Determine AM/PM option if present */
	tmpStr = strValue.toUpperCase();

	if (tmpStr.indexOf("A") >= 0) {
		strAMPM = "AM";
	} else if (tmpStr.indexOf("P") >= 0) {
		strAMPM = "PM";
	}

	if (strAMPM != "") {
		strValue = js_Replace(strValue, "A", "", "ALL");
		strValue = js_Replace(strValue, "P", "", "ALL");
		strValue = js_Trim(strValue);
	}

	// Get position of ":" in string
	iPos = strValue.indexOf(":");

	// Add ":" to string if appropriate number of digits are present
	if (iPos < 0) {
		if ((strValue.length == 1) || (strValue.length == 2)) {
			strNewTime = strValue + ":00";
		} else if (strValue.length == 3) {
			strNewTime = strValue.substr(0, 1) + ":" + strValue.substr(1, 2)
		} else if (strValue.length == 4) {
			strNewTime = strValue.substr(0, 2) + ":" + strValue.substr(2, 2)
		}
	} else {
		strNewTime = strValue;
	}

	// Get position of ":" in string
	iPos = strNewTime.indexOf(":");

	// Add ":" to string if appropriate number of digits are present
	if (iPos >= 0) {
		strHour = strNewTime.substr(0, iPos);

		if (js_IsNumeric(strHour)) {
			if (strHour > 12 && strHour < 24) {
				strNewTime = js_Replace(strNewTime, strHour + ":", "", "ALL");

				strHour = strHour - 12;
				strAMPM = "PM";

				strNewTime = strHour + ":" + strNewTime;
			}
		}
	}

	timeObject.value = strNewTime;

	if (document.getElementsByName(strAMPMObject).length == 2
	&& strAMPM != "") {
		if (strAMPM == "AM") {
			document.getElementsByName(strAMPMObject)[0].checked = true;
		} else if (strAMPM == "PM") {
			document.getElementsByName(strAMPMObject)[1].checked = true;
		}
	}
}

function ValidateTime(strTime, strLabel) {
	var i, invalidTime, listValidChar, onHour, strHour, strMin;

	invalidTime = false;
	onHour = true;
	listValidChar = "0123456789:";
	strHour = "";
	strMin = "";

	/* Replace periods with colons */
	strTime = js_Replace(strTime, ".", ":", "ONE");

	for (i=0;i<strTime.length;i++) {
		tmpStr = strTime.charAt(i);

		if (listValidChar.indexOf(tmpStr) < 0) {
			invalidTime = true;
			break;
		}

		if (tmpStr != ":") {
			if (onHour) {
				strHour = strHour + tmpStr;
			} else {
				strMin = strMin + tmpStr;
			}
		} else {
			onHour = false;
		}
	}

	if (!js_IsNumeric(strHour) || !js_IsNumeric(strMin)) {
		invalidTime = true;
	} else if ((strHour < 1) || (strHour > 24)) {
		invalidTime = true;
	} else if ((strMin < 0) || (strMin > 59)) {
		invalidTime = true;
	}

	if (invalidTime) {
		alert(strLabel + " Time must be formatted as follows: 12:00");
		return false;
	}

	return true;
}

function ClearZero (dateObject) {
// Used to avoid a javascript error on certain Cold Fusion form validation
// functions.  The error usually occurs when the date is formatted a certain way.
// To avoid the error, the date is reformatted as "m/d/yyyy" when focus on the 
// control is lost
// dateObject: Physical "INPUT TYPE=text" object to reformat
	var strValue, strNewDate, strYearPart,
		objNow, iCurYear, strNewYear, iPos, iPos2;

	strValue = js_Trim(dateObject.value + "");

	/* Replace periods with colons */
	strValue = js_Replace(strValue, ".", "/", "ALL");

	// Get position of "/" in string
	iPos = strValue.indexOf("/");

	// Add "/" to string if appropriate number of digits are present and
	// no current slashes exist
	if (((strValue.length == 6) || (strValue.length == 8)) && (iPos < 0)) {
		strNewDate = strValue.substr(0, 2) + "/" + strValue.substr(2, 2) + "/" +
			strValue.substr(4, 4)
	} else {
		strNewDate = strValue;
	}

	// Get position of slashes in string since slashes may have been added above
	iPos = strNewDate.indexOf("/");
	iPos2 = strNewDate.lastIndexOf("/");

	// Ensure that date contains correct century
	if (iPos2 >= 0) {
		strYearPart = strNewDate.substr((iPos2 + 1), strNewDate.length);
		objNow = new Date();
		iCurYear = objNow.getFullYear();

		if (js_IsNumeric(strYearPart)) {
			// Ensure that dates > 5 years from now are not entered
			if ((parseInt(strYearPart, 10) > 99 && parseInt(strYearPart, 10) < 2000)
			|| (parseInt(strYearPart, 10) > parseInt(iCurYear + 5, 10))) {
				strYearPart = parseInt(strYearPart.substr((strYearPart.length - 2), strYearPart.length), 10);
			}
		}

		if (js_IsNumeric(strYearPart) && (strYearPart.length != 4)) {
			// There is a 5 year tolerance for future dates.  Any year that is entered
			// without 4 digits will be reformatted as a 2XXX if the year is less than
			// 5 years from today's year.  Otherwise, the 19XX format is used.
			if (((2000 + parseInt(strYearPart, 10)) - iCurYear) <= 5) {
				strNewYear = (parseInt(2000) + parseInt(strYearPart, 10));
			} else {
				strNewYear = (parseInt(1900) + parseInt(strYearPart, 10));
			}

			strNewDate = strNewDate.substring(0, iPos2 + 1) + strNewYear;
		}
	}

	iPos2 = strNewDate.lastIndexOf("/");

	if (iPos >= 0) {
		// Remove leading "0" in all parts of date string
		if (strNewDate.charAt(0) == "0") {
			strNewDate = strNewDate.substring(1, strNewDate.length)
		}

		iPos = strNewDate.indexOf("/");

		if (iPos >= 0) {
			if (strNewDate.charAt(iPos + 1) == "0") {
				strNewDate = strNewDate.substring(0, iPos + 1) +
					strNewDate.substring(iPos + 2, strNewDate.length);
		    }
		}
	}

	// Remove all multiple backslashes from date fields (/)
	strNewDate = js_Replace(strNewDate, "//", "/", "ALL");

	dateObject.value = strNewDate;
}

function GetAttributeValue (obj, strName) {
// Used to return the value of a specific attribute of an element
// If the attribute is not valid, "null" is returned
// obj: Object to check
// strName: Name of attribute to look for
	var i, rValue;

	rValue = "";

	for (i=0;i<obj.attributes.length;i++) {
		if (obj.attributes[i].name.toUpperCase() == strName.toUpperCase()) {
			rValue = obj.attributes[i].value;
			break;
		}
	}

	return rValue;
}

function SetAttributeValue (obj, strName, strValue) {
// Used to set the value of a specific attribute of an element
// Returns true if successful, false if unsuccessful
// obj: Object to check
// strName: Name of attribute to look for
// strValue: Value to set
	var i;

	for (i=0;i<obj.attributes.length;i++) {
		if (obj.attributes[i].name.toUpperCase() == strName.toUpperCase()) {
			obj.attributes[i].value = strValue;
			return true;
		}
	}

	return false;
}

function ShowHideTables (obj, objLabel) {
	if (obj.style.display == "none") {
		obj.style.display = "";
		objLabel.innerHTML = "(Hide)";
	} else {
		obj.style.display = "none";
		objLabel.innerHTML = "(Show)";
	}
}

function ShowHideSection (strObj) {
	var i, isOpen, objImages, objTable, objImg, strImg, hideTable;

	objTable = document.getElementById(strObj);
	objImages = document.getElementById(strObj + 'Header').getElementsByTagName("IMG");

	if (arguments.length >= 3) {
		hideTable = arguments[2];
	} else {
		hideTable = false;
	}

	if (arguments.length >= 2) {
		strImg = arguments[1];
		objImg = document.getElementById(strImg);
	} else {
		if (objImages.length > 0) {
			objImg = objImages[0];
		} else {
			objImg = null;
		}
	}

	isOpen = GetAttributeValue(document.getElementById(strObj), "isOpen");

	// Update first IMG object with new src
	if (isOpen == "0") {
		objTable.className = objTable.className.replace(/Closed/gi, "Open");
		if (objImg != null)
			objImg.src = "/images/hideShow_md_navy_opened.gif";
	} else {
		objTable.className = objTable.className.replace(/Open/gi, "Closed");
		if (objImg != null)
			objImg.src = "/images/hideShow_md_navy_closed.gif";
	}

	SetAttributeValue(document.getElementById(strObj), "isOpen", 1 - isOpen);
}

function ToggleMoreLink (objLink, objContent) {
	if (objContent.style.display.toLowerCase() == "none") {
		objContent.style.display = "inline";
		objLink.style.fontStyle = "normal";
		objLink.innerHTML = "[Close]";
	} else {
		objContent.style.display = "none";
		objLink.style.fontStyle = "italic";
		objLink.innerHTML = "... [more]";
	}
}

function ToggleAdditionalInfo (strType, strObjLink, strObj) {
	var i, iState, obj, iLen, strContent;

	if (typeof strObjLink == 'undefined') {
		strObjLink = "additionalInfoLink";
	}

	if (typeof strObj == 'undefined') {
		strObj = "objAdditionalInfo";
	}

	iState = GetAttributeValue(document.getElementById(strObjLink), 'curState');

	obj = document.getElementsByName(strObj);

	for (i=0;i<obj.length;i++) {
		if (iState == 1) {
			obj[i].style.display = "none";
		} else {
			obj[i].style.display = "";
		}
	}

	if (strType == "") {
		strContent = "";
	} else {
		strContent = " " + strType;
	}

	if (iState == 0) {
		strContent = "(Hide" + strContent + ")";
	} else {
		strContent = "(Show" + strContent + ")";
	}

	document.getElementById(strObjLink).innerHTML = strContent;

	SetAttributeValue(document.getElementById(strObjLink), "curState", (1 - iState));
}

function ChangeRowOver (obj, isHeader) {
// Used in conjunction with ChangeRowOut to highlight an object
	if (obj.LineItem == null)
		return;

	if (isHeader) {
		obj.style.color = "gold";
	} else {
		obj.style.background = "gold";
	}
}

function ChangeRowOut (obj, isHeader) {
// Used in conjunction with ChangeRowOver to unhighlight an object
	if (obj.LineItem == null)
		return;

	if (isHeader) {
		obj.style.color = "white";
	} else {
		obj.style.background = "#ALT_LINE_COLOR#";
	}
}

function ShowCalendarSelect (strDate, strObj, strParam) {
	var strURL;

	strURL = '/misc/calendarDateSelect.cfm?strObj=' + strObj +
		'&iIndex=' + strParam;

	if (strDate != '') {
		strURL = strURL + '&curDate=' + strDate;
	}

	window.open(strURL, 'CalSelect',
		'width=180,height=190,location=No,' +
		'menubar=No,scrollbars=no,status=no,toolbar=No,' +
		'resizable=yes,modal=yes');
}

function SetHover(obj, isHover) {
	if (isHover) {
		obj.className = obj.className.replace('HoverOff', 'HoverOn');
	} else {
		obj.className = obj.className.replace('HoverOn', 'HoverOff');
	}
}

// ##############################################
// GENERIC FUNCTIONS BELOW THIS SECTION
// ##############################################

// NEW FUNCTIONS
function js_FormatNumber(iNum, iDec) {
	if (!js_IsNumeric(iNum) || (iNum.length == 0)) {
		return iNum;
	}

	var i, iDecConvert, iNewNum, strTestNum, strNewNum,
		iDecCount, iPos;

	iDecConvert = Math.pow(10, iDec);

	iNewNum = parseFloat(iNum);
	iNewNum = Math.round(iNewNum * iDecConvert) / iDecConvert;
	strTestNum = iNewNum + "";
	strNewNum = "";

	iPos = strTestNum.indexOf(".");

	if (iDec > 0) {
		if (iDec > 0) {
			if (iPos < 0) {
				strTestNum = strTestNum + ".";
			}

			iPos = strTestNum.indexOf(".");

			iDecCount = strTestNum.length - iPos;

			for (i=0;i<=(iDec - iDecCount);i++) {
				strTestNum = strTestNum + "0";
			}
		}
	} else if ((iPos > 0) && (iDec == 0)) {
		strTestNum = strTestNum.substring(0, iPos);
	}

	iPos = strTestNum.indexOf(".");

	for (i=0;i<strTestNum.length;i++) {
		if ((((iPos - i) % 3) == 0)
		&& (i < iPos)
		&& (strNewNum != "")) {
			strNewNum = strNewNum + ",";
		}

		strNewNum = strNewNum + strTestNum.charAt(i);
	}

	return strNewNum;
}

function js_IsNumeric(str) {
	var i, listNum, iPosDec1, iPosDec2, strChar, iPos;

	listNum = "0123456789";

	str = str + "";

	if (str.length == 0) {
		return false;
	}

	iPosDec1 = str.indexOf(".");
	iPosDec2 = str.lastIndexOf(".");

	if (iPosDec1 != iPosDec2) {
		return false;
	}

	for (i=0;i<str.length;i++) {
		strChar = str.charAt(i);
		iPos = listNum.indexOf(strChar);

		if ((iPos < 0) && (strChar != ".") && !(i==0 && strChar == '-')) {
			return false;
		}
	}

	return true;
}

function js_Trim(str) {
	var i, iLen, strNew;

	str = str + "";

	iLen = str.length;
	strNew = "";

	for (i=0;i<iLen;i++) {
		if (str.charAt(i) != " ") {
			strNew = str.substring(i, iLen);
			break;
		}
	}

	str = strNew;
	iLen = str.length;

	for (i=0;i<iLen;i++) {
		if (str.charAt(iLen - i - 1) != " ") {
			strNew = str.substring(0, iLen - i);
			break;
		}
	}

	return strNew;
}

function js_GetNumeric (str) {
	var i, strChar, iStr;

	str = js_Trim(str);

	iStr = " ";

	for (i=0;i<str.length;i++) {
		strChar = str.substr(i,1);

		if (js_IsNumeric(strChar)) {
			iStr = iStr + strChar;
		} else {
			break;
		}
	}

	iStr = js_Trim(iStr);

	if (!js_IsNumeric(iStr)) {
		iStr = 0;
	}

	return iStr;
}

function js_DateAdd (strType, iValue, dateValue) {
	var i, strChar, iStr;

	if (!js_IsNumeric(iValue)) {
		i = 0;
	} else {
		i = iValue;
	}

	if (strType == 'n' || strType == 'nn' || strType == 'minute') {
		i = (i * 60 * 1000);
	} else if (strType == 'h' || strType == 'hh' || strType == 'hour') {
		i = (i * 60 * 60 * 1000);
	} else if (strType == 'd' || strType == 'dd' || strType == 'day') {
		i = (i * 24 * 60 * 60 * 1000);
	}

    return new Date(dateValue.getTime() + i);
}

function js_Replace(strSource, strReplaceOld, strReplaceNew, strAll) {
	var i, tmpSource, tmpOld, tmpNew, strNew, iPos, iLenOld, iLen;

	strSource = strSource + "";
	strReplaceOld = strReplaceOld + "";
	strReplaceNew = strReplaceNew + "";
	strAll = strAll + "";

	/* Set initial return string */
	strNew = strSource;

	/* Exit if certain empty strings exist */
	if (strSource == "" || strReplaceOld == "") {
		return strNew;
	}

	/* Set to upper case to allow for for case-insensitive */
	strAll = strAll.toUpperCase();
	tmpOld = strReplaceOld.toUpperCase();
	tmpNew = strReplaceNew.toUpperCase();

	i = 1;
	iLenOld = tmpOld.length;

	do {
		tmpSource = strNew.toUpperCase();

		iPos = tmpSource.indexOf(tmpOld);
		iLen = tmpSource.length;

		if (iPos >= 0) {
			strNew = strNew.substring(0, iPos) + strReplaceNew +
				strNew.substring(iPos + iLenOld, iLen);
		}

		/* Exit if first instance and only replacing first occurance */
		if (i == 1 && strAll == "ONE") {
			break;
		}

		i++;
	} while (iPos >= 0)

	return strNew;
}

function js_SetCookie (strName, strValue, iDays, strDomain) {
	var strDate = new Date();
	var strCookie = "";

	if (typeof strDomain == "undefined")
		strDomain = "";

	strDate.setDate(strDate.getDate() + iDays);

	strCookie = strName + "=" + escape(strValue) +
		((iDays==null) ? "" : ";expires=" + strDate.toGMTString());

	if (strDomain != "")
		strCookie = strCookie + ";domain=." + strDomain;

	document.cookie = strCookie;
}

function LoadInfoWindow (strType, ID, strParam) {
	var strURL, iHeight, iWidth;

	if (typeof strParam == 'undefined') strParam = "";

	strType = strType.toUpperCase();
	iHeight = 350;
	iWidth = 500;

	if (ID != 1) {
		if (strType == 'GAME') {
			strURL = "/misc/gameInfo.cfm?gmID=" + ID;
		} else if (strType == 'GAMELOG') {
			strURL = "/misc/gameLogInfo.cfm?gmID=" + ID;
			iWidth = 650;
		} else if (strType == 'REF') {
			strURL = "/misc/refInfo.cfm?refID=" + ID;
		} else if (strType == 'USER') {
			strURL = "/misc/userInfo.cfm?usersID=" + ID;
		} else if (strType == 'LOC') {
			strURL = "/misc/locInfo.cfm?locID=" + ID;
		} else if (strType == 'COMPLEX') {
			strURL = "/misc/complexInfo.cfm?complexID=" + ID;
		} else if (strType == 'LEAGUE') {
			strURL = "/misc/leagueInfo.cfm?lgID=" + ID;
		} else if (strType == 'TEAMGROUP') {
			strURL = "/misc/teamGroupInfo.cfm?tgID=" + ID;
		} else if (strType == 'TEAM') {
			strURL = "/misc/teamInfo.cfm?tmID=" + ID;
		} else if (strType == 'GAMEREPORT') {
			strURL = "/misc/gameReportInfo.cfm?rptID=" + ID;
		} else if (strType == 'ASSESSOR') {
			strURL = "/misc/assessInfo.cfm?assessID=" + ID;
		} else if (strType == 'CONTACT') {
			strURL = "/misc/contactInfo.cfm?cnID=" + ID;
		} else if (strType == 'EMAILLOG') {
			strURL = "/misc/emailLogInfo.cfm?emlID=" + ID;
		} else if (strType == 'HOTEL') {
			strURL = "/misc/hotelInfo.cfm?hotelID=" + ID;
		} else if (strType == 'PROSPECT') {
			strURL = "/public/contactFeedback.cfm?prospectID=" + ID;
		} else if (strType == 'ASSIGNOR') {
			strURL = "/misc/assignorInfo.cfm?assignorID=" + ID;
		} else if (strType == 'ASSIGNORLIST') {
			strURL = "/misc/assignorListInfo.cfm?sgID=" + ID;
		} else if (strType == 'INSTRUCTOR') {
			strURL = "/misc/instructInfo.cfm?instructID=" + ID;
		} else if (strType == 'CLASS') {
			strURL = "/misc/classInfo.cfm?cID=" + ID;
			iWidth = 600;
		} else if (strType == 'ROSTER') {
			strURL = "/misc/classRosterInfo.cfm?cID=" + ID;
			iHeight = 500;
			iWidth = 650;
		} else if (strType == 'ROSTEREMAIL') {
			strURL = "/misc/classEmailInfo.cfm?cID=" + ID;
			iWidth = 650;
		} else if (strType == 'NEWFEATURE') {
			strURL = "/misc/featureHistoryInfo.cfm?fhID=" + ID;
		} else if (strType == 'IMGUPLOAD') {
			strURL = "/utility/uploadImage.cfm?usrID=" + ID;
			iHeight = 650;
			iWidth = 650;
		} else if (strType == 'HELP') {
			strURL = "/help/inlineHelp.cfm?module=" + ID;
		} else if (strType == 'ABOUT') {
			strURL = "/public/about.cfm";
		} else if (strType == 'USSFPMT') {
			strURL = "/misc/USSFLogInfo.cfm?usID=" + ID;
			iHeight = 500;
			iWidth = 650;
		} else if (strType == 'USSFHISTORY') {
			strURL = "/misc/USSFHistoryInfo.cfm?usID=" + ID;
			iWidth = 650;
		} else if (strType == 'EMAILASSESS') {
			strURL = "/misc/assessmentEmailInfo.cfm?gmID=" + ID;
			iHeight = 500;
			iWidth = 550;
		} else if (strType == 'DELETEINFO') {
			strURL = ID;
		} else {
			strURL = "";

			alert("We were unable to retrieve the information you " +
				"requested. This may be a new feature and might " +
				"need to be reloaded/refreshed in order to work.\n\n" +
				"To do this, reload/refresh this individual page,\n"+
				"(or) Log out of the system, close your browser, " +
				"open a new browser, and then log back into the system.");
		}

		if (strURL != "") {
			if (strParam != "") {
				strURL = strURL + strParam;
			}

			window.open(strURL, strType + "Info_" + ID,
				"toolbar=yes,menubar=no,status=no,location=no,resizable=yes," +
				"scrollbars=yes,height=" + iHeight + ",width=" + iWidth);
		}
	}
}

function LoadDeleteInfo (strURL) {
	if (strURL != "") {
		window.open(strURL, "DeleteInfo",
			"toolbar=yes,menubar=no,status=no,location=no,resizable=yes," +
			"scrollbars=yes,height=350,width=500");
	}
}

function ContextHelp (strText) {
	if (strText == "AutoEmailList") {
		alert("Current Auto Official Emails\n" +
			"-------------------------------\n" +
			"- Notification of New Assignments\n" +
			"- Notification when Game is Cancelled\n" +
			"- Notification of Critical Detail Changes to Assigned Games\n" +
			"- Notification when Unassigned From Game\n" +
			"- Notification of Position Change (Center, AR, etc)\n" +
			"\n\n" +
			"Current Auto Assignor Emails\n" +
			"-------------------------------\n" +
			"- Notification when Officials Decline Games\n" +
			"- Notification when Game is Cancelled *\n" +
			"- Notification of Critical Detail Changes to Games *\n" +
			"\n" +
			"* Only when changed by a non-Assignor user (i.e. Team/League)");
	} else if (strText == "TimeEntry") {
		alert("Data Entry Tip:\n" +
			"When entering time data, you can enter a time without ':' or ':00' " +
			"and the system will automatically add ':' or ':00' to the time for you. " +
			"For instance, to save time, enter '2' instead of '2:00' or " +
			"enter '330' instead of '3:30'." +
			"\n\n" +
			"You can also enter times in military format (i.e. 1600, " +
			"1030). If you enter a time past 1200 (i.e. 1430), " +
			"the system will automatically set the time to PM when " +
			"posting the information to the database. However, if the " +
			"time is before 1200, you MUST verify that AM is checked before posting.");
	} else if (strText == "BatchCrewMove") {
		alert("Batch Crew Changes:\n" +
			"\n" +
			"This function allows you to move an entire crew to another game, " +
			"use the same crew on a different game, or swap a crew with a crew " +
			"already assigned to a different game. You can only move, copy, " +
			"or swap crews between games that are on the Batch Maintenance " +
			"page at the same time" +
			"\n\n" +
			"First, click the MOVE, COPY, or SWAP link next to the crew you want to " +
			"move, copy, or swap. Then click the Crew Icon (multiple officials) " +
			"next to the game you want to move, copy, or swap them to. When copying " +
			"crews, you can continue to copy the original crew to multiple games " +
			"without having to click Copy each time. When finished, " +
			"simply click the Cancel link next to the original game." +
			"\n\n" +
			"If you decide not to finish your action, simply click the Cancel link " +
			"and the initial action will be cancelled. Remember you must click " +
			"the SAVE button at the bottom of the page when you have made all " +
			"of your changes and are ready to post the information to the database.");
	} else if (strText == "dummyGames") {
		alert("Duplicate 'TBD' Games:\n" +
			"\n" +
			"This function allows you to enter a 'Dummy' game record " +
			"for several games at one time. You will complete the New Game " +
			"information as usual, but you will also have the option " +
			"to specify the number of games to create for that same " +
			"date, time, level, teams, etc." +
			"\n\n" +
			"This can be used for entering games in batch mode where " +
			"the details will be filled out individually for each game " +
			"at a later date or in batch mode using the Batch Game Edit. " +
			"Usually, the time is set to 12:01am (TBD) and the " +
			"Location and/or Teams are set to [TBD].");
	} else if (strText == "availabilityFilter") {
		alert("Availability Filter Options:\n" +
			"\n" +
			"Assume Unavailable" +
			"\nOfficials will be assumed to be Unavailable for a game " +
			"if they do not have an availability entry that states they " +
			"are available for the entire time period of that game." +
			"\n\n" +
			"Assume Available" +
			"\nOfficials will be assumed to be Available for a game " +
			"unless they have an availability entry that states they " +
			"are NOT available for some or all of that game.");
	} else if (strText == "GameNumEntry") {
		alert("Data Entry Tip:\n" +
			"When entering game numbers, you can enter any combination of " +
			"letters and numbers. If you have changed the game number and want " +
			"to reset it back to the random 5 digit number, enter \"TBD\" and " +
			"the original number will be restored when you save the information.");
	} else if (strText == "BillToEntry") {
		alert("Data Entry Tip:\n" +
			"N/A (No Fees) means that there will be no Bills or Payments for this game.");
	} else if (strText == "PaidOnsiteEntry") {
		alert("Data Entry Tip:\n" +
			"Paid Onsite means that the League / Team will not be billed " +
			"for the Officials' Fees but will still be billed " +
			"for any amount that exceeds the Officials' Fees (if applicable).");
	} else if (strText == "AssignFilterList") {
		alert("If the list of Officials for this game is smaller than expected, " +
			"disable one or more of the Assignor Filters for this League " +
			"and reload this page.\n\nYou can enable or disable Assignor " +
			"Filters under Group Maint : League : (Select League)." +
			"\n\nBe sure to save any work you have done on this page " +
			"before navigating to another area.");
	}

	return false;
}

function js_Left(str, n) {
	if (n <= 0)
	    return "";
	else if (n > String(str).length)
	    return str;
	else
	    return String(str).substring(0,n);
}

function js_Right(str, n) {
    if (n <= 0)
       return "";
    else if (n > String(str).length)
       return str;
    else {
       var iLen = String(str).length;
       return String(str).substring(iLen, iLen - n);
    }
}

// ##############################################
/*
Name: jsDate
Desc: VBScript native Date functions emulated for Javascript
Author: Rob Eberhardt, Slingshot Solutions - http://slingfive.com/
History:
	2005-08-04	v0.94		scrapped new dateDiff approach to better match VBScript's simplistic Y/M/Q
	2005-08-03	v0.93		fixed dateDiff/leapyear bug with yyyy/m/q intervals
	2004-11-26	v0.91		fixed datePart/ww bug, added weekdayName() & monthName()
	2004-08-30	v0.9		brand new
	
*/
// ##############################################

// used by dateAdd, dateDiff, datePart, weekdayName, and monthName
// note: less strict than VBScript's isDate, since JS allows invalid dates to overflow (e.g. Jan 32 transparently becomes Feb 1)
function isDate(p_Expression){
	return !isNaN(new Date(p_Expression));		// <<--- this needs checking
}


// REQUIRES: isDate()
function dateAdd(p_Interval, p_Number, p_Date){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}
	if(isNaN(p_Number)){return "invalid number: '" + p_Number + "'";}	

	p_Number = new Number(p_Number);
	var dt = new Date(p_Date);
	switch(p_Interval.toLowerCase()){
		case "yyyy": {// year
			dt.setFullYear(dt.getFullYear() + p_Number);
			break;
		}
		case "q": {		// quarter
			dt.setMonth(dt.getMonth() + (p_Number*3));
			break;
		}
		case "m": {		// month
			dt.setMonth(dt.getMonth() + p_Number);
			break;
		}
		case "y":		// day of year
		case "d":		// day
		case "w": {		// weekday
			dt.setDate(dt.getDate() + p_Number);
			break;
		}
		case "ww": {	// week of year
			dt.setDate(dt.getDate() + (p_Number*7));
			break;
		}
		case "h": {		// hour
			dt.setHours(dt.getHours() + p_Number);
			break;
		}
		case "n": {		// minute
			dt.setMinutes(dt.getMinutes() + p_Number);
			break;
		}
		case "s": {		// second
			dt.setSeconds(dt.getSeconds() + p_Number);
			break;
		}
		case "ms": {		// second
			dt.setMilliseconds(dt.getMilliseconds() + p_Number);
			break;
		}
		default: {
			return "invalid interval: '" + p_Interval + "'";
		}
	}
	return dt;
}


// REQUIRES: isDate()
// NOT SUPPORTED: firstdayofweek and firstweekofyear (defaults for both)
function dateDiff(p_Interval, p_Date1, p_Date2, p_firstdayofweek, p_firstweekofyear){
	if(!isDate(p_Date1)){return "invalid date: '" + p_Date1 + "'";}
	if(!isDate(p_Date2)){return "invalid date: '" + p_Date2 + "'";}
	var dt1 = new Date(p_Date1);
	var dt2 = new Date(p_Date2);

	// get ms between dates (UTC) and make into "difference" date
	var iDiffMS = dt2.valueOf() - dt1.valueOf();
	var dtDiff = new Date(iDiffMS);

	// calc various diffs
	var nYears  = dt2.getUTCFullYear() - dt1.getUTCFullYear();
	var nMonths = dt2.getUTCMonth() - dt1.getUTCMonth() + (nYears!=0 ? nYears*12 : 0);
	var nQuarters = parseInt(nMonths/3);	//<<-- different than VBScript, which watches rollover not completion
	
	var nMilliseconds = iDiffMS;
	var nSeconds = parseInt(iDiffMS/1000);
	var nMinutes = parseInt(nSeconds/60);
	var nHours = parseInt(nMinutes/60);
	var nDays  = parseInt(nHours/24);
	var nWeeks = parseInt(nDays/7);


	// return requested difference
	var iDiff = 0;		
	switch(p_Interval.toLowerCase()){
		case "yyyy": return nYears;
		case "q": return nQuarters;
		case "m": return nMonths;
		case "y": 		// day of year
		case "d": return nDays;
		case "w": return nDays;
		case "ww":return nWeeks;		// week of year	// <-- inaccurate, WW should count calendar weeks (# of sundays) between
		case "h": return nHours;
		case "n": return nMinutes;
		case "s": return nSeconds;
		case "ms":return nMilliseconds;	// millisecond	// <-- extension for JS, NOT available in VBScript
		default: return "invalid interval: '" + p_Interval + "'";
	}
}


// REQUIRES: isDate(), dateDiff()
// NOT SUPPORTED: firstdayofweek and firstweekofyear (does system default for both)
function datePart(p_Interval, p_Date, p_firstdayofweek, p_firstweekofyear){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}

	var dtPart = new Date(p_Date);
	switch(p_Interval.toLowerCase()){
		case "yyyy": return dtPart.getFullYear();
		case "q": return parseInt(dtPart.getMonth()/3)+1;
		case "m": return dtPart.getMonth()+1;
		case "y": return dateDiff("y", "1/1/" + dtPart.getFullYear(), dtPart);			// day of year
		case "d": return dtPart.getDate();
		case "w": return dtPart.getDay();	// weekday
		case "ww":return dateDiff("ww", "1/1/" + dtPart.getFullYear(), dtPart);		// week of year
		case "h": return dtPart.getHours();
		case "n": return dtPart.getMinutes();
		case "s": return dtPart.getSeconds();
		case "ms":return dtPart.getMilliseconds();	// millisecond	// <-- extension for JS, NOT available in VBScript
		default: return "invalid interval: '" + p_Interval + "'";
	}
}


// REQUIRES: isDate()
// NOT SUPPORTED: firstdayofweek (does system default)
function weekdayName(p_Date, p_abbreviate){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}
	var dt = new Date(p_Date);
	var retVal = dt.toString().split(' ')[0];
	var retVal = Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')[dt.getDay()];
	if(p_abbreviate==true){retVal = retVal.substring(0, 3)}	// abbr to 1st 3 chars
	return retVal;
}
// REQUIRES: isDate()
function monthName(p_Date, p_abbreviate){
	if(!isDate(p_Date)){return "invalid date: '" + p_Date + "'";}
	var dt = new Date(p_Date);	
	var retVal = Array('January','February','March','April','May','June','July','August','September','October','November','December')[dt.getMonth()];
	if(p_abbreviate==true){retVal = retVal.substring(0, 3)}	// abbr to 1st 3 chars
	return retVal;
}

// ====================================

// bootstrap different capitalizations
function IsDate(p_Expression){
	return isDate(p_Expression);
}
function DateAdd(p_Interval, p_Number, p_Date){
	return dateAdd(p_Interval, p_Number, p_Date);
}
function DateDiff(p_interval, p_date1, p_date2, p_firstdayofweek, p_firstweekofyear){
	return dateDiff(p_interval, p_date1, p_date2, p_firstdayofweek, p_firstweekofyear);
}
function DatePart(p_Interval, p_Date, p_firstdayofweek, p_firstweekofyear){
	return datePart(p_Interval, p_Date, p_firstdayofweek, p_firstweekofyear);
}
function WeekdayName(p_Date){
	return weekdayName(p_Date);
}
function MonthName(p_Date){
	return monthName(p_Date);
}


// ##############################################
// Changes:  Sandeep V. Tamhankar (stamhankar@hotmail.com)
// ##############################################

/*
	JJB: Added additional parameters to function and integrated

   1.1.2: Fixed a bug where trailing . in e-mail address was passing
            (the bug is actually in the weak regexp engine of the browser; I
            simplified the regexps to make it work).
   1.1.1: Removed restriction that countries must be preceded by a domain,
            so abc@host.uk is now legal.  However, there's still the 
            restriction that an address must end in a two or three letter
            word.
     1.1: Rewrote most of the function to conform more closely to RFC 822.
     1.0: Original  */

// This script and many more are available free online at
// The JavaScript Source!! http://javascript.internet.com

function IsValidEmail (emailStr, useAlert) {
	if (typeof useAlert == 'undefined')
		useAlert = true;

	/* The following pattern is used to check if the entered e-mail address
	   fits the user@domain format.  It also is used to separate the username
	   from the domain. */
	var emailPat=/^(.+)@(.+)$/
	/* The following string represents the pattern for matching all special
	   characters.  We don't want to allow special characters in the address. 
	   These characters include ( ) < > @ , ; : \ " . [ ]    */
	var specialChars="\\(\\)<>@,;:\\\\\\\"\\.\\[\\]"
	/* The following string represents the range of characters allowed in a 
	   username or domainname.  It really states which chars aren't allowed. */
	var validChars="\[^\\s" + specialChars + "\]"
	/* The following pattern applies if the "user" is a quoted string (in
	   which case, there are no rules about which characters are allowed
	   and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com
	   is a legal e-mail address. */
	var quotedUser="(\"[^\"]*\")"
	/* The following pattern applies for domains that are IP addresses,
	   rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
	   e-mail address. NOTE: The square brackets are required. */
	var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/
	/* The following string represents an atom (basically a series of
	   non-special characters.) */
	var atom=validChars + '+'
	/* The following string represents one word in the typical username.
	   For example, in john.doe@somewhere.com, john and doe are words.
	   Basically, a word is either an atom or quoted string. */
	var word="(" + atom + "|" + quotedUser + ")"
	// The following pattern describes the structure of the user
	var userPat=new RegExp("^" + word + "(\\." + word + ")*$")
	/* The following pattern describes the structure of a normal symbolic
	   domain, as opposed to ipDomainPat, shown above. */
	var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$")


	/* Finally, let's start trying to figure out if the supplied address is
	   valid. */

	/* Begin with the coarse pattern to simply break up user@domain into
	   different pieces that are easy to analyze. */
	var matchArray=emailStr.match(emailPat)
	if (matchArray==null) {
	  /* Too many/few @'s or something; basically, this address doesn't
	     even fit the general mould of a valid e-mail address. */
		if (useAlert) { alert("Email address seems incorrect (check @ and .'s)") }
		return false
	}
	var user=matchArray[1]
	var domain=matchArray[2]

	// See if "user" is valid 
	if (user.match(userPat)==null) {
	    // user is not valid
	    if (useAlert) { alert("Invalid Email Address: The username doesn't seem to be valid") }
	    return false
	}

	/* if the e-mail address is at an IP address (as opposed to a symbolic
	   host name) make sure the IP address is valid. */
	var IPArray=domain.match(ipDomainPat)
	if (IPArray!=null) {
	    // this is an IP address
		  for (var i=1;i<=4;i++) {
		    if (IPArray[i]>255) {
		        if (useAlert) { alert("Invalid Email Address: Destination IP address is invalid") }
			return false
		    }
	    }
	    return true
	}

	// Domain is symbolic name
	var domainArray=domain.match(domainPat)
	if (domainArray==null) {
		if (useAlert) { alert("Invalid Email Address: The domain name doesn't seem to be valid") }
	    return false
	}

	/* domain name seems valid, but now make sure that it ends in a
	   three-letter word (like com, edu, gov) or a two-letter word,
	   representing country (uk, nl), and that there's a hostname preceding 
	   the domain or country. */

	/* Now we need to break up the domain to get a count of how many atoms
	   it consists of. */
	var atomPat=new RegExp(atom,"g")
	var domArr=domain.match(atomPat)
	var len=domArr.length
	if (domArr[domArr.length-1].length<2 || 
	    domArr[domArr.length-1].length>4) {
	   // the address must end in a two, three or four letter word.
	   if (useAlert) { alert("Invalid Email Address: The address must end in a three or four-letter domain, or two letter country.") }
	   return false
	}

	// Make sure there's a host name preceding the domain.
	if (len<2) {
	   var errStr="Invalid Email Address: This address is missing a hostname!"
	   if (useAlert) { alert(errStr) }
	   return false
	}

	// If we've gotten this far, everything's valid!
	return true;
}
//  End

function IsValidState(str) {
	var listStates = ',AL,AK,AZ,AR,CA,CO,CT,DE,FL,GA,HI,ID,IL,IN,IA,KS,' +
		'KY,LA,ME,MD,MA,MI,MN,MS,MO,MT,NE,NV,NH,NJ,NM,NY,NC,ND,OH,OK,OR,' +
		'PA,RI,SC,SD,TN,TX,UT,VT,VA,WA,WV,WI,WY,AS,DC,FM,GU,MH,MP,PW,PR,' +
		'VI,AE,AA,AP,ON,QC,NF,NS,NB,MB,SK,AB,BC,';

	str = str.toUpperCase();

	if (listStates.indexOf(',' + str + ',') >= 0) {
		return true;
	} else {
		return false;
	}
}

function GetZipCodeDistance(lat1, lon1, lat2, lon2, unit) {
	if (parseFloat(lat1) == 0
	|| parseFloat(lon1) == 0
	|| parseFloat(lat2) == 0
	|| parseFloat(lon2) == 0) {
		return 0;
	}

	var radlat1 = Math.PI * lat1 / 180;
	var radlat2 = Math.PI * lat2 / 180;
	var radlon1 = Math.PI * lon1 / 180;
	var radlon2 = Math.PI * lon2 / 180;

	var theta = lon1 - lon2;
	var radtheta = Math.PI * theta / 180;
	var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);

	dist = Math.acos(dist);
	dist = dist * 180 / Math.PI;
	dist = dist * 60 * 1.1515;

	if (unit=="K") { dist = dist * 1.609344 }
	if (unit=="N") { dist = dist * 0.8684 }

	return dist;
}
