function onlineWindow(theAction, theCourse, theTitle, anyExtra){
	var newwin = window.open("" ,"popup", "scrollbars=yes,screenX=50,screenY=50,width=630,height=510,resizable=yes");
	//newwin.resizeTo(600,400);
	//if (document.layers){
	//	newwin.setResizable(true);
	//}

	newwin.document.location.href = ('output.php?inc='+theAction+'&CourseCode='+theCourse+'&title='+theTitle+'&'+anyExtra);
	newwin.focus();
}

function focusForm() {
	var theElements = document.getElementsByTagName("input");
	for (var i=0; i<theElements.length; i++) {
		if(theElements[i].className == 'searchInput'){
			theElements[i].onfocus = function() {
				if(this.value == this.defaultValue) { 
					this.value = ''
				}
			}
			theElements[i].onblur = function() {
				if(this.value.replace(' ','') == '') {
					this.value = this.defaultValue
				}
			}
		}
	}
}

function framesPopup(theAction, extras) {
	var newwin = window.open('framespopup.php?inc=' + theAction + '&' + extras, "framepopup", "scrollbars=yes,screenX=50,screenY=50,width=630,height=510,resizable=yes");
	newwin.focus();
}

function dlfile(filename, version) {
	var newwin = window.open("" ,"dlfile", "width=235,height=160,scrollbars=no,resizable=yes,status=no,toolbar=no,location=no,menubar=no");
	var extra = "";
	if (version != undefined)
		extra = "&v="+version;
	newwin.document.location.href = 'download.php?f='+filename+extra;
	newwin.focus();
}

//javascript popups
var pagePopups = new Array();

function popupInit() {
	for (var i=0; i < pagePopups.length; i++) {
		jsPopup(pagePopups[i][0], pagePopups[i][1], pagePopups[i][2], pagePopups[i][3], pagePopups[i][4], pagePopups[i][5]);
	}
}

//basically creates a div for a popup and then fills it
function jsPopup(name, top, left, width, zIndex, innards) {
	var target = document.createElement('div');
	target.id = name;
	target.style.position = "absolute";	// this could be done in the CSS, but it's better to make sure here.
	target.style.top = top+"px";
	target.style.left = left+"px";
	target.style.width = width+"px";
	target.style.zIndex = zIndex;
	target.zIndex = zIndex;
	target.innerHTML = innards;
	document.body.appendChild(target);

	var inputElements = target.getElementsByTagName('input');
	if(inputElements != undefined && inputElements.length > 0) {
		for(var i=0; i<inputElements.length; i++) {
			if(inputElements[i].type == 'text') {
				inputElements[i].focus();
				break;
			}
		}
	}
}

//=============================================================================================
//======================================ACTIVE HELP & TOOLTIPS=================================

var tooltips = { };		//add to this array to build tooltip data

function setActiveHelp(el, helpID, tipWidth) {
	el = getElement(el);
	var parts = helpID.split(".");
	var theText = helpText;
	
	for (var i = 0; i < parts.length; i++) {
		theText = theText[parts[i]];
		if (theText == undefined) {
			theText = 'Help ID invalid: ' + helpID;
			return;
		}
	}
	var tip = showTooltip(theText, el, undefined, true);
	if (tip != false && tipWidth != undefined && tipWidth != "") {
		tip.style.width = tipWidth+"px";
	}
	el.onmouseout = function() { hideTooltip(); return true; };	//saves us having to code it into all pages
}

function hideActiveHelp() {
	hideTooltip();
}

/**
 * @author			pospi
 * TODO: doesn't work in an iframe until you mouseover it twice
 * Parameters:
 * tooltipID		mixed		index in tooltips object of data to retrieve, or raw text to print out
 * el				element		the element to put the tooltip next to
 * refField			element		an input element to decide the tooltip text, based on its value.
 								In this case, the tooltipID must be an array index, and that array item
 								is a subarray with indices corresponding to refField's possible values
 * bPassDirectly	bool		true if tooltipID should be treated as a string to be printed out
 */
function showTooltip(tooltipID, el, refField, bPassDirectly) {
	var tip = 0;
	if (bPassDirectly) {
		tip = tooltipID;
	} else if (tooltipID != undefined && tooltips[tooltipID] != undefined) {
		tip = tooltips[tooltipID];
	}
	
	if (tip) {
		var ttEl = getTooltipElement();
		hide(ttEl);
		if (typeof tip == "string") {
			ttEl.innerHTML = tip;
		} else {
			var lookupEl = getElement(refField);
			if (lookupEl) {
				ttEl.innerHTML = tip[lookupEl.value];
			}
		}
		var outputElPos = getPos(el);
		outputElPos.x += el.offsetWidth;
		ttEl.style.left = outputElPos.x + 'px';
		ttEl.style.top = outputElPos.y + 'px';
		show(ttEl);
		
		var browserWidth = (document.all && !window.opera) ? ietruebody().clientWidth : window.innerWidth - 20;
		var browserHeight = (document.all && !window.opera) ? ietruebody().clientHeight : window.innerHeight - 20;
		browserHeight += (document.all && !window.opera ? ietruebody().scrollTop : window.pageYOffset);
		if (outputElPos.x + ttEl.offsetWidth > browserWidth) {
			ttEl.style.left = (browserWidth - ttEl.offsetWidth) + 'px';
			ttEl.style.top = (outputElPos.y + el.offsetHeight) + 'px';
		}
		if (outputElPos.y + ttEl.offsetHeight > browserHeight) {
			ttEl.style.top = (browserHeight - ttEl.offsetHeight) + 'px';
		}
		return ttEl;
	}
	return false;
}

function ietruebody(){
	return (document.compatMode && document.compatMode != "BackCompat") ? document.documentElement : document.body;
}
				  
function hideTooltip() {
	hide('tooltipDiv');
}
				  
function getTooltipElement() {
	var el = getElement('tooltipDiv');
	if (!el) {
		el = document.createElement('div');
		el.setAttribute('id', 'tooltipDiv');
		el.style.position = 'absolute';
		el.style.zIndex = 1000;
		el.className = 'tooltip';
		document.body.appendChild(el);
	}
	el.style.width = "";
	return el;
}

//=============================================================================================


// Check browser support for layers
// note: in firefox, ie4 AND ns4 are false
var ns4 = (document.layers) ? true : false;
var ie4 = (document.all) ? true : false;

var offsetX, offsetY, curz = 1;
var mousex, mousey, activeelement, movingElement;
var dragTimeoutID;

function shiftTo(obj, x, y) {
	if (obj != null) {
		if (ie4) {
			theObj = obj.style;
			theObj.pixelLeft = x;
			theObj.pixelTop = y;
		} else if (ns4) {
			theObj = obj;
			theObj.moveTo(x, y);
		} else {
			theObj = getElement(obj);
			theObj.style.top = y + 'px';
			theObj.style.left = x + 'px';
		}
	}
}

//makes a transparent div with a nice outline
function getDragBox(thing) {
	var box;
	var madeNew = false;
	if (!(box = getElement('dragBox'))) {
		madeNew = true;
		box = document.createElement("div");
		box.setAttribute("id", "dragBox");
		box.style.border = "3px #555 dashed";
		box.style.position = "absolute";
//		box.innerHTML = '<img src="images/spacer.gif" width="100%" height="100%" alt="">';
//		box.style.background = "url(images/spacer.gif)";
	} else {
		box.style.display = "";
	}
	box.style.top = thing.style.top;
	box.style.left = thing.style.left;
	box.style.width = thing.offsetWidth + "px";
	box.style.height = thing.offsetHeight + "px";
	if (madeNew) {
		document.body.appendChild(box);
	}
	return box;
}

function engage(thing) {
	thing = getElement(thing);
	activeelement = getDragBox(thing);
	movingElement = thing;
	dragTimeoutID = setTimeout("release()", 3000);
	if (ie4) {
		offsetX = window.event.offsetX + 0;
		offsetY = window.event.offsetY + 0;
		theObj = thing.style;
		theOtherObj = activeelement.style;
	} else {
		offsetX = mousex - parseInt(activeelement.style.left);
		offsetY = mousey - parseInt(activeelement.style.top);
		if (ns4) {
			theObj = thing;
			theOtherObj = activeelement;
		} else {
			theObj = thing.style;
			theOtherObj = activeelement.style;
		}
	}
	theObj.zIndex = curz++;
	theOtherObj.zIndex = curz++;
	if (ns4) {
		window.captureEvents(Event.MOUSEMOVE);
		window.captureEvents(Event.MOUSEUP);
		window.onmousemove = mousemoved;
		window.onmouseup = release;
	} else {
		document.onmousemove = mousemoved;
		document.onmouseup = release;
	}
}

function release() {
	if (dragTimeoutID != 0) {
		clearTimeout(dragTimeoutID);
		dragTimeoutID = 0;
		movingElement.style.top = activeelement.style.top;
		movingElement.style.left = activeelement.style.left;
		movingElement.style.zIndex = activeelement.style.zIndex + 1;
		activeelement.style.display = "none";
		activeelement = null;
		if (ns4) {
			window.onmousemove = null;
			window.onmouseup = null;
		} else {
			document.onmousemove = null;
			document.onmouseup = null;
		}
	}
}

//stupid IE wants to not let you select text unless this gets called on page load
function IEHackRelease() {
	if (ns4) {
		window.onmousemove = null;
		window.onmouseup = null;
	} else {
		document.onmousemove = null;
		document.onmouseup = null;
	}
}

function mousemoved(evt) {
	if (!ie4 && !ns4) {
		mousex = evt.pageX;
		mousey = evt.pageY;
	}
	if (activeelement) {
		if (ie4) {
			mousex = window.event.clientX+document.body.scrollLeft;
			mousey = window.event.clientY+document.body.scrollTop;
		} else if (ns4) {
			mousex = evt.pageX+window.pageXOffset;
			mousey = evt.pageY+window.pageYOffset;
		}
		wx = mousex - offsetX;
		wy = mousey - offsetY;
		wx = (wx > 0) ? wx : 0;
		wy = (wy > 0) ? wy : 0;
		shiftTo(activeelement, wx, wy);
	}
	return false;
}
if (ie4) {
	document.onmousemove = mousemoved;
} else {
	window.captureEvents(Event.MOUSEMOVE);
	window.onmousemove = mousemoved;
}

// END DRAGGABLE CODE


//// VISIBLE/INVISBLE FUNCTION ////

// fix cross-browser issues
if (ie4) {
	visible = 'visible';
	hidden = 'hidden';
} else if (ns4) {
	visible = 'show';
	hidden = 'hide';
} else {
	visible = 'visible';
	hidden = 'hidden';
}

// showlayer function
function makeVis(newlayername, newleftvalue) {

	if (ie4)  {
		newlayerstyle = document.all(newlayername).style;
	} else if (ns4) {
		newlayerstyle = document.layers[newlayername];
	} else {
		newlayerstyle = document.getElementById(newlayername).style;
	}

	if (newleftvalue) {
		if (ie4) {
			newlayerstyle.left = newleftvalue
		} else {
			newlayerstyle.left = newleftvalue + "px"
		}
	}

	newlayerstyle.visibility = visible;
}

function makeInVis(newlayername, newleftvalue) {
	// alert(newlayername);
	if (ie4)  {
		newlayerstyle = document.all(newlayername).style;
	} else if (ns4) {
		newlayerstyle = document.layers[newlayername];
	} else {
		newlayerstyle = document.getElementById(newlayername).style;
	}

	if (newleftvalue) {
		if (ie4) {
			newlayerstyle.left = newleftvalue
		} else {
			newlayerstyle.left = newleftvalue + "px"
		}
	}
	newlayerstyle.visibility = hidden;
}

function printPopup(title, body) {
   var newWindow = window.open("","displayWindow","menubar=yes");
   newWindow.document.write("<HEAD><TITLE>"+title+"</TITLE><LINK REL='stylesheet' HREF='css/ciacdefault.css' TYPE='text/css'></HEAD>");
   newWindow.document.write(body);
   newWindow.print();
}

// Change row colour
function setRowColor(thisRow, newColor) {
	thisRow.style.backgroundColor = newColor;
}

function addtosendlist(username)
{
	to = document.forms.composeMessage.toUserName;

	if (to.value.substr(0,1) == '') {
		to.value = username;
		to.text = to.value;
	} else {
		to.value = to.value + ', ' + username;
		to.text = to.value;
	}
}

// Rollovers

/*
function MM_preloadImages() { //v2.0
	if (document.images) {
		var imgFiles = MM_preloadImages.arguments;
		if (document.preloadArray==null) document.preloadArray = new Array();
		var i = document.preloadArray.length;
		
		with (document) for (var j=0; j<imgFiles.length; j++) if (imgFiles[j].charAt(0)!="#") {
			preloadArray[i] = new Image;
			preloadArray[i++].src = imgFiles[j];
		}
	}
}

function MM_swapImgRestore() { //v2.0
	if (document.MM_swapImgData != null)
		for (var i=0; i<(document.MM_swapImgData.length-1); i+=2)
			document.MM_swapImgData[i].src = document.MM_swapImgData[i+1];
}

function MM_swapImage() { //v2.0
	var i,j=0,objStr,obj,swapArray=new Array,oldArray=document.MM_swapImgData;

	for (i=0; i < (MM_swapImage.arguments.length-2); i+=3) {
		//alert (navigator.appName);
		//alert ((navigator.appName == 'Netscape')?i:i+1);

		objStr = MM_swapImage.arguments[(navigator.appName == 'Netscape')?i:i+1];
		//alert (objStr);
		if ((objStr.indexOf('document.layers[') == 0 && document.layers == null) ||
			(objStr.indexOf('document.all[') == 0 && document.all == null))
				objStr = 'document'+objStr.substring(objStr.lastIndexOf('.'),objStr.length);
		alert (objStr);
		obj = eval(objStr);

		if (obj != null) {
			swapArray[j++] = obj;
			swapArray[j++] = (oldArray == null || oldArray[j-1] != obj) ? obj.src:oldArray[j];
			obj.src = MM_swapImage.arguments[i+2];
		}
	}

	document.MM_swapImgData = swapArray; //used for restore
}
*/

//////
// start of functions added by NickF
// - these were added for the ContextMenu, but should be applicable to many different circumstances
//

/**
*	hide()
*	Hides a HTML element
*		- pass it an element to hide, or the string identifier of an element
*	eg: <div id="myElement">..</div>
*		hide("myElement");
*
*/
function hide (el) {
	if (typeof el == "String" || typeof el == "string") {
		el = getElement(el);
	}
	if(el != null) 
		el.style.display = "none";
}
/**
*	see hide()
*/
function show (el) {
	if (typeof el == "String" || typeof el == "string") {
		el = getElement(el);
	}
	
	if(el != undefined) {
		el.style.display = "";
	}
	
}

function setVis(what, showHide) {
	if (showHide) {
		show(what);
	} else {
		hide(what);
	}
}
function toggleVis(el) {
	if (typeof el == "String" || typeof el == "string") {
		el = getElement(el);
	}
	if (el.style.display == "none") {
		show(el);
		return true;			// we just showed one
	} else {
		hide(el);
		return false;			// we just hid one
	}
}
/**
*	getElement()
*	Pass it the string id of an element and it returns a reference to the element with that id
*	It's pretty much cross-browser - but i've never really tried it out with older browsers, screw em.
*/
function getElement (elId) {
	if (typeof elId != "string") return elId;
	return	document.all ? document.all[elId] :
			document.getElementById ? document.getElementById(elId) :
			null;
}
/**
*	getElementsByTag
*	gets all the elements with the given tag name, within the specified element.
*	the second parameter is optional. leave it blank to get all tags.
*	ie: getElementsByTag("div", myElement) returns an array of all the <div>s within the myElement element.
*		getElementsByTag("div")			   returns an array of all the <div>s within the whole document.
*/
function getElementsByTag(tag, el) {
	if (el == undefined) el = document;
	return document.all ? el.all.tags(tag) :
		   document.getElementsByTagName ? el.getElementsByTagName(tag) :
		   null;
}
/**
*	addslashes()
*	Will convert: O'Malley's 			to 		O\'Malley\'s
*				  He's "good"\lala 		to		He\'s \"good\"\\lala
*	returns the result, and doesn't affect the string passed in itself.
*/
function addslashes (str) {
	str = str.replace(/\\/g, "\\\\");
	str = str.replace(/"/g, "\\\"");
	str = str.replace(/'/g, "\\'");
	return str;
}

/**
*	Javascript doesn't have a built-in ability to clone an object
*	Using code like:
*		a = new Object();
*		a.id = 1;
*		b = a;
*		b.id = 2;
*		alert(a.id + " " + b.id);
*	...will output "2 2", so what you gotta do is use this function like so:
*		a = new Object();
*		a.id = 1;
*		b = new CloneObject(a);	// creates a clone of a
*		b.id = 2;
*		alert (a.id + " " + b.id);
*	...will output "1 2".
*/
function CloneObject(what) {
    for (i in what) {
        this[i] = what[i];
    }
}

function getCookie(c_name) {
	if (document.cookie.length > 0) {
		c_start = document.cookie.indexOf(c_name + "=")
		if (c_start != -1) {
			c_start = c_start + c_name.length + 1;
			c_end = document.cookie.indexOf(";", c_start);
			if (c_end == -1) c_end = document.cookie.length;
			return unescape(document.cookie.substring(c_start, c_end));
		}
	}
	return null;
}

function setCookie(c_name, value, expiredays) {
	var exdate = new Date();
	if (expiredays == undefined) expiredays = 28;	// 4 week default
	exdate.setTime(exdate.getTime() + (expiredays*86400000));
	document.cookie = c_name + "=" + escape(value) + (expiredays == null ? "" : "; expires=" + exdate);
}

/**
*		This is used by the NavBar.class.php class
*			it just adds event handlers onto specific elements, giving them rollover effects etc.
*			The ButtonBar->draw() function adds code to call this function, and normally shouldn't need to be called manually
*/
function initButtons() {
	var items;
	var divs = getElementsByTag("div");
	for (var i in divs) {
		if (divs[i].className && divs[i].className.indexOf("navbar") != -1) {
			items = getElementsByTag("li", divs[i]);
			for (var j in items) {
				if (!items[j].className || items[j].className.indexOf("disabled") == -1) {
					addEvent(items[j], "onmouseover", function () {
						this.className = "active";
					});
					addEvent(items[j], "onmouseout", function () {
						this.className = "";
					});
				}
			}
		}
	}
}

//PNG transparency fix for IE 6
function initPNGs() {
	if (!(window.XMLHttpRequest)) { 		//this should give us IE6 and lower
		for (var i=0; i<document.images.length; i++) {
			if (document.images[i].src.indexOf(".png") != -1) {
				document.images[i].style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+document.images[i].src+"', sizingMethod='scale')";
				document.images[i].style.width = document.images[i].offsetWidth;
				document.images[i].style.height = document.images[i].offsetHeight;
				document.images[i].src = "images/spacer.gif"; //clear gif needed to let the filter show through
			}
		}
	}
}

function swapImage(imgId, imgPath) {
	var obj = getElement(imgId);
	if (obj) obj.src = imgPath;
}

function selectAll(formObj, isInverse) {
	for (var i=0;i < formObj.length;i++) {
		fldObj = formObj.elements[i];
		if (fldObj.type == 'checkbox') {
			if (isInverse) fldObj.checked = (fldObj.checked) ? false : true;
				else fldObj.checked = true;
		}
	}
}

//
//	pass it a HTML element and it returns an object with 2 properties, x and y, which represent the x and y position of the element.
//
function getPos(el) {
	for (var lx=0, ly=0;
	     el != null;
		 lx += el.offsetLeft, ly += el.offsetTop, el = el.offsetParent);
	return {x: lx,y: ly};
}

function getRadioValue(el) {
	var radioLength = el.length;
	if(radioLength == undefined)
		if(el.checked)
			return radioObj.value;
		else
			return "";
	for(var i = 0; i < radioLength; i++) {
		if(el[i].checked) {
			return el[i].value;
		}
	}
	return "";
}

function showElementCentred(el) {
	el.style.visibility = "hidden";	// so we can get an accurate reading of its width/height
	show(el);

	var winSize = getWindowSize();
	var scrollOffset = getScrollXY();

	el.style.left = ((winSize[0] - el.offsetWidth) / 2 + scrollOffset[0]) + "px";
	el.style.top = ((winSize[1] - el.offsetHeight) / 2 + scrollOffset[1]) + "px";

	el.style.visibility = '';
}

/**
*	stolen from http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
*/
function getScrollXY() {
	var scrOfX = 0, scrOfY = 0;
	if (typeof(window.pageYOffset) == 'number') {
		//Netscape compliant
		scrOfY = window.pageYOffset;
		scrOfX = window.pageXOffset;
	} else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
		//DOM compliant
		scrOfY = document.body.scrollTop;
		scrOfX = document.body.scrollLeft;
	} else if (document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
		//IE6 standards compliant mode
		scrOfY = document.documentElement.scrollTop;
		scrOfX = document.documentElement.scrollLeft;
	}
	return [ scrOfX, scrOfY ];
}

/**
*	stolen from http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
*/
function getWindowSize() {
  var myWidth = 0, myHeight = 0;
  if( typeof( window.innerWidth ) == 'number' ) {
    //Non-IE
    myWidth = window.innerWidth;
    myHeight = window.innerHeight;
  } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
    //IE 6+ in 'standards compliant mode'
    myWidth = document.documentElement.clientWidth;
    myHeight = document.documentElement.clientHeight;
  } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
    //IE 4 compatible
    myWidth = document.body.clientWidth;
    myHeight = document.body.clientHeight;
  }
  return [myWidth, myHeight];
}

// Javascript includes.
// usage: just like php: include_once('path/to/file.js');
// update: now does css too.
var included_files = new Array();
function include_once(script_filename) {
    if (!in_array(script_filename, included_files)) {
        included_files[included_files.length] = script_filename;
        if (script_filename.indexOf(".css") != -1) {	// css
        	includeStylesheet(script_filename);
        } else {	// js
        	include_dom(script_filename);
        }
    }
}
function in_array(needle, haystack) {
    for (var i = 0; i < haystack.length; i++) {
        if (haystack[i] == needle) {
            return true;
        }
    }
    return false;
}
function include_dom(script_filename) {
    var html_doc = document.getElementsByTagName('head').item(0);
    var js = document.createElement('script');
    js.setAttribute('language', 'javascript');
    js.setAttribute('type', 'text/javascript');
    js.setAttribute('src', script_filename);
    html_doc.appendChild(js);
    return false;
}
function includeStylesheet(css) {
	var html_doc = document.getElementsByTagName('head').item(0);
	var link = document.createElement('link');
	link.setAttribute('rel', 'stylesheet');
	link.setAttribute('href', css);
	link.setAttribute('type', 'text/css');
    html_doc.appendChild(link);
}
/////////////////////
// Date extensions //
/////////////////////
Date.prototype.toDateString = function () {
	// 30/1/1984
	return this.getDate() + "/" + (this.getMonth() + 1) + "/" + this.getFullYear();
}
Date.prototype.toTimeString = function () {
	// 20:30
	// 8:03
	var m = this.getMinutes();
	return this.getHours() + ":" + (m < 10 ? "0" : "") + m;
}
Date.prototype.toTimeString12Hour = function () {
	// 3:30pm
	// 12:01am
	// 12:59pm
	var h = this.getHours();
	h = h > 12 ? h - 12 : (h == 0 ? 12 : h);
	var m = this.getMinutes();
	return h + ":" + (m < 10 ? "0" : "") + m + (this.getHours() >= 12 ? "pm" : "am");
}
Date.prototype.getDayStr = function () {
	return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][this.getDay()];
}
Date.prototype.getMonthStr = function () {
	return ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][this.getMonth()];
}
Date.prototype.daysInMonth = function () {
	if (this.getMonth() == 1) {
		return this.isLeapYear() ? 29 : 28;
	}
	return [31, (28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][this.getMonth()];
}
Date.prototype.isLeapYear = function () {
	 var strYear  = this.getFullYear();
	 return (strYear % 4 == 0) && (strYear % 100 != 0 || strYear % 400 == 0);
}

Date.prototype.getFriendlyDate = function() {
	// Monday, 20 March 2006
	return this.getDayStr() + ", " + this.getDate() + " " + this.getMonthStr() + " " + this.getFullYear();
}
Date.prototype.firstOfMonth = function () {
	return new Date(this.getFullYear(), this.getMonth(), 1);
}
// ausDate = "24/05/06" or something
// the year part can be 2 or 4 digits. 2 digit values are treated as a year between 1940 and 2039
Date.prototype.setDateFromString = function (ausDate) {
	var arr = ausDate.split("/");
	arr[2] = parseInt(arr[2]);
	if (arr[2] < 40) arr[2] += 2000
	else if (arr[2] < 100) arr[2] += 1900;

	this.setFullYear(arr[2], parseInt(arr[1] - 1), parseInt(arr[0]));	// yes, setFullYear can take month and day parameters.
}

// uses the same syntax as php's date function (http://au.php.net/manual/en/function.date.php)
Date.prototype.phpDate = function (formatStr) {
	var out = "";
	var temp;
	var format = formatStr.split('');
	for (var i = 0; i < format.length; i++) {
		switch (format[i]) {
			case '\\' :
				if (i != format.length - 1) {
					i++;
					out += format[i];
				}
				break;
			/****		Days		*****/
			case "d" :	// 01-31
				temp = this.getDate()
				out += (temp < 10 ? "0" : "") + temp;
				break;
			case "D" :	// "Sun"-"Sat"
				out += ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][this.getDay()];
				break;
			case "j" :	// 1-31
				out += this.getDate();
				break;
			case "l" :	// "Sunday" - "Saturday"
				out += ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][this.getDay()];
				break;
			case "S" :	// "st", "nd", "rd", "th"... (works well with 'j')
				temp = this.getDate();
				if (parseInt(temp / 10) == 1) {
					out += "th"; // 10-19 all have "th"
				} else {
					switch (temp % 10) {
						case 1 : out += "st"; break;
						case 2 : out += "nd"; break;
						case 3 : out += "rd"; break;
						default: out += "th";
					}
				}
				break;
			case "w" :	// 0 - 6 (0 for sunday, 6 for saturday)
				out += this.getDay();
				break;
			case "z" :	// day of the year (starting from 0) 0-365
				temp = this.getDate() - 1;
				var anotherTemp = [31, this.isLeapYear() ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
				for (var x = this.getMonth() - 1; x >= 0; x--) {
					temp += anotherTemp[x];
				}
				out += temp;
				delete anotherTemp;
				break;
			/****		Week		*****/
			case "W" :	// week of the year
			 	out += "??";
			 	break;
			/****		Month		*****/
			case "F" :
				out += ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][this.getMonth()];
				break;
			case "m" : // 01-12
				temp = this.getMonth() + 1;
				out += (temp < 10 ? "0" : "") + temp;
				break;
			case "M" :
				out += ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][this.getMonth()];
				break;
			case "n" : // 1-12
				out += this.getMonth() + 1;
				break;
			case "t" :
				if (this.getMonth() == 1) {
					out += this.isLeapYear() ? 29 : 28;
				} else {
					out += [31, (28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][this.getMonth()];
				}
				break;
			/****		Years			****/
			case "L" :
				out += this.isLeapYear() ? "1" : "0";
				break;
			case "Y" :
				out += this.getFullYear();
				break;
			case "y" :
				out += String(this.getFullYear()).substr(-2);
				break;
			/****		Time			****/
			case "a" :
				out += (this.getHours() < 12 ? "am" : "pm");
				break;
			case "A" :
				out += (this.getHours() < 12 ? "AM" : "PM");
				break;
			case "B" :
				// internet Time
				out += "??";
				break;
			case "g" : // 1-12
				temp = this.getHours();
				if (temp == 0) out += "12";
				else if (temp > 12) {
					out += (temp - 12);
				} else {
					out += temp;
				}
				break;
			case "G" : // 0-23
				out += this.getHours();
				break;
			case "h" : // 01-12
				temp = this.getHours();
				if (temp == 0) {
					temp += 12;
				} else if (temp > 12) {
					temp -= 12;
				}
				out += (temp < 10 ? "0" : "") + temp;
				break;
			case "H" : // 00-23
				temp = this.getHours();
				out += (temp < 10 ? "0" : "") + temp;
				break;
			case "i" :	// 00-59 min
				temp = this.getMinutes();
				out += (temp < 10 ? "0" : "") + temp;
				break;
			case "s" :	// 00-59 sec
				temp = this.getSeconds();
				out += (temp < 10 ? "0" : "") + temp;
				break;
			case "I" :	// daylight savings ?
				// bugger that
				out += "??";
				break;
			/****		Timezone stuff		****/
			case "O" : // (capital "o") - difference to GMT
				temp = -this.getTimezoneOffset() / 60 * 100;
				if (temp > 0) out += "+";
				out += (Math.abs(temp) < 100 ? "00" : (Math.abs(temp) < 1000 ? "0" : "")) + temp;
				break;
			case "T" : // timezone name (eg, "EST", "CMT"...)
				// bugger that
				out += "??";
				break;
			case "Z" :
				out += -this.getTimezoneOffset() * 60;
				break;
			/**** full date time ****/
			case "c" :
				//2004-02-12T15:19:21+00:00
				temp = this.phpDate("O");
				out += this.phpDate("Y-m-d\\TH:i:s") + temp.substr(0, 3) + ":" + temp.substr(-2);
				break;
			case "r" :
				//Thu, 21 Dec 2000 16:01:07 +0200
				out += this.phpDate("D, j M Y H:i:s O");
				break;
			case "U" :
				out += parseInt(this.getTime() / 1000);
				break;
			default :
				out += format[i];
		}
	}
	return out;
}
function ausdatetime2Date(dateStr) {	// expected input: "15:31 31/1/2005", return a date object

    var parts = dateStr.split(" ");
    if (parts.length != 2) return false;

	var timeparts = parts[0].split(":");
	var dateparts = parts[1].split("/");

	if (dateparts.length != 3 || timeparts.length != 2) return false;

	/*
	* Date constuctor
	* new Date(yr_num, mo_num, day_num
    *    [, hr_num, min_num, sec_num, ms_num])
    * note: mo_num is a number in the range 0-11 (0 = january, 11 = december)
    */
	return new Date(dateparts[2], dateparts[1] - 1, dateparts[0], timeparts[0], timeparts[1]);
}
/**
*	For the mini calendar date selector
*	@param		element		the element to anchor the mini calendar to. Appears to the right of the element
*	@param		mixed		a string id of, or an element to which the selected date is going into. should be an input el, or something with a property called "value"
*	@param		int			(optional) the month to start on (0 = january). default: current month
*	@param		int			(optional) the year to start on. default: current year
*	@param		string		(optional) a string used to format the date before being put into outputEl. uses the phpDate() function to format, which has the same syntax as php's date(). default: "j/n/Y" (ie: 9/3/2006)
*/
function showDateSelector (anchorTo, outputEl, month, year, dateFormat) {

	// dateFormat is optional
	if (dateFormat == undefined) {
		dateFormat = "j/n/Y";
	}

	// make sure the outputEl isn't a string
	// if it's an element, then grab its id and use that
	// if it doesn't have an id, then assign it one. dodgy? yes.
	var outputElId;
	if (typeof outputEl != "string" && typeof outputEl != "String") {
		if (outputEl.id == undefined || outputEl.id == '') {
			outputEl.id = 'miniCalTarget';
		}
		outputElId = outputEl.id;
	} else {
		outputElId = outputEl;
		outputEl = getElement(outputElId);
	}

	var temp = new Date();
	if (year == undefined || year == null) {
		year = temp.getFullYear();
	}
	if (month == undefined || month == null) {
		month = temp.getMonth();
	} else {
		if (month == -1) {
			month = 11;
			year--;
		} else if (month == 12) {
			month = 0;
			year++;
		}
	}
	delete temp;


	var out;
	var div = getElement('miniCalendarDiv');
	if (!div) div = createMiniCalDiv();

	if (anchorTo != undefined && anchorTo != '') {
		outputElPos = getPos(anchorTo);
		div.style.left = (outputElPos.x + anchorTo.offsetWidth) + "px";
		div.style.top = (outputElPos.y) + "px";
	}

	var today = new Date(year, month, 1);
	var daysInMonth = today.daysInMonth();
	var offset = today.getDay(); // 0-6

	out = "<div class=\"miniCalTitle\"><div id=\"grippy\"><div style=\"width: 82%; border: 0px solid #000000; float: left; padding: 0 5px;\" onmousedown=\"engage('miniCalendarDiv');\" onmouseup=\"release();\">Select a date</div><a href=\"#\" onclick=\"hide('miniCalendarDiv'); return false\" title=\"Close calendar\">X</a><div style='clear: both;'></div></div>"
		+ "<a href=\"#\" style=\"float: left\" onclick=\"showDateSelector('', '" + outputElId + "'," + month + ", " + (year - 1) + ", '" + dateFormat + "'); return false\">&laquo;</a> "
		+ "<a href=\"#\" style=\"float: left\" onclick=\"showDateSelector('', '" + outputElId + "'," + (month - 1) + ", " + year + ", '" + dateFormat + "'); return false\">&lt;</a>"
		+ "<a href=\"#\" style=\"float: right\" onclick=\"showDateSelector('', '" + outputElId + "'," + month + "," + (year + 1)+ ", '" + dateFormat + "'); return false\">&raquo;</a>"
		+ "<a href=\"#\" style=\"float: right\" onclick=\"showDateSelector('', '" + outputElId + "'," + (month + 1) + "," + year + ", '" + dateFormat + "'); return false\">&gt;</a>"
		+ today.getMonthStr() + " " + year
		+ "</div>";

	out += "<table width=\"100%\">\n";
	for (var i = 0; i < 7; i++) out += "<col width=\"14%\">\n";
	out += "<thead><tr><th>" + ['S','M','T','W','T','F','S'].join("</th><th>") + "</th></tr></thead><tbody><tr>";

	for (var i = 0; i < offset; i++) {
		out += "<td class=\"empty\">&nbsp;</td>";
	}

	var dayOffset, thisDate;
	for (var i = 1; i <= daysInMonth; i++) {
		thisDate = new Date(year, month, i);
		dayOffset = thisDate.getDay();
		if (i != 1 && dayOffset == 0) out += "<tr>";
		out += "<td onmouseover=\"this.className='hovered'\" onmouseout=\"this.className=''\" onclick=\"selectDate('" + outputElId + "','" + thisDate.phpDate(dateFormat) + "')\">" + i + "</td>";
		if (i != daysInMonth && dayOffset == 6) out += "</tr>\n";
	}

	while (dayOffset++ < 6) out += "<td class=\"empty\">&nbsp;</td>";

	out += "</tr></tbody></table>";
	div.innerHTML = out;
	show(div);
}

function selectDate(what, x) {
	hide('miniCalendarDiv');
	var el = getElement(what);
	if (el) el.value = x;
	else alert ("Error accessing element: '" + what + "'");
}

function createMiniCalDiv() {
	var div = document.createElement('div');
	div.id = "miniCalendarDiv";
	div.style.position = "absolute";
	document.body.appendChild(div);
	return div;
}

/*
Jonas Raoni Soares Silva
http://www.joninhas.ath.cx
*/
function shuffle(o) {
	for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
	return o;
}


/* cookie stuff - http://www.quirksmode.org/js/cookies.html */

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 var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name)
{
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++)
	{
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

function eraseCookie(name)
{
	createCookie(name,"",-1);
}

/**
 *	Use this function to add events to elements.
 *	Most useful when you don't know if an element already has an
 *  event, or if it does, and you don't want to override the
 *	existing function.
 *
 *	Usage:
 *	addEvent(element, eventname, function);
 *	ie:
 *	addEvent(document.body, "onload", function() { alert("Hello world"); } );
 *  addEvent(document.body, "onload", function() { alert("Hello world again!"); } );
 */
function addEvent(oTarget, sType, fpDest) {
  var oOldEvent = oTarget[sType];
  if (typeof oOldEvent != "function") {
    oTarget[sType] = fpDest;
  } else {
    oTarget[sType] = function(e) {
      oOldEvent(e);
      fpDest(e);
    }
  }
}

function playSound(soundURL) {
	alert ("play sound");
	var el = getElement('soundElement');
	if (el) {
		var embed = el.getElementsByTagName("embed")[0];
		if (embed.play) {
			embed.src = soundURL;
			embed.play();
		} else {
			el.innerHTML= "<embed src='"+soundURL+"' hidden=\"true\" autostart=\"true\" loop=\"false\" type=\"audio/x-wav\" />";
		}
	} else {
		el = document.createElement('div');
		el.id = 'soundElement';
		//el.style.display = 'hidden';
		el.style.position = 'absolute';
		el.style.top = '0';
		el.innerHTML= "<embed src='"+soundURL+"' hidden=\"true\" autostart=\"true\" loop=\"false\" type=\"audio/x-wav\" />";
		document.body.appendChild(el);
	}
}

/***********************************************************************************
				alerts system - pulse text in a fancy red fashion
***********************************************************************************/

function notifyOn(element) {
	notifyIds.push(element);
	checkPulse();
}
function notifyOff(element, replacementHTML) {
	var el = getElement(element);
	if (replacementHTML) {
		el.innerHTML = replacementHTML;
	}
	for (var i = 0; i < notifyIds.length; i++) {
		if (notifyIds[i] == element) { 
			notifyIds.splice(i, 1); 
			break;
		}
	}
	el.style.color = '';
	el.style.fontWeight = 'normal';
}

var notifyPulseId;				//interval id
var notifyIds = new Array();	//array of elements to pulse
var pulseColor = 0x000000;		//start color
var pulseChange = 0x080101;		//color increment
function elementPulse() {
	if (pulseColor + pulseChange >= 0xFF4444 || pulseColor + pulseChange <= 0) {
		pulseChange *= -1;
	}
	pulseColor += pulseChange;
	var e;
	for (var i = 0; i < notifyIds.length; i++) {
		if ((notifyIds[i] != '') && (e = getElement(notifyIds[i]))) {
			e.style.color = toHexStr(pulseColor);
			e.style.fontWeight = "bold";
		}
	}
}
function toHexStr(d) {
	var hD = "0123456789ABCDEF";
	var h = hD.substr(d & 15, 1);
	while (d > 15) {
		d >>= 4;
		h = hD.substr(d & 15, 1) + h;
	}
	while (h.length < 6) h = "0"+h;
	return "#" + h;
}
function checkPulse() {
	if (notifyPulseId == null) {
		notifyPulseId = setInterval('elementPulse()', 5);
	}
}

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

//submit a form using a button but replace that button's text with a pretty spinny image while uploading takes place
function doUpload(butt, form) {
	butt.disabled = true;
	// butt.innerHTML = '&nbsp; <img src="images/button-loader.gif"> &nbsp; ';
	form.submit();
}
loadingImg = new Image();
loadingImg.src = "images/button-loader.gif";	//this just preloads it so it will actually show

//this hack seems to be needed for every page now if you want to use select boxes or select text at all. WTF!?!?!?
//GOD DAMN YOU MICROSOFT WHY DO YOU HATE US
IEHackRelease();


