// READ ME
// READ ME
// READ ME
// READ ME
// 
// THE VALIDATOR BELOW IS USED WITH ALL PAGES ON THE PLATFORM. PLEASE MAKE SURE YOU UNDERSTAND HOW IT WORKS
// BEFORE CHANGING ANYTHING. IF YOU HAVE DOUBTS OR NEED HELP, ASSIGN THE JIRA TO MAUVIS
//
// A lot of the validation engine is still being worked on. If you look at the code, you'll notice
// that a lot of it is repeated twice. This is to support the older "new validation" pages that haven't
// been updated it. If you see "/*KILL THIS WHEN DONE */" around any of the code you are changing you 
// are probably changing the wrong code. Here is where the final stuff is: 
//
// ERROR MESSAGES:
// Ka.formValidation.messages
// RULES:
// Ka.formValidation.rules 

// READ ME
// READ ME
// READ ME
// READ ME

//TO USE THIS VALIDATOR ON ANY FORM:
// 1) View the HTML source of the page, if Ka.formValidation.js script isn't there add that forms page model object to 
//	  WEB-INF/JSP/JS/ValidationLogicJS.jsp so this JS file get's included on  that page
// 2) If you see the old validation.js, remove it (switch this off in ValidationLogicJS.jsp, too)
// 3) On the actual <form> element add in the attribute  validate="validate", and remove any onsubmit logic that 
//    may already  be on the form. Also remove any javascript on the submit button, and make sure the submit button
//	  is type="submit" not button, so the form submits correctly without javascript <<== this is important
// 4) Add require="true" to any form element that is required. Then add in any additional rule from the rules
//    object below to add that element in. See the join page as a good example. You can add rules to any form
//    elements and not inlucde required="true" so the rule only applies if the user enters content.
// 5) If you want to specifially say something different on error instead of the error of the broken
//    validation rule, you can add in an errorKey with some custom error text. Use an errorKey message from
//	  the messages object below, or add your own. 
// 6) You should test that all validation rules you add are the same as the backend ones when the JS is turned off. 
//    If there are no applicable existing rule for what youw want you can add in a custom one. Just make sure
//    It returns true or false only.
// 7) For complex forms, using JS you can dynamically remove and add in rules, and required="true" elements as 
//    the person fills out the form.

//	AJAX FORMS:
// 8) If the form you are using doesn't sumbit like a regular html form and calls something like an ajax call 
//    "on valid" instead, then you can add the attribute onvalid="nameOfYourFunction" on the <form> elemnt. This will 
// 	  override the on success form submission and run this method on success instead (passing the form into it
// 	  as an argument.
//
// EXRTA METHODS
// 9) If you need to run some JS before the from is validtion you can set this logic up before hand using 
//    Ka.formValidation.actions.addOnBeforeValidFunction(func). Any functions qued in here will run before the 
//    formValidation process starts (with the actual form element being passed in to each qued function.)
// 10) If you want to que up a bunch of functions to be called after the form is verified to be valid but before 
//    the form submits you can que them up through this method: Ka.formValidation.actions.addOnValidFunction(func) 
//    anytime before form submittal. When the form is validated by the validator it will run through any functins 
//    in the addOnValidFunction array passing in the actual form object as an argument.


Ka.formValidation = {
	
	config: {
		defaultErrorContainerClass: "ka_Error"
	},

	messages: { // overriding error messages:
		
		//doesn't look like it's used anywhere
		birthday:"Please enter your birthday.",
		
		blogTextMaxLength:Ka.Messages.BLOGTEXTMAXLENGTH,
	
		//affiliate/displayMediaDetails.jsp + pages/editBlog.jsp
		blogTextRequiredForTextBlog:"Blog text is required for creating a text blog.",
		
		//doesn't look like it's currently used anywhere
		editBlogTextRequiredForTextBlog:"Blog text is required for a text blog.",
		
		profileCommentSubject: Ka.Messages.PROFILEPAGEERRORMSG,
		
		dobMonth:Ka.Messages.DOBMONTH,
		dobDay:Ka.Messages.DOBDAY,
		dobYear:Ka.Messages.DOBYEAR,
		
		//doesn't look like it's currently used anywhere
		email:Ka.Messages.EMAILADDR,		
		
		//doesn't look like it's currently used anywhere
		emails:"Please include at least one email address.",
		
		//doesn't look like it's currently used anywhere
		emailInvalid:"Your email address isn't valid. Please check it carefully.",
		
		emailListTwentyMax:Ka.Messages.ONLYMEMBERS,
		emailPlease:Ka.Messages.EMAILPLEASE,
		
		//doesn't look like it's currently used anywhere
		emailPleaseInclude: "Please include at least one username or email address.",
		//doesn't look like it's currently used anywhere
		emailListInvalid: "Please verify that the email addresses are correct.",
		
		// affiliate/siteMediaCategories
		enterName:"Please enter a name.",
		
		forumTitle:Ka.Messages.MBFORUMVALIDATIONMSG,
		discussionTitle: Ka.Messages.MBDISCUSSIONVALIDATIONMSG,
		
		file:Ka.Messages.CHOOSEFILE,
		fileSelect:Ka.Messages.PLEASESELECTAFILE,
		
		//doesn't look like it's currently used anywhere
		invalidEmailAddresses: "Invalid email address(es).",
	
		messageSubject:Ka.Messages.PLZENTERSUBJECT,
		messageRequired:Ka.Messages.PLZENTERMSG,
		
		password:Ka.Messages.PASSWORD,
		passwordConfirm:Ka.Messages.PASSWORDCONFIRM,
		
		//affiliate/site_rss.jsp
		rssUrl:"Please Enter RSS Url.",
		//affiliate/site_rss.jsp
		rssName:"Please Enter a Url Name.",
		
		securityText:Ka.Messages.SECURITY_TEXT,
		
		//affiliate/site.jsp
		siteNameRequired:"Please enter your site name.",
	
		termsOfService:Ka.Messages.TERMSOFSERVICE,
		title:Ka.Messages.TITLE,
	
		url:Ka.Messages.ENTERAVALIDURL,
		username:Ka.Messages.USERNAME
	},

// validation rules array (return true if data validates ok, false if data fails validation):
// add rules as needed
	rules: {

		"canada-postal-code": {
			message:Ka.Messages.ENTERVALLIDCANADIANPORTALCODE,
			test:function(val,propVal){
				val = val + ""; // make sure it's data type is String
				switch(val.length){ // needs to be 6 or 7 characters long
					case 6 :
						var CaZipSix = /[A-Za-z]\d[A-Za-z]\d[A-Za-z]\d/;
						if(CaZipSix.test(val)){ return true; }else{ return false; }
						break;
					case 7 :
						var CaZipSeven = /[A-Za-z]\d[A-Za-z][ -]\d[A-Za-z]\d/;
						if(CaZipSeven.test(val)){ return true; }else{ return false; }
						break;
					default :
						return false;
				}
			}
		},

		"depends-on": {
			message:Ka.Messages.REQFIELD,
			test:function(val,propVal){ // this field has a problem if it is empty AND any of it's counterparts has a value:
				// if not empty, we're done:
				if(val !== ""){ return true; }
				// field is empty...
	
				var idArray;
				if(propVal.indexOf(",") == -1){ idArray = [propVal]; }else{ idArray = propVal.split(","); }
				
				var othersEmpty = true;
				for(var i = 0; i < idArray.length; i++){
					if($(idArray[i]).value !== ""){ othersEmpty = false; }
				}
				return othersEmpty;
			}
		},
		"email-and-or-member-list-max-200": {
			message:Ka.Messages.EMAILHELPERTEXT,
			test:function(val,propVal,element){
				
				if (val === ''){return false;}
				var mainArr = [];
				var emailArr = [];
				var membersArr = [];
				var hasErrors = false;				
				//clean string
				val = Ka.String.trim(val);			
				val = Ka.String.singleSpace(val);				
				
				mainArr = val.split(',');
				
				//seperate string into emails arr and members arr
				for (var i=0;i<mainArr.length;i++){
					mainArr[i] = Ka.String.trim(mainArr[i]);
					if (mainArr[i].indexOf('@') !== -1){
						emailArr.push(mainArr[i]);
					}else{
						membersArr.push(mainArr[i]);
					}
				}
				
				if (emailArr.length > 0){
					for (var i=0;i<emailArr.length;i++){
						if (!Ka.formValidation.rules['is-email'].test(emailArr[i])){
							hasErrors = true;
							break;
						}
					}
				}
				
				//skip for SSO enabled sites
				if(Ka.Info.SSOENABLED == 'false'){
					if (membersArr.length > 0 && hasErrors === false){
						for (var i=0;i<membersArr.length;i++){
							if (!Ka.formValidation.rules['is-member-format'].test(membersArr[i])){
								hasErrors = true;
								break;
							}
						}
					}
				}
				
				if ( hasErrors === false && emailArr.length + membersArr.length > 200){
					element.setAttribute("errorkey","emailListTwentyMax");
				}

				return !hasErrors;
			}
		},
/* rewritten by Mauvis and verified */			
		"email-and-or-member-list-twenty-max": {
			message:"Please enter comma-separated, valid email addresses and/or usernames",
			test:function(val,propVal,element){
				
				if (val == ''){return false;}
				var mainArr = [];
				var emailArr = [];
				var membersArr = [];
				var hasErrors = false;				
				//clean string
				val = Ka.String.trim(val);			
				val = Ka.String.singleSpace(val);				
				
				mainArr = val.split(',');
				
				//seperate string into emails arr and members arr
				for (var i=0;i<mainArr.length;i++){
					mainArr[i] = Ka.String.trim(mainArr[i]);
					if (mainArr[i].indexOf('@') !== -1){
						emailArr.push(mainArr[i]);
					}else{
						membersArr.push(mainArr[i]);
					}
				}
				
				if (emailArr.length > 0){
					for (var i=0;i<emailArr.length;i++){
						if (!Ka.formValidation.rules['is-email'].test(emailArr[i])){
							hasErrors = true;
							break;
						}
					}
				}
				
				//skip for SSO enabled sites
				if(Ka.Info.SSOENABLED == 'false'){
					if (membersArr.length > 0 && hasErrors === false){
						for (var i=0;i<membersArr.length;i++){
							if (!Ka.formValidation.rules['is-member-format'].test(membersArr[i])){
								hasErrors = true;
								break;
							}
						}
					}
				}
				
				if ( hasErrors === false && emailArr.length + membersArr.length > 20){
					element.setAttribute("errorkey","emailListTwentyMax");
				}

				return !hasErrors;
			}
		},

/* rewritten by Mauvis and verified */
		"email-list": {
			message:"Invalid email address(es).",
			test:function(val){
				
				if (val.indexOf('@') === -1){return false;}
				
				//split if needed
				var emailArray;
				var allEmailsValid = true;
				
				if(val.indexOf(",") != -1){
					emailArray = val.split(",");
				}else{
					emailArray = [val];
				}
				
				//remove spaces
				emailArray = Ka.Array.trim(emailArray);

				// clean up:
				emailArray = Ka.formValidation.cleanStringArray(emailArray);
				emailArray = Ka.formValidation.removeDuplicatesFromArray(emailArray);
				
				for(var i=0; i < emailArray.length; i++){
					if(!Ka.formValidation.rules["is-email"].test(emailArray[i])){
						allEmailsValid = false;
					}
				}
				
				if(allEmailsValid){
					return true;
				}else{
					return false;
				}
			}
		},

		"is-alpha-numeric": {
			message:"This field accepts only letters, numbers and the underscore (_)",
			test:function(val,propVal){
				var nonAlphaRegX = /\W/;
				if(nonAlphaRegX.test(val)){
					return false;
				}else{
					return true;
				}
			}
		},
		

		"is-email": {
			message:"Please enter a valid email address",
			test:function(val,propVal){
				if (/\".*\"\s*\<.*\>/.test(val)){val = /\<(.*)\>/.exec(val)[1];}
				var emailFilter = /^([a-zA-Z0-9_\.\-\+])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
				if(emailFilter.test(val)){
					return true;
				}else{
					return false;
				}
			}
		},
	
		"is-integer": {
			message:"This field must be a number",
			test:function(val,propVal){
				if(isNaN(parseInt(val, 10))){
					return false;
				}else{
					return true;
				}
			}
		},

		"is-member-format": {
			message:"This field must be a number",
			test:function(val){
				if (val.length < 3){
					return false;
				}
				//skip for SSO enabled sites
				if(Ka.Info.SSOENABLED == 'false'){
					return Ka.formValidation.rules["is-alpha-numeric"].test(val);
				}else{
					return true;
				}
			}
		},
						
		"is-tags": {
			message:Ka.Messages.CLOSEOPENQUOTES,
			test:function(val,propVal,element){

				// first strip out any new-line characters:
				if(val.indexOf("\n") != -1){
					val = val.split("\n");
					val = val.join(" ");
				}
				
				// check for invalid characters
				if(!/^[a-z0-9\s\"]*$/ig.test(val)) {
					this.message = Ka.Messages.INVALIDTAGCHARACTERS || 'Tags can only include letters, numbers, and underscores';
					return false;
				}
				
				var qArray = Ka.formValidation.tags.doubleQuoteLocations(val);
				if((qArray.length % 2) != 0){ // double-quote number is off
					return false;
				}
				var tagArray; // this will hold the array of tags
				// if there are no quotes, just split on space:
				if(qArray.length == 0){
					tagArray = val.split(" ");
				}else{ // ok, manual labor time...
					tagArray = Ka.formValidation.tags.buildTagArrayManually(qArray,val);
				}
				
				tagArray = Ka.formValidation.cleanStringArray(tagArray);
				tagArray = Ka.formValidation.removeDuplicatesFromArray(tagArray);
				
				var outStr = Ka.formValidation.tags.buildDataStringForSubmission(tagArray);
				element.value = outStr;
				return true;
			}
		},
		
		"is-url": {
			message:Ka.Messages.ENTERAVALIDURL,
			test:function(val,propVal){
				val = val + "";
				if(!(val.indexOf("http://") == 0 || val.indexOf("https://") == 0)){
					val = "http://" + val;
				}
				var urlRegX = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/;
				if(urlRegX.test(val)){
					return true;
				}else{
					return false;
				}
			}
		},

		"length-max":{
			message:"This field cannot be longer than % characters",
			test:function(val,propVal){
				// make sure we're dealing with correct data-types:
				val = val + ""; propVal = parseFloat(propVal);
				if(val.length <= propVal){
					return true;
				}else{
					return false;
				}
			}
		},	
		
		"length-min":{
			message:Ka.Messages.ENTERATLEAST,
			test:function(val,propVal){
				// make sure we're dealing with correct data-types:
				val = val + ""; 
				propVal = parseFloat(propVal);
				if(val.length >= propVal){
					return true;
				}else{
					return false;
				}
			}
		},
		
		"min-characters": {
			message:"This field requires at least % characters",
			test:function(val,propVal){
				// make sure we're dealing with correct data types:
				propVal = parseFloat(propVal);
				val = val + "";
				if(val.length < propVal){
					return false;
				}else{
					return true;
				}
			}
		},

		"no-dash": {
			message:"Please select a state",
			test:function(val,propVal){
				if(val.indexOf("-") == -1){
					return true;
				}else{
					return false;
				}
			}
		},
			
		"no-spaces": {
			message:"This field cannot contain spaces",
			test:function(val,propVal){
				if(val.indexOf(" ") == -1){
					return true;
				}else{
					return false;
				}
			}
		},
		
		"not-equal-to":{
			message:"This value cannot be %",
			test:function(val,propVal){
				if(val == propVal){
					return false;
				}else{
					return true;
				}
			}
		},
		
		"number-max": {
			message:"This value must be equal-to or less than %",
			test:function(val,propVal){
				// make sure we're dealing with numbers:
				val = parseFloat(val); propVal = parseFloat(propVal);
				if(val <= propVal){
					return true;
				}else{
					return false;
				}
			}
		},
		
		"number-min": {
			message:"This value must be equal-to or greater than %, because % is the lowest we go",
			test:function(val,propVal){
				// make sure we're dealing with numbers:
				val = parseFloat(val); propVal = parseFloat(propVal);
				if(val >= propVal){
					return true;
				}else{
					return false;
				}
			}
		},

		"password-match-with": {
			message:"Your passwords must match exactly.",
			test:function(val,propVal){
				if(val == $(propVal).value){
					return true;
				}else{
					return false;
				}
			}
		},
		
		"required": {
			message:Ka.Messages.REQFIELD,
			test:function(val,propVal){
				val = Ka.String.trim(val);
				if(val == ""){
					return false;
				}else{
					return true;
				}
			}
		},
		
		"us-postal-code": {
			message:Ka.Messages.ENTERVALLIDUSPORTALCODE,
			test:function(val,propVal){
				val = val + ""; // make sure it's data type is String
				switch(val.length){ // needs to be 5 or 10 characters long
					case 5 :
						var UsZipFive = /\d{5}/;
						if(UsZipFive.test(val)){ return true; }else{ return false; }
						break;
					case 10 :
						var UsZipTen = /\d{5}[ -]\d{4}/;
						if(UsZipTen.test(val)){ return true; }else{ return false; }
						break;
					default :
						return false;
				}
			}
		},
		
		"min-age": {
			message:"You must be a certain age.",
			test:function(val,propVal){
				// get the dates
				var bday = document.getElementById(val.split(',')[0]).value;
				var bmonth = document.getElementById(val.split(',')[1]).value;
				var byear = document.getElementById(val.split(',')[2]).value;

				// parse them
				bday = bday=='Select' ? 0 : parseInt(bday);
				bmonth = bmonth=='Select' ? 0 : parseInt(bmonth) - 1;
				byear = byear=='Select' ? 0 : parseInt(byear);

				// get the current date info.
				var now = new Date();
				cday = now.getDate();
				cmonth = now.getMonth();
				cyear = now.getFullYear();

				// if the current month is greater than the birthday month, or the current month is equal to the birthday month, and the current day is equal to or greater than the birthday day
				if((cmonth > bmonth) || (cmonth==bmonth && cday>=bday))	{
					// set the age to the year
					var age = byear;
					age = cyear-age;
				} else {
					// set the age to the year plus 1, since their birthday hasn't been hit yet
					var age = byear+1;
					age = cyear-age;
				}
				// return the status of an age check
				return (age>=propVal ? true : false);
			}
		}
		
	},
	
	containers: {
		formsToValidate: [],
		submitButtonMessage: '',
		submittingButtonMessage: Ka.Messages.SENDING,
		/* custom functions to run before form is validated (used to setup logic) */
		onBeforeValidFuncs: [],
		/* custom functions to run after form is valid but before submit */
		onValidFuncs: []
	},
	
	events: {
		
		onInit: function(){
			Ka.formValidation.actions.populateFormsToValidate();
			//add submit listener to forms
			Ka.formValidation.actions.addSubmitListener();
			//Ka.formValidation.actions.addCancelListener();
		},
		
		//returning false here prevents form submission
		onFormSubmit: function(thisForm){
			
			//remove old errors
			Ka.formValidation.actions.removeOldErrors(thisForm);
			
			//check for tinyMCE rich text editors and copy content to applicable textarea
			Ka.formValidation.actions.checkAndAdjustforTinyMCE();
			
			//console.log('submit recieved...');
			//disable submit action and button
			Ka.formValidation.actions.disableSubmit(thisForm);

			//run these custom funcs before validation start
			if (Ka.formValidation.containers.onBeforeValidFuncs.length !== 0){
				for (var i=0;i<Ka.formValidation.containers.onBeforeValidFuncs.length;i++){
					Ka.formValidation.containers.onBeforeValidFuncs[i](thisForm);
				}
			}

			//check if the form is valid
			if ( Ka.formValidation.actions.validateForm(thisForm) ){
				
				//if customValidFuncsContainer has funcs
				if (Ka.formValidation.containers.onValidFuncs.length !== 0){
					for (var i=0;i<Ka.formValidation.containers.onValidFuncs.length;i++){
						Ka.formValidation.containers.onValidFuncs[i](thisForm);
					}
				}	
				//if onValid override is set use that instead of submitting the form
				var onValidCallback;
				if (typeof $j(thisForm).attr('onvalid') == 'string'){
					try{
						onValidCallback = eval($j(thisForm).attr('onvalid'));
					//on error default to submitting the form
					}catch(error){
						alert(error);
						return false;
					}
					if(onValidCallback){
						onValidCallback(thisForm);
						//Ka.formValidation.actions.enableSubmit(thisForm);
					}		
					return false;
				}else{
					//console.log('submitted true');
					return true;
				}
			}else{
				//console.log('submitted false');
				return false;
			}
		}
		
		
	},
	
	actions: {
		
		checkAndAdjustforTinyMCE: function(){
			if ( typeof tinymce != 'undefined' ){
				tinyMCE.triggerSave();
			}
		},
			
		disableSubmit: function(thisForm){
			//console.log('disableSubmit');
			Ka.formValidation.actions.disableSubmitButton(thisForm);
			$j(thisForm).unbind('submit').submit(function(){
				return false;
			});
		},

		enableSubmit: function(thisForm){
			//console.log('enableSubmit');
			Ka.formValidation.actions.enableSubmitButton(thisForm);
			$j(thisForm).unbind('submit').submit(function(){
				return Ka.formValidation.events.onFormSubmit(this);
			});
		},
				
		disableSubmitButton: function(thisForm){
			//first look for input submit
			var $submitButton =  $j(thisForm).find("input[@type=submit],button[@type=submit]")
				.not('[value=]')
				.filter(function(index) {
				    return ( ($j(this).attr('value').toLowerCase().indexOf('ok') !== -1) || 
				    	($j(this).attr('value').toLowerCase().indexOf('add') !== -1) ||
				    	($j(this).attr('value').toLowerCase().indexOf('post') !== -1) ||
				    	($j(this).attr('value').toLowerCase().indexOf('join') !== -1) ||
				    	($j(this).attr('value').toLowerCase().indexOf('save') !== -1) ||
				    	($j(this).attr('value').toLowerCase().indexOf('send') !== -1) );
				});
		
			if ($submitButton.length !== 0){
				Ka.formValidation.containers.submitButtonMessage = $submitButton.attr('value');
				$submitButton.attr('disabled','disabled')
				.addClass('ka_disabledInput')
				.blur()
				.attr('value',Ka.formValidation.containers.submittingButtonMessage);
			}

		},

		enableSubmitButton: function(thisForm){
			var $submitButton;
			//first look for input submit
			$submitButton = $j(thisForm).find("input[@type=submit],button[@type=submit]");
			if ($submitButton.length !== 0){
				$submitButton.removeAttr('disabled')
					.removeClass('ka_disabledInput');
			}
			//Look for sending... button and rename to old submit value
			if (Ka.formValidation.containers.submitButtonMessage !== ''){
				$submitButton.filter(function(){
					return (this.value.indexOf(Ka.formValidation.containers.submittingButtonMessage) !== -1);
				}).attr('value',Ka.formValidation.containers.submitButtonMessage);
			}
		},
		
		populateFormsToValidate: function(){
			var allForms = document.getElementsByTagName('form');
			for (var i=0;i<allForms.length;i++){
				if ($j( allForms[i] ).attr('validate')){
					Ka.formValidation.containers.formsToValidate.push(allForms[i]);
				}
			}
		},
		
		addSubmitListener: function(){
			$j(Ka.formValidation.containers.formsToValidate).each(function(){
				$j(this).submit(function(){
					//return Ka.formValidation.validateForm(this,'checkError-error');
					return Ka.formValidation.events.onFormSubmit(this);
				});
			});
		},

		addCancelListener: function(){
			//find any buttons with the value cancel
			$j(Ka.formValidation.containers.formsToValidate).each(function(){
				var $cancelButton = $j(this).find("input[@type=submit]")
					.filter(function(index) {
					    return ($j(this).attr('value').toLowerCase().indexOf('cancel') !== -1);
					});
					
				if ($cancelButton.length != 0){
					$cancelButton.click(function(){
						history.back();
						return false;
					});
				}
			});
		},
		
		disableAllInputs: function(thisForm){
			$j(thisForm).find('input,button').attr('disabled','disabled');
		},

		addOnBeforeValidFunction: function(func){
			Ka.formValidation.containers.onBeforeValidFuncs.push(func);
		},
			
		addOnValidFunction: function(func){
			Ka.formValidation.containers.onValidFuncs.push(func);
		},
				
		removeOldErrors: function(thisForm){
			$j(thisForm).find('.ka_Error').remove();	
		},
		
		validateForm: function(thisForm){
		//validateForm: function(thisForm,mainErrorId){
			mainErrorId = 'checkError-error';
			
			//find only unhidden form elemts
			var elements = thisForm.elements;
			var formHasProblems = false;
			var radioNameArray = [];
			
			// clear all error messages first:
			for(var j=0; j < elements.length; j++){
				Ka.formValidation.removeFormFieldErrorMessages(elements[j]);
			}
			
			for(var j=0; j < elements.length; j++){ // cycle through form elements...

				Ka.alert('Checking form element for rules', elements[j]);
				
				// so, tell me about this element....
				var elementType = elements[j].getAttribute("type");
				var elementName = elements[j].getAttribute("name");
				var elementValue = elements[j].value;
				
				var skipThisElement = false;
				
				// override?
				if(elements[j].getAttribute("do-not-validate") == "true"){
					skipThisElement = true;
				}
				
				// Any of the following conditions should supress the validation of this element:
				if( // the field is NOT required, AND it is empty, AND it isn't dependent on another element
					((!elements[j].getAttribute("required"))||(elements[j].getAttribute("required") == "false")) // not required
					&& 
					elementValue == "" // is empty
					&&
					((!elements[j].getAttribute("depends-on"))||(elements[j].getAttribute("depends-on") == "")) // isn't dependent on another element
				){ skipThisElement = true; }
				if( // - (it is a radio button) whose group has already been checked
					Ka.formValidation.stringInArray(elementName,radioNameArray) // this field's name can only be in radioNameArray if it has been checked
				){ skipThisElement = true; }
		
				if(skipThisElement){
					// do not validate...
				}else{ // validate:
					var errorMessages = [];
					//for each rule, check against 
					$j.each( Ka.formValidation.rules, function(i){
						var thisRule = this; 
						thisRule.ruleName = i;
						
						//console.log(thisRule);
						//if the form element has this rule and it isn't equal false
						if(	elements[j].getAttribute(thisRule.ruleName)	&& elements[j].getAttribute(thisRule.ruleName) != "false"){
							
							Ka.alert('	has rule',thisRule.ruleName);
							
							var attributeValue = elements[j].getAttribute(thisRule.ruleName);
							// is this a radio button?
							if(elementType == "radio"){
								// add name to 'radioNameArray' so group will no be checked again 
								radioNameArray.push(elementName);
								// are any in the group selected?
								if(Ka.formValidation.radioGroupHasSelection(thisForm[elementName])){
									elementValue = "checked"; // fake a value
								}else{
									elementValue = ""; // simulate empty value
								}
							}
		
							// if this is a checkbox?
							if(elementType=="checkbox"){
								if(elements[j].checked){
									elementValue = "checked"; // fake a value
								}else{
									elementValue = ""; // simulate empty value
								}
							}
							
							if(!(this.test(elementValue,attributeValue,elements[j]))){ // failed test
								var thisMessage = thisRule.message;
								// if the message contains '%', replace it with attributeValue
								thisMessage = Ka.formValidation.replaceCharacterWithValue("%",attributeValue,thisMessage);
								
								// add error message to array:
								errorMessages.push(thisMessage);
								Ka.alert('		failed rule',thisRule.ruleName);
							}else{
								Ka.alert('		passed',thisRule.ruleName);
							}
						}
					});
					
					if(errorMessages.length){ // this field has errors that need to be displayed
						formHasProblems = true; // the form as a whole has failed validation
						// display messages:
						Ka.formValidation.showFormFieldError(elements[j],errorMessages);
					}					

				}
			}
			
			if(formHasProblems){ // there are form errors
				// unhide main error message at top of form
				if(mainErrorId != "" && $(mainErrorId) && $(mainErrorId).innerHTML !==''){
					$j('#'+mainErrorId).show().ScrollTo();
					//scroll to error
					//window.location.href = "#"+mainErrorId;
					
				}else{
					$j('#'+thisForm.id).ScrollTo();
					//window.location.href = "#"+thisForm.id;
				}
				Ka.formValidation.actions.enableSubmit(thisForm);
				return false;
			}else{
				// hide main error message at top of form
				if(mainErrorId != "" && $(mainErrorId)){
					$(mainErrorId).style.display = "none";
				}
				return true;
			}
	

		}

	},
	
	util: {
		dummy: function(){}
		
	},
	
	/*
		******** Do not modify below this line ****************************************
	*/	
	removeDuplicatesFromArray: function(arrayIn){
		var outArray = [];
		while(arrayIn.length > 1){
			var testMe = arrayIn.pop();
			if(!Ka.formValidation.stringInArray(testMe,arrayIn)){ outArray.push(testMe); }
		}
		if(arrayIn.length == 1){
			outArray.push(arrayIn[0]);
		}
		outArray.reverse(); // restore original order
		return outArray;
	},
	
	cleanStringArray: function(arrayIn){
		var arrayOut = [];
		// remove empty slots:
		for(var i = 0; i < arrayIn.length; i++){
			if(arrayIn[i] != "" && arrayIn[i] != " " && arrayIn[i] != '"'){
				arrayOut.push(Ka.formValidation.removeLeadingAndTrailingSpaces(arrayIn[i]));
			}
		}
		return arrayOut;
	},
	
	removeLeadingAndTrailingSpaces: function(inputString){
		var removeChar = ' ';
		var returnString = inputString;
		while(''+returnString.charAt(0)==' '){
			returnString=returnString.substring(1,returnString.length);
		}
		while(''+returnString.charAt(returnString.length-1)==' '){
			returnString=returnString.substring(0,returnString.length-1);
		}
		return returnString;
	},
	
	hasThisAttribute: function(el,attName){ // because IE doesn't support hasAttribute()
		if(el.getAttribute(attName) || el.getAttribute(attName) == ""){ return true; }else{ return false; }
	},
	
	setAttributeForEachIdStrInArray: function(idStrArray,aName,aValue){
		//console.log('hit');
		for(var i = 0; i < idStrArray.length; i++){
			try{ $(idStrArray[i]).setAttribute(aName,aValue); }
			catch(e){ Ka.alert("error on: idStrArray[i]:",idStrArray[i]); }
		}
	},
	
	elementWithInnerHTML: function(el,str){
		var newEl = document.createElement(el);
		newEl.innerHTML = str;
		return newEl;
	},
	
	radioGroupHasSelection: function(radioGroup){
		var hasSelection = false;
		for(var p=0; p < radioGroup.length; p++){
			if(radioGroup[p].checked){ hasSelection = true; }
		}
		return hasSelection;
	},
		
	stringInArray: function(testStr,arrayObj){
		var inArray = false;
		for(var i=0; i < arrayObj.length; i++){
			if(arrayObj[i] == testStr){
				inArray = true;
			}
		}
		return inArray;
	},

	replaceCharacterWithValue: function(replaceChar,val,inStr){
		var outStr = inStr + "";
		if(outStr.indexOf(replaceChar) >= 0){
			outStr = outStr.split(replaceChar);
			outStr = outStr.join(val);
		}
		return outStr;
	},

	
	showFormFieldError: function(element,messageArray){
		var errorContainerElement;
		// if there is only one message (or message comes from errorkey), use a div instead of ul:
		if(messageArray.length == 1 || Ka.formValidation.hasThisAttribute(element,"errorkey")){ // use a div (only one message to show)
			errorContainerElement = document.createElement("div");
	
			if(Ka.formValidation.hasThisAttribute(element,"errorkey")){ // use key:
				errorContainerElement.innerHTML = Ka.formValidation.messages[element.getAttribute("errorkey")];
			}else{ // use messageArray[0]:
				errorContainerElement.innerHTML = messageArray[0];
			}
		}else{ // use ul (more than one error message to show):
			errorContainerElement = document.createElement("ul");
			for(var i=0; i < messageArray.length; i++){
				errorContainerElement.appendChild(Ka.formValidation.elementWithInnerHTML("li",messageArray[i]));
			}
		}
		// give the error message container a handle we can reference later to remove it:
		errorContainerElement.setAttribute("errormessagecontainer","");
		
		// set css class:
		errorContainerElement.className = Ka.formValidation.config.defaultErrorContainerClass;
		
		// if error-container attribute exists and is not blank, put message there:
		if(Ka.formValidation.hasThisAttribute(element,"error-container") && element.getAttribute("error-container") != ""){
			$(element.getAttribute("error-container")).appendChild(errorContainerElement);
		}else{
			// add the ul element directly above the form element:
			element.parentNode.insertBefore(errorContainerElement, element);
		}
	},
	
	removeFormFieldErrorMessages: function(element){
		// if error-container attribute exists and is not blank, clear it:
		if(Ka.formValidation.hasThisAttribute(element,"error-container") && element.getAttribute("error-container") != ""){
			$(element.getAttribute("error-container")).innerHTML = "";
		}else{
			// if the previousSibling has the 'errormessagecontainer' attribute, remove it:
			if(!element.previousSibling){ return; }
			if(element.previousSibling.nodeType == 1){ // make sure it isn't a text node (would be a 3)
				
				if(Ka.formValidation.hasThisAttribute(element.previousSibling,"errormessagecontainer")){
					// remove it:
					element.parentNode.removeChild(element.previousSibling);
				}
			}
		}
	},
	
	/********************************************************
	Ka.formValidation.textAreaMax
	********************************************************/
	textAreaMax: {
		intializeTextAreaCharacterLimits: function(){
			var textareas = document.getElementsByTagName("textarea");
			for(var j=0; j < textareas.length; j++){
				if(textareas[j].getAttribute("maxlength")){
					Ka.formValidation.textAreaMax.makeTextareaCharacterLimit(textareas[j]);
				}
			}
		},

		makeTextareaCharacterLimit: function(ta){
			var charLimit = parseInt(ta.getAttribute("maxlength"));
			// to access this value more easily later, set as a property of ta:
			ta.max = charLimit;
			var currentLength = ta.value.length;
			
			// create UI feedback elements:
			var newDiv = document.createElement("div");
			newDiv.className = "textareaCharacterCountDisplay";
			var statusStr = Ka.Messages.CHARACTERSLEFT.replace("($count)", "<span>"+(charLimit-currentLength)+"</span>").replace("($count2)",charLimit);
			newDiv.innerHTML = statusStr;
			
			// insert UI feedback elements before textarea:
			ta.parentNode.insertBefore(newDiv, ta);
			
			// add event handlers to monitor textarea:
			ta.onkeyup = Ka.formValidation.textAreaMax.textareaUpdateCharacterLength;
			ta.onchange = Ka.formValidation.textAreaMax.textareaUpdateCharacterLength;
		},
		
		textareaUpdateCharacterLength: function(){
			var currentLength = this.value.length;
			// if length exceeds max, chop
			if(currentLength > this.max){
				this.value = this.value.substr(0,this.max); // chop
				currentLength = this.value.length; // get new length
			}
			// target span that displays remaining characters:
			// - there may be an error message that was injected between the textarea and the character-limit container
			// if the previousSibling has a className of 'textareaCharacterCountDisplay', we're good;
			var displaySpan;
			if(this.previousSibling.className == "textareaCharacterCountDisplay"){
				displaySpan = this.previousSibling.getElementsByTagName("span")[0];
			}else{
				displaySpan = this.previousSibling.previousSibling.getElementsByTagName("span")[0];
			}
			// update UI with new length:
			displaySpan.innerHTML = this.max - currentLength;
		}
	},

	/********************************************************
		Ka.formValidation.tags
	********************************************************/
	tags: {
		doubleQuoteLocations: function(strIn){
			var q = '"';
			var resultArray = [];
			if(strIn.indexOf(q) == -1){ return resultArray; }
			for(var i = 0; i < strIn.length; i++){
				if(strIn.charAt(i) == q){ resultArray.push(i); }
			}
			return resultArray;
		},

		buildDataStringForSubmission: function(tagArray){
			var outStr = '';
			var quote = '"';
			var space = ' ';
			for(var i=0; i < tagArray.length; i++){
				if(i > 0){ outStr += space; }
				if(tagArray[i].indexOf(space) != -1){ // has spaces
					outStr += quote + tagArray[i] + quote;
				}else{ // no spaces
					outStr += tagArray[i];
				}
			}
			return outStr;
		},
		
		buildTagArrayManually: function(qLocAry,strIn){
			var arrayOut = [];
			// first push in anything before first quote:
			var beforeQuotes = strIn.substring(0,qLocAry[0]);
			arrayOut = Ka.formValidation.tags.transferToTagArrayAfterSplit(beforeQuotes,arrayOut);
			
			for(var i=0; i < qLocAry.length; i = i + 2){
				// add content in quotes:
				var inQuotes = strIn.substring(qLocAry[i] + 1,qLocAry[i+1]); 
				arrayOut.push(inQuotes);
				// add content outside quotes, if there is any more:
				if(qLocAry[i+2] < (strIn.length-1)){
					var outQuotes = strIn.substring(qLocAry[i+1] + 1,qLocAry[i+2]);
					arrayOut = Ka.formValidation.tags.transferToTagArrayAfterSplit(outQuotes,arrayOut);
				}
			}
			// push in anything after last quote:
			var afterQuotes = strIn.substring(qLocAry[qLocAry.length-1],strIn.length); 
			
			if(afterQuotes.indexOf(" ") > -1){
				var tempArray = afterQuotes.split(" ");
				for(var j=0; j < tempArray.length; j++){ arrayOut.push(tempArray[j]); }
			}else{
				arrayOut.push(afterQuotes);
			}
			return arrayOut;
		},

		transferToTagArrayAfterSplit: function(testStr,arrayToAddTo){
			if(testStr.indexOf(" ") > -1){
				var tempArray = testStr.split(" ");
				for(var j=0; j < tempArray.length; j++){ arrayToAddTo.push(tempArray[j]); }
			}else{
				arrayToAddTo.push(testStr);
			}
			return arrayToAddTo;
		}
		
	},
		
/* KILL THIS METHOD WHEN DONE */
	validateForm: function(thisForm,mainErrorId,errorContainerClass){
		if(errorContainerClass){
			Ka.formValidation.config.defaultErrorContainerClass = errorContainerClass;
		}
		var elements = thisForm.elements;
		var formHasProblems = false;
		var radioNameArray = [];
/* KILL THIS METHOD WHEN DONE */	
		// clear all error messages first:
		for(var j=0; j < elements.length; j++){
			Ka.formValidation.removeFormFieldErrorMessages(elements[j]);
		}
/* KILL THIS METHOD WHEN DONE */	
		for(var j=0; j < elements.length; j++){ // cycle through form elements...
			// so, tell me about this element....
			var elementType = elements[j].getAttribute("type");
			var elementName = elements[j].getAttribute("name");
			var elementValue = elements[j].value;
/* KILL THIS METHOD WHEN DONE */			
			var skipThisElement = false;
/* KILL THIS METHOD WHEN DONE */			
			// override?
			if(elements[j].getAttribute("do-not-validate") == "true"){
				skipThisElement = true;
			}
/* KILL THIS METHOD WHEN DONE */			
			// Any of the following conditions should supress the validation of this element:
			if( // the field is NOT required, AND it is empty, AND it isn't dependent on another element
				((!elements[j].getAttribute("required"))||(elements[j].getAttribute("required") == "false")) // not required
				&& 
				elementValue == "" // is empty
				&&
				((!elements[j].getAttribute("depends-on"))||(elements[j].getAttribute("depends-on") == "")) // isn't dependent on another element
			){ skipThisElement = true; }
			if( // - (it is a radio button) whose group has already been checked
				Ka.formValidation.stringInArray(elementName,radioNameArray) // this field's name can only be in radioNameArray if it has been checked
			){ skipThisElement = true; }
	
			if(skipThisElement){
				// do not validate...
/* KILL THIS METHOD WHEN DONE */
			}else{ // validate:
				var errorMessages = [];
				for(var k=0; k < Ka.formValidation.rulesArray.length; k++){ // cycle through rules...
					// test to see if this value should be checked against this rule:
					if(
						elements[j].getAttribute(Ka.formValidation.rulesArray[k].ruleName) // attribute exists
						&&
						elements[j].getAttribute(Ka.formValidation.rulesArray[k].ruleName) != "false" // and isn't 'false'
					){
						var attributeValue = elements[j].getAttribute(Ka.formValidation.rulesArray[k].ruleName);
						// is this a radio button?
						if(elementType == "radio"){
							// add name to 'radioNameArray' so group will no be checked again 
							radioNameArray.push(elementName);
							// are any in the group selected?
							if(Ka.formValidation.radioGroupHasSelection(thisForm[elementName])){
								elementValue = "checked"; // fake a value
							}else{
								elementValue = ""; // simulate empty value
							}
						}
/* KILL THIS METHOD WHEN DONE */	
						// if this is a checkbox?
						if(elementType=="checkbox"){
							if(elements[j].checked){
								elementValue = "checked"; // fake a value
							}else{
								elementValue = ""; // simulate empty value
							}
						}
/* KILL THIS METHOD WHEN DONE */						
						if(!(Ka.formValidation.rulesArray[k].test(elementValue,attributeValue,elements[j]))){ // failed test
							var thisMessage = Ka.formValidation.rulesArray[k].message;
							// if the message contains '%', replace it with attributeValue
							thisMessage = Ka.formValidation.replaceCharacterWithValue("%",attributeValue,thisMessage);
							
							// add error message to array:
							errorMessages.push(thisMessage);
						}
					} 
				}
/* KILL THIS METHOD WHEN DONE */
				if(errorMessages.length){ // this field has errors that need to be displayed
					formHasProblems = true; // the form as a whole has failed validation
					// display messages:
					Ka.formValidation.showFormFieldError(elements[j],errorMessages);
				}
			}
		}
/* KILL THIS METHOD WHEN DONE */		
		if(formHasProblems){ // there are form errors
			// unhide main error message at top of form
			if(mainErrorId != ""){
				$(mainErrorId).style.display = "block";
				window.location.href = "#"+mainErrorId;
			}
/* KILL THIS METHOD WHEN DONE */		
			return false;
		}else{
			// hide main error message at top of form
			if(mainErrorId != ""){
				$(mainErrorId).style.display = "none";
			}
			return true;
		}
	},

/*KILL THIS WHEN DONE */		
	// add rules as needed
	rulesArray: [ 
	// validation rules array (return true if data validates ok, false if data fails validation):
		{
			ruleName:"required",
			message:Ka.Messages.REQFIELD,
			test:function(val,propVal){
				if(val == ""){
					return false;
				}else{
					return true;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"is-tags",
			message:Ka.Messages.CLOSEOPENQUOTES,
			test:function(val,propVal,element){
				// first strip out any new-line characters:
				if(val.indexOf("\n") != -1){
					val = val.split("\n");
					val = val.join(" ");
				}
				var qArray = Ka.formValidation.tags.doubleQuoteLocations(val);
				if((qArray.length % 2) != 0){ // double-quote number is off
					return false;
				}
/*KILL THIS WHEN DONE */
				var tagArray; // this will hold the array of tags
				// if there are no quotes, just split on space:
				if(qArray.length == 0){
					tagArray = val.split(" ");
				}else{ // ok, manual labor time...
					tagArray = Ka.formValidation.tags.buildTagArrayManually(qArray,val);
				}
				
				tagArray = Ka.formValidation.cleanStringArray(tagArray);
				tagArray = Ka.formValidation.removeDuplicatesFromArray(tagArray);
				
				var outStr = Ka.formValidation.tags.buildDataStringForSubmission(tagArray);
				element.value = outStr;
				return true;
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"is-url",
			message:"Please enter a valid URL, like 'www.example.com'.",
			test:function(val,propVal){
				val = val + "";
				if(!(val.indexOf("http://") == 0 || val.indexOf("https://") == 0)){
					val = "http://" + val;
				}
				var urlRegX = /^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(([0-9]{1,5})?\/.*)?$/;
				if(urlRegX.test(val)){
					return true;
				}else{
					return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"is-integer",
			message:"This field must be a number",
			test:function(val,propVal){
				if(isNaN(parseInt(val, 10))){
					return false;
				}else{
					return true;
				}
			}
		},
/*KILL THIS WHEN DONE */	
		{
			ruleName:"no-spaces",
			message:"This field cannot contain spaces",
			test:function(val,propVal){
				if(val.indexOf(" ") == -1){
					return true;
				}else{
					return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"no-dash",
			message:"Please select a state",
			test:function(val,propVal){
				if(val.indexOf("-") == -1){
					return true;
				}else{
					return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"canada-postal-code",
			message:"Please enter a valid Canadian postal code",
			test:function(val,propVal){
				val = val + ""; // make sure it's data type is String
				switch(val.length){ // needs to be 6 or 7 characters long
					case 6 :
						var CaZipSix = /[A-Za-z]\d[A-Za-z]\d[A-Za-z]\d/;
						if(CaZipSix.test(val)){ return true; }else{ return false; }
						break;
					case 7 :
						var CaZipSeven = /[A-Za-z]\d[A-Za-z][ -]\d[A-Za-z]\d/;
						if(CaZipSeven.test(val)){ return true; }else{ return false; }
						break;
					default :
						return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"us-postal-code",
			message:"Please enter a valid US postal code",
			test:function(val,propVal){
				val = val + ""; // make sure it's data type is String
				switch(val.length){ // needs to be 5 or 10 characters long
					case 5 :
						var UsZipFive = /\d{5}/;
						if(UsZipFive.test(val)){ return true; }else{ return false; }
						break;
					case 10 :
						var UsZipTen = /\d{5}[ -]\d{4}/;
						if(UsZipTen.test(val)){ return true; }else{ return false; }
						break;
					default :
						return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"number-min",
			message:"This value must be equal-to or greater than %, because % is the lowest we go",
			test:function(val,propVal){
				// make sure we're dealing with numbers:
				val = parseFloat(val); propVal = parseFloat(propVal);
				if(val >= propVal){
					return true;
				}else{
					return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"number-max",
			message:"This value must be equal-to or less than %",
			test:function(val,propVal){
				// make sure we're dealing with numbers:
				val = parseFloat(val); propVal = parseFloat(propVal);
				if(val <= propVal){
					return true;
				}else{
					return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"is-email",
			message:"Please enter a valid email address",
			test:function(val,propVal){
				var emailFilter = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
				if(emailFilter.test(val)){
					return true;
				}else{
					return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"is-alpha-numeric",
			message:"This field accepts only letters, numbers and the underscore (_)",
			test:function(val,propVal){
				var nonAlphaRegX = /\W/;
				if(nonAlphaRegX.test(val)){
					return false;
				}else{
					return true;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"depends-on",
			message:Ka.Messages.REQFIELD,
			test:function(val,propVal){ // this field has a problem if it is empty AND any of it's counterparts has a value:
				// if not empty, we're done:
				if(val != ""){ return true; }
				// field is empty...
	
				var idArray;
				if(propVal.indexOf(",") == -1){ idArray = [propVal]; }else{ idArray = propVal.split(","); }
				
				var othersEmpty = true;
				for(var i = 0; i < idArray.length; i++){
					if($(idArray[i]).value != ""){ othersEmpty = false; }
				}
				return othersEmpty;
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"password-match-with",
			message:"Your passwords must match exactly.",
			test:function(val,propVal){
				if(val == $(propVal).value){
					return true;
				}else{
					return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"email-and-or-member-list-twenty-max",
			message:"Please enter comma-separated, valid email addresses and/or usernames",
			test:function(val,propVal,element){
				var emailArray;
				if(val.indexOf(",") != -1){ // split...
					emailArray = val.split(",");
				}else{ // just push value
					emailArray = [val];
				}
				// clean up:
				emailArray = Ka.formValidation.cleanStringArray(emailArray);
				emailArray = Ka.formValidation.removeDuplicatesFromArray(emailArray);
				
				// update value:
				var outStr = emailArray.join(", ");
				element.value = outStr;
/*KILL THIS WHEN DONE */				
				var allEmailsValid = true;
				for(var i=0; i < emailArray.length; i++){
					if(
						!Ka.formValidation.rulesArray[9].test(emailArray[i])
						&&
						!Ka.formValidation.rulesArray[10].test(emailArray[i])
					){
						allEmailsValid = false;
					}
				}
				if(allEmailsValid && emailArray.length <= 20){
					return true;
				}else{ // handle errors, then return false
					if(!allEmailsValid){ element.setAttribute("errorkey","invalidEmailAddresses"); }
					if(emailArray.length > 20){ element.setAttribute("errorkey","emailListTwentyMax"); }
					return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"min-characters",
			message:"This field requires at least % characters",
			test:function(val,propVal){
				// make sure we're dealing with correct data types:
				propVal = parseFloat(propVal);
				val = val + "";
				if(val.length < propVal){
					return false;
				}else{
					return true;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"email-list",
			message:"Invalid email address(es).",
			test:function(val,propVal,element){
				var emailArray;
				if(val.indexOf(",") != -1){ // split...
					emailArray = val.split(",");
				}else{ // just push value
					emailArray = [val];
				}
				// clean up:
				emailArray = Ka.formValidation.cleanStringArray(emailArray);
				emailArray = Ka.formValidation.removeDuplicatesFromArray(emailArray);
				
				// update value:
				var outStr = emailArray.join(", ");
				element.value = outStr;
				
				var allEmailsValid = true;
				for(var i=0; i < emailArray.length; i++){
					if(!Ka.formValidation.rulesArray[9].test(emailArray[i])){
						allEmailsValid = false;
					}
				}
				if(allEmailsValid){
					return true;
				}else{
					return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"not-equal-to",
			message:"This value cannot be %",
			test:function(val,propVal){
				if(val == propVal){
					return false;
				}else{
					return true;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"length-min",
			message:"Enter more than % characters",
			test:function(val,propVal){
				// make sure we're dealing with correct data-types:
				val = val + ""; propVal = parseFloat(propVal);
				if(val.length >= propVal || val.length == 0){
					return true;
				}else{
					return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:"length-max",
			message:"Enter less than % characters and spaces for this field.",
			test:function(val,propVal){
				// make sure we're dealing with correct data-types:
				val = val + ""; propVal = parseFloat(propVal);
				if(val.length <= propVal){
					return true;
				}else{
					return false;
				}
			}
		},
/*KILL THIS WHEN DONE */		
		{
			ruleName:	"min-age",
			message:	"You must be at least 13 years old to join.",
			test:		function(val,propVal)
						{
							// get the dates
							var bday     	  =    document.getElementById(val.split(',')[0]).value;
							var bmonth    	  =    document.getElementById(val.split(',')[1]).value;
							var byear    	  =    document.getElementById(val.split(',')[2]).value;

							// parse them
							bday			  =    bday=='Select' ? 0 : parseInt(bday);
							bmonth			  =    bmonth=='Select' ? 0 : parseInt(bmonth) - 1;
							byear			  =    byear=='Select' ? 0 : parseInt(byear);

 							// get the current date info.
							var now    		  =    new Date();
							cday      		  =	   now.getDate();
							cmonth			  =    now.getMonth();
							cyear			  =	   now.getFullYear();

							// if the current month is greater than the birthday month, or the current month is equal to the birthday month, and the current day is equal to or greater than the birthday day
							if((cmonth > bmonth) || (cmonth==bmonth && cday>=bday))
							{
								// set the age to the year
								var age    =    byear;
								age		   =	cyear-age;
							}
							// 
							else
							{
								// set the age to the year plus 1, since their birthday hasn't been hit yet
								var age    =    byear+1;
								age		   =	cyear-age;
 							}
 							// return the status of an age check
 							return (age>=propVal ? true : false);
						}
		}
/*KILL THIS WHEN DONE */		
	]
	
};


// initialize text area maxlength functionality:
Ka.addDOMLoadEvent(Ka.formValidation.textAreaMax.intializeTextAreaCharacterLimits);
// iniitalize validator
Ka.addDOMLoadEvent(Ka.formValidation.events.onInit);