/*
***********************************************************************************
*
*   UTILITY.JS
*	Source Code Library for Javascript development
*
*   This Module contains many reusable generic functions for use within Javascript.  
*	Any code entered into this module should be completely reusable by any application.
*
*	Modification History:
*		Date		Author		Change Description
*		--------------------------------------------------------------------------
***********************************************************************************
*/
	// convert all characters to lowercase to simplify testing
	var agt=navigator.userAgent.toLowerCase();
	var appVer = navigator.appVersion.toLowerCase();

	// *** BROWSER VERSION ***
	var is_minor = parseFloat(appVer);
	var is_major = parseInt(is_minor);

	// Note: On IE, start of appVersion return 3 or 4
	// which supposedly is the version of Netscape it is compatible with.
	// So we look for the real version further on in the string
	var iePos  = appVer.indexOf('msie');
	if (iePos !=-1) {
	   is_minor = parseFloat(appVer.substring(iePos+5,appVer.indexOf(';',iePos)))
	   is_major = parseInt(is_minor);
	}

	// Netscape6 is mozilla/5 + Netscape6/6.0!!!
	// Mozilla/5.0 (Windows; U; Win98; en-US; m18) Gecko/20001108 Netscape6/6.0
	var nav6Pos = agt.indexOf('netscape6');
	if (nav6Pos !=-1) {
	   is_minor = parseFloat(agt.substring(nav6Pos+10))
	   is_major = parseInt(is_minor)
	}

	var is_getElementById   = (document.getElementById) ? "true" : "false";
	var is_getElementsByTagName = (document.getElementsByTagName) ? "true" : "false";
	var is_documentElement = (document.documentElement) ? "true" : "false";

	var is_nav  = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
	            && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
	            && (agt.indexOf('webtv')==-1));
	var is_nav2 = (is_nav && (is_major == 2));
	var is_nav3 = (is_nav && (is_major == 3));
	var is_nav4 = (is_nav && (is_major == 4));
	var is_nav4up = (is_nav && is_minor >= 4);

	var is_navonly      = (is_nav && ((agt.indexOf(";nav") != -1) ||
	                      (agt.indexOf("; nav") != -1)) );

	var is_nav6   = (is_nav && is_major==6);
	var is_nav6up = (is_nav && is_minor >= 6)

	var is_nav5   = (is_nav && is_major == 5 && !is_nav6);
	var is_nav5up = (is_nav && is_minor >= 5);

	var is_ie   = (iePos!=-1);
	var is_ie3  = (is_ie && (is_major < 4));

	var is_ie4   = (is_ie && is_major == 4);
	var is_ie4up = (is_ie && is_minor >= 4);
	var is_ie5   = (is_ie && is_major == 5);
	var is_ie5up = (is_ie && is_minor >= 5);

	// KNOWN BUG: On AOL4, returns false if IE3 is embedded browser
	// or if this is the first browser window opened.  Thus the
	// variables is_aol, is_aol3, and is_aol4 aren't 100% reliable.

	var is_aol   = (agt.indexOf("aol") != -1);
	var is_aol3  = (is_aol && is_ie3);
	var is_aol4  = (is_aol && is_ie4);

	var is_opera = (agt.indexOf("opera") != -1);
	var is_webtv = (agt.indexOf("webtv") != -1);

	// *** JAVASCRIPT VERSION CHECK ***
	// Useful to workaround Nav3 bug in which Nav3 loads <SCRIPT LANGUAGE="JavaScript1.2">.
	var is_js;
	if (is_nav2 || is_ie3) is_js = 1.0
	else if (is_nav3 || is_opera) is_js = 1.1
	else if ((is_nav4 && (is_minor <= 4.05)) || is_ie4) is_js = 1.2
	else if ((is_nav4 && (is_minor > 4.05)) || is_ie5) is_js = 1.3
	else if (is_nav5 && !(is_nav6)) is_js = 1.4
	else if (is_nav6) is_js = 1.5
	else if (is_nav && (is_major > 5)) is_js = 1.4
	else if (is_ie && (is_major > 5)) is_js = 1.3
	else is_js = 0.0;

	// *** PLATFORM ***
	var is_win   = ( (agt.indexOf("win")!=-1) || (agt.indexOf("16bit")!=-1) );
	// NOTE: On Opera 3.0, the userAgent string includes "Windows 95/NT4" on all
	//        Win32, so you can't distinguish between Win95 and WinNT.
	var is_win95 = ((agt.indexOf("win95")!=-1) || (agt.indexOf("windows 95")!=-1));

	// is this a 16 bit compiled version?
	var is_win16 = ((agt.indexOf("win16")!=-1) ||
	           (agt.indexOf("16bit")!=-1) || (agt.indexOf("windows 3.1")!=-1) ||
	           (agt.indexOf("windows 16-bit")!=-1) );

	var is_win31 = ((agt.indexOf("windows 3.1")!=-1) || (agt.indexOf("win16")!=-1) ||
	                (agt.indexOf("windows 16-bit")!=-1));

	// NOTE: Reliable detection of Win98 may not be possible. It appears that:
	//       - On Nav 4.x and before you'll get plain "Windows" in userAgent.
	//       - On Mercury client, the 32-bit version will return "Win98", but
	//         the 16-bit version running on Win98 will still return "Win95".
	var is_win98 = ((agt.indexOf("win98")!=-1) || (agt.indexOf("windows 98")!=-1));
	var is_winnt = ((agt.indexOf("winnt")!=-1) || (agt.indexOf("windows nt")!=-1));
	var is_win32 = (is_win95 || is_winnt || is_win98 ||
	                ((is_major >= 4) && (navigator.platform == "Win32")) ||
	                (agt.indexOf("win32")!=-1) || (agt.indexOf("32bit")!=-1));

	var is_os2   = ((agt.indexOf("os/2")!=-1) ||
	                (navigator.appVersion.indexOf("OS/2")!=-1) ||
	                (agt.indexOf("ibm-webexplorer")!=-1));

	var is_mac    = (agt.indexOf("mac")!=-1);
	var is_mac68k = (is_mac && ((agt.indexOf("68k")!=-1) ||
	                           (agt.indexOf("68000")!=-1)));
	var is_macppc = (is_mac && ((agt.indexOf("ppc")!=-1) ||
	                            (agt.indexOf("powerpc")!=-1)));

	var is_sun   = (agt.indexOf("sunos")!=-1);
	var is_sun4  = (agt.indexOf("sunos 4")!=-1);
	var is_sun5  = (agt.indexOf("sunos 5")!=-1);
	var is_suni86= (is_sun && (agt.indexOf("i86")!=-1));
	var is_irix  = (agt.indexOf("irix") !=-1);    // SGI
	var is_irix5 = (agt.indexOf("irix 5") !=-1);
	var is_irix6 = ((agt.indexOf("irix 6") !=-1) || (agt.indexOf("irix6") !=-1));
	var is_hpux  = (agt.indexOf("hp-ux")!=-1);
	var is_hpux9 = (is_hpux && (agt.indexOf("09.")!=-1));
	var is_hpux10= (is_hpux && (agt.indexOf("10.")!=-1));
	var is_aix   = (agt.indexOf("aix") !=-1);      // IBM
	var is_aix1  = (agt.indexOf("aix 1") !=-1);
	var is_aix2  = (agt.indexOf("aix 2") !=-1);
	var is_aix3  = (agt.indexOf("aix 3") !=-1);
	var is_aix4  = (agt.indexOf("aix 4") !=-1);
	var is_linux = (agt.indexOf("inux")!=-1);
	var is_sco   = (agt.indexOf("sco")!=-1) || (agt.indexOf("unix_sv")!=-1);
	var is_unixware = (agt.indexOf("unix_system_v")!=-1);
	var is_mpras    = (agt.indexOf("ncr")!=-1);
	var is_reliant  = (agt.indexOf("reliantunix")!=-1);
	var is_dec   = ((agt.indexOf("dec")!=-1) || (agt.indexOf("osf1")!=-1) ||
	       (agt.indexOf("dec_alpha")!=-1) || (agt.indexOf("alphaserver")!=-1) ||
	       (agt.indexOf("ultrix")!=-1) || (agt.indexOf("alphastation")!=-1));
	var is_sinix = (agt.indexOf("sinix")!=-1);
	var is_freebsd = (agt.indexOf("freebsd")!=-1);
	var is_bsd = (agt.indexOf("bsd")!=-1);
	var is_unix  = ((agt.indexOf("x11")!=-1) || is_sun || is_irix || is_hpux ||
	             is_sco ||is_unixware || is_mpras || is_reliant ||
	             is_dec || is_sinix || is_aix || is_linux || is_bsd || is_freebsd);

	var is_vms   = ((agt.indexOf("vax")!=-1) || (agt.indexOf("openvms")!=-1));
	var is_anchors = (document.anchors) ? "true":"false";
	var is_regexp = (window.RegExp) ? "true":"false";
	var is_option = (window.Option) ? "true":"false";
	var is_all = (document.all) ? "true":"false";

	document.cookie = "cookies=true";
	var is_cookie = (document.cookie) ? "true" : "false";
	var is_images = (document.images) ? "true":"false";
	var is_layers = (document.layers) ? "true":"false"; // gecko m7 bug?

	var is_forms = (document.forms) ? "true" : "false";
	var is_links = (document.links) ? "true" : "false";
	var is_frames = (window.frames) ? "true" : "false";
	var is_screen = (window.screen) ? "true" : "false";

	var is_java = (navigator.javaEnabled());


	function jfFormatDateMDY(pstrDate) {
	/************************************************************************
	' Function:		jfFormatDateMDY
	' Purpose:		Format the specified date string in the format MM/DD/YYYY
	' Arguments:	pstrDate	- Value to format
	' Returns:		String formatted to MM/DD/YYYY if valid, empty string otherwise
	' Author:		Jeff Baron
	' Date:			11/8/2000
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		var vData = new Date(pstrDate);
		var vMonth = 1 + vData.getMonth();
		var vDay = vData.getDate();
		var vYear = vData.getFullYear();

		if ((isNaN(vMonth) == true) || (isNaN(vDay) == true) || (isNaN(vYear) == true)) {
			vData = "";
		}
		else {
			vMonth = (vMonth.toString().length < 2) ? "0" + vMonth : vMonth;
			vDay = (vDay.toString().length < 2) ? "0" + vDay : vDay;

			vData = vMonth + "\/" + vDay + "\/" + vYear;
		}

		return vData;
	}


	function jfSelectComboItem(pctlSelect, pstrSearch, pintProperty) {
	/************************************************************************
	' Function:		jfSelectComboItem
	' Purpose:		Check if the search string is also in the SELECT.
	' Arguments:	pctlSelect	- <SELECT> control to search.
	'				pstrSearch	- Value to search for.
	'				pintProperty- What to search (0 = value, 1 = text)
	' Returns:		1 if a match was found, 0 otherwise
	' Author:		Adapted by Jeff Baron.  Original code found at 
	'				http://www.houts.com/devel/javascript/search_combo.html
	' Date:			12/11/2000
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		var i,j;
		var strCheckString;
		var intNumChars;
		var strComboString;
		var boolItemFound = false;
		var intListIndex = 0;

		if (pctlSelect.options.length > 0) {
			intNumChars = pstrSearch.length;

			for ( i = 0; i < intNumChars ; i++) {
				boolItemFound = false;
				strCheckString = String(pstrSearch.substring(0, i + 1)).toUpperCase();

				for ( j = intListIndex; j < pctlSelect.options.length ; j++) {
					if (pintProperty == 0) {
						strComboString = String(pctlSelect.options[j].value).toUpperCase();
					}
					else {
						strComboString = String(pctlSelect.options[j].text).toUpperCase();
					}

					strComboString = strComboString.substring(0,i+1);

					if (strCheckString == strComboString) {
						boolItemFound = true;
						intListIndex = j;
						break;
					}
				}

				if (!boolItemFound)
					break;
			}

			pctlSelect.options[intListIndex].selected = true;
		}
	}


	function jfIsText(pstrSource) {
	/************************************************************************
	' Procedure:	jfIsText
	' Purpose:		Verify that the passed in string contains at least one 
	'				character
	' Arguments:	pstrSource	- String you want to check
	' Returns:		True if valid, False otherwise
	' Author:		Jeff Baron
	' Date:			2/2000
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		// Test for a string
		if (pstrSource.length > 0) {
			return true;
		}
		return false;
	}


	function jfAutoTrimText(pctlSource) {
	/************************************************************************
	' Procedure:	jfAutoTrimText
	' Purpose:		Strip all leading and trailing spaces from the 
	'				passed-in string.
	' Arguments:	pctlSource	- Control whose text you want to reformat.
	' Returns:		Nothing
	' Author:		Jeff Baron
	' Date:			2/2000
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		if (is_ie4up) {
			var ctlSource = eval(pctlSource);
		}
		else if (is_nav4up) {
			var ctlSource = eval(pctlSource.target);
		}

		var strTemp = ctlSource.value;

		if (jfIsText(strTemp)) {
			// Trim leading spaces from the original string
			while (1) {
				if (strTemp.substring(0, 1) != " ")
					break;

				strTemp = strTemp.substring(1, strTemp.length);
			}

			// Trim trailing spaces from the original string
			while (1) {
				if (strTemp.substring(strTemp.length - 1, strTemp.length) != " ")
					break;

				strTemp = strTemp.substring(0, strTemp.length - 1);
			}

			ctlSource.value = strTemp;
		}
	}


	function jfResetControl(pctlSource, pstrMessage) {
	/************************************************************************
	' Function:		ResetControl
	' Purpose:		Wrapper around focus() function.  Use to clear out a
	'				control and set focus back to it.
	' Arguments:	pctlSource	- Control to clear out and focus on
	'				pstrMessage	- Message to display to user (optional)
	' Returns:		Nothing
	' Author:		Jeff Baron
	' Date:			2/25/2000
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		if (jfIsText(pstrMessage)) {
			alert(pstrMessage);
		}

		pctlSource.value = "";
		pctlSource.focus();
	}

	function jfResetCheckBox(pctlSource, pstrMessage) {
	/************************************************************************
	' Function:		ResetCheckbox
	' Purpose:		Wrapper around focus() function.  Use to uncheck a
	'				control and set focus back to it.
	' Arguments:	pctlSource	- Control to clear out and focus on
	'				pstrMessage	- Message to display to user (optional)
	' Returns:		Nothing
	' Author:		Jeff Baron
	' Date:			2/25/2000
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		if (jfIsText(pstrMessage)) {
			alert(pstrMessage);
		}

		pctlSource.checked = false;
		pctlSource.focus();
	}


	function jfIsDateMDY(pstrSource) {
	/************************************************************************
	' Function:		jfIsDateMDY
	' Purpose:		Check if the specified value is a valid date
	' Arguments:	pstrSource	- String to check
	' Returns:		True if a valid date, False otherwise
	' Author:		Jeff Baron
	' Date:			
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	'	12/27/2000	WJB			Removed requirement of year being > 1500 and 
	'							changed to allow either two or four digit year.
	************************************************************************/
		if (jfIsText(pstrSource)) {
			var date_regex = /^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$/;
			var date_str = pstrSource;

			// ^ indicates start of expression
			// \d{1,2} - the \d means digits and {1,2} means 1 or 2 digits
			// $ indicates end f expression

			if (!date_regex.test(date_str)) {
				return(false);
			}

			//---- separate the month, day and year ----
			var month = RegExp.$1;
			var day = RegExp.$2;
			var year = RegExp.$3;

			if (month < 1 || month > 12) {
				return(false);
			}

			if (day == 0) { 
				return(false);
			}

			if ((month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) && (day > 31)) {
				return (false) ;
			}

			if ((month == 4 || month == 6 || month == 9 || month == 11) && (day > 30)) {
				return(false);
			} 

			if (month == 2) {
				//---- check for leap year -----
				if ((day > 28) && (year%4 != 0)) {
					return(false);
				}

				if ((day > 29) && (year%4 == 0)) {
					return(false);
				}
			}

			return(true);
		}
		else {
			return(true);
		}
	}


	function jfIsNumeric(pstrSource, pintAllowDecimal) {
	/************************************************************************
	' Procedure:	jfIsNumeric
	' Purpose:		Verify that the passed in string is a number
	' Arguments:	pstrSource			- String you want to check
	'				pintAllowDecimal	- Whether decimals are allowed
	'										(1 = True, 0 = False)
	' Returns:		True if valid, False otherwise
	' Author:		Jeff Baron
	' Date:			2/2000
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	'	7/7/2000	WJB			Added parameter pintAllowDecimal.
	************************************************************************/
		var boolPeriodFound = false;

		// Test for a string
		if (jfIsText(pstrSource)) {
			for (var i = 0;  i < pstrSource.length;  i++) {
		    	strTemp = pstrSource.charAt(i);

				if (strTemp == '.') {
					if (pintAllowDecimal == 1) {
						if (boolPeriodFound == false){
							boolPeriodFound = true;
						}
						else {
							return false;
						}
					}
					else {
						return false;
					}
				}
				else if (strTemp == '0') {
					// Character is numeric so continue
				}
				else if (parseInt(strTemp) > 0) {
					// Character is numeric so continue
				}
				else {
					return false;
				}
			}
			return true;
		}
		return false;
	}


	function jfFormatCurrency(pstrValue) {
	/************************************************************************
	' Procedure:	jfFormatCurrency
	' Purpose:		Format the passed-in value as currency
	' Arguments:	pstrValue	- String you want to reformat
	' Returns:		An empty string if equal to zero, otherwise the 
	'				formatted value in $9.99 format
	' Author:		Jeff Baron
	' Date:			12/2000
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		pstrValue = pstrValue.toString().replace(/\$|\,/g,'');

		if (isNaN(pstrValue)) 
			pstrValue = "0";

		cents = Math.floor((pstrValue*100+0.5)%100);
		pstrValue = Math.floor((pstrValue*100+0.5)/100).toString();

		if (cents < 10) 
			cents = "0" + cents;

		for (var i = 0; i < Math.floor((pstrValue.length-(1+i))/3); i++)
			pstrValue = pstrValue.substring(0,pstrValue.length-(4*i+3))+','+pstrValue.substring(pstrValue.length-(4*i+3));

		if ((pstrValue == '0') && (cents == '00')) {
			return '';
		}
		else {
			return ('$' + pstrValue + '.' + cents);
		}
	}


	function jfOpenPopup(pstrURL, pstrWindowName, pstrToolbar, pstrLocation, pstrDirectories, pstrStatus, pstrMenu, pstrScroll, pstrResize, pintWidth, pintHeight, pintTop, pintLeft) {
	/************************************************************************
	' Procedure:	jfOpenPopup
	' Purpose:		Open a URL in a new popup window
	' Arguments:	pstrURL			- URL to open
	'				pstrWindowName	- Name to assign the window
	'				pintHeight		- Height of window
	'				pintWidth		- Width of window
	' Returns:		Nothing
	' Author:		Jeff Baron
	' Date:			1/19/2001
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		var intTop;
		var intLeft;
		var strWinName;

		if (pintTop == null) {
			intTop = eval((screen.availHeight - pintHeight)/2);
		}
		else {
			intTop = pintTop;
		}
					
		if (pintLeft == null) {
			intLeft = eval((screen.availWidth - pintWidth)/2);
		}
		else {
			intLeft = pintLeft;
		}
				
		if (pstrWindowName == null) 
			strWinName = "winPopup"
		else
			strWinName = pstrWindowName

		var winPopup = window.open (pstrURL, pstrWindowName, "toolbar=" + pstrToolbar + ",location=" + pstrLocation + ",directories=" + pstrDirectories + ",status=" + pstrStatus + ",menubar=" + pstrMenu + ",scrollbars=" + pstrScroll + ",resizable=" + pstrResize + ",width=" + pintWidth + ",height=" + pintHeight + ",top=" + intTop + ",left=" + intLeft);
		winPopup.focus();
	}

	function jfSetMaxTextLength(pctlSource, pintMaxLength) {
	/************************************************************************
	' Procedure:	jfSetMaxTextLength
	' Purpose:		Limit the amount of characters in the given control
	'				to the specified amount
	' Arguments:	pctlSource		- Control to limit
	'				pintMaxLength	- Max number of characters to allow
	' Returns:		Nothing
	' Author:		Jeff Baron
	' Date:			7/7/2000
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		if (is_ie4up) {
			var ctlSource = eval(pctlSource);
		}
		else if (is_nav4up) {
			var ctlSource = eval(pctlSource.target);
		}

		var strTemp = ctlSource.value;
		ctlSource.value = strTemp.substring(0, pintMaxLength);
	}

	function jfIsEmail(pstrSource) {
	/************************************************************************
	' Procedure:	jfIsEmail
	' Purpose:		Verify that the passed in string is a potentially valid
	'				email address
	' Arguments:	pstrSource	- String you want to check
	' Returns:		True if valid, False otherwise
	' Author:		Adapted by Jeff Baron from source code found at
	'				http://javascript.internet.com/forms/check-email.html
	' Date:			6/20/2000
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		/* 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 = pstrSource.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. */
			return false
		}

		var user = matchArray[1]
		var domain = matchArray[2]

		// See if "user" is valid 
		if (user.match(userPat) == null) {
		    // user is not 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) {
					return false
			    }
		    }
		    return true
		}

		// Domain is symbolic name
		var domainArray = domain.match(domainPat)
		if (domainArray == null) {
		    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) {
			// there must be at least 2 characters after the "."
			return false
		}

		// Make sure there's a host name preceding the domain.
		if (len < 2) {
			return false
		}

		// If we've gotten this far, everything's valid!
		return true;
	}


	function jfIsYear(pstrSource) {
	/************************************************************************
	' Procedure:	jfIsYear
	' Purpose:		Verify that the passed in string is potentially a valid year
	' Arguments:	pstrSource	- String you want to check
	' Returns:		True if valid, False otherwise
	' Author:		Jeff Baron
	' Date:			6/19/2000
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		// Test for a four-character string
		if (pstrSource.length == 4) {
			if (jfIsNumeric(pstrSource, 0)) {
				return true;
			}
			else {
				return false;
			}
		}
		return false;		
	}


	function jfMoveListItem(pctlSource, pctlDestination, pintSortSource, pintSortDestination) {
	/************************************************************************
	' Procedure:	jfMoveListItem
	' Purpose:		Move an <OPTION> item from one select control to another
	' Arguments:	pctlSource			- Source control
	'				pctlDestination		- Destination control
	'				pintSortSource		- Whether to re-sort the source control
	'				pintSortDestination	- Whether to re-sort the destination control
	' Returns:		Nothing
	' Author:		Jeff Baron
	' Date:			2/4/2002
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		var astrSource = new Array();
		var astrDestination = new Array();
		var astrLookup = new Array();
		var intCounter;
		var lngSourceCount = 0;
		var lngDestinationCount;
		var ctlOption;

		for (intCounter = 0; intCounter < pctlDestination.options.length; intCounter++) {
			astrLookup[pctlDestination.options[intCounter].text] = pctlDestination.options[intCounter].value;
			astrDestination[intCounter] = pctlDestination.options[intCounter].text;
		}

		lngDestinationCount = astrDestination.length;

		for(intCounter = 0; intCounter < pctlSource.options.length; intCounter++) {
			astrLookup[pctlSource.options[intCounter].text] = pctlSource.options[intCounter].value;

			if (pctlSource.options[intCounter].selected && pctlSource.options[intCounter].value != "") {
				astrDestination[lngDestinationCount] = pctlSource.options[intCounter].text;
				lngDestinationCount++;
			}
			else {
				astrSource[lngSourceCount] = pctlSource.options[intCounter].text;
				lngSourceCount++;
			}
		}

		if (pintSortSource == 1) astrSource.sort();
		if (pintSortDestination == 1) astrDestination.sort();

		pctlSource.length = 0;
		pctlDestination.length = 0;

		for(intCounter = 0; intCounter < astrSource.length; intCounter++) {
			ctlOption = new Option();

			ctlOption.value = astrLookup[astrSource[intCounter]];
			ctlOption.text = astrSource[intCounter];
			pctlSource[intCounter] = ctlOption;
		}

		for(intCounter = 0; intCounter < astrDestination.length; intCounter++) {
			ctlOption = new Option();

			ctlOption.value = astrLookup[astrDestination[intCounter]];
			ctlOption.text = astrDestination[intCounter];
			pctlDestination[intCounter] = ctlOption;
		}
	}


	function jfCountSelectedOptions(pctlSource) {
	/************************************************************************
	' Procedure:	jfCountSelectedOptions
	' Purpose:		Count the number of items selected in the specified control
	' Arguments:	pctlSource		- Source control
	' Returns:		Number of <OPTION> items selected
	' Author:		Jeff Baron
	' Date:			2/4/2002
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		var lngOptionCount;
		var ctlSource = pctlSource;

		lngOptionCount = ctlSource.options.length;

		return lngOptionCount;		
	}

	function jfStringFilter (pstrSource, pstrFilter) {
	/************************************************************************
	' Procedure:	jfStringFilter
	' Purpose:		Remove specified characters from the source string
	' Arguments:	pstrSource	- String to filter
	'			pstrFilter	- Character(s) to remove from string
	' Returns:		Filtered string
	' Author:		Adapted by Jeff Baron from original code at
	'			http://javascript.internet.com/forms/strip-characters.html
	' Date:		4/23/2002
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		var intCounter;
		var strReturn = '';

		for (intCounter = 0; intCounter < pstrSource.length; intCounter++) {  
			// Search through string and append to unfiltered values to returnString.
			var strTempChar = pstrSource.charAt(intCounter);

			if (pstrFilter.indexOf(strTempChar) == -1) 
				strReturn += strTempChar;
		}

		return strReturn;
	}

	function jfChangeSelectOrder(pctlSource, pintOriginalIndex, pvarNewIndex) {
	/************************************************************************
	' Procedure:	jfChangeSelectOrder
	' Purpose:		Change the order of the items in a select list
	' Arguments:	pctlSource			- Select list to modify
	'				pintOriginalIndex	- Original index position of the item
	'				pvarNewIndex		- New requested index of the item
	' Returns:		Nothing
	' Author:		Jeff Baron
	' Date:			9/13/2002
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		var lngTotal = pctlSource.options.length - 1;
		var intCounter;
		var strTemp1, strTemp2, strTemp3, strTemp4;
		var ctlOption;

		if (pintOriginalIndex == -1) return false;
		if (pvarNewIndex == +1 && pintOriginalIndex == lngTotal) return false;
		if (pvarNewIndex == -1 && pintOriginalIndex == 0) return false;

		var astrValues = new Array;
		var astrItems = new Array;

		for (intCounter = 0; intCounter <= lngTotal; intCounter++) {
			astrValues[intCounter] = pctlSource.options[intCounter].value;
			astrItems[intCounter] = pctlSource.options[intCounter].text;
		}

		strTemp1 = astrValues[pintOriginalIndex];
		strTemp2 = astrItems[pintOriginalIndex];

		strTemp3 = astrValues[pintOriginalIndex + pvarNewIndex]
		strTemp4 = astrItems[pintOriginalIndex + pvarNewIndex]

		astrValues[pintOriginalIndex] = strTemp3;
		astrItems[pintOriginalIndex] = strTemp4;

		astrValues[pintOriginalIndex + pvarNewIndex] = strTemp1;
		astrItems[pintOriginalIndex + pvarNewIndex] = strTemp2;

		pctlSource.length = 0;

		for(intCounter = 0; intCounter < astrValues.length; intCounter++) {
			ctlOption = new Option();

			ctlOption.value = astrValues[intCounter];
			ctlOption.text = astrItems[intCounter];

			if (intCounter == pintOriginalIndex + pvarNewIndex) {
				ctlOption.selected = true;
			}

			pctlSource[intCounter] = ctlOption;
		}
	}

	function jfRemoveSelectedListItem(pctlSource) {
	/************************************************************************
	' Procedure:	jfRemoveSelectedListItem
	' Purpose:		Remove the selected item from the specified list control
	' Arguments:	pctlSource	- Select list to modify
	' Returns:		Nothing
	' Author:		Jeff Baron
	' Date:			9/12/2002
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		var intCounter;

		for(intCounter = 0; intCounter < pctlSource.options.length; intCounter++) {
			if (pctlSource.options[intCounter].selected && pctlSource.options[intCounter].value != "") {
		        pctlSource.options[intCounter] = null;

				break;
			}
		}
	}

	function jfAddListItem(pctlDestination, pstrValue, pstrText, pboolAllowDuplicates) {
	/************************************************************************
	' Procedure:	jfAddListItem
	' Purpose:		Add a new item to the specified list control
	' Arguments:	pctlDestination			- Select list to modify
	'				pstrValue				- Value of list item
	'				pstrText				- String that will display
	'				pboolAllowDuplicates	- Whether to add the item if it
	'											is already there.
	' Returns:		Nothing
	' Author:		Jeff Baron
	' Date:			9/12/2002
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		var intCounter;
		var boolItemExists = false;
		var ctlOption;

		if (pboolAllowDuplicates == false) {
			for(intCounter = 0; intCounter < pctlDestination.options.length; intCounter++) {
				if (pctlDestination.options[intCounter].value == pstrValue) {
					boolItemExists = true;
					break;
				}
			}
		}

		if (((pboolAllowDuplicates == false) && (boolItemExists == false)) || (pboolAllowDuplicates == true)) {
			ctlOption = new Option();

			ctlOption.value = pstrValue;
			ctlOption.text = pstrText;

			pctlDestination[pctlDestination.options.length] = ctlOption;
		}
	}


	function jfLookupIndex(pvarForm, pvarControlName) {
		var lngCounter;
		var lngIndexMatch = -1;
			
		for (lngCounter = 0; lngCounter <= pvarForm.length - 1 ; lngCounter++) {
			if ( pvarForm.elements[lngCounter].name == pvarControlName ) {
				lngIndexMatch = lngCounter;
				break;
			}
		}
		return lngIndexMatch;
	}

	function jfSelectListItems(pctlSource) {
	/************************************************************************
	' Procedure:	jfSelectListItems
	' Purpose:		Select all items in the specified select list
	' Arguments:	pctlSource	- Control to select
	' Returns:		Nothing
	' Author:		Jeff Baron
	' Date:			11/26/2002
	'
	' Modification History:
	'	Date		Author		Change Description
	'	------------------------------------------------------------------
	************************************************************************/
		var intCounter;

		for(intCounter = 0 ; intCounter < pctlSource.options.length ; intCounter++) {
			pctlSource.options[intCounter].selected = true;
		}
	}


	function jfLastXDays () {
	/*	
	*	Function:		jfLastXDays
	*	Arguments:	none
	*	Purpose:		Resubmits the page with the new Last X Days
	*	Author:			Michael J. Lukaszevicz
	*	Date:			07/29/03
	*/	
		var varResult = 1;
		for (var i = 0; i< document.frmMain.LastXDays.length ; i++) {
			if ( document.frmMain.LastXDays.options[i].selected == true ) {
				varResult = document.frmMain.LastXDays.options[i].value;
				return varResult;
			}
		}
		return varResult;
	}


