// BOI, followed by one or more whitespace characters, followed by EOI.
var reWhitespace = /^\s+$/

// BOI, followed by one lower or uppercase English letter, followed by EOI.
var reLetter = /^[a-zA-Z]$/

// BOI, followed by one or more lower or uppercase English letters,
// followed by EOI.
var reAlphabetic = /^[a-zA-Z]+$/

// BOI, followed by one or more lower or uppercase English letters
// or digits, followed by EOI.
var reAlphanumeric = /^[a-zA-Z0-9]+$/

// BOI, followed by one digit, followed by EOI.
var reDigit = /^\d/

// BOI, followed by one or two digits, followed by "/" followed by
// one or two digits, followed by "/" followed by four digits.
var reDate = /^\d+\/\d+\/\d\d\d\d/

// BOI, followed by one lower or uppercase English letter
// or digit, followed by EOI.
var reLetterOrDigit = /^([a-zA-Z]|\d)$/

// BOI, followed by one or more digits, followed by EOI.
var reInteger = /^\d+$/

// BOI, followed by an optional + or -, followed by one or more digits,
// followed by EOI.
var reSignedInteger = /^(\+|-)?\d+$/

// BOI, followed by one of these two patterns:
// (a) one or more digits, followed by ., followed by zero or more digits
// (b) zero or more digits, followed by ., followed by one or more digits
// ... followed by EOI.
var reFloat = /^((\d+(\.\d*)?)|((\d*\.)?\d+))$/

// BOI, followed by an optional + or -, followed by one of these two patterns:
// (a) one or more digits, followed by ., followed by zero or more digits
// (b) zero or more digits, followed by ., followed by one or more digits
// ... followed by EOI.
var reSignedFloat = /^(((\+|-)?\d+(\.\d*)?)|((\+|-)?(\d*\.)?\d+))$/

// BOI, followed by one or more characters, followed by @,
// followed by one or more characters, followed by .,
// followed by one or more characters, followed by EOI.
var reEmail = /^.+\@.+\..+$/

// VARIABLE DECLARATIONS

var digits = "0123456789"

var lowercaseLetters = "abcdefghijklmnopqrstuvwxyz"

var uppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

// Delimeters (valid non-digit chars) and valid characters
var phoneNumberDelimiters = "+()- "
var validUSPhoneChars = digits + phoneNumberDelimiters
// Allowed in international phone numbers (a leading + is OK)
var validWorldPhoneChars = digits + phoneNumberDelimiters + "+"

var SSNDelimiters = "- "
var validSSNChars = digits + SSNDelimiters
var digitsInSocialSecurityNumber = 9

var TaxIdDelimiters = "-"
var validTaxIdChars = digits + TaxIdDelimiters
var digitsInTaxId = 9

var DUNSDelimiters = "-"
var validDUNSChars = digits + DUNSDelimiters
var digitsInDUNS = 9

var digitsInUSPhoneNumber = 10
var digitsInUSShortPhoneNumber = 7

var ZIPCodeDelimiters = "-"
// our preferred delimiter for reformatting ZIP Codes
var ZIPCodeDelimeter = "-"
var validZIPCodeChars = digits + ZIPCodeDelimiters
var digitsInZIPCode1 = 5
var digitsInZIPCode2 = 9

var creditCardDelimiters = " "

// non-digit characters which are not allowed in integers and decimals
var invalidIntChars = " $()_+&*^%#@!";	// Add comma and decimalPoint
var invalidDecChars = " $()_+&*^%#@!";	// Add comma


// CONSTANT STRING DECLARATIONS
// (grouped for ease of translation and localization)
// m is an abbreviation for "missing"
var mPrefix = "You did not enter a value into the "
var mSuffix = " field. This is a required field. Please enter it now."

// s is an abbreviation for "string"
var sUSLastName = "Last Name"
var sUSFirstName = "First Name"
var sWorldLastName = "Family Name"
var sWorldFirstName = "Given Name"
var sTitle = "Title"
var sCompanyName = "Company Name"
var sUSAddress = "Street Address"
var sWorldAddress = "Address"
var sCity = "City"
var sStateCode = "State Code"
var sWorldState = "State, Province, or Prefecture"
var sCountry = "Country"
var sZIPCode = "ZIP Code"
var sWorldPostalCode = "Postal Code"
var sPhone = "Phone Number"
var sFax = "Fax Number"
var sDateOfBirth = "Date of Birth"
var sExpirationDate = "Expiration Date"
var sEmail = "Email"
var sSSN = "Social Security Number"
var sCreditCardNumber = "Credit Card Number"
var sOtherInfo = "Other Information"
var sNumber = "Number"
var sTaxId = "Tax ID"
var sTaxId = "DUNS Number"

// i is an abbreviation for "invalid"
var iStateCode = " must be a valid two character U.S. state abbreviation (like CA for California)."
var iZIPCode1 = " must be a 5 digit U.S. ZIP Code (like 94043)."
var iZIPCode2 = " must be a 5 or 9 digit U.S. ZIP Code (like 94043-1234)."
var iZIPCode3 = " must be a 9 digit U.S. ZIP Code (like 94043-1234)."
var iUSPhone = " must be a 10 digit U.S. phone number (like 415 555 1212)"
var iUSShortPhone = " must be a 7 or 10 digit U.S. phone number (like 555 1212 or 415 555 1212)"
var iWorldPhone = " must be a valid international phone number."
var iSSN = " must be a 9 digit U.S. social security number (like 123 45 6789)."
var iEmail = " must be a valid email address (like john.doe@dots-usa.com)."
var iCreditCardPrefix = "This is not a valid "
var iCreditCardSuffix = " credit card number. (Click the link on this form to see a list of sample numbers.)"
var iDay = "This field must be a day number between 1 and 31."
var iMonth = "This field must be a month number between 1 and 12."
var iYear = "This field must be a 2 or 4 digit year number."
var iDatePrefix = "The Day, Month, and Year for "
var iDateSuffix = " do not form a valid date."
var iReEnter = " Please reenter."
var iNumber = " must be a number"
var iNumberRangeMin = " greater than or equal to "
var iNumberRangeMax = " less than or equal to "
var iTaxId = " must be a " + digitsInTaxId + " digit Tax ID (like 12-3456789)."
var iDUNS = " must be a " + digitsInDUNS + " digit DUNS number (like 12-345-6789)."

// p is an abbreviation for "prompt"
var pEntryPrompt = "Please enter a "
var pStateCode = "2 character code (like CA)."
var pZIPCode1 = "5 digit U.S. ZIP Code (like 94043)."
var pZIPCode2 = "5 or 9 digit U.S. ZIP Code (like 94043 or 94043-1234)."
var pZIPCode3 = "9 digit U.S. ZIP Code (like 94043-1234)."
var pUSPhone = "10 digit U.S. phone number (like 415 555 1212)"
var pUSShortPhone = "7 or 10 digit U.S. phone number (like 555 1212 or 415 555 1212)"
var pWorldPhone = "international phone number."
var pSSN = "9 digit U.S. social security number (like 123 45 6789)."
var pEmail = "valid email address (like john.doe@dots-usa.com)."
var pCreditCard = "valid credit card number."
var pDay = "day number between 1 and 31."
var pMonth = "month number between 1 and 12."
var pYear = "2 or 4 digit year number."
var pRequiredText = "non-blank value"
var pNotRequiredText = "blank (empty) field or a non-blank value"
var pMinLength = " with at least %1 characters"
var pMaxLength = " with no more than %2 characters."
var pNoMaxLength = " with no length limit."
var pDate = "date in the format 'mm/dd/yyyy' from "
var pDateRangeMid = " to "
var pDateMin = "1/1/1000"
var pDateMax = "12/31/9999"
var pNumber = "number"
var pNumberRangeMin = " greater than or equal to "
var pNumberRangeMax = " less than or equal to "
var pTaxId = digitsInTaxId + " digit Tax ID (like 12-3456789)."
var pDUNS = digitsInDUNS + " digit DUNS number (like 12-345-6789)."


// Global variable defaultEmptyOK defines default return value
// for many functions when they are passed the empty string.
// By default, they will return defaultEmptyOK.
//
// defaultEmptyOK is false, which means that by default,
// these functions will do "strict" validation.  Function
// isInteger, for example, will only return true if it is
// passed a string containing an integer; if it is passed
// the empty string, it will return false.
//
// You can change this default behavior globally (for all
// functions which use defaultEmptyOK) by changing the value
// of defaultEmptyOK.
//
// Most of these functions have an optional argument emptyOK
// which allows you to override the default behavior for
// the duration of a function call.
//
// This functionality is useful because it is possible to
// say "if the user puts anything in this field, it must
// be an integer (or a phone number, or a string, etc.),
// but it's OK to leave the field empty too."
// This is the case for fields which are optional but which
// must have a certain kind of content if filled in.
var defaultEmptyOK = false

// Attempting to make this library run on Navigator 2.0,
// so I'm supplying this array creation routine as per
// JavaScript 1.0 documentation.  If you're using
// Navigator 3.0 or later, you don't need to do this;
// you can use the Array constructor instead.
function makeArray(n) {
	//*** BUG: If I put this line in, I get two error messages:
	//(1) Window.length can't be set by assignment
	//(2) daysInMonth has no property indexed by 4
	//If I leave it out, the code works fine.
	//   this.length = n;
	for (var i = 1; i <= n; i++) {
	  this[i] = 0
	}
	return this
}

// daysInFebruary (INTEGER year)
//
// Given integer argument year,
// returns number of days in February of that year.

function daysInFebruary (year)
{   // February has 29 days in any year evenly divisible by four,
    // EXCEPT for centurial years which are not also divisible by 400.
    return (  ((year % 4 == 0) && ( (!(year % 100 == 0)) || (year % 400 == 0) ) ) ? 29 : 28 );
}

var daysInMonth = makeArray(12);
daysInMonth[1] = 31;
daysInMonth[2] = 28;   // 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;

// Valid U.S. Postal Codes for states, territories, armed forces, etc.
// See http://www.usps.gov/ncsc/lookups/abbr_state.txt.
var USStateCodeDelimiter = "|";
var USStateCodes = "AL|AK|AS|AZ|AR|CA|CO|CT|DE|DC|FM|FL|GA|GU|HI|ID|IL|IN|IA|KS|KY|LA|ME|MH|MD|MA|MI|MN|MS|MO|MT|NE|NV|NH|NJ|NM|NY|NC|ND|MP|OH|OK|OR|PW|PA|PR|RI|SC|SD|TN|TX|UT|VT|VI|VA|WA|WV|WI|WY|AE|AA|AE|AE|AP"

//------------------------------------------
// Basic String Tests (The isFunctions)
//------------------------------------------
//
// Check whether string s is empty.
function isEmpty(s)
{   return ((s == null) || (s.length == 0))
}

// Returns true if string s is empty or
// whitespace characters only.
function isWhitespace (s)
{   // Is s empty?
    return (isEmpty(s) || reWhitespace.test(s));
}

// isInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if all characters in string s are numbers.
//
// Accepts non-signed integers only. Does not accept floating
// point, exponential notation, etc.
//
// We don't use parseInt because that would accept a string
// with trailing non-numeric characters.
//
// By default, returns defaultEmptyOK if s is empty.
// There is an optional second argument called emptyOK.
// emptyOK is used to override for a single function call
//      the default behavior which is specified globally by
//      defaultEmptyOK.
// If emptyOK is false (or any value other than true),
//      the function will return false if s is empty.
// If emptyOK is true, the function will return true if s is empty.
//
// EXAMPLE FUNCTION CALL:     RESULT:
// 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);

    return reInteger.test(s);
}

// Returns true if character c is an English letter
// (A .. Z, a..z).
//
// NOTE: Need i18n version to support European characters.
// This could be tricky due to different character
// sets and orderings for various languages and platforms.
function isLetter (c)
{   return reLetter.test(c);
}

// Returns true if character c is a digit
// (0 .. 9).
function isDigit (c)
{   return reDigit.test(c);
}

// Returns true if character c is a letter or digit.
function isLetterOrDigit (c)
{   return reLetterOrDigit.test(c);
}

// isPositiveInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if string s is an integer > 0.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
function isPositiveInteger (s)
{   var secondArg = defaultEmptyOK;

    if (isPositiveInteger.arguments.length > 1)
        secondArg = isPositiveInteger.arguments[1];

    // The next line is a bit byzantine.  What it means is:
    // 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) ) );
}

// isSignedInteger (STRING s [, BOOLEAN emptyOK])
//
// Returns true if all characters are numbers;
// first character is allowed to be + or - as well.
//
// Does not accept floating point, exponential notation, etc.
//
// We don't use parseInt because that would accept a string
// with trailing non-numeric characters.
//
// For explanation of optional argument emptyOK,
// see comments of function isInteger.
//
// EXAMPLE FUNCTION CALL:          RESULT:
// isSignedInteger ("5")           true
// isSignedInteger ("")            defaultEmptyOK
// isSignedInteger ("-5")          true
// isSignedInteger ("+5")          true
// isSignedInteger ("", false)     false
// isSignedInteger ("", true)      true
function isSignedInteger (s)
{   isSInt = false;
	if (isEmpty(s))
       if (isSignedInteger.arguments.length == 1) return defaultEmptyOK;
       else return (isSignedInteger.arguments[1] == true);
    else {
       return reSignedInteger.test(s);
    }
}

//-----------------------------------------
// String Modification Functions
//-----------------------------------------
//
// Removes all characters which appear in regexp bag from string s.
// NOTES:
// 1) bag must be a regexp which matches single characters in isolation,
//    i.e. A or B or C or D or 1 or 2 ...
//    e.g. /\d/g  or /[a-zA-Z]/g
// 2) make sure to append the 'g' modifier (for global search & replace)
//    at the end of the regexp
//    e.g. /\d/g  or /[a-zA-Z]/g
function stripCharsInRE (s, bag)
{       return s.replace(bag, "");
}

// Removes all characters which appear in string bag from string s.
function stripCharsInBag (s, bag)
{   var i;
    var returnString = "";

    // Search through string's characters one by one.
    // If character is not in bag, append to returnString.

    for (i = 0; i < s.length; i++)
    {
        // Check that current character isn't in the bag.
        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 = "";

    // Search through string's characters one by one.
    // If character is in bag, append to returnString.

    for (i = 0; i < s.length; i++)
    {
        // Check that current character isn't whitespace.
        var c = s.charAt(i);
        if (bag.indexOf(c) != -1) returnString += c;
    }

    return returnString;
}

// Returns true if any characters in the bag appear in the string
function illegalCharactersExist(testString, theBag)
{
	if (testString == "") {return false;}
	var myTest = stripCharsNotInBag(testString, theBag)
	if (myTest.length > 0) {
		return true;
	} else {
		return false;
	}
}

// Removes all whitespace characters from s.
// Global variable whitespace (see above)
// defines which characters are considered whitespace.
function stripWhitespace (s)
{   return stripCharsInBag (s, whitespace);
}

// WORKAROUND FUNCTION FOR NAVIGATOR 2.0.2 COMPATIBILITY.
//
// The below function *should* be unnecessary.  In general,
// avoid using it.  Use the standard method indexOf instead.
//
// However, because of an apparent bug in indexOf on
// Navigator 2.0.2, the below loop does not work as the
// body of stripInitialWhitespace:
//
// while ((i < s.length) && (whitespace.indexOf(s.charAt(i)) != -1))
//   i++;
//
// ... so we provide this workaround function charInString
// instead.
//
// charInString (CHARACTER c, STRING s)
//
// Returns true if single 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;
}

// reformat (TARGETSTRING, STRING, INTEGER, STRING, INTEGER ... )
//
// Handy function for arbitrarily inserting formatting characters
// or delimiters of various kinds within TARGETSTRING.
//
// 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.
//
// reformat processes the other arguments in order one by one.
// * 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.  This is to
// provide backward compatibility to Navigator 2.0.2 JavaScript
// by avoiding use of the typeof operator.
//
// It is the caller's responsibility to make sure that we do not
// try to copy more characters from s than s.length.
//
// EXAMPLES:
//
// * To reformat a 10-digit U.S. phone number from "1234567890"
//   to "(123) 456-7890" make this function call:
//   reformat("1234567890", "(", 3, ") ", 3, "-", 4)
//
// * To reformat a 9-digit U.S. Social Security number from
//   "123456789" to "123-45-6789" make this function call:
//   reformat("123456789", "", 3, "-", 2, "-", 4)
//
// HINT:
//
// If you have a string which is already delimited in one way
// (example: a phone number delimited with spaces as "123 456 7890")
// and you want to delimit it in another way using function reformat,
// call function stripCharsNotInBag to remove the unwanted
// characters, THEN call function reformat to delimit as desired.
//
// EXAMPLE:
//
// reformat (stripCharsNotInBag ("123 456 7890", digits),
//           "(", 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;
}

// takes USPhone, a string of 10 digits
// and reformats as (123) 456-789
function reformatUSPhone(USPhone)
{   return (reformat (USPhone, "(", 3, ") ", 3, "-", 4));
}

// takes USPhone, a string of 10 digits
// and reformats as (123) 456-789
function reformatUSShortPhone(USPhone)
{   return (reformat (USPhone, "", 3, "-", 4));
}

// takes SSN, a string of 9 digits
// and reformats as 123-45-6789
function reformatSSN (SSN)
{   return (reformat (SSN, "", 3, "-", 2, "-", 4));
}

// takes Tax ID, a string of 9 digits
// and reformats as 12-3456789
function reformatTaxId (taxId)
{   return (reformat (taxId, "", 2, TaxIdDelimiters, 7));
}

// takes DUNS number, a string of 9 digits
// and reformats as 12-345-6789
function reformatDUNS (DUNS)
{   return (reformat (DUNS, "", 2, DUNSDelimiters, 3, DUNSDelimiters, 4));
}

// takes ZIPString, a string of 5 or 9 digits;
// if 9 digits, inserts separator hyphen
function reformatZIPCode (ZIPString)
{   if (ZIPString.length == 5) return ZIPString;
    else return (reformat (ZIPString, "", 5, ZIPCodeDelimeter, 4));
}

// takes a formatted positive integer and reformats it with the given comma separator
// 100000 becomes 100,000. 2000000 becomes 2,000,000.
function reformatIntWithCommas(theInt, theComma) {
	var intwcIdx
	preComma1 = theInt.length % 3;
	commas = parseInt(theInt.length / 3);
	if ((commas < 2) && (preComma1 == 0)) {
		intString = theInt;
	} else {
		if (preComma1 == 0) {
			preComma1 = 3
			commas = commas - 1
		}
		refCommand = "intString = reformat(\"" + theInt + "\", \"\", " + preComma1;
		for (intwcIdx = 0; intwcIdx < commas; intwcIdx++) {
		   refCommand += ", \"" + theComma + "\", 3";
		}
		refCommand += ")"
		eval(refCommand);
	}
	return intString
}

//----------------------------
// Main validate function
//----------------------------
// This function loops through all the elements in the form and
// calls the element's validate function for each element that
// has one. All such elements are checked, regardless if any failed.
// If any fail, the full description of all errors are displayed
// and false is returned. If all pass, then true is returned.
//
function validateForm(){

	this.errorText = "";	// The full error text.
	errorOccurred = false;	// Assume the best

	for (i = 0; i < this.elements.length; i++) {
		if (typeof(this.elements[i].validator) != "undefined") {
			if (! this.elements[i].validator.validate()) {
				errorOccurred = true;
				this.errorText = this.errorText + this.elements[i].validator.errorText +"\n";
			}
		}
	}
	if (errorOccurred) {
		alert("Data Entry Validation Failed. " + iReEnter + "\n\n" + this.errorText);
	}
	return !errorOccurred;
}

//----------------------------
// Main format function
//----------------------------
// This function loops through all the elements in the form and
// calls the element's format function for each element that
// has a validator.
//
function formatForm(){
	var frmtIdx
	for (frmtIdx = 0; frmtIdx < this.elements.length; frmtIdx++) {
		if (typeof(this.elements[frmtIdx].validator) != "undefined") {
			this.elements[frmtIdx].validator.format();
		}
	}
}

//----------------------------
// Main unformat function
//----------------------------
// This function loops through all the elements in the form and
// calls the element's unformat function for each element that
// has a validator.
//
function unformatForm(){
	for (i = 0; i < this.elements.length; i++) {
		if (typeof(this.elements[i].validator) != "undefined") {
			this.elements[i].validator.unformat();
		}
	}
}

//=======================================================================
// Validator Types
//=======================================================================
//
// The EMailValidator object.
//
function EMailValidator(obj, labelText, required) {

	this.obj = obj;				// The form element
	this.labelText = labelText;	// What we call the field for the user.
	this.required = required;	// Indicates user must enter valid data
	this.errorText = ""; 		// Holds error message for failures
	this.validate = isEmail;	// Validates field.
	this.format = formatEmail;
	this.unformat = nullMethod;
}

// The PhoneValidator object.
//
function PhoneValidator(obj, labelText, required, USOK, USAreaRequired, IntlOK){

	this.obj = obj;				// The form element
	this.labelText = labelText;	// What we call the field for the user.
	this.required = required;	// Indicates user must enter valid data
	this.USOK = USOK;			// US phone format OK?
	this.USAreaRequired = USAreaRequired;	// US Area Code required?
	this.IntlOK = IntlOK;		// International format OK?
	this.errorText = ""; 		// Holds error message for failures
	this.validate = isPhoneNumber;	// Validates field.
	this.format = formatPhoneNumber;
	this.unformat = unformatPhoneNumber;
}

// The SingleSelectValidator object.
//
function SingleSelectValidator(obj, labelText, required, invSelIndex) {

	this.obj = obj;										// The form element
	this.labelText = labelText;							// What we call the field for the user.
	this.required = required;							// Indicates user must enter valid data
	this.invSelIndex = invSelIndex;						// Indicates which select item is invalid
	this.errorText = ""; 								// Holds error message for failures
	this.args = SingleSelectValidator.arguments.length;	// Holds number of arguments passed
	this.validate = checkSingleSelect;					// Validates field.
	this.format = nullMethod;
	this.unformat = nullMethod;
}

// The CleanTextValidator object.
//
function CleanTextValidator(obj, labelText, required, minLength, maxLength) {

	this.obj = obj;				// The form element
	this.labelText = labelText;	// What we call the field for the user.
	this.required = required;	// Indicates user must enter valid data
	this.minLength = minLength;	// Minimum length of clean text
	this.maxLength = maxLength;	// Maximum length of clean text
	this.errorText = ""; 		// Holds error message for failures
	this.validate = cleanText;	// Validates field.
	this.format = formatCleanText;
	this.unformat = nullMethod;
	
	if (document._illegalFormCharacters_) {
		this.illegalChars = document._illegalFormCharacters_;
	} else {
		this.illegalChars = "";
	}
}

// The AnyTextValidator object.
//
function AnyTextValidator(obj, labelText, required, minLength, maxLength) {

	this.obj = obj;				// The form element
	this.labelText = labelText;	// What we call the field for the user.
	this.required = required;	// Indicates user must enter valid data
	this.minLength = minLength;	// Minimum length of clean text
	this.maxLength = maxLength;	// Maximum length of clean text
	this.errorText = ""; 		// Holds error message for failures
	this.validate = anyText;	// Validates field.
	this.format = nullMethod;
	this.unformat = nullMethod;

	if (document._illegalFormCharacters_) {
		this.illegalChars = document._illegalFormCharacters_;
	} else {
		this.illegalChars = "";
	}
}

// The SSNValidator object.
//
function SSNValidator(obj, labelText, required) {

	this.obj = obj;				// The form element
	this.labelText = labelText;	// What we call the field for the user.
	this.required = required;	// Indicates user must enter valid data
	this.errorText = ""; 		// Holds error message for failures
	this.validate = isSSN;		// Validates field.
	this.format = formatSSN;
	this.unformat = unformatSSN;
}

// The TaxIdValidator object.
//
function TaxIdValidator(obj, labelText, required) {

	this.obj = obj;				// The form element
	this.labelText = labelText;	// What we call the field for the user.
	this.required = required;	// Indicates user must enter valid data
	this.errorText = ""; 		// Holds error message for failures
	this.validate = isTaxId;		// Validates field.
	this.format = formatTaxId;
	this.unformat = unformatTaxId;
}

// The DUNSValidator object.
//
function DUNSValidator(obj, labelText, required) {

	this.obj = obj;				// The form element
	this.labelText = labelText;	// What we call the field for the user.
	this.required = required;	// Indicates user must enter valid data
	this.errorText = ""; 		// Holds error message for failures
	this.validate = isDUNS;		// Validates field.
	this.format = formatDUNS;
	this.unformat = unformatDUNS;
}

// The USZipCodeValidator object.
//
function USZipCodeValidator(obj, labelText, required, plus4Allowed, plus4Required) {

	this.obj = obj;				// The form element
	this.labelText = labelText;	// What we call the field for the user.
	this.required = required;	// Indicates user must enter valid data
	this.plus4Allowed = plus4Allowed; // Indicates if plus-4 digits allowed
	this.plus4Required = plus4Required;	// Indicates if plus-4 digits required
	this.errorText = ""; 		// Holds error message for failures
	this.validate = isUSZip;	// Validates field.
	this.format = formatUSZipCode;
	this.unformat = unformatUSZipCode;
}

// The StateCodeValidator object.
//
function StateCodeValidator(obj, labelText, required) {

	this.obj = obj;				// The form element
	this.labelText = labelText;	// What we call the field for the user.
	this.required = required;	// Indicates user must enter valid data
	this.errorText = ""; 		// Holds error message for failures
	this.validate = isStateCode; // Validates field.
	this.format = formatStateCode;
	this.unformat = nullMethod;
}

// The DateValidator object.
//
function DateValidator(obj, labelText, required, earliest, latest) {
	/*
	var earliest = "01/11/1753";;
	var latest = "12/31/9999";
	
	if (this.args >= 4) earliest = this.args[3];
	if (this.args >= 5) earliest = this.args[4];*/
	
	this.obj = obj;				// The form element
	this.labelText = labelText;	// What we call the field for the user.
	this.required = required;	// Indicates user must enter valid data
	this.earliest = earliest;	// Earliest acceptable date
	this.latest = latest;		// Latest acceptable date
	this.errorText = ""; 		// Holds error message for failures
	this.args = DateValidator.arguments.length;
	this.validate = isDate;		// Validates field.
	this.format = formatDate;
	this.unformat = nullMethod;
	
	// In the case where earliest has not been passed AND document.DateValidatorMinDate
	// has been set, then use that value for this.earliest...
	if ((this.args < 4) && (typeof(document.DateValidatorMinDate) == "string")) {
		this.earliest = document.DateValidatorMinDate;
	} 
	// In the case where latest has not been passed AND document.DateValidatorMaxDate
	// has been set, then use that value for this.latest...
	if ((this.args < 5) && (typeof(document.DateValidatorMaxDate) == "string")) {
		this.latest = document.DateValidatorMaxDate;
	} 
}

// The NumberValidator object. If not a dollar value, but min or max needed,
// use "" as dollarSign.
//
function NumberValidator(obj, labelText, required, decimals, dollarSign, minimum, maximum) {

	this.obj = obj;				// The form element
	this.labelText = labelText;	// What we call the field for the user.
	this.required = required;	// Indicates user must enter valid data
	this.decimals = decimals;	// Number of decimal places to the right of the decimal pt
	this.dollarSign = dollarSign // Holds the character that indicates money
	this.minimum = minimum;		// Minimum acceptable value
	this.maximum = maximum;		// Maximum acceptable value
	this.errorText = ""; 		// Holds error message for failures
	this.comma = ",";				// Value to use as comma.
	this.formatWithCommas = true;	// Formats with thousands delimiter if true.
	this.decimalPoint = "."		// Holds the value used for decimal point.
	this.redNegative = false	// Indicates if the text should be set to red if negative.
	this.args = NumberValidator.arguments.length;
	this.validate = isNumber;	// Validates field.
	this.setErrorText = setNumberFullErrorText;
	this.testRange = testNumberRange;
	this.format = formatNumber;
	this.unformat = unformatNumber;
	if (this.args < 7) {this.maximum = null;}
	if (this.args < 6) {this.minimum = null;}
	if (this.args < 5) {this.dollarSign = "";}
	if (document.layers) {
		this.origColor = this.obj.color;
	} else {
		// IE
		this.origColor = this.obj.style.color;
	}
}

//----------------------------
// Validation Functions
//----------------------------
//
// isEmail()
//
// Email address must be of form a@b.c -- in other words:
// * there must be at least one character before the @
// * there must be at least one character before and after the .
// * the characters @ and . are both required
//
function isEmail() {
	if (isEmpty(this.obj.value)) {
		if (this.required) {
			this.errorText = this.labelText + ": " + pEntryPrompt + pEmail;
			return false;
		} else {
			this.errorText = "";
			return true;
		}
	} else {
		if (reEmail.test(this.obj.value)) {
			this.errorText = "";
			return true;
		}  else {
			this.errorText = this.labelText + iEmail;
			return false;
		}
	}
}

function isPhoneNumber() {
	phoneOK = true;
	// Strip out any delimiters (spaces, hyphens, parentheses, etc.)...
	phoneString = stripCharsInBag(this.obj.value, phoneNumberDelimiters);
	this.errorText = "";

	// First see if it's empty...
	if (isEmpty(phoneString)) {
		if (this.required) {
			this.errorText = this.labelText + ": " + pEntryPrompt +
				(this.USOK ? (this.USAreaRequired ? pUSPhone: pUSShortPhone):"")
				+ (this.IntlOK && this.USOK ? " or " : "") + (this.IntlOK ? pWorldPhone : ".");
			return false;
		} else {
			return true;
		}
	// Now check allowable phone types...
	} else {
		if (this.USOK) {
			if (this.USAreaRequired) {
				// returns true if string is a valid U.S. Phone
				// Number.  Must be 10 digits.
				phoneOK = (isInteger(phoneString) && (phoneString.length == digitsInUSPhoneNumber));
			} else {
				// returns true if string is a valid U.S. Phone
				// Number.  Must be 7 or 10 digits.
				phoneOK = (isInteger(phoneString) && (phoneString.length ==digitsInUSPhoneNumber) || (phoneString.length ==digitsInUSShortPhoneNumber));
			}
		}
		// Reformat the US phone number to standard format...
		if (phoneOK) {
			this.format();
		}
		// Check to see if it's an international phone number...
		if ((!phoneOK || !this.USOK) && this.IntlOK) {
			// returns true if string is a valid
			// international phone number.  Must be digits only; any length OK.
			// May be prefixed by + character.
			// NOTE: A phone number of all zeros would not be accepted.
			// I don't think that is a valid phone number anyway.
			phoneOK = isPositiveInteger(phoneString);
		}

		if(phoneOK) {
			return true;
		} else {
			this.errorText = this.labelText + (this.USOK ? (this.USAreaRequired ? iUSPhone: iUSShortPhone ) : "") + ((this.USOK && this.IntlOK) ? " or " : "") + (this.IntlOK ? iWorldPhone : "");

			return false;
		}
	}
}

// checkSingleSelect()     note: this is an object declaration not function!
//
// 		Validation checks:
// 			1) Fail if: blank or null, and is required
// 			2) Fail if: selection is made and is not the invalid item based on invSelIndex
//
function checkSingleSelect() {
	// check if a selection was made, and then if a selection was required
	if (this.obj.selectedIndex == -1) {
		if (this.required) {
			this.errorText = this.labelText + ": a selection is required.";
			return false;
		} else {
			return true;
		}
	}
	// a selection has been made, now check if it is valid
	if (this.args == 4) {
		if (this.obj.selectedIndex != this.invSelIndex) {
			return true;
		}
		else {
			if (this.required) {
				this.errorText = this.labelText + ": A valid selection is required.";
				return false;
			} else {
				return true;
			}
		}
	} else {
		return true;
	}
}

// cleanText()
//
// Checks to make sure entered data is within length limits (after triming).
// Removes leading and trailing whitespace (trims).
//
function cleanText() 
{
	this.errorText = " ";
	// Trim leading and trailing whitespace...
	tempString = trim(this.obj.value);
	// Check for empty validation...
	if (isEmpty(tempString)) 
	{
		if (!this.required) 
		{
			// It's OK. Remove leading and trailing spaces...
			this.obj.value = tempString;
			return(true);
		}
	} 
	else 
	{
		// Check to make sure string is within given length range...
		if (tempString.length >= this.minLength &&
			(tempString.length <= this.maxLength || this.maxLength == 0)) 
		{
			// Within range. Now test for illegal characters...
			if (this.illegalChars != "") 
			{
				if (illegalCharactersExist(tempString, this.illegalChars)) 
				{
					this.errorText = this.labelText + " contains one of the following disallowed characters: " + this.illegalChars;
					this.obj.value = tempString;
					return(false);
				}
			}
			
			//added 8/25/2004 Adam Webster, check for ascii printable characters only
			//for (var i=0; i<tempString.length; i++)
			//	if (tempString.search(/[:print:]/)
			
			// It's OK. Reformat the entry (trim)...
			//this.obj.value = tempString;
			//changed to remove any non printable characters.
			//this.obj.value = tempString.replace(/[^ A-Za-z0-9`~!@#\$%\^&\*\(\)-_=\+\\\|\]\[\}\{'";:\?\/\.>,<,\s,\n,\t]/g, "");
			
			//the previous method did not allow for special characters, i.e. unicode 241 = ñ
			//see http://www.website101.com/HTML/unicode.html
			var iString = this.obj.value;
			var rString = "";
			for (var i=0; i<iString.length; i++)
				if (((iString.charCodeAt(i) <= 128) || (iString.charCodeAt(i) >= 160))
					&& (iString.charCodeAt(i) <= 255))
					rString += iString.charAt(i);
			
			this.obj.value = rString;
			
			/*this.obj.value += "\n";
			for (var j=160; j<=255; j++)
				this.obj.value += "[" + String.fromCharCode(j) + "] ";*/
			//return(false);
			
			return(true);
		}
	}
	// If it makes it this far, there is an error. Provide message...
	if (this.required) this.errorText = this.labelText + ": " + pEntryPrompt + pRequiredText;
	else this.errorText = this.labelText + ": " + pEntryPrompt + pNotRequiredText;
	
	// Check for minimum length requirement...
	if (this.minLength > 0) this.errorText += pMinLength;
	
	// Check for maximum length requirement...
	if (this.maxLength > 0) this.errorText += pMaxLength;
	else this.errorText += pNoMaxLength;
	
	// Do quantity substitutions...
	this.errorText = this.errorText.replace(new RegExp("%1"), this.minLength);
	this.errorText = this.errorText.replace(new RegExp("%2"), this.maxLength);
	return(false);
}

// anyText()
//
// Checks to make sure entered data is within length limits (without triming).
//
function anyText() {
	this.errorText = "";
	// Work with a variable for easier readability...
	tempString = this.obj.value;
	// Check for empty validation...
	if (isEmpty(tempString)) {
		if (!this.required) {
			return true;
		}
	} else {
		// Check to make sure string is within given length range...
		if (tempString.length >= this.minLength &&
			(tempString.length <= this.maxLength || this.maxLength == 0)) {
			// Within range. Now test for illegal characters...
			if (this.illegalChars != "") {
				if (illegalCharactersExist(tempString, this.illegalChars)) {
					this.errorText = this.labelText + " contains one of the following disallowed characters: " + this.illegalChars;
					this.obj.value = tempString;
					return false
				}
			}
			return true;
		}
	}
	// If it makes it this far, there is an error. Provide message...
	if (this.required) {
		this.errorText = this.labelText + ": " + pEntryPrompt + pRequiredText;
	} else {
		this.errorText = this.labelText + ": " + pEntryPrompt + pNotRequiredText;
	}
	// Check for minimum length requirement...
	if (this.minLength > 0) {
		this.errorText += pMinLength;
	}
	// Check for maximum length requirement...
	if (this.maxLength > 0) {
		this.errorText += pMaxLength;
	} else {
		this.errorText += pNoMaxLength;
	}
	// Do quantity substitutions...
	this.errorText = this.errorText.replace(new RegExp("%1"), this.minLength);
	this.errorText = this.errorText.replace(new RegExp("%2"), this.maxLength);
	return false;
}

// isSSN()
//
// Checks to make sure entered data is a valid Social Security Number.
// Reformats string to ###-##-####.
//
function isSSN() {
	this.errorText = "";
	// Strip out any delimiters (spaces, hyphens, parentheses, etc.)...
	tempString = stripCharsInBag(this.obj.value, SSNDelimiters);
	// Check for empty validation...
	if (isEmpty(tempString)) {
		if (!this.required) {
			return true;
		} else {
			// Provide error message...
			this.errorText = this.labelText + ": " + pEntryPrompt + pSSN;
			return false;
		}
	} else {
		// Check to make sure string is a valid SSN...
		if (isInteger(tempString) && tempString.length == digitsInSocialSecurityNumber) {
			// Is SSN. Reformat and return success.
			this.obj.value = reformatSSN(tempString);
			return true;
		} else {
			this.errorText = this.labelText + iSSN;
			return false;
		}
	}
}

// isTaxId()
//
// Checks to make sure entered data is a valid Tax ID.
// Reformats string to ##-#######.
//
function isTaxId() {
	this.errorText = "";
	// Strip out any delimiters (spaces, hyphens, etc.)...
	tempString = stripCharsInBag(this.obj.value, TaxIdDelimiters + " ");
	// Check for empty validation...
	if (isEmpty(tempString)) {
		if (!this.required) {
			this.obj.value = "";
			return true;
		} else {
			// Provide error message...
			this.errorText = this.labelText + ": " + pEntryPrompt + pTaxId;
			return false;
		}
	} else {
		// Check to make sure string is a valid TaxId...
		if (isInteger(tempString) && tempString.length == digitsInTaxId) {
			// Is Tax ID. Reformat and return success.
			this.obj.value = reformatTaxId(tempString);
			return true;
		} else {
			this.errorText = this.labelText + iTaxId;
			return false;
		}
	}
}

// isDUNS()
//
// Checks to make sure entered data is a valid DUNS number.
// Reformats string to ##-###-####.
//
function isDUNS() {
	this.errorText = "";
	// Strip out any delimiters (spaces, hyphens, etc.)...
	tempString = stripCharsInBag(this.obj.value, DUNSDelimiters + " ");
	// Check for empty validation...
	if (isEmpty(tempString)) {
		if (!this.required) {
			this.obj.value = "";
			return true;
		} else {
			// Provide error message...
			this.errorText = this.labelText + ": " + pEntryPrompt + pDUNS;
			return false;
		}
	} else {
		// Check to make sure string is a valid DUNS...
		if (isInteger(tempString) && tempString.length == digitsInDUNS) {
			// Is DUNS. Reformat and return success.
			this.obj.value = reformatDUNS(tempString);
			return true;
		} else {
			this.errorText = this.labelText + iDUNS;
			return false;
		}
	}
}

// isUSZip()
//
// Checks to make sure entered data is a valid US Zip Code.
// Reformats string to #####-####.
//
function isUSZip() {
	this.errorText = "";
	// Make plus4 stuff make sense...
	if (this.plus4Required) this.plus4Allowed = true;
	// Strip out any delimiters (spaces, hyphens, parentheses, etc.)...
	tempString = stripCharsInBag(this.obj.value, ZIPCodeDelimiters);
	// Check for empty validation...
	if (isEmpty(tempString)) {
		if (!this.required) {
			return true;
		} else {
			// Provide error message...
			this.errorText = this.labelText + ": " + pEntryPrompt + (this.plus4Allowed ? (this.plus4Required ? pZIPCode3: pZIPCode2): pZIPCode1);
			return false;
		}
	} else {
		// Check to make sure string is a valid Zip Code...
		if (isInteger(tempString)) {
			// Determine which tests are needed...
			if (this.plus4Required) {
				if (tempString.length == digitsInZIPCode2) {
					// It's good. Reformat and return true...
					this.obj.value = reformatZIPCode(tempString);
					return true;
				}
			} else {
				if (tempString.length == digitsInZIPCode1) {
					// It's good.
					this.obj.value = reformatZIPCode(tempString);
					return true;
				} else {
					if (this.plus4Allowed) {
						if (tempString.length == digitsInZIPCode2) {
							this.obj.value = reformatZIPCode(tempString);
							return true;
						}
					}
				}

			}
		}
	}
	// If it makes it this far, there was an error.
	this.errorText = this.labelText + (this.plus4Allowed ? (this.plus4Required ? iZIPCode3: iZIPCode2): iZIPCode1);
	return false;
}

// isState()
//
// Checks to make sure entered data is within length limits (without triming).
//
function isStateCode() {
	this.errorText = "";
	// Use a temp string for ease...
	tempString = trim(this.obj.value.toUpperCase());
	// Check for empty validation...
	if (isEmpty(tempString)) {
		if (!this.required) {
			this.obj.value = tempString;
			return true;
		} else {
			// Provide the prompt...
			this.errorText = this.labelText + ": " + pEntryPrompt + pStateCode;
			return false;
		}
	} else {
		// Check to make sure It's a state code
		if ((tempString.length == 2) 
			&& (USStateCodes.indexOf(tempString) != -1) 
			&& (tempString.indexOf(USStateCodeDelimiter) == -1)) {
			
			// It's good.
			
			this.obj.value = tempString;
			return true;
		} else {
			this.errorText = this.labelText + iStateCode;
			return false;
		}
	}
}

// isDate()
//
// isDate returns true if year, month, and day
// form a valid date. (Format is mm/dd/yyyy)"
//
function isDate() {
	this.errorText = "";
	// Use a temp string for ease...
	tempString = trim(this.obj.value);
	// Check for empty validation...
	if (isEmpty(tempString)) {
		if (!this.required) {
			this.obj.value = tempString;
			return true;
		}
	} else {
		// Make sure we have the required string format...
		if (reDate.test(tempString)) {
			// It's in m[m]/d[d]/yyyy format. Parse the pieces.
			dateParts = parseDateString(tempString);
			mm = dateParts[0];
			dd = dateParts[1];
			yy = dateParts[2];
			// Make sure we have the right number of days in a valid month...
			if (((mm > 0) && (mm <= 12) && (dd > 0) && (dd <= daysInMonth[mm])) || ((mm == 2) && (dd <= daysInFebruary(yy)))) {
				// Now see if we need to check date range...
				if (typeof(this.earliest) == "string") {
					// Check against earliest date...
					eDateParts = parseDateString(trim(this.earliest));
					dCompare = compareDateByParts(dateParts, eDateParts);
					if (dCompare != -1) {
						// Date is on or after earliest, check latest if one given...
						if (typeof(this.latest) == "string") {
							// Latest date given...
							lDateParts = parseDateString(trim(this.latest));
							dCompare = compareDateByParts(dateParts, lDateParts);
							if (dCompare != 1) {
								// Given date on or before latest. It's good.
								this.obj.value = tempString;
								return true;
							}
						} else {
							// No latest date given. Date is good.
							this.obj.value = tempString;
							return true;
						}
					}
				} else {
					// No range checking to do. Value is good.
					this.obj.value = tempString;
					return true;
				}
			}
		}
	}
	// If we made it this far, there is an error. Since message is
	// complicated, use same one for empty and invalid. (Lazy)
	this.errorText = this.labelText + ": " + pEntryPrompt + pDate;
	if (typeof(this.earliest) == "string") {
		// Earliest was provided.
		this.errorText += trim(this.earliest) + pDateRangeMid;
		if (typeof(this.latest) == "string") {
			// Latest was provided.
			this.errorText += trim(this.latest) + ".";
			return false;
		} else {
			this.errorText += pDateMax + ".";
			return false;
		}
	}
	this.errorText += pDateMin + pDateRangeMid + pDateMax + ".";
	return false;
}

// isNumber()
//
// Checks to make sure entered data is a valid number.
//
function isNumber() {
	this.errorText = "";
	// Strip out any delimiters (spaces, parentheses, etc.)...
	if (this.decimals > 0) {
		myDelims = invalidDecChars + this.comma;
	} else {
		myDelims = invalidIntChars + this.comma;
	}
	tempString = stripCharsInBag(this.obj.value, myDelims);
	// Check for empty validation...
	if (isEmpty(tempString)) {
		if (!this.required) {
			return true;
		} else {
			// Provide error message...
			this.setErrorText(": " + pEntryPrompt + pNumber, pNumberRangeMin, pNumberRangeMax);
			return false;
		}
	} else {
		// Check to make sure string is a valid number...
		if (this.decimals > 0) {
			// It's a decimal. Create the appropriate regular expression based
			// on the number of decimal places.
			// BOI, followed by an optional + or -, followed by one of these two patterns:
			// (a) one or more digits, followed by ., followed by zero or more digits up
			//	   to decimal number of digits
			// (b) zero or more digits, followed by ., followed by one or more digits
			//     up to decimal digits
			// ... followed by EOI.
			//reDecimalSource = "^(((\+|-)?\d+(\.\d{0," + this.decimals + "})?)|((\+|-)?(\d*\.)?\d{1," + this.decimals + "}))$";
			reDecimalSource = "^(((\\+|-)?\\d+(\\.\\d{0," + this.decimals + "})?)|((\\+|-)?(\\d*\\.)?\\d{1," + this.decimals + "}))$";
			reDecimal = new RegExp(reDecimalSource);
			if (reDecimal.test(tempString)) {
				isError = (this.testRange(parseFloat(tempString)) != 0);
			} else {
				isError = true;
			}
		} else {
			// It's an integer. Make sure it is, but strip off trailing decimal if it exists
			if (tempString.charAt(tempString.length - 1) == this.decimalPoint) {
				tempString = tempString.slice(0, tempString.length - 1);
			}
			if (isSignedInteger(tempString)) {
				isError = (this.testRange(parseInt(tempString)) != 0);
			} else {
				isError = true;
			}
		}
		if (isError) {
			this.setErrorText(iNumber, iNumberRangeMin, iNumberRangeMax);
			return false;
		} else {
			this.format();
			return true;
		}
	}
}

function setNumberFullErrorText(part1, part2, part3) {
	this.errorText = this.labelText + part1;
	if ((this.maximum) || (this.maximum == 0)) {
		var formattedMax = getFormattedNumber(this.maximum.toString(), this.decimals,
								this.comma, this.decimalPoint, "", true)
	}
	if ((this.minimum) || (this.minimum == 0)) {
		var formattedMin = getFormattedNumber(this.minimum.toString(), this.decimals,
									this.comma, this.decimalPoint, "", true);
		this.errorText += part2 + formattedMin;
		if ((this.maximum) || (this.maximum == 0)) {
			this.errorText += " and"
		}
	}
	if ((this.maximum) || (this.maximum == 0)) {
		this.errorText += part3 + formattedMax;
	}
	this.errorText += " with no more than " + this.decimals + " decimal places."
}

function testNumberRange(theNumber) {
	// Return -1 if too small, 0 if OK, 1 if too large.
	var retVal = 0;
	if (((this.minimum) || (this.minimum ==0)) && (theNumber < this.minimum)) {
		// Too small
		retVal = -1;
	}
	if (((this.maximum) || (this.maximum == 0)) && (theNumber > this.maximum)) {
		// Too large
		retVal = 1;
	}
	return retVal;
}

//----------------------------
// Formatter Methods
//----------------------------
//
function nullMethod() {
	// do nothing
}

function formatEmail() {
	this.obj.value = stripCharsInBag(this.obj.value, " ");
}

function formatPhoneNumber() {
	phoneString = stripCharsInBag(this.obj.value, phoneNumberDelimiters);
	if (phoneString == "") {
		this.obj.value = phoneString;
		return;
	}
	if (this.USOK) {
		if(phoneString.length == digitsInUSPhoneNumber) {
			this.obj.value = reformatUSPhone(phoneString);
		} else {
			this.obj.value = reformatUSShortPhone(phoneString);
		}
	}
}

function unformatPhoneNumber() {
	this.obj.value = stripCharsInBag(this.obj.value, phoneNumberDelimiters);
}

function formatCleanText() {
	this.obj.value = trim(this.obj.value);
}

function formatSSN() {
	tempString = stripCharsInBag(this.obj.value, SSNDelimiters);
	if (tempString == "") {
		this.obj.value = tempString;
		return;
	}
	this.obj.value = reformatSSN(tempString);
}

function unformatSSN() {
	this.obj.value = stripCharsInBag(this.obj.value, SSNDelimiters);
}

function formatTaxId() {
	tempString = stripCharsInBag(this.obj.value, " " + TaxIdDelimiters);
	if (tempString == "") {
		this.obj.value = tempString;
		return;
	}
	this.obj.value = reformatTaxId(tempString);
}

function unformatTaxId() {
	this.obj.value = stripCharsInBag(this.obj.value, " " + TaxIdDelimiters);
}

function formatDUNS() {
	tempString = stripCharsInBag(this.obj.value, " " + DUNSDelimiters);
	if (tempString == "") {
		this.obj.value = tempString;
		return;
	}
	this.obj.value = reformatDUNS(tempString);
}

function unformatDUNS() {
	this.obj.value = stripCharsInBag(this.obj.value, " " + DUNSDelimiters);
}

function formatUSZipCode() {
	tempString = stripCharsInBag(this.obj.value, " " + ZIPCodeDelimiters);
	if (tempString == "") {
		this.obj.value = tempString;
		return;
	}
	this.obj.value = reformatZIPCode(tempString);
}

function unformatUSZipCode() {
	this.obj.value = stripCharsInBag(this.obj.value, ZIPCodeDelimiters);
}

function formatStateCode() {
	this.obj.value = trim(this.obj.value.toUpperCase());
}

function formatDate() {
	this.obj.value = trim(this.obj.value);
}

function formatNumber() {
	// Head west if empty...
	if (trim(this.obj.value) == "")
	{
		return;
	}

	// Strip out spaces, parens, etc., then assume the number of decimals
	// is in limit already. For positive integers, simply add the dollarSign
	// to the front, if there is one. For negative integers, the negative
	// sign must come before the dollarSign. For decimals, find the pt and
	// concat correct # of zeros.
	var tempString = getFormattedNumber(this.obj.value, this.decimals,
									this.comma, this.decimalPoint,
									this.dollarSign, this.formatWithCommas);

	this.obj.value = tempString;

	// Handle changing text color to red or black, if redNegative is true.
	var theColor = this.origColor;	// Default to positive color
	if (this.redNegative) {
		if (this.obj.value.indexOf("-") > -1) {
			// Value is negative. Make it red.
			theColor = "red"
		}
		if (document.layers) {
			// Netscape
			this.obj.color = theColor;
		} else {
			// IE
			this.obj.style.color = theColor;
		}
	}
}

function getFormattedNumber(theNumber, theDecimals,
									theComma, theDecimalPoint,
									theDollarSign, formatWithCommas) {
	var ptIdx;
	var tempString;
	var myBag;
	var numPrefix;
	var intPortion;
	var part1;
	var part2;
	var theResult;
	if (theDecimals > 0) {
		// Decimal number
		tempString = stripCharsInBag(theNumber, invalidDecChars + theComma);
		// Break the string into before and after decimal points
		ptIdx = tempString.indexOf(theDecimalPoint);
		if (ptIdx > -1) {
			// There's a decimal point
			part1 = tempString.slice(0, ptIdx);
			part2 = tempString.slice(ptIdx + 1);
		} else {
			// no decimal point
			part1 = tempString;
			part2 = "";
		}
		if (tempString.charAt(0) == '-') {
			// Negative
			numPrefix = "-" + theDollarSign;
			// Remove negative sign:
			part1 = part1.slice(1);
		} else {
			// Positive
			numPrefix = theDollarSign;
		}
		// Build integer portion with comma value if commas are turned on...
		if (formatWithCommas) {
			intPortion = reformatIntWithCommas(part1, theComma);
		} else {
			intPortion = part1;
		}
		theResult = numPrefix + intPortion + theDecimalPoint + 
							reformat(part2 + "00000000000000000000", "", theDecimals);
	} else {
		// Integer
		// In case value has a decimal point, get rid of it and decimals...
		myBag = invalidIntChars + theComma;
		tempString = stripCharsInBag(theNumber, myBag);
		ptIdx = tempString.indexOf(theDecimalPoint)
		if (ptIdx > -1) {
			// Somebody passed in an integer with a decimal point (so we assume)
			// Truncate it.
			tempString = tempString.slice(0, ptIdx)
		}
		if (tempString == "")  {
			// Don't use a Dollar Sign for an empty value.
			theDollarSign = ""
		}
		if (tempString.charAt(0) == '-') {
			// Negative
			numPrefix = "-" + theDollarSign;
			tempString = tempString.slice(1);
		} else {
			// Positive
			numPrefix = theDollarSign;
		}
		if (formatWithCommas) {
			intPortion = reformatIntWithCommas(tempString, theComma);
		} else {
			intPortion = tempString;
		}
		theResult = numPrefix + intPortion;
	}
	return theResult;
}

function unformatNumber() {
	// Just remove the money indicator, being careful to note that negative
	// numbers have the negative sign first...
	if (this.decimals > 0) {
		myBag = invalidDecChars + this.comma;
	} else {
		myBag = invalidIntChars + this.comma + this.decimalPoint;
	}
	this.obj.value = stripCharsInBag(this.obj.value, myBag);
}

function trim(myString)
{
	return(myString.replace(/^\s+|\s+$/g, ""));
}
