////////////////////////////////////////////////////////////////
// common.inc.js
// Commonly used JavaScript functions web applications
////////////////////////////////////////////////////////////////
// Compiled from various code samples, 11/27/01, Trint Ladd
////////////////////////////////////////////////////////////////
// Added Form field validation and formatting scripts, 11/28/01, Trint Ladd
// Added isFileType(), 11/28/01, Trint Ladd
////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////
// For error handling, msg is the error message to the user.
// filed is the offending field object.  Best not to use this
// at the field level because it sets focus and can cause
// an infinite loop.
// msg = STRING
// field = FORM FIELD OBJECT
function errAlert(msg, field)
{	alert(msg);
	if(!field) //object doesn't exist
		field = window;
	if(field.type == "text" || field.type == "file")
		field.select();
	else
		field.focus();
}

////////////////////////////////////////////////////////////////
// Gets rid of the pesky outline when you click an image link.
// Apply to onClick event of <a> tag.
function clearme()
{	window.focus();
}

////////////////////////////////////////////////////////////////
// Grab the selected value from a <select> tag.
// field is the form field object
function getOptionValue(field)
{	var index = field.selectedIndex;
	return field.options[index].value;
}

////////////////////////////////////////////////////////////////
// Get checked value from radio button.
// field is the form field object
function getRadioButtonValue(field)
{	var retVal = "";
	for (var i = 0; i < field.length; i++)
	{	if (field[i].checked)
			retVal = field[i].value;
	}
	return retVal;
}

////////////////////////////////////////////////////////////////
// Get checked value from check box.
// field is the form field object
function getCheckBoxValue(field)
{	if (field.checked)
		return field.value;
}

////////////////////////////////////////////////////////////////
// Navigate to the previous page by setting the action of the
// source form to the target page.
// srcFrm = "formname"
// target = "page1.php"
function backNav(srcFrm, target)
{	var frm = eval("document." + srcFrm);
	frm.action = target;
	frm.submit();
}

////////////////////////////////////////////////////////////////
// Sets focus to a field.  frm and fld are STRINGS:
// frm = "formname"
// fld = "fieldname"
function fieldFocus(frm, fld)
{	var target = eval("document." + frm + "." + fld);
	target.focus();
}

////////////////////////////////////////////////////////////////
// Image Rollover Functions
// target is the name in the image tag
// newSrc is the full or relative path to the new image
function rover(target, newSrc)
{	if(document.images[target])
		document.images[target].src = newSrc;
}

/////////////////////////////////////////////////////////////////
// True if s contains a file that is one of the specified types
// types is an array of strings containing the acceptable file suffixes
// EXAMPLE:
// isFileType("myfolder/myfile.txt", ['doc', 'pdf', 'txt'])	true
// isFileType("myfolder/myfile.exe", ['doc', 'pdf', 'txt'])	false
function isFileType(s, types)
{	var suffixPat = new RegExp("^.+\\.([^\\.]+)$"); //grab everything after the last dot "."
	var matchArray = s.match(suffixPat);
	if(matchArray == null)
		return false;
	var suffix = matchArray[1].toLowerCase();
	for(i = 0; i < types.length; i++)
	{	if(types[i].toLowerCase() == suffix)
			return true;
	}
	return false; //didn't find file suffix in list of acceptable types
}


////////////////////////////////////////////////////////////////
// Browser Sniffer Functions
// Portions of this sniffer where taken from...
// Ultimate client-side JavaScript client sniff. Version 3.02
// (C) Netscape Communications 1999-2001.
// Permission granted to reuse and distribute.
////////////////////////////////////////////////////////////////
// Detects Internet Explorer.  Returns 0 for false or version for true.
function isIE()
{	var agt = navigator.userAgent.toLowerCase();
	if((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1))
		return parseInt(navigator.appVersion); //true
	else
		return 0; //false
}

////////////////////////////////////////////////////////////////
// Detects Internet Explorer.  Returns 0 for false or version for true.
function isIE4()
{	var agt = navigator.userAgent.toLowerCase();
	if((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1)
		&& (parseInt(navigator.appVersion) == 4)
		&& (agt.indexOf("msie 4") != -1))
		return true;
	else
		return false;
}

////////////////////////////////////////////////////////////////
// Detects Netscape.  Returns 0 for false or version for true.
function isNS()
{	var agt = navigator.userAgent.toLowerCase();
	if((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
		&& (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
		&& (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1))
		return parseInt(navigator.appVersion); //true
	else
		return 0; //false
}

////////////////////////////////////////////////////////////////
// Detects Netscape 6.
function isNS6()
{	var agt = navigator.userAgent.toLowerCase();
	if((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
		&& (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
		&& (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-1)
		&& (parseInt(navigator.appVersion) == 5))
		return true;
	else
		return false;
}
////////////////////////////////////////////////////////////////
// End Browser Sniffer Functions
////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////
// Form field validation and formatting
// This is a set of JavaScript functions for validating input on 
// an HTML form.  The following functions are provided for validation.
// NOTE: eok is an optional argument that signifies that an empty
// string is allowed. For explanation of optional argument emptyOK,
// see comments of function isInteger.
//
// isWhitespace (s)				True if string s is empty or whitespace.
// isLetter (c)					True if character c is an English letter 
// isDigit (c)					True if character c is a digit 
// isLetterOrDigit (c)			True if character c is a letter or digit.
// isInteger (s [,eok])			True if all characters in string s are numbers.
// isSignedInteger (s [,eok])		True if all characters in string s are numbers; leading + or - allowed.
// isPositiveInteger (s [,eok])		True if string s is an integer > 0.
// isNonnegativeInteger (s [,eok])	True if string s is an integer >= 0.
// isNegativeInteger (s [,eok])		True if s is an integer < 0.
// isNonpositiveInteger (s [,eok])	True if s is an integer <= 0.
// isFloat (s [,eok])			True if string s is an unsigned floating point (real) number. (Integers also OK.)
// isSignedFloat (s [,eok])		True if string s is a floating point number; leading + or - allowed. (Integers also OK.)
// isAlphabetic (s [,eok])		True if string s is English letters 
// isAlphanumeric (s [,eok])	True if string s is English letters and numbers only.
// isSSN (s [,eok])				True if string s is a valid U.S. Social Security Number.
// isUSPhoneNumber (s [,eok])	True if string s is a valid U.S. Phone Number. 
// isInternationalPhoneNumber (s [,eok])	True if string s is a valid international phone number.
// isZIPCode (s [,eok])			True if string s is a valid U.S. ZIP code.
// isAreaCode (s [,eok])		True if string s is a valid U.S. Area code.
// isTelPrefixCode (s [,eok])	True if string s is a valid U.S. Telphone prefix.
// isTelSuffixCode (s [,eok])	True if string s is a valid U.S. Telphone Suffix.
// isStateCode (s [,eok])		True if string s is a valid U.S. Postal Code
// isEmail (s [,eok])			True if string s is a valid email address.
// isYear (s [,eok])			True if string s is a valid Year number.
// isIntegerInRange (s, a, b [,eok])		True if string s is an integer between a and b, inclusive.
// isMonth (s [,eok])			True if string s is a valid month between 1 and 12.
// isDay (s [,eok])				True if string s is a valid day between 1 and 31.
// isDate (year, month, day)	True if string arguments form a valid date.
// isIPAddress (s)				True if s is a valid, four part, IP address
//
// The following functions return correctly formatted data.
// reformatZIPCode (ZIPString)	Reformats as 12345 or 12345-6789.
// reformatSSN (SSN)			Reformats as 123-45-6789.
// reformatUSPhone (USPhone)	Reformats as (123) 456-789 or 123-4567.
// formatPureDollars(s)			Reformats as an int.
// formatPureDollarsAndCents(s)	Reformats as a float with two decimals places.
//
// The following functions are utilities used to perform the above validation or formatting.
// stripCharsInBag (s, bag)		Removes all characters in string bag from string s.
// stripCharsNotInBag (s, bag)	Removes all characters NOT in string bag from string s.
// stripWhitespace (s)			Removes all whitespace characters from s.
// charInString (c, s)			True if character c appears in string s.
// stripInitialWhitespace (s)	Removes initial (leading) whitespace characters from s.
// stripTrailingWhitespace (s)	Removes trailing whitespace characters from s.
// reformat (TARGETSTRING, STRING, INTEGER, STRING, INTEGER ... )
//								Function for inserting formatting characters or delimiters into TARGETSTRING.
// daysInFebruary (year)		Returns number of days in February of that year.
//
// VARIABLE DECLARATIONS
//
// Global variable defaultEmptyOK defines default return value 
// for many functions when they are passed the empty string. 
// By default, they will return defaultEmptyOK.
var defaultEmptyOK = false

var digits = "0123456789";
var lowercaseLetters = "abcdefghijklmnopqrstuvwxyz"
var uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
var whitespace = " \t\n\r";
var decimalPointDelimiter = ".";
var phoneNumberDelimiters = "()- ";
var validUSPhoneChars = digits + phoneNumberDelimiters;
var validWorldPhoneChars = digits + phoneNumberDelimiters + "+";
var namechars = lowercaseLetters + uppercaseLetters + whitespace + ".,-'";
var SSNDelimiters = "- ";
var validSSNChars = digits + SSNDelimiters;
var digitsInSocialSecurityNumber = 9;
var digitsInUSPhoneNumber1 = 10;
var digitsInUSPhoneNumber2 = 7
var ZIPCodeDelimiters = "-";
var validZIPCodeChars = digits + ZIPCodeDelimiters
var digitsInZIPCode1 = 5
var digitsInZIPCode2 = 9
var digitsInAreaCode = 3
var digitsInTelPrefixCode = 3
var digitsInTelSuffixCode = 4
var daysInMonth = new Array(12);
daysInMonth[1] = 31;
daysInMonth[2] = 29;	// must programmatically check this
daysInMonth[3] = 31;
daysInMonth[4] = 30;
daysInMonth[5] = 31;
daysInMonth[6] = 30;
daysInMonth[7] = 31;
daysInMonth[8] = 31;
daysInMonth[9] = 30;
daysInMonth[10] = 31;
daysInMonth[11] = 30;
daysInMonth[12] = 31;
var USStateCodeDelimiter = "|";
var USStateCodes = "AL|AK|AS|AZ|AR|CA|CO|CT|DE|DC|FM|FL|GA|GU|HI|ID|IL|IN|IA";
USStateCodes += "|KS|KY|LA|ME|MH|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND";
USStateCodes += "|MP|OH|OK|OR|PW|PA|PR|RI|SC|SD|TN|TX|UT|VT|VI|VA|WA|WV|WI|WY";
USStateCodes += "|AE|AA|AE|AE|AP"

////////////////////////////////////////////////////////////////
// Check whether string s is empty.
function isEmpty(s)
{	return ((s == null) || (s.length == 0))
}

////////////////////////////////////////////////////////////////
// True if string s is empty or 
// whitespace characters only.
function isWhitespace (s)
{	var i;
	if (isEmpty(s))
		return true;

	for (i = 0; i < s.length; i++)
	{	var c = s.charAt(i);
		if (whitespace.indexOf(c) == -1) return false;
	}
	return true;
}

////////////////////////////////////////////////////////////////
// True if character c is an English letter 
// (A .. Z, a..z).
function isLetter (c)
{	return ( ((c >= "a") && (c <= "z")) || ((c >= "A") && (c <= "Z")) )
}

////////////////////////////////////////////////////////////////
// True if character c is a digit 
// (0 .. 9).
function isDigit (c)
{	return ((c >= "0") && (c <= "9"))
}

////////////////////////////////////////////////////////////////
// True if character c is a letter or digit.
function isLetterOrDigit (c)
{	return (isLetter(c) || isDigit(c))
}

////////////////////////////////////////////////////////////////
// True if all characters in string s are numbers.
// Accepts non-signed integers only.
// EXAMPLES:
// isInteger ("5")			true 
// isInteger ("")			defaultEmptyOK
// isInteger ("-5")			false
// isInteger ("", true)		true
// isInteger ("", false)	false
// isInteger ("5", false)	true
function isInteger (s)
{	var i;
	if (isEmpty(s))
	{	if (isInteger.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isInteger.arguments[1] == true);
	}
	for (i = 0; i < s.length; i++)
	{	var c = s.charAt(i);
		if (!isDigit(c))
			return false;
	}
	return true;
}

////////////////////////////////////////////////////////////////
// True if all characters are numbers.
// First character is allowed to be + or - as well.
// EXAMPLE:
// isSignedInteger ("5")		true 
// isSignedInteger ("")			defaultEmptyOK
// isSignedInteger ("-5")		true
// isSignedInteger ("+5")		true
// isSignedInteger ("", false)	false
// isSignedInteger ("", true)	true
function isSignedInteger (s)
{	if (isEmpty(s))
	{	if (isSignedInteger.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isSignedInteger.arguments[1] == true);
	}
	else
	{	var startPos = 0;
		var secondArg = defaultEmptyOK;
		if (isSignedInteger.arguments.length > 1)
			secondArg = isSignedInteger.arguments[1];
		// skip leading + or -
		if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
			startPos = 1;
		return (isInteger(s.substring(startPos, s.length), secondArg))
	}
}

////////////////////////////////////////////////////////////////
// True if string s is an integer > 0.
function isPositiveInteger (s)
{	var secondArg = defaultEmptyOK;
	if (isPositiveInteger.arguments.length > 1)
		secondArg = isPositiveInteger.arguments[1];

	// a) s must be a signed integer, AND
	// b) one of the following must be true:
	//	i)  s is empty and we are supposed to return true for
	//  empty strings
	//	ii) this is a positive, not negative, number
	return (isSignedInteger(s, secondArg) && ( (isEmpty(s) && secondArg)  || (parseInt (s) > 0) ) );
}

////////////////////////////////////////////////////////////////
// True if string s is an integer >= 0.
function isNonnegativeInteger (s)
{	var secondArg = defaultEmptyOK;
	if (isNonnegativeInteger.arguments.length > 1)
		secondArg = isNonnegativeInteger.arguments[1];

	// a) s must be a signed integer, AND
	// b) one of the following must be true:
	//	i)  s is empty and we are supposed to return true for
	//  empty strings
	//	ii) this is a number >= 0
	return (isSignedInteger(s, secondArg) && ( (isEmpty(s) && secondArg)  || (parseInt (s) >= 0) ) );
}

////////////////////////////////////////////////////////////////
// True if string s is an integer < 0.
function isNegativeInteger (s)
{	var secondArg = defaultEmptyOK;
	if (isNegativeInteger.arguments.length > 1)
		secondArg = isNegativeInteger.arguments[1];

	// a) s must be a signed integer, AND
	// b) one of the following must be true:
	//	i)  s is empty and we are supposed to return true for
	//  empty strings
	//	ii) this is a negative, not positive, number
	return (isSignedInteger(s, secondArg) && ( (isEmpty(s) && secondArg)  || (parseInt (s) < 0) ) );
}

////////////////////////////////////////////////////////////////
// True if string s is an integer <= 0.
function isNonpositiveInteger (s)
{	var secondArg = defaultEmptyOK;
	if (isNonpositiveInteger.arguments.length > 1)
		secondArg = isNonpositiveInteger.arguments[1];

	// a) s must be a signed integer, AND
	// b) one of the following must be true:
	//	i)  s is empty and we are supposed to return true for
	//  empty strings
	//	ii) this is a number <= 0
	return (isSignedInteger(s, secondArg) && ( (isEmpty(s) && secondArg)  || (parseInt (s) <= 0) ) );
}

////////////////////////////////////////////////////////////////
// True if string s is an unsigned floating point (real) number. 
// Also returns true for unsigned integers.
function isFloat (s)
{	var i;
	var seenDecimalPoint = false;
	if (isEmpty(s)) 
	{	if (isFloat.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isFloat.arguments[1] == true);
	}
	if (s == decimalPointDelimiter)
		return false;

	for (i = 0; i < s.length; i++)
	{	var c = s.charAt(i);
		if ((c == decimalPointDelimiter) && !seenDecimalPoint)
			seenDecimalPoint = true;
		else if (!isDigit(c))
			return false;
	}
	return true;
}

////////////////////////////////////////////////////////////////
// True if string s is a signed or unsigned floating point 
// (real) number. First character is allowed to be + or -.
// Also returns true for unsigned integers.
function isSignedFloat (s)
{	if (isEmpty(s))
	{	if (isSignedFloat.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isSignedFloat.arguments[1] == true);
	}
	else
	{	var startPos = 0;
		var secondArg = defaultEmptyOK;
		if (isSignedFloat.arguments.length > 1)
			secondArg = isSignedFloat.arguments[1];
		// skip leading + or -
		if ( (s.charAt(0) == "-") || (s.charAt(0) == "+") )
			startPos = 1;
		return (isFloat(s.substring(startPos, s.length), secondArg))
	}
}

////////////////////////////////////////////////////////////////
// True if string s is English letters 
// (A .. Z, a..z) only.
function isAlphabetic (s)
{	var i;
	if (isEmpty(s))
	{	if (isAlphabetic.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isAlphabetic.arguments[1] == true);
	}
	for (i = 0; i < s.length; i++)
	{	var c = s.charAt(i);
		if (!isLetter(c))
			return false;
	}
	return true;
}

////////////////////////////////////////////////////////////////
// True if string s is English letters 
// (A .. Z, a..z) and numbers only.
function isAlphanumeric (s)
{	var i;
	if (isEmpty(s))
	{	if (isAlphanumeric.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isAlphanumeric.arguments[1] == true);
	}
	for (i = 0; i < s.length; i++)
	{	var c = s.charAt(i);
		if (! (isLetter(c) || isDigit(c) ) )
			return false;
	}
	return true;
}

////////////////////////////////////////////////////////////////
// isSSN True if string s is a valid U.S. Social Security Number.
// NOTE: Strip out any delimiters (spaces, hyphens, etc.)
// from string s before calling this function.
function isSSN (s)
{	if (isEmpty(s))
	{	if (isSSN.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isSSN.arguments[1] == true);
	}
	return (isInteger(s) && s.length == digitsInSocialSecurityNumber)
}

////////////////////////////////////////////////////////////////
// True if string s is a valid U.S. Phone Number.
// NOTE: Strip out any delimiters (spaces, hyphens, parentheses, etc.)
// from string s before calling this function.
function isUSPhoneNumber (s)
{	if (isEmpty(s))
	{	if (isUSPhoneNumber.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isUSPhoneNumber.arguments[1] == true);
	}
	return (isInteger(s) && (s.length == digitsInUSPhoneNumber1 || s.length == digitsInUSPhoneNumber2))
}

////////////////////////////////////////////////////////////////
// True if string s is a valid international phone number.
// May be prefixed by + character.
// NOTE: A phone number of all zeros would not be accepted.
// NOTE: Strip out any delimiters (spaces, hyphens, parentheses, etc.)
// from string s before calling this function.  You may leave in 
// leading + character if you wish.
function isInternationalPhoneNumber (s)
{	if (isEmpty(s))
	{	if (isInternationalPhoneNumber.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isInternationalPhoneNumber.arguments[1] == true);
	}
	return (isPositiveInteger(s))
}

////////////////////////////////////////////////////////////////
// True if string s is a valid U.S. ZIP code.
// NOTE: Strip out any delimiters (spaces, hyphens, etc.)
// from string s before calling this function.
function isZIPCode (s)
{	if (isEmpty(s))
	{	if (isZIPCode.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isZIPCode.arguments[1] == true);
	}
	return (isInteger(s) && ((s.length == digitsInZIPCode1) || (s.length == digitsInZIPCode2)))
}

////////////////////////////////////////////////////////////////
// True if string s is a valid U.S. Area code.
// NOTE: Strip out any delimiters (spaces, hyphens, etc.)
// from string s before calling this function.
function isAreaCode (s)
{	if (isEmpty(s))
	{	if (isAreaCode.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isAreaCode.arguments[1] == true);
	}
	return (isInteger(s) && (s.length == digitsInAreaCode))
}

////////////////////////////////////////////////////////////////
// True if string s is a valid Telephone prefix code.
// NOTE: Strip out any delimiters (spaces, hyphens, etc.)
// from string s before calling this function.
function isTelPrefixCode (s)
{	if (isEmpty(s))
	{	if (isTelPrefixCode.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isTelPrefixCode.arguments[1] == true);
	}
	return (isInteger(s) && (s.length == digitsInTelPrefixCode))
}

////////////////////////////////////////////////////////////////
// True if string s is a valid telephone Suffix code.
// NOTE: Strip out any delimiters (spaces, hyphens, etc.)
// from string s before calling this function.
function isTelSuffixCode (s)
{	if (isEmpty(s))
	{	if (isTelSuffixCode.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isTelSuffixCode.arguments[1] == true);
	}
	return (isInteger(s) && (s.length == digitsInTelSuffixCode))
}

/////////////////////////////////////////////////////////////////
// True if s is a valid U.S. Postal Code (abbreviation for state).
function isStateCode(s)
{	if (isEmpty(s))
	{	if (isStateCode.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isStateCode.arguments[1] == true);
	}
	return ( (USStateCodes.indexOf(s) != -1) && (s.indexOf(USStateCodeDelimiter) == -1) )
}

////////////////////////////////////////////////////////////////
// True if s is a valid e-mail address.
function isEmail (s)
{	// user@domain format.  also is used to separate the username from the domain.
	var emailPat=/^(.+)@(.+)$/

	// special characters not allowed: ( ) < > @ , ; : \ " . [ ]
	var specialChars="\\(\\)<>@,;:\\\\\\\"\\.\\[\\]"

	// characters not allowed in a username or domainname.
	var validChars="\[^\\s" + specialChars + "\]"

	// The following pattern applies if the "user" is a quoted string in which case, anything goes).
	var quotedUser="(\"[^\"]*\")"

	// The following pattern applies to IP addresses
	var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/
	
	// characters allowed in an atom
	var atom=validChars + '+'
	
	// 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
	var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$")

	var matchArray=s.match(emailPat)
	if (matchArray==null) // incorrect format
		return false

 	var user=matchArray[1]
	var domain=matchArray[2]

	if (user.match(userPat)==null) // user is not valid
		return false

	var IPArray=domain.match(ipDomainPat)
	if (IPArray!=null) // Domain is an IP Address
	{	for (var i=1;i<=4;i++)
		{	if (IPArray[i]>255)
				return false
		}
		return true
	}

	// Domain is a symbolic name
	var domainArray=domain.match(domainPat)
	if (domainArray==null)
		return false

	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>3) // invalid suffix (i.e. com, org, uk)
		return false
	
	if (len<2) // invalid hostname
		return false
	
	// If we've gotten this far, everything's valid!
	return true;
}

////////////////////////////////////////////////////////////////
// True if string s is a valid Year number.  Must be 2 or 4 digits only.
function isYear (s)
{	if (isEmpty(s))
	{	if (isYear.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isYear.arguments[1] == true);
	}
	if (!isNonnegativeInteger(s))
		return false;
	return ((s.length == 2) || (s.length == 4));
}

////////////////////////////////////////////////////////////////
// True if string s is an integer within the range of integer arguments a and b, inclusive.
function isIntegerInRange (s, a, b)
{	if (isEmpty(s))
	{	if (isIntegerInRange.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isIntegerInRange.arguments[1] == true);
	}

	// Check for non-integer strings to avoid creating a NaN below,
	// which isn't available on JavaScript 1.0 for Windows.
	if (!isInteger(s, false))
		return false;

	var num = parseInt (s);
	return ((num >= a) && (num <= b));
}

////////////////////////////////////////////////////////////////
// True if string s is a valid month number between 1 and 12.
function isMonth (s)
{	if (isEmpty(s))
	{	if (isMonth.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isMonth.arguments[1] == true);
	}
	return isIntegerInRange (s, 1, 12);
}

////////////////////////////////////////////////////////////////
// True if string s is a valid day number between 1 and 31.
function isDay (s)
{	if (isEmpty(s))
	{	if (isDay.arguments.length == 1)
			return defaultEmptyOK;
		else
			return (isDay.arguments[1] == true);
	}
	return isIntegerInRange (s, 1, 31);
}

////////////////////////////////////////////////////////////////
// True if string arguments year, month, and day form a valid date.
function isDate (year, month, day)
{	// check for invalid years (not 2- or 4-digit) and invalid months and days.
	if (! (isYear(year, false) && isMonth(month, false) && isDay(day, false)))
		return false;

	var intYear = parseInt(year);
	var intMonth = parseInt(month);
	var intDay = parseInt(day);

	if (intDay > daysInMonth[intMonth])
		return false; 

	if ((intMonth == 2) && (intDay > daysInFebruary(intYear))) //February
		return false;

	return true;
}

////////////////////////////////////////////////////////////////
// True if string s is a valid IP Address.
function isIPAddress (s)
{	var IPArray = s.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
	if(IPArray)
	{	for(var i = 1; i <= 4; i++)
		{	if (IPArray[i]>255) //Found value too large
				return false;
		}
	}
	else
		return false;
	return true;
}

////////////////////////////////////////////////////////////////
// returns 12345 or 12345-6789
function reformatZIPCode (ZIPString)
{	s = stripCharsNotInBag (ZIPString, digits)
	if (s.length >= 9)
		return (reformat (s, "", 5, "-", 4));
	else
		return s;
}

////////////////////////////////////////////////////////////////
// returns 123-45-6789
function reformatSSN (SSN)
{	s = stripCharsNotInBag (SSN, digits)
	if (s.length == 9)
		return (reformat (s, "", 3, "-", 2, "-", 4))
	else
		return s;
}

////////////////////////////////////////////////////////////////
// returns (123) 456-7890 or 123-4567
function reformatUSPhone (USPhone)
{	s = stripCharsNotInBag (USPhone, digits)
	if(s.length >= 10)
		return (reformat (s, "(", 3, ") ", 3, "-", 4))
	else if(s.length == 7)
		return (reformat(s, "", 3, "-", 4))
	else
		return USPhone;
}

////////////////////////////////////////////////////////////////
// Formats a string of digits to standard int, removing any cents
function formatPureDollars(s)
{	var bag = digits + decimalPointDelimiter
	var decIndex;
	s = stripCharsNotInBag(s, bag);
	
	//Remove leading 0's
	while(s.charAt(0) == "0")
		s = s.substring(1,s.length);
	
	//Ensure no decimal places
	decIndex = s.indexOf(decimalPointDelimiter);
	if(decIndex == -1) //No decimal found
		return s;
	else
		return s.substring(0,decIndex);
}

////////////////////////////////////////////////////////////////
// Formats a string of digits to standard float with two decimal places
function formatPureDollarsAndCents(s)
{	var bag = digits + decimalPointDelimiter
	var decIndex;
	s = stripCharsNotInBag(s, bag);
	
	//Remove leading 0's
	while(s.charAt(0) == "0")
		s = s.substring(1,s.length);
	
	//Ensure exactly two decimal places
	decIndex = s.indexOf(decimalPointDelimiter);
	if(decIndex == -1) //No decimal found
		return s + decimalPointDelimiter + "00";
	if(s.length > decIndex + 3)
		return s.substring(0,decIndex + 3);
	while(s.length < decIndex + 3)
		s = s + "0";
	return s;
}

////////////////////////////////////////////////////////////////
// Removes all characters which appear in string bag from string s.
function stripCharsInBag (s, bag)
{	var i;
	var returnString = "";

	for (i = 0; i < s.length; i++)
	{	var c = s.charAt(i);
		if (bag.indexOf(c) == -1)
			returnString += c;
	}
	return returnString;
}

////////////////////////////////////////////////////////////////
// Removes all characters which do NOT appear in string bag from string s.
function stripCharsNotInBag (s, bag)
{	var i;
	var returnString = "";

	for (i = 0; i < s.length; i++)
	{	var c = s.charAt(i);
		if (bag.indexOf(c) != -1)
			returnString += c;
	}
	return returnString;
}

////////////////////////////////////////////////////////////////
// Removes all whitespace characters from s.
function stripWhitespace (s)
{	return stripCharsInBag (s, whitespace)
}

////////////////////////////////////////////////////////////////
// True if character c (actually a string) is contained within string s.
function charInString (c, s)
{	for (i = 0; i < s.length; i++)
	{	if (s.charAt(i) == c) return true;
	}
	return false
}

////////////////////////////////////////////////////////////////
// Removes initial (leading) whitespace characters from s.
function stripInitialWhitespace (s)
{	var i = 0;
	while ((i < s.length) && charInString (s.charAt(i), whitespace))
		i++;
	return s.substring (i, s.length);
}

////////////////////////////////////////////////////////////////
// Remove trailing whitespace characters from s.
function stripTrailingWhitespace(s)
{	var i = s.length - 1;
	while((i > 0) && charInString (s.charAt(i), whitespace))
		i--;
	return s.substring(0,i+1);
}

////////////////////////////////////////////////////////////////
// reformat takes one named argument, a string s, and any number
// of other arguments.  The other arguments must be integers or
// strings.  These other arguments specify how string s is to be
// reformatted and how and where other strings are to be inserted
// into it. If the argument is an integer, reformat appends that number 
// of sequential characters from s to the resultString. If the argument
// is a string, reformat appends the string to the resultString.
// NOTE: The first argument after TARGETSTRING must be a string.
// (It can be empty.)  The second argument must be an integer.
// Thereafter, integers and strings must alternate.
// EXAMPLE:
// a 10-digit U.S. phone number from "1234567890" to "(123) 456-7890"
//	reformat("1234567890", "(", 3, ") ", 3, "-", 4)
function reformat (s)
{	var arg;
	var sPos = 0;
	var resultString = "";

	for (var i = 1; i < reformat.arguments.length; i++)
	{	arg = reformat.arguments[i];
		if (i % 2 == 1)
			resultString += arg;
		else
		{	resultString += s.substring(sPos, sPos + arg);
			sPos += arg;
		}
	}
	return resultString;
}

////////////////////////////////////////////////////////////////
// Given integer argument year, returns number of days in February of that year.
function daysInFebruary (year)
{	return (  ((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0) ) ) ? 29 : 28 );
}

////////////////////////////////////////////////////////////////
// End Form field validation and formatting
////////////////////////////////////////////////////////////////

