/* FILE: templates/ja_sargas/scripts/ja.script.js*/
var currentFontSize = 4;

function revertStyles(fontsize){
    currentFontSize = fontsize;
    changeFontSize(0);
}

function changeFontSize(sizeDifference){
    //get css font size
    var rule = getRuleByName("body.fs" + (currentFontSize + sizeDifference));
    if (rule){
        document.body.style.fontSize = rule.style.fontSize;
        currentFontSize = currentFontSize + sizeDifference;
        createCookie("FontSize", currentFontSize, 365);
    }
    return;

};

function getRuleByName(ruleName){
    for (i=0; i<document.styleSheets.length; i++){
        var style = document.styleSheets[i];
        var rules = style.cssRules?style.cssRules:style.rules;
        if (rules){
            for (j = 0; j<rules.length; j++){
                if (rules[j].selectorText.trim().toUpperCase() == ruleName.trim().toUpperCase()){
                    return rules[j];
                }
            }
        }
    }
    return null;
}

function setActiveStyleSheet(title) {

    createCookie("ColorCSS", title, 365);
    window.location.reload();
    return;
    /*
    var i, a, main, arr;
    arr = document.getElementsByTagName("link");
    for(i=0; (a = arr[i]); i++) {
    var ltitle = a.getAttribute("title");
    if(a.getAttribute("rel").indexOf("style") != -1 && ltitle) {
    a.disabled = true;
    if(ltitle == title) a.disabled = false;
    }
    }
    createCookie("ColorCSS", title, 365);
    */
}

function createCookie(name,value,days) {
    if (days) {
        var date = new Date();
        date.setTime(date.getTime()+(days*24*60*60*1000));
        var expires = "; expires="+date.toGMTString();
    }
    else expires = "";
    document.cookie = name+"="+value+expires+"; path=/";
}

function setScreenType(screentype){
    /*
    bclass = document.body.className.trim();
    if (bclass.indexOf(' ') > 0){
    bclass = bclass.replace(/^\w+/,screentype);
    }else{
    bclass = screentype + ' ' + bclass;
    }

    document.body.className = bclass;
    */
    createCookie("ScreenType", screentype, 365);
    window.location.reload();
    return;
}

String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ""); };

function changeToolHilite(oldtool, newtool) {
    if (oldtool != newtool) {
        if (oldtool) {
            oldtool.src = oldtool.src.replace(/-hilite/,'');
        }
        newtool.src = newtool.src.replace(/.gif$/,'-hilite.gif');
    }
}

//addEvent - attach a function to an event
function addEvent(obj, evType, fn){
    if (obj.addEventListener){
        obj.addEventListener(evType, fn, false);
        return true;
    } else if (obj.attachEvent){
        var r = obj.attachEvent("on"+evType, fn);
        return r;
    } else {
        return false;
    }
}

/*
Global "swap" holder
Use value, null, if no layer initially visible
*/
var currDivId = "show_the_hotel";

function togLayer(id)
{
    if(currDivId) setDisplay(currDivId, "none");
  	if(id)setDisplay(id, "block");
    currDivId = id;
}

function setDisplay(id,value)
{
    var elm = document.getElementById(id);
    elm.style.display = value;
}

function MM_jumpMenu(targ,selObj,restore){ //v3.0
    eval(targ+".location='"+selObj.options[selObj.selectedIndex].value+"'");
    if (restore) selObj.selectedIndex=0;
}

/*
Global "swap" holder
Use value, null, if no layer initially visible
*/
var currDivIdSpecOff = "eastern_cape";

function togLayerSpecOff(id)
{
    if(currDivIdSpecOff) setDisplay(currDivIdSpecOff, "none");
    if(id)setDisplay(id, "block");
    currDivIdSpecOff = id;
}

function setDisplay(id,value)
{
    var elm = document.getElementById(id);
    if(elm) elm.style.display = value;
}


// var iStartTime = new Date().valueOf();
function popup(sURL) {
    var iWidth = 640;
    var iHeight = 480;
    window.open(sURL, 'protea_popup', "left=50px, top=50px, width=" + iWidth + "px,height=" + iHeight + "px, resizable=1, status=0, address=0, scrollbars=1");
}
/* FILE: templates/ja_sargas/scripts/opacity.js*/
// Browser Detect Lite  v2.1
// http://www.dithered.com/javascript/browser_detect/index.html
// modified by Chris Nott (chris@NOSPAMdithered.com - remove NOSPAM)
//
// modified by Michael Lovitt to include OmniWeb and Dreamcast

function BrowserDetectLite() {
	var ua = navigator.userAgent.toLowerCase(); 
	this.ua = ua;

	// browser name
	this.isGecko     = (ua.indexOf('gecko') != -1);
	this.isMozilla   = (this.isGecko && ua.indexOf("gecko/") + 14 == ua.length);
	this.isNS        = ( (this.isGecko) ? (ua.indexOf('netscape') != -1) : ( (ua.indexOf('mozilla') != -1) && (ua.indexOf('spoofer') == -1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1) && (ua.indexOf('hotjava') == -1) ) );
	this.isIE        = ( (ua.indexOf("msie") != -1) && (ua.indexOf("opera") == -1) && (ua.indexOf("webtv") == -1) ); 
	this.isOpera     = (ua.indexOf("opera") != -1); 
	this.isKonqueror = (ua.indexOf("konqueror") != -1); 
	this.isIcab      = (ua.indexOf("icab") != -1); 
	this.isAol       = (ua.indexOf("aol") != -1); 
	this.isWebtv     = (ua.indexOf("webtv") != -1); 
	this.isOmniweb   = (ua.indexOf("omniweb") != -1);
	this.isDreamcast   = (ua.indexOf("dreamcast") != -1);
	
	// spoofing and compatible browsers
	this.isIECompatible = ( (ua.indexOf("msie") != -1) && !this.isIE);
	this.isNSCompatible = ( (ua.indexOf("mozilla") != -1) && !this.isNS && !this.isMozilla);
	
	// browser version
	this.versionMinor = parseFloat(navigator.appVersion); 
	
	// correct version number for NS6+ 
	if (this.isNS && this.isGecko) {
		this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('/') + 1 ) );
	}
	
	// correct version number for IE4+ 
	else if (this.isIE && this.versionMinor >= 4) {
		this.versionMinor = parseFloat( ua.substring( ua.indexOf('msie ') + 5 ) );
	}
	
	// correct version number for Opera 
	else if (this.isOpera) {
		if (ua.indexOf('opera/') != -1) {
			this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera/') + 6 ) );
		}
		else {
			this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera ') + 6 ) );
		}
	}
	
	// correct version number for Konqueror
	else if (this.isKonqueror) {
		this.versionMinor = parseFloat( ua.substring( ua.indexOf('konqueror/') + 10 ) );
	}
	
	// correct version number for iCab 
	else if (this.isIcab) {
		if (ua.indexOf('icab/') != -1) {
			this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab/') + 6 ) );
		}
		else {
			this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab ') + 6 ) );
		}
	}
	
	// correct version number for WebTV
	else if (this.isWebtv) {
		this.versionMinor = parseFloat( ua.substring( ua.indexOf('webtv/') + 6 ) );
	}
	
	this.versionMajor = parseInt(this.versionMinor); 
	this.geckoVersion = ( (this.isGecko) ? ua.substring( (ua.lastIndexOf('gecko/') + 6), (ua.lastIndexOf('gecko/') + 14) ) : -1 );
	
	// platform
	this.isWin   = (ua.indexOf('win') != -1);
	this.isWin32 = (this.isWin && ( ua.indexOf('95') != -1 || ua.indexOf('98') != -1 || ua.indexOf('nt') != -1 || ua.indexOf('win32') != -1 || ua.indexOf('32bit') != -1) );
	this.isMac   = (ua.indexOf('mac') != -1);
	this.isUnix  = (ua.indexOf('unix') != -1 || ua.indexOf('linux') != -1 || ua.indexOf('sunos') != -1 || ua.indexOf('bsd') != -1 || ua.indexOf('x11') != -1)
	
	// specific browser shortcuts
	this.isNS4x = (this.isNS && this.versionMajor == 4);
	this.isNS40x = (this.isNS4x && this.versionMinor < 4.5);
	this.isNS47x = (this.isNS4x && this.versionMinor >= 4.7);
	this.isNS4up = (this.isNS && this.versionMinor >= 4);
	this.isNS6x = (this.isNS && this.versionMajor == 6);
	this.isNS6up = (this.isNS && this.versionMajor >= 6);
	
	this.isIE4x = (this.isIE && this.versionMajor == 4);
	this.isIE4up = (this.isIE && this.versionMajor >= 4);
	this.isIE5x = (this.isIE && this.versionMajor == 5);
	this.isIE55 = (this.isIE && this.versionMinor == 5.5);
	this.isIE5up = (this.isIE && this.versionMajor >= 5);
	this.isIE6x = (this.isIE && this.versionMajor == 6);
	this.isIE6up = (this.isIE && this.versionMajor >= 6);
	
	this.isIE4xMac = (this.isIE4x && this.isMac);
}
var browser = new BrowserDetectLite();

// if IE5.5+ on Win32, then display PNGs with AlphaImageLoader
if ((browser.isIE55 || browser.isIE6up) && browser.isWin32) {
	var pngAlpha = true;
// else, if the browser can display PNGs normally, then do that
} else if ((browser.isGecko) ||
(browser.isIE5up && browser.isMac) ||
(browser.isOpera && browser.isWin && browser.versionMajor >= 6) ||
(browser.isOpera && browser.isUnix && browser.versionMajor >= 6) ||
(browser.isOpera && browser.isMac && browser.versionMajor >= 5) ||
(browser.isOmniweb && browser.versionMinor >= 3.1) ||
(browser.isIcab && browser.versionMinor >= 1.9) ||
(browser.isWebtv) ||
(browser.isDreamcast)) {
	var pngNormal = true;
}

//---------------------------------------------------------------
// Opacity Displayer, Version 1.0
// Copyright Michael Lovitt, 6/2002.
// Distribute freely, but please leave this notice intact.
//---------------------------------------------------------------

//---------------------------------------------------------------
// OPACITY OBJECT
//
// Instantiates the object, defines the properties and methods.
function OpacityObject(divId, strPath) {
	this.id = divId;
	this.path = strPath;
	if (ns){
		if (browserVersion>=5) {
			this.layerObject = document.getElementById(divId).style;
		} else { 
			this.layerObject = eval("document."+divId);
		}
	} else {
		this.layerObject = document.getElementById(divId).style;
	}
	this.setBackground = od_object_setBackground;
}
// Uses AlphaImageLoader filter, or the css background property,
// as appropriate, to apply a PNG or GIF as the background of the layerObject.
// La til background-repeat
function od_object_setBackground() {	
	if (pngAlpha) {
		this.layerObject.zoom = "1";
		this.layerObject.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled = true, src='"+this.path+".png', sizingMethod='scale')";
		//this.layerObject.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=70)";
	} else if (pngNormal) {
		this.layerObject.backgroundImage = 'url('+this.path+'.png)';
		this.layerObject.backgroundRepeat = 'repeat';
	} else {
		this.layerObject.backgroundImage = 'url('+this.path+'.gif)';
		this.layerObject.backgroundRepeat = 'repeat';
	}
}
//---------------------------------------------------------------

//---------------------------------------------------------------
// OPACITY DISPLAY FUNCTION
// Outputs the image as a div with the AlphaImageLoader, or with
// a standard image tag.
function od_displayImage(strId, strPath, intWidth, intHeight, strClass, strAlt) {	
	if (pngAlpha) {
		document.write('<div style="height:'+intHeight+'px;width:'+intWidth+'px;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\''+strPath+'.png\', sizingMethod=\'scale\')" id="'+strId+'" class="'+strClass+'"></div>');
	} else if (pngNormal) {
		document.write('<img src="'+strPath+'.png" width="'+intWidth+'" height="'+intHeight+'" name="'+strId+'" border="0" class="'+strClass+'" alt="'+strAlt+'" />');
	} else {
		document.write('<img src="'+strPath+'.gif" width="'+intWidth+'" height="'+intHeight+'" name="'+strId+'" border="0" class="'+strClass+'" alt="'+strAlt+'" />');
	}
}
//---------------------------------------------------------------

//---------------------------------------------------------------
// global variables

// if IE5.5+ on win32, then display PNGs with AlphaImageLoader
if ((browser.isIE55 || browser.isIE6up) && browser.isWin32) {
	var pngAlpha = true;
	var strExt = ".png";
// else, if the browser can display PNGs normally, then do that. that list includes:
	//     -Gecko Engine: Netscape 6 or Mozilla, Mac or PC
	//     -IE5+ Mac (OpacityObject applies the background image at 100% opacity)
	//     -Opera 6+ PC
	//     -Opera 5+ Mac (Doesn't support dynamically-set background images)
	//     -Opera 6+ Linux 
	//     -Omniweb 3.1+ 
	//     -Icab 1.9+ 
	//     -WebTV 
	//     -Sega Dreamcast
} else if ((browser.isGecko) || (browser.isIE5up && browser.isMac) || (browser.isOpera && browser.isWin && browser.versionMajor >= 6) || (browser.isOpera && browser.isUnix && browser.versionMajor >= 6) || (browser.isOpera && browser.isMac && browser.versionMajor >= 5) || (browser.isOmniweb && browser.versionMinor >= 3.1) || (browser.isIcab && browser.versionMinor >= 1.9) || (browser.isWebtv) || (browser.isDreamcast)) {
	var pngNormal = true;
	var strExt = ".png";
	// otherwise, we use plain old GIFs
} else {
	var strExt = ".gif";
}

var ns = (document.all)?false:true;
var browserVersion = parseFloat(navigator.appVersion );
//---------------------------------------------------------------
/* FILE: modules/mod_scripts/javascript-general.js*/
function XmlHttp(func) {
	var xmlhttp = null;
	if (window.XMLHttpRequest) {
		xmlhttp = new XMLHttpRequest();
		if ( typeof xmlhttp.overrideMimeType != 'undefined') {
			xmlhttp.overrideMimeType('text/plain');
		}
	} else if (window.ActiveXObject) {
		xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
	} else {
		alert('Your browser has no JSON support. Please upgrade your browser.');

		return false;
	}

	xmlhttp.onreadystatechange = function() {

		if(xmlhttp.readyState == 4) {
			var response = null;
			if(xmlhttp.status == 200) {
				response = xmlhttp.responseText;
			}
			var object = null;
//document.write(response);
			if(response != null && response != '') {
				try {
					object = eval('(' + response + ')');
				} catch(ex) {
					// object remains null.
				}
			}

			func(object);
		}
	}

	return xmlhttp;
}

function sendRequest(url, func, append) {
	var client = new XmlHttp(func);
	
	var urls = url.split("?");
	client.open('POST', urls[0] + "?" + append, true);
	client.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	
	client.send(urls[1]);
}

function confirmSend(json){
	if (json == null){
		return false;
	}
	else{
		return true;
	}
}

function activateButtons(){
	var elems = document.getElementsByName('disabledGroup[]');
	for(var i = 0; i < elems.length; i++) {
		elems[i].disabled = false;
	}	
}


function getElement(id) {
	return document.getElementById(id);
}

function showProgressBar(feature){
	var booking_engine = getElement('bookingEngine');
	var regionElem = getElement('selectRegions');
	var progressDivElem = getElement('progressDiv');

	var progressBarHTML;

	//regionElem.style.visibility='hidden';
	if(feature == "search"){
		var hide1 = getElement('hotel-searchBox');
		var hide2 = getElement('hotel-searchImage');
		var hide3 = getElement('hotel-introText');
		var hide4 = getElement('ja-rightcol');
		var hide_specials = getElement('div_special_description');
		var hide_contentwrap = getElement('ja-contentwrap');
		
		if(hide_contentwrap){
			hide_contentwrap.style.display = "none";
		}
			
		if(hide_specials){
			hide_specials.style.display = "none";
		}
		
		booking_engine.style.display = "none";
		if(!hide1){
			hide1 = getElement('ja-footerwrap')
			hide1.style.display = "none";
			
			hide2 = getElement('ja-content');
			hide2.style.display = "none";
			
			hide3 = getElement('ja-botnavwrap');
			hide3.style.display = "none";
		}
		else{
			
			getElement('ja-botslwrap').style.display="none";
			getElement('ja-botnavwrap').style.display="none";
			getElement('threeBrand').style.display="none";
			hide1.style.display = "none";
			hide2.style.display = "none";
			hide3.style.display = "none";
			hide4.style.display = "none";
		}

	}
	else{
		hide1 = getElement('ja-footerwrap')
		hide1.style.display = "none";
		
		hide2 = getElement('ja-content');
		hide2.style.display = "none";
			
		hide3 = getElement('ja-botnavwrap');
		hide3.style.display = "none";
		if(hide1){
			var hide1 = getElement('ja-contentwrap');
			hide1.style.display = "none";
		}
		var hide2 = getElement('ja-leftcol');
		hide2.style.display = "none";
	}
	progressDivElem.style.display = "block";
}

function show_hide_credit_card(){
	var creditCardTableElem = getElement('credit_card_table');
	var voucherElem = getElement('voucher_table');

	
	if(creditCardTableElem.style.display != "none"){
		creditCardTableElem.style.display = "none";
		voucherElem.style.display = "block";
	}else{
		creditCardTableElem.style.display = "block";
		voucherElem.style.display = "none";
	}
	
}

/* FILE: modules/mod_scripts/javascript-general.js*/
function XmlHttp(func) {
	var xmlhttp = null;
	if (window.XMLHttpRequest) {
		xmlhttp = new XMLHttpRequest();
		if ( typeof xmlhttp.overrideMimeType != 'undefined') {
			xmlhttp.overrideMimeType('text/plain');
		}
	} else if (window.ActiveXObject) {
		xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
	} else {
		alert('Your browser has no JSON support. Please upgrade your browser.');

		return false;
	}

	xmlhttp.onreadystatechange = function() {

		if(xmlhttp.readyState == 4) {
			var response = null;
			if(xmlhttp.status == 200) {
				response = xmlhttp.responseText;
			}
			var object = null;
//document.write(response);
			if(response != null && response != '') {
				try {
					object = eval('(' + response + ')');
				} catch(ex) {
					// object remains null.
				}
			}

			func(object);
		}
	}

	return xmlhttp;
}

function sendRequest(url, func, append) {
	var client = new XmlHttp(func);
	
	var urls = url.split("?");
	client.open('POST', urls[0] + "?" + append, true);
	client.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	
	client.send(urls[1]);
}

function confirmSend(json){
	if (json == null){
		return false;
	}
	else{
		return true;
	}
}

function activateButtons(){
	var elems = document.getElementsByName('disabledGroup[]');
	for(var i = 0; i < elems.length; i++) {
		elems[i].disabled = false;
	}	
}


function getElement(id) {
	return document.getElementById(id);
}

function showProgressBar(feature){
	var booking_engine = getElement('bookingEngine');
	var regionElem = getElement('selectRegions');
	var progressDivElem = getElement('progressDiv');

	var progressBarHTML;

	//regionElem.style.visibility='hidden';
	if(feature == "search"){
		var hide1 = getElement('hotel-searchBox');
		var hide2 = getElement('hotel-searchImage');
		var hide3 = getElement('hotel-introText');
		var hide4 = getElement('ja-rightcol');
		var hide_specials = getElement('div_special_description');
		var hide_contentwrap = getElement('ja-contentwrap');
		
		if(hide_contentwrap){
			hide_contentwrap.style.display = "none";
		}
			
		if(hide_specials){
			hide_specials.style.display = "none";
		}
		
		booking_engine.style.display = "none";
		if(!hide1){
			hide1 = getElement('ja-footerwrap')
			hide1.style.display = "none";
			
			hide2 = getElement('ja-content');
			hide2.style.display = "none";
			
			hide3 = getElement('ja-botnavwrap');
			hide3.style.display = "none";
		}
		else{
			
			getElement('ja-botslwrap').style.display="none";
			getElement('ja-botnavwrap').style.display="none";
			getElement('threeBrand').style.display="none";
			hide1.style.display = "none";
			hide2.style.display = "none";
			hide3.style.display = "none";
			hide4.style.display = "none";
		}

	}
	else{
		hide1 = getElement('ja-footerwrap')
		hide1.style.display = "none";
		
		hide2 = getElement('ja-content');
		hide2.style.display = "none";
			
		hide3 = getElement('ja-botnavwrap');
		hide3.style.display = "none";
		if(hide1){
			var hide1 = getElement('ja-contentwrap');
			hide1.style.display = "none";
		}
		var hide2 = getElement('ja-leftcol');
		hide2.style.display = "none";
	}
	progressDivElem.style.display = "block";
}

function show_hide_credit_card(){
	var creditCardTableElem = getElement('credit_card_table');
	var voucherElem = getElement('voucher_table');

	
	if(creditCardTableElem.style.display != "none"){
		creditCardTableElem.style.display = "none";
		voucherElem.style.display = "block";
	}else{
		creditCardTableElem.style.display = "block";
		voucherElem.style.display = "none";
	}
	
}

/* FILE: modules/mod_scripts/javascript-json.js*/


var default_name = "Select >>";
var default_name_country = "Select Country";
var default_name_region = "Select Region";
var default_name_city = "Select Town";
var default_name_hotel = "Select Hotel";

var default_value = "";

var msg = "";

var load_type = "";

var countryElem;
var regionElem;
var cityElem;
var hotelElem;

var selectedCountryId;
var selectedRegionId;
var selectedCityId;
var selectedHotelId;

var j_countries;
var j_country;
var curr_country;

var j_regions;
var j_region;
var curr_region;

var j_cities;
var j_city;
var curr_city;

var j_hotels;
var j_hotel;

//testing
var j_test_country = 0;
var j_test_region = 0;
var j_test_city = 0;
var j_test_hotel = 0;

function reset_booking_form(){
	var elem = getElement('selectCountries');
	elem.selectedIndex = 0;
	var elem = getElement('selectRegions');
	elem.selectedIndex = 0;
	var elem = getElement('selectCities');
	elem.selectedIndex = 0;
	var elem = getElement('selectHotels');
	elem.selectedIndex = 0;
	var elem = getElement('checkin_date');
	elem.value = "Check In";
	var elem = getElement('checkout_date');
	elem.value = "Check Out";
	var elem = getElement('nightsNumber');
	elem.value = "Number of nights";
	
	
}

function do_area(section){

	j_test_country = 0;
	j_test_region = 0;
	j_test_city = 0;
	j_test_hotel = 0;

	load_type = section;
	countryElem = getElement('selectCountries');
	regionElem = getElement('selectRegions');
	cityElem = getElement('selectCities');
	hotelElem = getElement('selectHotels');

	selectedCountryId = getValue(countryElem);
	selectedRegionId = getValue(regionElem);
	selectedCityId = getValue(cityElem);
	selectedHotelId = getValue(hotelElem);

	if(!isSet(selectedCountryId)){selectedCountryId = null;}
	if(!isSet(selectedRegionId)){selectedRegionId = null;}
	if(!isSet(selectedCityId)){selectedCityId = null;}
	if(!isSet(selectedHotelId)){selectedHotelId = null;}

	j_countries = json_areas;

	switch (load_type){
		case "country":

		selectedRegionId = "";
		selectedCityId = "";
		selectedHotelId = "";

		countryElem.options.length = 0;
		regionElem.options.length = 0;
		cityElem.options.length = 0;
		hotelElem.options.length = 0;

		curr_country = null;
		curr_region = null;
		curr_city = null;

		do_countries(j_countries);

		//if the regions are empty then do not display
		if(regionElem.options.length == 1){
			regionElem.style.visibility = "hidden";
			//if the region is hidden then set it to only contain the default name and value
			selectedRegionId = "";
			regionElem.options.length = 0;
			regionElem.options.add(new Option(default_name_region,default_value));
		}else{
			regionElem.style.visibility = "visible";
		}

		break;

		case "region":
		selectedCityId = "";
		selectedHotelId = "";

		regionElem.options.length = 0;
		cityElem.options.length = 0;
		hotelElem.options.length = 0;

		curr_region = null;
		curr_city = null;

		//if the country is not selected then set the regions to do for all countries
		if(isSet(curr_country)){
			j_regions = curr_country.regions;
		}else{
			j_countries = json_areas;
			for (var h = 0; h < j_countries.length; h++){
				j_country = j_countries[h];
				j_regions = j_country.regions;
				do_regions(j_regions);

			}
		}

		do_regions(j_regions);

		break;

		case "city":
		selectedHotelId = "";

		cityElem.options.length = 0;
		hotelElem.options.length = 0;

		curr_city = null;

		//if no region is selected
		if(!isSet(curr_region)){
			//if no region and country is selected
			if(!isSet(curr_country)){
				for(var g = 0; g < j_countries.length;g++){
					j_country = j_countries[g];
					for(var h = 0; h < j_country.regions.length;h++){
						j_region = j_country.regions[h];
						j_cities = j_region.cities;
						do_cities(j_cities);
					}
				}
			}else{
				//if country is selected but no region selected
				for(var g = 0; g < curr_country.regions.length;g++){
					j_region = curr_country.regions[g];
					j_cities = j_region.cities;
					do_cities(j_cities);
				}

			}
		}
		//if a region is selected
		else{
			//if a no country is selected but region is selected
			if(!isSet(curr_country)){
				//if no region selected and no country selected
				j_cities = curr_region.cities;
				do_cities(j_cities);
			}else{
				//if a region and country is selected
				j_cities = curr_region.cities;
				do_cities(j_cities);
			}

		}

		break;

		case "hotel":
		break;


	}
	sortList(countryElem,selectedCountryId,default_name_country);
	sortList(regionElem,selectedRegionId,default_name_region);
	sortList(cityElem,selectedCityId,default_name_city);
	sortList(hotelElem,selectedHotelId,default_name_hotel);


	//alert("country looped:"+j_test_country+"\nregion looped:"+j_test_region+"\ncity looped:"+j_test_city+"\nhotel looped:"+j_test_hotel+"\nselected items:\ncountry:"+selectedCountryId+"\nregion:"+selectedRegionId+"\ncity:"+selectedCityId+"\nhotel:"+selectedHotelId+"\ncurrent variables:\ncurr_country:"+curr_country+"\ncurr_region:"+curr_region+"\ncurr_city:"+curr_city);

}

function do_countries(j_countries){
	//loop through all the countries
	for(var a = 0; a < j_countries.length; a++){
		j_test_country++;
		j_country = j_countries[a];

		//if the looped country is the selected one
		if(j_country.id == selectedCountryId){
			curr_country = j_country;
			//set selected dropdown item
			add_country(j_country,true);
			//if country has been selected only do the regions for this country
			do_regions(j_country.regions);
		}else{
			//add country to the list
			add_country(j_country);

			if(selectedCountryId == null){
				//if no country is selected do the regions for all countries
				do_regions(j_country.regions);
			}
		}
	}
}

function do_regions(j_regions){
	for(var b = 0; b < j_regions.length; b++){
		j_test_region++;
		j_region = j_regions[b];
		//if the looped region is the selected one
		if(j_region.id == selectedRegionId){
			curr_region = j_region;
			//set selected dropdown item
			add_region(j_region,true);
			//if region has been selected only do the cities for this region
			do_cities(j_region.cities);
		}else{
			//add region to the list
			add_region(j_region);

			if(!isSet(selectedRegionId)){
				//if no region is selected do the cities for all regions
				do_cities(j_region.cities);
			}
		}
	}
}

function do_cities(j_cities){
	for(var c = 0; c < j_cities.length; c++){
		j_test_city++;
		j_city = j_cities[c];

		//if the looped city is the selected one
		if(j_city.id == selectedCityId){
			curr_city = j_city;
			//set selected dropdown item
			add_city(j_city,true);
			//if city has been selected only do the hotels for this city
			do_hotels(j_city.hotels);
		}else{
			//add city to the list
			add_city(j_city);

			if(!isSet(selectedCityId)){
				//if no city is selected do the hotels for all cities
				do_hotels(j_city.hotels);
			}
		}
	}
}

function do_hotels(j_hotels){
	for(var d = 0; d < j_hotels.length; d++){
		j_test_hotel++;
		j_hotel = j_hotels[d];
		add_hotel(j_hotel);
	}
}


function add_country(j_country,selected){
	if(countryElem.options.length == 0){
		countryElem.options.add(new Option(default_name_country,default_value));
	}
	countryElem.options.add(new Option(j_country.name,j_country.id));
	if(selected){
		countryElem.selectedIndex = countryElem.options.length-1;
	}
}

function add_region(j_region,selected){
	if(regionElem.options.length == 0){
		regionElem.options.add(new Option(default_name_region,default_value));
	}

	if(j_region.name != null){
		regionElem.options.add(new Option(j_region.name,j_region.id));
		if(selected){
			regionElem.selectedIndex = regionElem.options.length-1;
		}
	}
}

function add_city(j_city,selected){
	if(cityElem.options.length == 0){
		cityElem.options.add(new Option(default_name_city,default_value));
	}

	cityElem.options.add(new Option(j_city.name,j_city.id));
	if(selected){
		cityElem.selectedIndex = cityElem.options.length-1;
	}
}

function add_hotel(j_hotel){
	if(hotelElem.options.length == 0){
		hotelElem.options.add(new Option(default_name_hotel,default_value));
	}

	hotelElem.options.add(new Option(j_hotel.name,j_hotel.code))
}


function getValue(elem){
	return elem.options[elem.selectedIndex].value;
}


function isSet(val){
	if(val == null || val == "" || val == " "){
		return false;
	}
	return true;
}

function sortHotelNames(hotel_rows){
	var ph_hotel_rows = new Array();
	var other_hotel_rows = new Array();
	var ph_count = 0;
	var other_count = 0;
	for(var i = 0; i < hotel_rows.length; i++){

		//if(strpos($hotel_row->name,"Protea Hotel") === 0){
		if(hotel_rows[i].name.indexOf("Protea Hotel") != -1){

			//$hotel_row->name = str_replace("Protea Hotel","PH",$hotel_row->name);
			hotel_rows[i].name = hotel_rows[i].name.replace("Protea Hotel","PH");
			//$ph_hotels_rows[] = $hotel_row;
			ph_hotel_rows[ph_count] = hotel_rows[i];
			ph_count++;

		}else{
			//$other_hotel_rows[] = $hotel_row;
			other_hotel_rows[other_count] = hotel_rows[i];
			other_count++;
		}
	}

	//add the hotels that have PH as prefix first
	hotel_rows = ph_hotel_rows;
	//add the hotels that doesnt contain PH


	var curr_size = hotel_rows.length;
	for (var i = 0; i < other_hotel_rows.length; i++){
		hotel_rows[curr_size+i] = other_hotel_rows[i];
	}
	return hotel_rows;
}

function sortList(obj,selectedId,default_name) {

	var values = new Array();
	var ph_values = new Array();
	var ph_count = 0;
	var count = 0;

	for(var i = 1; i < obj.options.length; i++) {
		if(obj.options[i].innerHTML.indexOf("Protea Hotel ") != -1){
			ph_values.push(obj.options[i].innerHTML.replace("Protea Hotel ","PH ") + "--xx--" + obj.options[i].value);

		}
		else{
			values.push(obj.options[i].innerHTML + "--xx--" + obj.options[i].value);
		}
	}

	ph_values = ph_values.sort();
	values = values.sort();
	obj.options.length = 0;
	obj.options.add(new Option(default_name,default_value));

	for(var i = 0; i < ph_values.length; i++) {
		valueArray = ph_values[i].split('--xx--');
		obj.options.add(new Option(valueArray[0],valueArray[1]));

		if(selectedId == valueArray[1]){
			obj.selectedIndex = i+1;
		}

		//obj.options[i].innerHTML = valueArray[0];
		//obj.options[i].value = valueArray[1];
	}

	for(var i = 0; i < values.length; i++) {
		valueArray = values[i].split('--xx--');
		obj.options.add(new Option(valueArray[0],valueArray[1]));

		if(selectedId == valueArray[1]){
			obj.selectedIndex = i+1;
		}

		//obj.options[i].innerHTML = valueArray[0];
		//obj.options[i].value = valueArray[1];
	}
}



/* FILE: modules/mod_scripts/calender.js*/
/*  Copyright Mihai Bazon, 2002-2005  |  www.bazon.net/mishoo
* -----------------------------------------------------------
*
* The DHTML Calendar, version 1.0 "It is happening again"
*
* Details and latest version at:
* www.dynarch.com/projects/calendar
*
* This script is developed by Dynarch.com.  Visit us at www.dynarch.com.
*
* This script is distributed under the GNU Lesser General Public License.
* Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
*/

// $Id: calender.js,v 1.2 2007/07/10 09:05:52 chogori Exp $

/** The Calendar object constructor. */
Calendar = function (firstDayOfWeek, dateStr, onSelected, onClose) {
	// member variables
	this.activeDiv = null;
	this.currentDateEl = null;
	this.getDateStatus = null;
	this.getDateToolTip = null;
	this.getDateText = null;
	this.timeout = null;
	this.onSelected = onSelected || null;
	this.onClose = onClose || null;
	this.dragging = false;
	this.hidden = false;
	this.minYear = 1970;
	this.maxYear = 2050;
	this.dateFormat = Calendar._TT["DEF_DATE_FORMAT"];
	this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"];
	this.isPopup = true;
	this.weekNumbers = true;
	this.firstDayOfWeek = typeof firstDayOfWeek == "number" ? firstDayOfWeek : Calendar._FD; // 0 for Sunday, 1 for Monday, etc.
	this.showsOtherMonths = false;
	this.dateStr = dateStr;
	this.ar_days = null;
	this.showsTime = false;
	this.time24 = true;
	this.yearStep = 1;
	this.hiliteToday = true;
	this.multiple = null;
	// HTML elements
	this.table = null;
	this.element = null;
	this.tbody = null;
	this.firstdayname = null;
	// Combo boxes
	this.monthsCombo = null;
	this.yearsCombo = null;
	this.hilitedMonth = null;
	this.activeMonth = null;
	this.hilitedYear = null;
	this.activeYear = null;
	// Information
	this.dateClicked = false;

	// one-time initializations
	if (typeof Calendar._SDN == "undefined") {
		// table of short day names
		if (typeof Calendar._SDN_len == "undefined")
		Calendar._SDN_len = 3;
		var ar = new Array();
		for (var i = 8; i > 0;) {
			ar[--i] = Calendar._DN[i].substr(0, Calendar._SDN_len);
		}
		Calendar._SDN = ar;
		// table of short month names
		if (typeof Calendar._SMN_len == "undefined")
		Calendar._SMN_len = 3;
		ar = new Array();
		for (var i = 12; i > 0;) {
			ar[--i] = Calendar._MN[i].substr(0, Calendar._SMN_len);
		}
		Calendar._SMN = ar;
	}
};

// ** constants

/// "static", needed for event handlers.
Calendar._C = null;

/// detect a special case of "web browser"
Calendar.is_ie = ( /msie/i.test(navigator.userAgent) &&
!/opera/i.test(navigator.userAgent) );

Calendar.is_ie5 = ( Calendar.is_ie && /msie 5\.0/i.test(navigator.userAgent) );

/// detect Opera browser
Calendar.is_opera = /opera/i.test(navigator.userAgent);

/// detect KHTML-based browsers
Calendar.is_khtml = /Konqueror|Safari|KHTML/i.test(navigator.userAgent);

// BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate
//        library, at some point.

Calendar.getAbsolutePos = function(el) {
	var SL = 0, ST = 0;
	var is_div = /^div$/i.test(el.tagName);
	if (is_div && el.scrollLeft)
	SL = el.scrollLeft;
	if (is_div && el.scrollTop)
	ST = el.scrollTop;
	var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
	if (el.offsetParent) {
		var tmp = this.getAbsolutePos(el.offsetParent);
		r.x += tmp.x;
		r.y += tmp.y;
	}
	return r;
};

Calendar.isRelated = function (el, evt) {
	var related = evt.relatedTarget;
	if (!related) {
		var type = evt.type;
		if (type == "mouseover") {
			related = evt.fromElement;
		} else if (type == "mouseout") {
			related = evt.toElement;
		}
	}
	while (related) {
		if (related == el) {
			return true;
		}
		related = related.parentNode;
	}
	return false;
};

Calendar.removeClass = function(el, className) {
	if (!(el && el.className)) {
		return;
	}
	var cls = el.className.split(" ");
	var ar = new Array();
	for (var i = cls.length; i > 0;) {
		if (cls[--i] != className) {
			ar[ar.length] = cls[i];
		}
	}
	el.className = ar.join(" ");
};

Calendar.addClass = function(el, className) {
	Calendar.removeClass(el, className);
	el.className += " " + className;
};

// FIXME: the following 2 functions totally suck, are useless and should be replaced immediately.
Calendar.getElement = function(ev) {
	var f = Calendar.is_ie ? window.event.srcElement : ev.currentTarget;
	while (f.nodeType != 1 || /^div$/i.test(f.tagName))
	f = f.parentNode;
	return f;
};

Calendar.getTargetElement = function(ev) {
	var f = Calendar.is_ie ? window.event.srcElement : ev.target;
	while (f.nodeType != 1)
	f = f.parentNode;
	return f;
};

Calendar.stopEvent = function(ev) {
	ev || (ev = window.event);
	if (Calendar.is_ie) {
		ev.cancelBubble = true;
		ev.returnValue = false;
	} else {
		ev.preventDefault();
		ev.stopPropagation();
	}
	return false;
};

Calendar.addEvent = function(el, evname, func) {
	if (el.attachEvent) { // IE
		el.attachEvent("on" + evname, func);
	} else if (el.addEventListener) { // Gecko / W3C
		el.addEventListener(evname, func, true);
	} else {
		el["on" + evname] = func;
	}
};

Calendar.removeEvent = function(el, evname, func) {
	if (el.detachEvent) { // IE
		el.detachEvent("on" + evname, func);
	} else if (el.removeEventListener) { // Gecko / W3C
		el.removeEventListener(evname, func, true);
	} else {
		el["on" + evname] = null;
	}
};

Calendar.createElement = function(type, parent) {
	var el = null;
	if (document.createElementNS) {
		// use the XHTML namespace; IE won't normally get here unless
		// _they_ "fix" the DOM2 implementation.
		el = document.createElementNS("http://www.w3.org/1999/xhtml", type);
	} else {
		el = document.createElement(type);
	}
	if (typeof parent != "undefined") {
		parent.appendChild(el);
	}
	return el;
};

// END: UTILITY FUNCTIONS

// BEGIN: CALENDAR STATIC FUNCTIONS

/** Internal -- adds a set of events to make some element behave like a button. */
Calendar._add_evs = function(el) {
	with (Calendar) {
		addEvent(el, "mouseover", dayMouseOver);
		addEvent(el, "mousedown", dayMouseDown);
		addEvent(el, "mouseout", dayMouseOut);
		if (is_ie) {
			addEvent(el, "dblclick", dayMouseDblClick);
			el.setAttribute("unselectable", true);
		}
	}
};

Calendar.findMonth = function(el) {
	if (typeof el.month != "undefined") {
		return el;
	} else if (typeof el.parentNode.month != "undefined") {
		return el.parentNode;
	}
	return null;
};

Calendar.findYear = function(el) {
	if (typeof el.year != "undefined") {
		return el;
	} else if (typeof el.parentNode.year != "undefined") {
		return el.parentNode;
	}
	return null;
};

Calendar.showMonthsCombo = function () {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	var cal = cal;
	var cd = cal.activeDiv;
	var mc = cal.monthsCombo;
	if (cal.hilitedMonth) {
		Calendar.removeClass(cal.hilitedMonth, "hilite");
	}
	if (cal.activeMonth) {
		Calendar.removeClass(cal.activeMonth, "active");
	}
	var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()];
	Calendar.addClass(mon, "active");
	cal.activeMonth = mon;
	var s = mc.style;
	s.display = "block";
	if (cd.navtype < 0)
	s.left = cd.offsetLeft + "px";
	else {
		var mcw = mc.offsetWidth;
		if (typeof mcw == "undefined")
		// Konqueror brain-dead techniques
		mcw = 50;
		s.left = (cd.offsetLeft + cd.offsetWidth - mcw) + "px";
	}
	s.top = (cd.offsetTop + cd.offsetHeight) + "px";
};

Calendar.showYearsCombo = function (fwd) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	var cal = cal;
	var cd = cal.activeDiv;
	var yc = cal.yearsCombo;
	if (cal.hilitedYear) {
		Calendar.removeClass(cal.hilitedYear, "hilite");
	}
	if (cal.activeYear) {
		Calendar.removeClass(cal.activeYear, "active");
	}
	cal.activeYear = null;
	var Y = cal.date.getFullYear() + (fwd ? 1 : -1);
	var yr = yc.firstChild;
	var show = false;
	for (var i = 12; i > 0; --i) {
		if (Y >= cal.minYear && Y <= cal.maxYear) {
			yr.innerHTML = Y;
			yr.year = Y;

			yr.style.display = "block";
			show = true;
		} else {
			yr.style.display = "none";
		}
		yr = yr.nextSibling;
		Y += fwd ? cal.yearStep : -cal.yearStep;
	}
	if (show) {
		var s = yc.style;
		s.display = "block";
		if (cd.navtype < 0)
		s.left = cd.offsetLeft + "px";
		else {
			var ycw = yc.offsetWidth;
			if (typeof ycw == "undefined")
			// Konqueror brain-dead techniques
			ycw = 50;
			s.left = (cd.offsetLeft + cd.offsetWidth - ycw) + "px";
		}
		s.top = (cd.offsetTop + cd.offsetHeight) + "px";
	}
};

// event handlers

Calendar.tableMouseUp = function(ev) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	if (cal.timeout) {
		clearTimeout(cal.timeout);
	}
	var el = cal.activeDiv;
	if (!el) {
		return false;
	}
	var target = Calendar.getTargetElement(ev);
	ev || (ev = window.event);
	Calendar.removeClass(el, "active");
	if (target == el || target.parentNode == el) {
		Calendar.cellClick(el, ev);
	}
	var mon = Calendar.findMonth(target);
	var date = null;
	if (mon) {
		date = new Date(cal.date);
		if (mon.month != date.getMonth()) {
			date.setMonth(mon.month);
			cal.setDate(date);
			cal.dateClicked = false;
			cal.callHandler();
		}
	} else {
		var year = Calendar.findYear(target);
		if (year) {
			date = new Date(cal.date);
			if (year.year != date.getFullYear()) {
				date.setFullYear(year.year);
				cal.setDate(date);
				cal.dateClicked = false;
				cal.callHandler();
			}
		}
	}
	with (Calendar) {
		removeEvent(document, "mouseup", tableMouseUp);
		removeEvent(document, "mouseover", tableMouseOver);
		removeEvent(document, "mousemove", tableMouseOver);
		cal._hideCombos();
		_C = null;
		return stopEvent(ev);
	}
};

Calendar.tableMouseOver = function (ev) {
	var cal = Calendar._C;
	if (!cal) {
		return;
	}
	var el = cal.activeDiv;
	var target = Calendar.getTargetElement(ev);
	if (target == el || target.parentNode == el) {
		Calendar.addClass(el, "hilite active");
		Calendar.addClass(el.parentNode, "rowhilite");
	} else {
		if (typeof el.navtype == "undefined" || (el.navtype != 50 && (el.navtype == 0 || Math.abs(el.navtype) > 2)))
		Calendar.removeClass(el, "active");
		Calendar.removeClass(el, "hilite");
		Calendar.removeClass(el.parentNode, "rowhilite");
	}
	ev || (ev = window.event);
	if (el.navtype == 50 && target != el) {
		var pos = Calendar.getAbsolutePos(el);
		var w = el.offsetWidth;
		var x = ev.clientX;
		var dx;
		var decrease = true;
		if (x > pos.x + w) {
			dx = x - pos.x - w;
			decrease = false;
		} else
		dx = pos.x - x;

		if (dx < 0) dx = 0;
		var range = el._range;
		var current = el._current;
		var count = Math.floor(dx / 10) % range.length;
		for (var i = range.length; --i >= 0;)
		if (range[i] == current)
		break;
		while (count-- > 0)
		if (decrease) {
			if (--i < 0)
			i = range.length - 1;
		} else if ( ++i >= range.length )
		i = 0;
		var newval = range[i];
		el.innerHTML = newval;

		cal.onUpdateTime();
	}
	var mon = Calendar.findMonth(target);
	if (mon) {
		if (mon.month != cal.date.getMonth()) {
			if (cal.hilitedMonth) {
				Calendar.removeClass(cal.hilitedMonth, "hilite");
			}
			Calendar.addClass(mon, "hilite");
			cal.hilitedMonth = mon;
		} else if (cal.hilitedMonth) {
			Calendar.removeClass(cal.hilitedMonth, "hilite");
		}
	} else {
		if (cal.hilitedMonth) {
			Calendar.removeClass(cal.hilitedMonth, "hilite");
		}
		var year = Calendar.findYear(target);
		if (year) {
			if (year.year != cal.date.getFullYear()) {
				if (cal.hilitedYear) {
					Calendar.removeClass(cal.hilitedYear, "hilite");
				}
				Calendar.addClass(year, "hilite");
				cal.hilitedYear = year;
			} else if (cal.hilitedYear) {
				Calendar.removeClass(cal.hilitedYear, "hilite");
			}
		} else if (cal.hilitedYear) {
			Calendar.removeClass(cal.hilitedYear, "hilite");
		}
	}
	return Calendar.stopEvent(ev);
};

Calendar.tableMouseDown = function (ev) {
	if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) {
		return Calendar.stopEvent(ev);
	}
};

Calendar.calDragIt = function (ev) {
	var cal = Calendar._C;
	if (!(cal && cal.dragging)) {
		return false;
	}
	var posX;
	var posY;
	if (Calendar.is_ie) {
		posY = window.event.clientY + document.body.scrollTop;
		posX = window.event.clientX + document.body.scrollLeft;
	} else {
		posX = ev.pageX;
		posY = ev.pageY;
	}
	cal.hideShowCovered();
	var st = cal.element.style;
	st.left = (posX - cal.xOffs) + "px";
	st.top = (posY - cal.yOffs) + "px";
	return Calendar.stopEvent(ev);
};

Calendar.calDragEnd = function (ev) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	cal.dragging = false;
	with (Calendar) {
		removeEvent(document, "mousemove", calDragIt);
		removeEvent(document, "mouseup", calDragEnd);
		tableMouseUp(ev);
	}
	cal.hideShowCovered();
};

Calendar.dayMouseDown = function(ev) {
	var el = Calendar.getElement(ev);
	if (el.disabled) {
		return false;
	}
	var cal = el.calendar;
	cal.activeDiv = el;
	Calendar._C = cal;
	if (el.navtype != 300) with (Calendar) {
		if (el.navtype == 50) {
			el._current = el.innerHTML;
			addEvent(document, "mousemove", tableMouseOver);
		} else
		addEvent(document, Calendar.is_ie5 ? "mousemove" : "mouseover", tableMouseOver);
		addClass(el, "hilite active");
		addEvent(document, "mouseup", tableMouseUp);
	} else if (cal.isPopup) {
		cal._dragStart(ev);
	}
	if (el.navtype == -1 || el.navtype == 1) {
		if (cal.timeout) clearTimeout(cal.timeout);
		cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250);
	} else if (el.navtype == -2 || el.navtype == 2) {
		if (cal.timeout) clearTimeout(cal.timeout);
		cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250);
	} else {
		cal.timeout = null;
	}
	return Calendar.stopEvent(ev);
};

Calendar.dayMouseDblClick = function(ev) {
	Calendar.cellClick(Calendar.getElement(ev), ev || window.event);
	if (Calendar.is_ie) {
		document.selection.empty();
	}
};

Calendar.dayMouseOver = function(ev) {
	var el = Calendar.getElement(ev);
	if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) {
		return false;
	}
	if (el.ttip) {
		if (el.ttip.substr(0, 1) == "_") {
			el.ttip = el.caldate.print(el.calendar.ttDateFormat) + el.ttip.substr(1);
		}
		el.calendar.tooltips.innerHTML = el.ttip;
	}
	if (el.navtype != 300) {
		Calendar.addClass(el, "hilite");
		if (el.caldate) {
			Calendar.addClass(el.parentNode, "rowhilite");
		}
	}
	return Calendar.stopEvent(ev);
};

Calendar.dayMouseOut = function(ev) {
	with (Calendar) {
		var el = getElement(ev);
		if (isRelated(el, ev) || _C || el.disabled)
		return false;
		removeClass(el, "hilite");
		if (el.caldate)
		removeClass(el.parentNode, "rowhilite");
		if (el.calendar)
		el.calendar.tooltips.innerHTML = _TT["SEL_DATE"];
		return stopEvent(ev);
	}
};

/**
*  A generic "click" handler :) handles all types of buttons defined in this
*  calendar.
*/
Calendar.cellClick = function(el, ev) {
	var cal = el.calendar;
	var closing = false;
	var newdate = false;
	var date = null;
	if (typeof el.navtype == "undefined") {
		if (cal.currentDateEl) {
			Calendar.removeClass(cal.currentDateEl, "selected");
			Calendar.addClass(el, "selected");
			closing = (cal.currentDateEl == el);
			if (!closing) {
				cal.currentDateEl = el;
			}
		}
		cal.date.setDateOnly(el.caldate);
		date = cal.date;
		var other_month = !(cal.dateClicked = !el.otherMonth);
		if (!other_month && !cal.currentDateEl)
		cal._toggleMultipleDate(new Date(date));
		else
		newdate = !el.disabled;
		// a date was clicked
		if (other_month)
		cal._init(cal.firstDayOfWeek, date);
	} else {
		if (el.navtype == 200) {
			Calendar.removeClass(el, "hilite");
			cal.callCloseHandler();
			return;
		}
		date = new Date(cal.date);
		if (el.navtype == 0)
		date.setDateOnly(new Date()); // TODAY
		// unless "today" was clicked, we assume no date was clicked so
		// the selected handler will know not to close the calenar when
		// in single-click mode.
		// cal.dateClicked = (el.navtype == 0);
		cal.dateClicked = false;
		var year = date.getFullYear();
		var mon = date.getMonth();
		function setMonth(m) {
			var day = date.getDate();
			var max = date.getMonthDays(m);
			if (day > max) {
				date.setDate(max);
			}
			date.setMonth(m);
		};
		switch (el.navtype) {
			case 400:
			Calendar.removeClass(el, "hilite");
			var text = Calendar._TT["ABOUT"];
			if (typeof text != "undefined") {
				text += cal.showsTime ? Calendar._TT["ABOUT_TIME"] : "";
			} else {
				// FIXME: this should be removed as soon as lang files get updated!
				text = "Help and about box text is not translated into this language.\n" +
				"If you know this language and you feel generous please update\n" +
				"the corresponding file in \"lang\" subdir to match calendar-en.js\n" +
				"and send it back to <mihai_bazon@yahoo.com> to get it into the distribution  ;-)\n\n" +
				"Thank you!\n" +
				"http://dynarch.com/mishoo/calendar.epl\n";
			}
			alert(text);
			return;
			case -2:
			if (year > cal.minYear) {
				date.setFullYear(year - 1);
			}
			break;
			case -1:
			if (mon > 0) {
				setMonth(mon - 1);
			} else if (year-- > cal.minYear) {
				date.setFullYear(year);
				setMonth(11);
			}
			break;
			case 1:
			if (mon < 11) {
				setMonth(mon + 1);
			} else if (year < cal.maxYear) {
				date.setFullYear(year + 1);
				setMonth(0);
			}
			break;
			case 2:
			if (year < cal.maxYear) {
				date.setFullYear(year + 1);
			}
			break;
			case 100:
			cal.setFirstDayOfWeek(el.fdow);
			return;
			case 50:
			var range = el._range;
			var current = el.innerHTML;
			for (var i = range.length; --i >= 0;)
			if (range[i] == current)
			break;
			if (ev && ev.shiftKey) {
				if (--i < 0)
				i = range.length - 1;
			} else if ( ++i >= range.length )
			i = 0;
			var newval = range[i];
			el.innerHTML = newval;
			cal.onUpdateTime();
			return;
			case 0:
			// TODAY will bring us here
			if ((typeof cal.getDateStatus == "function") &&
			cal.getDateStatus(date, date.getFullYear(), date.getMonth(), date.getDate())) {
				return false;
			}
			break;
		}
		if (!date.equalsTo(cal.date)) {
			cal.setDate(date);
			newdate = true;
		} else if (el.navtype == 0)
		newdate = closing = true;
	}
	if (newdate) {
		ev && cal.callHandler();
	}
	if (closing) {
		Calendar.removeClass(el, "hilite");
		ev && cal.callCloseHandler();
	}
};

// END: CALENDAR STATIC FUNCTIONS

// BEGIN: CALENDAR OBJECT FUNCTIONS

/**
*  This function creates the calendar inside the given parent.  If _par is
*  null than it creates a popup calendar inside the BODY element.  If _par is
*  an element, be it BODY, then it creates a non-popup calendar (still
*  hidden).  Some properties need to be set before calling this function.
*/
Calendar.prototype.create = function (_par) {
	var parent = null;
	if (! _par) {
		// default parent is the document body, in which case we create
		// a popup calendar.
		parent = document.getElementsByTagName("body")[0];
		this.isPopup = true;
	} else {
		parent = _par;
		this.isPopup = false;
	}
	this.date = this.dateStr ? new Date(this.dateStr) : new Date();

	var table = Calendar.createElement("table");
	this.table = table;
	table.cellSpacing = 0;
	table.cellPadding = 0;
	table.calendar = this;
	Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown);

	var div = Calendar.createElement("div");
	this.element = div;
	div.className = "calendar";
	if (this.isPopup) {
		div.style.position = "absolute";
		div.style.display = "none";
	}
	div.appendChild(table);

	var thead = Calendar.createElement("thead", table);
	var cell = null;
	var row = null;

	var cal = this;
	var hh = function (text, cs, navtype) {
		cell = Calendar.createElement("td", row);
		cell.colSpan = cs;
		cell.className = "button";
		if (navtype != 0 && Math.abs(navtype) <= 2)
		cell.className += " nav";

		Calendar._add_evs(cell);
		cell.calendar = cal;
		cell.navtype = navtype;
		cell.innerHTML = "<div unselectable='on'>" + text + "</div>";
		return cell;
	};

	row = Calendar.createElement("tr", thead);
	var title_length = 7;
	(this.isPopup) && --title_length;
	(this.weekNumbers) && ++title_length;

	//hh("?", 1, 400).ttip = Calendar._TT["INFO"];
	this.title = hh("", title_length, 300);
	this.title.className = "title";
	if (this.isPopup) {
		this.title.ttip = Calendar._TT["DRAG_TO_MOVE"];
		this.title.style.cursor = "move";
		hh("&#x00d7;", 1, 200).ttip = Calendar._TT["CLOSE"];
	}

	row = Calendar.createElement("tr", thead);
	row.className = "headrow";

	//this._nav_py = hh("&#x00ab;", 1, -2);
	//this._nav_py.ttip = Calendar._TT["PREV_YEAR"];

	this._nav_pm = hh("&#x2039;", 1, -1);
	this._nav_pm.ttip = Calendar._TT["PREV_MONTH"];

	this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 5, 0);
	this._nav_now.ttip = Calendar._TT["GO_TODAY"];

	this._nav_nm = hh("&#x203a;", 1, 1);
	this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"];

	//this._nav_ny = hh("&#x00bb;", 1, 2);
	//this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"];

	// day names
	row = Calendar.createElement("tr", thead);
	row.className = "daynames";
	if (this.weekNumbers) {
		cell = Calendar.createElement("td", row);
		cell.className = "name wn";
		cell.innerHTML = Calendar._TT["WK"];
	}
	for (var i = 7; i > 0; --i) {
		cell = Calendar.createElement("td", row);
		if (!i) {
			cell.navtype = 100;
			cell.calendar = this;
			Calendar._add_evs(cell);
		}
	}
	this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild;
	this._displayWeekdays();

	var tbody = Calendar.createElement("tbody", table);
	this.tbody = tbody;

	for (i = 6; i > 0; --i) {
		row = Calendar.createElement("tr", tbody);
		if (this.weekNumbers) {
			cell = Calendar.createElement("td", row);
		}
		for (var j = 7; j > 0; --j) {
			cell = Calendar.createElement("td", row);
			cell.calendar = this;
			Calendar._add_evs(cell);
		}
	}

	if (this.showsTime) {
		row = Calendar.createElement("tr", tbody);
		row.className = "time";

		cell = Calendar.createElement("td", row);
		cell.className = "time";
		cell.colSpan = 2;
		cell.innerHTML = Calendar._TT["TIME"] || "&nbsp;";

		cell = Calendar.createElement("td", row);
		cell.className = "time";
		cell.colSpan = this.weekNumbers ? 4 : 3;

		(function(){
			function makeTimePart(className, init, range_start, range_end) {
				var part = Calendar.createElement("span", cell);
				part.className = className;
				part.innerHTML = init;
				part.calendar = cal;
				part.ttip = Calendar._TT["TIME_PART"];
				part.navtype = 50;
				part._range = [];
				if (typeof range_start != "number")
				part._range = range_start;
				else {
					for (var i = range_start; i <= range_end; ++i) {
						var txt;
						if (i < 10 && range_end >= 10) txt = '0' + i;
						else txt = '' + i;
						part._range[part._range.length] = txt;
					}
				}
				Calendar._add_evs(part);
				return part;
			};
			var hrs = cal.date.getHours();
			var mins = cal.date.getMinutes();
			var t12 = !cal.time24;
			var pm = (hrs > 12);
			if (t12 && pm) hrs -= 12;
			var H = makeTimePart("hour", hrs, t12 ? 1 : 0, t12 ? 12 : 23);
			var span = Calendar.createElement("span", cell);
			span.innerHTML = ":";
			span.className = "colon";
			var M = makeTimePart("minute", mins, 0, 59);
			var AP = null;
			cell = Calendar.createElement("td", row);
			cell.className = "time";
			cell.colSpan = 2;
			if (t12)
			AP = makeTimePart("ampm", pm ? "pm" : "am", ["am", "pm"]);
			else
			cell.innerHTML = "&nbsp;";

			cal.onSetTime = function() {
				var pm, hrs = this.date.getHours(),
				mins = this.date.getMinutes();
				if (t12) {
					pm = (hrs >= 12);
					if (pm) hrs -= 12;
					if (hrs == 0) hrs = 12;
					AP.innerHTML = pm ? "pm" : "am";
				}
				H.innerHTML = (hrs < 10) ? ("0" + hrs) : hrs;
				M.innerHTML = (mins < 10) ? ("0" + mins) : mins;
			};

			cal.onUpdateTime = function() {
				var date = this.date;
				var h = parseInt(H.innerHTML, 10);
				if (t12) {
					if (/pm/i.test(AP.innerHTML) && h < 12)
					h += 12;
					else if (/am/i.test(AP.innerHTML) && h == 12)
					h = 0;
				}
				var d = date.getDate();
				var m = date.getMonth();
				var y = date.getFullYear();
				date.setHours(h);
				date.setMinutes(parseInt(M.innerHTML, 10));
				date.setFullYear(y);
				date.setMonth(m);
				date.setDate(d);
				this.dateClicked = false;
				this.callHandler();
			};
		})();
	} else {
		this.onSetTime = this.onUpdateTime = function() {};
	}

	var tfoot = Calendar.createElement("tfoot", table);

	row = Calendar.createElement("tr", tfoot);
	row.className = "footrow";

	cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300);
	cell.className = "ttip";
	if (this.isPopup) {
		cell.ttip = Calendar._TT["DRAG_TO_MOVE"];
		cell.style.cursor = "move";
	}
	this.tooltips = cell;

	div = Calendar.createElement("div", this.element);
	this.monthsCombo = div;
	div.className = "combo";
	for (i = 0; i < Calendar._MN.length; ++i) {
		var mn = Calendar.createElement("div");
		mn.className = Calendar.is_ie ? "label-IEfix" : "label";
		mn.month = i;
		mn.innerHTML = Calendar._SMN[i];
		div.appendChild(mn);
	}

	div = Calendar.createElement("div", this.element);
	this.yearsCombo = div;
	div.className = "combo";
	for (i = 12; i > 0; --i) {
		var yr = Calendar.createElement("div");
		yr.className = Calendar.is_ie ? "label-IEfix" : "label";
		div.appendChild(yr);
	}

	this._init(this.firstDayOfWeek, this.date);
	parent.appendChild(this.element);
};

/** keyboard navigation, only for popup calendars */
Calendar._keyEvent = function(ev) {
	var cal = window._dynarch_popupCalendar;
	if (!cal || cal.multiple)
	return false;
	(Calendar.is_ie) && (ev = window.event);
	var act = (Calendar.is_ie || ev.type == "keypress"),
	K = ev.keyCode;
	if (ev.ctrlKey) {
		switch (K) {
			case 37: // KEY left
			act && Calendar.cellClick(cal._nav_pm);
			break;
			case 38: // KEY up
			act && Calendar.cellClick(cal._nav_py);
			break;
			case 39: // KEY right
			act && Calendar.cellClick(cal._nav_nm);
			break;
			case 40: // KEY down
			act && Calendar.cellClick(cal._nav_ny);
			break;
			default:
			return false;
		}
	} else switch (K) {
		case 32: // KEY space (now)
		Calendar.cellClick(cal._nav_now);
		break;
		case 27: // KEY esc
		act && cal.callCloseHandler();
		break;
		case 37: // KEY left
		case 38: // KEY up
		case 39: // KEY right
		case 40: // KEY down
		if (act) {
			var prev, x, y, ne, el, step;
			prev = K == 37 || K == 38;
			step = (K == 37 || K == 39) ? 1 : 7;
			function setVars() {
				el = cal.currentDateEl;
				var p = el.pos;
				x = p & 15;
				y = p >> 4;
				ne = cal.ar_days[y][x];
			};setVars();
			function prevMonth() {
				var date = new Date(cal.date);
				date.setDate(date.getDate() - step);
				cal.setDate(date);
			};
			function nextMonth() {
				var date = new Date(cal.date);
				date.setDate(date.getDate() + step);
				cal.setDate(date);
			};
			while (1) {
				switch (K) {
					case 37: // KEY left
					if (--x >= 0)
					ne = cal.ar_days[y][x];
					else {
						x = 6;
						K = 38;
						continue;
					}
					break;
					case 38: // KEY up
					if (--y >= 0)
					ne = cal.ar_days[y][x];
					else {
						prevMonth();
						setVars();
					}
					break;
					case 39: // KEY right
					if (++x < 7)
					ne = cal.ar_days[y][x];
					else {
						x = 0;
						K = 40;
						continue;
					}
					break;
					case 40: // KEY down
					if (++y < cal.ar_days.length)
					ne = cal.ar_days[y][x];
					else {
						nextMonth();
						setVars();
					}
					break;
				}
				break;
			}
			if (ne) {
				if (!ne.disabled)
				Calendar.cellClick(ne);
				else if (prev)
				prevMonth();
				else
				nextMonth();
			}
		}
		break;
		case 13: // KEY enter
		if (act)
		Calendar.cellClick(cal.currentDateEl, ev);
		break;
		default:
		return false;
	}
	return Calendar.stopEvent(ev);
};

/**
*  (RE)Initializes the calendar to the given date and firstDayOfWeek
*/
Calendar.prototype._init = function (firstDayOfWeek, date) {
	var today = new Date(),
	TY = today.getFullYear(),
	TM = today.getMonth(),
	TD = today.getDate();
	this.table.style.visibility = "hidden";
	var year = date.getFullYear();
	if (year < this.minYear) {
		year = this.minYear;
		date.setFullYear(year);
	} else if (year > this.maxYear) {
		year = this.maxYear;
		date.setFullYear(year);
	}
	this.firstDayOfWeek = firstDayOfWeek;
	this.date = new Date(date);
	var month = date.getMonth();
	var mday = date.getDate();
	var no_days = date.getMonthDays();

	// calendar voodoo for computing the first day that would actually be
	// displayed in the calendar, even if it's from the previous month.
	// WARNING: this is magic. ;-)
	date.setDate(1);
	var day1 = (date.getDay() - this.firstDayOfWeek) % 7;
	if (day1 < 0)
	day1 += 7;
	date.setDate(-day1);
	date.setDate(date.getDate() + 1);

	var row = this.tbody.firstChild;
	var MN = Calendar._SMN[month];
	var ar_days = this.ar_days = new Array();
	var weekend = Calendar._TT["WEEKEND"];
	var dates = this.multiple ? (this.datesCells = {}) : null;
	for (var i = 0; i < 6; ++i, row = row.nextSibling) {
		var cell = row.firstChild;
		if (this.weekNumbers) {
			cell.className = "day wn";
			cell.innerHTML = date.getWeekNumber();
			cell = cell.nextSibling;
		}
		row.className = "daysrow";
		var hasdays = false, iday, dpos = ar_days[i] = [];
		for (var j = 0; j < 7; ++j, cell = cell.nextSibling, date.setDate(iday + 1)) {
			iday = date.getDate();
			var wday = date.getDay();
			cell.className = "day";
			cell.pos = i << 4 | j;
			dpos[j] = cell;
			var current_month = (date.getMonth() == month);
			if (!current_month) {
				if (this.showsOtherMonths) {
					cell.className += " othermonth";
					cell.otherMonth = true;
				} else {
					cell.className = "emptycell";
					cell.innerHTML = "&nbsp;";
					cell.disabled = true;
					continue;
				}
			} else {
				cell.otherMonth = false;
				hasdays = true;
			}
			cell.disabled = false;
			cell.innerHTML = this.getDateText ? this.getDateText(date, iday) : iday;
			if (dates)
			dates[date.print("%Y%m%d")] = cell;
			if (this.getDateStatus) {
				var status = this.getDateStatus(date, year, month, iday);
				if (this.getDateToolTip) {
					var toolTip = this.getDateToolTip(date, year, month, iday);
					if (toolTip)
					cell.title = toolTip;
				}
				if (status === true) {
					cell.className += " disabled";
					cell.disabled = true;
				} else {
					if (/disabled/i.test(status))
					cell.disabled = true;
					cell.className += " " + status;
				}
			}
			if (!cell.disabled) {
				cell.caldate = new Date(date);
				cell.ttip = "_";
				if (!this.multiple && current_month
				&& iday == mday && this.hiliteToday) {
					cell.className += " selected";
					this.currentDateEl = cell;
				}
				if (date.getFullYear() == TY &&
				date.getMonth() == TM &&
				iday == TD) {
					cell.className += " today";
					cell.ttip += Calendar._TT["PART_TODAY"];
				}
				if (weekend.indexOf(wday.toString()) != -1)
				cell.className += cell.otherMonth ? " oweekend" : " weekend";
			}
		}
		if (!(hasdays || this.showsOtherMonths))
		row.className = "emptyrow";
	}
	this.title.innerHTML = Calendar._MN[month] + ", " + year;
	this.onSetTime();
	this.table.style.visibility = "visible";
	this._initMultipleDates();
	// PROFILE
	// this.tooltips.innerHTML = "Generated in " + ((new Date()) - today) + " ms";
};

Calendar.prototype._initMultipleDates = function() {
	if (this.multiple) {
		for (var i in this.multiple) {
			var cell = this.datesCells[i];
			var d = this.multiple[i];
			if (!d)
			continue;
			if (cell)
			cell.className += " selected";
		}
	}
};

Calendar.prototype._toggleMultipleDate = function(date) {
	if (this.multiple) {
		var ds = date.print("%Y%m%d");
		var cell = this.datesCells[ds];
		if (cell) {
			var d = this.multiple[ds];
			if (!d) {
				Calendar.addClass(cell, "selected");
				this.multiple[ds] = date;
			} else {
				Calendar.removeClass(cell, "selected");
				delete this.multiple[ds];
			}
		}
	}
};

Calendar.prototype.setDateToolTipHandler = function (unaryFunction) {
	this.getDateToolTip = unaryFunction;
};

/**
*  Calls _init function above for going to a certain date (but only if the
*  date is different than the currently selected one).
*/
Calendar.prototype.setDate = function (date) {
	if (!date.equalsTo(this.date)) {
		this._init(this.firstDayOfWeek, date);
	}
};

/**
*  Refreshes the calendar.  Useful if the "disabledHandler" function is
*  dynamic, meaning that the list of disabled date can change at runtime.
*  Just * call this function if you think that the list of disabled dates
*  should * change.
*/
Calendar.prototype.refresh = function () {
	this._init(this.firstDayOfWeek, this.date);
};

/** Modifies the "firstDayOfWeek" parameter (pass 0 for Synday, 1 for Monday, etc.). */
Calendar.prototype.setFirstDayOfWeek = function (firstDayOfWeek) {
	/** disabled - confused users ;-)
	this._init(firstDayOfWeek, this.date);
	this._displayWeekdays();
	*/
};

/**
*  Allows customization of what dates are enabled.  The "unaryFunction"
*  parameter must be a function object that receives the date (as a JS Date
*  object) and returns a boolean value.  If the returned value is true then
*  the passed date will be marked as disabled.
*/
Calendar.prototype.setDateStatusHandler = Calendar.prototype.setDisabledHandler = function (unaryFunction) {
	this.getDateStatus = unaryFunction;
};

/** Customization of allowed year range for the calendar. */
Calendar.prototype.setRange = function (a, z) {
	this.minYear = a;
	this.maxYear = z;
};

/** Calls the first user handler (selectedHandler). */
Calendar.prototype.callHandler = function () {
	if (this.onSelected) {
		this.onSelected(this, this.date.print(this.dateFormat));
	}
};

/** Calls the second user handler (closeHandler). */
Calendar.prototype.callCloseHandler = function () {
	if (this.onClose) {
		this.onClose(this);
	}
	this.hideShowCovered();
};

/** Removes the calendar object from the DOM tree and destroys it. */
Calendar.prototype.destroy = function () {
	var el = this.element.parentNode;
	el.removeChild(this.element);
	Calendar._C = null;
	window._dynarch_popupCalendar = null;
};

/**
*  Moves the calendar element to a different section in the DOM tree (changes
*  its parent).
*/
Calendar.prototype.reparent = function (new_parent) {
	var el = this.element;
	el.parentNode.removeChild(el);
	new_parent.appendChild(el);
};

// This gets called when the user presses a mouse button anywhere in the
// document, if the calendar is shown.  If the click was outside the open
// calendar this function closes it.
Calendar._checkCalendar = function(ev) {
	var calendar = window._dynarch_popupCalendar;
	if (!calendar) {
		return false;
	}
	var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev);
	for (; el != null && el != calendar.element; el = el.parentNode);
	if (el == null) {
		// calls closeHandler which should hide the calendar.
		window._dynarch_popupCalendar.callCloseHandler();
		return Calendar.stopEvent(ev);
	}
};

/** Shows the calendar. */
Calendar.prototype.show = function () {
	var rows = this.table.getElementsByTagName("tr");
	for (var i = rows.length; i > 0;) {
		var row = rows[--i];
		Calendar.removeClass(row, "rowhilite");
		var cells = row.getElementsByTagName("td");
		for (var j = cells.length; j > 0;) {
			var cell = cells[--j];
			Calendar.removeClass(cell, "hilite");
			Calendar.removeClass(cell, "active");
		}
	}
	this.element.style.display = "block";
	this.hidden = false;
	if (this.isPopup) {
		window._dynarch_popupCalendar = this;
		Calendar.addEvent(document, "keydown", Calendar._keyEvent);
		Calendar.addEvent(document, "keypress", Calendar._keyEvent);
		Calendar.addEvent(document, "mousedown", Calendar._checkCalendar);
	}
	this.hideShowCovered();
};

/**
*  Hides the calendar.  Also removes any "hilite" from the class of any TD
*  element.
*/
Calendar.prototype.hide = function () {
	if (this.isPopup) {
		Calendar.removeEvent(document, "keydown", Calendar._keyEvent);
		Calendar.removeEvent(document, "keypress", Calendar._keyEvent);
		Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar);
	}
	this.element.style.display = "none";
	this.hidden = true;
	this.hideShowCovered();
};

/**
*  Shows the calendar at a given absolute position (beware that, depending on
*  the calendar element style -- position property -- this might be relative
*  to the parent's containing rectangle).
*/
Calendar.prototype.showAt = function (x, y) {
	var s = this.element.style;
	s.left = x + "px";
	s.top = y + "px";
	this.show();
};

/** Shows the calendar near a given element. */
Calendar.prototype.showAtElement = function (el, opts) {
	var self = this;
	var p = Calendar.getAbsolutePos(el);
	if (!opts || typeof opts != "string") {
		this.showAt(p.x, p.y + el.offsetHeight);
		return true;
	}
	function fixPosition(box) {
		if (box.x < 0)
		box.x = 0;
		if (box.y < 0)
		box.y = 0;
		var cp = document.createElement("div");
		var s = cp.style;
		s.position = "absolute";
		s.right = s.bottom = s.width = s.height = "0px";
		document.body.appendChild(cp);
		var br = Calendar.getAbsolutePos(cp);
		document.body.removeChild(cp);
		if (Calendar.is_ie) {
			br.y += document.body.scrollTop;
			br.x += document.body.scrollLeft;
		} else {
			br.y += window.scrollY;
			br.x += window.scrollX;
		}
		var tmp = box.x + box.width - br.x;
		if (tmp > 0) box.x -= tmp;
		tmp = box.y + box.height - br.y;
		if (tmp > 0) box.y -= tmp;
	};
	this.element.style.display = "block";
	Calendar.continuation_for_the_fucking_khtml_browser = function() {
		var w = self.element.offsetWidth;
		var h = self.element.offsetHeight;
		self.element.style.display = "none";
		var valign = opts.substr(0, 1);
		var halign = "l";
		if (opts.length > 1) {
			halign = opts.substr(1, 1);
		}
		// vertical alignment
		switch (valign) {
			case "T": p.y -= h; break;
			case "B": p.y += el.offsetHeight; break;
			case "C": p.y += (el.offsetHeight - h) / 2; break;
			case "t": p.y += el.offsetHeight - h; break;
			case "b": break; // already there
		}
		// horizontal alignment
		switch (halign) {
			case "L": p.x -= w; break;
			case "R": p.x += el.offsetWidth; break;
			case "C": p.x += (el.offsetWidth - w) / 2; break;
			case "l": p.x += el.offsetWidth - w; break;
			case "r": break; // already there
		}
		p.width = w;
		p.height = h + 40;
		self.monthsCombo.style.display = "none";
		fixPosition(p);
		self.showAt(p.x, p.y);
	};
	if (Calendar.is_khtml)
	setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10);
	else
	Calendar.continuation_for_the_fucking_khtml_browser();
};

/** Customizes the date format. */
Calendar.prototype.setDateFormat = function (str) {
	this.dateFormat = str;
};

/** Customizes the tooltip date format. */
Calendar.prototype.setTtDateFormat = function (str) {
	this.ttDateFormat = str;
};

/**
*  Tries to identify the date represented in a string.  If successful it also
*  calls this.setDate which moves the calendar to the given date.
*/
Calendar.prototype.parseDate = function(str, fmt) {
	if (!fmt)
	fmt = this.dateFormat;
	this.setDate(Date.parseDate(str, fmt));
};

Calendar.prototype.hideShowCovered = function () {
	if (!Calendar.is_ie && !Calendar.is_opera)
	return;
	function getVisib(obj){
		var value = obj.style.visibility;
		if (!value) {
			if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C
				if (!Calendar.is_khtml)
				value = document.defaultView.
				getComputedStyle(obj, "").getPropertyValue("visibility");
				else
				value = '';
			} else if (obj.currentStyle) { // IE
				value = obj.currentStyle.visibility;
			} else
			value = '';
		}
		return value;
	};

	var tags = new Array("applet", "iframe", "select");
	var el = this.element;

	var p = Calendar.getAbsolutePos(el);
	var EX1 = p.x;
	var EX2 = el.offsetWidth + EX1;
	var EY1 = p.y;
	var EY2 = el.offsetHeight + EY1;

	for (var k = tags.length; k > 0; ) {
		var ar = document.getElementsByTagName(tags[--k]);
		var cc = null;

		for (var i = ar.length; i > 0;) {
			cc = ar[--i];

			p = Calendar.getAbsolutePos(cc);
			var CX1 = p.x;
			var CX2 = cc.offsetWidth + CX1;
			var CY1 = p.y;
			var CY2 = cc.offsetHeight + CY1;

			if (this.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) {
				if (!cc.__msh_save_visibility) {
					cc.__msh_save_visibility = getVisib(cc);
				}
				cc.style.visibility = cc.__msh_save_visibility;
			} else {
				if (!cc.__msh_save_visibility) {
					cc.__msh_save_visibility = getVisib(cc);
				}
				cc.style.visibility = "hidden";
			}
		}
	}
};

/** Internal function; it displays the bar with the names of the weekday. */
Calendar.prototype._displayWeekdays = function () {
	var fdow = this.firstDayOfWeek;
	var cell = this.firstdayname;
	var weekend = Calendar._TT["WEEKEND"];
	for (var i = 0; i < 7; ++i) {
		cell.className = "day name";
		var realday = (i + fdow) % 7;
		if (i) {
			cell.ttip = Calendar._TT["DAY_FIRST"].replace("%s", Calendar._DN[realday]);
			cell.navtype = 100;
			cell.calendar = this;
			cell.fdow = realday;
			//Calendar._add_evs(cell);
		}
		if (weekend.indexOf(realday.toString()) != -1) {
			Calendar.addClass(cell, "weekend");
		}
		cell.innerHTML = Calendar._SDN[(i + fdow) % 7];
		cell = cell.nextSibling;
	}
};

/** Internal function.  Hides all combo boxes that might be displayed. */
Calendar.prototype._hideCombos = function () {
	this.monthsCombo.style.display = "none";
	this.yearsCombo.style.display = "none";
};

/** Internal function.  Starts dragging the element. */
Calendar.prototype._dragStart = function (ev) {
	if (this.dragging) {
		return;
	}
	this.dragging = true;
	var posX;
	var posY;
	if (Calendar.is_ie) {
		posY = window.event.clientY + document.body.scrollTop;
		posX = window.event.clientX + document.body.scrollLeft;
	} else {
		posY = ev.clientY + window.scrollY;
		posX = ev.clientX + window.scrollX;
	}
	var st = this.element.style;
	this.xOffs = posX - parseInt(st.left);
	this.yOffs = posY - parseInt(st.top);
	with (Calendar) {
		addEvent(document, "mousemove", calDragIt);
		addEvent(document, "mouseup", calDragEnd);
	}
};

// BEGIN: DATE OBJECT PATCHES

/** Adds the number of days array to the Date object. */
Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31);

/** Constants used for time computations */
Date.SECOND = 1000 /* milliseconds */;
Date.MINUTE = 60 * Date.SECOND;
Date.HOUR   = 60 * Date.MINUTE;
Date.DAY    = 24 * Date.HOUR;
Date.WEEK   =  7 * Date.DAY;

Date.parseDate = function(str, fmt) {
	var today = new Date();
	var y = 0;
	var m = -1;
	var d = 0;
	var a = str.split(/\W+/);
	var b = fmt.match(/%./g);
	var i = 0, j = 0;
	var hr = 0;
	var min = 0;
	for (i = 0; i < a.length; ++i) {
		if (!a[i])
		continue;
		switch (b[i]) {
			case "%d":
			case "%e":
			d = parseInt(a[i], 10);
			break;

			case "%m":
			m = parseInt(a[i], 10) - 1;
			break;

			case "%Y":
			case "%y":
			y = parseInt(a[i], 10);
			(y < 100) && (y += (y > 29) ? 1900 : 2000);
			break;

			case "%b":
			case "%B":
			for (j = 0; j < 12; ++j) {
				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; }
			}
			break;

			case "%H":
			case "%I":
			case "%k":
			case "%l":
			hr = parseInt(a[i], 10);
			break;

			case "%P":
			case "%p":
			if (/pm/i.test(a[i]) && hr < 12)
			hr += 12;
			else if (/am/i.test(a[i]) && hr >= 12)
			hr -= 12;
			break;

			case "%M":
			min = parseInt(a[i], 10);
			break;
		}
	}
	if (isNaN(y)) y = today.getFullYear();
	if (isNaN(m)) m = today.getMonth();
	if (isNaN(d)) d = today.getDate();
	if (isNaN(hr)) hr = today.getHours();
	if (isNaN(min)) min = today.getMinutes();
	if (y != 0 && m != -1 && d != 0)
	return new Date(y, m, d, hr, min, 0);
	y = 0; m = -1; d = 0;
	for (i = 0; i < a.length; ++i) {
		if (a[i].search(/[a-zA-Z]+/) != -1) {
			var t = -1;
			for (j = 0; j < 12; ++j) {
				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
			}
			if (t != -1) {
				if (m != -1) {
					d = m+1;
				}
				m = t;
			}
		} else if (parseInt(a[i], 10) <= 12 && m == -1) {
			m = a[i]-1;
		} else if (parseInt(a[i], 10) > 31 && y == 0) {
			y = parseInt(a[i], 10);
			(y < 100) && (y += (y > 29) ? 1900 : 2000);
		} else if (d == 0) {
			d = a[i];
		}
	}
	if (y == 0)
	y = today.getFullYear();
	if (m != -1 && d != 0)
	return new Date(y, m, d, hr, min, 0);
	return today;
};

/** Returns the number of days in the current month */
Date.prototype.getMonthDays = function(month) {
	var year = this.getFullYear();
	if (typeof month == "undefined") {
		month = this.getMonth();
	}
	if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) {
		return 29;
	} else {
		return Date._MD[month];
	}
};

/** Returns the number of day in the year. */
Date.prototype.getDayOfYear = function() {
	var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
	var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
	var time = now - then;
	return Math.floor(time / Date.DAY);
};

/** Returns the number of the week in year, as defined in ISO 8601. */
Date.prototype.getWeekNumber = function() {
	var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
	var DoW = d.getDay();
	d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
	var ms = d.valueOf(); // GMT
	d.setMonth(0);
	d.setDate(4); // Thu in Week 1
	return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
};

/** Checks date and time equality */
Date.prototype.equalsTo = function(date) {
	return ((this.getFullYear() == date.getFullYear()) &&
	(this.getMonth() == date.getMonth()) &&
	(this.getDate() == date.getDate()) &&
	(this.getHours() == date.getHours()) &&
	(this.getMinutes() == date.getMinutes()));
};

/** Set only the year, month, date parts (keep existing time) */
Date.prototype.setDateOnly = function(date) {
	var tmp = new Date(date);
	this.setDate(1);
	this.setFullYear(tmp.getFullYear());
	this.setMonth(tmp.getMonth());
	this.setDate(tmp.getDate());
};

/** Prints the date in a string according to the given format. */
Date.prototype.print = function (str) {
	var m = this.getMonth();
	var d = this.getDate();
	var y = this.getFullYear();
	var wn = this.getWeekNumber();
	var w = this.getDay();
	var s = {};
	var hr = this.getHours();
	var pm = (hr >= 12);
	var ir = (pm) ? (hr - 12) : hr;
	var dy = this.getDayOfYear();
	if (ir == 0)
	ir = 12;
	var min = this.getMinutes();
	var sec = this.getSeconds();
	s["%a"] = Calendar._SDN[w]; // abbreviated weekday name [FIXME: I18N]
	s["%A"] = Calendar._DN[w]; // full weekday name
	s["%b"] = Calendar._SMN[m]; // abbreviated month name [FIXME: I18N]
	s["%B"] = Calendar._MN[m]; // full month name
	// FIXME: %c : preferred date and time representation for the current locale
	s["%C"] = 1 + Math.floor(y / 100); // the century number
	s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
	s["%e"] = d; // the day of the month (range 1 to 31)
	// FIXME: %D : american date style: %m/%d/%y
	// FIXME: %E, %F, %G, %g, %h (man strftime)
	s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
	s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
	s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
	s["%k"] = hr;		// hour, range 0 to 23 (24h format)
	s["%l"] = ir;		// hour, range 1 to 12 (12h format)
	s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
	s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
	s["%n"] = "\n";		// a newline character
	s["%p"] = pm ? "PM" : "AM";
	s["%P"] = pm ? "pm" : "am";
	// FIXME: %r : the time in am/pm notation %I:%M:%S %p
	// FIXME: %R : the time in 24-hour notation %H:%M
	s["%s"] = Math.floor(this.getTime() / 1000);
	s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
	s["%t"] = "\t";		// a tab character
	// FIXME: %T : the time in 24-hour notation (%H:%M:%S)
	s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
	s["%u"] = w + 1;	// the day of the week (range 1 to 7, 1 = MON)
	s["%w"] = w;		// the day of the week (range 0 to 6, 0 = SUN)
	// FIXME: %x : preferred date representation for the current locale without the time
	// FIXME: %X : preferred time representation for the current locale without the date
	s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
	s["%Y"] = y;		// year with the century
	s["%%"] = "%";		// a literal '%' character

	var re = /%./g;
	if (!Calendar.is_ie5 && !Calendar.is_khtml)
	return str.replace(re, function (par) { return s[par] || par; });

	var a = str.match(re);
	for (var i = 0; i < a.length; i++) {
		var tmp = s[a[i]];
		if (tmp) {
			re = new RegExp(a[i], 'g');
			str = str.replace(re, tmp);
		}
	}

	return str;
};

if ( !Date.prototype.__msh_oldSetFullYear ) {
	Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;
	Date.prototype.setFullYear = function(y) {
		var d = new Date(this);
		d.__msh_oldSetFullYear(y);
		if (d.getMonth() != this.getMonth())
		this.setDate(28);
		this.__msh_oldSetFullYear(y);
	}
}

// END: DATE OBJECT PATCHES


// global object that remembers the calendar
window._dynarch_popupCalendar = null;


/* FILE: modules/mod_scripts/calender-en.js*/
// ** I18N

// Calendar EN language
// Author: Mihai Bazon, <mihai_bazon@yahoo.com>
// Encoding: any
// Distributed under the same terms as the calendar itself.

// For translators: please use UTF-8 if possible.  We strongly believe that
// Unicode is the answer to a real internationalized world.  Also please
// include your contact information in the header, as can be seen above.

// full day names
Calendar._DN = new Array
("Sunday",
 "Monday",
 "Tuesday",
 "Wednesday",
 "Thursday",
 "Friday",
 "Saturday",
 "Sunday");

// Please note that the following array of short day names (and the same goes
// for short month names, _SMN) isn't absolutely necessary.  We give it here
// for exemplification on how one can customize the short day names, but if
// they are simply the first N letters of the full name you can simply say:
//
//   Calendar._SDN_len = N; // short day name length
//   Calendar._SMN_len = N; // short month name length
//
// If N = 3 then this is not needed either since we assume a value of 3 if not
// present, to be compatible with translation files that were written before
// this feature.

// short day names
Calendar._SDN = new Array
("Sun",
 "Mon",
 "Tue",
 "Wed",
 "Thu",
 "Fri",
 "Sat",
 "Sun");

// First day of the week. "0" means display Sunday first, "1" means display
// Monday first, etc.
Calendar._FD = 0;

// full month names
Calendar._MN = new Array
("January",
 "February",
 "March",
 "April",
 "May",
 "June",
 "July",
 "August",
 "September",
 "October",
 "November",
 "December");

// short month names
Calendar._SMN = new Array
("Jan",
 "Feb",
 "Mar",
 "Apr",
 "May",
 "Jun",
 "Jul",
 "Aug",
 "Sep",
 "Oct",
 "Nov",
 "Dec");

// tooltips
Calendar._TT = {};
Calendar._TT["INFO"] = "About the calendar";

Calendar._TT["ABOUT"] =
"DHTML Date/Time Selector\n" +
"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-)
"For latest version visit: http://www.dynarch.com/projects/calendar/\n" +
"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details." +
"\n\n" +
"Date selection:\n" +
"- Use the \xab, \xbb buttons to select year\n" +
"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" +
"- Hold mouse button on any of the above buttons for faster selection.";
Calendar._TT["ABOUT_TIME"] = "\n\n" +
"Time selection:\n" +
"- Click on any of the time parts to increase it\n" +
"- or Shift-click to decrease it\n" +
"- or click and drag for faster selection.";

Calendar._TT["PREV_YEAR"] = "Prev. year";
Calendar._TT["PREV_MONTH"] = "Prev. month";
Calendar._TT["GO_TODAY"] = "Go Today";
Calendar._TT["NEXT_MONTH"] = "Next month";
Calendar._TT["NEXT_YEAR"] = "Next year";
Calendar._TT["SEL_DATE"] = "&nbsp;";
Calendar._TT["DRAG_TO_MOVE"] = "Drag to move";
Calendar._TT["PART_TODAY"] = " (today)";

// the following is to inform that "%s" is to be the first day of week
// %s will be replaced with the day name.
Calendar._TT["DAY_FIRST"] = "Display %s first";

// This may be locale-dependent.  It specifies the week-end days, as an array
// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1
// means Monday, etc.
Calendar._TT["WEEKEND"] = "0,6";

Calendar._TT["CLOSE"] = "Close";
Calendar._TT["TODAY"] = "Today";
Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value";

// date formats
Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d";
Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e";

Calendar._TT["WK"] = "wk";
Calendar._TT["TIME"] = "Time:";


/* FILE: modules/mod_scripts/calender-setup.js*/
/*  Copyright Mihai Bazon, 2002, 2003  |  http://dynarch.com/mishoo/
 * ---------------------------------------------------------------------------
 *
 * The DHTML Calendar
 *
 * Details and latest version at:
 * http://dynarch.com/mishoo/calendar.epl
 *
 * This script is distributed under the GNU Lesser General Public License.
 * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
 *
 * This file defines helper functions for setting up the calendar.  They are
 * intended to help non-programmers get a working calendar on their site
 * quickly.  This script should not be seen as part of the calendar.  It just
 * shows you what one can do with the calendar, while in the same time
 * providing a quick and simple method for setting it up.  If you need
 * exhaustive customization of the calendar creation process feel free to
 * modify this code to suit your needs (this is recommended and much better
 * than modifying calendar.js itself).
 */

// $Id: calender-setup.js,v 1.2 2007/07/10 09:05:52 chogori Exp $

/**
 *  This function "patches" an input field (or other element) to use a calendar
 *  widget for date selection.
 *
 *  The "params" is a single object that can have the following properties:
 *
 *    prop. name   | description
 *  -------------------------------------------------------------------------------------------------
 *   inputField    | the ID of an input field to store the date
 *   displayArea   | the ID of a DIV or other element to show the date
 *   button        | ID of a button or other element that will trigger the calendar
 *   eventName     | event that will trigger the calendar, without the "on" prefix (default: "click")
 *   ifFormat      | date format that will be stored in the input field
 *   daFormat      | the date format that will be used to display the date in displayArea
 *   singleClick   | (true/false) wether the calendar is in single click mode or not (default: true)
 *   firstDay      | numeric: 0 to 6.  "0" means display Sunday first, "1" means display Monday first, etc.
 *   align         | alignment (default: "Br"); if you don't know what's this see the calendar documentation
 *   range         | array with 2 elements.  Default: [1900, 2999] -- the range of years available
 *   weekNumbers   | (true/false) if it's true (default) the calendar will display week numbers
 *   flat          | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID
 *   flatCallback  | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar)
 *   disableFunc   | function that receives a JS Date object and should return true if that date has to be disabled in the calendar
 *   onSelect      | function that gets called when a date is selected.  You don't _have_ to supply this (the default is generally okay)
 *   onClose       | function that gets called when the calendar is closed.  [default]
 *   onUpdate      | function that gets called after the date is updated in the input field.  Receives a reference to the calendar.
 *   date          | the date that the calendar will be initially displayed to
 *   showsTime     | default: false; if true the calendar will include a time selector
 *   timeFormat    | the time format; can be "12" or "24", default is "12"
 *   electric      | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close
 *   step          | configures the step of the years in drop-down boxes; default: 2
 *   position      | configures the calendar absolute position; default: null
 *   cache         | if "true" (but default: "false") it will reuse the same calendar object, where possible
 *   showOthers    | if "true" (but default: "false") it will show days from other months too
 *
 *  None of them is required, they all have default values.  However, if you
 *  pass none of "inputField", "displayArea" or "button" you'll get a warning
 *  saying "nothing to setup".
 */
Calendar.setup = function (params) {
	function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

	param_default("inputField",     null);
	param_default("displayArea",    null);
	param_default("button",         null);
	param_default("eventName",      "click");
	param_default("ifFormat",       "%Y/%m/%d");
	param_default("daFormat",       "%Y/%m/%d");
	param_default("singleClick",    true);
	param_default("disableFunc",    null);
	param_default("dateStatusFunc", params["disableFunc"]);	// takes precedence if both are defined
	param_default("dateText",       null);
	param_default("firstDay",       null);
	param_default("align",          "Br");
	param_default("range",          [1900, 2999]);
	param_default("weekNumbers",    true);
	param_default("flat",           null);
	param_default("flatCallback",   null);
	param_default("onSelect",       null);
	param_default("onClose",        null);
	param_default("onUpdate",       null);
	param_default("date",           null);
	param_default("showsTime",      false);
	param_default("timeFormat",     "24");
	param_default("electric",       true);
	param_default("step",           2);
	param_default("position",       null);
	param_default("cache",          false);
	param_default("showOthers",     false);
	param_default("multiple",       null);

	var tmp = ["inputField", "displayArea", "button"];
	for (var i in tmp) {
		if (typeof params[tmp[i]] == "string") {
			params[tmp[i]] = document.getElementById(params[tmp[i]]);
		}
	}
	if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) {
		alert("Calendar.setup:\n  Nothing to setup (no fields found).  Please check your code");
		return false;
	}

	function onSelect(cal) {
		var p = cal.params;
		var update = (cal.dateClicked || p.electric);
		if (update && p.inputField) {
			p.inputField.value = cal.date.print(p.ifFormat);
			if (typeof p.inputField.onchange == "function")
				p.inputField.onchange();
		}
		if (update && p.displayArea)
			p.displayArea.innerHTML = cal.date.print(p.daFormat);
		if (update && typeof p.onUpdate == "function")
			p.onUpdate(cal);
		if (update && p.flat) {
			if (typeof p.flatCallback == "function")
				p.flatCallback(cal);
		}
		if (update && p.singleClick && cal.dateClicked)
			cal.callCloseHandler();
	};

	if (params.flat != null) {
		if (typeof params.flat == "string")
			params.flat = document.getElementById(params.flat);
		if (!params.flat) {
			alert("Calendar.setup:\n  Flat specified but can't find parent.");
			return false;
		}
		var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect);
		cal.showsOtherMonths = params.showOthers;
		cal.showsTime = params.showsTime;
		cal.time24 = (params.timeFormat == "24");
		cal.params = params;
		cal.weekNumbers = params.weekNumbers;
		cal.setRange(params.range[0], params.range[1]);
		cal.setDateStatusHandler(params.dateStatusFunc);
		cal.getDateText = params.dateText;
		if (params.ifFormat) {
			cal.setDateFormat(params.ifFormat);
		}
		if (params.inputField && typeof params.inputField.value == "string") {
			cal.parseDate(params.inputField.value);
		}
		cal.create(params.flat);
		cal.show();
		return false;
	}

	var triggerEl = params.button || params.displayArea || params.inputField;
	triggerEl["on" + params.eventName] = function() {
		var dateEl = params.inputField || params.displayArea;
		var dateFmt = params.inputField ? params.ifFormat : params.daFormat;
		var mustCreate = false;
		var cal = window.calendar;
		if (dateEl)
			params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt);
		if (!(cal && params.cache)) {
			window.calendar = cal = new Calendar(params.firstDay,
							     params.date,
							     params.onSelect || onSelect,
							     params.onClose || function(cal) { cal.hide(); });
			cal.showsTime = params.showsTime;
			cal.time24 = (params.timeFormat == "24");
			cal.weekNumbers = params.weekNumbers;
			mustCreate = true;
		} else {
			if (params.date)
				cal.setDate(params.date);
			cal.hide();
		}
		if (params.multiple) {
			cal.multiple = {};
			for (var i = params.multiple.length; --i >= 0;) {
				var d = params.multiple[i];
				var ds = d.print("%Y%m%d");
				cal.multiple[ds] = d;
			}
		}
		cal.showsOtherMonths = params.showOthers;
		cal.yearStep = params.step;
		cal.setRange(params.range[0], params.range[1]);
		cal.params = params;
		cal.setDateStatusHandler(params.dateStatusFunc);
		cal.getDateText = params.dateText;
		cal.setDateFormat(dateFmt);
		if (mustCreate)
			cal.create();
		cal.refresh();
		if (!params.position)
			cal.showAtElement(params.button || params.displayArea || params.inputField, params.align);
		else
			cal.showAt(params.position[0], params.position[1]);
		return false;
	};

	return cal;
};


/* FILE: modules/mod_scripts/calender-load.js*/
/* Callback function for on-select of a date in the calendar */
function selectHandler(calendar, date) {
   if(calendar == null || !calendar.dateClicked) {
       return;
   }

   calendar.sel.value = date;
   if(calendar.sel.onchange) {
       calendar.sel.onchange();
   }

   calendar.hide();

   if ((document.getElementById("pickup_time")) && (document.getElementById("dropoff_time")))
       calcDaysDifference();
}

/* Callback function for on-close of the calendar */
function closeHandler(calendar) {
   if(calendar == null) {
       return;
   }

   calendar.destroy();
   calendar == null;
}

function showCalendarById(id) {
   var elem = document.getElementById(id + "_date");
   var button = document.getElementById(id + "_button");   
   showCalendar(elem, button);
}

function showCalendar(elem, button) {
   if(calendar != null) {
       calendar.destroy();
       calendar = null;
   }

   if(elem == null) {
       alert("The supplied input field cannot be found");
       return;
   }
   if(elem == null) {
       alert("The supplied button cannot be found");
       return;
   }

   var calendar = new Calendar(true, null, selectHandler, closeHandler);
   calendar.setDateFormat("%d-%m-%Y");
   calendar.sel = elem;
   calendar.create();
   calendar.setDate(getDateFromElement(elem));

   calendar.showAtElement(button, "BR");
}

function getDateFromElement(elem) {
   var date = new Date();
   if(elem.value != null) {
       var pieces = elem.value.split("-");
       if(pieces != null && pieces.length == 3) {
           date.setFullYear(pieces[2]);
           date.setMonth(pieces[1] - 1);
           date.setDate(pieces[0]);
       }
   }

   return date;
}


var dayMs = 1000 * 60 * 60 * 24;

//calculate the difference in the pickup & dropoff dates on the step_location view
function calcDaysDifference() {
      //extract the values from the date objects

   //**pickup datetime section
       var pickUpDate = document.getElementById("pickup_date");           var pickUpTime = document.getElementById("pickup_time");

       //extract the date contents off the format dd-mm-yyyy
   var yearElem = pickUpDate.value.substring(pickUpDate.value.lastIndexOf("-") + 1);
   var monthElem = (pickUpDate.value.substring(pickUpDate.value.indexOf("-") + 1, pickUpDate.value.indexOf("-", pickUpDate.value.indexOf("-") + 1))) - 1;
   var dayElem = pickUpDate.value.substring(0, pickUpDate.value.indexOf("-"));
   var hourElem = pickUpTime.value.substring(0, pickUpTime.value.indexOf(":"));
   var minElem = pickUpTime.value.substring(pickUpTime.value.lastIndexOf(":") + 1);

       //create a new date off the extracted date values
       var startdate = new Date(0);
   startdate.setFullYear(yearElem);
   startdate.setMonth(monthElem);
   startdate.setDate(dayElem);
   startdate.setHours(hourElem);
   startdate.setMinutes(minElem);

   //**drop off datetime section
   var dropOffDate = document.getElementById("dropoff_date");
       var dropOffTime = document.getElementById("dropoff_time");
          //extract the date contents off the format dd-mm-yyyy
   yearElem = dropOffDate.value.substring(dropOffDate.value.lastIndexOf("-") + 1);
   monthElem = (dropOffDate.value.substring(dropOffDate.value.indexOf("-") + 1, dropOffDate.value.indexOf("-", dropOffDate.value.indexOf("-") + 1))) - 1;
   dayElem = dropOffDate.value.substring(0, dropOffDate.value.indexOf("-"));
   hourElem = dropOffTime.value.substring(0, dropOffTime.value.indexOf(":"));
   minElem = dropOffTime.value.substring(dropOffTime.value.lastIndexOf(":") + 1);

   //create a new date off the extracted date values
       var enddate = new Date(0);
       enddate.setFullYear(yearElem);
   enddate.setMonth(monthElem);
   enddate.setDate(dayElem);
   enddate.setHours(hourElem);
   enddate.setMinutes(minElem);

   //get the difference in days between the two dates
       var diff = calcdays(startdate, enddate);

       //if negative days are returned, set the dropoff date = pickupdate + 7days
       if(diff < 0) {

           var timeDiff = 1000 * 60 * 60 * 24 * 7;

           enddate.setTime(startdate.getTime() + timeDiff);

           var strEndDate = enddate.getDate() +"-"+ (enddate.getMonth() + 1) +"-"+ enddate.getFullYear();

           dropOffDate.value = strEndDate;

           //set the number of days
       document.getElementById("numberOfDays").value = calcdays(startdate, enddate);                      }

   else {
           //set the number of days
           document.getElementById("numberOfDays").value = diff;
   }
}

//calculate the difference between the two dates
function calcdays(start, end) {
       var diff = end.getTime() - start.getTime();
       var msPday = 1000 * 60 * 60 * 24;
       diff = (diff / msPday) + (diff % msPday > 0 ? 1 : 0);

       return Math.floor(diff);
}







/* FILE: modules/mod_scripts/validation.js*/
// If no SAST date was set, default to the clients date. This prevents things from breaking
if(!sastDate) {
    var sastDate = new Date();
}

var msPday = 1000 * 60 * 60 * 24;

var initialDaysDiff = 3;

//////////////////////////
//CREDIT CARD VALIDATION//
//////////////////////////
function CreditCardValidation(card_number,return_field){
    var validator = new MOD10Validator();
    var type = validator.getCardInfo(card_number);
    if(type == null) {
        return "invalid";
    } else {

        var cardTypeElem = getElement('selectCardType');

        var cardType = new Array();
        cardType[0] = new Array("MC","MASTERCARD","Mastercard");
        cardType[1] = new Array("VI","VISA","Visa");
        cardType[2] = new Array("AX","AMEX","American Express");
        cardType[3] = new Array("DN","DINERS","Diners Club");

        return_field.value
        for(var i = 0; i < cardType.length; i ++){
            if (cardType[i][0] == return_field.value){
                if(type.type == cardType[i][1]){
                    return "valid";
                }
            }
        }
        return "invalid_type";
    }
}

function MOD10Validator() {
    // Card type class used to store card info
    function CardType(prefix, length, type) {
        this.prefix = prefix;
        this.length = length;
        this.type = type;
    }

    this.cardTypes = new Array();

    this.register = function(type, prefix, length) {
        this.cardTypes.push(new CardType(prefix, length, type));
    }

    // register known card types
    this.register('MASTERCARD', '51', 16);
    this.register('MASTERCARD', '52', 16);
    this.register('MASTERCARD', '53', 16);
    this.register('MASTERCARD', '54', 16);
    this.register('MASTERCARD', '55', 16);
    this.register('VISA', '4', 13);
    this.register('VISA', '4', 16);
    this.register('AMEX', '34', 15);
    this.register('AMEX', '37', 15);
    this.register('DINERS', '300', 14);
    this.register('DINERS', '301', 14);
    this.register('DINERS', '302', 14);
    this.register('DINERS', '303', 14);
    this.register('DINERS', '304', 14);
    this.register('DINERS', '305', 14);
    this.register('DINERS', '36', 14);
    this.register('DINERS', '38', 14);
    this.register('DISCOVERY', '6011', 16);

    // Check LUHN formula against number
    this.isMOD10 = function(number) {
        number = new String(number);
        var total = 0;

        var even = false;
        for(var i = number.length - 1; i >= 0; i--) {
            var n = parseInt(number.charAt(i),10);

            if(even) {
                var d = n * 2;
                total += (d % 10) + Math.floor(d / 10);
            } else {
                total += n;
            }

            even = !even;
        }

        return total % 10 == 0;
    }

    // Loops registered types, doing comparisons. Returns null on an invalid number.
    this.getCardInfo = function(number) {
        number = new String(number);

        var info = null;
        var check = /^\d+$/;
        if(check.test(number)) {
            for(var i = 0; i < this.cardTypes.length; i++) {
                var type = this.cardTypes[i];
                if(type.length != number.length) {
                    continue;
                }

                if(number.indexOf(type.prefix) != 0) {
                    continue;
                }

                if(this.isMOD10(number)) {
                    info = type;
                    break;
                }
            }

        }

        return info;
    }
}


//////////////////////
//GENERAL VALIDATION//
//////////////////////

function validateModify(field1,field2){
    var msg = "Please enter the following:";
    var inv = false;
    if(field1 == "" || field1 == " "){
        msg += "\n- Reference number";
        inv = true;
    }
    if(field2 == "" || field2 == " "){
        msg += "\n- Email address used to place the booking";
        inv = true;
    }

    if(inv){
        alert(msg);
        return false;
    }else{
        return true;
    }
}

function regexMatch(string, regex) {
    var match = string.match(regex);
    if(match == null) {
        return false;
    }
    return match == null ? false : match[0] == string;
}

function trim(string) {
    return string.replace(/^\s*(.*?)\s*$/, '$1');
}

function charTrap(regex, evt) {
    if(evt){
        var ch = evt.which ? evt.which : (window.event == null ? 13 : window.event.keyCode);
        if(ch == 8 || ch == 13) { // 8: bspace, 13: enter
            return true;
        }

        var char = String.fromCharCode(ch);

        return regexMatch(char, new RegExp(regex));
    }else{
        return;
    }

}


function validateUserInfo(elements){
    var msgs = new Array();

    //if using direct bill then no need to check for credit card details

    if(!elements['chkDirectBill'] || !elements['chkDirectBill'].checked){

        if(CreditCardValidation(elements['txtCardNumber'].value,elements['selectCardType']) == "invalid_type"){
            msgs.push("Invalid credit card type");
        }

        if(CreditCardValidation(elements['txtCardNumber'].value,elements['selectCardType']) == "invalid"){
            msgs.push("Invalid credit card number");
        }

        if (elements['txtCardCVV'].value.length != 4 && elements['selectCardType'].value == "AX"){
            msgs.push("CVV for American Express should be 4 characters");
        }

        if (elements['txtCardCVV'].value.length != 3 && elements['selectCardType'].value != "AX"){
            msgs.push("Invalid CVV");
        }
    }

    if (elements['txtFirstName'].value == ""){
        msgs.push("No first name entered");
    }

    if (elements['txtSurname'].value == ""){
        msgs.push("No surname entered");
    }

    if (elements['txtTelephone'].value == ""){
        msgs.push("Telephone number blank");
    }

    //if (inStr(elements['txtEmail'].value,"@") > 0 && inStr(elements['txtEmail'].value,".") > 0){
    //	msgs.push("Invalid email address");
    //}
    if (elements['txtTelephone'].value == ""){
        msgs.push("E-mail address blank");
//    }else if (!(/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(elements['txtEmail'].value))){
    }else if (!(/[^@]+@[^.]+\..*/.test(elements['txtEmail'].value))){
    msgs.push("Invalid e-mail address");
}

if (elements['txtAddressLine1'].value == ""){
    msgs.push("Invalid address line 1");
}

if (elements['txtAddressCity'].value == ""){
    msgs.push("Invalid address city");
}

if (elements['txtAddressCountry'].value == ""){
    msgs.push("Blank country");
}

if (elements['txtIdNumber'].value == ""){
    msgs.push("Please enter a passport / id number");
}
/*			GILHAMS DATE CHECKER			*/
var curdate = getSASTDate();
var year = curdate.getYear();
var mnth = curdate.getMonth();

if (parseInt(elements['txtCardExpiryYear'].value) == (parseInt(year)-100) && parseInt(elements['txtCardExpiryMonth'].value) < (parseInt(mnth)+1)){
    msgs.push("Your credit card has expired");
}

//if (elements[''].value == ){
//	msgs.push("");
//}*/

return showMessages("Please enter the following values:", msgs);
}

function is_valid_date_format(dateString,fmt){
    var match;

    switch(fmt){
        case "dd-mm-yyyy":
        match = dateString.toString().match(/^((3[0-1])|(0?[1-9])|([1-2][0-9]))-((0?[1-9])|(1[0-2]))-(20[0-9]{2})$/);
        break;
    }
    if(match != null){
        return true;
    }else{
        return false;
    }

}
function validateProteaSearch(elements,feature){
    var msgs = new Array();

    //make sure there's no search excuted for more than 15 hotels seeing that this takes too long and times out
    if(elements['selectHotels']) {
        if(elements['selectHotels'].length > 15 && elements['selectHotels'].value == ""){
            msgs.push("Please refine your search*");
        }
    }

    //if checkin date is selected
    if(elements['checkin_date'].value == "Check In" || elements['checkin_date'].value == ""){
        msgs.push("Please select a valid checkin date");
    }else if(!is_valid_date_format(elements['checkin_date'].value,'dd-mm-yyyy')){
        msgs.push("Checkin date format is invalid, should be 'dd-mm-yyyy'");
    }
    else{
        var check_in = createDate(elements['checkin_date'].value);
        if(check_in == null){
            msgs.push("Invalid checkin date");
        }
    }

    if(elements['checkout_date'].value == "Check Out" || elements['checkout_date'].value == ""){
        msgs.push("Please select a checkout date");
    }else if(!is_valid_date_format(elements['checkout_date'].value,'dd-mm-yyyy')){
        msgs.push("Checkout date format is invalid, should be 'dd-mm-yyyy'");
    }
    else{
        var check_out = createDate(elements['checkout_date'].value);
        if(check_out == null){
            msgs.push("Invalid checkout date");
        }
    }

    //if both dates are correct then
    if(check_in != null && check_out != null){
        var checkInBeforeOut = true;
        if(!dateMatch(elements['checkin_date'].value)){
            msgs.push("Invalid checkin date");
            checkInBeforeOut = false;
            alert("inv in date");
        }

        if(!dateMatch(elements['checkout_date'].value)){
            msgs.push("Invalid checkout date");
            checkInBeforeOut = false;
            alert("inv out date");
        }

        if(checkInBeforeOut){
            if(!isDateBefore(check_out, check_in)){
                msgs.push("Checkout date can not be before checkin date");
            }
            var tmp_days = diffdays(elements['checkin_date'].value,elements['checkout_date'].value,"convert");
            if(tmp_days == 0){
                msgs.push("Checkin and checkout date cannot be the same");
            }else if(tmp_days == null){
                msgs.push("something");
            }
        }
    }

    if(elements['selectRooms'].value < 1 || trim(elements['selectRooms'].value) == "Rooms"){
        msgs.push("Amount of rooms cannot be zero");
    }else if(elements['selectRooms'].value > 4){
        msgs.push("Amount of rooms cannot exceed 4");
    }else if(isNaN(elements['selectRooms'].value)){
        msgs.push("Amount of rooms needs to be a valid number from 1 to 4");
    }

    if(elements['selectAdults'].value < 1 || trim(elements['selectAdults'].value) == "Adults"){
        msgs.push("Must have at least one adult");
    }else if(elements['selectAdults'].value > 20){
        msgs.push("Amount of adults cannot exceed 20");
    }else if(isNaN(elements['selectAdults'].value)){
        msgs.push("Amount of adults needs to be a valid number from 1 to 20");
    }

    if(elements['selectKids'].value == ""){
        elements['selectKids'].value = 0;
    }else if(elements['selectKids'].value > 20){
        msgs.push("Amount of children cannot exceed 20");
    }else if(isNaN(elements['selectKids'].value)){
        msgs.push("Amount of children needs to be a valid number from 1 to 20");
    }

    var submitting = showMessages("Please enter the following values:", msgs);
    if(submitting){
        showProgressBar(feature);
        return true;
    }
    return false;
}


function showMessages(title, msgs) {
    if(msgs.length > 0) {
        var msg = title;
        for(var i = 0; i < msgs.length; i++) {
            msg += "\n  * " + msgs[i];
        }
        alert(msg);
        return false;
    }

    return true;
}

//////////////////
//DATE FUNCTIONS//
//////////////////
function ensureTwoDigits(num1){
    //ensure that a number is prefixed by a zero if only one digit
    var num = ""+num1;
    if(num.length == 1){
        num = "0"+num;
    }
    return num;
}

function dateAfter(strDate1_yy,strDate1_mm,strDate1_dd,strDate2_yy,strDate2_mm,strDate2_dd){
    //today first

    var intDate1 = parseInt(""+strDate1_yy+ensureTwoDigits(strDate1_mm)+ensureTwoDigits(strDate1_dd),10);
    var intDate2 = parseInt(""+strDate2_yy+ensureTwoDigits(strDate2_mm)+ensureTwoDigits(strDate2_dd),10);

    if(intDate1 > intDate2){

        return false;
    }else{
        return true;
    }
}

function dateChangeOrder(the_date){
    the_date = the_date.substr(0,10);
    var rate_yy = the_date.substr(0,4);
    var rate_mm = the_date.substr(5,2);
    var rate_dd = the_date.substr(8,2);
    the_date = rate_dd+"-"+rate_mm+"-"+rate_yy;
    return the_date;
}

function dateSame(strDate1_yy,strDate1_mm,strDate1_dd,strDate2_yy,strDate2_mm,strDate2_dd){
    var year = "";
    var month = "";
    var day = "";

    year = bigger_smaller_equal(strDate1_yy,strDate2_yy);
    month = bigger_smaller_equal(strDate1_mm,strDate2_mm);
    day = bigger_smaller_equal(strDate1_dd,strDate2_dd);

    if(year == "equal" && month == "equal" && day == "equal"){
        return true;
    }
    else{
        return false;
    }
}

function checkValidCheckin(check_in,check_out,number_nights){
    var msg1 = "Checkout date must be after checkin date";
    var msg2 = "You cannot book in past ";
    var msg3 = "Warning: Please note that Check In date was after the Check Out date and that the Check Out date has been pushed forward.";

    var todayDate = getSASTDate();

    var checkinDate = createDate(check_in.value);
    var checkoutDate = createDate(check_out.value);

    if(checkinDate == null) {
        return;
    }

    if(todayDate.getTime() > checkinDate.getTime()) {
        alert(msg2);

        check_in.value = 'Check In';

        updateDaysDiff(check_in.value, check_out.value, number_nights);

        return;
    }

    if(checkoutDate == null) {
        checkoutDate = dateAddDays(checkinDate, initialDaysDiff);
        check_out.value = createDateString(checkoutDate);
    }

    if(checkoutDate.getTime() <= checkinDate.getTime()) {
        alert(msg3);

        check_out.value = createDateString(dateAddDays(checkinDate, initialDaysDiff));
    }

    updateDaysDiff(check_in.value, check_out.value, number_nights);
}



function checkValidCheckout(check_in,check_out,number_nights){
    var msg = 'Your checkout date must be after your checkin date';

    var checkinDate = createDate(check_in.value);
    var checkoutDate = createDate(check_out.value);

    if(checkinDate == null) {
        updateDaysDiff(check_in.value, check_out.value, number_nights);
        return;
    }

    if(checkoutDate.getTime() <= checkinDate.getTime()) {
        alert(msg);

        check_out.value = 'Check Out';

        updateDaysDiff(check_in.value, check_out.value, number_nights);

        return;
    }

    updateDaysDiff(check_in.value, check_out.value, number_nights);

}

function bigger_smaller_equal(val1,val2){
    if(val1 > val2){
        return "bigger";
    }else if(val1 < val2){
        return "smaller";
    }else{
        return "equal";
    }

}

function updateCheckout(check_in,check_out){
    if(check_out.value == "Check Out" && check_in.value != "Check In"){
        //change here to change the number of days that are added automatically

        var addDays = defaultAddDays;

        var dd = check_in.value.substr(0,2);
        var mm = check_in.value.substr(3,2);
        var yyyy = check_in.value.substr(6,4);

        //months are one less in java
        mm = mm - 1;

        var myDate=new Date();

        //initialize the date with the selected date
        myDate.setFullYear(yyyy);
        myDate.setMonth(mm);
        myDate.setDate(dd);

        //add the days
        myDate.setDate(myDate.getDate()+addDays)

        dd = myDate.getDate();
        mm = myDate.getMonth();
        mm = mm + 1;
        yyyy = myDate.getFullYear();

        if(myDate.getDate() < 10){
            dd = "0" + dd;
        }

        if(myDate.getMonth() < 9){
            mm = "0" + mm;
        }
        check_out.value =  dd + "-" + mm + "-" + yyyy;
    }
}

function numberNightsUpdate(date_in,date_out){
    if(date_in != "Check In" && date_out != "Check Out"){
        var diff = diffdays(date_in,date_out,"convert")
        var nights_text;
        if(diff > 0){
            if(diff == 1){
                nights_text = " night";
            }else{
                nights_text = " nights";
            }
            return diff + nights_text;
        }
    }
    return "*Number of nights";
}

function createDate(dateString) {
    var date = dateString;
    if(dateString.indexOf("-") == -1){
        dateString = date[0]+date[1]+"-"+date[2]+date[3]+"-"+date[4]+date[5]+date[6]+date[7];
    }

    //										D        A          Y       -    M  O  N  T  H   -  Y E A R
    //christoff interpret				30/31	|	01-9  |   10 & 20s  -   01-9   |  10-12	 - 2000 - 2099
    var match = dateString.match(/^((3[0-1])|(0?[1-9])|([1-2][0-9]))-((0?[1-9])|(1[0-2]))-(20[0-9]{2})$/);

    if(match == null) {
        return null;
    }

    var year = new Number(match[8]);
    var month = new Number(match[5]) - 1;
    var day = new Number(match[1]);

    var date = new Date();
    date.setDate(1); // needed to prevent the rolling of months towards the end of some months...
    date.setFullYear(year);
    date.setMonth(month);
    date.setDate(day);
    date.setHours(0);
    date.setMinutes(0);
    date.setSeconds(0);

    // Make sure input string is actually valid... i.e. not entering 31 days in feb, causing rollover months.
    if(date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) {
        return null;
    }

    return date;
}

function isDateBefore(check_in, check_out) {
    return (check_in.getTime() - check_out.getTime()) > 0;
}

function dateMatch(date) {
    return createDate(date) != null;
}

//calculate the difference between the two dates
function diffdays(in_date, out_date, modify) {
    var check_in;
    var check_out;
    if(modify == "convert"){
        //must be in format dd-mm-yyyy
        check_in = createDate(in_date);
        check_out = createDate(out_date);
    }else{
        check_in = in_date;
        check_out = out_date;
    }

    if(check_in == null || check_out == null){
        return null;
    }
    var diff = check_out.getTime() - check_in.getTime();

    diff = (diff / msPday);

    return Math.floor(diff);
}

function unixToHuman(unixTimeStamp) {
    var theDate = new Date(unixTimeStamp * 1000);
    dateString = theDate.toGMTString();
    arrDateStr = dateString.split(" ");
    var mm = getMonthNum(arrDateStr[2]);
    var dd = arrDateStr[1];
    var yy = arrDateStr[3];
    var hour = arrDateStr[4].substr(0,2);
    var min = arrDateStr[4].substr(3,2);
    var sec = arrDateStr[4].substr(6,2);

    var date = new Date();
    date.setFullYear(yy);
    date.setMonth(mm);
    date.setDate(dd);
    var dd = date.getDate()+1;

    var myDate = new Date();
    myDate.setFullYear(yy);
    myDate.setMonth(mm);
    myDate.setDate(dd);

    dd = myDate.getDate();
    mm = getMonthName(myDate.getMonth());
    yy = myDate.getFullYear();

    if(dd < 9){
        dd = "0"+dd;
    }

    var fmt_date = dd+"-"+mm+"-"+yy;
    return fmt_date;
}

function getMonthNum(abbMonth) {
    var arrMon = new Array("Jan","Feb","Mar","Apr","May","Jun",
    "Jul","Aug","Sep","Oct","Nov","Dec");
    for(i=0; i<arrMon.length; i++)
    {
        if(abbMonth == arrMon[i])
        return i+1;
    }
}
function getMonthName(numMonth) {
    var arrMon = new Array("Jan","Feb","Mar","Apr","May","Jun",
    "Jul","Aug","Sep","Oct","Nov","Dec");
    for(i=0; i<arrMon.length; i++)
    {
        if(numMonth == (i+1))
        return arrMon[i];
    }
}












/* New stuffs */
function calcDaysDiff(from, to) {
    var fromDate = createDate(from);
    var toDate = createDate(to);

    if(fromDate == null || toDate == null) return null;

    return Math.floor((toDate.getTime() - fromDate.getTime()) / msPday);
}

function updateDaysDiff(from, to, daysElem) {
    var diff = calcDaysDiff(from, to);
    if(diff == null) diff = -1;

    if(diff <= 0) {
        daysElem.value = 'Number of Nights';
    } else if (diff == 1) {
        daysElem.value = '1 Night';
    } else {
        daysElem.value = diff + ' Nights';
    }
}

function dateAddDays(date, days) {
    var newDate = new Date();
    newDate.setTime(date.getTime());
    newDate.setDate(newDate.getDate() + days);

    return newDate;
}

function createDateString(date) {
    return padLeft(date.getDate(), 2, '0') + '-' + padLeft(date.getMonth() + 1, 2, '0') + '-' + date.getFullYear();
}

function padLeft(str, amount, ch) {
    str = new String(str);

    while(str.length < amount) {
        str = ch + str;
    }

    return str;
}

function getSASTDate() {
    var date = new Date();
    date.setTime(sastDate.getTime());

    return date;
}

/* FILE: templates/ja_sargas/ja_transmenu/ja-transmenu.js*/
/* =================================================================================================
 * TransMenu 
 * March, 2003
 *
 * Customizable multi-level animated DHTML menus with transparency.
 *
 * Copyright 2003-2004, Aaron Boodman (www.youngpup.net)
 * =================================================================================================
 * "Can I use this?"
 * 
 * Use of this library is governed by the Creative Commons Attribution 2.0 License. You can check it 
 * out at: http://creativecommons.org/licenses/by/2.0/
 *
 * Basically: You may copy, distribute, and eat this code as you wish. But you must give me credit 
 * for writing it. You may not misrepresent yourself as the author of this code.
 * =================================================================================================
 * "It's kinda hard to read, though"
 *
 * The uncompressed, commented version of this script can be found at: 
 * http://youngpup.net/projects/transMenus
 * =================================================================================================
 * updates:
 * 04.19.04 fixed cascade problem with menus nested greater than two levels.
 * 12.23.03 added hideCurrent for menu actuators with no menus. renamed to TransMenu.
 * 04.18.03	fixed render bug in IE 5.0 Mac by removing that browser from compatibility table ;)
 *			also made gecko check a little more strict by specifying build no.
 * ============================================================================================== */



//==================================================================================================
// Configuration properties
//==================================================================================================
//==================================================================================================
TransMenu.spacerGif = "img/x.gif";                     // path to a transparent spacer gif
TransMenu.dingbatOn = "img/arrowchild-on.gif";            // path to the active sub menu dingbat
TransMenu.dingbatOff = "img/arrowchild-off.gif";          // path to the inactive sub menu dingbat
TransMenu.dingbatSize = 8;                            // size of the dingbat (square shape assumed)
TransMenu.menuPadding = 0;                             // padding between menu border and items grid
TransMenu.itemPadding = 5;                             // additional padding around each item
TransMenu.shadowSize = 2;                              // size of shadow under menu
TransMenu.shadowOffset = 3;                            // distance shadow should be offset from leading edge
TransMenu.shadowColor = "#362582";                        // color of shadow (transparency is set in CSS)
TransMenu.shadowPng = "img/grey-40.png";               // a PNG graphic to serve as the shadow for mac IE5
TransMenu.backgroundColor = "#000000";                   // color of the background (transparency set in CSS)2B98B7
//TransMenu.backgroundPng = "moreBtn.png";          // a PNG graphic to server as the background for mac IE5
TransMenu.hideDelay = 1500;                            // number of milliseconds to wait before hiding a menu
TransMenu.slideTime = 200;                             // number of milliseconds it takes to open and close a menu
TransMenu.subpad_x = 0;								   // Horizontal Padding between top right corner of item menu and its submenu (level > 2)
TransMenu.subpad_y = -2;							   // Vertical Padding between top right corner of item menu and its submenu (level > 2)

//==================================================================================================
// Internal use properties
//==================================================================================================
TransMenu.reference = {topLeft:1,topRight:2,bottomLeft:3,bottomRight:4};
TransMenu.direction = {down:1,right:2};
TransMenu.registry = [];
TransMenu._maxZ = 100;

TransMenu.updateImgPath = function (imgPath){
	TransMenu.spacerGif = imgPath + TransMenu.spacerGif;
	TransMenu.dingbatOn = imgPath + TransMenu.dingbatOn;
	TransMenu.dingbatOff = imgPath + TransMenu.dingbatOff;
	TransMenu.shadowPng = imgPath + TransMenu.shadowPng;
	TransMenu.backgroundPng = imgPath + TransMenu.backgroundPng;
}

//==================================================================================================
// Static methods
//==================================================================================================
// supporting win ie5+, mac ie5.1+ and gecko >= mozilla 1.0
TransMenu.isSupported = function() {
        var ua = navigator.userAgent.toLowerCase();
		var pf = navigator.platform.toLowerCase();
        var an = navigator.appName;
        var r = false;

        if (ua.indexOf("gecko") > -1 && navigator.productSub >= 20020605) r = true; // gecko >= moz 1.0
        else if (an == "Microsoft Internet Explorer") {
                if (document.getElementById) { // ie5.1+ mac,win
                        if (pf.indexOf("mac") == 0) {
							r = /msie (\d(.\d*)?)/.test(ua) && Number(RegExp.$1) >= 5.1;
						}
						else r = true;
                }
        }

        return r;
}

// call this in onload once menus have been created
TransMenu.initialize = function() {
        for (var i = 0, menu = null; menu = this.registry[i]; i++) {
                menu.initialize();
        }
}

// call this in document body to write out menu html
TransMenu.renderAll = function() {
        var aMenuHtml = [];
        for (var i = 0, menu = null; menu = this.registry[i]; i++) {
                aMenuHtml[i] = menu.toString();
        }
        document.write(aMenuHtml.join(""));
}

//==================================================================================================
// TransMenu constructor (only called internally)
//==================================================================================================
// oActuator            : The thing that causes the menu to be shown when it is mousedover. Either a
//                        reference to an HTML element, or a TransMenuItem from an existing menu.
// iDirection           : The direction to slide out. One of TransMenu.direction.
// iLeft                : Left pixel offset of menu from actuator
// iTop                 : Top pixel offset of menu from actuator
// iReferencePoint      : Corner of actuator to measure from. One of TransMenu.referencePoint.
// parentMenuSet        : Menuset this menu will be added to.
//==================================================================================================
function TransMenu(oActuator, iDirection, iLeft, iTop, iReferencePoint, parentMenuSet) {
        // public methods
        this.addItem = addItem;
        this.addMenu = addMenu;
        this.toString = toString;
        this.initialize = initialize;
        this.isOpen = false;
        this.show = show;
        this.hide = hide;
        this.items = [];

        // events
        this.onactivate = new Function();       // when the menu starts to slide open
        this.ondeactivate = new Function();     // when the menu finishes sliding closed
        this.onmouseover = new Function();      // when the menu has been moused over
        this.onqueue = new Function();          // hack .. when the menu sets a timer to be closed a little while in the future
		this.ondequeue = new Function();

        // initialization
        this.index = TransMenu.registry.length;
        TransMenu.registry[this.index] = this;

        var id = "TransMenu" + this.index;
        var contentHeight = null;
        var contentWidth = null;
        var childMenuSet = null;
        var animating = false;
        var childMenus = [];
        var slideAccel = -1;
        var elmCache = null;
        var ready = false;
        var _this = this;
        var a = null;

        var pos = iDirection == TransMenu.direction.down ? "top" : "left";
        var dim = null;

        // private and public method implimentations
        function addItem(sText, sUrl, browserNav, active) {
                var item = new TransMenuItem(sText, sUrl, this, browserNav, active);
                item._index = this.items.length;
                this.items[item._index] = item;
        }

        function addMenu(oMenuItem) {
                if (!oMenuItem.parentMenu == this) throw new Error("Cannot add a menu here");

                if (childMenuSet == null) childMenuSet = new TransMenuSet(TransMenu.direction.right, TransMenu.subpad_x, TransMenu.subpad_y, TransMenu.reference.topRight);

                var m = childMenuSet.addMenu(oMenuItem);

                childMenus[oMenuItem._index] = m;
                m.onmouseover = child_mouseover;
                m.ondeactivate = child_deactivate;
                m.onqueue = child_queue;
				m.ondequeue = child_dequeue;

                return m;
        }

        function initialize() {
                initCache();
                initEvents();
                initSize();
                ready = true;
        }

        function show() {
                //dbg_dump("show");
                if (ready) {
                        _this.isOpen = true;
                        animating = true;
                        setContainerPos();
                        elmCache["clip"].style.visibility = "visible";
                        elmCache["clip"].style.zIndex = TransMenu._maxZ++;
                        //dbg_dump("maxZ: " + TransMenu._maxZ);
                        slideStart();
                        _this.onactivate();
                }
        }

        function hide() {
                if (ready) {
                        _this.isOpen = false;
                        animating = true;

                        for (var i = 0, item = null; item = elmCache.item[i]; i++) 
                                dehighlight(item);

                        if (childMenuSet) childMenuSet.hide();

                        slideStart();
                        _this.ondeactivate();
                        
                        if (!oActuator.parentMenu) {
                        	oActuator.className = oActuator.className.replace(/ jahover-active/, '');
                        	oActuator.className = oActuator.className.replace(/ jahover/, '');
                        }
                }
        }

        function setContainerPos() {
                var sub = oActuator.constructor == TransMenuItem; 
                var act = sub ? oActuator.parentMenu.elmCache["item"][oActuator._index] : oActuator; 
                var el = act;
                
                var x = 0;
                var y = 0;

                
                var minX = 0;
                var maxX = (window.innerWidth ? window.innerWidth : document.body.clientWidth) - parseInt(elmCache["clip"].style.width);
                var minY = 0;
                var maxY = (window.innerHeight ? window.innerHeight : document.body.clientHeight) - parseInt(elmCache["clip"].style.height);
				maxX = 10000;
				maxY = 10000;

                // add up all offsets... subtract any scroll offset
                while (sub ? el.parentNode.className.indexOf("transMenu") == -1 : el.offsetParent) {
                        x += el.offsetLeft;
                        y += el.offsetTop;

                        if (el.scrollLeft) x -= el.scrollLeft;
                        if (el.scrollTop) y -= el.scrollTop;
                        
                        el = el.offsetParent;
                }

                if (oActuator.constructor == TransMenuItem) {
                        x += parseInt(el.parentNode.style.left);
                        y += parseInt(el.parentNode.style.top);
                }

                switch (iReferencePoint) {
                        case TransMenu.reference.topLeft:
                                break;
                        case TransMenu.reference.topRight:
                                x += act.offsetWidth;
                                break;
                        case TransMenu.reference.bottomLeft:
                                y += act.offsetHeight;
                                break;
                        case TransMenu.reference.bottomRight:
                                x += act.offsetWidth;
                                y += act.offsetHeight;
                                break;
                }

                x += iLeft;
                y += iTop;

                x = Math.max(Math.min(x, maxX), minX);
                y = Math.max(Math.min(y, maxY), minY);

                elmCache["clip"].style.left = x + "px";
                elmCache["clip"].style.top = y + "px";
        }

        function slideStart() {
                var x0 = parseInt(elmCache["content"].style[pos]);
                var x1 = _this.isOpen ? 0 : -dim;

                if (a != null) a.stop();
                a = new Accelimation(x0, x1, TransMenu.slideTime, slideAccel);

                a.onframe = slideFrame;
                a.onend = slideEnd;

                a.start();
        }

        function slideFrame(x) {
                elmCache["content"].style[pos] = x + "px";
        }

        function slideEnd() {
                if (!_this.isOpen) elmCache["clip"].style.visibility = "hidden";
                animating = false;
        }

        function initSize() {
                // everything is based off the size of the items table...
                var ow = elmCache["items"].offsetWidth;
                var oh = elmCache["items"].offsetHeight;
                var ua = navigator.userAgent.toLowerCase();

                // clipping container should be ow/oh + the size of the shadow
                elmCache["clip"].style.width = ow + TransMenu.shadowSize +  2 + "px";
                elmCache["clip"].style.height = oh + TransMenu.shadowSize + 2 + "px";

                // same with content...
                elmCache["content"].style.width = ow + TransMenu.shadowSize + "px";
                elmCache["content"].style.height = oh + TransMenu.shadowSize + "px";

                contentHeight = oh + TransMenu.shadowSize;
                contentWidth = ow + TransMenu.shadowSize;
                
                dim = iDirection == TransMenu.direction.down ? contentHeight : contentWidth;

                // set initially closed
                elmCache["content"].style[pos] = -dim - TransMenu.shadowSize + "px";
                elmCache["clip"].style.visibility = "hidden";

                // if *not* mac/ie 5
                if (ua.indexOf("mac") == -1 || ua.indexOf("gecko") > -1) {
                        // set background div to offset size
                        elmCache["background"].style.width = ow + "px";
                        elmCache["background"].style.height = oh + "px";
                        elmCache["background"].style.backgroundColor = TransMenu.backgroundColor;

                        // shadow left starts at offset left and is offsetHeight pixels high
                        elmCache["shadowRight"].style.left = ow + "px";
                        elmCache["shadowRight"].style.height = oh - (TransMenu.shadowOffset - TransMenu.shadowSize) + "px";
                        elmCache["shadowRight"].style.backgroundColor = TransMenu.shadowColor;

                        // shadow bottom starts at offset height and is offsetWidth - shadowOffset 
                        // pixels wide (we don't want the bottom and right shadows to overlap or we 
                        // get an extra bright bottom-right corner)
                        elmCache["shadowBottom"].style.top = oh + "px";
                        elmCache["shadowBottom"].style.width = ow - TransMenu.shadowOffset + "px";
                        elmCache["shadowBottom"].style.backgroundColor = TransMenu.shadowColor;
                }
                // mac ie is a little different because we use a PNG for the transparency
                else {
                        // set background div to offset size
                        elmCache["background"].firstChild.src = TransMenu.backgroundPng;
                        elmCache["background"].firstChild.width = ow;
                        elmCache["background"].firstChild.height = oh;

                        // shadow left starts at offset left and is offsetHeight pixels high
                        elmCache["shadowRight"].firstChild.src = TransMenu.shadowPng;
                        elmCache["shadowRight"].style.left = ow + "px";
                        elmCache["shadowRight"].firstChild.width = TransMenu.shadowSize;
                        elmCache["shadowRight"].firstChild.height = oh - (TransMenu.shadowOffset - TransMenu.shadowSize);

                        // shadow bottom starts at offset height and is offsetWidth - shadowOffset 
                        // pixels wide (we don't want the bottom and right shadows to overlap or we 
                        // get an extra bright bottom-right corner)
                        elmCache["shadowBottom"].firstChild.src = TransMenu.shadowPng;
                        elmCache["shadowBottom"].style.top = oh + "px";
                        elmCache["shadowBottom"].firstChild.height = TransMenu.shadowSize;
                        elmCache["shadowBottom"].firstChild.width = ow - TransMenu.shadowOffset;
                }
        }
        
        function initCache() {
                var menu = document.getElementById(id);
                var all = menu.all ? menu.all : menu.getElementsByTagName("*"); // IE/win doesn't support * syntax, but does have the document.all thing

                elmCache = {};
                elmCache["clip"] = menu;
                elmCache["item"] = [];
                
                for (var i = 0, elm = null; elm = all[i]; i++) {
                        switch (elm.className) {
                                case "items":
                                case "content":
                                case "background":
                                case "shadowRight":
                                case "shadowBottom":
                                        elmCache[elm.className] = elm;
                                        break;
                                case "item":
                                        elm._index = elmCache["item"].length;
                                        elmCache["item"][elm._index] = elm;
                                        break;
                        }
                }

                // hack!
                _this.elmCache = elmCache;
        }

        function initEvents() {
                // hook item mouseover
                for (var i = 0, item = null; item = elmCache.item[i]; i++) {
                        item.onmouseover = item_mouseover;
                        item.onmouseout = item_mouseout;
                        item.onclick = item_click;
                }

                // hook actuation
                if (typeof oActuator.tagName != "undefined") {
                        oActuator.onmouseover = actuator_mouseover;
                        oActuator.onmouseout = actuator_mouseout;
                }

                // hook menu mouseover
                elmCache["content"].onmouseover = content_mouseover;
                elmCache["content"].onmouseout = content_mouseout;
        }

        function highlight(oRow) {
                oRow.className = "item hover";
                if (childMenus[oRow._index]) 
                        oRow.lastChild.firstChild.src = TransMenu.dingbatOn;
        }

        function dehighlight(oRow) {
                oRow.className = "item";
                if (childMenus[oRow._index]) 
                        oRow.lastChild.firstChild.src = TransMenu.dingbatOff;
        }

        function item_mouseover() {
                if (!animating) {
                        highlight(this);

                        if (childMenus[this._index]) 
                                childMenuSet.showMenu(childMenus[this._index]);
                        else if (childMenuSet) childMenuSet.hide();
                }
        }

        function item_mouseout() {
                if (!animating) {
                        if (childMenus[this._index])
                                childMenuSet.hideMenu(childMenus[this._index]);
                        else    // otherwise child_deactivate will do this
                                dehighlight(this);
                }
        }

        function item_click() {
                if (!animating) {
                        if (_this.items[this._index].url) {
							switch (_this.items[this._index].browserNav) {
								// cases are slightly different
								case 1:
								// open in a new window
								window.open(_this.items[this._index].url, '', '');;
									
								break;

								case 2:
								// open in a popup window
								window.open(_this.items[this._index].url, '', 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=780,height=550');;
								break;

								case 3:
								// don't link it
								break;

								default:	// formerly case 2
								// open in parent window
								location.href = _this.items[this._index].url;
								break;
							}
						}
                }
        }

        function actuator_mouseover() {
                parentMenuSet.showMenu(_this);
                if (!oActuator.parentMenu) {
                	if (oActuator.className.indexOf(' jahover') < 0){
                		if (oActuator.className.indexOf('-active') < 0)
                			oActuator.className += ' jahover';
                		else
                			oActuator.className += ' jahover-active';              			
                	}
                }
        }

        function actuator_mouseout() {
                parentMenuSet.hideMenu(_this);
        }

        function content_mouseover() {
                if (!animating) {
                        parentMenuSet.showMenu(_this);
                        _this.onmouseover();
                }
        }

        function content_mouseout() {
                if (!animating) {
                        parentMenuSet.hideMenu(_this);
                }
        }

        function child_mouseover() {
                if (!animating) {
                        parentMenuSet.showMenu(_this);
                }
        }

        function child_deactivate() {
                for (var i = 0; i < childMenus.length; i++) {
                        if (childMenus[i] == this) {
                                dehighlight(elmCache["item"][i]);
                                break;
                        }
                }
        }

        function child_queue() {
                parentMenuSet.hideMenu(_this);
        }

		function child_dequeue() {
				parentMenuSet.showMenu(_this);
		}

        function toString() {
                var aHtml = [];
                var sClassName = "transMenu" + (oActuator.constructor != TransMenuItem ? " top" : "");

                for (var i = 0, item = null; item = this.items[i]; i++) {
                        aHtml[i] = item.toString(childMenus[i]);
                }

                return '<div id="' + id + '" class="' + sClassName + '">' + 
                        '<div class="content"><table summary="." class="items" cellpadding="0" cellspacing="0" border="0">' + 
                        '<tr><td colspan="2"><img src="' + TransMenu.spacerGif + '" width="1" height="' + TransMenu.menuPadding + '"></td></tr>' + 
                        aHtml.join('') + 
                        '<tr><td colspan="2"><img src="' + TransMenu.spacerGif + '" width="1" height="' + TransMenu.menuPadding + '"></td></tr></table>' + 
                        '<div class="shadowBottom"><img src="' + TransMenu.spacerGif + '" width="1" height="1"></div>' + 
                        '<div class="shadowRight"><img src="' + TransMenu.spacerGif + '" width="1" height="1"></div>' + 
		        '<div class="background"><img src="' + TransMenu.spacerGif + '" width="1" height="1"></div>' + 
	                '</div></div>';
        }
}


//==================================================================================================
// TransMenuSet
//==================================================================================================
// iDirection           : The direction to slide out. One of TransMenu.direction.
// iLeft                : Left pixel offset of menus from actuator
// iTop                 : Top pixel offset of menus from actuator
// iReferencePoint      : Corner of actuator to measure from. One of TransMenu.referencePoint.
//==================================================================================================
TransMenuSet.registry = [];

function TransMenuSet(iDirection, iLeft, iTop, iReferencePoint) {
        // public methods
        this.addMenu = addMenu;
        this.showMenu = showMenu;
        this.hideMenu = hideMenu;
        this.hide = hide;
        this.hideCurrent = hideCurrent;

        // initialization
        var menus = [];
        var _this = this;
        var current = null;

        this.index = TransMenuSet.registry.length;
        TransMenuSet.registry[this.index] = this;

        // method implimentations...
        function addMenu(oActuator) {
                var m = new TransMenu(oActuator, iDirection, iLeft, iTop, iReferencePoint, this);
                menus[menus.length] = m;
                return m;
        }

        function showMenu(oMenu) {
                if (oMenu != current) {
                        // close currently open menu
                        if (current != null) hide(current);        

                        // set current menu to this one
                        current = oMenu;

                        // if this menu is closed, open it
                        oMenu.show();
                }
                else {
                        // hide pending calls to close this menu
                        cancelHide(oMenu);
                }
        }

        function hideMenu(oMenu) {
                //dbg_dump("hideMenu a " + oMenu.index);
                if (current == oMenu && oMenu.isOpen) {
                        //dbg_dump("hideMenu b " + oMenu.index);
                        if (!oMenu.hideTimer) scheduleHide(oMenu);
                }
        }

        function scheduleHide(oMenu) {
                //dbg_dump("scheduleHide " + oMenu.index);
                oMenu.onqueue();
                oMenu.hideTimer = window.setTimeout("TransMenuSet.registry[" + _this.index + "].hide(TransMenu.registry[" + oMenu.index + "])", TransMenu.hideDelay);
        }

        function cancelHide(oMenu) {
                //dbg_dump("cancelHide " + oMenu.index);
                if (oMenu.hideTimer) {
						oMenu.ondequeue();
                        window.clearTimeout(oMenu.hideTimer);
                        oMenu.hideTimer = null;
                }
        }

        function hide(oMenu) {   
                if (!oMenu && current) oMenu = current;

                if (oMenu && current == oMenu && oMenu.isOpen) {
                        hideCurrent();
                }
        }

        function hideCurrent() {
				if (null != current) {
					cancelHide(current);
					current.hideTimer = null;
					current.hide();
					current = null;
				}
        }
}

//==================================================================================================
// TransMenuItem (internal)
// represents an item in a dropdown
//==================================================================================================
// sText        : The item display text
// sUrl         : URL to load when the item is clicked
// oParent      : Menu this item is a part of
//==================================================================================================
function TransMenuItem(sText, sUrl, oParent, browserNav, active) {
        this.toString = toString;
        this.text = sText;
        this.url = sUrl;
		this.browserNav = browserNav;
        this.parentMenu = oParent;
		this.active = active;

        function toString(bDingbat) {
                var sDingbat = bDingbat ? TransMenu.dingbatOff : TransMenu.spacerGif;
                var iEdgePadding = TransMenu.itemPadding + TransMenu.menuPadding;
                var sPaddingLeft = "padding:" + TransMenu.itemPadding + "px; padding-left:" + iEdgePadding + "px;"
                var sPaddingRight = "padding:" + TransMenu.itemPadding + "px; padding-right:" + iEdgePadding + "px;"
				var id = active?' id="active" ':'';
					/*return '<tr class="item"'+id+'><td nowrap style="' + sPaddingLeft + sPaddingRight + '"><div style="background: url(' + sDingbat + ') right no-repeat;">' + 
                        sText + '</div></td></tr>';*/
                return '<tr class="item"'+id+'><td nowrap style="' + sPaddingLeft + '">' + 
                        sText + '</td><td width="10" style="' + sPaddingRight + '">' + 
                        '<img src="' + sDingbat + '" width="8" height="8"></td></tr>';
        }
}

//=====================================================================
// Accel[erated] [an]imation object
// change a property of an object over time in an accelerated fashion
//=====================================================================
// obj  : reference to the object whose property you'd like to animate
// prop : property you would like to change eg: "left"
// to   : final value of prop
// time : time the animation should take to run
// zip	: optional. specify the zippiness of the acceleration. pick a 
//		  number between -1 and 1 where -1 is full decelerated, 1 is 
//		  full accelerated, and 0 is linear (no acceleration). default
//		  is 0.
// unit	: optional. specify the units for use with prop. default is 
//		  "px".
//=====================================================================
// bezier functions lifted from the lib_animation.js file in the 
// 13th Parallel API. www.13thparallel.org
//=====================================================================

function Accelimation(from, to, time, zip) {
	if (typeof zip  == "undefined") zip  = 0;
	if (typeof unit == "undefined") unit = "px";

        this.x0         = from;
        this.x1		= to;
	this.dt		= time;
	this.zip	= -zip;
	this.unit	= unit;
	this.timer	= null;
	this.onend	= new Function();
        this.onframe    = new Function();
}



//=====================================================================
// public methods
//=====================================================================

// after you create an accelimation, you call this to start it-a runnin'
Accelimation.prototype.start = function() {
	this.t0 = new Date().getTime();
	this.t1 = this.t0 + this.dt;
	var dx	= this.x1 - this.x0;
	this.c1 = this.x0 + ((1 + this.zip) * dx / 3);
	this.c2 = this.x0 + ((2 + this.zip) * dx / 3);
	Accelimation._add(this);
}

// and if you need to stop it early for some reason...
Accelimation.prototype.stop = function() {
	Accelimation._remove(this);
}



//=====================================================================
// private methods
//=====================================================================

// paints one frame. gets called by Accelimation._paintAll.
Accelimation.prototype._paint = function(time) {
	if (time < this.t1) {
		var elapsed = time - this.t0;
	        this.onframe(Accelimation._getBezier(elapsed/this.dt,this.x0,this.x1,this.c1,this.c2));
        }
	else this._end();
}

// ends the animation
Accelimation.prototype._end = function() {
	Accelimation._remove(this);
        this.onframe(this.x1);
	this.onend();
}




//=====================================================================
// static methods (all private)
//=====================================================================

// add a function to the list of ones to call periodically
Accelimation._add = function(o) {
	var index = this.instances.length;
	this.instances[index] = o;
	// if this is the first one, start the engine
	if (this.instances.length == 1) {
		this.timerID = window.setInterval("Accelimation._paintAll()", this.targetRes);
	}
}

// remove a function from the list
Accelimation._remove = function(o) {
	for (var i = 0; i < this.instances.length; i++) {
		if (o == this.instances[i]) {
			this.instances = this.instances.slice(0,i).concat( this.instances.slice(i+1) );
			break;
		}
	}
	// if that was the last one, stop the engine
	if (this.instances.length == 0) {
		window.clearInterval(this.timerID);
		this.timerID = null;
	}
}

// "engine" - call each function in the list every so often
Accelimation._paintAll = function() {
	var now = new Date().getTime();
	for (var i = 0; i < this.instances.length; i++) {
		this.instances[i]._paint(now);
	}
}


// Bezier functions:
Accelimation._B1 = function(t) { return t*t*t }
Accelimation._B2 = function(t) { return 3*t*t*(1-t) }
Accelimation._B3 = function(t) { return 3*t*(1-t)*(1-t) }
Accelimation._B4 = function(t) { return (1-t)*(1-t)*(1-t) }


//Finds the coordinates of a point at a certain stage through a bezier curve
Accelimation._getBezier = function(percent,startPos,endPos,control1,control2) {
	return endPos * this._B1(percent) + control2 * this._B2(percent) + control1 * this._B3(percent) + startPos * this._B4(percent);
}


//=====================================================================
// static properties
//=====================================================================

Accelimation.instances = [];
Accelimation.targetRes = 10;
Accelimation.timerID = null;


//=====================================================================
// IE win memory cleanup
//=====================================================================

if (window.attachEvent) {
	var cearElementProps = [
		'data',
		'onmouseover',
		'onmouseout',
		'onmousedown',
		'onmouseup',
		'ondblclick',
		'onclick',
		'onselectstart',
		'oncontextmenu'
	];

	window.attachEvent("onunload", function() {
        var el;
        for(var d = document.all.length;d--;){
            el = document.all[d];
            for(var c = cearElementProps.length;c--;){
                el[cearElementProps[c]] = null;
            }
        }
	});
}

