//**************************************************************************
//*
//* Version 1.0  01/01/2006
//* Version 1.1  09/05/2006 - correction of date picker details
//* Version 1.11 28/08/2006 - Array declarations changed to old style (= new Array()) instead of (= [])
//* Version 1.12 28/08/2006 - aum_cbt_check_required_fields rewritten and aum_cbt_check_suggested_fields added
//* Version 1.13 06/09/2006 - aum_cbt_putInOrder constructor and methods added
//* Version 1.14 07/09/2006 - separated out "overlib" block and increased data encapsulation of aum_cbt_putInOrder
//* Version 1.15 25/09/2006 - changed names to cbt.module convention 
//*
//* DOCUMENTATION FOR THE CBT JAVASCRIPT FUNCTION LIBRARY
//*
//* Copyright © 2006 Modulus Pty. Ltd.
//*
//**************************************************************************
//*

var version = '1.15';

//* CBT-Specific Functions
//**************************************************************************
//*
//* These (high-level) functions should be directly useful to CBT developers 
//*
//**************************************************************************
//*

var globalDefaultHeight = 400;
var globalDefaultWidth = 400;
var globalBrowserOS,globalBrowserName;
var globalBrowserVersion = 0;

//////// OBJECT PUTINORDER ///////////
//* function cbt_putInOrder - OOP constructor for put-in-order questions
//***********************************************************************
//* @author prh
//* @version 2006 1.0
//* @param 
//* @return n/a 
//* @exception
//* @method .selectItem(theItem,formID,offset)
//* @method .promote(formID)
//* @method .promotePlus(formID)
//* @method .demote(formID, maxNdx)
//* @method .demotePlus(formID, maxNdx)
//*
//* @example var pio = new cbt_putInOrder();
function cbt_putInOrder()
{
		//class definition
		var dSelectedNdx = 0;
		var dSelectedOffset = 0;
		this.selectItem = selectItem;
		this.promote = promote;
		this.promotePlus = promotePlus;
		this.demote = demote;
		this.demotePlus = demotePlus;
				function selectItem (theItem, formID, offset)
				{
					// selecting an item is easy, but we need to set selectedNdx and selectedOffset as well
					var i = 0;
					var tiName = theItem.name;
					var ndx = 0;
					// step thro' all form elements to find the index of the matching one
					for (var i = 0; i < document.forms[formID].length; i++)
					{
						if (document.forms[formID].elements[i].name == tiName){
							ndx = i;
							// ? break;
						}
					}
					dSelectedNdx = ndx;
					dSelectedOffset = offset;
					theItem.select();
				}
				
				function promote (formID)
				{
					var saveValue = document.forms[formID].elements[dSelectedNdx].value;
					if (dSelectedOffset > 0){
						document.forms[formID].elements[dSelectedNdx].value = document.forms[formID].elements[dSelectedNdx - 1].value;
						document.forms[formID].elements[dSelectedNdx - 1].value = saveValue;
						dSelectedNdx--;
						dSelectedOffset--;
					}
					document.forms[formID].elements[dSelectedNdx].select();
					return false;
				}
				
				function promotePlus (formID)
				{
					var saveValue = document.forms[formID].elements[dSelectedNdx].value;
					var i = 0;
					if (dSelectedOffset > 0){
						for (i = dSelectedNdx; i > (dSelectedNdx - dSelectedOffset); i--)
						{
							document.forms[formID].elements[i].value = document.forms[formID].elements[i-1].value;
						}
						document.forms[formID].elements[dSelectedNdx - dSelectedOffset].value = saveValue;
						dSelectedNdx -= dSelectedOffset;
						dSelectedOffset = 0;
					}
					document.forms[formID].elements[dSelectedNdx].select();
					return false;
				}
				
				function demote  (formID, maxNdx)
				{
					var saveValue = document.forms[formID].elements[dSelectedNdx].value;
					if (dSelectedOffset < maxNdx){
						document.forms[formID].elements[dSelectedNdx].value = document.forms[formID].elements[dSelectedNdx + 1].value;
						document.forms[formID].elements[dSelectedNdx + 1].value = saveValue;
						dSelectedNdx++;
						dSelectedOffset++;
					}
					document.forms[formID].elements[dSelectedNdx].select();
					return false;
				}
				
				function demotePlus  (formID, maxNdx)
				{
					var saveValue = document.forms[formID].elements[dSelectedNdx].value;
					var i = 0;
					if (dSelectedOffset < maxNdx){
						for (i = dSelectedNdx; i < dSelectedNdx + (maxNdx - dSelectedOffset); i++)
						{
							document.forms[formID].elements[i].value = document.forms[formID].elements[i + 1].value;
						}
						document.forms[formID].elements[dSelectedNdx + (maxNdx-dSelectedOffset)].value = saveValue;
						dSelectedNdx += maxNdx - dSelectedOffset;
						dSelectedOffset = maxNdx;
					}
					document.forms[formID].elements[dSelectedNdx].select();
					return false;
				}	
}
///////// END OBJECT PUTINORDER ////////


//* function cbt_previous(pageURL) attempts to load the specified page into the current window
//***************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param pageURL - URL of the page to open
//* @param 
//* @return true if successful, false for failure 
//* @exception
//*
//* @example cbt_previous('prior_page.html');
//* @example cbt_previous('http://somewhere.modulus.com.au/prior_page.html');
function cbt_previous(pageURL)
{
	if ((pageURL != undefined) && (pageURL != ''))
	{
		window.location.href = pageURL;
		return true;
	}
	else
	{
		alert('No previous page exists.');
		return false;
	}
}
//*

//* function cbt_next(pageURL) attempts to load the specified page into the current window
//***********************************************************************
//* @author prh
//* @version 2006 1.0
//* @param pageURL - URL of the page to open
//* @param 
//* @return  true if successful, false for failure 
//* @exception
//*
//* @example cbt_next('next_page.html');
//* @example cbt_next('http://somewhere.modulus.com.au/next_page.html');
function cbt_next(pageURL)
{
 	return cbt_previous(pageURL);
}
//*

//* function cbt_illustrate(imageURL,width,height) creates a new, pop-up window containing the specified image
//**************************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param imageURL - URL of an image to be used as an illustration
//* @param width - [optional] parameter to control the width in pixels of the created window; defaults to globalDefaultWidth
//* @param height - [optional] parameter to control the height in pixels of the created window; defaults to globalDefaultHeight
//* @param 
//* @return 
//* @exception
//*
//* @example cbt_illustrate('images/toolbox.jpg');
//* @example cbt_illustrate('http://somewhere.modulus.com.au/images/toolbox.jpg');
//* @example cbt_illustrate('images/toolbox.jpg',250,150);
function cbt_illustrate(imageURL,width,height)
{
	if (! width)
	{
		width = globalDefaultWidth;
	}
	if (! height)
	{
		height = globalDefaultHeight;
	}	
	var theWnd = window.open('','theWnd','resizable,width=' + width + ', height=' + height);
	if (theWnd != null)
	{
		theWnd.document.writeln('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">');
		theWnd.document.writeln('<HTML><HEAD><TITLE>Illustration</TITLE></HEAD><BODY>');
		theWnd.document.writeln('<DIV ALIGN="CENTER"><A HREF="javascript:self.close();"><IMG SRC="' + imageURL + '" ALT="Click to close" ALIGN="BOTTOM" BORDER="0"><BR><IMG SRC="http://cbt.module.com.au/images/aum_aqua_delete_icon.gif" ALT="Click to close" BORDER="0" VSPACE="5"></A></DIV>');
		theWnd.document.writeln('</BODY></HTML>');
	}
}
//*
		

//* function cbt_information(informationURL,width,height) opens a new window with the specified URL shown
//***********************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param informationURL - URL of document containing information
//* @param width - [optional] parameter to control the width in pixels of the created window; defaults to globalDefaultWidth
//* @param height - [optional] parameter to control the height in pixels of the created window; defaults to globalDefaultHeight
//* @param 
//* @return 
//* @exception
//*
//* @example cbt_information('more_information.html');
//* @example cbt_information('http://somewhere.modulus.com.au/more_information.html');
//* @example cbt_information('more_information.html', 150, 250);
function cbt_information(informationURL,width,height)
{
	if (! width)
	{
		width = globalDefaultWidth;
	}
	if (! height)
	{
		height = globalDefaultHeight;
	}	
	var theWnd = window.open('','theWnd','resizable,width=' + width + ', height=' + height);
	if (theWnd != null)
	{
		theWnd.location.href = informationURL;
	}
}
//*

//* function cbt_getRandomNFromM(n,m) returns a random selection size n from an array size m
//**************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param n
//* @param m
//* @return an array, size n, comprising randomly selected elements from an m sized array
//* @exception
//*
//* @example cbt_getRandomNFromM(n,m) 
function cbt_getRandomNFromM(n,m)
{
	var ary = new Array();
	for (var i = 0; i < m; i++){
		ary[i] = i;
	}
	//Fisher-Yates shuffle
	for (var i = ary.length - 1; i >= 0; i--)
	{
		var j = Math.floor(Math.random() * i);
		if (i != j){
			var save = ary[i];
			ary[i] = ary[j];
			ary[j] = save;
		}
	}
	var subAry = new Array();
	for (var i = 0; i < n; i++){
		subAry[i] = ary[i];
	}
	return subAry;
}
//*


//* function cbt_dateTime(formatStr) returns a string representing the current date and/or time
//**************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param formatStr - [optional] string representing the format required
//* formatStr may include (case is important):
//* c - replaced by date e.g.31/12/2006
//* t - replaced by time e.g. 21:33:59
//* yyyy - replaced by 4-digit year e.g. 2006
//* yy - replaced by 2-digit year e.g. 06
//* mmmm - replaced by full month name e.g. January
//* mmm - replaced by 3-character month name e.g. Jan
//* mm - replaced by leading zero month number e.g. 03
//* m - replaced by month number e.g. 3
//* dddd - replaced by full day name e.g. Monday
//* ddd - replaced by 3-character day name e.g. Mon
//* dd - replaced by leading zero day of month e.g. 09
//* hh - replaced by leading zero hour e.g. 08
//* nn - replaced by leading zero minute e.g. 05
//* ss - replaced by leading zero second e.g. 05
//* ampm - replaced by AM or PM as appropriate
//* "xx/xx" - characters quoted in single or double quotes are displayed as is and do not affect formatting
//*
//* @param 
//* @return				The formatted date/time
//* @exception
//*
//* @example cbt_dateTime();
//* @example cbt_dateTime('dddd, dd/mm/yyyy hh:nn:ss ampm EST');
function cbt_dateTime(formatStr)
{
	var today = new Date();
	var twelveHour = false;
	var year = today.getYear();
	var month = today.getMonth() + 1;
	var day = today.getDate();
	var dow = today.getDay();
	var dowName = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
	var monthName = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
	var hour = today.getHours();
	var minute = today.getMinutes();
	var second = today.getSeconds();
	var ampmStr = 'am';
	var monthStr = String(month);
	var lzMonthStr = monthStr;
	var dayStr = String(day);
	var lzDayStr = dayStr;
	var hourStr = String(hour);
	var lzHourStr = hourStr;
	var minuteStr = String(minute);
	var lzMinuteStr = minuteStr;
	var secondStr = String(second);
	var lzSecondStr = secondStr;
	var pos = 0;
	var len = 0;
	var quote = new Array();
	var quotePos = 0;
	if (hour >= 12) { ampmStr = 'pm'; }
	if (month <= 9) { lzMonthStr = '0' + monthStr; }
	if (hour <=9) { lzHourStr = '0' + hourStr; } 
	if (minute <= 9) { lzMinuteStr = '0' + minuteStr; } 
	if (second <= 9) { lzSecondStr = '0' + secondStr; } 
	if (! formatStr)
	{
		return dowName[dow] + ', ' + monthName[month - 1] + ' ' +  day + ', ' + year + ' ' + hourStr + ':' + minuteStr +':' + secondStr;
	}
	else
	{
		//there may be quoted strings within the string
		pos = formatStr.indexOf('"');
		while (pos >= 0)
		{
			len = formatStr.substring(pos + 1,formatStr.length).indexOf('"');
			if (len >= 0)
			{
				quote[quotePos] = formatStr.substr(pos + 1, len);
				formatStr = formatStr.substring(0, pos) + '##' + quotePos + formatStr.substring(pos + len + 2,formatStr.length);
				quotePos++;
			}
			pos = formatStr.indexOf('"');
		}
		pos = formatStr.indexOf("'");
		while (pos >= 0)
		{
			len = formatStr.substring(pos + 1,formatStr.length).indexOf("'");
			if (len >= 0)
			{
				quote[quotePos] = formatStr.substr(pos + 1, len);
				formatStr = formatStr.substring(0, pos) + '##' + quotePos + formatStr.substring(pos + len + 2,formatStr.length);
				quotePos++;
			}
			pos = formatStr.indexOf("'");
		}
		//determine whether to use 12 or 24 hour clock
		pos = formatStr.indexOf('ampm');
		if (pos >=0)
		{
			twelveHour = true;
			hour = hour % 12;
			hourStr = String(hour);
	   lzHourStr = hourStr;
		}
		//short date format substitution
		pos = formatStr.indexOf('c');
		len = 'c'.length;
		if (pos >= 0)
		{
			formatStr = formatStr.substring(0,pos) + day + '/' + month + '/' + year  + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
		}
		//short time format substitution
		pos = formatStr.indexOf('t');
		len = 't'.length;
		if (pos >= 0)
		{
			formatStr = formatStr.substring(0,pos) + hourStr + ':' + minuteStr + ':' + secondStr  + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
		}		
		//year substitutions
		pos = formatStr.indexOf('yyyy');
		len = 'yyyy'.length;
		if (pos >= 0)
		{
			formatStr = formatStr.substring(0,pos) + year + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
		}
		else
		{
			pos = formatStr.indexOf('yy');
			len = 'yy'.length;
			if (pos >= 0)
			{
				var yearStr = String(year);
				yearStr = yearStr.substring(2,3);
				formatStr = formatStr.substring(0,pos) + year + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
			}
		}
		//month substitutions
		pos = formatStr.indexOf('mmmm');
		len = 'mmmm'.length;
		if (pos >= 0)
		{
			formatStr = formatStr.substring(0,pos) + monthName[month - 1] + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
		}		
		else
		{
			pos = formatStr.indexOf('mmm');
			len = 'mmm'.length;
			if (pos >= 0)
			{
				var monStr = monthName[month - 1];
				monStr = monStr.substring(0,3);
				formatStr = formatStr.substring(0,pos) + monStr + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
			}
			else
			{
				pos = formatStr.indexOf('mm');
				len = 'mm'.length;
				if (pos >= 0)
				{
					formatStr = formatStr.substring(0,pos) + month + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
				}
			}
		}
		//dow and day substitutions
		pos = formatStr.indexOf('dddd');
		len = 'dddd'.length;
		if (pos >= 0)
		{
			formatStr = formatStr.substring(0,pos) + dowName[dow] + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
		}
		else
		{
			pos = formatStr.indexOf('ddd');
			len = 'ddd'.length;
			if (pos >= 0)
			{
				var dStr = dowName[dow];
				dStr = dStr.substring(0,3);
				formatStr = formatStr.substring(0,pos) + dStr + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
			}
		}
		// do we have any dd's left?
		pos = formatStr.indexOf('dd');
		len = 'dd'.length;
		if (pos >= 0)
		{
					formatStr = formatStr.substring(0,pos) + lzDayStr + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));		
		}
		//hour substitutions
		pos = formatStr.indexOf('hh');
		len = 'hh'.length;
		if (pos >= 0)
		{
			formatStr = formatStr.substring(0,pos) + lzHourStr + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
		}
		//minute substitutions
		pos = formatStr.indexOf('nn');
		len = 'nn'.length;
		if (pos >= 0)
		{
			formatStr = formatStr.substring(0,pos) + lzMinuteStr + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
		}
		//second substitutions
		pos = formatStr.indexOf('ss');
		len = 'ss'.length;
		if (pos >= 0)
		{
			formatStr = formatStr.substring(0,pos) + lzSecondStr + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
		}
		//ampm substitution
		pos = formatStr.indexOf('ampm');
		len = 'ampm'.length;
		if (pos >= 0)
		{
			formatStr = formatStr.substring(0,pos) + ampmStr + formatStr.substring(pos + len,(pos + len) + formatStr.length - (pos + len));
		}		
		// undo quoted substitutions
		if (quotePos > 0)
		{
			var step = 0;
			pos = formatStr.indexOf('##' + step);
			while (pos >= 0)
			{
				formatStr = formatStr.substring(0,pos) + quote[step] + formatStr.substring(pos+3,formatStr.length);
				step++;
				pos = formatStr.indexOf('##' + step);
			}
		}
		return formatStr;
	}
}
//*

function checkIt(detect,string)
{
		place = detect.indexOf(string) + 1;
		thestring = string;
		return place;
}

	var detect = navigator.userAgent.toLowerCase();
	var OS,browser,total,thestring;
	var version = 0;

	if (checkIt('konqueror'))
	{
		browser = "Konqueror";
		OS = "Linux";
	}
	else if (checkIt(detect,'safari')) browser = "Safari"
	else if (checkIt(detect,'omniweb')) browser = "OmniWeb"
	else if (checkIt(detect,'opera')) browser = "Opera"
	else if (checkIt(detect,'webtv')) browser = "WebTV";
	else if (checkIt(detect,'icab')) browser = "iCab"
	else if (checkIt(detect,'msie')) browser = "Internet Explorer"
	else if (!checkIt(detect,'compatible'))
	{
		browser = "Netscape Navigator"
		version = detect.charAt(8);
	}
	else browser = "An unknown browser";

	if (!version) version = detect.charAt(place + thestring.length);

	if (!OS)
	{
		if (checkIt(detect,'linux')) OS = "Linux";
		else if (checkIt(detect,'x11')) OS = "Unix";
		else if (checkIt(detect,'mac')) OS = "Mac"
		else if (checkIt(detect,'win')) OS = "Windows"
		else OS = "an unknown operating system";
	}


	globalBrowserVersion = version;
	globalBrowserOS = OS;
	globalBrowserName = browser;

//* function cbt_browserName() returns the name of the user's browser
//********************************************************
//* @author prh
//* @version 2006 1.0
//* @param 
//* @return The browser name as a string
//* @exception
//*
//* @example cbt_browserName();
function cbt_browserName()
{
	return globalBrowserName;
}
//*

//* function cbt_browserVersion() returns the version of the user's browser
//***********************************************************
//* @author prh
//* @version 2006 1.0
//* @param 
//* @return The browser version as a string 
//* @exception
//*
//* @example cbt_browserVersion();
function cbt_browserVersion()
{
	return globalBrowserVersion;
}
//*

//* function cbt_browserOS() returns the name of the user's Operating System
//*************************************************************
//* @author prh
//* @version 2006 1.0
//* @param 
//* @returnThe Operating System name as a string
//* @exception
//*
//* @example cbt_browserOS();
function cbt_browserOS()
{
	return globalBrowserOS;
}
//*

//* function cbt_lastModified() shows the date on which the current HTML file was last modified
//**************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param 
//* @return The date/time last modified as a string
//* @exception
//*
//* @example cbt_lasModified();
function cbt_lastModified()
{
	if (document.lastModified)
	{
		return document.lastModified;
	}
	else
	{
		return cbt_dateTime();
	}
}
//*

//* function cbt_delay() casues a delay in processing
//******************************************
//* @author prh
//* @version 2006 1.0
//* @param ms - number of milliseconds to delay
//* @param 
//* @return true;
//* @exception
//*
//* @example cbt_delay();
function cbt_delay(ms)
{
	var aDate = new Date();
	var newDate = new Date();
	while ((newDate - aDate) < ms)
		newDate = new Date();
	{
	}
	return true;
}
//*

//* function cbt_check_suggested_fields() checks that a supplied list of fields all have entries 
//*************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param frm - the current form (use this)
//* @param list - comma separated list of required input field names
//* @param 
//* @return true if all required fields filled, false otherwise
//* @exception
//*
//* @example OnSubmit = "return cbt_check_required_fields(this,'some_field,some_other');"
function cbt_check_suggested_fields(frm,list)
{
	var ritems = new Array();
	ritems = list.split(',');
	var satisfied = new Array();
	for (i = 0; i < ritems.length; i++){
		satisfied.push(false);
		//alert('analysing: '+ritems[i]);
		for (k = 0; k < frm.length; k++)
		{
			if (frm.elements[k].name == ritems[i]){
				// one of our required elements
				if ((frm.elements[k].type == 'radio') || (frm.elements[k].type == 'checkbox'))
				{
						if (frm.elements[k].checked)
						{
							satisfied[i] = true;
						}
				}
				else 	if ((frm.elements[k].type == 'text') || (frm.elements[k].type == 'hidden') || (frm.elements[k].type == 'password') || (frm.elements[k].type == 'textarea'))
				{
						if (frm.elements[k].value != '')
						{
								satisfied[i] = true;
						}
				}
				else if (frm.elements[k].type == 'select')
				{
						if (frm.elements[k].selectedIndex >= 0)
						{
							satisfied[i] = true;
						}
				}
				else if ((frm.elements[k].type == 'reset') || (frm.elements[k].type == 'submit') || (frm.elements[k].type == 'button'))
				{
					satisfied[i] = true;
				}
				else  // other types, hidden etc
				{
						// do nothing but alert the type
						alert('special type of '+frm.elements[k].name+' is:'+frm.elements[k].type);
				}
			}
		}
	}
	for (i=0; i < ritems.length; i++){
		if (! satisfied[i])
		{
			if (confirm('Some questions are left unanswered. Continue submission?'))
			{
				return true;
				break;
			}
			else
			{
					if (frm.elements[ritems[i]].type == 'text')
					{
							frm.elements[ritems[i]].focus();
					}
					return false;
					break;
			}
		}
	}
	return true;
}
//*

//* function cbt_check_required_fields() checks that a supplied list of fields all have entries (before allowing form submission)
//************************************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param frm - the current form (use this)
//* @param list - comma separated list of required input field names
//* @param 
//* @return true if all required fields filled, false otherwise
//* @exception
//*
//* @example OnSubmit = "return cbt_check_required_fields(this,'some_field,some_other');"
function cbt_check_required_fields(frm,list)
{
	var ritems = new Array();
	ritems = list.split(',');
	var satisfied = new Array();
	for (i = 0; i < ritems.length; i++){
		satisfied.push(false);
		//alert('analysing: '+ritems[i]);
		for (k = 0; k < frm.length; k++)
		{
			if (frm.elements[k].name == ritems[i]){
				// one of our required elements
				if ((frm.elements[k].type == 'radio') || (frm.elements[k].type == 'checkbox'))
				{
						if (frm.elements[k].checked)
						{
							satisfied[i] = true;
						}
				}
				else 	if ((frm.elements[k].type == 'text') || (frm.elements[k].type == 'hidden') || (frm.elements[k].type == 'password') || (frm.elements[k].type == 'textarea'))
				{
						if (frm.elements[k].value != '')
						{
								satisfied[i] = true;
						}
				}
				else if (frm.elements[k].type == 'select')
				{
						if (frm.elements[k].selectedIndex >= 0)
						{
							satisfied[i] = true;
						}
				}
				else if ((frm.elements[k].type == 'reset') || (frm.elements[k].type == 'submit') || (frm.elements[k].type == 'button'))
				{
					satisfied[i] = true;
				}
				else  // other types, hidden etc
				{
						// do nothing but alert the type
						alert('special type of '+frm.elements[k].name+' is:'+frm.elements[k].type);
				}
			}
		}
	}
	for (i=0; i < ritems.length; i++){
		if (! satisfied[i])
		{
			alert('Field :"'+ritems[i]+'" is a required item; please supply it and re-submit');
			if (frm.elements[ritems[i]].type == 'text')
			{
					frm.elements[ritems[i]].focus();
			}
			return false;
			break;
		}
	}
	return true;
}
//*


//* function cbt_date_picker() allows interactive selection of a date
//*****************************************************
//* @author prh
//* @version 2006 1.0
//* @param ctrl - the name of the control to which the return value is applied as a string e.g. 'F1.Q8'
//* @param 
//* @return a date in 'DD-MM-YYYY' format
//* @exception
//*
//* @example cbt_date_picker('F_1.Q8');
function cbt_date_picker(ctrl,formatStr)
{
	// DD-MM-YYYY
	show_calendar(ctrl,null,null,formatStr);
}

//* function cbt_image_picker() allows interactive selection of an image from a series of images
//*************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param ctrl - the name of the control to which the return value is applied as a string e.g. 'F1.Q8'
//* @param imageList - comma separated list of image names to include e.g. 'images/circle.gif,images/square.gif'
//* @return the stripped name of the selected image, e.g. 'circle'
//* @exception
//*
//* @example cbt_image_picker('F_1.Q9','images/circle.gif,images/square.gif');
function cbt_image_picker(ctrl,imageList)
{
	var ggWinContent = '';
	var height = 0;
	var width = 0;
	var imageNames = new Array();
	imageNames = imageList.split(',');
	for (i = 0; i < imageNames.length; i++){
		//alert(imageNames[i]);
		var anImage = new Image();
		anImage.src = imageNames[i];
		width += anImage.width;
		height = cbt_greater(height,anImage.height);
		ggWinContent += '<A HREF="javascript:void(0);" onClick="document.' + ctrl + '.value=\'' + cbt_before('.',cbt_after('/',imageNames[i])) + '\'; return cClick();"><IMG SRC="' + imageNames[i] + '" HSPACE="0" VSPACE="0" BORDER="1"></A>';
	}
	width += 12;
	height += 12;
  overlib(ggWinContent, AUTOSTATUSCAP, STICKY, CLOSECLICK, 
			TEXTSIZE, '8pt', CAPTIONSIZE, '8pt', CLOSESIZE, '8pt',
			CAPTION, "Select one of the images.", RELX, 100, RELY, 100, WIDTH,width,HEIGHT,height);			
}

//* function cbt_sound_picker() allows interactive selection of an sound from a series of sounds.
//*************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param ctrl - the name of the control to which the return value is applied as a string e.g. 'F1.Q8'
//* @param soundList - comma separated list of sound names to include e.g. 'sounds/cork.au,sounds/ice.au'
//* @return the stripped name of the selected image, e.g. 'cork'
//* @exception
//*
//* @example cbt_sound_picker('F_1.Q9','sounds/cork.au,sounds/ice.au'); Note that when clicking on the sound to hear it,
//* @example the resultant action depends on how the user's browser and OS are configured.
function cbt_sound_picker(ctrl,soundList)
{
	var ggWinContent = '';
	var height = 0;
	var width = 0;
	var i = 0;
	var row1 = '<TR>';
	var row2 = '<TR>'; 
	var soundNames = new Array();
	soundNames = soundList.split(',');
	ggWinContent = '<TABLE FRAME="VOID" BORDER="2" CELLPADDING="2" CELLSPACING="2" RULES="NONE" WIDTH="100%">';
	for (i=0; i < soundNames.length; i++){
		ggWinContent += '<COL ALIGN="LEFT" VALIGN="TOP">';
	}
	ggWinContent += '<TBODY>';
	for (i = 0; i < soundNames.length; i++){
		row1 += '<TD><A HREF="' + soundNames[i] + '"><IMG SRC="http://cbt.module.com.au/images/js_sounds.gif"></A></TD>';
		row2 += '<TD><A HREF="javascript:void(0);" onClick="document.' + ctrl + '.value=\'' + cbt_before('.',cbt_after('/',soundNames[i])) + '\'; return cClick();">select</A></TD>';
	}
	row1 += '</TR>';
	row2 += '</TR>';
	ggWinContent += row1 + row2 + '</TBODY></TABLE>';
	overlib(ggWinContent, AUTOSTATUSCAP, STICKY, CLOSECLICK, 
			TEXTSIZE, '8pt', CAPTIONSIZE, '8pt', CLOSESIZE, '8pt',
			CAPTION, "Select one of the sounds.", RELX, 100, RELY, 100);
}

<!-- This script and many more are available free online at -->
<!-- The JavaScript Source!! http://javascript.internet.com -->
<!-- Original:  James O'Connor (joconnor@nordenterprises.com) -->
<!-- Web Site:  http://nordenterprises.com -->
<!-- Original:  Kedar R. Bhave (softricks@hotmail.com) -->
<!-- Web Site:  http://www.softricks.com -->
<!-- This script and many more are available free online at -->
<!-- The JavaScript Source!! http://javascript.internet.com -->
<!-- -->
<!-- modifications and customizations to work with the "overLIB" library: -->
<!-- Author:   James B. O'Connor (joconnor@nordenterprises.com) -->
<!-- Web Site: http://www.nordenterprises.com -->
<!-- developed for use with http://home-owners-assoc.com -->
<!-- Note: while overlib works fine with Netscape 4, this function does not work very well, since portions of the "over" div -->
<!--   end up under other fields on the form and cannot be seen.  If you really want to use this with NS4, -->
<!--   you'll need to change the positioning in the overlib() call to make sure the "over" div gets positioned -->
<!--   away from all other form fields -->
<!-- you can get overLIB from: -->
//\  overLIB 3.50  --  This notice must remain untouched at all times.
//\  Copyright Erik Bosrup 1998-2001. All rights reserved.
//\  By Erik Bosrup (erik@bosrup.com).  Last modified 2001-08-28.
//\  Portions by Dan Steinman (dansteinman.com). Additions by other people are
//\  listed on the overLIB homepage.
//\  Get the latest version at http://www.bosrup.com/web/overlib/

var headerBarColor = '#E0E0E0';
var spareDaysFontColor = '#CCCCCC';
var dayHeaderColor = '#669999';
var todayHighlightColor = '#FF0000';
var weekend = new Array(0,6);
var weekendColor = '#E0E0E0';


var olFgColor="#CCCCFF"; //window background
var olFgColor="#E0E0E0"; //window background
var olBgColor="#333399"; //top bar of window
var olTextColor="#000000"; // month, year top header text
var olCapColor="#FFFFFF"; //caption text colour
var olCloseColor="#9999FF"; //"close" control colour

var fontface = "Verdana";
var fontsize = 8;			// in "pt" units; used with "font-size" style element


var gNow = new Date();
var ggWinContent;
var ggPosX = -1;
var ggPosY = -1;

Calendar.Months = new Array("January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December");

// Non-Leap year Month days..
Calendar.DOMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
// Leap year Month days..
Calendar.lDOMonth = new Array(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

function Calendar(p_item, p_month, p_year, p_format) {
	if ((p_month == null) && (p_year == null))	return;

	if (p_month == null) {
		this.gMonthName = null;
		this.gMonth = null;
		this.gYearly = true;
	} else {
		this.gMonthName = Calendar.get_month(p_month);
		this.gMonth = new Number(p_month);
		this.gYearly = false;
	}

	this.gYear = p_year;
	this.gFormat = p_format;
	this.gBGColor = "white";
	this.gFGColor = "black";
	this.gTextColor = "black";
	this.gHeaderColor = "black";
	this.gReturnItem = p_item;
}

Calendar.get_month = Calendar_get_month;
Calendar.get_daysofmonth = Calendar_get_daysofmonth;
Calendar.calc_month_year = Calendar_calc_month_year;

function Calendar_get_month(monthNo) {
	return Calendar.Months[monthNo];
}

function Calendar_get_daysofmonth(monthNo, p_year) {
	/*
	Check for leap year ..
	1.Years evenly divisible by four are normally leap years, except for...
	2.Years also evenly divisible by 100 are not leap years, except for...
	3.Years also evenly divisible by 400 are leap years.
	*/
	if ((p_year % 4) == 0) {
		if ((p_year % 100) == 0 && (p_year % 400) != 0)
			return Calendar.DOMonth[monthNo];

		return Calendar.lDOMonth[monthNo];
	} else
		return Calendar.DOMonth[monthNo];
}

function Calendar_calc_month_year(p_Month, p_Year, incr) {
	/*
	Will return an 1-D array with 1st element being the calculated month
	and second being the calculated year
	after applying the month increment/decrement as specified by 'incr' parameter.
	'incr' will normally have 1/-1 to navigate thru the months.
	*/
	var ret_arr = new Array();

	if (incr == -1) {
		// B A C K W A R D
		if (p_Month == 0) {
			ret_arr[0] = 11;
			ret_arr[1] = parseInt(p_Year) - 1;
		}
		else {
			ret_arr[0] = parseInt(p_Month) - 1;
			ret_arr[1] = parseInt(p_Year);
		}
	} else if (incr == 1) {
		// F O R W A R D
		if (p_Month == 11) {
			ret_arr[0] = 0;
			ret_arr[1] = parseInt(p_Year) + 1;
		}
		else {
			ret_arr[0] = parseInt(p_Month) + 1;
			ret_arr[1] = parseInt(p_Year);
		}
	}

	return ret_arr;
}

function Calendar_calc_month_year(p_Month, p_Year, incr) {
	/*
	Will return an 1-D array with 1st element being the calculated month
	and second being the calculated year
	after applying the month increment/decrement as specified by 'incr' parameter.
	'incr' will normally have 1/-1 to navigate thru the months.
	*/
	var ret_arr = new Array();

	if (incr == -1) {
		// B A C K W A R D
		if (p_Month == 0) {
			ret_arr[0] = 11;
			ret_arr[1] = parseInt(p_Year) - 1;
		}
		else {
			ret_arr[0] = parseInt(p_Month) - 1;
			ret_arr[1] = parseInt(p_Year);
		}
	} else if (incr == 1) {
		// F O R W A R D
		if (p_Month == 11) {
			ret_arr[0] = 0;
			ret_arr[1] = parseInt(p_Year) + 1;
		}
		else {
			ret_arr[0] = parseInt(p_Month) + 1;
			ret_arr[1] = parseInt(p_Year);
		}
	}

	return ret_arr;
}

// This is for compatibility with Navigator 3, we have to create and discard one object before the prototype object exists.
new Calendar();

Calendar.prototype.getMonthlyCalendarCode = function() {
	var vCode = "";
	var vHeader_Code = "";
	var vData_Code = "";

	// Begin Table Drawing code here..
	vCode += ("<div align=center><TABLE BORDER=1 BGCOLOR=\"" + this.gBGColor + "\" style='font-size:" + fontsize + "pt;'>");

	vHeader_Code = this.cal_header();
	vData_Code = this.cal_data();
	vCode += (vHeader_Code + vData_Code);

	vCode += "</TABLE></div>";

	return vCode;
}

Calendar.prototype.show = function() {
	var vCode = "";

	// build content into global var ggWinContent
	ggWinContent += ("<FONT FACE='" + fontface + "' ><B>");
	ggWinContent += (this.gMonthName + " " + this.gYear);
	ggWinContent += "</B><BR>";

	// Show navigation buttons
	var prevMMYYYY = Calendar.calc_month_year(this.gMonth, this.gYear, -1);
	var prevMM = prevMMYYYY[0];
	var prevYYYY = prevMMYYYY[1];

	var nextMMYYYY = Calendar.calc_month_year(this.gMonth, this.gYear, 1);
	var nextMM = nextMMYYYY[0];
	var nextYYYY = nextMMYYYY[1];

	ggWinContent += ("<TABLE WIDTH='100%' BORDER=1 CELLSPACING=0 CELLPADDING=0 BGCOLOR='"+headerBarColor+"' style='font-size:" + fontsize + "pt;'><TR><TD ALIGN=center>");
	ggWinContent += ("[<A HREF=\"javascript:void(0);\" " +
		"onMouseOver=\"window.status='Go back one year'; return true;\" " +
		"onMouseOut=\"window.status=''; return true;\" " +
		"onClick=\"Build(" +
		"'" + this.gReturnItem + "', '" + this.gMonth + "', '" + (parseInt(this.gYear)-1) + "', '" + this.gFormat + "'" +
		");" +
		"\">&lt;&lt;Year<\/A>]</TD><TD ALIGN=center>");
	ggWinContent += ("[<A HREF=\"javascript:void(0);\" " +
		"onMouseOver=\"window.status='Go back one month'; return true;\" " +
		"onMouseOut=\"window.status=''; return true;\" " +
		"onClick=\"Build(" +
		"'" + this.gReturnItem + "', '" + prevMM + "', '" + prevYYYY + "', '" + this.gFormat + "'" +
		");" +
		"\">&lt;Mon<\/A>]</TD><TD ALIGN=center>");
	ggWinContent += "       </TD><TD ALIGN=center>";
	ggWinContent += ("[<A HREF=\"javascript:void(0);\" " +
		"onMouseOver=\"window.status='Go forward one month'; return true;\" " +
		"onMouseOut=\"window.status=''; return true;\" " +
		"onClick=\"Build(" +
		"'" + this.gReturnItem + "', '" + nextMM + "', '" + nextYYYY + "', '" + this.gFormat + "'" +
		");" +
		"\">Mon&gt;<\/A>]</TD><TD ALIGN=center>");
	ggWinContent += ("[<A HREF=\"javascript:void(0);\" " +
		"onMouseOver=\"window.status='Go forward one year'; return true;\" " +
		"onMouseOut=\"window.status=''; return true;\" " +
		"onClick=\"Build(" +
		"'" + this.gReturnItem + "', '" + this.gMonth + "', '" + (parseInt(this.gYear)+1) + "', '" + this.gFormat + "'" +
		");" +
		"\">Year&gt;&gt;<\/A>]</TD></TR></TABLE><BR>");

	// Get the complete calendar code for the month, and add it to the
	//	content var
	vCode = this.getMonthlyCalendarCode();
	ggWinContent += vCode;
}

Calendar.prototype.showY = function() {
	var vCode = "";
	var i;

	ggWinContent += "<FONT FACE='" + fontface + "' ><B>"
	ggWinContent += ("Year : " + this.gYear);
	ggWinContent += "</B><BR>";

	// Show navigation buttons
	var prevYYYY = parseInt(this.gYear) - 1;
	var nextYYYY = parseInt(this.gYear) + 1;

	ggWinContent += ("<TABLE WIDTH='100%' BORDER=1 CELLSPACING=0 CELLPADDING=0 BGCOLOR='"+headerBarColor+"' style='font-size:" + fontsize + "pt;'><TR><TD ALIGN=center>");
	ggWinContent += ("[<A HREF=\"javascript:void(0);\" " +
		"onMouseOver=\"window.status='Go back one year'; return true;\" " +
		"onMouseOut=\"window.status=''; return true;\" " +
		"onClick=\"Build(" +
		"'" + this.gReturnItem + "', null, '" + prevYYYY + "', '" + this.gFormat + "'" +
		");" +
		"\">&lt;&lt;Year<\/A>]</TD><TD ALIGN=center>");
	ggWinContent += "       </TD><TD ALIGN=center>";
	ggWinContent += ("[<A HREF=\"javascript:void(0);\" " +
		"onMouseOver=\"window.status='Go forward one year'; return true;\" " +
		"onMouseOut=\"window.status=''; return true;\" " +
		"onClick=\"Build(" +
		"'" + this.gReturnItem + "', null, '" + nextYYYY + "', '" + this.gFormat + "'" +
		");" +
		"\">Year&gt;&gt;<\/A>]</TD></TR></TABLE><BR>");

	// Get the complete calendar code for each month.
	// start a table and first row in the table
	ggWinContent += ("<TABLE WIDTH='100%' BORDER=0 CELLSPACING=0 CELLPADDING=5 style='font-size:" + fontsize + "pt;'><TR>");
	var j;
	for (i=0; i<12; i++) {
		// start the table cell
		ggWinContent += "<TD ALIGN='center' VALIGN='top'>";
		this.gMonth = i;
		this.gMonthName = Calendar.get_month(this.gMonth);
		vCode = this.getMonthlyCalendarCode();
		ggWinContent += (this.gMonthName + "/" + this.gYear + "<BR>");
		ggWinContent += vCode;
		ggWinContent += "</TD>";
		if (i == 3 || i == 7) {
			ggWinContent += "</TR><TR>";
			}

	}

	ggWinContent += "</TR></TABLE></font><BR>";
}

Calendar.prototype.cal_header = function() {
	var vCode = "";

	vCode = vCode + "<TR>";
	vCode = vCode + "<TD WIDTH='14%'><FONT FACE='" + fontface + "' COLOR='" + this.gHeaderColor + "'><B>Sun</B></FONT></TD>";
	vCode = vCode + "<TD WIDTH='14%'><FONT FACE='" + fontface + "' COLOR='" + this.gHeaderColor + "'><B>Mon</B></FONT></TD>";
	vCode = vCode + "<TD WIDTH='14%'><FONT FACE='" + fontface + "' COLOR='" + this.gHeaderColor + "'><B>Tue</B></FONT></TD>";
	vCode = vCode + "<TD WIDTH='14%'><FONT FACE='" + fontface + "' COLOR='" + this.gHeaderColor + "'><B>Wed</B></FONT></TD>";
	vCode = vCode + "<TD WIDTH='14%'><FONT FACE='" + fontface + "' COLOR='" + this.gHeaderColor + "'><B>Thu</B></FONT></TD>";
	vCode = vCode + "<TD WIDTH='14%'><FONT FACE='" + fontface + "' COLOR='" + this.gHeaderColor + "'><B>Fri</B></FONT></TD>";
	vCode = vCode + "<TD WIDTH='16%'><FONT FACE='" + fontface + "' COLOR='" + this.gHeaderColor + "'><B>Sat</B></FONT></TD>";
	vCode = vCode + "</TR>";

	return vCode;
}

Calendar.prototype.cal_data = function() {
	var vDate = new Date();
	vDate.setDate(1);
	vDate.setMonth(this.gMonth);
	vDate.setFullYear(this.gYear);

	var vFirstDay=vDate.getDay();
	var vDay=1;
	var vLastDay=Calendar.get_daysofmonth(this.gMonth, this.gYear);
	var vOnLastDay=0;
	var vCode = "";

	/*
	Get day for the 1st of the requested month/year..
	Place as many blank cells before the 1st day of the month as necessary.
	*/
	vCode = vCode + "<TR>";
	for (i=0; i<vFirstDay; i++) {
		vCode = vCode + "<TD WIDTH='14%'" + this.write_weekend_string(i) + "><FONT FACE='" + fontface + "'> </FONT></TD>";
	}

	// Write rest of the 1st week
	for (j=vFirstDay; j<7; j++) {
		vCode = vCode + "<TD WIDTH='14%'" + this.write_weekend_string(j) + "><FONT FACE='" + fontface + "'>" +
			"<A HREF='javascript:void(0);' " +
				"onMouseOver=\"window.status='set date to " + this.format_data(vDay) + "'; return true;\" " +
				"onMouseOut=\"window.status=' '; return true;\" " +
				"onClick=\"document." + this.gReturnItem + ".value='" +
				this.format_data(vDay) +
				"';ggPosX=-1;ggPosY=-1;nd();nd();\">" +
				this.format_day(vDay) +
			"</A>" +
			"</FONT></TD>";
		vDay=vDay + 1;
	}
	vCode = vCode + "</TR>";

	// Write the rest of the weeks
	for (k=2; k<7; k++) {
		vCode = vCode + "<TR>";

		for (j=0; j<7; j++) {
												// commented section contains a (pointless) call to window.scroll, which scrolls the main window
			                        /*vCode = vCode + "<TD WIDTH='14%'" + this.write_weekend_string(j) + "><FONT FACE='" + fontface + "'>" +
				                       "<A HREF='javascript:void(0);' " +
												"onMouseOver=\"window.status='set date to " + this.format_data(vDay) + "'; return true;\" " +
												"onMouseOut=\"window.status=' '; return true;\" " +
												"onClick=\"document." + this.gReturnItem + ".value='" +
												this.format_data(vDay) +
												"';window.scroll(0,ggPosY);ggPosX=-1;ggPosY=-1;nd();nd();\">" +
												this.format_day(vDay) +
												"</A>" +
												"</FONT></TD>"; */
			vCode = vCode + "<TD WIDTH='14%'" + this.write_weekend_string(j) + "><FONT FACE='" + fontface + "'>" +
				"<A HREF='javascript:void(0);' " +
					"onMouseOver=\"window.status='set date to " + this.format_data(vDay) + "'; return true;\" " +
					"onMouseOut=\"window.status=' '; return true;\" " +
					"onClick=\"document." + this.gReturnItem + ".value='" +
					this.format_data(vDay) +
					"';ggPosX=-1;ggPosY=-1;nd();nd();\">" +
				this.format_day(vDay) +
				"</A>" +
				"</FONT></TD>";				
			vDay=vDay + 1;

			if (vDay > vLastDay) {
				vOnLastDay = 1;
				break;
			}
		}

		if (j == 6)
			vCode = vCode + "</TR>";
		if (vOnLastDay == 1)
			break;
	}

	// Fill up the rest of last week with proper blanks, so that we get proper square blocks
	for (m=1; m<(7-j); m++) {
		if (this.gYearly)
			vCode = vCode + "<TD WIDTH='14%'" + this.write_weekend_string(j+m) +
			"><FONT FACE='" + fontface + "' COLOR='"+spareDaysFontColor+"'> </FONT></TD>";
		else
			vCode = vCode + "<TD WIDTH='14%'" + this.write_weekend_string(j+m) +
			"><FONT FACE='" + fontface + "' COLOR='"+spareDaysFontColor+"'>" + m + "</FONT></TD>";
	}

	return vCode;
}

Calendar.prototype.format_day = function(vday) {
	var vNowDay = gNow.getDate();
	var vNowMonth = gNow.getMonth();
	var vNowYear = gNow.getFullYear();

	if (vday == vNowDay && this.gMonth == vNowMonth && this.gYear == vNowYear)
		return ("<FONT COLOR='"+ todayHighlightColor +"'><B>" + vday + "</B></FONT>");
	else
		return (vday);
}

Calendar.prototype.write_weekend_string = function(vday) {
	var i;

	// Return special formatting for the weekend day.
	for (i=0; i<weekend.length; i++) {
		if (vday == weekend[i])
			return (" BGCOLOR=\"" + weekendColor + "\"");
	}

	return "";
}

Calendar.prototype.format_data = function(p_day) {
	var vData;
	var vMonth = 1 + this.gMonth;
	vMonth = (vMonth.toString().length < 2) ? "0" + vMonth : vMonth;
	var vMon = Calendar.get_month(this.gMonth).substr(0,3).toUpperCase();
	var vFMon = Calendar.get_month(this.gMonth).toUpperCase();
	var vY4 = new String(this.gYear);
	var vY2 = new String(this.gYear.substr(2,2));
	var vDD = (p_day.toString().length < 2) ? "0" + p_day : p_day;

	switch (this.gFormat) {
		case "MM\/DD\/YYYY" :
			vData = vMonth + "\/" + vDD + "\/" + vY4;
			break;
		case "MM\/DD\/YY" :
			vData = vMonth + "\/" + vDD + "\/" + vY2;
			break;
		case "YYYY\/MM\/DD" :
			vData = vY4 + "\/" + vMonth + "\/" + vDD;
			break;	
		case "MM-DD-YYYY" :
			vData = vMonth + "-" + vDD + "-" + vY4;
			break;
		case "YYYY-MM-DD" :
			vData = vY4 + "-" + vMonth + "-" + vDD;
			break;
		case "MM-DD-YY" :
			vData = vMonth + "-" + vDD + "-" + vY2;
			break;
		case "DD\/MON\/YYYY" :
			vData = vDD + "\/" + vMon + "\/" + vY4;
			break;
		case "DD\/MON\/YY" :
			vData = vDD + "\/" + vMon + "\/" + vY2;
			break;
		case "DD-MON-YYYY" :
			vData = vDD + "-" + vMon + "-" + vY4;
			break;
		case "DD-MON-YY" :
			vData = vDD + "-" + vMon + "-" + vY2;
			break;
		case "DD\/MONTH\/YYYY" :
			vData = vDD + "\/" + vFMon + "\/" + vY4;
			break;
		case "DD\/MONTH\/YY" :
			vData = vDD + "\/" + vFMon + "\/" + vY2;
			break;
		case "DD-MONTH-YYYY" :
			vData = vDD + "-" + vFMon + "-" + vY4;
			break;
		case "DD-MONTH-YY" :
			vData = vDD + "-" + vFMon + "-" + vY2;
			break;
		case "DD\/MM\/YYYY" :
			vData = vDD + "\/" + vMonth + "\/" + vY4;
			break;
		case "DD\/MM\/YY" :
			vData = vDD + "\/" + vMonth + "\/" + vY2;
			break;
		case "DD-MM-YYYY" :
			vData = vDD + "-" + vMonth + "-" + vY4;
			break;
		case "DD-MM-YY" :
			vData = vDD + "-" + vMonth + "-" + vY2;
			break;
		default :
			vData = vMonth + "\/" + vDD + "\/" + vY4;
	}

	return vData;
}

function Build(p_item, p_month, p_year, p_format) {
	gCal = new Calendar(p_item, p_month, p_year, p_format);

	// Customize your Calendar here..
	gCal.gBGColor="white";
	gCal.gLinkColor="black";
	gCal.gTextColor="black";
	gCal.gHeaderColor=dayHeaderColor;

	// initialize the content string
	ggWinContent = "";

	// Choose appropriate show function
	if (gCal.gYearly) {
		// and, since the yearly calendar is so large, override the positioning and fontsize
		// warning: in IE6, it appears that "select" fields on the form will still show
		//	through the "over" div; Note: you can set these variables as part of the onClick
		//	javascript code before you call the show_yearly_calendar function
		if (ggPosX == -1) ggPosX = 10;
		if (ggPosY == -1) ggPosY = 10;
		if (fontsize == 8) fontsize = 6;
		// generate the calendar
		gCal.showY();
		}
	else {
		gCal.show();
		}

	// if this is the first calendar popup, use autopositioning with an offset
	if (ggPosX == -1 && ggPosY == -1) {
		//alert(ggWinContent);
		overlib(ggWinContent, AUTOSTATUSCAP, STICKY, CLOSECLICK,
			TEXTSIZE, '8pt', CAPTIONSIZE, '8pt', CLOSESIZE, '8pt',
			CAPTION, "Select a date", OFFSETX, 20, OFFSETY, -20);
		// save where the 'over' div ended up; we want to stay in the same place if the user
		//	clicks on one of the year or month navigation links
		if ( (ns4) || (ie4) ) {
		        ggPosX = parseInt(over.left);
		        ggPosY = parseInt(over.top);
			} else if (ns6) {
			ggPosX = parseInt(over.style.left);
			ggPosY = parseInt(over.style.top);
			} else { // default for other browsers
			ggPosX = parseInt(over.style.left);
			ggPosY = parseInt(over.style.top);
			}
		}
	else {
		// we have a saved X & Y position, so use those with the FIXX and FIXY options
		overlib(ggWinContent, AUTOSTATUSCAP, STICKY, CLOSECLICK, 
			TEXTSIZE, '8pt', CAPTIONSIZE, '8pt', CLOSESIZE, '8pt',
			CAPTION, "Select a date", RELX, ggPosX, RELY, ggPosY);
		}
	window.scroll(ggPosX, ggPosY);
}

function show_calendar() {
	/*
		p_item	: Return Item.
		p_month : 0-11 for Jan-Dec; 12 for All Months.
		p_year	: 4-digit year
		p_format: Date format (mm/dd/yyyy, dd/mm/yy, ...)
	*/

	p_item = arguments[0];
	if (arguments[1] == null)
		p_month = new String(gNow.getMonth());
	else
		p_month = arguments[1];
	if (arguments[2] == "" || arguments[2] == null)
		p_year = new String(gNow.getFullYear().toString());
	else
		p_year = arguments[2];
	if (arguments[3] == null)
		p_format = "YYYY-MM-DD";
	else
		p_format = arguments[3];

	Build(p_item, p_month, p_year, p_format);
}

/*
Yearly Calendar Code Starts here
*/
function show_yearly_calendar() {
	// Load the defaults..
	//if (p_year == null || p_year == "")
	//	p_year = new String(gNow.getFullYear().toString());
	//if (p_format == null || p_format == "")
	//	p_format = "YYYY-MM-DD";

	p_item = arguments[0];
	if (arguments[1] == "" || arguments[1] == null)
		p_year = new String(gNow.getFullYear().toString());
	else
		p_year = arguments[1];
	if (arguments[2] == null)
		p_format = "YYYY-MM-DD";
	else
		p_format = arguments[2];

	Build(p_item, null, p_year, p_format);
}


//*
//* General & Generic Library functions
//**************************************************************************
//*
//* These functions are low-level functions, typically used by higher-level functions but which might 
//* be useful to a CBT developer in occassional circumstances.
//*
//**************************************************************************

//* function cbt_before(token,str) returns that part of str before token
//********************************************************
//* @author prh
//* @version 2006 1.0
//* @param token - a string to search for
//* @param str a string to search in
//* @return that part of str before the token
//* @exception
//*
//* @example cbt_before('/','images/circle.gif') returns 'images'
function cbt_after(token, str)
{
	if (str.indexOf(token) != -1) 
	{
		return str.substring(str.indexOf(token) + token.length);
	}
	else
	{
		return "";
	}
}
//*

//* function cbt_after(token,str) returns that part of str after token
//********************************************************
//* @author prh
//* @version 2006 1.0
//* @param token - a string to search for
//* @param str a string to search in
//* @return that part of str after the token
//* @exception
//*
//* @example cbt_after('/','images/circle.gif') returns 'circle.gif'
function cbt_before(token, str)
{
	if (str.indexOf(token) != -1)
	{
		return str.substring(0,str.indexOf(token));
	}
	else
	{
		return str;
	}
}
//*
	
//* function cbt_greater(a,b) returns the greater value of a and b
//****************************************************
//* @author prh
//* @version 2006 1.0
//* @param a - integer or real (or string)
//* @param b - integer or real (or string)
//* @return the greater of a and b
//* @exception
//*
//* @example cbt_greater(a,b);	
function cbt_greater(a,b)
{
	if (a >= b){
		return a;
	}
	return b;
}
//*

//* function cbt_lesser(a,b) returns the lesser value of a and b
//****************************************************
//* @author prh
//* @version 2006 1.0
//* @param a - integer or real (or string)
//* @param b - integer or real (or string)
//* @return the greater of a and b
//* @exception
//*
//* @example cbt_lesser(a,b);	
function cbt_lesser(a,b)
{
	if (a >= b){
		return b;
	}
	return a;
}
//*

//* function cbt_trim(str) rtrims leading and trailing spaces from str
//*****************************************************
//* @author prh
//* @version 2006 1.0
//* @param str - string
//* @param 
//* @return str trimmed
//* @exception
//*
//* @example cbt_trim(' and ') returns 'and'	
function cbt_trim(str)
{
	while(str.charAt(str.length - 1) == " ")
	   str = str.substring(0,str.length - 1);
	while(str.charAt(0) == " ")
	   str = str.substring(1);
	return str;
}

//* function cbt_plural() returns the plural form of a string where appropriate
//************************************************************
//* @author prh
//* @version 2006 1.0
//* @param singularstr - singular form of string
//* @param pluralstr - plural form of string 
//* @param nr - integer number under consideration
//* @return str trimmed
//* @exception
//*
//* @example cbt_plural('datum','data',2) returns 'data'		
function cbt_plural(singularstr, pluralstr, nr)
{
	if (nr > 1)
	{
		return pluralstr;
	}
	else
	{
		return singularstr;
	}
} 
//*

//* function cbt_invert() returns its input reversed
//*****************************************
//* @author prh
//* @version 2006 1.0
//* @param str - string to be inverted
//* @return string
//*
//* @example str = cbt_invert("ABC") --> "CBA"
function cbt_invert(str)
{
	var tmpStr = "";
	for (var i = str.length; i >= 0; i--)
	{
		tmpStr = tmpStr + str.charAt(i);
	}
	return tmpStr;
}
//*	

//* function cbt_replaceFirst() returns a string with the first occurrence of a specified string replaced
//******************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param str - string to be operated on
//* @param what - string to search for
//* @param withWhat - replacement string
//* @return string
//*
//* @example cbt_replaceFirst("AABBBBBBBCC","BB","XX") --> "AAXXBBBBBCC"		
function cbt_replaceFirst(str, what, withWhat)
{
	if (str.indexOf(what) != -1)
	{
		str = cbt_before(what, str) + withWhat + cbt_after(what, str);
	}
	return str;
}
//*

//* function cbt_replaceAll() returns a string with all occurrences of a specified string replaced
//*************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param str - string to be operated on
//* @param what - string to search for
//* @param withWhat - replacement string
//* @return string
//*
//* @example cbt_replaceAll("AABBBBBBBCC","BB","XX") --> "AAXXXXXXBCC"	
function cbt_replaceAll(str, what, withWhat)
{
	if (withWhat.indexOf(what) != -1)
	{
		return str;
	}
	while (str.indexOf(what) != -1)
	{
		str = cbt_before(what, str) + withWhat + cbt_after(what, str);
	}
	return str;
}
//*

//* function cbt_padWithStrRight() returns a string padded to a specified minimum length with a specified char or string
//*******************************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param str - string to be operated on
//* @param nr - (minimum) resulting string length
//* @param withStr - padding string
//* @return string
//*		
//* @example cbt_padWithStrRight("ABC",4,"XXX"); --> "ABCXXX"
function cbt_padWithStrRight(str, nr, withStr)
{
	while (str.length < nr)
	{
		str = str + withStr;
	}
	return str;
}
//*

//* function cbt_padWithStrLeft() returns a string left padded to a specified minimum length with a specified char or string
//**********************************************************************************************
//* @author prh
//* @version 2006 1.0
//* @param str - string to be operated on
//* @param nr - (minimum) resulting string length
//* @param withStr - padding string
//* @return string
//*		
//* @example cbt_padWithStrLeft("ABC",4,"XXX"); --> "XXXABC"
function cbt_padWithStrLeft(str, nr, withStr)
{
	while (str.length < nr)
	{
		str = withStr + str;
	}
	return str;
}
//*

//* function cbt_cookiesAvailable() returns true if cookies are available
//*******************************************************
//* @author prh
//* @version 2006 1.0
//* @param 
//* @return Boolean true or false
//*		
//* @example cbt_cookiesAvailable();		
function cbt_cookiesAvailable()
{
	return (document.cookie != null);
}
//*

//* function cbt_getCookie() returns a cookie of a specified name
//****************************************************
//* @author prh
//* @version 2006 1.0
//* @param name - string representing the cookie to retrieve
//* @return Boolean true or false
//*		
//* @example cbt_getCookie('shazam');	
function cbt_getCookie(name) 
{
    var arg = name + "=";
    var alen = arg.length;
    var clen = document.cookie.length;
    var i = 0;
    var j = 0;
    var endstr = 0;
        
    while (i < clen) 
    {
      	j = i + alen;
        if (document.cookie.substring(i, j) == arg)
        {
           	endstr = document.cookie.indexOf (";", j);
           	if (endstr == -1)
               endstr = document.cookie.length;
       		return unescape(document.cookie.substring(j, endstr));
        }
       	i = document.cookie.indexOf(" ", i) + 1;
        if (i == 0) 
           	break; 
    }
	return null;
}
//*

//* function cbt_setCookie() sets a cookie with an expiry period
//**************************************************
//* @author prh
//* @version 2006 1.0
//* @param name - string representing the cookie to set
//* @param value - dtring representing value to set
//* @param daystoexpire - integer number of days until expiry
//* @return Boolean true or false
//*		
//* @example cbt_setCookie('shazam','123',99);
function cbt_setCookie(name, value, daystoexpire)
{
	var expdate = new Date ();
	
	expdate.setTime(expdate.getTime() + (24 * 60 * 60 * 1000 * daystoexpire));
	document.cookie = name + "=" + escape(value) + "; expires=" + expdate.toGMTString();
	return;
}
//*

//* function cbt_killCookie() kills a named cookie
//***************************************
//* @author prh
//* @version 2006 1.0
//* @param name - string representing the cookie to kill
//* @param 
//* @return N/A
//*		
//* @example cbt_killCookie('shazam');
function cbt_killCookie(name)
{
	var expdate = new Date ();
	
	expdate.setTime (expdate.getTime() - (24*60*60*1000));
	document.cookie = name + "=deleted; expires=" + expdate.toGMTString();
	return;
}
//*

//* function cbt_version() returns our version
//************************************
//* @author prh
//* @version 2006 1.0
//* @return version string
//*		
//* @example cbt_killCookie('shazam');
function cbt_version()
{
	return version;
}
//*

	