function Validate() {
	//*** Uber important alias for the class object.  Used to reference methods and properties from within methods and event handlers
	var me = this;

	var cipher = null;
	var deciphered = null;
	var confirmMsg = "";
	var notBlank = true;
	var ccNumber = null;
	var ccExpiry = null;
	var email = null;
	var confirmEmail = null;
	var numberField = null;
	
	this.formObject;
	this.validateFields = null;
	this.numericFields = null;
	this.blankMsg = "One or more Required Fields have not been completed.<br>Please fill in the highlighted spaces.";
	this.emailMsg = "The Email Address you entered does not appear to be valid.<br>Please check it and try again.";
	this.ccMsg;
	this.ccExpiredMsg;
	this.numericSuccess = true;
	this.emailMsg;
	this.matchMsg;
	this.numericMsg;
	this.customTests;
	this.emailField = "email";
	this.confirmEmailField = "confirm_email";
	this.errorText = "formError"
	this.errorMsg = "";
	this.success = true;
	
	
	Validate.prototype.process = function () {
		var argv = arguments;
		var argc = arguments.length;
		var result;
		
		this.errorMsg = "";
		
		for (var i=0; i<argc; i++) {
			//*** To use this check, a variable called "cipherField" must define the name of the encrypted field
			if (argv[i] == "cipher") {
				cipher = this.formObject[cipherField].value;
				deciphered = decrypt(cipher);
				this.formObject[nameField].value = deciphered;
				if (deciphered != "")
					return true;
			}
			switch (argv[i]) {
				case "blank" :
					//*** Check for blank fields against list in "validateFields" array.  
					if (!(this.validateFields instanceof Array))
						break;
					notBlank = this.required_fields();
					if (!notBlank) {
						this.build_error("Blank");
						this.success = false;
					}
					break;
				case "cc_valid" :
					//*** To use this check, a variable called "ccField" must define the name of the credit card field
					ccNumber = this.get_control_value(this.formObject[this.ccField]);
					if (ccNumber == "")
						break;
					if (!this.luhn_check(ccNumber)) {
						this.build_error("CCError");
						this.highlight_error(this.formObject[ccField]);
						this.success = false;
					}
					break;
				case "cc_expiry" :
					//*** To use this check, a variable called "ccExpiryField" must define the name of the credit card field
					ccExpiry = this.get_control_value(this.formObject[this.ccExpiryField]);
					if (ccExpiry == "")
						break;
					if (!this.expiry_check(ccExpiry)) {
						this.build_error("CCExpired");
						this.highlight_error(this.formObject[ccExpiryField]);
						this.success = false;
					}
					break;
				case "numeric" :
					//*** To use this check, the numericFields property must be filled with an array
					if (!(this.numericFields instanceof Array))
						break;
					for (var i=0; i<numericFields.length; i++) {
						numberField = this.formObject[numericFields[i]].value;
						if (!this.is_numeric(numberField) && numberField != "?") {
							this.build_error("NumericError");
							this.highlight_error(this.formObject[numericFields[i]]);
							this.numericSuccess = false
							this.success = false;
						}
					}
					break;
				case "email_valid" :
					//*** To use this check, a variable named "emailField" must be defined
					email = this.get_control_value(this.formObject[this.emailField]);
					if (email == "")
						break;
					if (!this.is_valid_email(email)) {
						this.build_error("EmailError");
						this.highlight_error(this.formObject[this.emailField]);
						this.success = false;
					}
					break;
				case "email_confirm" :
					//*** To use this check, variables named "email_validField" and "email_confirmField" must be defined
					email = this.get_control_value(this.formObject[this.emailField]);
					confirmEmail = this.get_control_value(this.formObject[this.confirmEmailField]);
					if (email == "" || confirmEmail == "")
						break;
					if (!this.is_valid_email(email)) {
						this.build_error("EmailError");
						this.highlight_error(this.formObject[this.emailField]);
						this.success = false;
						break;
					} else if (email != confirmEmail) {
						this.build_error("MatchError");
						this.highlight_error(this.formObject[this.emailField],this.formObject[this.confirmEmailField]);
						this.success = false;
					}
					break;
			}
			
			if ((this.customTests instanceof Array)) {
				for (c=0; c<this.customTests.length; c++) {
					if (this.customTests[c]["test"] == argv[i]) {
						result = eval(this.customTests[c]["testFunc"]);
						if (!result) {
							this.errorMsg += "<li>" + this.customTests[c]["testMessage"] + "</li>";
							eval(this.customTests[c]["onComplete"]);
							this.success = false;
						}
					}
				}
			}

		}
		if (!this.success)
			this.show_error();
		
	}
	
	

	Validate.prototype.add = function (testName, testMessage, testFunc, onComplete) {
		var testParams = new Array();
		var cLength = 0;
		if (!(this.customTests instanceof Array)) {
			this.customTests = new Array();
		} else {
			cLength = this.customTests.length;
		}
		
		testParams["test"] = testName;
		testParams["testMessage"] = testMessage;
		testParams["testFunc"] = testFunc;
		testParams["onComplete"] = onComplete;
		
		this.customTests[cLength] = testParams;
		return;
	}
	
	Validate.prototype.build_error = function (errType) {

		switch (errType) {
			case "Blank" :
				this.errorMsg += "<li>" + this.blankMsg + "</li>";
				break;
			case "CCError" :
				this.errorMsg += "<li>" + this.ccMsg + "</li>";
				break;
			case "CCExpired" :
				this.errorMsg += "<li>" + this.ccExpiredMsg + "</li>";
				break;
			case "EmailError" :
				this.errorMsg += "<li>" + this.emailMsg + "</li>";
				break;
			case "MatchError" :
				this.errorMsg += "<li>" + this.matchMsg + "</li>";
				break;
			case "NumericError" :
				this.errorMsg += "<li>" + this.numericMsg + "</li>";
				break;
		}
	}

	Validate.prototype.caesar = function (clicks,input) {
	    var output = "";
	    var cur_char = "";
		 var new_char = "";
	    //get the length of the string once to aid in efficency
	    var str_len = input.length;
	
	    //encryption loop
	    for(var i=0; i<str_len; i++) {
	        //get the ascii value of the current character
	        cur_char = this.ord(input.substring(i,i+1));
	        //if this is an upper case letter
	        if (cur_char > 64 && cur_char < 91) {
	            //turn the letter into its position in the alphebet
	            new_char = cur_char - 65;
	            //move the position according to clicks and turn the position
	            //back into the value of the ascii letter
	            new_char = (new_char + clicks)%26 + 65;
	            
	        //if this is a lower case letter 
	        } else if (cur_char > 96 && cur_char < 123) {
	            //turn the letter into its position in the alphebet
	            new_char = cur_char - 97;
	            //move the position according to clicks and turn the position
	            //back into the value of the ascii letter
	            new_char = (new_char + clicks)%26 + 97; 
	        } //end if
	        
			  if (cur_char != -1)
	        	output += this.chr(new_char);
	    } //end for
	    return output;
	}

	Validate.prototype.chr = function (inNum) {
		return String.fromCharCode(inNum);
	}
	
	Validate.prototype.decrypt = function (inValue) {
		var outName = "";
		inValue = inValue.toLowerCase();
		var clicks = this.ord(inValue.substring(0,1)) - 96;
		var nlen = this.ord(inValue.substring(1,2)) - 96;
		var decrypted = this.caesar(26-clicks,inValue.substring(2,inValue.length));
		var lastword = decrypted.substring(decrypted.length-6,decrypted.length);
		if (lastword == "shplun") {
			for (var i=0; i<(nlen * 2); i+=2) {
				outName += decrypted.substring(i,i+1);
			}
		}
		return outName;
	}
	
	Validate.prototype.expiry_check = function (ccExpiry) {
		var dateParts = ccExpiry.split("-");
		var year = dateParts[1];
		var month = dateParts[0];
		var expiry;
	
		if (!this.is_numeric(year+""))
			return false;
		if (!this.is_numeric(month+""))
			return false;
		today = new Date();
		expiry = new Date(year, month);
		if (today.getTime() > expiry.getTime())
			return false;
		else
			return true;
	}
	
	//*** Gets current value of any type of control
	Validate.prototype.get_control_value = function (ctl) {
		var ctlVal = "";
		switch (ctl.type) {
			case "select-one" :
			case "select-multiple" :
				ctlIndex = ctl.selectedIndex;
				if (ctlIndex != -1)
					ctlVal = ctl.options[ctlIndex].value;
				if (ctl.options[ctlIndex].text.indexOf("(select)") != -1)
					ctlVal = "";
				break;
			case "radio" :
				//if (radioTested) break;
				//if (!checkRadio(formObject))
					//ctlVal = "";
				//radioTested = true;
				break;
			default :
				ctlVal = ctl.value;
				break;
		}
		if (typeof(ctlVal) == "undefined" || ctlVal == null)
			ctlVal = "";
		return ctlVal;
	}
	
	Validate.prototype.highlight_error = function () {
		var argv = arguments;
		var argc = arguments.length;
		
		for (var i=0; i<argc; i++) {
			argv[i].className += '-error';
		}
	}
	
	Validate.prototype.is_numeric = function is_numeric(sText) {
		var matched = sText.match(/[0-9.,$]+/);
		return (sText == matched);
	}
	
	Validate.prototype.is_valid_email = function (emailTest) {
		var eParts;
		
		if (emailTest.indexOf("@") != -1) {
			eParts = emailTest.split("@");
			if (eParts[0].length < 1)
				return false;
			if (eParts[1].indexOf(".") == -1)
				return false;	
		} else {
			return false;
		}
		
		return true;
	}

	//*** Uses Luhn algorithm to generate checksum for credit card number
	Validate.prototype.luhn_check = function (ccNumber) {
		if (!is_numeric(ccNumber)) {
			return false;
		}
		
		var digitCount = ccNumber.length;
		var parity = digitCount & 1;
		var sum = 0;
		
		for (var i=0; i < digitCount; i++) {
			var digit = parseInt(ccNumber.charAt(i));
			if (!((i & 1) ^ parity)) {
				digit *= 2;
			if (digit > 9)
				digit -= 9;
			}
			sum += digit;
		}
		return (sum % 10 == 0)
	}
	
	Validate.prototype.ord = function (inChar) {
		return inChar.charCodeAt(0);
	}
	
	Validate.prototype.required_fields = function () {
		var ctl = null;
		var ctlType = "";
		var ctlName = "";
		var ctlVal = "";
		var ctlIndex = 0;
		var ctlDisabled = false;
		var success = true;
		var border = "";
		
		for (var i = 0; i<this.validateFields.length; i++) {
			ctl = document.getElementById(this.validateFields[i]);
			if (me.validateFields[i].indexOf("AND") != -1)
				continue;
			if (!isUndefined(ctl)) {
				ctlDisabled = ctl.disabled;
				ctlVal = this.get_control_value(ctl);
	
				//*** This section assumes that you've defined class names like 
				//		"input-text" and "input-text-error" for your input fields
				ctl.className = ctl.className.replace( '-error', '' );
				if(ctlVal == "" && !ctlDisabled) {
					success = false;
					ctl.className += '-error';
				}
				if (ctlDisabled)
					ctl.style.background = "#EBEBE4";
			}
		} //*** for (var i = 0; i<fieldArray.length; i++) 
		return success;
	} //*** function required_fields

	Validate.prototype.show_error = function () {
		var msg = document.getElementById(this.errorText);
		msg.innerHTML = "<ul>" + this.errorMsg + "</ul>";
	}


} //*** Validate


