//
// Javascript utility functions
// Created by RCE & others

var PERMISSION_NONE = 0;
var PERMISSION_READ= 10;
var PERMISSION_WRITE = 20;
var SUPER_USER = 100;


/*************************************/
function AJAX_buildParamString (elements) {
	var i, params='';
	for (i=0; i<elements.length; i++) {
		fld = elements[i];
		params += '&'+(fld.id ? fld.id : fld.name)+'=';
		switch (fld.tagName.toLowerCase()) {
			case 'button': continue;
			case 'input':
				switch (fld.type.toLowerCase()) {
					case 'checkbox':
						params += fld.checked ? 1 : 0;
						break;
					case 'radio':
						params += getSelectedRadioValue(fld.name);
						while (i+1 < elements.length && elements[i+1].name == fld.name) {
							i++;
						}
						break;
					case 'text':
					case 'email':
					case 'phone':
					case 'hidden':
					case 'number':
						params += encodeURIComponent(fld.value);
						break;
				}
				break;					
			case 'textarea':
				params += encodeURIComponent(fld.value);
				break;
			case 'select':
				params += getSelectedOptionInfo(fld,'value');
				break;
		}
	}		
	return params;
}

function AJAX_displayJson (elements, json) {
	var i, fld, val;
	for (i=0; i<elements.length; i++) {
		fld = elements[i];
		val = json[isEmpty(fld.id) ? fld.name : fld.id];
		if (val === undefined) {
			val = "";
		}
		switch (fld.tagName.toLowerCase()) {
			case 'button': continue;
			case 'input':
				switch (fld.type.toLowerCase()) {
					case 'checkbox':
						fld.checked = (val == '1' ? true : false);
						break;
					case 'radio':
						setRadioValue(fld.name,val);
						while (i+1 < elements.length && elements[i+1].name == fld.name) {
							i++;
						}
						break;
					case 'text':
					case 'email':
					case 'phone':
					case 'hidden':
						fld.value = val;
						break;
				}
				break;					
			case 'textarea':
				fld.value = val;
				break;
			case 'select':
				setSelectedOptionByValue(fld,val);
				break;
		}
	}
}



/*************************************/
function charOK (okChars,event) {
   var keycode;
   if (window.event)
      keycode = window.event.keyCode;
   else if (event) 
      keycode = event.which;
   else
      return true;

   for (var i=0; i<okChars.length; i++) {
      if (okChars.charCodeAt(i) == keycode)
         return (true);	// character is in approved set
   }
   return (false); // character not found in approved set

} /* charOK */


/******************************/
function CheckAddrForPObox (addrField) {

	var testStr = addrField.value;
	boxExp1 = / box /gi;
	boxExp2 = /box /gi;
	if (testStr.search(boxExp1) != -1 || testStr.search(boxExp2) == 0) {
		LZ_alert("<p>The shipper will not deliver to a PO Box.  If this is a PO Box, please give a physical address instead.</p>",addrField);
	}
	return (true);
}


/******************************/
function CheckCreditCard (cardField,emptyOK,maskOK) {

  // Test credit card number for validity
  // Created 2001-04-03 by RCE
  // Modified 2002-08-21 by RCE
  //   added 'emptyOK' to allow user to tab
  //   out of field during data entry
  //
  var checkdigit = 0;
  var checksum = 0;
  var checkStr = cardField.value;
  var digitStr = "";	// for storage of the digits only
  var digitnumber = 0;
  
  if (maskOK == null) {
	  maskOK = false;
  }

  if (cardField.type == 'hidden') return (true);

  if (isEmpty(checkStr)) {
    if (!emptyOK) {
      LZ_alert("<p>Please enter your credit card number.</p>",cardField);
      return (false);
    } else {
      return (true);
    }
  }
  
  if (maskOK && checkStr.substr(1,7) == "XXX-XXX") {	// masked? accept it
	  return (true);
  }

  // Run through the number backwards
  for (var i = checkStr.length-1; i >= 0; i--) {
    // first strip out all but numbers
    checkdigit = checkStr.charCodeAt(i) - 48;
    if ((checkdigit >= 0) && (checkdigit <= 9)) {
      digitStr += checkStr.charAt(i);	// Save the digit for later
      digitnumber += 1;			// Note: counts 1..n+1, not 0..n
      if (digitnumber % 2 == 0)
        checkdigit *= 2;		// Even? Double it
      if (checkdigit > 9)
        checkdigit = checkdigit-9;	// Too big? Reduce by 9 (same as adding digits)
      checksum += checkdigit;		// Add to checksum
    }
  }
  if (digitStr == "7200000007004" || digitStr == "5100000000004245") {
     // test numbers - fine as is
     return (true);
  }
  if ((digitStr.length == 16 && digitStr.charAt(15) != '4' && digitStr.charAt(15) != '5') || 
      (digitStr.length == 15 && digitStr.charAt(14) != '3') ||
      (digitStr.length < 15 || digitStr.length > 16)) {
     LZ_alert("<p>Sorry - we only accept Visa, Mastercard, and American Express. Please try again.</p>",cardField);
     return (false);
  }


  if ((checksum % 10) != 0) {
    LZ_alert("<p>Please re-check your credit card number.</p>",cardField);
    return (false);
  }

  // digitStr now has the card number, backwards.
  // Reverse it.
  checkStr = digitStr;
  digitStr = "";
  var len = checkStr.length;
  for (i = len-1; i>=0; i--) {
    digitStr += checkStr.charAt(i);
  }

  // Now format the string correctly
  // Only current options are Visa and Mastercard,
  // both of which are 16-digit numbers.
  // Format it as XXXX-XXXX-XXXX-XXXX, using digitStr.
  // Append MM-YYYY from cc_exp_mo and cc_exp_yr.
  
  if (digitStr.length == 16) 
     cardField.value = digitStr.substr(0,4) + "-" +
                       digitStr.substr(4,4) + "-" +
                       digitStr.substr(8,4) + "-" +
                       digitStr.substr(12,4);
  else
     cardField.value = digitStr.substr(0,4) + "-" +
                       digitStr.substr(4,4) + "-" +
                       digitStr.substr(8,3) + "-" +
                       digitStr.substr(11,4);


  return (true);
} /* CheckCreditCard */


/******************************/
function CheckDate (field) {
	return checkDate(field);
}
function checkDate (field) {
	var dates = field.value.replace(/\//g,'-').split("-");
	if (dates.length != 3) {
		LZ_alert('<p>Please enter a valid date.</p>',field);
		return false;
	}
	var had_slashes = field.value.search(/\//) != -1;
	// clean it up a bit more
	for (var i=0; i<3; i++) {
		if (dates[i].length == 1) dates[i] = '0'+dates[i];
		if (dates[i] > '31' && dates[i] <= '99') {
			// must be the year, in the 1900s; add the '19' to it
			dates[i] = '19'+dates[i];
		}
	}
	if (dates[2].length == 4) {
		// user probably did M-D-Y rather than Y-M-D
		var m = dates[0];
		var d = dates[1];
		dates[0] = dates[2];
		dates[1] = m;
		dates[2] = d;
	}
	if (dates[1] > '12') {
		// user did Y-D-M
		d = dates[1];
		dates[1] = dates[2];
		dates[2] = d;
	}
	if (dates.length > 3) {
		LZ_alert('<p>Please enter the full 4-digit year.  The date should be in the form YYYY-MM-DD.</p>',field);
		return false;
	}
	if (dates[0].length==2 && dates[1].length==2 && dates[2].length==2 && had_slashes) {
		// user probably entered M/D/YY; shift to YYYY-MM-DD
		d = dates[2];
		dates[2] = dates[0];
		dates[0] = '20'+d;
	}
	if (dates[1].length == 1) dates[1] = '0' + dates[1];
	if (dates[2].length == 1) dates[2] = '0' + dates[2];
	var ds = dates[1] + "/" + dates[2] + "/" + dates[0];
	var test = new Date (ds);
	if (isNaN(test)) {
		LZ_alert('<p>Please enter a date in the form YYYY-MM-DD.</p>',field);
		return false;
	} else {
		if (test.getFullYear() != (dates[0] * 1) || (test.getMonth()+1) != (dates[1] * 1) || test.getDate() != (dates[2] * 1)) {
			LZ_alert('<p>Sorry, but '+field.value+' is not a valid date. Please enter a date in the form YYYY-MM-DD.</p>',field);
			return false;
		} else {
			field.value = dates[0]+'-'+dates[1]+'-'+dates[2];
			return true;
		}
	}
}


/******************************/
function CheckEmail (emailField,emptyOK) {
  // RCE added new email validation routine from Netscape 10-23-2001
  // Also modified to ensure it contains a valid top-level domain
  // 2002-08-21 RCE added broader TLD testing
  if (emailField.value === undefined && emailField.currentTarget) {
	  // handle condition where caller isn't passing parameters
	  emailField = emailField.currentTarget;
	  emptyOK = true;
  }
  if (emailField.type == 'hidden') return (true);
  var emails = emailField.value.toLowerCase().split(',');
  
  for (var i=0; i<emails.length; i++) {
	  emails[i] = trim(emails[i]);
	  if (!checkOneEmail (emailField,emails[i],emptyOK)) {
		  return false;
	  }
  }
  
  emailField.value = emails.join(',');
  return true;
  

} /* CheckEmail() */


  var validTLDs = ":com:net:org:edu:gov:aero:biz:coop:info:museum:name:pro:ad:ae:af:ag:ai:" +
                  "al:am:an:ao:aq:ar:as:at:au:aw:az:ba:bb:bd:be:bf:bg:bh:bi:bj:bm:bn:" +
                  "bo:br:bs:bt:bv:bw:by:bz:ca:cc:cf:cg:ch:ci:ck:cl:cm:cn:co:cr:cs:cu:" +
                  "cv:cx:cy:cz:de:dj:dk:dm:do:dz:ec:ee:eg:eh:er:es:et:fi:fj:fk:fm:fo:" +
                  "fr:fx:ga:gb:gd:ge:gf:gh:gi:gl:gm:gn:gp:gq:gr:gs:gt:gu:gw:gy:hk:hm:" +
                  "hn:hr:ht:hu:id:ie:il:in:io:iq:ir:is:it:jm:jo:jp:ke:kg:kh:ki:km:kn:" +
                  "kp:kr:kw:ky:kz:la:lb:lc:li:lk:lr:ls:lt:lu:lv:ly:ma:mc:md:mg:mh:mk:" +
                  "ml:mm:mn:mo:mp:mq:mr:ms:mt:mu:mv:mw:mx:my:mz:na:nc:ne:nf:ng:ni:nl:" +
                  "no:np:nr:nt:nu:nz:om:pa:pe:pf:pg:ph:pk:pl:pm:pn:pr:pt:pw:py:qa:re:" +
                  "ro:ru:rw:sa:sb:sc:sd:se:sg:sh:si:sj:sk:sl:sm:sn:so:sr:st:su:sv:sy:" +
                  "sz:tc:td:tf:tg:th:tj:tk:tm:tn:to:tp:tr:tt:tv:tw:tz:ua:ug:uk:um:us:" +
                  "uy:uz:va:vc:ve:vg:vi:vn:vu:wf:ws:ye:yt:yu:za:zm:zr:zw:int:mil:arpa:nato:";

function checkOneEmail (emailField, email, emptyOK) {
	var newstr = "";
	var at = false;
	var dot = false;
	var i, tld = "";
	var msg;
	
	if (isEmpty(email) && (emptyOK == true)) {
		return (true);
	}
	
	// Pull the putative TLD and validate it against the acceptable set
	// This involves pulling the tail-end of the field, from the final '.',
	// and comparing it to the list of acceptable TLDs in validTLDs.  Note
	// that the validTLD string has every valid TLD bracketed by colons,
	// so that .co (=":co:") doesn't match .com (=":com:").
	i = email.lastIndexOf('.');
	tld = ':'+email.substr(i+1)+':';
	//tld = tld.substr(0,tld.search(/\./));			// find the '.' and copy to it
	//tld = ":" + reverseStr(tld).toLowerCase() + ":";	//This becomes the search string
	if (validTLDs.search(tld) == -1) {
		msg = "<p>The top-level domain appears invalid (for example, there's no '.com' in the address).</p><p>Please enter a valid email address.</p>";
		if (typeof LZ_alert == 'function') {
			LZ_alert(msg,emailField);   
		} else {
			alert(msg);
			emailField.focus();
		}
		return false;
	}
	
	
	for (i = 0; i < email.length; i++) {
		ch = email.substring(i, i + 1)
		if ((ch >= "A" && ch <= "Z") || (ch >= "a" && ch <= "z")
				|| (ch == "@") || (ch == ".") || (ch == "_")
				|| (ch == "-") || (ch >= "0" && ch <= "9")) {
			newstr += ch;
			if (ch == "@") {
				if (at == true) { //only one per address!
					at = false;
					break;
				}
				at=true;
			}
		}
	}
	if (!at) {
		msg = "<p>There's no '@' sign in your email address.</p><p>Please enter a valid email address.</p>";   
			if (typeof LZ_alert == 'function') {
			LZ_alert(msg,emailField);   
		} else {
			alert(msg);
			emailField.focus();
		}
		return (false);
	}
	if (newstr.length != email.length) {	// invalid characters were not copied
		msg = "<p>The email address you entered contains invalid characters."+
				"<br />Allowable characters are letters, numbers, periods, dashes, underscores, and the @ sign. </p>"+
				"<p>Please enter a valid email address.</p>";
			if (typeof LZ_alert == 'function') {
			LZ_alert(msg,emailField);   
		} else {
			alert(msg);
			emailField.focus();
		}
		return (false);
	}
	
	return (true);
}

/******************************/
function CheckPhoneNumber (phoneField, emptyOK) {

  var checkOK = "0123456789";
  var checkStr = phoneField.value;
  var newStr = "";
  var digits = 0;
  var allValid = true;

  if (phoneField.type == 'hidden' || (isEmpty(checkStr) && (emptyOK == true))) {
    return (true);
  }
  for (var i = 0;  i < checkStr.length;  i++) {
    var ch = checkStr.charAt(i);
    if (ch >= "0" && ch <= "9") {
      digits++;
      newStr += ch;
    }
  }
  if ((digits!=10)) {
    LZ_alert("<p>Please enter a valid phone number.</p>",phoneField);
    return (false);
  }
  phoneField.value = "(" + newStr.substr(0,3) + ") " + newStr.substr(3,3) + "-" +newStr.substr(6,4);
  return (true);
} /* CheckPhoneNumber */

/******************************/
function CheckTime (fld, emptyOK) {
	if (isEmpty(fld.value) && emptyOK == true) {
		return true;
	}
	// time fields should have been governed by time_only()
	var parts = fld.value.split(':');
	if (parts.length != 2) {
		LZ_alert('<p>Time fields take a 24-hour time in the form hh:mm; please enter a valid time.</p>',fld);
		return false;
	}
	if (isEmpty(parts[0]) || parseInt(parts[0],10) > 23) {
		LZ_alert("<p>The hour portion must be between 00 and 23; please enter a valid time.</p>",fld);
		return false;
	}
	if (isEmpty(parts[1]) || parseInt(parts[1],10) > 59) {
		LZ_alert("<p>The minute portion must be between 00 and 59; please enter a valid time.</p>",fld);
		return false;
	}
	fld.value = TimeFormatted(fld.value).substr(0,5);
	return true;
}

/******************************/
// ZIP/Postal Code routines
/******************************/

function CheckZIP (zipField,emptyOK,countryCode) {

	if (!countryCode) {
		countryCode = 'US';
	}
	if (zipField.type == 'hidden') return (true);
	
	if (countryCode == '-1') {
		var which = zipField.id.substr(0,5);
		var cntry_fld = document.getElementById(which+'country');
		if (!cntry_fld) return true;
		LZ_alert('<p>Please choose the country, then enter the zip/postal code.</p>',cntry_fld);
		return false;
	}
	
	if (countryCode != 'US' && countryCode != 'CA') {
		return true;
	}
	
	// format field
	var checkStr, str = zipField.value.replace(/[ -]/g,'').toUpperCase();	//strip spaces and dashes; capitalize
	if (isEmpty(str) && emptyOK) {
		return false;	// false forces ZipLookup to return; it also stops an untimely submit()
	}
	if (countryCode == 'US') {
		checkStr = str.substr(0,5);
		if (str.length > 5) {
			checkStr += '-'+str.substr(5);
		}
	} else {
		checkStr = str.substr(0,3) + ' ' + str.substr(3);
	}
	zipField.value = checkStr;
	if (!isValidPostalCode(checkStr,countryCode)) {
		if (countryCode == 'US') {
			LZ_alert('<p>Please enter a valid ZIP code.</p>',zipField);
		} else {
			LZ_alert('<p>Please enter a valid Canadian Postal Code.</p>',zipField);
		}
		return false;
	}
	return true;
	
} /* CheckZIP */
function isValidPostalCode(postalCode, countryCode) {
	if (!countryCode) countryCode = 'US';
	switch (countryCode) {
		case "US":
			postalCodeRegex = /^([0-9]{5})(?:[-\s]*([0-9]{4}))?$/;
			break;
		case "CA":
			postalCodeRegex = /^([A-Z][0-9][A-Z])\s*([0-9][A-Z][0-9])$/;
			break;
		default:
			postalCodeRegex = /^(?:[A-Z0-9]+([- ]?[A-Z0-9]+)*)?$/;
	}
	return postalCodeRegex.test(postalCode);
}

var ZipFieldMouseLoc;
var ZipFieldDisambiguateCity;

var StateJSON = [
	{"abbr":"AL","name":" Alabama","cntry":"US"},
	{"abbr":"AK","name":" Alaska","cntry":"US"},
	{"abbr":"AZ","name":" Arizona","cntry":"US"},
	{"abbr":"AR","name":" Arkansas","cntry":"US"},
	{"abbr":"CA","name":" California","cntry":"US"},
	{"abbr":"CO","name":" Colorado","cntry":"US"},
	{"abbr":"CT","name":" Connecticut","cntry":"US"},
	{"abbr":"DE","name":" Delaware","cntry":"US"},
	{"abbr":"DC","name":" District Of Columbia","cntry":"US"},
	{"abbr":"FL","name":" Florida","cntry":"US"},
	{"abbr":"GA","name":" Georgia","cntry":"US"},
	{"abbr":"HI","name":" Hawaii","cntry":"US"},
	{"abbr":"ID","name":" Idaho","cntry":"US"},
	{"abbr":"IL","name":" Illinois","cntry":"US"},
	{"abbr":"IN","name":" Indiana","cntry":"US"},
	{"abbr":"IA","name":" Iowa","cntry":"US"},
	{"abbr":"KS","name":" Kansas","cntry":"US"},
	{"abbr":"KY","name":" Kentucky","cntry":"US"},
	{"abbr":"LA","name":" Louisiana","cntry":"US"},
	{"abbr":"ME","name":" Maine","cntry":"US"},
	{"abbr":"MD","name":" Maryland","cntry":"US"},
	{"abbr":"MA","name":" Massachusetts","cntry":"US"},
	{"abbr":"MI","name":" Michigan","cntry":"US"},
	{"abbr":"MN","name":" Minnesota","cntry":"US"},
	{"abbr":"MS","name":" Mississippi","cntry":"US"},
	{"abbr":"MO","name":" Missouri","cntry":"US"},
	{"abbr":"MT","name":" Montana","cntry":"US"},
	{"abbr":"NE","name":" Nebraska","cntry":"US"},
	{"abbr":"NV","name":" Nevada","cntry":"US"},
	{"abbr":"NH","name":" New Hampshire","cntry":"US"},
	{"abbr":"NJ","name":" New Jersey","cntry":"US"},
	{"abbr":"NM","name":" New Mexico","cntry":"US"},
	{"abbr":"NY","name":" New York","cntry":"US"},
	{"abbr":"NC","name":" North Carolina","cntry":"US"},
	{"abbr":"ND","name":" North Dakota","cntry":"US"},
	{"abbr":"OH","name":" Ohio","cntry":"US"},
	{"abbr":"OK","name":" Oklahoma","cntry":"US"},
	{"abbr":"OR","name":" Oregon","cntry":"US"},
	{"abbr":"PA","name":" Pennsylvania","cntry":"US"},
	{"abbr":"PR","name":" Puerto Rico","cntry":"USextra"},
	{"abbr":"RI","name":" Rhode Island","cntry":"US"},
	{"abbr":"SC","name":" South Carolina","cntry":"US"},
	{"abbr":"SD","name":" South Dakota","cntry":"US"},
	{"abbr":"TN","name":" Tennessee","cntry":"US"},
	{"abbr":"TX","name":" Texas","cntry":"US"},
	{"abbr":"UT","name":" Utah","cntry":"US"},
	{"abbr":"VT","name":" Vermont","cntry":"US"},
	{"abbr":"VA","name":" Virginia","cntry":"US"},
	{"abbr":"VI","name":" Virgin Islands","cntry":"USextra"},
	{"abbr":"WA","name":" Washington","cntry":"US"},
	{"abbr":"WV","name":" West Virginia","cntry":"US"},
	{"abbr":"WI","name":" Wisconsin","cntry":"US"},
	{"abbr":"WY","name":" Wyoming","cntry":"US"},
	{"abbr":"AB","name":" Alberta","cntry":"CA"},
	{"abbr":"BC","name":" British Columbia","cntry":"CA"},
	{"abbr":"MB","name":" Manitoba","cntry":"CA"},
	{"abbr":"NB","name":" New Brunswick","cntry":"CA"},
	{"abbr":"NL","name":" Newfoundland","cntry":"CA"},
	{"abbr":"NT","name":" Northwest Territories","cntry":"CA"},
	{"abbr":"NS","name":" Nova Scotia","cntry":"CA"},
	{"abbr":"NU","name":" Nunavut","cntry":"CA"},
	{"abbr":"ON","name":" Ontario","cntry":"CA"},
	{"abbr":"PE","name":" Prince Edward Island","cntry":"CA"},
	{"abbr":"QC","name":" Quebec","cntry":"CA"},
	{"abbr":"SK","name":" Saskatchewan","cntry":"CA"},
	{"abbr":"YT","name":" Yukon Territory","cntry":"CA"}
];

var LookingUpZip = false;

function ZipLookup (fld,emptyOK,disambiguate) {
	
	if (!emptyOK) emptyOK = true;
	if (disambiguate === undefined || disambiguate === null) disambiguate = true;
	
	var which = fld.id.substr(0,5), countryFld, countryCode;
	countryFld = document.getElementById(which+"country");
	if (!countryFld) {
		countryCode = 'US';
	} else {
		countryCode = getSelectedOptionInfo(countryFld,'value');
	}
	
	if (!CheckZIP(fld,emptyOK,countryCode)) return false;
	//if (disambiguate == false) return;
	var prefix = fld.id.substring(0,4);	// 'bill' or 'ship'
	var zipHttp = GetXmlHttpObject();
	ZipFieldMouseLoc = mouseLoc; //getPageEventCoords();
	ZipFieldDisambiguateCity = prefix + "_city";
	zipHttp.onreadystatechange = function() {
		if (zipHttp.readyState == 4) {
			LookingUpZip = false;
			try {
				var json = JSON.parse(zipHttp.responseText);
			}
			catch (e) {
				return false;
			}
			if (!json || json.error == 1) return false;	// no need to notify
			var state_fld = document.getElementById(prefix+"_state");
			if (state_fld.tagName.toLowerCase() == "select") {
				setSelectedOptionByValue(state_fld,json.state);
			} else {
				state_fld.value = json.state;
			}
			if (document.getElementById(prefix+"_state_echo")) {
				document.getElementById(prefix+"_state_echo").value = json.state;
			}
			/*
			if (json.alternatives !== 0) {
				if (!document.getElementById('salesTaxDisambiguation_div')) {
					var div = document.createElement('div');
					div.id = 'salesTaxDisambiguation_div';
					var elem = document.createElement('h4');
					elem.id = 'zip_header';
					div.appendChild(elem);
					elem = document.createElement('div');
					elem.id = 'zip_cities';
					div.appendChild(elem);
					document.body.appendChild(div);
				}

				// multiple cities; need to disambiguate
				document.getElementById('zip_header').innerHTML = "There are "+(json.alternatives+1)+" cities associated with zipcode "+json.zipcode+".<br />Please select the correct one.";
				var span = document.getElementById('zip_cities');
				if (span.hasChildNodes()) {
					while (span.childNodes.length >= 1) {
						span.removeChild(span.firstChild);
					}
				}
				var checked = " checked='checked'";
				for (var i=0; i<json.alt_data.length; i++) {
					span.innerHTML += "<input type='radio' name='zip_city_choice' value='"+json.alt_data[i].city+"' onclick='setZipCity();' />"+json.alt_data[i].city+"<br />";
					checked = "";
				}
				var div = document.getElementById('salesTaxDisambiguation_div');
				div.style.top = Math.max(0,(ZipFieldMouseLoc.y - 50))+'px';
				div.style.left = Math.max(0,(ZipFieldMouseLoc.x - 300))+'px';
				div.style.display = 'block';
			}
			*/
			document.getElementById(prefix+"_city").value = json.city;
			document.getElementById(prefix+"_city_echo").value = json.city;
			if (typeof ZipLookupAfterFn == 'function') {
				ZipLookupAfterFn();
			}
			return false;
		}
	}
	var url = "lz_getHTTPrequestData.php?REQ_TYPE=Misc_ZipLookup&ZIP="+fld.value+"&COUNTRY="+countryCode;
	zipHttp.open("GET",url,true);
	zipHttp.send(null);
	LookingUpZip = true;
}
function setZipCity () {
	var city = getSelectedRadioValue('zip_city_choice');
	document.getElementById(ZipFieldDisambiguateCity).value = city;
	document.getElementById(ZipFieldDisambiguateCity+"_echo").value = city;
	document.getElementById('salesTaxDisambiguation_div').style.display = 'none';
}

var country_related_fields = ['state','city','postal','city_echo','state_echo'];
function setCountryFields (caller,wipe,warn) {
	if (wipe === undefined) {
		wipe = true;
	}
	if (warn === undefined) {
		warn = true;
	}
	var i, s, fld, prefix, source_field;
	// caller can be a field, or a string
	if (caller.id) {
		prefix = caller.id.substr(0,5);
		source_field = caller.id;
	} else {
		prefix = caller;
		source_field = prefix + 'country';
	}
	if (prefix != 'bill_' && prefix != 'ship_') prefix = '';
	if (wipe == true) {
		for (i=0; i<country_related_fields.length; i++) {
			fld = document.getElementById(prefix+country_related_fields[i]);
			switch (fld.tagName.toLowerCase()) {
				case 'input':
					fld.value = '';
					break;
				case 'select':
					fld.options.length = 0;
					break;
			}
		}
	}
	var cntry = getSelectedOptionInfo(source_field,'value');
	if (cntry == 'US' || cntry == 'CA') {
		document.getElementById(prefix+'state_echo').style.display = '';
		document.getElementById(prefix+'state').style.display = 'none';
		document.getElementById(prefix+'city_echo').style.display = '';
		document.getElementById(prefix+'city').style.display = 'none';
		var state = document.getElementById(prefix+'state');
		if (state.tagName.toLowerCase() == 'select') {
			// swap options
			for (var i=0; i<StateJSON.length; i++) {
				s = StateJSON[i];
				if (s.cntry != cntry) continue;
				state.options[state.options.length] = new Option(s.abbr+' - '+s.name,s.abbr,false,false);
			}
		}
	} else {
		document.getElementById(prefix+'state_echo').style.display = 'none';
		document.getElementById(prefix+'state').style.display = 'none';
		document.getElementById(prefix+'city_echo').style.display = 'none';
		document.getElementById(prefix+'city').style.display = '';
	}
	if (warn && prefix == 'ship_' && cntry != 'US') {
		LZ_alert('<p>Note: Shipping costs to '+getSelectedOptionInfo(source_field,'text')+' must be calculated by hand; we will contact you.</p>');
	}
	setDirtyBit();
	document.getElementById(prefix+'postal').focus;
}

function getStateName (abbr) {
	for (var i=0; i<StateJSON.length; i++) {
		if (StateJSON[i].abbr == abbr) {
			return StateJSON[i].name;
		}
	}
	return "";
}



/***********************************/

function replaceTableBody (old_node,new_node) {
	if (new_node === undefined) {
		new_node = old_node.cloneNode(false);
	}
	old_node.parentNode.replaceChild(new_node,old_node);
}

/***********************************/
function closeParentDivWindow (element) {
	// crawls up the DOM stack until it finds a DIV with an ID, then closes that 'window' and turns off the mask
	element = element.parentNode;	// move up one layer to begin with, since caller isn't the parent.
	while ((element.tagName != "DIV" || element.id === "") && element.offsetParent) {
		element = element.parentNode;
	}
	element.style.display = "none";
	var mask_id = element.id + '_mask';
	if (document.getElementById(mask_id) && document.getElementById(mask_id).style.display == 'block') {
		document.getElementById(mask_id).style.display = 'none';
	} else
	if (document.getElementById("lz_advancedEditMask") && document.getElementById("lz_advancedEditMask").style.display != 'none') {
		document.getElementById("lz_advancedEditMask").style.display = "none";
	} else
	if (document.getElementById("lz_editContainerMask") && document.getElementById("lz_editContainerMask").style.display != 'none') {
		document.getElementById("lz_editContainerMask").style.display = "none";
	}
	
}


/***********************************/
function CommaFormatted(amount,showZero,showDollarSign,decimals) {
	if (amount === undefined || amount === null) {
		amount = '0';
	}
	amount = strdecimal(amount).toString();	// strip all but numeric-related characters
	amount += '';
	
	if (decimals === undefined) {
		decimals = 2;
	}
	amount = parseFloat(amount).toFixed(decimals).toString();
		
	x = amount.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	var rgx = /(\d+)(\d{3})/;
	while (rgx.test(x1)) {
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	amount = x1 + x2;
	if (showZero == false && parseFloat(amount) === 0) return ('');
	if (showDollarSign) amount = '$' + amount;
	return amount;

} /* CommaFormatted */

/******************************/
function TimeFormatted (val) {
	if (val === undefined || val === null) {
		val = '00:00';
	}
	var h, s, p = val.split(':');
	h = p[0];
	s = p[1];
	if (h === null) h = '0';
	if (s === null) s = '0';
	h = parseInt(h,10);
	s = parseInt(s,10);
	if (h > 23) h = 0;
	if (s > 59) s = 0;
	h = h.toString();
	s = s.toString();
	if (h.length < 2) h = '0'+h;
	if (s.length < 2) s = '0'+s;
	return h+':'+s+':00';
}

/******************************/
function copyFields (from_prefix,to_prefix,src) {
	for (var from, dest, dest_type, val, i=0; i<src.length; i++) {
		from = document.getElementById(from_prefix+src[i]);
		dest = document.getElementById(to_prefix+src[i]);
		if (from === null || dest === null) {
			continue;
		}
		dest_type = dest.tagName.toLowerCase();
		if (from.tagName.toLowerCase() == "input") {
			val = from.value;
		} else
		if (from.tagName.toLowerCase() == "select") {
			val = getSelectedOptionInfo(from.id,(dest_type == "select" ? "value" : "text"));
		}
		if (dest_type == "input") {
			dest.value = val;
		} else
		if (dest_type == "select") {
			setSelectedOptionByValue(dest,val);
		}
	}
}
function copyFieldsAndSetCountry (from_prefix, to_prefix, src) {
	// used to make sure that the proper fields are shown
	// actually, to-country has to be set first.
	// var cntry = getSelectedOptionInfo(from_prefix+'country','value');
	// setSelectedOptionByValue(to_prefix+'country',cntry);
	copyFields(from_prefix, to_prefix, src);
	setCountryFields(to_prefix,false);	// don't wipe content
}

/************************************/
// NOTE from RCE 2003-11-03: There's a bug in this when adding a day to 2003-10-26; not sure why.
function DateAdd(startDate, numDays, numMonths, numYears) {
   var returnDate = new Date(startDate.getTime());
   var yearsToAdd = numYears;
   var month = returnDate.getMonth() + numMonths;
   if (month > 11) {
      yearsToAdd = Math.floor((month+1)/12);
      month -= 12*yearsToAdd;
      yearsToAdd += numYears;
   }
   returnDate.setMonth(month);
   returnDate.setFullYear(returnDate.getFullYear()+ yearsToAdd);
   returnDate.setTime(returnDate.getTime()+60000*60*24*numDays);
   	
   return returnDate;

} /* DateAdd */


/******************************/
function dateHandler (e,dateField,fmt) {
	if (!e) {
		e = window.event;
	}
	if (!fmt) {
		fmt = "Y-m-d";
	}
	var keycode = e.keyCode;
	var handled = false;
	
	// return if it's a number or navigation.  otherwise, wipe the event.
	if (keycode >= 46 && keycode <= 57) return true;	// "-./0123456789"
	if (keycode < 32 || keycode > 126) return true;	// navigation characters
	
	switch (keycode) {
		case 116:	// 't'
		case 84:	// 'T'
			if (e.stopPropogation) e.stopPropogation();
			e.cancelBubble = true;
			e.returnValue = false;
			if (e.preventDefault) e.preventDefault();
			
			var stamp = new Date();
			var month = (stamp.getMonth()+1 < 10) ? "0" : "";
			month += (stamp.getMonth()+1).toString();
			var day = (stamp.getDate() < 10) ? "0" : "";
			day += stamp.getDate().toString();
			var val = (fmt == "Y-m-d" ? stamp.getFullYear().toString() + "-" : "") + month + "-" + day;
			dateField.value = val;
			handled = true;
			break;
		case 70:	// 'F'
		case 102:	// 'f'
			//	first of whatever month it's in
			if (e.stopPropogation) e.stopPropogation();
			e.cancelBubble = true;
			e.returnValue = false;
			if (e.preventDefault) e.preventDefault();

			var base = dateField.value;
			if (base.length < 10) {
				stamp = new Date();
				month = (stamp.getMonth()+1 < 10) ? "0" : "";
				month += (stamp.getMonth()+1).toString();
				day = (stamp.getDate() < 10) ? "0" : "";
				day += stamp.getDate().toString();
				val = (fmt == "Y-m-d" ? stamp.getFullYear().toString() + "-" : "") + month + "-" + day;
				base = val;
			}
			dateField.value = base.substr(0,8)+'01';
			handled = true;
			break;
		case 76:	// 'L'
		case 108:	// 'l'
			// last of whatever month it's in
			if (e.stopPropogation) e.stopPropogation();
			e.cancelBubble = true;
			e.returnValue = false;
			if (e.preventDefault) e.preventDefault();

			base = dateField.value;
			if (base.length < 10) {
				stamp = new Date();
				month = (stamp.getMonth()+1 < 10) ? "0" : "";
				month += (stamp.getMonth()+1).toString();
				day = (stamp.getDate() < 10) ? "0" : "";
				day += stamp.getDate().toString();
				val = (fmt == "Y-m-d" ? stamp.getFullYear().toString() + "-" : "") + month + "-" + day;
				base = val;
			}
			var parts = base.split('-');
			year = parseInt(parts[0],10);
			month = parseInt(parts[1],10);
			stamp = new Date(year,month,0);
			month = (stamp.getMonth()+1 < 10) ? "0" : "";
			month += (stamp.getMonth()+1).toString();
			day = (stamp.getDate() < 10) ? "0" : "";
			day += stamp.getDate().toString();
			val = (fmt == "Y-m-d" ? stamp.getFullYear().toString() + "-" : "") + month + "-" + day;
			dateField.value = val;
			handled = true;
			break;
		case 38:	// up arrow
		case 40:	// down arrow
			if (e.stopPropogation) e.stopPropogation();
			e.cancelBubble = true;
			e.returnValue = false;
			if (e.preventDefault) e.preventDefault();
			var date = dateField.value;
			var offset;
			if (fmt == "Y-m-d") {
				year = strvalue(date.substr(0,4));
				offset = 5;
			} else
			if (fmt == "m-d") {
				year = new Date();
				year = year.getFullYear();
				offset = 0;
			}
			month= strvalue(date.substr(offset,2))-1;
			var day  = strvalue(date.substr(offset+3,2));
			
			var years  = (e.altKey   ? (keycode == 40 ? -1 : 1) : 0);
			var months = (e.shiftKey ? (keycode == 40 ? -1 : 1) : 0);
			var days   = (e.shiftKey || e.altKey ? 0 : (keycode == 40 ? -1 : 1));
			var nextDate = DateAdd(new Date (year,month,day),days,months,years);
			if (fmt == "Y-m-d") {
				dateField.value = nextDate.getFullYear() + '-';
			} else {
				dateField.value = "";
			}
			dateField.value += 	(nextDate.getMonth()<9 ? '0'+(nextDate.getMonth()+1) : (nextDate.getMonth()+1)) +
								'-' + 
								(nextDate.getDate()<10 ? '0'+(nextDate.getDate()) : (nextDate.getDate()));
			handled = true;
			break;
		}
		if (handled) {
			for (var s, i=0; i<dateField.attributes.length; i++) {
				if (dateField.attributes[i].nodeName == 'onchange' && dateField.attributes[i].nodeValue.search(/setDirtyBit/) != -1) {
					setDirtyBit();
					break;
			}
		}
	}
	return false;
	
} /* dateHandler */


/*************************************/
/* Move a div
**	usage: <div id="foo" onMouseDown="dragDiv(event,this);">
**	source: http://waseemblog.com/42/movable-div-using-javascript.html
*/
// Global object to hold drag information.
var DivDragObj = new Object();
function dragDiv(event, caller, use_parent) {
	return false;
	var x, y;
	if (typeof use_parent != "boolean") {
		use_parent = false;
	}
	if (use_parent == true) {
		DivDragObj.elNode = caller.offsetParent;
	} else {
		DivDragObj.elNode = caller;
	}
	// Get cursor position with respect to the page.
	try {
		x = window.event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
		y = window.event.clientY + document.documentElement.scrollTop  + document.body.scrollTop;
	}
	catch (e) {
		x = event.clientX + window.scrollX;
		y = event.clientY + window.scrollY;
	}
	// Save starting positions of cursor and element.
	DivDragObj.cursorStartX = x;
	DivDragObj.cursorStartY = y;
	DivDragObj.elStartLeft  = parseInt(DivDragObj.elNode.style.left, 10);
	DivDragObj.elStartTop   = parseInt(DivDragObj.elNode.style.top,  10);
	if (isNaN(DivDragObj.elStartLeft)) {
		DivDragObj.elStartLeft = 0;
	}
	if (isNaN(DivDragObj.elStartTop))  {
		DivDragObj.elStartTop  = 0;
	}
	// Capture mousemove and mouseup events on the page.
	try {
		document.attachEvent("onmousemove", dragDivStart);
		document.attachEvent("onmouseup",   dragDivStop);
		window.event.cancelBubble = true;
		window.event.returnValue = false;
	}
	catch (e) {
		document.addEventListener("mousemove", dragDivStart,   true);
		document.addEventListener("mouseup",   dragDivStop, true);
		event.preventDefault();
	}
}
function dragDivStart(event) {
	var x, y;
	// Get cursor position with respect to the page.
	try  {
		x = window.event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft;
		y = window.event.clientY + document.documentElement.scrollTop  + document.body.scrollTop;
	}
	catch (e) {
		x = event.clientX + window.scrollX;
		y = event.clientY + window.scrollY;
	}
	// Move drag element by the same amount the cursor has moved.
	var drLeft = (DivDragObj.elStartLeft + x - DivDragObj.cursorStartX);
	var drTop = (DivDragObj.elStartTop  + y - DivDragObj.cursorStartY);
	if (drLeft > 0) {
		DivDragObj.elNode.style.left = drLeft  + "px";
	} else {
		DivDragObj.elNode.style.left = "1px";
	}
	if (drTop > 0) {
		DivDragObj.elNode.style.top  = drTop + "px";
	} else {
		DivDragObj.elNode.style.top  = "1px";
	}
	try {
		window.event.cancelBubble = true;
		window.event.returnValue = false;
	}
	catch (e) {
		event.preventDefault();
	}
}
function dragDivStop(event) {
	// Stop capturing mousemove and mouseup events.
	try {
		document.detachEvent("onmousemove", dragDivStart);
		document.detachEvent("onmouseup",   dragDivStop);
	}
	catch (e) {
		document.removeEventListener("mousemove", dragDivStart,   true);
		document.removeEventListener("mouseup",   dragDivStop, true);
	}
}

/*************************************/
function highlightRow (caller) {
	var tr;
	if (caller && caller.currentTarget) {
		tr = caller.currentTarget;
	} else
	if (this) {
		tr = this;
	} else {
		tr = null;
	}
	
	if (tr !== null) {
		tr.className += " Highlit";
	}
}
function lowlightRow (caller) {
	var tr;
	if (caller && caller.currentTarget) {
		tr = caller.currentTarget;
	} else
	if (this) {
		tr = this;
	} else {
		tr = null;
	}
	
	if (tr !== null) {
		tr.className = tr.className.replace(" Highlit","");
	}
}


/******************************/
function int_only (e) {
	var key = window.event ? e.keyCode : e.which;
	var keychar = String.fromCharCode(key);
	if (keychar < " ") return true;
	reg = /\d/;
	return reg.test(keychar);	// true if a number
}
function real_only (e) {
	var key = window.event ? e.keyCode : e.which;
	var keychar = String.fromCharCode(key);
	if (keychar < " ") return true;
	reg = /[-\.\d]/;
	return reg.test(keychar);	// true if a number or a decimal
}
function bucks_only (e) {
	var key = window.event ? e.keyCode : e.which;
	var keychar = String.fromCharCode(key);
	if (keychar < " ") return true;
	reg = /[,\.\$\d]/;
	return reg.test(keychar);	// true if a number or a decimal or a comma or a dollar sign
}
function time_only (e) {
	var key = window.event ? e.keyCode : e.which;
	var keychar = String.fromCharCode(key);
	if (keychar < " ") return true;
	reg = /[:\d]/;
	return reg.test(keychar);	// true if a number
}

/******************************/
function isEmpty (inStr) {
	if (typeof inStr == 'number') return inStr > 0;
	if (inStr === undefined || inStr === null || inStr === "" || inStr == "null" || inStr == "NaN") return true;
	if (typeof inStr == 'object') {
		return (inStr.length > 0 ? false : true);
	}
	var s = inStr.replace(/^\s+/,'').replace(/\s+$/,'');
	return ((s.length == 0) || (s == ""));
} /* isEmpty */

/******************************/
function reverseStr (inStr) {
   var outStr;
   for (outStr="", i=inStr.length-1;i>-1;i=i-1) {
       outStr += inStr.charAt(i);
   }
   return (outStr);
} /* reverseStr */

/******************************/
function setEndDate (startDate, endDate) {
   var eD = endDate.value;
   if (!isEmpty(eD)) return (true);	// don't mess with an existing date
   var sD   = startDate.value;
   var year = strvalue(sD.substr(0,4));
   var month= strvalue(sD.substr(5,2))-1;
   // method: assume it's the first of the month, then add a month, the subtract a day
   var EOM  = DateAdd(DateAdd(new Date (year,month,1),0,1,0),-1,0,0);
   endDate.value = 
     EOM.getFullYear() +
     '-' + 
     (EOM.getMonth()<9 ? '0'+(EOM.getMonth()+1) : (EOM.getMonth()+1)) +
     '-' + 
     (EOM.getDate()<10 ? '0'+(EOM.getDate()) : (EOM.getDate()));
   return (true);

} /* setEndDate */

/******************************/
function strdecimal (inStr) {
   // strips everything but the numbers, minus sign, and decimal point
   var outStr = "";
   inStr = inStr.toString();	// make sure we're dealing with a string
   for (var i=0; i<inStr.length; i++) {
      var thisChar = inStr.charAt(i);
      if ((thisChar >= '0' && thisChar <= '9') || thisChar == '.' || thisChar == '-') outStr += thisChar;
   }
   if (outStr == "") outStr = "0.00";
   return (parseFloat(outStr));

} /* strdecimal */

/******************************/
function strvalue (inStr) {
   var outStr = "";
   for (var i=0; i<inStr.length; i++) {
      var thisChar = inStr.charAt(i);
      if (thisChar >= '0' && thisChar <= '9') outStr += thisChar;
   }
   return (Math.floor(outStr));

} /* strvalue */

/******************************/
function strip_spaces (inStr) {
	return inStr.split(' ').join('');
}

/******************************/
function testFieldLength (fld,len) {
	if (fld.value.length > len) {
		LZ_alert("<p>Sorry, but this field cannot be more than "+len+" characters long; you have entered "+fld.value.length+".</p>",fld);
		return false;
	}
	return true;
}

/******************************
** This Javascript code trim implementation removes all leading and trailing occurrences of a set of characters specified. 
** If no characters are specified it will trim whitespace characters from the beginning or end or both of the string.
******************************/
function trim(str, chars) {
	return ltrim(rtrim(str, chars), chars);
}

function ltrim(str, chars) {
	chars = chars || "\\s";
	return str.replace(new RegExp("^[" + chars + "]+", "g"), "");
}

function rtrim(str, chars) {
	chars = chars || "\\s";
	return str.replace(new RegExp("[" + chars + "]+$", "g"), "");
}


/***********************************/
function inspect(elm){
   var str = "";
   var j = 1;
   for (var i in elm)
      str += i + ": " + elm.getAttribute(i) + (j++ % 3 ? "\t" : "\n");
   LZ_alert(str);
} /* inspect */

/**********************************/
function getSelectedOptionInfo (fieldID,attrib) {
    // gets the selectedIndex option of type 'attrib'
    var selIndex;
	if (fieldID.id) {
		fieldID = fieldID.id;
	}
	var fld = document.getElementById(fieldID);
	if (fld.tagName.toLowerCase() == 'input') {
		return fld.value;
	}
	selIndex = fld.selectedIndex;
	if (selIndex == -1) return "";	// no value selected
	
	if (attrib == 'value') {
		return fld.options[selIndex].value;
	} else {
		return fld.options[selIndex].text;
	}
} // getSelectedOptionInfo

/**********************************/
function setSelectedOptionByText (selField,txt) {
    for (i=0; i<selField.options.length; i++) {
        if (selField.options[i].text == txt) {
            selField.selectedIndex = i;
            break;
        }
    }
    if (i < selField.options.length) {
        return selField.options[i].value;
    } else {
        return '';
    }
}

/**********************************/
function setSelectedOptionByValue (selField,val) {
	if (typeof selField == 'string') {
		selField = document.getElementById(selField);
	}
	selField.selectedIndex = 0;	// default to default
    for (i=0; i<selField.options.length; i++) {
        if (selField.options[i].value == val) {
            selField.selectedIndex = i;
            break;
        }
    }
    if (i < selField.options.length) {
        return selField.options[i].value;
    } else {
        return '';
    }
}

/**********************************/
function getSelectedRadioValue (field) {
	var btns;
	if (typeof field == "string") {
		btns = document.getElementsByName(field);
	} else
	if (field.name) {	// just one
		btns = document.getElementsByName(field.name);
	} else {	// already did this
		btns = field;
	}
	for (var i=0; i<btns.length; i++) {
		if (btns[i].checked) {
			return (btns[i].value);
		}
	}
	return ("");
}

/**********************************/
function setRadioValue (field,value) {
	var btns;
	if (typeof(field) == 'string') {
		btns = document.getElementsByName(field);
	} else
	if (field.name) {	// just one
		btns = document.getElementsByName(field.name);
	} else {	// already did this
		btns = field;
	}

	for (var i=0; i<btns.length; i++) {
		if (btns[i].value == value) {
			btns[i].checked = true;
			return;
		} else {
			btns[i].checked = false;
		}
	}
	if (value !== -1 && value != '') {
		btns[0].checked = true;
	}
}

/**********************************/
function setDirtyBit() {
	if (document.getElementById('dirtyBit')) {
		document.getElementById('dirtyBit').value = 1;
	} else {
		dirtyBit = 1;
		if (window.setDirtyBitExtraFn !== undefined) {
			setDirtyBitExtraFn();
		}
	}
}

/*********************************/
var CloseEditWindowToo;
function closeEditContainerIfNotDirty(close) {
	CloseEditWindowToo = close;
	var docDirtyBit = document.getElementById('dirtyBit');
	if ((dirtyBit && dirtyBit == 1) || (docDirtyBit && docDirtyBit.value == 1)) {
		LZ_confirm("Are you sure you want to close this window (your changes will be lost if you do)?",closeEditContainerIfNotDirty_step2,"Caution - You have unsaved changes!",LZ_btn_saveOK,LZ_btn_saveCancel,"");
	} else {
		LZ_confirm_result = '1';
		closeEditContainerIfNotDirty_step2();
	}
}
function closeEditContainerIfNotDirty_step2 () {
	if (LZ_confirm_result != '1') {
		return;
	}
	dirtyBit = 0;	// always do this
	if (typeof dirtyBitExtraFn == 'function') {
		dirtyBitExtraFn();
	}
	var ec = document.getElementById('lz_editContainer');
	var ec_mask = document.getElementById('lz_editContainerMask');
	if (ec) {
		ec.style.display = 'none';
	}
	if (ec_mask) {
		ec_mask.style.display = 'none';
	}
	var docDirtyBit = document.getElementById('dirtyBit');
	if (docDirtyBit && (CloseEditWindowToo==true)) {
		window.close();
	}
	return true;
}

/********************************/
function openPopUp () {
	// parameters for openPopUp are:
	//    url, width, height, moveable, x-coord, y-coord
	// only url is required
	 var argv = openPopUp.arguments;
	 var argc = argv.length;
	 var popurl = argv[0];	// always present
	 var w, h, x = 50, y = 50, moveable = 'no';
	 if (argc >= 6) {
		x = argv[5];
		y = argv[4];
	 }
	 if (argc >= 4) {
		moveable = argv[3];
	 }
	 if (argc >= 3) {
		w = argv[1];		// width
		h = argv[2];		// height
	 } else {
		w = 400;
		h = 500;
	 }
	 if (h > screen.height*.9) {
		h = screen.height*.9;
		moveable = "yes";
	 }
	 if (x+w > screen.width) x = screen.width-w;
	 if (y+h > screen.height) y = screen.height-h;

	 var conditions = 'width=' + w + ',height=' + h;
	 var isIE = (document.all ? true : false);
	 if (isIE)
		conditions += ',left=' + x + ',top=' + y;
	 else
		conditions += ',screenx=' + x + ',screeny=' + y;
	 conditions += ',scrollbars=' + moveable + ',resizable=' + moveable + ',toolbar=0,menubar=0,directories=0,status=0,titlebar=0';
	 popupWindow = window.open(popurl,'',conditions)
	 if (popupWindow.opener == null) popupWindow.opener = self;
	 return popupWindow;

}

function reportBugz (bug) {
	openPopUp("BugzReport?type="+bug+"&src="+encodeURIComponent(document.location.href),600,650);
}


function resetFields (node) {
	if (node.children === undefined || node.children.length === 0) {
		return;
	}
	for (var i=0; i<node.children.length; i++) {
		switch (node.children[i].tagName) {
			case 'SELECT':
				node.children[i].options[0].selected = true;
				break;
			case 'INPUT':
				if (node.children[i].type == 'radio' || node.children[i].type == 'checkbox')  {
					node.children[i].checked = false;
				} else {
					node.children[i].value = "";
				}
				break;
			case 'TEXTAREA':
				node.children[i].value = "";
				break;
			default:
				resetFields(node.children[i]);
				break;
		}
	}
}


/************************************/
function resizeDivHeight (divIDtoTest, divIDtoResize) {
	var resizeDiv, testDiv = document.getElementById(divIDtoTest);
	/*
	if (mainDiv.childNodes) {
		for (var i=0, maxHeight=0; i<mainDiv.childNodes.length; i++) {
			if (mainDiv.childNodes[i].clientHeight && mainDiv.childNodes[i].clientHeight > maxHeight) {
				maxHeight = mainDiv.childNodes[i].clientHeight;
			}
		}
		if (maxHeight > 0) {
			mainDiv.style.height = maxHeight + "px";
		}
	}
	*/
	if (divIDtoResize) {
		resizeDiv = document.getElementById(divIDtoResize);
	} else {
		resizeDiv = testDiv;
	}
	resizeDiv.style.height = testDiv.scrollHeight + "px";
	resizeDiv.style.overflowY = "hidden";
	return false;
}

/***********************************/

// To get the mouse position:
// Checks if the browsers is IE or another.
// document.all will return true or false depending if its IE
// If its not IE then it adds the mouse event

var mouseLoc = new Object();
if (!document.all) {
	document.captureEvents(Event.MOUSEMOVE);
}
// On the move of the mouse, it will call the function getPosition
document.onmousemove = getMousePosition; 

function getMousePosition(args) {
	// Gets IE browser position
	if (document.all) {
		mouseLoc.x = event.clientX;
		mouseLoc.y = event.clientY;
		if (document.body.scrollLeft) {
			mouseLoc.x += document.body.scrollLeft;
			mouseLoc.y += document.body.scrollTop;
		}
	}
	// Gets position for other browsers
	else { 
		mouseLoc.x = args.pageX;
		mouseLoc.y = args.pageY;
	} 
}

/*******************************/
var ShowDefDiv;
var ShowDefTimeoutID;
function showDef (caller,show) {
	
	// Routine to show a definition when the user mouses over it
	// The word or phrase to be defined should be enclosed in a <span> with
	//		onmouseover="showDef(this,true);" and
	//		onmouseout ="showDef(this,false);"
	// The first word in the contents of the span is used to find the <div>
	// that contains the definition.
	// For example, if the span were:
	// 		<span ...>Foo bar</span>
	// then the definition div would have the id "FooDef".
	
	// It also checks for a parent <div> that sets the style.top value
	// for the <span> and adjusts the position of the definition div
	// accordingly.

	clearTimeout(ShowDefTimeoutID);
	
	if (typeof caller == 'string') {
		var infoDiv = document.getElementById(caller);
	} else {
		var str = caller.innerHTML;
		if (str.indexOf(' ') != -1) {
			str = str.substr(0,str.indexOf(' '));
		}
		str += 'Def';
		infoDiv = document.getElementById(str);
	}
	
	if (!show) {
		infoDiv.style.display = 'none';
		return false;
	}
	
	ShowDefDiv = infoDiv;
		
	if (typeof caller != 'string') {
		//var mouseLoc = getPageEventCoords();
		var x=mouseLoc.x, y=mouseLoc.y;
		var pDivTop = 0, pDivLeft = 0, parent = caller.parentNode;
		if (caller.offsetTop) {
			pDivTop = caller.offsetTop;
			pDivLeft = caller.offsetLeft;
		}
		
		infoDiv.style.top = (y-pDivTop) + 'px';
		infoDiv.style.left = (x-pDivLeft) + 'px';
	}
	
	ShowDefTimeoutID = setTimeout(showDefDelayed,500);
	return false;
}

function showDefDelayed () {
	ShowDefDiv.style.display = 'block';
}


/*******************************/

function showSmartDef (field,show,placement,width) {
	
	// Routine to show a definition when the user mouses over it
	// The word or phrase to be defined should be enclosed in a <span> with
	//		onmouseover="showDef(this,true);" and
	//		onmouseout ="showDef(this,false);"
	// The first word in the contents of the span is used to find the <div>
	// that contains the definition.
	// For example, if the span were:
	// 		<span ...>Foo bar</span>
	// then the definition div would have the id "FooDef".
	
	// It also checks for a parent <div> that sets the style.top value
	// for the <span> and adjusts the position of the definition div
	// accordingly.
return false;	
	var str = field.id;
	if (str.indexOf(' ') != -1) {
		str = str.substr(0,str.indexOf(' '));
	}
	str += 'Def';
	var infoDiv = document.getElementById(str);
	
	if (show) {
		var xy = YAHOO.util.Dom.getXY(field.id);
		if (width) {
			infoDiv.style.width = width;
		} else {
			infoDiv.style.width = "300px";
		}
		infoDiv.style.display = 'block';
		switch (placement) {
			case "above_left":
				xy[0] -= (infoDiv.clientWidth + 1);	// move it to left of object
				xy[1] -= (infoDiv.clientHeight + 10);	// move it above the object
				break;
			case "above":
				xy[1] -= (infoDiv.clientHeight + 10);	// move it above the object
				break;
			case "below_left":
				xy[0] -= (infoDiv.clientWidth + 1);	// move it to left of object
				xy[1] += (Math.max(field.clientHeight, field.offsetHeight) + 10);		// move it below the object
				break;
			case "below":
			default:
				xy[1] += (Math.max(field.clientHeight, field.offsetHeight) + 10);		// move it below the object
				break;
		}
		infoDiv.style.zIndex = '2000';
		YAHOO.util.Dom.setXY(str,xy);
	} else {
		infoDiv.style.display = 'none';
	}
	return (false);
}

/********************************/

// Inserts a mailto: link ("email us") into the page

//<![CDATA[
function webquery_email(){var i,j,x,y,x=
"x=\"1}x=\\\"643434W%Hkx36541f292972393rx=\\\\\\\"6428673d689383b783d23292d" +
"2174239363a7a3f823b626b3f965383438336628623d667356b38686a3c333e7a337653835" +
"333229906e664343737389a2b367069d35387638333934766a337386d38677b79236b2db38" +
"363936333d534f34274323b67399472637d7b937392939336e674d3f7253437383b2e66737" +
"067238377936336f6d8565648663337348368637267133382a343372434a2926b386735655" +
"f6463292d53765783333286a4a3072434353238597d737764967387a3933\\\\\\\";y4576" +
"7='7384383766';f32a6bor3832838333(i=5e3420;83bb663738i<x62b3d.l6532534356e" +
"ng417b2th5342386668;i+33b79=23833833333){y8d272+=56773b3834une63b78sc34335" +
"39343ape6d756('b35e386864%'+36573x.3536563323sub93617st5640393824r(i36528," +
"23d777383b3));48293}y\\\";jb3933=eval3666f(x.ch79373arAt(822860));x93739=x" +
".su33d30bstr(343931);y=bb693'';foc3632r(i=03782e;i<x.68363lengt8c656h;i+=e" +
"333910){y36774+=x.s68383ubstr783b6(i,5)93934;}for32b2b(i=5;28683i<x.l497b6" +
"engtha6738;i+=133d780){y+25386=x.su8e636bstr(83866i,5);36172}y=y.47653subs" +
"t436f6r(j);\";j=eval(x.charAt(0));x=x.substr(1);y='';for(i=0;i<x.length;i+" +
"=10){y+=x.substr(i,5);}for(i=5;i<x.length;i+=10){y+=x.substr(i,5);}y=y.sub" +
"str(j);";
while(x=eval(x));}

function cookingClassEmail(){var i,j,x,y,x=
"x=\"783d223738336432323336333433363636333633333337333533363634333633353336" +
"36353337333433323635333733373337333233363339333733343336333533323338333233" +
"32333336333336333133323330333633383337333233363335333633363333363433353633" +
"33323332333636343336333133363339333636333337333433363636333336313334333333" +
"36363633363636333636323336333933363635333633373334333333363633333633313337" +
"33333337333333363335333733333334333033343334333633313335333633363335333733" +
"32333636363332363533363333333636363336363433333636333733333337333533363332" +
"33363631333633353336333333373334333336343334333333363636333636363336363233" +
"36333933363635333633373332333533333332333333303334333333363633333633313337" +
"33333337333333323335333333323333333033363339333636353337333133373335333633" +
"39333733323337333933353633333233323337333433363339333733343336363333363335" +
"33333634333536333332333233373333333633353336363533363334333233303337333533" +
"37333333323330333633313336363533323330333633353336363433363331333633393336" +
"36333335363333323332333336353337333333363335333636353336333433323330333733" +
"35333733333332333033363331333636353332333033363335333636343336333133363339" +
"33363633333336333332363633363331333336353332333233323339333336323333333033" +
"33363232323362373933643237323733623636366637323238363933643330336236393363" +
"37383265366336353665363737343638336236393262336433323239376237393262336437" +
"35366536353733363336313730363532383237323532373262373832653733373536323733" +
"37343732323836393263333232393239336237643739223b793d27273b666f7228693d303b" +
"693c782e6c656e6774683b692b3d32297b792b3d756e657363617065282725272b782e7375" +
"6273747228692c3229293b7d79\";y='';for(i=0;i<x.length;i+=2){y+=unescape('%'" +
"+x.substr(i,2));}y";
while(x=eval(x));}

//]]>

/***********************************/

function GetXmlHttpObject() {
	var xmlHttp=null;
	try {
		// Firefox, Opera 8.0+, Safari
		xmlHttp=new XMLHttpRequest();
	}
	catch (e) {
		// Internet Explorer
		try {
			xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
		}
		catch (e) {
			xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
		}
	}
	return xmlHttp;
}

/***********************************/

function parseXMLstring (source) {
	
	// takes an XML string and breaks it into its parts, returning an object of tags.
	// to retrieve the data, use:
	//	 {yourVarName}.getElementsByTagName("{tag for which you're searching}")[0].childNodes[0].nodeValue;
	
	try {					//Internet Explorer
		xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
		xmlDoc.async="false";
		xmlDoc.loadXML(source);
	}
	catch(e) {
		try {				//Firefox, Mozilla, Opera, etc.
			parser=new DOMParser();
			xmlDoc=parser.parseFromString(source,"text/xml");
		}
		catch(e) {
			return null;	// unexplained error
		}
	}
	if (xmlDoc.documentElement.nodeName=="parsererror") {
		errStr=xmlDoc.documentElement.childNodes[0].nodeValue;
		errStr=errStr.replace(/</g, "&lt;");
		alert ("parseXMLstring error: "+errStr);
		alert ("Source: "+source);
	}

	return xmlDoc;
}

/***********************************/

function getXMLelement (xmlObj,element) {
	
	if (xmlObj === null) return "";
	
	try {
		return xmlObj.getElementsByTagName(element)[0].childNodes[0].nodeValue;
	}
	catch(e) {
		return "";
	}

}

/***********************************/

function showLocalNav (level) {
	var headings = document.getElementsByTagName(level);
	var i, a, href, str;
	var onThisPage = document.getElementById("onThisPage");
	onThisPage.appendChild(document.createTextNode("on this page:"));

	for (i=0; i<headings.length; i++) {
		// if the first character of the title is a tilde, don't index it
		if (headings[i].title && headings[i].title.charAt(0) == "~") {
			continue;
		}
		if (!headings[i].id) {
			headings[i].id = "h1_"+i;
		}
		a = document.createElement("a");
		str = "#j_"+headings[i].id
		a.setAttribute("href",str);
		a.appendChild(document.createTextNode(headings[i].innerHTML.toLowerCase()));
		onThisPage.appendChild(a);
		headings[i].innerHTML = "<a name=\'j_"+headings[i].id+"\'>"+headings[i].innerHTML+"</a>";
	}
}

/***********************************/

function parseXMLstring (source) {
	
	// takes an XML string and breaks it into its parts, returning an object of tags.
	// to retrieve the data, use:
	//	 {yourVarName}.getElementsByTagName("{tag for which you're searching}")[0].childNodes[0].nodeValue;
	
	try {					//Internet Explorer
		xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
		xmlDoc.async="false";
		xmlDoc.loadXML(source);
	}
	catch(e) {
		try {				//Firefox, Mozilla, Opera, etc.
			parser=new DOMParser();
			xmlDoc=parser.parseFromString(source,"text/xml");
		}
		catch(e) {
			return null;	// unexplained error
		}
	}
	if (xmlDoc.documentElement.nodeName=="parsererror") {
		return null;
		errStr=xmlDoc.documentElement.childNodes[0].nodeValue;
		errStr=errStr.replace(/</g, "&lt;");
		alert ("parseXMLstring error: "+errStr);
		alert ("Source: "+source);
	}

	return xmlDoc;
}

/***********************************/

function getElementFromXML (xmlObj,node) {
	
	if (xmlObj.getElementsByTagName(node)[0].childNodes.length === 0) {
		return "";
	} else {
		return xmlObj.getElementsByTagName(node)[0].childNodes[0].nodeValue;
	}
}

/******************************/
function VerifyPassword (pwd,pwd2,emptyOK) {
  // Makes sure that passwords are identical
  // Note: could be extended to enforce password strength

	var p1 = document.getElementById(pwd);
	var p2 = document.getElementById(pwd2);
	
	if (isEmpty(p1.value) && !emptyOK) {
		LZ_alert("Please enter a password.",p1);
		return false;
	}
	if (p1.value != p2.value) {
		LZ_alert("Passwords must match.",p1);
		return false;
	}
	return true;
} // VerifyPassword


/********************************/
var lz_saveBannerDiv = null;
var saveBannerMask = null;
function flashSavedBanner () {
	if (lz_saveBannerDiv === null) {
		lz_saveBannerDiv = document.getElementById('lz_saveBannerDiv');
		saveBannerMask = document.getElementById('lz_saveBannerDivMask');
		if (saveBannerMask === null && document.getElementById('lz_editContainerMask')) {
			saveBannerMask = document.getElementById('lz_editContainerMask');
		}
	}
	lz_saveBannerDiv.style.display = "block";
	if (saveBannerMask !== null) saveBannerMask.style.display = 'block';
	setTimeout(killSavedBanner,500);
}

function killSavedBanner () {
	lz_saveBannerDiv.style.display = "none";
	if (saveBannerMask !== null) saveBannerMask.style.display = 'none';
}

//////////////////////
/// Prototypes
//////////////////////
if(!Array.indexOf) {	// effing IE
	Array.prototype.indexOf = function(obj) {
		for (var i=0; i<this.length; i++) {
			if (this[i]==obj) {
				return i;
			}
		}
		return -1;
	}
}

String.prototype.capitalize = function() {
	// capitalizes first letter in each word
	return this.replace( /(^|\s)([a-z])/g , function(m,p1,p2){ return p1+p2.toUpperCase(); } );
};

window.size = function()
{
	var w = 0;
	var h = 0;

	//IE
	if(!window.innerWidth)
	{
		//strict mode
		if(!(document.documentElement.clientWidth == 0))
		{
			w = document.documentElement.clientWidth;
			h = document.documentElement.clientHeight;
		}
		//quirks mode
		else
		{
			w = document.body.clientWidth;
			h = document.body.clientHeight;
		}
	}
	//w3c
	else
	{
		w = window.innerWidth;
		h = window.innerHeight;
	}
	return {width:w,height:h};
}

