/* COMMON DHTML FUNCTIONS */

/****************************************
 *			EVENT MANAGEMENT			*
 ****************************************/
 
/**
 * X-browser event handler attachment and detachment
 * TH: Switched first true to false per http://www.onlinetools.org/articles/unobtrusivejavascript/chapter4.html
 * @argument evType - name of the event - DONT ADD "on", pass only "mouseover", etc
 */
function addEvent(obj, evType, fn){
	if (obj.addEventListener){
    	obj.addEventListener(evType, fn, false);
	    return true;
	} else if (obj.attachEvent){
		return obj.attachEvent("on"+evType, fn);
	}
	return false;
}
function removeEvent(obj, evType, fn, useCapture){
	if (obj.removeEventListener){
    	obj.removeEventListener(evType, fn, useCapture);
		return true;
	} else if (obj.detachEvent){
    	return obj.detachEvent("on"+evType, fn);
	}
	alert("Handler could not be removed");
}

/****************************************
 *			WINDOW MANAGEMENT			*
 ****************************************/

function showWindow(url, name, width, height, bReplace, bResizable) {

    width	= (width)  ? width	: "750px";
    height	= (height) ? height	: "350px";
    name	= (name)   ? name	: "_blank";
    bResizable = (bResizable) ? bResizable : "yes";

	// Calculate the center coordinates    
	var fullHeight	= getViewportHeight();
	var fullWidth	= getViewportWidth();
	var viewTop		= (window.screenTop)  ? window.screenTop  : window.screenY + 200;
	var viewLeft	= (window.screenLeft) ? window.screenLeft : window.screenX;
	var newLeft		= viewLeft + (fullWidth - parseInt(width, 10)) / 2;
	var newTop		= viewTop + (fullHeight - parseInt(height, 10)) / 2;

    var newWindow = window.open(url, name, "width="+width+",height="+height+",status=no,resizable="+bResizable+",toolbar=no,scrollbars=yes,menubar=no,location=no", bReplace);
    newWindow.moveTo(newLeft, newTop);
    newWindow.focus();
    
    return newWindow;
}
function urlNav(url, target) {
	document.location=url;
}
/**
 * Code below taken from - http://www.evolt.org/article/document_body_doctype_switching_and_more/17/30655/
 * Modified 4/22/04 to work with Opera/Moz (by webmaster at subimage dot com)
 * Gets the full width/height because it's different for most browsers.
 */
function getViewportHeight() {
	if (window.innerHeight!=window.undefined) return window.innerHeight;
	if (document.compatMode=='CSS1Compat') return document.documentElement.clientHeight;
	if (document.body) return document.body.clientHeight; 
	return window.undefined; 
}
function getViewportWidth() {
	if (window.innerWidth!=window.undefined) return window.innerWidth; 
	if (document.compatMode=='CSS1Compat') return document.documentElement.clientWidth; 
	if (document.body) return document.body.clientWidth; 
	return window.undefined; 
}
/**
 * Gets the real scroll top
 */
function getScrollTop() {
	if (self.pageYOffset) { // all except Explorer
		return self.pageYOffset;
	} else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
		return document.documentElement.scrollTop;
	} else if (document.body) { // all other Explorers
		return document.body.scrollTop;
	}
}
function getScrollLeft() {
	if (self.pageXOffset) { // all except Explorer
		return self.pageXOffset;
	} else if (document.documentElement && document.documentElement.scrollLeft) { // Explorer 6 Strict
		return document.documentElement.scrollLeft;
	} else if (document.body) { // all other Explorers
		return document.body.scrollLeft;
	}
}
/****************************************
 *			FORMAT MANAGEMENT			*
 ****************************************/

function rightTrim() {
    return this.replace(/\s+$/gi, "");
}
function leftTrim() {
    return this.replace(/^\s*/gi, "");
}
function rightPad(str, padChar, length) {
	while (str.length < length) {
		str = str + padChar;
	}
	return str;
}
function leftPad(str, padChar, length) {
	while (str.length < length) {
		str = padChar + str;
	}
	return str;
}
function Trim() {
    return this.rightTrim().leftTrim();	
}
function trimString(str) {
	str = new String(str).replace(/\s+$/gi, "");
	return str.replace(/^\s*/gi, "");
}
String.prototype.rightTrim = rightTrim;
String.prototype.leftTrim = leftTrim;
String.prototype.Trim = Trim;

function stripAll(str, pattern) {
	var result = "";
    var sections = str.split(pattern);
    for (var i = 0; i < sections.length; i++) {
        result+=sections[i];
	}
    return result;
}
function addslashes(str) {
	str=str.replace(/\\/g,'\\\\');
	str=str.replace(/\'/g,'\\\'');
	str=str.replace(/\"/g,'\\"');
	str=str.replace(/\0/g,'\\0');
	return str;
}
function stripslashes(str) {
	str=str.replace(/\\'/g,'\'');
	str=str.replace(/\\"/g,'"');
	str=str.replace(/\\0/g,'\0');
	str=str.replace(/\\\\/g,'\\');
	return str;
}
function expandDouble(val, fractionDigits) {

	var str = (val instanceof String) ? val : new String(val);
	str = stripAll(str, ",");
	// Expand abbreviated values e.g. 1B, 45.67M etc
	var length = str.length;
	var floatValue = parseFloat(str.substring(0, length));
	var lastChar = str.charAt(length - 1);
	if (lastChar == 'B' || lastChar == 'b') {
		floatValue *= 1000000000;
	} else if (lastChar == 'M' || lastChar == 'm') {
		floatValue *= 1000000;
	} else if (lastChar == 'K' || lastChar == 'k') {
		floatValue *= 1000;
	}
	floatValue = (fractionDigits != undefined) ? new Number(new Number(floatValue).toFixed(fractionDigits)) : floatValue;
	return floatValue;
}
			            
function formatDouble(val, fractionDigits) {
	
	var pattern = ",";
	var interval = 3;
	var str = (val instanceof String) ? val : new String(val);
	
	var num = expandDouble(str, fractionDigits != undefined && fractionDigits >= 0 ? fractionDigits : 0);
	if (isNaN(num) || !isFinite(num)) {
		return "";
	}
	str = new Number(num).toString();

	var sign = "";
	if (str.length > 2) {
		if (str.charAt(0) == '-') {
			str = str.substring(1, str.length);
			sign = "-";
		} else if (str.charAt(0) == "+") {
			str = str.substring(1, str.length);
			sign = "+";
		}
	}	
	var mantissa = "";	
	var exponentLength = str.indexOf('.');
	if (exponentLength != -1) {
		mantissa = str.substring(exponentLength, str.length);
		if (fractionDigits != undefined){
			if (fractionDigits > 0) {
				if (mantissa.length > fractionDigits) {
					mantissa = mantissa.substring(0, fractionDigits + 1);
				} else {
					for (var i = mantissa.length; i <= fractionDigits; i++) {
						mantissa += "0";
					}
				}
			} else {
				mantissa = "";
			}
		}
	} else {
    	exponentLength = str.length;
		if (fractionDigits != undefined && fractionDigits > 0) {
			mantissa += ".";
			for (var i = mantissa.length; i <= fractionDigits; i++) {
				mantissa += "0";
			}
		}
	}
	
	var sections = str.split("");
	var count = 1;               	
	var result = "";               	
	for (var i = exponentLength - 1; i >= 0; i--) {
	    if (count > interval) {
	    	result = sections[i] + pattern + result;
	    	count = 1;
	    } else {
		    result = sections[i] + result;
	    }
	    count++;
	}
	return sign + result + mantissa;
}
function escapeString(str) {
	if (!str || str.length < 0) {
		return str;
	}
	// Reference: http://www.cs.sfu.ca/~ggbaker/reference/characters/#other
	var escaped = str;
	escaped = escaped.replace("&(?!#)", "&#x0026;");
	escaped = escaped.replace("<", 		"&#x003C;");
	escaped = escaped.replace(">", 		"&#x003E;");
	escaped = escaped.replace("\"", 	"&#x0022;");
	escaped = escaped.replace("'", 		"&#x0027;");
	escaped = escaped.replace("`", 		"&#x0060;");
	escaped = escaped.replace("�", 		"&#x2018;");
	escaped = escaped.replace("�", 		"&#x2019;");
	escaped = escaped.replace("�", 		"&#x201C;");
	escaped = escaped.replace("�", 		"&#x201D;");
	escaped = escaped.replace(/\u2022/, "&#x2022;");//� (bullet)
	escaped = escaped.replace(/\u00B0/, "&#x00B0;");//� (degree)
	escaped = escaped.replace(/\u00B0/, "&#x00B0;");//� (interpunct)
	escaped = escaped.replace(/\u00AB/, "&#x00AB;");//� (guillemet left)
	escaped = escaped.replace(/\u00BB/, "&#x00BB;");//� (guillemet right)
	escaped = escaped.replace(/\u0024/, "&#x0024;");//� (cent)
	escaped = escaped.replace(/\u00A2/, "&#x00A2;");//$ (dollar)
	escaped = escaped.replace(/\u20AC/, "&#x20AC;");//� (Euro)
	escaped = escaped.replace(/\u00A3/, "&#x00A3;");//� (Pound)
	escaped = escaped.replace(/\u00A5/, "&#x00A5;");//� (Yen)
	escaped = escaped.replace(/\u20A6/, "&#x20A6;");//? (Naira)
		 
	escaped = escaped.replace(/\u2032/, "&#x2032;");
	escaped = escaped.replace(/\u2033/, "&#x2033;");
	escaped = escaped.replace(/\u3003/, "&#x3003;");
	return escaped;
}
function fixURL(url) {
	if (url.indexOf("http://") == 0) {
		url = (url.length > 7) ? url : ("http://" + url);
	} else if (url.indexOf("https://") == 0) {
		url = (url.length > 8) ? url : ("https://" + url);
	} else {
		url = "http://";
	}
	if (url.match(/http\:\/(.)?/)) { 
		url = url.replace(/(http\:\/(.)?http(.)?\:\/(.)?)/, "http://"); 
	} else if (url.match(/https\:\/(.)?/)) { 
		url = url.replace(/(http(.)?\:\/(.)?http(.)?\:\/(.)?)/, "https://"); 
	}
	return url;
}
function enforceInputLength(input, maxlength, output) {
	var text = input.value;
	if (text && text.length > maxlength) {
		input.value = text.substring(0, maxlength);
	}
	getObject(output).innerHTML = maxlength - text.length;
}

/****************************************
 *			FORM DATA MANAGEMENT		*
 ****************************************/
function formClear(form) {
	var elements = form.elements;
	for (var i = 0; i < elements.length; i++) {
    	var objElement = elements[i];
		if (objElement.tagName == "INPUT" || objElement.tagName == "SELECT" || objElement.tagName == "TEXTAREA") {    
			if (objElement.type != "submit" && objElement.type != "reset") {
				if (objElement.type == "radio" || objElement.type == "checkbox" ) {
					objElement.checked = false;
				} else {
					objElement.value = "";	
				}
			}
		}
	}
}
function showLoadIcon(loaderID, busyMessage, iconPath) {
	var loadingElement = null;
	if (loaderID && (loadingElement = getObject(loaderID))) {
		var childNodes = loadingElement.getElementsByTagName('*');
		for (var i = 0; i < childNodes.length; i++) { childNodes[i].style.display = "none"; }
		
		var obj_DIV = document.createElement("DIV");
		busyMessage = (busyMessage != undefined) ? busyMessage : (window.busyMessage ? window.busyMessage : "Processing. Please wait.");
		obj_DIV.className = "loading";
		obj_DIV.innerHTML = "<em class='soft'> " + busyMessage + "</em>";
		obj_DIV.style.margin = "auto";
		obj_DIV.style.display = "inline";
		
		var obj_Loading = document.createElement("IMG");
		obj_Loading.src = iconPath ? iconPath : (window.getCDN() + "/images/icons/loading.gif");
		obj_Loading.setAttribute("align", "absmiddle");
		obj_Loading.style.margin = "0px 10px 0px 10px";
		
		loadingElement.appendChild(obj_DIV);
		loadingElement.appendChild(obj_Loading);
	}
	//alert('loaderID=' + loaderID + ', loadingElement=' + loadingElement);
}
function formSubmit(form, action, loaderID) {
	if (isFormValid(form)) {
		loadDefaults(form);
		form.target = (form.target) ? form.target : "_self";
		form.action	= (action) ? action : document.location;
		loaderID = (loaderID) ? loaderID : "formsubmitcontainer";
		showLoadIcon(loaderID);
		form.submit();
		return true;
	}
	return false;
}
function formSubmitAsync(xmlHttp, form, action, responseHandler, loaderID) {
	xmlHttp = (xmlHttp) ? xmlHttp : getDefaultXMLHttpObject();
	var elements = form.elements;
	var parameters = "?";

	for (var i = 0; i < elements.length; i++) {
		var objElement = elements[i];
		//alert("elements["+i+"].name="+elements[i].name+", className="+elements[i].className+", className="+elements[i].tagName);
		if (objElement.type != 'hidden' && !objElement.disabled && !isFormDataValid(objElement)) {
			return;
		}
		var name	= (objElement.name) ? objElement.name.Trim() : "";
		var tagName = (objElement.tagName) ? objElement.tagName.Trim().toLowerCase() : "";
		var type 	= (objElement.type) ? objElement.type.Trim().toLowerCase() : "";
		var value	= (tagName == "select") ? getSelectValue(objElement) : objElement.value;
		if ((tagName == "input" || tagName == "select" || tagName == "textarea") && 
				name.length > 0 && !objElement.disabled && 
				((type != "checkbox" && type != "radio") || objElement.checked)) {
			parameters += "&"+name+"="+encodeURIComponent(value);
		}
    }
	loadDefaults(form);
	//alert(parameters);
	loaderID = (loaderID) ? loaderID : "formsubmitcontainer";
	showLoadIcon(loaderID);
	var formAction = (action) ? action : document.location;
	xmlHttpPostData(xmlHttp, formAction, parameters, responseHandler);
    return;
//	form.target = (form.target) ? form.target : "_self";
//	form.action	= (action) ? action : document.location;
//	form.submit();
}
function isFormValid(form) {
	var elements = form.elements;
	for (var i = 0; i < elements.length; i++) {
		var objElement = elements[i];
		if (objElement.type != 'hidden' && !objElement.disabled && !isFormDataValid(objElement)) {
			return false;
		}
    }
    return true;
}
function loadDefaults(form) {
	var elements = form.elements;
	for (var i = 0; i < elements.length; i++) {
		var defaultValue = elements[i].getAttribute("default");
		if (elements[i].value == '' && (defaultValue != null && defaultValue != undefined)) {
			elements[i].value = defaultValue;
		}
    }
}
var FORM_ERROR_MESSAGE = null;
function isFormDataValid(objElement)  {
	
	var wasValidated = true;
	var errorMsg = "";
	// Check for the existence of a validation function
	var callback = objElement.getAttribute("validate");
    if (callback && (callback = eval("window."+callback))) {
    	var minChars = objElement.getAttribute("minchars");
    	var maxChars = objElement.getAttribute("maxchars");
    	var minNum	 = objElement.getAttribute("minnum");
    	var maxNum	 = objElement.getAttribute("maxnum");
    	
		FORM_ERROR_MESSAGE = null;
		wasValidated = (!minChars || isValid(objElement.value, null, minChars)) &&
					(!maxChars || isValid(objElement.value, null, null, maxChars)) &&
					(!minNum || isValidDecimal(objElement.value, minNum, null)) &&
					(!maxNum || isValidDecimal(objElement.value, null, maxNum));
					
    	if (!wasValidated || !callback.call(objElement, objElement.value)) {
    		var defaultValue = objElement.getAttribute("default");
			if (defaultValue != null && defaultValue != undefined) {
    			objElement.value = ""; // Will be set to default at final submit
    			wasValidated = true;
    		} else {
				highlightElement(objElement, true);
				//errorMsg = errorMsg ? errorMsg : objElement.getAttribute("errmsg");
				FORM_ERROR_MESSAGE = (FORM_ERROR_MESSAGE) ? FORM_ERROR_MESSAGE : "One of the required inputs is invalid";
				FORM_ERROR_MESSAGE += "\n\nPlease amend the highlighted item and retry.";
				alert(FORM_ERROR_MESSAGE);
				//alert(errorMsg ? errorMsg : "The highlighted item contains an invalid value. Please amend it then retry.");
				FORM_ERROR_MESSAGE = null;
				wasValidated = false;
			}
		} else {
			highlightElement(objElement, false);
		}
    }
	return wasValidated;
}

/****************************************
 *			DATA VALIDATION				*
 ****************************************/
// http://www.the-art-of-web.com/javascript/escape/
var LEGAL_NUMBERS		= '0123456789';
var LEGAL_DECIMALS		= LEGAL_NUMBERS + unescape('.-+%2C'); // '.-+,';
var LEGAL_HEXADECIMALS 	= LEGAL_NUMBERS + 'ABCDEFabcdef';
var LEGAL_UPPERCASE_CHARACTERS	= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var LEGAL_LOWERCASE_CHARACTERS	= 'abcdefefghijklmnopqrstuvwxyz';
var LEGAL_CHARACTERS	= LEGAL_UPPERCASE_CHARACTERS + LEGAL_LOWERCASE_CHARACTERS;;
var LEGAL_PRINTABLES 	= LEGAL_DECIMALS + LEGAL_CHARACTERS;
var LEGAL_URL_CHARACTERS = LEGAL_PRINTABLES + unescape('@%26%25%3F%3D_%3A*%24%23%21%27%5E%7E%3B%28%29/'); // '@&%?=_:*$#!\'^~;()/'
function isValidDecimal(string, minNum, maxNum) {
	//alert("string="+string+",minNum="+minNum+",maxNum="+maxNum);
    if (!isValid(string, LEGAL_DECIMALS)) {
    	//FORM_ERROR_MESSAGE = "The value is not an acceptable number min="+minNum+", max="+maxNum;
    	return false;
    }
    var value = parseFloat(stripAll(string, ","));
    minNum = (minNum) ? parseFloat(stripAll(minNum, ",")) : -Number.MAX_VALUE;
    if (minNum && value < minNum) {
    	FORM_ERROR_MESSAGE = "The value should be greater than or equal to " + minNum;
    	return false;
    }
    maxNum = (maxNum) ? parseFloat(stripAll(maxNum, ",")) : Number.MAX_VALUE;
    if (maxNum && value > maxNum) {
    	FORM_ERROR_MESSAGE = "The value should be less than or equal to " + maxNum;
    	return false;
    }
    return true;
}
function isValidPrintable(string, minChars, maxChars) {
	return isValid(string, LEGAL_PRINTABLES, minChars, maxChars);
}
function isValidAlphaNumeric(string, minChars, maxChars) {
	return isValid(string.Trim(), LEGAL_NUMBERS + LEGAL_CHARACTERS, minChars, maxChars);
}
function isValidName(string, minChars, maxChars) {
	return isValid(string.Trim(), LEGAL_NUMBERS + LEGAL_CHARACTERS + '.-+/' + ' ', minChars, maxChars);
}
function isValidString(string, minChars, maxChars) {
	return isValid(string, null, minChars, maxChars);
}
function isValid(string, allowed, minChars, maxChars) {
    if (string == null || string == undefined || (string = trimString(string)) == "") {
    	FORM_ERROR_MESSAGE = "The value is empty";
    	return false;
    }
    if (minChars && string.length < minChars) {
    	FORM_ERROR_MESSAGE = "The length of the value is should be greater than or equal to " + minChars;
    	return false;
    }
    if (maxChars && string.length > maxChars) {
    	FORM_ERROR_MESSAGE = "The length of the value is should be less than or equal to " + maxChars;
    	return false;
    }
    if (allowed != null && allowed != undefined && allowed.length > 0) {
	    for (var i=0; i < string.length; i++) {
	        if (allowed.indexOf(string.charAt(i)) == -1) {
	        	FORM_ERROR_MESSAGE = string + " contains an illegal character: " + string.charAt(i) + " at position " + i;
	            return false;
	        }
	    }
	}
    return true;
}
function isValidURL(string) {
    var v = new RegExp();
    v.compile(/(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i);
    if (!v.test(string)) {
        alert("The URL is not valid");
        return false;
    } 
	return true;
}
var DEFAULT_EMAIL_ERROR_MESSAGE = "The email address is improperly formatted";
function isValidEmail(string) {
	
	var LEGAL_EMAIL_CHARACTERS = LEGAL_NUMBERS + LEGAL_CHARACTERS;
	if (!isValid(string, LEGAL_EMAIL_CHARACTERS + '._-@', 6)) {
		FORM_ERROR_MESSAGE = DEFAULT_EMAIL_ERROR_MESSAGE + ". (Error Code 1)";
		return false;
	}
	if (LEGAL_EMAIL_CHARACTERS.indexOf(string.charAt(0)) == -1 || 
			LEGAL_CHARACTERS.indexOf(string.charAt(string.length - 1)) == -1) {
		FORM_ERROR_MESSAGE = DEFAULT_EMAIL_ERROR_MESSAGE + ". (Error Code 2)";
		return false;
	}
	var at1 = string.indexOf('@');
	var at2 = string.lastIndexOf('@');
	var dot1 = string.lastIndexOf('.');
	if (at1 == -1 || at1 != at2 || dot1 == -1 || at1 > dot1) {
		FORM_ERROR_MESSAGE = DEFAULT_EMAIL_ERROR_MESSAGE + ". (Error Code 3)";
		return false;
	}
	var hy1 = string.indexOf('-');
	if (hy1 == 0 || hy1 == (string.length - 1) ||
			LEGAL_EMAIL_CHARACTERS.indexOf(string.charAt(hy1 - 1)) == -1 ||
			LEGAL_EMAIL_CHARACTERS.indexOf(string.charAt(hy1 + 1)) == -1) {
		FORM_ERROR_MESSAGE = DEFAULT_EMAIL_ERROR_MESSAGE + ". (Error Code 4)";
		return false;
	}
	FORM_ERROR_MESSAGE = null;
	return true;
}
function isValidUsername(string) {
	if (!isValid(string, LEGAL_NUMBERS + LEGAL_CHARACTERS)) {
	    FORM_ERROR_MESSAGE = "Your username must only consist of alphabets and numeric characters";
	    return false;
	}
	if (LEGAL_CHARACTERS.indexOf(string.charAt(0)) == -1) {
		FORM_ERROR_MESSAGE = "Your username must start with an alphabetic character";
	    return false;
	}
	FORM_ERROR_MESSAGE = null;
	return true;
}
function isValidDate(string, allowed) {
	var sections= string.split('-');
	var yyyy	= sections[0];
	var mm		= sections[1];
	var dd		= sections[2];

    if (!isValid(yyyy, LEGAL_NUMBERS, 4, 4) ||
    		!isValid(mm, LEGAL_NUMBERS, 2, 2) || !isValid(dd, LEGAL_NUMBERS, 2, 2)) {
	    FORM_ERROR_MESSAGE += "\nThe date is improperly formatted";
	    return false;
    }
    FORM_ERROR_MESSAGE = null;
    return true;
}
/* Added by NG */
var MONTH_NAMES=new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
function parseDateYYYYMMDD(dateString) {
	var sections= dateString.split('-');
	var yyyy	= sections[0];
	var mm		= sections[1];
	var dd		= sections[2];
	return new Date(MONTH_NAMES[mm - 1] + ', ' + dd + ' ' + yyyy);
}

/****************************************
 *			PARAMETER MANAGEMENT		*
 ****************************************/

function createParameters(quantity) {
	//alert('createParameters('+quantity+')');
    document.paramArray = new Array(quantity);    
    for (var i = 0; i < document.paramArray.length; i++) {
        document.paramArray[i] = new Array(4);
    	document.paramArray[i][0] = null; // label
    	document.paramArray[i][1] = null; // value
    	document.paramArray[i][2] = null; // type
    	document.paramArray[i][3] = null; // class name
    	document.paramArray[i][4] = null; // onchange
    	document.paramArray[i][5] = null; // validation callback
    	document.paramArray[i][6] = null; // style
    }
}
function setParameter(index, label, value, type, className, onchange, validate, style) {
    //alert('setParameter('+index+','+label+','+value+')');
    if (document.paramArray && index < document.paramArray.length) {
    	if (value != null) {
    	    document.paramArray[index][0] = label;
    	    document.paramArray[index][1] = (value) ? value : "";
    	    document.paramArray[index][2] = (type) ? type : "text";
    	    document.paramArray[index][3] = (className) ? className : "text";
    	    document.paramArray[index][4] = (onchange) ? onchange : "";
    	    document.paramArray[index][5] = (validate) ? validate: "";
    	    document.paramArray[index][6] = (style) ? style : "";
        } else {
    	    document.paramArray[index][0] = null;
    	    document.paramArray[index][1] = null;
    	    document.paramArray[index][2] = null;
    	    document.paramArray[index][3] = null;
    	    document.paramArray[index][4] = null;
    	    document.paramArray[index][5] = null;
    	    document.paramArray[index][6] = null;
        }
    }
}
function showParameterDialog(url, callback, width, height) {
    var i = 0;    
    for (; document.paramArray && i < document.paramArray.length; i++) {	
    	if (document.paramArray[i][0] == null) {
    	    break;
    	}
    }    
	width 	= (width) 	? width   : "320px";
	height	= (height) 	? height  : "200px";
	url		= (url)		? url	  : (getBase()+"/jsp/tools/parameters.jsp?numparams="+i);

	document.paramCallback = (callback) ? callback : objectCallback;
	showWindow(url, "paramdialog", width, height);
}
function objectCallback(values) {
	var objOBJECT = document.documentElement.getElementsByTagName('OBJECT')[0]; 
	//alert(objOBJECT.innerHTML);
    for (i = 0; i < values.length; i++) {                
    	document.paramArray[i][1] = values[i];
        objOBJECT.handleCallback('setParameterValue'+i, values[i]);
	}
}

/****************************************
 *			XML DATA MANAGEMENT			*
 ****************************************/

var xmlHttpObject = createXMLHTTPObject();
function createXMLHTTPObject() {
	var xmlHttp;	
	/*@cc_on
	@if(@_jscript_version >= 5)
		try {
			xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
		} catch(e) {
			try {
				xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
			} catch(exception) {
				xmlHttp = false;
			}			  
		}
	@else
		xmlHttp = false;
	@end @*/
	if (!xmlHttp && typeof XMLHttpRequest != 'undefined') {
		try {
			xmlHttp = new XMLHttpRequest();
		} catch(e) {
			xmlHttp = false;
		}
	}		
	return xmlHttp;		
}
function createXMLHTTPObjectALTERNATIVE(url) {
  var xhr;
  try {
    xhr = new XMLHttpRequest();
  } catch (e) {
    var a = ['MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0',
      'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'MICROSOFT.XMLHTTP.1.0',
      'MICROSOFT.XMLHTTP.1', 'MICROSOFT.XMLHTTP'];
    for (var i = 0; i < a.length; i++) {
      try {
        xhr = new ActiveXObject(a[i]);
        break;
      } catch (e) {
      }
    }
  }
  if (xhr) {
    xhr.open("POST", url, true);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    var data = '&js=' + encodeURIComponent(top.js.document.body.innerHTML);
    xhr.send(data);
  }
}
function getDefaultXMLHttpObject() {
	return xmlHttpObject;
}
function xmlHttpLoadData(xmlHttp, url, responseHandler, loaderID, abortPendingCalls, canLoadFromCache) {
	abortPendingCalls = (abortPendingCalls == null) ? true : abortPendingCalls;
	if (abortPendingCalls || !xmlCallInProgress(xmlHttp)) {
		try {
			if (!canLoadFromCache) {
				var rand = ".rand="+Math.random();
				url += (url.indexOf('?') != -1) ? ("&" + rand) : ("?" + rand);
			}
			//alert(url);
			showLoadIcon(loaderID);
			xmlHttp.open("GET", url, true);
			xmlHttp.onreadystatechange = responseHandler;
			xmlHttp.send(null);
			return true;
		} catch (e) {
		}
	}
	return false;
}
function xmlHttpPostData(xmlHttp, url, parameters, responseHandler, loaderID) {
	if (!xmlCallInProgress(xmlHttp)) {
		try {
			//var rand = ".rand="+Math.random();
			//url += (url.indexOf('?') != -1) ? ("&" + rand) : ("?" + rand);
			//alert("Posting to "+url+", params="+parameters);
			showLoadIcon(loaderID);
			xmlHttp.open("POST", url, true);
			xmlHttp.onreadystatechange = responseHandler;
			xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			xmlHttp.setRequestHeader("Content-length", parameters.length);
			xmlHttp.setRequestHeader("Connection", "close");
			xmlHttp.send(parameters);
			return true;
		} catch (e) {
		}
	}
	return false;
}
function xmlCallInProgress(xmlHttp) {
	switch (xmlHttp.readyState) {
	case 1: case 2: case 3:
		return true;
	// Case 4 and 0
	default:
		return false;
	}
}

/****************************************
 *				NAVIGATION 				*
 ****************************************/

function pageNav(pageID, showPrevious) {
	var nextTable = getObject(pageID);
	if (nextTable) {
		if (window.activePage != null) {
			window.activePage.style.zindex = 0;
			window.activePage.style.display = showPrevious ? "block" : "none";
		}
        window.activePage = nextTable;
        window.activePage.style.zindex = 1;
        window.activePage.style.display = "block";
        activatePageLink(pageID + "Link");	
	}	
}
function activatePageLink(pageLinkID) {
	var newActivePageLink = getObject(pageLinkID);
	if (newActivePageLink) {
		if (window.activePageLink) {
			window.activePageLink.className = 'navlink';
		}
	 	window.activePageLink = newActivePageLink;
	 	window.activePageLink.className = 'activenavlink';
	}
}
function isControlPage(pageText) {
	var isControl = false;
	if (pageText.indexOf("<!--TRAFFICSPACES_LOGIN-->") != -1) {
		//alert("Found Login Page");
		document.location = getBase() + "/";
		isControl = true;
	} else if (pageText.indexOf("<!--TRAFFICSPACES_REDIRECT-->") == 0) {
		//alert("Found Redirect Page");
		var redirectURL = pageText.substr(29);
		if (!isValidURL(redirectURL)) {
			redirectURL = getBase() + "/"
		} 
		document.location = redirectURL;
		isControl = true;
	} else if (pageText.indexOf("<!--TRAFFICSPACES_JAVASCRIPT-->") == 0) {
		//alert("Found Redirect Page");
		var scriptCode = pageText.substr(31);
		eval(scriptCode);
		isControl = true;
	} else if (pageText.indexOf("<!--TRAFFICSPACES_ERROR-->") != -1) {
		//alert(pageText);
	}
	return isControl;
}
/****************************************
 *				MISCELLANEOUS 			*
 ****************************************/

function getBase() {
	return window.getRoot ? window.getRoot() : "";	
}	
function getObject(id, parentElement) {
	if (id) {
		if (parentElement == document || !parentElement || parentElement == "") {
			return document.getElementById(id);
		} else {
			var childNodes = parentElement.elements;
			for (var i = 0; i < childNodes.length; i++) {
				var node = childNodes[i];
				if (node.getAttribute("id") == id || node.getAttribute("name") == id) {
					return node;
				}
			}
		}
	}
	return null;
}
function toggleObjects(showID, hideID, type, parent) {
	var objShow = getObject(showID, parent);
	var objHide = getObject(hideID, parent);
	
	var objShowPadding = objShow ? objShow.style.padding : "";
	var objShowMargin = objShow ? objShow.style.margin : "";
	var objShowHeight = objShow ? objShow.style.height : "";
	var objHidePadding = objHide ? objHide.style.padding : "";
	var objHideMargin = objHide ? objHide.style.margin : "";
	var objHideHeight = objHide ? objHide.style.height : "";
	
	if (objShow == objHide) {
		if (objHide) {
			objHide.style.display = (objHide.style.display == "none") ? ((type != null) ? type : "inline") : "none";
		}
	} else {
		if (objShow) {
			objShow.style.display = (type != null) ? type : "inline";
		}
		if (objHide) {
			objHide.style.display = "none";
		}
	}
	if (objShow) { objShow.style.padding = objShowPadding; objShow.style.margin = objShowMargin; objShow.style.margin = objHideHeight; }
	if (objHide) { objHide.style.padding = objHidePadding; objHide.style.margin = objHideMargin; objHide.style.margin = objHideHeight; }
}
function togglePageHelp(helpID, displayMode) {
	var childNodes = document.getElementsByTagName('DIV');
	for (var i = 0; i < childNodes.length; i++) {
		var node = childNodes[i];
		if (node.className == "pagehelp" || node.className == "pagehelpheader") {
			if (helpID == null || node.getAttribute("id") == helpID) {
				node.style.display = (displayMode != null) ? displayMode : ((node.style.display == "" || !node.style.display || node.style.display == "none") ? "block" : "none");
			}
		}
	}
}
function toggleClass(objectID, classA, classB, parent) {
	var object = getObject(objectID, parent);
	object.className = (object.className == classA) ? classB : classA;
}
function highlightElement(objElement, canHighlight) {
	var offset = objElement.className.indexOf("-highlight");
	if (canHighlight) {
		objElement.className = (offset != -1) ? objElement.className : objElement.className + "-highlight";
	} else {
		objElement.className = (offset != -1) ? objElement.className.substring(0, offset) : objElement.className;
	}
}
/****************************************
 *		  SELECT LIST MANAGEMENT		*
 ****************************************/

function getSelectedOption(selectList) {
    var col_Opts = selectList.options;
    var i;
    for (i = 0; i < col_Opts.length; i++) {
		var opt = col_Opts[i];
		if (opt.selected) {
		    return opt;
		}
    }
    return null;
}
function getSelectValue(selectList) {
    var col_Opts = selectList.options;
    var i;
    var value = "";
    for (i = 0; i < col_Opts.length; i++) {
		var opt = col_Opts[i];
		if (opt.selected) {
		    value += (value.length != 0) ? (","+opt.value) : opt.value;
		}
    }
    return value;
}
function replaceOption(selectList, optionValue, optionText, optionClass, index) {
    addOption(selectList, optionValue, optionText ? optionText : optionValue, optionClass, index, true, true);
}
function addOption(selectList, optionValue, optionText, optionClass, index, isSelected, canReplace) {
	if (!selectList || optionValue == null || optionText == null || (optionText = optionText.Trim()) == '') { 
		return;
	}
    if (canReplace) {
        removeOption(selectList, optionValue);
    }    
    var obj_Opt = document.createElement("OPTION");
    if (index != null && index != undefined && index >= 0 && index < selectList.options.length) {
        selectList.options.add(obj_Opt, index);
    } else {
        selectList.options.add(obj_Opt);
        //selectList.options.appendChild(obj_Opt);
    }
    obj_Opt.value 		= optionValue;
    obj_Opt.className	= optionClass;
    obj_Opt.innerHTML 	= optionText;
    obj_Opt.selected 	= isSelected == true;    
    //alert("Adding option value="+optionValue+", text="+optionText+", position="+index);
    //alert("Final selectList.innerHTML="+selectList.innerHTML);        
    return obj_Opt;
}
function findOptionIndex(selectList, optionValue) {
    var col_Opts = selectList.options;       
    for (var i = 0; i < col_Opts.length; i++) {
        var opt = col_Opts[i];        
        if (opt.value == optionValue) {
            return i;
        }        
    }
    return -1;
}
function findOption(selectList, optionValue) {
    var index = findOptionIndex(selectList, optionValue);
    if (index != -1) {
    	return selectList.options.item(index);    
    }
    return null;
}
function clearOptions(selectList) {
	selectList.innerHTML = "";
	var opts = selectList.options;
	while (opts.length > 0) {
	    if (opts.remove) {
	    	opts.remove(0);
	    } else {
	    	opts[0]=null;
	    }
	}
}
function removeSelectedOptions(selectList) {
	var opts = selectList.options;
    for (var i = 0; i < opts.length; i++) {
		var opt = opts[i];
		if (opt.selected) {
			if (opts.remove) {
			    opts.remove(i--);
			} else {
				opts[i] = null;
			}
		}
    }
}
function removeOption(selectList, optionValue) {
    var index = findOptionIndex(selectList, optionValue);
    if (index != -1) {
	    if (selectList.options.remove) {
	    	selectList.options.remove(index);
	    } else {
	    	selectList.options[index]=null;
	    }
    }    
}
function moveOption(selectList, optionValue, distance) {
    if (distance == null || distance == undefined) {
    	distance = 0;
    }
    var index = findOptionIndex(selectList, optionValue);
    if (index != -1) {
    	var optval = selectList.options.item(index).value;
    	var opttxt = selectList.options.item(index).innerHTML;
		var optcls = selectList.options.item(index).className;
		
    	selectList.options.remove(index);
    	
    	var nextpos = index + distance;
    	addOption(selectList, optval, opttxt, optcls, (nextpos >= 0) ? nextpos : 0);
    }
}
function populateSelect(selectList, optionsText) {
	//alert("populateSelect: select=" + selectList + ", opts=" + optionsText);
	clearOptions(selectList);
	var rootElement = Xparse(optionsText);
	for (var i = 0; i < rootElement.contents.length; i++) {
		var childNode = rootElement.contents[i];
		if (childNode.type == "element" && childNode.name.toLowerCase() == "option") {
			
			var optValue = childNode.attributes["value"];
			optValue = (optValue != null && optValue != undefined) ? optValue : "";
			
			var optSelected = childNode.attributes["selected"];
			//alert(optValue + "="+optSelected+"="+childNode.attributes["activevalue"]);
			var optText = null;
			for (var j = 0; j < childNode.contents.length; j++) {
				if (childNode.contents[j].type == "chardata") {
					optText = childNode.contents[j].value;
					break;
				}
			}
			var optClass = childNode.attributes["class"];
			optClass = (optClass != null && optClass != undefined) ? optClass : "";
			if (optValue != null) {
				addOption(selectList, optValue, optText, optClass, null, (optSelected == "true"));
			}
		}
	}
}
function exportSelectValues(selectList) {
	var data = "";
    var col_Opts = selectList.options;       
    for (var i = 0; i < col_Opts.length; i++) {
        var opt = col_Opts[i];        
        if (opt.selected) {
        	data += data.length != 0 ? "," : "";
        	data += opt.value;
        }        
    }
    return data;
}
function exportSelect(selectList) {
	var data = "";
    var col_Opts = selectList.options;       
    for (var i = 0; i < col_Opts.length; i++) {
        var opt = col_Opts[i];        
        if (opt.selected) {
        	var escapedOptValue = opt.value.replace(/\s+/gi,'\\ ').replace(/:/gi,'\\:');
        	data += data.length != 0 ? "\n" : "";
        	data += escapedOptValue + "\t" + opt.innerHTML;
        }        
    }
    return data;
}
function selectAll(selectList) {
	toggleSelectAll(selectList, true);
}
function deselectAll(selectList) {
	toggleSelectAll(selectList, false);
}
function toggleSelectAll(selectList, canSelect) {
    var col_Opts = selectList.options;
    var i;
    for (i = 0; i < col_Opts.length; i++) {
		col_Opts[i].selected = canSelect;
    }
}
function exportCheckboxesValues(name, parentElement, minNum, maxNum, separator) {
	return exportInputValues(name, parentElement, minNum, maxNum, "checkbox", separator);
}
function exportInputValues(name, parentElement, minNum, maxNum, inputType, separator) {
	parentElement = (parentElement) ? parentElement : document;
	separator = (separator) ? separator : ",";
	var data = "";
	var childNodes = parentElement.elements;
	var count = 0;
	for (var i = 0; i < childNodes.length; i++) {
		var node = childNodes[i];
		if (node.tagName == "INPUT" && (!inputType || node.getAttribute("type") == inputType) && 
				node.getAttribute("name") == name && (!inputType || (inputType == "checkbox" && node.checked))) {
			if (maxNum && count == maxNum) {
				highlightElement(node, true);
				return false;
			} else {
				highlightElement(node, false);
			}
			data += data.length != 0 ? separator : "";
        	data += node.value;
        	count++;
		}
	}
	if (minNum && count < minNum) {
		return false;
	}	
    return data;
}
function toggleSelectAllCheckboxes(name, parentElement, canCheck) {
	parentElement = (parentElement) ? parentElement : document;
	var data = "";
	//alert(parentElement);
	var childNodes = parentElement.elements;
	//alert(childNodes);
	//alert(childNodes.length);
	for (var i = 0; i < childNodes.length; i++) {
		var node = childNodes[i];
		//alert(node.tagName + ", " + node.getAttribute("type") + ", " + node.getAttribute("name"));
		if (!node.disabled && node.tagName == "INPUT" && node.getAttribute("type") == "checkbox" && node.getAttribute("name") == name) {
			node.checked = canCheck;
		}
	}
    return data;
}
function showHide(objectName, showClass, hideClass) {
	showClass = (showClass) ? showClass : "down_arrow_link";
	hideClass = (hideClass) ? hideClass : "arrow_link";
	if (getObject(objectName+'_link')) { toggleClass(objectName+'_link', hideClass, showClass); }
	if (getObject(objectName+'_data')) { toggleObjects(objectName+'_data', objectName+'_data', 'block'); }
}
function mouseOverLink(link) {
	if (!link) { return; }
	var defaultLinkClass = link.getAttribute("defaultclass");
	if (defaultLinkClass == "headerlink" || defaultLinkClass == "menuitem") { link.className = "active" + defaultLinkClass; }
}
function mouseOutLink(link) {
	if (!link) { return; }
	var defaultLinkClass = link.getAttribute("defaultclass");
	if (defaultLinkClass == "headerlink" || defaultLinkClass == "menuitem") { link.className = defaultLinkClass; }
}
function navBlockShowHide(objectName, additionalHeight) {
	showHide(objectName);
	var navBlockContainer = getObject('navblockcontainer');
	additionalHeight = (additionalHeight) ? additionalHeight : 200;
	additionalHeight = (getObject(objectName+'_data').style.display == 'none') ? -additionalHeight : additionalHeight;
	navBlockContainer.style.height = parseInt(navBlockContainer.style.height) + additionalHeight + "px";
}
function setStateType(stateType, stateRequired) {
	var stateINPUT = getObject('usstate');
	if (stateINPUT) {
		stateINPUT.style.display = "none";
		stateINPUT.setAttribute("validate", "");
	}
	stateINPUT = getObject('castate');
	if (stateINPUT) {
		stateINPUT.style.display = "none";
		stateINPUT.setAttribute("validate", "");
	}
	stateINPUT = getObject('otstate');
	if (stateINPUT) {
		stateINPUT.style.display = "none";
		stateINPUT.setAttribute("validate", "");
	}
	stateINPUT = getObject(stateType+'state');
	if (stateINPUT) {
		stateINPUT.style.display = "inline";
		stateINPUT.setAttribute("validate", stateRequired ? "isValid" : "");
		getObject('state').value = stateINPUT.value;
	}
	if (getObject('cc')) {	
		getObject('cc').value= (stateType != 'ot') ? stateType : "";
	}
	if (getObject('country')) {	
		getObject('country').value= (stateType != 'ot') ? stateType : "";
	}
}
// Ver .91 Feb 21 1998
//////////////////////////////////////////////////////////////
//
//	Copyright 1998 Jeremie
//	Free for public non-commercial use and modification
//	as long as this header is kept intact and unmodified.
//	Please see http://www.jeremie.com for more information
//	or email jer@jeremie.com with questions/suggestions.
//
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
////////// Simple XML Processing Library //////////////////////
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
////   Fully complies to the XML 1.0 spec 
////   as a well-formed processor, with the
////   exception of full error reporting and
////   the document type declaration(and it's
////   related features, internal entities, etc).
///////////////////////////////////////////////////////////////


/////////////////////////
//// the object constructors for the hybrid DOM

function _element()
{
	this.type = "element";
	this.name = new String();
	this.attributes = new Array();
	this.contents = new Array();
	this.uid = _Xparse_count++;
	_Xparse_index[this.uid]=this;
}

function _chardata()
{
	this.type = "chardata";
	this.value = new String();
}

function _pi()
{
	this.type = "pi";
	this.value = new String();
}

function _comment()
{
	this.type = "comment";
	this.value = new String();
}

// an internal fragment that is passed between functions
function _frag()
{
	this.str = new String();
	this.ary = new Array();
	this.end = new String();
}

/////////////////////////


// global vars to track element UID's for the index
var _Xparse_count = 0;
var _Xparse_index = new Array();


/////////////////////////
//// Main public function that is called to 
//// parse the XML string and return a root element object

function Xparse(src)
{
	var frag = new _frag();

	// remove bad \r characters and the prolog
	frag.str = _prolog(src);

	// create a root element to contain the document
	var root = new _element();
	root.name="ROOT";

	// main recursive function to process the xml
	frag = _compile(frag);

	// all done, lets return the root element + index + document
	root.contents = frag.ary;
	root.index = _Xparse_index;
	_Xparse_index = new Array();
	return root;
}

/////////////////////////


/////////////////////////
//// transforms raw text input into a multilevel array
function _compile(frag)
{
	// keep circling and eating the str
	while(1)
	{
		// when the str is empty, return the fragment
		if(frag.str.length == 0)
		{
			return frag;
		}

		var TagStart = frag.str.indexOf("<");

		if(TagStart != 0)
		{
			// theres a chunk of characters here, store it and go on
			var thisary = frag.ary.length;
			frag.ary[thisary] = new _chardata();
			if(TagStart == -1)
			{
				frag.ary[thisary].value = _entity(frag.str);
				frag.str = "";
			}
			else
			{
				frag.ary[thisary].value = _entity(frag.str.substring(0,TagStart));
				frag.str = frag.str.substring(TagStart,frag.str.length);
			}
		}
		else
		{
			// determine what the next section is, and process it
			if(frag.str.substring(1,2) == "?")
			{
				frag = _tag_pi(frag);
			}
			else
			{
				if(frag.str.substring(1,4) == "!--")
				{
					frag = _tag_comment(frag);
				}
				else
				{
					if(frag.str.substring(1,9) == "![CDATA[")
					{
						frag = _tag_cdata(frag);
					}
					else
					{
						if(frag.str.substring(1,frag.end.length + 3) == "/" + frag.end + ">" || _strip(frag.str.substring(1,frag.end.length + 3)) == "/" + frag.end)
						{
							// found the end of the current tag, end the recursive process and return
							frag.str = frag.str.substring(frag.end.length + 3,frag.str.length);
							frag.end = "";
							return frag;
						}
						else
						{
							frag = _tag_element(frag);
						}
					}
				}
			}

		}
	}
	return "";
}
///////////////////////


///////////////////////
//// functions to process different tags

function _tag_element(frag)
{
	// initialize some temporary variables for manipulating the tag
	var close = frag.str.indexOf(">");
	var empty = (frag.str.substring(close - 1,close) == "/");
	if(empty)
	{
		close -= 1;
	}

	// split up the name and attributes
	var starttag = _normalize(frag.str.substring(1,close));
	var nextspace = starttag.indexOf(" ");
	var attribs = new String();
	var name = new String();
	if(nextspace != -1)
	{
		name = starttag.substring(0,nextspace);
		attribs = starttag.substring(nextspace + 1,starttag.length);
	}
	else
	{
		name = starttag;
	}

	var thisary = frag.ary.length;
	frag.ary[thisary] = new _element();
	frag.ary[thisary].name = _strip(name);
	if(attribs.length > 0)
	{
		frag.ary[thisary].attributes = _attribution(attribs);
	}
	if(!empty)
	{
		// !!!! important, 
		// take the contents of the tag and parse them
		var contents = new _frag();
		contents.str = frag.str.substring(close + 1,frag.str.length);
		contents.end = name;
		contents = _compile(contents);
		frag.ary[thisary].contents = contents.ary;
		frag.str = contents.str;
	}
	else
	{
		frag.str = frag.str.substring(close + 2,frag.str.length);
	}
	return frag;
}

function _tag_pi(frag)
{
	var close = frag.str.indexOf("?>");
	var val = frag.str.substring(2,close);
	var thisary = frag.ary.length;
	frag.ary[thisary] = new _pi();
	frag.ary[thisary].value = val;
	frag.str = frag.str.substring(close + 2,frag.str.length);
	return frag;
}

function _tag_comment(frag)
{
	var close = frag.str.indexOf("-->");
	var val = frag.str.substring(4,close);
	var thisary = frag.ary.length;
	frag.ary[thisary] = new _comment();
	frag.ary[thisary].value = val;
	frag.str = frag.str.substring(close + 3,frag.str.length);
	return frag;
}

function _tag_cdata(frag)
{
	var close = frag.str.indexOf("]]>");
	var val = frag.str.substring(9,close);
	var thisary = frag.ary.length;
	frag.ary[thisary] = new _chardata();
	frag.ary[thisary].value = val;
	frag.str = frag.str.substring(close + 3,frag.str.length);
	return frag;
}

/////////////////////////


//////////////////
//// util for element attribute parsing
//// returns an array of all of the keys = values
function _attribution(str)
{
	var all = new Array();
	while(1)
	{
		var eq = str.indexOf("=");
		if(str.length == 0 || eq == -1)
		{
			return all;
		}

		var id1 = str.indexOf("\'");
		var id2 = str.indexOf("\"");
		var ids = new Number();
		var id = new String();
		if((id1 < id2 && id1 != -1) || id2 == -1)
		{
			ids = id1;
			id = "\'";
		}
		if((id2 < id1 || id1 == -1) && id2 != -1)
		{
			ids = id2;
			id = "\"";
		}
		var nextid = str.indexOf(id,ids + 1);
		var val = str.substring(ids + 1,nextid);

		var name = _strip(str.substring(0,eq));
		all[name] = _entity(val);
		str = str.substring(nextid + 1,str.length);
	}
	return "";
}
////////////////////


//////////////////////
//// util to remove \r characters from input string
//// and return xml string without a prolog
function _prolog(str)
{
	var A = new Array();

	A = str.split("\r\n");
	str = A.join("\n");
	A = str.split("\r");
	str = A.join("\n");

	var start = str.indexOf("<");
	var hdrPrefix  = str.substring(start,start + 3);
	var xmlPrefixA = "<" + "?" + "x";
	var xmlPrefixB = "<" + "?" + "X";
	if (hdrPrefix == xmlPrefixA || hdrPrefix == xmlPrefixB) {
		var close = str.indexOf("?>");
		str = str.substring(close + 2,str.length);
	}
	var start = str.indexOf("<!DOCTYPE");
	if(start != -1)
	{
		var close = str.indexOf(">",start) + 1;
		var dp = str.indexOf("[",start);
		if(dp < close && dp != -1)
		{
			close = str.indexOf("]>",start) + 2;
		}
		str = str.substring(close,str.length);
	}
	return str;
}
//////////////////


//////////////////////
//// util to remove white characters from input string
function _strip(str)
{
	var A = new Array();

	A = str.split("\n");
	str = A.join("");
	A = str.split(" ");
	str = A.join("");
	A = str.split("\t");
	str = A.join("");

	return str;
}
//////////////////


//////////////////////
//// util to replace white characters in input string
function _normalize(str)
{
	var A = new Array();

	A = str.split("\n");
	str = A.join(" ");
	A = str.split("\t");
	str = A.join(" ");

	return str;
}
//////////////////


//////////////////////
//// util to replace internal entities in input string
function _entity(str)
{
	var A = new Array();

	A = str.split("&lt;");
	str = A.join("<");
	A = str.split("&gt;");
	str = A.join(">");
	A = str.split("&quot;");
	str = A.join("\"");
	A = str.split("&apos;");
	str = A.join("\'");
	A = str.split("&amp;");
	str = A.join("&");

	return str;
}
//////////////////
/*
 * Copyright (C) 2004 Baron Schwartz <baron at sequent dot org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, version 2.1.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 * details.
 *
 * $Revision: 1.1 $
 */

// Shows or hides the date chooser on the page
function showChooser(obj, inputId, divId, start, end, format, isTimeChooser, isActiveDateCallback) {
    if (document.getElementById) {
        var input = document.getElementById(inputId);
        var div = document.getElementById(divId);
        if (input !== undefined && div !== undefined) {
        	format = (format) ? format : "Y-m-d";
            if (input.DateChooser === undefined) {
                input.DateChooser = new DateChooser(input, div, start, end, format, isTimeChooser, isActiveDateCallback);
            }
            input.DateChooser.setDate(Date.parseDate(input.value, format));
            if (input.DateChooser.isVisible()) {
                input.DateChooser.hide();
            }
            else {
                input.DateChooser.show();
            }
        }
    }
}
function hideChooser(inputId) {
    if (document.getElementById) {
        var input = document.getElementById(inputId);
        if (input !== undefined) {
            if (input.DateChooser != undefined && input.DateChooser.isVisible()) {
		setTimeout("document.getElementById('testdate1').DateChooser.hide()", 200);
            }
        }
    }
}

// Sets a date on the object attached to 'inputId'
function dateChooserSetDate(inputId, value) {
    var input = document.getElementById(inputId);
    if (input !== undefined && input.DateChooser !== undefined) {
        input.DateChooser.setDate(Date.parseDate(value, input.DateChooser._format));
        if (input.DateChooser.isTimeChooser()) {
            var theForm = input.form;
            var prefix = input.DateChooser._prefix;
            input.DateChooser.setTime(
                parseInt(theForm.elements[prefix + 'hour'].options[
                    theForm.elements[prefix + 'hour'].selectedIndex].value)
                    + parseInt(theForm.elements[prefix + 'ampm'].options[
                    theForm.elements[prefix + 'ampm'].selectedIndex].value),
                parseInt(theForm.elements[prefix + 'min'].options[
                    theForm.elements[prefix + 'min'].selectedIndex].value));
        }
        input.value = input.DateChooser.getValue();
        input.DateChooser.hide();
    }
}

// The callback function for when someone changes the pulldown menus on the date
// chooser
function dateChooserDateChange(theForm, prefix) {
    var input = document.getElementById(
        theForm.elements[prefix + 'inputId'].value);
    var newDate = new Date(
        theForm.elements[prefix + 'year'].options[
            theForm.elements[prefix + 'year'].selectedIndex].value,
        theForm.elements[prefix + 'month'].options[
            theForm.elements[prefix + 'month'].selectedIndex].value,
        1);
    // Try to preserve the day of month (watch out for months with 31 days)
    newDate.setDate(Math.max(1, Math.min(newDate.getDaysInMonth(),
                    input.DateChooser._date.getDate())));
    input.DateChooser.setDate(newDate);
    if (input.DateChooser.isTimeChooser()) {
        input.DateChooser.setTime(
            parseInt(theForm.elements[prefix + 'hour'].options[
                theForm.elements[prefix + 'hour'].selectedIndex].value)
                + parseInt(theForm.elements[prefix + 'ampm'].options[
                theForm.elements[prefix + 'ampm'].selectedIndex].value),
            parseInt(theForm.elements[prefix + 'min'].options[
                theForm.elements[prefix + 'min'].selectedIndex].value));
    }
    input.DateChooser.show();
}

// Gets the absolute position on the page of the element passed in
function getAbsolutePosition(obj) {
    var result = [0, 0];
    while (obj != null) {
        result[0] += obj.offsetTop;
        result[1] += obj.offsetLeft;
        obj = obj.offsetParent;
    }
    return result;
}

// DateChooser constructor
function DateChooser(input, div, start, end, format, isTimeChooser, isActiveDateCallback) {
    this._date = new Date();
    this._input = input;
    this._div = div;
    this._start = (start) ? start : "2007";
    this._end = (end) ? end : this._date.getFullYear();
    this._format = (format) ? format : "Y-m-d";    
    this._isTimeChooser = (isTimeChooser) ? true : false;
    this._isActiveDateCallback = isActiveDateCallback;
    // Choose a random prefix for all pulldown menus
    this._prefix = "";
    var letters = ["a", "b", "c", "d", "e", "f", "h", "i", "j", "k", "l",
        "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];
    for (var i = 0; i < 10; ++i) {
        this._prefix += letters[Math.floor(Math.random() * letters.length)];
    }
}

// DateChooser prototype variables
DateChooser.prototype._isVisible = false;

// Returns true if the chooser is currently visible
DateChooser.prototype.isVisible = function() {
    return this._isVisible;
}

// Returns true if the chooser is to allow choosing the time as well as the date
DateChooser.prototype.isTimeChooser = function() {
    return this._isTimeChooser;
}

// Gets the value, as a formatted string, of the date attached to the chooser
DateChooser.prototype.getValue = function() {
    return this._date.dateFormat(this._format);
}

// Hides the chooser
DateChooser.prototype.hide = function() {
    this._div.style.visibility = "hidden";
    this._div.style.display = "none";
    this._div.innerHTML = "";
    this._isVisible = false;
}

// Shows the chooser on the page
DateChooser.prototype.show = function() {
    // calculate the position before making it visible
    var inputPos = getAbsolutePosition(this._input);
    //this._div.style.top = (inputPos[0] + this._input.offsetHeight) + "px";
    //this._div.style.left = (inputPos[1] + this._input.offsetWidth) + "px";
    this._div.style.top = this._input.offsetTop + 22 + "px";
    this._div.style.left = this._input.offsetLeft + "px";
    this._div.innerHTML = this.createChooserHtml();
    this._div.style.display = "block";
    this._div.style.visibility = "visible";
    if (this._div.className.indexOf('dateChooserFixed') == -1) {
	    this._div.style.position = "absolute";
	}
    this._isVisible = true;
}

// Sets the date to what is in the input box
DateChooser.prototype.initializeDate = function() {
    if (this._input.value != null && this._input.value != "") {
        this._date = Date.parseDate(this._input.value, this._format);
    }
    else {
        this._date = new Date();
    }
}

// Sets the date attached to the chooser
DateChooser.prototype.setDate = function(date) {
    this._date = date ? date : new Date();
}

// Sets the time portion of the date attached to the chooser
DateChooser.prototype.setTime = function(hour, minute) {
    this._date.setHours(hour);
    this._date.setMinutes(minute);
}

// Creates the HTML for the whole chooser
DateChooser.prototype.createChooserHtml = function() {
    var formHtml = "<input type=\"hidden\" name=\""
        + this._prefix + "inputId\" value=\""
        + this._input.getAttribute('id') + "\">"
        + "\r\n  <select name=\"" + this._prefix 
        + "month\" onChange=\"dateChooserDateChange(this.form, '"
        + this._prefix + "');\">";
    for (var monIndex = 0; monIndex <= 11; monIndex++) {
        formHtml += "\r\n    <option value=\"" + monIndex + "\""
            + (monIndex == this._date.getMonth() ? " selected=\"1\"" : "")
            + ">" + Date.monthNames[monIndex] + "</option>";
    }
    formHtml += "\r\n  </select>\r\n  <select name=\""
        + this._prefix + "year\" onChange=\"dateChooserDateChange(this.form, '"
        + this._prefix + "');\">";
    for (var i = this._start; i <= this._end; ++i) {
        formHtml += "\r\n    <option value=\"" + i + "\""
            + (i == this._date.getFullYear() ? " selected=\"1\"" : "")
            + ">" + i + "</option>";
    }
    formHtml += "\r\n  </select>";
    formHtml += this.createCalendarHtml();
    if (this._isTimeChooser) {
        formHtml += this.createTimeChooserHtml();
    }
    return formHtml;
}

// Creates the extra HTML needed for choosing the time
DateChooser.prototype.createTimeChooserHtml = function() {
    // Add hours
    var result = "\r\n  <select name=\"" + this._prefix + "hour\">";
    for (var i = 0; i < 12; ++i) {
        result += "\r\n    <option value=\"" + i + "\""
            + (((this._date.getHours() % 12) == i) ? " selected=\"1\">" : ">")
            + i + "</option>";
    }
    // Add extra entry for 12:00
    result += "\r\n    <option value=\"0\">12</option>";
    result += "\r\n  </select>";
    // Add minutes
    result += "\r\n  <select name=\"" + this._prefix + "min\">";
    for (var i = 0; i < 60; i += 15) {
        result += "\r\n    <option value=\"" + i + "\""
            + ((this._date.getMinutes() == i) ? " selected=\"1\">" : ">")
            + String.leftPad(i, 2, '0') + "</option>";
    }
    result += "\r\n  </select>";
    // Add AM/PM
    result += "\r\n  <select name=\"" + this._prefix + "ampm\">";
    result += "\r\n    <option value=\"0\""
        + (this._date.getHours() < 12 ? " selected=\"1\">" : ">")
        + "AM</option>";
    result += "\r\n    <option value=\"12\""
        + (this._date.getHours() >= 12 ? " selected=\"1\">" : ">")
        + "PM</option>";
    result += "\r\n  </select>";
    return result;
}

// Creates the HTML for the actual calendar part of the chooser
DateChooser.prototype.createCalendarHtml = function() {
    var result = "\r\n<table cellspacing=\"0\" class=\"dateChooser\">"
        + "\r\n  <tr><th>S</th><th>M</th><th>T</th>"
        + "<th>W</th><th>T</th><th>F</th><th>S</th></tr>\r\n  <tr>";
    // Fill up the days of the week until we get to the first day of the month
    var firstDay = this._date.getFirstDayOfMonth();
    var lastDay = this._date.getLastDayOfMonth();
    if (firstDay != 0) {
        result += "<td colspan=\"" + firstDay + "\">&nbsp;</td>";
    }
    // Fill in the days of the month
    var i = 0;
    while (i < this._date.getDaysInMonth()) {
        if (((i++ + firstDay) % 7) == 0) {
            result += "</tr>\r\n  <tr>";
        }
        var thisDay = new Date(
            this._date.getFullYear(),
            this._date.getMonth(), i);
        var formattedDate = thisDay.dateFormat(this._format);
        var isDateActive = (this._isActiveDateCallback != undefined) ? this._isActiveDateCallback(formattedDate) : true;
        var dateChooserClass = "dateChooserInactive";
        var js = "";
        if (isDateActive) {
	        js = '"dateChooserSetDate(\''
    	        + this._input.getAttribute('id') + "', '"
        	    + formattedDate + '\');"'
        	dateChooserClass = "dateChooserActive";
        }            
        result += "\r\n    <td class=\"" + dateChooserClass
            // If the date is the currently chosen date, highlight it
            + (i == this._date.getDate() ? (" " + dateChooserClass + "Today") : "")
            + "\" onClick=" + js + ">" + i + "</td>";
    }
    // Fill in any days after the end of the month
    if (lastDay != 6) {
        result += "<td colspan=\"" + (6 - lastDay) + "\">&nbsp;</td>";
    }
    return result + "\r\n  </tr>\r\n</table><!--[if lte IE 6.5]><![endif]-->";
//    return result + "\r\n  </tr>\r\n</table><!--[if lte IE 6.5]><iframe></iframe><![endif]-->";
}/*
 * Copyright (C) 2004 Baron Schwartz <baron at sequent dot org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, version 2.1.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 * details.
 *
 * $Revision: 1.2 $
 */

Date.parseFunctions = {count:0};
Date.parseRegexes = [];
Date.formatFunctions = {count:0};

Date.prototype.dateFormat = function(format) {
    if (Date.formatFunctions[format] == null) {
        Date.createNewFormat(format);
    }
    var func = Date.formatFunctions[format];
    return this[func]();
}

Date.createNewFormat = function(format) {
    var funcName = "format" + Date.formatFunctions.count++;
    Date.formatFunctions[format] = funcName;
    var code = "Date.prototype." + funcName + " = function(){return ";
    var special = false;
    var ch = '';
    for (var i = 0; i < format.length; ++i) {
        ch = format.charAt(i);
        if (!special && ch == "\\") {
            special = true;
        }
        else if (special) {
            special = false;
            code += "'" + String.escape(ch) + "' + ";
        }
        else {
            code += Date.getFormatCode(ch);
        }
    }
    eval(code.substring(0, code.length - 3) + ";}");
}

Date.getFormatCode = function(character) {
    switch (character) {
    case "d":
        return "String.leftPad(this.getDate(), 2, '0') + ";
    case "D":
        return "Date.dayNames[this.getDay()].substring(0, 3) + ";
    case "j":
        return "this.getDate() + ";
    case "l":
        return "Date.dayNames[this.getDay()] + ";
    case "S":
        return "this.getSuffix() + ";
    case "w":
        return "this.getDay() + ";
    case "z":
        return "this.getDayOfYear() + ";
    case "W":
        return "this.getWeekOfYear() + ";
    case "F":
        return "Date.monthNames[this.getMonth()] + ";
    case "m":
        return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
    case "M":
        return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
    case "n":
        return "(this.getMonth() + 1) + ";
    case "t":
        return "this.getDaysInMonth() + ";
    case "L":
        return "(this.isLeapYear() ? 1 : 0) + ";
    case "Y":
        return "this.getFullYear() + ";
    case "y":
        return "('' + this.getFullYear()).substring(2, 4) + ";
    case "a":
        return "(this.getHours() < 12 ? 'am' : 'pm') + ";
    case "A":
        return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
    case "g":
        return "((this.getHours() %12) ? this.getHours() % 12 : 12) + ";
    case "G":
        return "this.getHours() + ";
    case "h":
        return "String.leftPad((this.getHours() %12) ? this.getHours() % 12 : 12, 2, '0') + ";
    case "H":
        return "String.leftPad(this.getHours(), 2, '0') + ";
    case "i":
        return "String.leftPad(this.getMinutes(), 2, '0') + ";
    case "s":
        return "String.leftPad(this.getSeconds(), 2, '0') + ";
    case "O":
        return "this.getGMTOffset() + ";
    case "T":
        return "this.getTimezone() + ";
    case "Z":
        return "(this.getTimezoneOffset() * -60) + ";
    default:
        return "'" + String.escape(character) + "' + ";
    }
}

Date.parseDate = function(input, format) {
    if (Date.parseFunctions[format] == null) {
        Date.createParser(format);
    }
    var func = Date.parseFunctions[format];
    return Date[func](input);
}

Date.createParser = function(format) {
    var funcName = "parse" + Date.parseFunctions.count++;
    var regexNum = Date.parseRegexes.length;
    var currentGroup = 1;
    Date.parseFunctions[format] = funcName;

    var code = "Date." + funcName + " = function(input){\n"
        + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1;\n"
        + "var d = new Date();\n"
        + "y = d.getFullYear();\n"
        + "m = d.getMonth();\n"
        + "d = d.getDate();\n"
        + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
        + "if (results && results.length > 0) {"
    var regex = "";

    var special = false;
    var ch = '';
    for (var i = 0; i < format.length; ++i) {
        ch = format.charAt(i);
        if (!special && ch == "\\") {
            special = true;
        }
        else if (special) {
            special = false;
            regex += String.escape(ch);
        }
        else {
            obj = Date.formatCodeToRegex(ch, currentGroup);
            currentGroup += obj.g;
            regex += obj.s;
            if (obj.g && obj.c) {
                code += obj.c;
            }
        }
    }

    code += "if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
        + "{return new Date(y, m, d, h, i, s);}\n"
        + "else if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
        + "{return new Date(y, m, d, h, i);}\n"
        + "else if (y > 0 && m >= 0 && d > 0 && h >= 0)\n"
        + "{return new Date(y, m, d, h);}\n"
        + "else if (y > 0 && m >= 0 && d > 0)\n"
        + "{return new Date(y, m, d);}\n"
        + "else if (y > 0 && m >= 0)\n"
        + "{return new Date(y, m);}\n"
        + "else if (y > 0)\n"
        + "{return new Date(y);}\n"
        + "}return null;}";

    Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
    eval(code);
}

Date.formatCodeToRegex = function(character, currentGroup) {
    switch (character) {
    case "D":
        return {g:0,
        c:null,
        s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
    case "j":
    case "d":
        return {g:1,
            c:"d = parseInt(results[" + currentGroup + "], 10);\n",
            s:"(\\d{1,2})"};
    case "l":
        return {g:0,
            c:null,
            s:"(?:" + Date.dayNames.join("|") + ")"};
    case "S":
        return {g:0,
            c:null,
            s:"(?:st|nd|rd|th)"};
    case "w":
        return {g:0,
            c:null,
            s:"\\d"};
    case "z":
        return {g:0,
            c:null,
            s:"(?:\\d{1,3})"};
    case "W":
        return {g:0,
            c:null,
            s:"(?:\\d{2})"};
    case "F":
        return {g:1,
            c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
            s:"(" + Date.monthNames.join("|") + ")"};
    case "M":
        return {g:1,
            c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
            s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
    case "n":
    case "m":
        return {g:1,
            c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
            s:"(\\d{1,2})"};
    case "t":
        return {g:0,
            c:null,
            s:"\\d{1,2}"};
    case "L":
        return {g:0,
            c:null,
            s:"(?:1|0)"};
    case "Y":
        return {g:1,
            c:"y = parseInt(results[" + currentGroup + "], 10);\n",
            s:"(\\d{4})"};
    case "y":
        return {g:1,
            c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
                + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
            s:"(\\d{1,2})"};
    case "a":
        return {g:1,
            c:"if (results[" + currentGroup + "] == 'am') {\n"
                + "if (h == 12) { h = 0; }\n"
                + "} else { if (h < 12) { h += 12; }}",
            s:"(am|pm)"};
    case "A":
        return {g:1,
            c:"if (results[" + currentGroup + "] == 'AM') {\n"
                + "if (h == 12) { h = 0; }\n"
                + "} else { if (h < 12) { h += 12; }}",
            s:"(AM|PM)"};
    case "g":
    case "G":
    case "h":
    case "H":
        return {g:1,
            c:"h = parseInt(results[" + currentGroup + "], 10);\n",
            s:"(\\d{1,2})"};
    case "i":
        return {g:1,
            c:"i = parseInt(results[" + currentGroup + "], 10);\n",
            s:"(\\d{2})"};
    case "s":
        return {g:1,
            c:"s = parseInt(results[" + currentGroup + "], 10);\n",
            s:"(\\d{2})"};
    case "O":
        return {g:0,
            c:null,
            s:"[+-]\\d{4}"};
    case "T":
        return {g:0,
            c:null,
            s:"[A-Z]{3}"};
    case "Z":
        return {g:0,
            c:null,
            s:"[+-]\\d{1,5}"};
    default:
        return {g:0,
            c:null,
            s:String.escape(character)};
    }
}

Date.prototype.getTimezone = function() {
    return this.toString().replace(
        /^.*? ([A-Z]{3}) [0-9]{4}.*$/, "$1").replace(
        /^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/, "$1$2$3");
}

Date.prototype.getGMTOffset = function() {
    return (this.getTimezoneOffset() > 0 ? "-" : "+")
        + String.leftPad(Math.floor(this.getTimezoneOffset() / 60), 2, "0")
        + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
}

Date.prototype.getDayOfYear = function() {
    var num = 0;
    Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
    for (var i = 0; i < this.getMonth(); ++i) {
        num += Date.daysInMonth[i];
    }
    return num + this.getDate() - 1;
}

Date.prototype.getWeekOfYear = function() {
    // Skip to Thursday of this week
    var now = this.getDayOfYear() + (4 - this.getDay());
    // Find the first Thursday of the year
    var jan1 = new Date(this.getFullYear(), 0, 1);
    var then = (7 - jan1.getDay() + 4);
    document.write(then);
    return String.leftPad(((now - then) / 7) + 1, 2, "0");
}

Date.prototype.isLeapYear = function() {
    var year = this.getFullYear();
    return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
}

Date.prototype.getFirstDayOfMonth = function() {
    var day = (this.getDay() - (this.getDate() - 1)) % 7;
    return (day < 0) ? (day + 7) : day;
}

Date.prototype.getLastDayOfMonth = function() {
    var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
    return (day < 0) ? (day + 7) : day;
}

Date.prototype.getDaysInMonth = function() {
    Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
    return Date.daysInMonth[this.getMonth()];
}

Date.prototype.getSuffix = function() {
    switch (this.getDate()) {
        case 1:
        case 21:
        case 31:
            return "st";
        case 2:
        case 22:
            return "nd";
        case 3:
        case 23:
            return "rd";
        default:
            return "th";
    }
}

String.escape = function(string) {
    return string.replace(/('|\\)/g, "\\$1");
}

String.leftPad = function (val, size, ch) {
    var result = new String(val);
    if (ch == null) {
        ch = " ";
    }
    while (result.length < size) {
        result = ch + result;
    }
    return result;
}

Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
Date.monthNames =
   ["January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December"];
Date.dayNames =
   ["Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday"];
Date.y2kYear = 50;
Date.monthNumbers = {
    Jan:0,
    Feb:1,
    Mar:2,
    Apr:3,
    May:4,
    Jun:5,
    Jul:6,
    Aug:7,
    Sep:8,
    Oct:9,
    Nov:10,
    Dec:11};
Date.patterns = {
    ISO8601LongPattern:"Y-m-d H:i:s",
    ISO8601ShortPattern:"Y-m-d",
    ShortDatePattern: "n/j/Y",
    LongDatePattern: "l, F d, Y",
    FullDateTimePattern: "l, F d, Y g:i:s A",
    MonthDayPattern: "F d",
    ShortTimePattern: "g:i A",
    LongTimePattern: "g:i:s A",
    SortableDateTimePattern: "Y-m-d\\TH:i:s",
    UniversalSortableDateTimePattern: "Y-m-d H:i:sO",
    YearMonthPattern: "F, Y"};
