// Validate the form fields for register.asp and submit to Chase
function ValidateRegistration() {

	var cCountry = document.getElementById('rvarHotelCountry').value;

	if(cCountry < 1){
		alert("You have not selected your country.");
		document.getElementById('rvarHotelCountry').focus();
		return false;
	}

	document.getElementById('UFName' + cCountry).value = RemoveJavaInjection(document.getElementById('UFName' + cCountry).value);
	if(!testLength(document.getElementById('UFName' + cCountry).value, 1, 25)){
		alert("You have not entered your first name.");
		document.getElementById('UFName' + cCountry).focus();
		return false;
	}
	
	document.getElementById('ULName' + cCountry).value = RemoveJavaInjection(document.getElementById('ULName' + cCountry).value);
	if(!testLength(document.getElementById('ULName' + cCountry).value, 1, 50)){
		alert("You have not entered your last name.");
		document.getElementById('ULName' + cCountry).focus();
		return false;
	}
	
	document.getElementById('UserName' + cCountry).value = RemoveJavaInjection(document.getElementById('UserName' + cCountry).value);
	if(!testLength(document.getElementById('UserName' + cCountry).value, 6, 25)){
		alert("Your user name must be between 6 and 25 characters.");
		document.getElementById('UserName' + cCountry).focus();
		return false;
	} else if(CheckForSpaces(document.getElementById('UserName' + cCountry).value)){
		alert("Your user name can not contain blank spaces.");
		document.getElementById('UserName' + cCountry).focus();
		return false;
	}
	
	document.getElementById('UPword' + cCountry).value = RemoveJavaInjection(document.getElementById('UPword' + cCountry).value);
	document.getElementById('UPword_Conf' + cCountry).value = RemoveJavaInjection(document.getElementById('UPword_Conf' + cCountry).value);
	if(!verifyPasswords(document.getElementById('UPword' + cCountry).value, document.getElementById('UPword_Conf' + cCountry).value, document.getElementById('UserName' + cCountry).value)){
		document.getElementById('UPword' + cCountry).value = "";
		document.getElementById('UPword_Conf' + cCountry).value = "";
		document.getElementById('UPword' + cCountry).focus();
	return false;
	}
	
	document.getElementById('ContactTitle' + cCountry).value = RemoveJavaInjection(document.getElementById('ContactTitle' + cCountry).value);
	if(!testLength(document.getElementById('ContactTitle' + cCountry).value, 1, 100)){
		alert("You have not entered your title.");
		document.getElementById('ContactTitle' + cCountry).focus();
		return false;
	}
	
	document.getElementById('HotelEmail' + cCountry).value = RemoveJavaInjection(document.getElementById('HotelEmail' + cCountry).value);
	if(!testLength(document.getElementById('HotelEmail' + cCountry).value, 1, 150)){
		alert("You have not entered your email address.");
		document.getElementById('HotelEmail' + cCountry).focus();
		return false;
	}
	
	document.getElementById('HotelWebsite' + cCountry).value = RemoveJavaInjection(document.getElementById('HotelWebsite' + cCountry).value);
	
	document.getElementById('HotelName' + cCountry).value = RemoveJavaInjection(document.getElementById('HotelName' + cCountry).value);
	if(!testLength(document.getElementById('HotelName' + cCountry).value, 1, 150)){
		alert("You have not entered the name of the hotel.");
		document.getElementById('HotelName' + cCountry).focus();
		return false;
	}
	
	document.getElementById('HotelAddress' + cCountry).value = RemoveJavaInjection(document.getElementById('HotelAddress' + cCountry).value);
	if(!testLength(document.getElementById('HotelAddress' + cCountry).value, 1, 250)){
		alert("You have not entered the hotel address.");
		document.getElementById('HotelAddress' + cCountry).focus();
		return false;
	}
	
	document.getElementById('HotelCity' + cCountry).value = RemoveJavaInjection(document.getElementById('HotelCity' + cCountry).value);
	if(!testLength(document.getElementById('HotelCity' + cCountry).value, 1, 50)){
		alert("You have not entered the hotel city.");
		document.getElementById('HotelCity' + cCountry).focus();
		return false;
	}
	
	if(!testLength(document.getElementById('HotelProvince' + cCountry).value, 1, 50)){
		alert("You have not selected your " + document.getElementById('ProvinceLabel' + cCountry).innerHTML.toLowerCase() + ".");
		document.getElementById('HotelProvince' + cCountry).focus();
		return false;
	}

	document.getElementById('HotelPostalCode' + cCountry).value = RemoveJavaInjection(document.getElementById('HotelPostalCode' + cCountry).value);
	if(!testLength(document.getElementById('HotelPostalCode' + cCountry).value, 1, 10)){
		alert("You have not entered the " + document.getElementById('PostalCodeLabel' + cCountry).innerHTML.toLowerCase() + ".");
		document.getElementById('HotelPostalCode' + cCountry).focus();
		return false;
	} 
	
	document.getElementById('HotelPhone' + cCountry).value = RemoveJavaInjection(document.getElementById('HotelPhone' + cCountry).value);
	if(!testLength(document.getElementById('HotelPhone' + cCountry).value, 1, 25)){
		alert("You have not entered your phone number.");
		document.getElementById('HotelPhone' + cCountry).focus();
		return false;
	}
	
	document.getElementById('HotelFax' + cCountry).value = RemoveJavaInjection(document.getElementById('HotelFax' + cCountry).value);
	if(!testLength(document.getElementById('HotelFax' + cCountry).value, 1, 25)){
		alert("You have not entered your fax number.");
		document.getElementById('HotelFax' + cCountry).focus();
		return false;
	}
	
	document.getElementById('NoofRooms' + cCountry).value = RemoveJavaInjection(document.getElementById('NoofRooms' + cCountry).value);
	if(isNaN(document.getElementById('NoofRooms' + cCountry).value)){
		document.getElementById('NoofRooms' + cCountry).value = "";
		alert("You have not entered a valid number of rooms.");
		document.getElementById('NoofRooms' + cCountry).focus();
		return false;
	} else if(document.getElementById('NoofRooms' + cCountry).value < 1){
		document.getElementById('NoofRooms' + cCountry).value = "";
		alert("You have not entered a valid number of rooms.");
		document.getElementById('NoofRooms' + cCountry).focus();
		return false;
	}
	
	document.getElementById('NoofEmployees' + cCountry).value = RemoveJavaInjection(document.getElementById('NoofEmployees' + cCountry).value);
	if(isNaN(document.getElementById('NoofEmployees' + cCountry).value)){
		document.getElementById('NoofEmployees' + cCountry).value = "";
		alert("You have not entered a valid number of employees.");
		document.getElementById('NoofEmployees' + cCountry).focus();
		return false;
	} else if(document.getElementById('NoofEmployees' + cCountry).value < 1){
		document.getElementById('NoofEmployees' + cCountry).value = "";
		alert("You have not entered a valid number of employees.");
		document.getElementById('NoofEmployees' + cCountry).focus();
		return false;
	}
	
	if (document.getElementById('Terms' + cCountry).checked == false ){
		alert("You have not accepted the program terms and conditions.");
		document.getElementById('Terms' + cCountry).focus();
		return false;
	}

	// Check for any discount from promo codes
	document.getElementById('PromoCode' + cCountry).value = Trim(document.getElementById('PromoCode' + cCountry).value);
	var nDiscount = CalculateDiscount(document.getElementById('PromoCode' + cCountry).value.toUpperCase(), ReverseString(document.getElementById('Code' + cCountry).value));
	if (nDiscount < 0){
		document.getElementById('PromoCode' + cCountry).value = "";
		document.getElementById('PromoCode' + cCountry).focus();
		alert("You have entered an invalid promo code.");
		return false;
	}

	// The form has been properly completed so calculate the registration fee and prepare to send to Chase
	var nBaseFee = Number(document.getElementById('RegistrationFee' + cCountry).value);
	
	// If the promo code discount is greater than the base fee than set the discount to the base fee
	if (nDiscount > nBaseFee){
		nDiscount = nBaseFee;
	}
	
	// Calculate the tax rate if any for this registration
	// First we will check if the Province/State/Region has a tax rate associated with it
	var cRegion = document.getElementById('HotelProvince' + cCountry).value;
	var cTaxRate = "";
	var cChar = "";
	var lFound = false;
	for (nLoop = 0; nLoop<=cRegion.length; nLoop++){
		cChar = cRegion.charAt(nLoop);
		if (cChar == "["){
			// Found the start of the regional tax rate
			lFound = true;
		} else if (cChar == "]"){
			// Found the end of the regional tax rate.  Do nothing
		} else if (lFound){
			// Character is part of the regional tax rate
			cTaxRate += cChar;
		}
	}
	// If the regional tax rate is '0' then use the country tax rate for this registration
	if (cTaxRate == "0"){
		cTaxRate = document.getElementById('TaxRate' + cCountry).value;
	}

	// Calculate the grand total that the hotel will pay including tax
	var nTotalFee = Math.round((nBaseFee - nDiscount) * (1 + Number(cTaxRate))*100)/100;

	// Calculate the tax on the invoice and store in form field for submission to Chase
	nTax = Math.round((nTotalFee - (nBaseFee - nDiscount))*100)/100;
	document.getElementById('x_tax').value = nTax;
	
	// Update invoice details in form field for submission to Chase
	if (nTax > 0){
		cTax = "YES";
	} else {
		cTax = "NO";
	}
	document.getElementById('x_line_item1').value = "GK<|>Green Key Program Registration Fee<|>Green Key Program Registration Fee<|>1<|>" + (nBaseFee) + "<|>" + cTax;
	
	// Update promo details in form field for submission to Chase
	if (nDiscount > 0) {
		document.getElementById('x_line_item2').name = "x_line_item";
		document.getElementById('x_line_item2').value = "PROMO<|>Promo Code - " + document.getElementById('PromoCode' + cCountry).value.toUpperCase() +"<|>Promo Code - " + document.getElementById('PromoCode' + cCountry).value.toUpperCase() +"<|>1<|>-" + nDiscount + "<|>NO";
	}
	
	// Store registration fee in form field for submission to Chase
	document.getElementById('x_amount').value = nTotalFee;
	
	// Store currency code in form field for submission to Chase
	document.getElementById('x_currency_code').value = document.getElementById('Currency' + cCountry).value;
	
	// Store client email in form field for submission to Chase
	document.getElementById('x_email').value = document.getElementById('HotelEmail' + cCountry).value;
	
	// Store payment page in form field for submission to Chase
	document.getElementById('x_login').value = document.getElementById('PaymentPage' + cCountry).value;
	
	// Store other info in form field for submission to Chase
	document.getElementById('x_company').value = document.getElementById('HotelName' + cCountry).value;
	document.getElementById('x_first_name').value = document.getElementById('UFName' + cCountry).value;
	document.getElementById('x_last_name').value = document.getElementById('ULName' + cCountry).value;

	// Code block calculates x_fp_timestamp for E-xact submmission
	// Store current date and time according to Magma server at the time the registration.asp page was loaded. Server is Eastern Standard Time.
	var dDate = new Date(document.getElementById('x_ServerDate').value + ' ' + document.getElementById('x_ServerTime').value);
	// Calculate users time zone
	var nTimeZoneOffset = dDate.getTimezoneOffset() / 60;
	// Calculate how many hours difference between the users time zone and EST
	nTimeZoneOffset = 4 - nTimeZoneOffset;
	// Calculate UTC time.  Divide by 1000 to shave off milliseconds
	var nUTC = Date.parse(dDate.toUTCString()) / 1000;
	// Add time zone difference as seconds
	nUTC = nUTC + (nTimeZoneOffset * 3600);
	// Add 10 minutes to the time that the user loaded register.asp to maximize chance that E-xact will accept time stamp
	nUTC = nUTC + 600;
	// Store UTC time in form field for submission to Chase.  Add 600 seconds to 
	document.getElementById('x_fp_timestamp').value = nUTC;

	// Calculate hash for and store in form field for submission to Chase
	document.getElementById('x_fp_hash').value = hex_hmac_md5(document.getElementById('Key' + cCountry).value, document.getElementById('x_login').value + "^" + document.getElementById('x_fp_sequence').value + "^" + document.getElementById('x_fp_timestamp').value + "^" + document.getElementById('x_amount').value + "^" + document.getElementById('x_currency_code').value);

	// This if block was modified on 07/12/2010 when it was decided that all online registrations would need to be paid with a credit card
	// if (document.getElementById('PayByCreditCard' + cCountry).checked && nTotalFee > 0){

	// If block replaced with this check that nTotalFee > $0.00
	if (nTotalFee > 0){
		// Client is paying fee by credit card so submit form to Chase for processing
		document.forms[0].submit();
	} else {
		// Old code to support pay by cheque option
		// Client is paying by cheque
		// document.getElementById('x_response_code').value = "CHEQUE";
		// document.getElementById('TransactionCardType').value = document.getElementById('PayByCheque' + cCountry).value;
		// document.forms[0].action = "completeregistration.asp";
		// document.forms[0].submit();

		// New code to complete registration if registering hotel uses a promo code that creates an invoice for $0.00
		document.getElementById('x_response_code').value = "PREPAID";
		document.getElementById('TransactionCardType').value = "PREPAID";
		document.forms[0].action = "completeregistration.asp";
		document.forms[0].submit();
	}

}

// Trims the string and returns "" if there is any hint of a user trying to insert scripting
function RemoveJavaInjection (cText) {

	cText = Trim(cText);

	// Check if user has entered a valid promo code and return the discount if they have
	var lFound = false;
	for (nLoop = 0; nLoop<=cText.length; nLoop++){
		cChar = cText.charAt(nLoop)
		if (lFound){
			// We have found the < character
			if (cChar == " "){
				// Keep looking for an "s"
			} else if (cChar == "s"){
				// Signs of java scripting detected so reject string
				return "";
			} else {
				// This < character looks ok so keep checking string
				lFound = false;
			}
		} else if (cChar == "<"){
			lFound = true;
		}
	}

	return cText;

}

// Returns True if the length of the cText variable is between the nMin and nMax paramaters
function testLength(cText, nMin, nMax) {
	
	if((cText.length < nMin) || (cText.length > nMax)){
		return false;
	} else {
		return true;
	}

}

// Prints out a table based on the provided table id
function PrintTable(cTableId, cDocumentTitle) {

	var cDisplaySettings="toolbar=yes, location=no, irectories=yes, menubar=yes, scrollbars=yes, width=750, height=600, left=100, top=25";
	var cInnerHtml = document.getElementById(cTableId).innerHTML;
	var oDocument=window.open("","",cDisplaySettings);
	oDocument.document.open();
	oDocument.document.write('<html><head><title>' + cDocumentTitle + '</title></head>');
	oDocument.document.write('<body style="font-family:verdana; font-size:12px;" onLoad="self.print();self.close();" >');
	oDocument.document.write(cInnerHtml);
	oDocument.document.write('</body></html>');
	oDocument.document.close();
	return false;
	
}

// Replaces special characters for POST/GET situations to html standards
function UrlEncode (str) {
 
    var hexStr = function (dec) {
        return '%' + dec.toString(16).toUpperCase();
    };
 
    var ret = '',
            unreserved = /[\w.-]/; // A-Za-z0-9_.- // Tilde is not here for historical reasons; to preserve it, use rawurlencode instead
    str = (str+'').toString();
 
    for (var i = 0, dl = str.length; i < dl; i++) {
        var ch = str.charAt(i);
        if (unreserved.test(ch)) {
            ret += ch;
        }
        else {
            var code = str.charCodeAt(i);
            // Reserved assumed to be in UTF-8, as in PHP
            if (code === 32) {
                ret += '+'; // %20 in rawurlencode
            }
            else if (code < 128) { // 1 byte
                ret += hexStr(code);
            }
            else if (code >= 128 && code < 2048) { // 2 bytes
                ret += hexStr((code >> 6) | 0xC0);
                ret += hexStr((code & 0x3F) | 0x80);
            }
            else if (code >= 2048 && code < 65536) { // 3 bytes
                ret += hexStr((code >> 12) | 0xE0);
                ret += hexStr(((code >> 6) & 0x3F) | 0x80);
                ret += hexStr((code & 0x3F) | 0x80);
            }
            else if (code >= 65536) { // 4 bytes
                ret += hexStr((code >> 18) | 0xF0);
                ret += hexStr(((code >> 12) & 0x3F) | 0x80);
                ret += hexStr(((code >> 6) & 0x3F) | 0x80);
                ret += hexStr((code & 0x3F) | 0x80);
            }
        }
    }
    return ret;
}

// Returns a string with leading spaces removed
function Ltrim(cText) { 
	for(var nLoop = 0; nLoop < cText.length && IsSpace(cText.charAt(nLoop)); nLoop++);
	return cText.substring(nLoop, cText.length);
}

// Returns a string with trailing spaces removed
function Rtrim(cText) {
	for(var nLoop = cText.length - 1; nLoop >= 0 && IsSpace(cText.charAt(nLoop)); nLoop--);
	return cText.substring(0, nLoop + 1);
}

// Returns a string with leading & trailing spaces removed
function Trim(cText) {
	return Ltrim(Rtrim(cText));
}

// Returns true if character passed is a space
function IsSpace(cChar) {
	var cSpaceChars = " \t\n\r\f";
	return (cSpaceChars.indexOf(cChar) != -1);
}
	
// Returns the discount for any promo code that has been entered
// Returns -1 for an invalid promo code
function CalculateDiscount (cPromoCodeEntered, cPromoCodes) {

	// No promo code entered so no discount
	if (cPromoCodeEntered == "") return 0;
	// No promo codes available for this country so return error
	if (cPromoCodes == "") return -1;

	// Check if user has entered a valid promo code and return the discount if they have
	var cDataBlock = "";
	var lPromoCode = true;
	var lFound = false;
	for (nLoop = 0; nLoop<=cPromoCodes.length; nLoop++){
		cChar = cPromoCodes.charAt(nLoop)
		if (cChar == "^"){
			// Found the end of a block of data
			if (lPromoCode){
				lPromoCode = false;
				if (cDataBlock == cPromoCodeEntered){
					// Found the keyed promo code so set trigger to figure out the discount
					lFound = true;
				}
			} else {
				lPromoCode = true;
				if (lFound){
					return LettersToNumber(cDataBlock);
				}
			}
			cDataBlock = "";
		} else {
			cDataBlock += cChar
		}
	}

	// Could not locate the promo code that was entered
	return -1;

}

// Returns a batch of letters as a number.  A=1,B=2,...,J=0,K=.
function LettersToNumber(cNumber) {

	var cReturn = "";

	for (nLoop = 0; nLoop<=cNumber.length; nLoop++){
		cChar = cNumber.charAt(nLoop)
		if (cChar == "A"){
			cReturn += "1";
		} else if (cChar == "B"){
			cReturn += "2";
		} else if (cChar == "C"){
			cReturn += "3";
		} else if (cChar == "D"){
			cReturn += "4";
		} else if (cChar == "E"){
			cReturn += "5";
		} else if (cChar == "F"){
			cReturn += "6";
		} else if (cChar == "G"){
			cReturn += "7";
		} else if (cChar == "H"){
			cReturn += "8";
		} else if (cChar == "I"){
			cReturn += "9";
		} else if (cChar == "J"){
			cReturn += "0";
		} else if (cChar == "K"){
			cReturn += ".";
		}
	}
	
	return parseFloat(cReturn);
	
}

// Returns TRUE if the provided text has any blank spaces in it
function CheckForSpaces(cText) {

	for (nLoop = 0; nLoop <= cText.length; nLoop++){
		cChar = cText.charAt(nLoop)
		if (cChar == " "){
			return true;
		}
	}
	
	return false;
	
}

// Returns the reverse of a string
function ReverseString (cString) {

	if (!cString) return "";
	
	var cReverse = "";

	for (nLoop = cString.length-1; nLoop>=0; nLoop--){
		cReverse += cString.charAt(nLoop)
	}
	
	return cReverse;

}

function open_guide(section) {
	windowHref = "greenkey_audit_guide.asp#" + section;
	window.open(windowHref, 'winGuide', 'toolbar=no, directories=no, location=no, status=yes, menubar=no, resizable=no, scrollbars=yes, width=760, height=400, left=25, top=25');
}

function get_question_number(obj) {
	var objName = obj.name;
	var tempStr = "";
	
	for(j=0; j<objName.length; j++) {
		if(objName.charAt(j) != "~") {
			tempStr = tempStr + objName.charAt(j);
		} else {
			return tempStr;
		}
	}
}

function set_updated(e) {
	strUpdated = "yes";
}

function add_form_handlers(f) {
	for(i=0; i<f.length; i++) {
		var element = f.elements[i];
		element.onclick = set_updated;
		if (element.captureEvents) element.captureEvents(Event.CLICK);
	}	
}

function save_warning(strUrl) {
	if(strUpdated=="yes") {
		if(confirm("Do you want to save your changes?  Press [OK] to save.")) {
			save(document.auditForm);
		}
		else {
			window.location.href=strUrl;
		}
	}
	else {
		window.location.href=strUrl;
	}
}

/* Modified May 28, 2004*/
function save(f) {

	// Added to prevent javascript injection on 07/26/2010
	f.verify_name.value = RemoveJavaInjection(f.verify_name.value);
	
	if(strUpdated=="no") {
		alert("There are no changes to be saved at this time."); 
		return;
	}
	else {
		f.submit_type.value = "save";
		f.submit();
	}
}

function validate_and_complete(f) {
	f.submit_type.value = "complete";
	var prev_number = get_question_number(f.elements[5]);	// first question (0 is verify type, 1 is submit type, 2 is sectionId, 3 & 4 are name/date verify)
	var last_element = f.elements[f.length-1]; // last question
	var valid = false;
	
	// validate name/date confirmations
	f.verify_name.value = RemoveJavaInjection(f.verify_name.value);
	if(f.verify_name.value=="") {
		alert("Please enter your name to verify that the information in this form is accurate and truthful.");
		f.verify_name.style.backgroundColor = "#FFBFBF";
		f.verify_name.focus();
		return;
	}
	
	if(f.verify_date.value=="") {
		alert("Please enter the date which you verify that the information in this form is accurate and truthful.");
		f.verify_date.style.backgroundColor = "#FFBFBF";
		f.verify_date.focus();
		return;
	}
	
	for(i=0; i<f.length; i++) {
		var element = f.elements[i];
		var e_name = element.name;

		if(e_name.slice(e_name.length - 4, e_name.length) == "_ans") {
			// validate radios and check boxes
			if((element.type == "radio" || element.type == "checkbox") && element.optional != true) {
				
				var question_number = get_question_number(element);
				
				if(question_number == prev_number) {
					// same element (question)
					if(element.checked == true) {
						valid = true;
					}
				} else {
					// new element (question), check previous
					if(valid != true) {
						alert("Please answer question #" + prev_number);
						return;
					}					
					
					valid = false;
					
					if(element.checked == true) {
						valid = true;
					}					
				}
				
				prev_number = question_number;
				
				// check the last element
				if(element == last_element) {
					if(valid != true) {
						alert("Please answer question #" + question_number);
						return;
					}		
				}
			}		
		}		
	}
	
	// validate extras
	
	// submit if all is ok
	f.submit_type.value = "complete";
	f.submit();
}

function confirmDelete(){
    if (confirm("Are you sure you want to delete this record?")) {
        return true;
    } else {
        return false;
    }
}

function isNumber (el) {
  if (isNaN(el.value)) {
    alert (el.name + " field must contain a valid number.");
    el.focus();
    return false;
  }
  return true;
}
  
function validateField (Id, type, allowEmpty) {
  //validate fields
  thisField = document.all(Id);
  if (!allowEmpty && (thisField.value == "")) {
    alert (Id + " field can not be empty.");
    thisField.focus();
    return false;
  }
  switch (type) {
    case ('number'):
      if (isNaN(thisField.value)) {
        alert(thisField.value + " is not a valid number.");
        thisField.focus();
        return false;
      } 
      break;
    case ('phone_number'):
      phone = "";
      for (i=0; i<thisField.value.length; i++) { 
        c = thisField.value.substr(i,1);
        if (!isNaN(c) && c != " ") {
          phone = phone + c;
        }
      }
      if (phone.length>0 && phone.length<6) {
        alert(phone + " is not a valid phone number.");
        thisField.focus();
        return false;
      } else if (phone.length>10) {
        alert(phone + " is not a valid phone number.");
        thisField.focus();
        return false;
      } else if (phone.length==10) {
        phone = "(" + phone.substr(0,3) + ") " + phone.substr(3,3) + "-" + phone.substr(6,4);
      } else if (phone.length==7) {
        phone = "(416) " + phone.substr(0,3) + "-" + phone.substr(3,4);
      } else if (phone.length<10) {
        phone = phone.substr(0, phone.length-4) + "-" + phone.substr(phone.length-4,4);
      }
      thisField.value = phone;
      break;
    default:
      break;
  }
  return true;
}

function vfAction() {
    formObj = document.Form;
    formObj.Action.value='save';
    return true;
}

function vfUpload() {
    formObj = document.Form1;
    formObj.Action.value='save';
    return true;
}

function vfMailAction(action) {
    formObj = document.Form;
    formObj.action.value= action;
    return true;
}

function vfeditPassword(){
    formObj = document.Form;
	if (formObj.password.value.length == 0){
		formObj.password.focus();
		alert ('Please enter your new password!');
    	return false;
    }
	if ((formObj.password.value.length < 6) || (formObj.password.value.length > 15)){
		formObj.password.focus();
		alert ('Your password needs to be between 6 to 15 characters.');
		return false;
    }	
	if (formObj.password1.value.length == 0){
		formObj.password1.focus();
		alert ('Please confirm your new password.');
    	return false;
    }
	if ((formObj.password1.value.length < 6) || (formObj.password1.value.length > 15)){
		formObj.password1.focus();
		alert ('Your password needs to be between 6 to 15 characters.');
    	return false;
    }	
	if (formObj.password.value != formObj.password1.value){
    	formObj.password1.value = "";
	    formObj.password1.focus();
    	alert ('Your new password and confirmation do not match. \n Please try again.');
	    return false;    
	}else{     
    	formObj.Action.value='save';
	    return true;
	}
}

// function that check all the required form fields
// and fill up not requiered feilds with default values.
function verify(myForm)
{
	var msg;
	var errors = "";
	var emptyField = "";
// cycles through all the elements of the form
	for(var i = 0; i < myForm.elements.length; i++) {
	    var element = myForm.elements[i];
	    if ((element.value == null) || (element.value == "") || (element.value == " ")){
	        //the first 3 feilds are required
			if (element.required) {
			    emptyField += "\n      " + element.name;
			    element.value = "";
			    continue;
			}else {
			    element.value = "N/A";
			}
	    }
	}
	
	//if there were errors, then display message
	if (!emptyField && !errors) return true;
    msg = "The form was not submited because the following errors were detected :\n\n";
    if (emptyField) {
   	    msg += " - The following requiered field(s) are empty:" + emptyField + "\n";
		if (errors) {
    		msg += "\n";
		}
	}
	msg += errors;
	alert(msg);
	return false;
}

function verifyPostalCode(pCode){
	var alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	var numeric = "0123456789";
	var returnValue = "";
	var lengthOK = false;
	var alphaOK = false;
	var numOK = false;

	// convert to upper case for consistent formatting
	pCode = pCode.toUpperCase();
	// remove any spaces for parsing
	pCode = pCode.replace(/\s/g, "");
	// check length (should be 6)
	lengthOK = (pCode.length == 6);
	// look at the alpha characters
	alphaOK = (alpha.indexOf(pCode.charAt(0)) > -1) && (alpha.indexOf(pCode.charAt(2)) > -1) && (alpha.indexOf(pCode.charAt(4)) > -1);
	// look at numeric characters
	numOK = (numeric.indexOf(pCode.charAt(1)) > -1) && (numeric.indexOf(pCode.charAt(3)) > -1) && (numeric.indexOf(pCode.charAt(5)) > -1);
	
	if(lengthOK && numOK && alphaOK){
		returnValue = pCode.substring(0,3) + " " + pCode.substring(3,6);
	}
	return returnValue;
}

function isPhoneNumber (num) {
  var phone="";
  // remove all characters except numbers
  num = num.replace(/[^\d]/g, "");
  // check length
  if(num.length == 10){
    // correct length, format the number
    phone = "(" + num.substring(0,3) + ") " + num.substring(3,6) + "-" + num.substring(6,10);
  }
  return phone;
}  

function isURL (url) {
  // return immediately if blank
  if(url == "") return "";
  // expression for matching url
    exp = /^(?:(?:ftp|https?):\/\/)?(?:[a-z0-9](?:[-a-z0-9]*[a-z0-9])?\.)+(?:com|edu|biz|org|gov|int|info|mil|net|name|museum|coop|aero|[a-z][a-z])\b(?:\d+)?(?:\/[^;"'<>()\[\]{}\s\x7f-\xff]*(?:[.,?]+[^;"'<>()\[\]{}\s\x7f-\xff]+)*)?/;
  if(!url.match(exp)){
    // not a match, try adding protocol and check again
    url = "http://" + url;
    if(!url.match(exp)){
      // still not a proper url
      return "";
    }
  }
  return url;
}

function verifyPasswords(pass1, pass2, userName){
  // added by S. Crawford/TOR for HAC website
	var valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
	var temp;
  if (pass1 != pass2){
    alert('The passwords were not the same. Please try again.');
    return false;
  }
  
  if (pass1 == userName){
    alert('The password and user name can not be the same. Please try again.');
    return false;
  }
    
  if ((pass1.length < 8) || (pass1.length > 15)){
    alert ('Your password must be between 8 and 15 characters. Please try again.');
		return false;
	}
	for (var i=0; i<pass1.length; i++) {
    temp = pass1.charAt(i);
		if (valid.indexOf(temp) == "-1"){
			alert ('Your password may only contain upper case characters, lower case characters or numbers. Please try again.');
			return false;
		}
	}
  return true;
}

function vfPassword(){
  formObj = document.form1;
	var valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
	var temp;
	var usertemp;
  if ((formObj.password.value.length < 6) || (formObj.password.value.length > 15)){
    formObj.password.focus();
		alert ('Your password needs to be between 6 to 15 characters.');
		return false;
	}
	else if (formObj.password.value !=''){
		for (var i=0; i<formObj.password.value.length; i++) {
    		temp = "" + formObj.password.value.substring(i, i+1);
		    if (valid.indexOf(temp) == "-1"){
		    	formObj.password.focus();
				alert ('Your password may only contain upper case characters, lower case characters or numbers. Please try again.');
				return false;
			}
		}
	}
	else{     
	    return true;
	}
}

function verifyPassword(el){
	var valid = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
	var ok = "yes";
	var temp;
	for (var i=0; i<el.value.length; i++) {
    	temp = "" + el.value.substring(i, i+1);
		alert(temp);
	    if (valid.indexOf(temp) == "-1") ok = "no";
		alert(ok);
	}
	if (ok == "no") {
    	return false;
	}
	
}

function FormatCurrency(expr){
  num = Math.round(expr * 100)/100;
  numString = num.toString();
  if((decLoc = numString.indexOf(".")) > -1){
    // has decimal point, determine location
    if(decLoc == (numString.length-2)){
      // decimal point is second last character, need to add trailing 0
      numString += "0";
    } 
  } else {
    // no decimal point, add .00 to number
    numString += ".00";
  }
  return numString;
}

function calcCharge(num){
  // added by S. Crawford/TOR for HAC website
  // calculation for determining rate
  var cost;
	if(isNaN(num)){
	  cost = -1;
	} else {
	  var intRooms = Number(num);
	  // removed by DRDC Aug 9, 2005 as per customer request - cost = (intRooms<75?500:600) + intRooms;
	  cost = 350;
	}
  return cost;
}

function openNewWindow(url, name){
	win = window.open(url, name, 'width=800, height=500, status=yes, address=no, resizable=yes, scrollbars=yes');
}

function emailCheck (emailStr) {

/* The following variable tells the rest of the function whether or not
to verify that the address ends in a two-letter country or well-known
TLD.  1 means check it, 0 means don't. */

var checkTLD=1;

/* The following is the list of known TLDs that an e-mail address must end with. */

var knownDomsPat=/^(com|net|org|edu|int|mil|gov|arpa|biz|aero|name|coop|info|pro|museum)$/;

/* The following pattern is used to check if the entered e-mail address
fits the user@domain format.  It also is used to separate the username
from the domain. */

var emailPat=/^(.+)@(.+)$/;

/* The following string represents the pattern for matching all special
characters.  We don't want to allow special characters in the address. 
These characters include ( ) < > @ , ; : \ " . [ ] */

var specialChars="\\(\\)><@,;:\\\\\\\"\\.\\[\\]";

/* The following string represents the range of characters allowed in a 
username or domainname.  It really states which chars aren't allowed.*/

var validChars="\[^\\s" + specialChars + "\]";

/* The following pattern applies if the "user" is a quoted string (in
which case, there are no rules about which characters are allowed
and which aren't; anything goes).  E.g. "jiminy cricket"@disney.com
is a legal e-mail address. */

var quotedUser="(\"[^\"]*\")";

/* The following pattern applies for domains that are IP addresses,
rather than symbolic names.  E.g. joe@[123.124.233.4] is a legal
e-mail address. NOTE: The square brackets are required. */

var ipDomainPat=/^\[(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\]$/;

/* The following string represents an atom (basically a series of non-special characters.) */

var atom=validChars + '+';

/* The following string represents one word in the typical username.
For example, in john.doe@somewhere.com, john and doe are words.
Basically, a word is either an atom or quoted string. */

var word="(" + atom + "|" + quotedUser + ")";

// The following pattern describes the structure of the user

var userPat=new RegExp("^" + word + "(\\." + word + ")*$");

/* The following pattern describes the structure of a normal symbolic
domain, as opposed to ipDomainPat, shown above. */

var domainPat=new RegExp("^" + atom + "(\\." + atom +")*$");

/* Finally, let's start trying to figure out if the supplied address is valid. */

/* Begin with the coarse pattern to simply break up user@domain into
different pieces that are easy to analyze. */

var matchArray=emailStr.match(emailPat);

if (matchArray==null) {

/* Too many/few @'s or something; basically, this address doesn't
even fit the general mould of a valid e-mail address. */

alert("The email address does not appear to be formatted correctly. Please double-check it.");
return false;
}
var user=matchArray[1];
var domain=matchArray[2];

// Start by checking that only basic ASCII characters are in the strings (0-127).

for (i=0; i<user.length; i++) {
if (user.charCodeAt(i)>127) {
alert("Ths user name contains invalid characters.");
return false;
   }
}
for (i=0; i<domain.length; i++) {
if (domain.charCodeAt(i)>127) {
alert("Ths domain name contains invalid characters.");
return false;
   }
}

// See if "user" is valid 

if (user.match(userPat)==null) {

// user is not valid

alert("The username does not appear to be valid.");
return false;
}

/* if the e-mail address is at an IP address (as opposed to a symbolic
host name) make sure the IP address is valid. */

var IPArray=domain.match(ipDomainPat);
if (IPArray!=null) {

// this is an IP address

for (var i=1;i<=4;i++) {
if (IPArray[i]>255) {
alert("The destination IP address is invalid.");
return false;
   }
}
return true;
}

// Domain is symbolic name.  Check if it's valid.
 
var atomPat=new RegExp("^" + atom + "$");
var domArr=domain.split(".");
var len=domArr.length;
for (i=0;i<len;i++) {
if (domArr[i].search(atomPat)==-1) {
alert("The domain name does not appear to be valid.");
return false;
   }
}

/* domain name seems valid, but now make sure that it ends in a
known top-level domain (like com, edu, gov) or a two-letter word,
representing country (uk, nl), and that there's a hostname preceding 
the domain or country. */

if (checkTLD && domArr[domArr.length-1].length!=2 && 
domArr[domArr.length-1].search(knownDomsPat)==-1) {
alert("The address must end in a well known domain or two letter country code.");
return false;
}

// Make sure there's a host name preceding the domain.

if (len<2) {
alert("This address is missing a hostname.");
return false;
}

// If we've gotten this far, everything's valid!
return true;
}

/*
 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 * Digest Algorithm, as defined in RFC 1321.
 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 * Distributed under the BSD License
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

/*
 * Configurable variables. You may need to tweak these to be compatible with
 * the server-side, but the defaults work in most cases.
*/
var hexcase = 0;   /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = "";  /* base-64 pad character. "=" for strict RFC compliance   */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_md5(s)    			{ return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
function b64_md5(s)    			{ return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
function any_md5(s, e) 			{ return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
function hex_hmac_md5(k, d) 	{ return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
function b64_hmac_md5(k, d) 	{ return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
function any_hmac_md5(k, d, e)  { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function md5_vm_test()
{
  return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
}

/*
 * Calculate the MD5 of a raw string
 */
function rstr_md5(s)
{
  return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
}

/*
 * Calculate the HMAC-MD5, of a key and some data (raw strings)
 */
function rstr_hmac_md5(key, data)
{
  var bkey = rstr2binl(key);
  if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
  return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
}

/*
 * Convert a raw string to a hex string
 */
function rstr2hex(input)
{
  try { hexcase } catch(e) { hexcase=0; }
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var output = "";
  var x;
  for(var i = 0; i < input.length; i++)
  {
    x = input.charCodeAt(i);
    output += hex_tab.charAt((x >>> 4) & 0x0F)
           +  hex_tab.charAt( x        & 0x0F);
  }
  return output;
}

/*
 * Convert a raw string to a base-64 string
 */
function rstr2b64(input)
{
  try { b64pad } catch(e) { b64pad=''; }
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var output = "";
  var len = input.length;
  for(var i = 0; i < len; i += 3)
  {
    var triplet = (input.charCodeAt(i) << 16)
                | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
                | (i + 2 < len ? input.charCodeAt(i+2)      : 0);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > input.length * 8) output += b64pad;
      else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
    }
  }
  return output;
}

/*
 * Convert a raw string to an arbitrary string encoding
 */
function rstr2any(input, encoding)
{
  var divisor = encoding.length;
  var i, j, q, x, quotient;

  /* Convert to an array of 16-bit big-endian values, forming the dividend */
  var dividend = Array(Math.ceil(input.length / 2));
  for(i = 0; i < dividend.length; i++)
  {
    dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
  }

  /*
   * Repeatedly perform a long division. The binary array forms the dividend,
   * the length of the encoding is the divisor. Once computed, the quotient
   * forms the dividend for the next step. All remainders are stored for later
   * use.
   */
  var full_length = Math.ceil(input.length * 8 /
                                    (Math.log(encoding.length) / Math.log(2)));
  var remainders = Array(full_length);
  for(j = 0; j < full_length; j++)
  {
    quotient = Array();
    x = 0;
    for(i = 0; i < dividend.length; i++)
    {
      x = (x << 16) + dividend[i];
      q = Math.floor(x / divisor);
      x -= q * divisor;
      if(quotient.length > 0 || q > 0)
        quotient[quotient.length] = q;
    }
    remainders[j] = x;
    dividend = quotient;
  }

  /* Convert the remainders to the output string */
  var output = "";
  for(i = remainders.length - 1; i >= 0; i--)
    output += encoding.charAt(remainders[i]);

  return output;
}

/*
 * Encode a string as utf-8.
 * For efficiency, this assumes the input is valid utf-16.
 */
function str2rstr_utf8(input)
{
  var output = "";
  var i = -1;
  var x, y;

  while(++i < input.length)
  {
    /* Decode utf-16 surrogate pairs */
    x = input.charCodeAt(i);
    y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
    if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
    {
      x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
      i++;
    }

    /* Encode output as utf-8 */
    if(x <= 0x7F)
      output += String.fromCharCode(x);
    else if(x <= 0x7FF)
      output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0xFFFF)
      output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
    else if(x <= 0x1FFFFF)
      output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
                                    0x80 | ((x >>> 12) & 0x3F),
                                    0x80 | ((x >>> 6 ) & 0x3F),
                                    0x80 | ( x         & 0x3F));
  }
  return output;
}

/*
 * Encode a string as utf-16
 */
function str2rstr_utf16le(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode( input.charCodeAt(i)        & 0xFF,
                                  (input.charCodeAt(i) >>> 8) & 0xFF);
  return output;
}

function str2rstr_utf16be(input)
{
  var output = "";
  for(var i = 0; i < input.length; i++)
    output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
                                   input.charCodeAt(i)        & 0xFF);
  return output;
}

/*
 * Convert a raw string to an array of little-endian words
 * Characters >255 have their high-byte silently ignored.
 */
function rstr2binl(input)
{
  var output = Array(input.length >> 2);
  for(var i = 0; i < output.length; i++)
    output[i] = 0;
  for(var i = 0; i < input.length * 8; i += 8)
    output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
  return output;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2rstr(input)
{
  var output = "";
  for(var i = 0; i < input.length * 32; i += 8)
    output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
  return output;
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length.
 */
function binl_md5(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);
}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t)
{
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

// *** End of MD5 functionality
