/***********************************************************
 * formChecker.js		written 12/01/2000 Dan Phifer
 *
 *						revised 08/01/2005 DF Denes
 *						• add "'" to valid email characters
 *
 *						revised 08/16/2002 DF Denes
 *
 *						revised 03/09/2002 DF Denes
 *						• added date/time key processing
 *
 *						revised 03/06/2002 DF Denes
 *						• changed rule storage
 *						• added interactive checking
 *
 *						revised 11/27/2001 DF Denes
 *						• added date/time and time edits
 *						• revised date edit
 *						• added date macros
 *                      • revised rule set/get functions
 *						• added arrays of rules, functions
 ***********************************************************/

function setCreditCard(	objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsCreditCard, 	name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setCustom(		objElement, strVr, name, strErrorMsg, objMsg, objCondition, strConditionValue)	{ setOneRule(objElement, strVr, 			name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setDate(		objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsDate,			name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setDateTime(	objElement,	name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsDateTime,		name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setDecimal(	objElement, name, DecPos, strErrorMsg, objMsg, objCondition, strConditionValue)	{ setOneRule(objElement, vrIsDecimal, 		name, strErrorMsg, objMsg, DecPos, objCondition, strConditionValue);}
function setEMail(		objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsEmail, 		name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setEmail(		objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsEmail, 		name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setFax(		objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsPhoneNumber, 	name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setFaxNumber(	objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsPhoneNumber, 	name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setNumber(		objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsNumber, 		name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setPhone(		objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsPhoneNumber, 	name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setPhoneNumber(objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsPhoneNumber, 	name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setRequired(	objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsRequired, 		name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setSSN(		objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsSSN, 			name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setTime(		objElement,	name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsTime,			name, strErrorMsg, objMsg, objCondition, strConditionValue);}
function setZipCode(	objElement, name, strErrorMsg, objMsg, objCondition, strConditionValue)			{ setOneRule(objElement, vrIsZipCode, 		name, strErrorMsg, objMsg, objCondition, strConditionValue);}

function setDateKeyProcess(objElement)	{ setKeyProcess(objElement, vrIsDate);}


function gimmeSeven()	{alert(7);}		// debugging function for minimal processing


/***************************************************************************************
* Set a custom error function.  receives the functions name, including parens.
* the function will be sent one parameter which will be an array.  The array
* contains the fields that were found to be invalid.  For example, if your custom
* function is called "customFunc" the following code is needed:
*		setErrorFunction("customFunc()")
*		 ...
*		function customFunc(fields)
*		{
*			...
*		}
***************************************************************************************/
function setErrorFunction(strErrorFunc)	{ m_ErrorFunction = strErrorFunc;	}

/***************************************************************************************
* set the allowed credit card types
***************************************************************************************/
function setCardTypes(nTypes)			{ m_nCardTypes	  = nTypes; 		}

/***************************************************************************************
* The predefined validation rules
***************************************************************************************/
var vrNbr = 0;
var	vrIsRequired		= Math.pow(2, vrNbr++);
var	vrHasNoNumbers		= Math.pow(2, vrNbr++);
var	vrHasNoSpaces		= Math.pow(2, vrNbr++);
var	vrIsNumber			= Math.pow(2, vrNbr++);
var	vrIsDecimal			= Math.pow(2, vrNbr++);
var vrIsEmail			= Math.pow(2, vrNbr++);
var	vrIsPhoneNumber		= Math.pow(2, vrNbr++);
var	vrIsCreditCard		= Math.pow(2, vrNbr++);
var	vrIsZipCode			= Math.pow(2, vrNbr++);
var	vrIsSSN				= Math.pow(2, vrNbr++);
var	vrIsDate			= Math.pow(2, vrNbr++);
var	vrIsDateTime		= Math.pow(2, vrNbr++);
var	vrIsTime			= Math.pow(2, vrNbr++);

var vrRules				= new Array(['isComplete()',	'is required'],
									['hasNoNumbers()',	'cannot contain numbers'],
									['hasNoSpaces()',	'cannot contain spaces'],
									['isNumber()',		'must be numeric'],
									['isDecimal()',		'must be numeric with no more than ^ decimals'],
									['isEmail()',		'is not a valid e-mail address'],
									['isPhoneNumber()',	'is not a valid phone number'],
									['isCreditCard()',	'is not a valid credit card number'],
									['isZipCode()',		'is not a valid zip code'],
									['isSSN()',			'is not a valid social security number'],
									['isDate()',		'is not a valid date'],
									['isDateTime()',	'is not a valid date/time'],
									['isTime()',		'is not a valid time']);

/**************************************************************************
* This function calls the function setOneValidation Rule for each rule
* that was specified in the parameter "rule"  For example, the field f
* can be made a required field and a phone number by the following code:
* 	setValidationRule(f, vrIsRequired | vrIsPhoneNumber)
**************************************************************************/
function setRule(objElement, rule, name, strErrorMsg, objMsg, DecPos, objCondition, strConditionValue)
{
	var i = 0
	var r

	// default to a required field
	if (name == null)			name		= "";
	if (rule == null)			rule		= vrIsRequired;
	if (strErrorMsg == null)	strErrorMsg = "";

	if (strIsNumber(rule))
	{
		for (i=0; i < vrRules.length; i++)
		{
			r = Math.pow(2, i);
			if ((r & rule) > 0)
			{
				setOneRule(objElement, r, name, strErrorMsg, objMsg, DecPos, objCondition, strConditionValue);
			}
		}
	}
	else
		setOneRule(objElement, rule, name, strErrorMsg, objMsg, DecPos, objCondition, strConditionValue);
}

/*******************************************************************************
* Sets the validation rule for the given element. An element can have any number
* of validation rules.  Ex: You may want to ensure that a field is a phone number
* if and only if it is filled out -- if it is left blank you don't care.  Or you
* may want to ensure that the field is both filled out AND a phone number. In the
* first case you need only set the vrIsPhoneNumber validation rule.  In the second
* you should set the vrIsPhoneNumber validation rule and the vrIsRequired rule.
*
*				For the following parameters, data can be specified as follows:
*
* HTML Element	- Reference to the HTML element (unquoted)
*				- Element Name (quoted)
*				- Element ID (quoted)
*
* String		- quoted string
*				- Null (no value)
*				- not provided (use default value)
*
*
* Parameters for setOneRule are:
*
* objElement	HTML element
*
* name			(Optional) a string to be used as the field's display name
*				if there is an error. If blank, the field's name is used.
*
* rule 			(Optional) one of the validation rules.  The available rules are:
*
*				vrIsRequired		(default) no restrications other than
*									the field is completed
* 				vrIsPhoneNumber		field must be a phone number
*				vrIsEmail 			field must be an e-mail address
*               vrIsFaxNumber	  	field must be a fax number (phone number)
*				vrHasNoSpaces	  	field must cantain a continuous string of
*									characters, none of which are spaces
*               vrHasNoNumbers	 	field CANNOT contain charaters 0 through 9
*				vrIsNumber			field contains only numbers
*				vrIsDecimal			field contains only numbers with no more
*									than requested decimal positions
*				vrIsCreditCard	 	must be a valid credit card number
*				vrIsZipCode			must be a valid zip code
*				vrIsSSN				must be a valid social security number
*				vrIsDate			must be a valid date
*				vrIsDateTime		must be a valid date and/or time
*				vrIsTime			must be a valid time
*
*				OR
*
* 				String: 		Any statement that can be evaluated using the eval()
* 				  				command. Can be a function or an expression.
*
* ErrorMsg	 	(Optional) String containing a custom error message. If blank,
*				the default message will be used.
*
* DecPos 		(Optional) number of decimal positions for isDecimal. Ignored
*				for all other rules. If blank, zero is assumed.
*
* objMsg 		(Optional) HTML element. If provided, this element will be used
*				to display interactive error message(s) on this field. Interactive
*				validation occurs when the 'onBlur' event is fired.
*
* Conditional Rule Validation (Optional)
*
*				The following two parameters, if both provided, allow for this rule
*				to be validated only if the condition is met. For example, if the
*				the objElement given is a communication number, then objCondition
*				could be the type. Then, if strCondition is "PHONE" or "=='PHONE'",
*				objElement will only be validated by this rule if objCondition
*				has the value of phone.
*
*				The same field can have as many conditional validation rules as you
*				want, all having different conditions to be met.
*
* objCondition	(Optional) HTML element. If provided, this element's value will be
*				used to determine if a the objElement should be validated by this rule.
*
* strCondition	(Optional) String. If provided, this is the value, or condition to
*				check against objCondition for conditional validation.
*
**************************************************************************************/
function setOneRule(objElement, rule, name, optionalParm1, optionalParm2, optionalParm3, optionalParm4, optionalParm5)
{
	var strErrorMsg			= null;
	var objMsg				= null;
	var DecPos				= null;
	var objCondition		= null;
	var strConditionValue	= null;
	var parms				= new Array();

	objElement				= getObjectElement(objElement)
	if (objElement == null)
		return false;

	if (typeof(optionalParm1) != 'undefined')
		parms[parms.length]	= optionalParm1;

	if (typeof(optionalParm2) != 'undefined')
		parms[parms.length]	= optionalParm2;

	if (typeof(optionalParm3) != 'undefined')
		parms[parms.length]	= optionalParm3;

	if (typeof(optionalParm4) != 'undefined')
		parms[parms.length]	= optionalParm4;

	if (typeof(optionalParm5) != 'undefined')
		parms[parms.length]	= optionalParm5;

	// load parameter types into temporary array
	var vType								= new Array(parms.length);
	var vObject								= 0;
	var vString								= 0;
	for (var i=0; i < parms.length; i++)
	{
		if (getObjectElement(parms[i]) != null)
		{
			vType[i]						= 'object';
			vObject++;
		}
		else if (strIsNumber(parms[i]))
		{
			DecPos							= parms[i];
			vType[i]						= '';			// invalidate type
		}
		else if (parms[i] != null)
		{
			vType[i]						= 'string';
			vString++;
		}
		else if (parms[i] == null)
		{
			if (vObject == 0)
			{
				vType[i]					= 'object';
				vObject++;									// count a null as an object for error message
			}
		}
	}

	if (vObject >= 1)
	{
		for (var i=0; i < vType.length; i++)
		{
			if (vType[i] == 'object')
			{
				if (parms[i] != null)
					objMsg					= getObjectElement(parms[i]);
				vType[i]					= '';			// invalidate type
				break;
			}
		}
	}
	if (vObject == 2 && vString >= 1)
	{
		for (var i=0; i < vType.length; i++)
		{
			if (vType[i] == 'object')
			{
				if (i < (vType.length -1))
				{
					if (vType[i+1] == 'string')
					{

						objCondition		= getObjectElement(parms[i]);
						strConditionValue	= parms[i+1];
						vType[i]			= '';			// invalidate type
						vType[i+1]			= '';			// invalidate type
					}
				}
				break;
			}
		}
	}

	for (var i=0; i < vType.length; i++)
	{
		if (vType[i] == 'string')
		{
			strErrorMsg						= parms[i];
			break;
		}
	}

	var thisField							= FieldItem(objElement, name);
	var thisRule							= new fieldRule(thisField, rule, strErrorMsg, DecPos, objMsg, objCondition, strConditionValue);
	thisField.Rules[thisField.Rules.length]	= thisRule;

	// set up interactive check using onBlur for the first rule
	// for a field that is interactive
	if (thisRule.Interactive && !thisRule.owner.Interactive)
	{
		thisRule.owner.Interactive	= true;

		if (isCapableBrowser(false))
		{
			strFunction						= '';
			strFunction					   += 'objElement.onblur';
			strFunction					   += ' = ';
			strFunction					   += "function() {validateThis('" + thisRule.owner.ID + "');}";
			eval(strFunction);
		}
	}
}

/*********************************************************************************
* Set the realtime key processing
*********************************************************************************/
function setKeyProcess(objElement, rule)
{
	if (isCapableBrowser(true))
	{
		objElement	= getObjectElement(objElement);
		if (objElement)
		{
			if (rule == vrIsDate)
				objElement.onkeydown	= keyProcessDate;
// future
//			else if (rule == vrIsTime)
//				objElement.onkeydown	= keyProcessTime;
		}
	}
}

/*********************************************************************************
* Validate all rules
*********************************************************************************/
function Validate()
{
	var strError;
	var field, rule;
	var f, r;
	var vErrorFields = new Array();

	strError = '';

	for (f=0; f< m_fieldItems.length; f++)
	{
		var field		= m_fieldItems[f];

		for (r=0; r < field.Rules.length; r++)
		{
			var rule	= field.Rules[r];
			if (!validRule(rule))
			{
				strError   += '  ' + strDot + ' ';
				strError   += getErrorMessage(rule) + '\n';
				vErrorFields[vErrorFields.length] = field.Element;
			}
		}
	}

	if (strError != "")
	{
		if (m_ErrorFunction == "")
		{
			strError = "Invalid Data ... \n" + strError;
			alert(strError);
		}
		else
			doMacro(m_ErrorFunction, vErrorFields);
		return false;
	}
	return true;
}


/*********************************************************************************
**********************************************************************************
******************************* Internal Functions *******************************
**********************************************************************************
*********************************************************************************/


/*********************************************************************************
* Validates an individual field when the "onBlur" event fires
*********************************************************************************/
function validateThis(vElement)
{
	var strError						= '';
	var thisField, thisRule;
	var r;

	thisField							= FieldItem(vElement);		// get the thisField item
	if (thisField != null)
	{
		for (r=0; r < thisField.Rules.length; r++)
		{
			thisRule					= thisField.Rules[r];
			if (!validRule(thisRule))
			{
				if (strError.length > 0)
					strError			+= '<br>';
				strError				+= strDot + ' ';
				strError		 		+= getErrorMessage(thisRule, false);
			}
		}
		if (thisRule.Message != null)
		{
			if (strError.length == 0)
				strError				= '&nbsp;'
			thisRule.Message.innerHTML	= strError;
		}
	}
}

function getErrorMessage(rule, bIncludeFieldName)
{
	if (bIncludeFieldName == null)	{bIncludeFieldName = true;}

	var	strErr				= rule.ErrorMessage;
	var strFieldName		= rule.owner.Name;
	var r					= rule.Rule;
	var decpos				= rule.DecPos;

	if (strErr == '')
	{
		if (typeof(r) == 'number')
		{
			for (var i=0; i < vrRules.length; i++)
			{
				if ((Math.pow(2, i) & r) > 0)
				{
					strErr = vrRules[i][1];
					break;
				}
			}
		}
		if (strErr == '')
			strErr 			= 'is not valid.';

		if (strErr.indexOf('^') > -1 && decpos != null)
			strErr			= strErr.replace('^', decpos);
		if (bIncludeFieldName)
			strErr			= strFieldName + ' ' + strErr;
		else
		{
			if (strErr.substr(0, 3).toLowerCase() == 'is ')
				strErr		= strErr.substr(3);
			strErr			= strErr.substr(0, 1).toUpperCase() + strErr.substr(1);
		}
	}
	return strErr;
}

function getRuleName(r)
{
	if (typeof(r) == 'number')
	{
		for (var i=0; i < vrRules.length; i++)
		{
			if ((Math.pow(2, i) & r) > 0)
				return vrRules[i][0];
		}
	}
	return "";
}

function isComplete(objElement)
{
	var t

	t 	= objElement.type
	if (!isValidType(t))
	{
		t	= objElement[0].type
		if (!isValidType(t))
		{
			alert(objElement.name & " could not be validated: unknown type")
			return false;
		}
	}
	if (isTypeText(t))
	{
		return Len(Trim(objElement.value)) > 0;
	}
	else if (t == 'select-one' || t == 'select-multiple')
	{
		if (objElement.selectedIndex < 0)
			return false;
		for (var i=0; i < objElement.options.length; i++)
		{
			if (objElement.options[i].selected && objElement.options[i].text.length > 0)
				return true;
		}
		return false;
	}
	else if (t == 'radio' || t=='checkbox')
	{
		for (i=0; i < objElement.length; i++)
		{
			if (objElement[i].checked) return true;
		}
		if (isNaN(objElement.length)) return objElement.checked
	}
	return false;
}

function isValidType(strType)
{
	return	(strType == "text")				||
			(strType == "password")			||
			(strType == "hidden")			||
			(strType == "select-one")		||
			(strType == "select-multiple")	||
			(strType == "radio")			||
			(strType == "checkbox")			||
			(strType == "textarea");
}

function isTypeText(t)
{
	return ((t == "text") || (t == "textarea") || (t == "password") || (t == "hidden"));
}

function validRule(rule)
{
	var vr				= rule.Rule;
	var DecPos			= rule.DecPos;
	var objElement		= rule.owner.Element;

	var bValidate		= (rule.Condition == null);
	if (!bValidate)
	{
		if (rule.Condition.substr(1,1) == '*')		// regular expression?
		{
			var re		= new RegExp(rule.ConditionValue, 'i');
			bValidate	= re.test(rule.ConditionObject.value);
			if (rule.Condition.substr(0,1) == '!')	// negate?
				bValidate	= (!bValidate);
		}
		else										// standard comparison
		{
			if (rule.ConditionValue == 'checked')
			{
				bValidate		= (rule.ConditionObject.checked);
				if (rule.Condition.substr(0,1) == '!')	// negate?
					bValidate	= (!bValidate);
			}
			else
				bValidate		= eval('rule.ConditionObject.value.toLowerCase()' + rule.Condition + '"' + rule.ConditionValue + '"');
		}
	}

	if (bValidate)
	{
		if (vr != '')
		{
			if (isMacro(vr))
				return doMacro(getRuleName(vr), objElement, DecPos);
			else
				return eval(vr);
		}
	}
	return true;
}

function isSSN(objElement)
{
	var strTemplate	= "";
	var i;
	var c;

	if (!isTypeText(objElement.type)) 	{ return false; }
	tmpStr	= Trim(objElement.value);

	for (i=0; i < tmpStr.length; i++)
	{
		c	= tmpStr.charAt(i);
		if (strIsNumber(c))
			strTemplate += "x";
		else
			strTemplate += c;
	}
	return IsSSTemplate(strTemplate);

}

function isPhoneNumber(objElement)
{
	var strPhone			= '';

	if (!isTypeText(objElement.type)) 	{ return false; }
	if (objElement.value == '')			{ return true;  }

	strPhone				= formatPhone(objElement.value);

	// reload "purified" phone number
	if (strPhone != null)
		objElement.value	= strPhone;

	return (strPhone != null);

}
function formatPhone(strInput)
{
	var strPhone		= '';
	var strValue			= removeNonNumerics(strInput);

	// foreign phone?
	if (Mid(strValue, 1, 3) == '011')
		strPhone		= strInput;

	else if (Mid(strValue, 1, 1) != '0')
	{
		// local?
		if (strValue.length == 7)
		{
			strPhone	   += Mid(strValue, 1, 3);
			strPhone	   += '-';
			strPhone	   += Mid(strValue, 4, 4);
		}

		// area code?
		else if (strValue.length > 9 && strValue.length < 16)
		{
			strPhone	   += '(';
			strPhone	   += Mid(strValue, 1, 3);
			strPhone	   += ') ';
			strPhone	   += Mid(strValue, 4, 3);
			strPhone	   += '-';
			strPhone	   += Mid(strValue, 7, 4);

			// extension?
			if (strValue.length > 10)
			{
				strPhone   += ' x';
				strPhone   += Mid(strValue, 11, strValue.length - 10);
			}
		}
	}

	// who knows what -- unrecognized format
	if (strPhone.length == 0)
		strPhone 			= null;

	return strPhone;
}


function IsEmailTemplate(strTemplate)
{
	return isMember(templateEmail, strTemplate);
}

function IsSSTemplate(strTemplate)
{
	return isMember(templateSSNumber, strTemplate);
}

function IsZipCodeTemplate(strTemplate)
{
	return isMember(templateZipCodes, strTemplate);
}

/****************************************************************
* is strTemplate a member of vTemplates
****************************************************************/
function isMember(vTemplates, strTemplate)
{
	for (var i=0; i < vTemplates.length; i++)
		if (strTemplate == vTemplates[i]) return true;

	return false;
}

function IsParen(s)	{	return (s == ")") || (s == "(");	}

function isEmail(objElement)
{
	var c;
	var i;
	var placeHolder = "x";
	var strTemplate = "";

	if (!isTypeText(objElement.type)) 	{ return false; }

	str = Trim(objElement.value);
	for (var i=0; i < str.length; i++)
	{
		c = str.charAt(i);
		if (IsAlphaNumeric(c))
		{
			strTemplate += placeHolder;
			placeHolder = "";
		}
		else if (c == '@' || c == '.')
		{
			strTemplate += c;
			placeHolder = "x";
		}
		else
			return false;
	}

	return IsEmailTemplate(strTemplate);
}

function isCreditCard(objElement)
{
	var ct;
	if (!isTypeText(objElement.type)) 	{ return false; }

	strCard = Trim(objElement.value);
	if ((getCardType(strCard) & m_nCardTypes) > 0)
	{
		return isValidCardNumber(strCard);
	}
	return false;
}
function getCardType(strNumber)
{
	var nLength	= Len(strNumber);
	if (nLength >= 13 && strIsNumber(strNumber))
	{
		if (Left(strNumber, 2) > 50 && Left(strNumber, 2) < 56)
		{
		    if (nLength == 16)
		    	return vrMasterCard;
		}

		if (Left(strNumber, 1) == 4)
		{
		   if (nLength == 13 || nLength == 16)
		   	return vrVisa;
		}

		if (Left(strNumber, 2) == 34 || Left(strNumber, 2) == 37)
		{
		    if (nLength == 15)
		    	return vrAmex;
		}

		if (Left(strNumber, 4) == 6011)
		{
		    if (nLength == 16)
			return vrDiscover;
		}
	}
	return 0;
}

/****************************************************************
* Runs the "Mod 10" algorithm on the credit card number to ensure
* it is a (potentially) valid number.
****************************************************************/
function isValidCardNumber(strNumber)
{
	var i
	var dblCount	= 1;
	var nSum	= 0;
	for (i = Len(strNumber)-1; i>=0; i--)
	{
		c = strNumber.charAt(i);
		if (dblCount % 2 == 0) c *= 2;
		nSum = nSum + (getDigitSum(c)-0);
		dblCount++;
	}
	return (nSum % 10 == 0);
}

/****************************************************************
* get the check digit for the requested number.
****************************************************************/
function getDigitSum(strNumber)
{
	var result = 0;
	var i;
	strNumber = strNumber + ""
	for (i=0; i < Len(strNumber); i++)
	{
		result = result + (strNumber.charAt(i)-0)
	}
	return result;
}

function isDate(objElement)
{
	if (!isTypeText(objElement.type))	{return false;}

	var strInput			= objElement.value;
	var vDate				= editDate(strInput);

	if (vDate == false)
		return false;

//	if (typeof(vDate) == 'string')
	{
		objElement.value	= vDate;
		return true;
	}
}

function isDateTime(objElement)
{
	var strInput, strDate, strTime, i, j;
	var vDate, vTime;
	var strOutput, bMacro;

	if (!isTypeText(objElement.type))	{return false;}

	// separate string into date and time strings (delimited with a space)
	strInput				= objElement.value;
	i						= strInput.indexOf(" ");
	if (i == -1)			// no space?
	{
		// try both edits
		vDate				= editDate(strInput);
		vTime				= editTime(strInput);

		// if both succeed, check for macro -- if not a macro, erase the time
		if ((typeof(vDate) == 'string') && (typeof(vTime) == 'string'))
		{
			bMacro			= false;
			for (j=0; j < dateMacroNames.length; j++)
			{
				if (strInput.indexOf(dateMacroNames[j]) != -1)
				{
					bMacro	= true;
					break;
				}
			}
			if (!bMacro)
				vTime		= "";
		}

		// if only date succeeds, erase the time
		if ((typeof(vDate) == 'string') && (typeof(vTime) != 'string'))
			vTime			= "";

		// if only time succeeds, erase the date
		if ((typeof(vDate) != 'string') && (typeof(vTime) == 'string'))
			vDate			= "";
	}
	else
	{
		strDate				= Left(strInput, i);
		strTime				= Right(strInput, Len(strInput)-(i+1));
		vDate				= editDate(strDate);
		vTime				= editTime(strTime);
	}

	if ((typeof(vDate) == 'string') && (typeof(vTime) == 'string'))
	{
		strOutput			= Trim(vDate);
		if (strOutput.length > 0)
			strOutput	   += ' ';
		strOutput		   += vTime;
		strOutput			= Trim(strOutput);
		objElement.value	= strOutput;
		return true;
	}
	else
		return false;
}

function isTime(objElement)
{
	if (!isTypeText(objElement.type))	{return false;}

	var strInput			= objElement.value;
	var vTime				= editTime(strInput);

	if (typeof(vTime) == 'string')
	{
		objElement.value	= vTime;
		return true;
	}
	else
		return false;
}

function editDate(strInput)
{
	var vTest, vDate;
	var strDate, strTemplate, c, idx, i
	var aDATE	= new Array("", "", "")
	var vNow	= new Date;

	strDate		= Trim(strInput);
	if (strDate == "")
		return strDate;						// valid (empty) date

	strDate		= strDate.toLowerCase();

	// if the date is a 'macro', return the value
	for (i=0; i < dateMacros.length; i++)
	{
		if (strDate.indexOf(dateMacroNames[i]) != -1)
		{
			vDate	 = eval(dateMacros[i]);
			vTest	 = "";
			vTest	+= vDate.getMonth() + 1;
			vTest	+= "/";
			vTest	+= vDate.getDate();
			vTest	+= "/";
			vTest	+= vDate.getFullYear();
			return vTest;
		}
	}

	// read through the string and build a template
	idx			= 0
	strTemplate	= ""
	for (i=0; i < strDate.length; i++)
	{
		c = strDate.charAt(i)
		if (isMember(dateDelimiters, c))
		{
			strTemplate += "d";
			idx++;
		}
		else if (strIsNumber(c))
		{
			vTest = "/" + strTemplate;
			if (vTest.substr(vTest.length -1) != "x")
				strTemplate += "x";
			aDATE[idx]	= (aDATE[idx] + "") + (c + "")
		}
		else
			return false
	}

	// edit the template
	if (!isMember(templateDate, strTemplate))	{return false;}

	// if this is a 1-element date, it should be used as the day
	// with the month and year defaulting to now.
	if (aDATE[1] == "")
	{
		aDATE[1] = aDATE[0];
		aDATE[0] = vNow.getMonth()+1;
		aDATE[2] = vNow.getFullYear();
	}
	// if this is a 2-element date, it should be used as the month and day
	// with the year defaulting to now.
	else if (aDATE[2] == "")
	{
		aDATE[2] = vNow.getFullYear();
	}

	// edit the actual date
	if (!isDate_3(aDATE[0], aDATE[1], aDATE[2]))	{return false;}

	// if we made it to here, this is a valid date
	// so return the "improved" date string
	vTest	 = "";
	vTest	+= aDATE[0];
	vTest	+= "/";
	vTest	+= aDATE[1];
	vTest	+= "/";
	vTest	+= y2k(aDATE[2]);
	return vTest;
}

/****************************************************************************
* Edit the input string to see whether it is a time.
****************************************************************************/
function keyProcessDate()
{
	var vDate, strDate;

	var vElement	= window.event.srcElement;
	var vKey		= window.event.keyCode;
	var strKey		= String.fromCharCode(vKey);
	var strKey		= strKey.toLowerCase();
	var vNumber		= 0;

	if (vKey >= 32)										// ensure this isn't a control character
	{
		if (strKey == 'n' || strKey == 't')				// macros (now, today)?
		{
			vElement.value	= editDate(strKey);				// run macro
			formCheckerFireDataChanged();					// fire data changed
			return false;									// and cancel the keydown
		}
		else if (vKey == 107 || vKey == 187 || vKey == 109 || vKey == 189)		// + or - (next or previous)
		{
			if (vKey == 107 || vKey == 187)
				vNumber				= 1;
			else
				vNumber				= -1;

			vDate					= editDate(vElement.value);
			if (vDate != false)
			{
				vDate				= new Date(vDate);
				vDate				= new Date(vDate.getFullYear(), vDate.getMonth(), (vDate.getDate() + vNumber));
				strDate				= "";
				strDate			   += (vDate.getMonth() + 1);
				strDate			   += "/";
				strDate			   += vDate.getDate();
				strDate			   += "/";
				strDate			   += vDate.getFullYear();
				vElement.value		= strDate
				formCheckerFireDataChanged();				// fire data changed
				return false;								// cancel the keydown
			}
		}
	}
	return true;
}

function formCheckerFireDataChanged()
{
	if (typeof(fireDataChange)!='undefined')
		fireDataChange();
}


function editTime(strInput)
{
	var vTest, vTime;
	var strTime, strTemplate, c, idx, i, strMeridian
	var aTIME	= new Array("", "", "")

	strTime		= Trim(strInput);
	if (strTime == "")
		return strTime;						// valid (empty) time

	strTime		= strTime.toLowerCase();

	// if the date is a 'macro', return the value
	for (i=0; i < dateMacros.length; i++)
	{
		if (strTime.indexOf(dateMacroNames[i]) != -1)
		{
			vTime	 = eval(dateMacros[i]);
			return getTimeString(vTime);
		}
	}

	// read through the string and build a template
	idx			= 0;
	strTemplate	= "";
	strMeridian	= "";
	for (i=0; i < strTime.length; i++)
	{
		c = strTime.charAt(i)
		if (isMember(timeDelimiters, c))
		{
			strTemplate += "d";
			idx++;
		}
		else if (strIsNumber(c))
		{
			vTest = "/" + strTemplate;
			if (vTest.substr(vTest.length -1) != "x")
				strTemplate += "x";
			aTIME[idx]	= (aTIME[idx] + "") + (c + "")
		}
		else if (isMember(timeMeridians, c))
		{
			if (strMeridian == '')
				strMeridian = c;
			vTest = "/" + strTemplate;
			if (vTest.substr(vTest.length -1) != "a")
				strTemplate += "a";
		}
		else
			return false
	}

	// edit the template
	if (!isMember(templateTime, strTemplate))	{return false;}

	// if this is a 1-element time, it should be used as the hour
	// with the minute and second set to zero
	if (aTIME[1] == "")
	{
		aTIME[1] = 0;
		aTIME[2] = 0;
	}
	// if this is a 2-element date, it should be used as the hour and minute
	// with the seconds set to zero;
	else if (aTIME[2] == "")
	{
		aTIME[2] = 0;
	}

	// if there is a meridian indicator, the hours cannot be past 12
	if ((strMeridian != "") && (parseInt(aTIME[0]) > 12))
		return false;

	// if there is a meridian indicator, adjust the hours
	if ((strMeridian == "p") && (parseInt(aTIME[0]) < 12))
		aTIME[0] = (parseInt(aTIME[0]) + 12);
	if (parseInt(aTIME[0]) == 24)
		aTIME[0] = 0;

	// edit the actual time
	vTime = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate(), aTIME[0], aTIME[1], aTIME[2]);
	if (aTIME[0] != vTime.getHours() ||
		aTIME[1] != vTime.getMinutes() ||
		aTIME[2] != vTime.getSeconds())
		return false;

	// if we made it to here, this is a valid time
	// so return the "improved" time string
	return getTimeString(vTime);
}

/**************************************************************************
* make sure the date is a valid date
**************************************************************************/
function isDate_3(month, day, year)
{
	var vNow	= new Date();
    if (!month)
		return false;
    if (!year)
		return false;
    if (!day)
		return false;
    if (year >= 100 && year < 1753)
		return false;

    year	= y2k(year);
    month	= month - 1;

	if (year > (vNow.getFullYear()+10))
		return false;


    var test = new Date(year,month,day);
    return	((year == test.getFullYear()) && (month	== test.getMonth())	&& (day	== test.getDate()));
}

function y2k(nYear)
{
	if (nYear < 30)
		nYear = (nYear - 0) + 2000
	else if (nYear >= 30 && nYear < 100)
		nYear = (nYear - 0) + 1900

	return nYear;
}

function getTimeString(vTime)
{
	var strTime, strMeridian, nHour;

	if (!typeof(vTime) == 'object')
		return "";

	strMeridian		= "";
	nHour		 	= vTime.getHours();
	if (nHour == 0)
	{
		nHour		= 12;
		strMeridian = "am";
	}
	else if (nHour < 12)
	{
		strMeridian	= "am";
	}
	else if (nHour == 12)
	{
		strMeridian = "pm";
	}
	else
	{
		strMeridian = "pm";
		nHour	   -= 12;
	}

	strTime			= "";
	strTime		   += nHour;

	strTime		   += ":";
	strTime		   += Right((" 0" + vTime.getMinutes().toString()), 2);

	if (vTime.getSeconds() > 0)
	{
		strTime		   += ":";
		strTime		   += Right((" 0" + vTime.getSeconds().toString()), 2);
	}

	strTime		   += strMeridian;

	if (strTime == "12:00am")
		return "";
	else
		return strTime;
}

function isZipCode(objElement)
{
	var c;
	var i;
	var strTemplate = "";

	if (!isTypeText(objElement.type)) 	{ return false; }

	str = Trim(objElement.value);
	if (str.length == 0)
		return true;

	for (i=0; i < str.length; i++)
	{
		c = str.charAt(i);
		if (c == ' ' || c == '-')
		{
			strTemplate += c;
		}
		else if (IsLetter(c))
		{
			strTemplate += "l";
		}
		else if (!isNaN(c))
		{
			strTemplate += "n";
		}
		else
		{
			return false;
		}
	}
	return IsZipCodeTemplate(strTemplate);
}

function IsAlphaNumeric(c)
{
	return (c >= '0'	&& c <= '9')	||					//> (shut up NoteTab Pro)
		   (c >= 'a'	&& c <= 'z')  	||					//> (shut up NoteTab Pro)
		   (c >= 'A' 	&& c <= 'Z')	||					//> (shut up NoteTab Pro)
		   (c == '_')					||
		   (c == '-')					||
  		   (c == "'");
}

function IsLetter(c)
{
	return (c >= 'a'	&& c <= 'z')  	||					//> (shut up NoteTab Pro)
		   (c >= 'A' 	&& c <= 'Z');						//> (shut up NoteTab Pro)
}

function hasNoSpaces(objElement)
{
	if (!isTypeText(objElement.type)) 	{ return true;  }
	return InStr(1, Trim(objElement.value), " ") == 0;
}

function hasNoNumbers(objElement)
{
	var str

	if (!isTypeText(objElement.type)) 	{ return true; 	}

	str = objElement.value
	if (InStr(1, str, "0")) { return false; }
	if (InStr(1, str, "1")) { return false; }
	if (InStr(1, str, "2")) { return false; }
	if (InStr(1, str, "3")) { return false; }
	if (InStr(1, str, "4")) { return false; }
	if (InStr(1, str, "5")) { return false; }
	if (InStr(1, str, "6")) { return false; }
	if (InStr(1, str, "7")) { return false; }
	if (InStr(1, str, "8"))	{ return false; }
	if (InStr(1, str, "9")) { return false; }

	return true;
}

function isNumber(objElement)
{
	var str
	if (!isTypeText(objElement.type)) 	{ return false; }
	str = removeCommas(Trim(objElement.value))
	return !isNaN(str)
}

function isDecimal(objElement, DecPos)
{
	var str;
	if (!isTypeText(objElement.type)) 	{ return false; }
	str = removeCommas(Trim(objElement.value))
	if (isNaN(str))						{ return false; }
	if (DecPos == null)					{ DecPos = 0;	}

	var i = str.indexOf(".");
	if (i > -1)							// found a decimal point?
	{
		if ((i + DecPos + 1) < str.length)
			return false;
	}
	return true;
}

function removeCommas(strSource)
{
	var strTmp	= ""
	strSource	= strSource + "";
	for (i=0; i < strSource.length; i++)
	{
		if ((strSource.charAt(i) != ",") && (strSource.charAt(i) != "$"))
			strTmp = (strTmp + "") + strSource.charAt(i);
	}
	return strTmp;
}

function removeNonNumerics(strSource)
{
	var strTmp	= ''
	strSource	= strSource + '';
	for (i=0; i < strSource.length; i++)
	{
		if ((strSource.charAt(i) >= '0') && (strSource.charAt(i) <= '9'))					//> (shut up NoteTab Pro)
			strTmp = (strTmp + '') + strSource.charAt(i);
	}
	return strTmp;
}

function strIsNumber(str)
{
	if (str == null)
		return false;
	if (str.length == 0)
		return false;
	for (i=0; i < str.length; i++)
	{
		if (str.charAt(i) < '0' || str.charAt(i) > '9') return false;
	}
	return true;
}

/*********************************************************************************
* call the given function "m" with the parameter "objElement"
*********************************************************************************/
function doMacro(inputMacro, objElement, DecPos)
{
	var evalString, result;
	var p	= InStr(1, inputMacro, "(");
	if (p > 0)
	{
		evalString			= Left(inputMacro, p-1);		// remove parens
		evalString		   += '(objElement';
		if (strIsNumber(DecPos))
			evalString	   += ', ' + DecPos;
		evalString	 	   += ')';
		return				eval(evalString);
	}
	return eval(inputMacro);
}

/*********************************************************************************
* Is the string "s" a predefined function (macro)
*********************************************************************************/
function isMacro(s)
{
	if (typeof(s) == 'number')
	{
		for (i=0; i < vrRules.length; i++)
			if ((Math.pow(2, i) & s) > 0)
				return true;
	}
	return false;
}

/*********************************************************************************
* get the requested field from the fields collection
*********************************************************************************/
function FieldItem(objElement, name)
{
	objElement			= getObjectElement(objElement);
	if (objElement == null)
		return;

	// get field name
	if (name == null)	{name = '';}
	if (name == '')		{name = objElement.name;}
	if (name == '')		{name = objElement.id;}

	// get object name
	var objID			= objElement.name;
	if (objID == '')
		objID	 		= objElement.id;


	for (var i=0; i < m_fieldItems.length; i++)
	{
		if (m_fieldItems[i].ID.toLowerCase() == objID.toLowerCase())
			return m_fieldItems[i];
	}
	var fld								= new fieldItem(objElement, objID, name);
	m_fieldItems[m_fieldItems.length]	= fld;
	return fld;
}

/*********************************************************************************
* Field item
*********************************************************************************/
fieldItem	= function(objElement, objID, name)
{
	this.Element				= objElement;
	this.ID						= objID;
	this.Name					= name;
	this.Interactive			= false;
	this.Rules					= new Array();
}

/*********************************************************************************
* Field rule
*********************************************************************************/
fieldRule	= function(field, rule, errormessage, decpos, objMsg, objCondition, strConditionValue)
{
	// =*, !* are regular expression shortcuts
	var vConditions						= ['==', '!=', '>=', '<=', '>', '<', '=*', '!*'];		//> (shut up NoteTab Pro)
	var vCondition						= null;

	if (rule == null)					{rule			= vrIsRequired;}
	if (errormessage == null)			{errormessage	= '';}
	if (rule != vrIsDecimal)			{DecPos			= null;}

	if (objCondition != null)
	{
		var nQuotes						= 0;
		vCondition						= '==';
		for (var i=0; i < vConditions.length; i++)
		{
			if (strConditionValue.substr(0,vConditions[i].length) == vConditions[i])
			{
				vCondition				= strConditionValue.substr(0,vConditions[i].length);
				strConditionValue		= strConditionValue.substr(vConditions[i].length);		// remove condition
				break;
			}
		}

		while (strConditionValue.substr(0, 1) == ' ')
			strConditionValue			= strConditionValue.substr(1);

		while (strConditionValue.substr(strConditionValue.length-1) == ' ')
			strConditionValue			= strConditionValue.substr(0, strConditionValue.length-1);

		while (strConditionValue.indexOf("'") > -1)
			strConditionValue			= strConditionValue.replace("'", "");

		while (strConditionValue.indexOf('"') > -1)
			strConditionValue			= strConditionValue.replace('"', '');
	}

	this.owner					= field;
	this.Rule					= rule;
	this.ErrorMessage			= errormessage;
	this.DecPos					= decpos;
	this.Message				= objMsg;
	this.Interactive			= (objMsg != null);
	this.ConditionObject		= objCondition;
	this.Condition				= vCondition;
	this.ConditionValue			= strConditionValue;
}


/***********************************************************************************
* Get the object -- return null if invalid
***********************************************************************************/
function getObjectElement(Element)
{
	var objTmp;

	if (!IsObject(Element))
	{
		if (Element != "")
		{
			objTmp = document.getElementsByName(Element);
			if (objTmp.length > 0)
			{
				Element 		= objTmp[0];
			}
			else
			{
				objTmp			= document.getElementById(Element);
				if (IsObject(objTmp))
					Element		= objTmp;
				else
					Element		= null;
			}
		}
		else
			Element				= null;
	}
	return Element;
}


/***********************************************************************************
* Translation functions: Originally this program was written in VBScript.  These
* functions were written to make conversion easier by mimicking the VBScript
* functions of the same name.
***********************************************************************************/
function IsObject(obj)	{	return typeof(obj) == "object";	}
function InStr(start, str, strFind)
{
	// make it 0 based
	start -= 1;
	tmp = str + "";
	return (tmp.substr(start)).indexOf(strFind) + 1;
}
function Mid(str, start, l)	{	return str.substr(start-1, l);						}
function Left(str, nLen)	{	return str.substr(0, nLen);							}
function Right(str, nLen)	{	return str.substr(str.length-nLen, str.length-1);	}
function Replace(str, find, r)
{
	pos = InStr(1, str, find);
	while (pos > 0)
	{
		str = str.substr(0,pos-1) + r + str.substr(pos, str.length-1);
		pos = InStr(1, str, find);
	}
	return str;
}
function Trim(s)
{
	lastChar = s.charAt(s.length-1);
	while (lastChar == ' ')
	{
		s = s.substr(0, s.length-1);
		lastChar = s.charAt(s.length-1);
	}
	return s;
}
function Len(str)
{
	if (str == null)	return 0;
	if (str == "")		return 0;
						return str.length;
}

function isCapableBrowser(bIE)
{
	// dfd 12/11/2001
	var agt;
	if (typeof(Server) == 'undefined')
		agt=navigator.userAgent;
	else
		agt=Request.ServerVariables("HTTP_USER_AGENT") + '';
	agt	= agt.toLowerCase();

	// dfd 12/11/2001
	var appVer;
	for (var i=0; i < agt.length; i++)
	{
		if (parseInt(agt.substr(i)) + '' != 'NaN')
		{
			appVer	= agt.substr(i);
			break;
		}
	}
	var is_major = parseInt(appVer);
	var is_minor = parseFloat(appVer);

	var is_nav  = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
	            && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
	            && (agt.indexOf('webtv')==-1) && (agt.indexOf('hotjava')==-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_major >= 4));
	var is_navonly  = (is_nav && ((agt.indexOf(";nav") != -1) ||
	                  (agt.indexOf("; nav") != -1)) );
	var is_nav6 = (is_nav && (is_major == 5));
	var is_nav6up = (is_nav && (is_major >= 5));
	var is_gecko = (agt.indexOf('gecko') != -1);


	var is_ie     = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
	var is_ie3    = (is_ie && (is_major < 4));
	var is_ie4    = (is_ie && (is_major == 4) && (agt.indexOf("msie 4")!=-1) );
	var is_ie4up  = (is_ie && (is_major >= 4));
	var is_ie5    = (is_ie && (is_major == 4) && (agt.indexOf("msie 5.0")!=-1) );
	var is_ie5_5  = (is_ie && (is_major == 4) && (agt.indexOf("msie 5.5") !=-1));
	var is_ie5up  = (is_ie && !is_ie3 && !is_ie4);
	var is_ie5_5up =(is_ie && !is_ie3 && !is_ie4 && !is_ie5);
	var is_ie6    = (is_ie && (is_major == 4) && (agt.indexOf("msie 6.")!=-1) );
	var is_ie6up  = (is_ie && !is_ie3 && !is_ie4 && !is_ie5 && !is_ie5_5);

	var is_aol   = (agt.indexOf("aol") != -1);

	var is_opera = (agt.indexOf("opera") != -1);
	var is_webtv = (agt.indexOf("webtv") != -1);

	var is_TVNavigator = ((agt.indexOf("navio") != -1) || (agt.indexOf("navio_aoltv") != -1));
	var is_AOLTV = is_TVNavigator;

	var is_hotjava = (agt.indexOf("hotjava") != -1);

	if (bIE)
		return (is_ie);
	else
		return (is_ie || is_nav6up);
}


/*********************************************************************************
**********************************************************************************
******************************** Internal Storage ********************************
**********************************************************************************
*********************************************************************************/

var m_ErrorFunction	= "";
var m_nCardTypes;
var vrAllCards;
var strDot			= '\u2022';

var vrMasterCard	= 1;	// MasterCard
var vrVisa			= 2;	// Visa
var vrDiscover		= 4;	// Discover
var vrAmex			= 8;	// American Express

vrAllCards			= vrMasterCard | vrVisa | vrDiscover | vrAmex;
m_nCardTypes		= vrAllCards


/*************************************************************************
* Internal storage of field items
**************************************************************************/
var m_fieldItems		= new Array();


/****************************************************************
* E-mail Templates:
* For e-mail templates, an "x" means one or more alphanumeric
* characters.  These character include all numbers and letters
* as well as "-", "_", and "'".  The template "x@x.x" means one or more
* alphanumeric characters, followed by and @ symbol, followed by one
* or more alphanumeric characters followed by a "." followed by
* one or more alphanumeric characters
****************************************************************/
var templateEmail = new Array("",
							  "x@x.x",
							  "x@x.x.x",
							  "x@x.x.x.x",
							  "x@x.x.x.x.x",
							  "x@x.x.x.x.x.x",
							  "x@x.x.x.x.x.x.x",
							  "x.x@x.x",
							  "x.x@x.x.x",
							  "x.x@x.x.x.x",
							  "x.x@x.x.x.x.x",
							  "x.x@x.x.x.x.x.x",
							  "x.x@x.x.x.x.x.x.x",
							  "x.x.x@x.x",
							  "x.x.x@x.x.x",
							  "x.x.x@x.x.x.x",
							  "x.x.x@x.x.x.x.x",
							  "x.x.x@x.x.x.x.x.x",
							  "x.x.x@x.x.x.x.x.x.x",
							  "x.x.x.x@x.x",
							  "x.x.x.x@x.x.x",
							  "x.x.x.x@x.x.x.x",
							  "x.x.x.x@x.x.x.x.x",
							  "x.x.x.x@x.x.x.x.x.x",
							  "x.x.x.x@x.x.x.x.x.x.x");


/******************************************************************
* Valid social security number templates.
******************************************************************/
var templateSSNumber = 	new Array("",
							  "xxxxxxxxx",
							  "xxx-xxxxxx",
							  "xxxxx-xxxx",
							  "xxx-xx-xxxx");


/******************************************************************
* Valid postal code templates
******************************************************************/
var templateZipCodes	= new Array("nnnnn",
									"nnnnn-nnnn",
									"nnnnn nnnn",
									"nnnnnnnnn",
									"lnl nln",
									"lnlnln",
									"llnnll",
									"lln nll")

/******************************************************************
* Valid date and time templates
******************************************************************/
var templateDate 	= 	new Array(	"x",
									"xdx",
									"xdxdx");

var templateTime 	= 	new Array(	"x",
									"xa",
									"xdx",
									"xdxa",
									"xdxdx",
									"xdxdxa");

var dateDelimiters	= new Array(	".",
									"/",
									"-");

var timeDelimiters	= new Array(	":");

var timeMeridians	= new Array(	"a",
									"p",
									"m");

var dateMacroNames	= new Array(	"now",
									"today",
									"yesterday",
									"tomorrow",
									"t",
									"n");
var dateMacros		= new Array(	"new Date()",																			// now
									"new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate())",		// today
									"new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()-1)",	// yesterday
									"new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()+1)",	// tomorrow
									"new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate())",		// t(oday)
									"new Date()");																			// n(ow)