/*===================================================================================
// filename:      mini_api.js
// last update:   23 July 2002 by Daniel Pupius <www.pupius.co.uk>
// description:   Abstracts certain interactions with the browser.  All functions
//                are compatible with version 4 browsers and up, but some effects
//                and functionality will be lost in the earlier browsers.
// rights:        copyright &copy;2002-2004 Daniel Pupius <www.pupius.co.uk>
//===================================================================================
                                          [Based on the 13thAPI @ 13thparallel.org] */

//object constructor for MiniApi DHTML library
var MA = {

	//=========================================================================================================
	// SUPPORT FUNCTIONS (used by the higher-level functions to access the various browser's DOM)
	//=========================================================================================================


				//Crossbrowser code to grab an id-based dom object
	getElement:		function(id) {
				  var el = null;
				  if(document.getElementById && document.getElementById(id)) el = document.getElementById(id);	//DOM based browsers
				  else if(document.all && document.all[id]) el =  document.all[id];			//Internet Explorer 4

				  if(el || navigator.appVersion.indexOf("MSIE")>-1) return el;							//we found the element
				  else return MA.find(id);
				},


				//Crossbrowser code to grab the styles for an id-based dom object
	getStyles:		function(id) {
				  if(!MA.getElement(id)) {
					  alert("ERROR in MA.getStyles: Can not find [" + id + "]");
					  return null;
				  }

				  if(document.getElementById || document.all) return MA.getElement(id).style;	//DOM based browsers
				  else if(document.layers) return MA.find(id);				//Netscape 4
				  else return null;							//Other browsers
				},



				// A function by: Michael van Ouwerkerk,  February 9 2002,  Updated for frames capability at March 19, 2002
				// find takes an id string as argument and returns a js reference to the image.
				// This method is used primarily for Netscape 4, to automatically find images that are nested in layers.
				// It can now also find an image in a frame, if the frame's name is given in the function call.
				// Example: MA.find('imgMinimalsm', 'mainFrame')
				// UPDATED ON 18/11/2003 BY DAN PUPIUS: Now will find elements in DOM browsers using the name property.
				// previously, Netscape 7 and Mozilla couldn't find anchors, forms or input fields using getElementById("name").
	find:			function(id,frame,parent) {
					var element = null;

					if(!parent) {
						if(frame && top[frame]) parent = top[frame].document;
						else parent = document;
						if(!parent) return null;
					}


					//try to find the element in IE4
					if(document.all && document.all[id]) element = document.all[id];


					//DOM browsers
					else if(document.getElementById && document.getElementById("id")) element = document.getElementById("id");


					//netscape 4
					else if(parent.layers) {
						element = parent.layers[id];
						if(!element) element = parent.links[id];
						if(!element) element = parent.images[id];
						if(!element) element = parent.anchors[id];
						if(!element) element = parent.embeds[id];


					//DOM browsers (for example Netscape 7) that don't support a getElementById call on a "name" property
					} else if (parent.childNodes) {
						for(var i=0;i<parent.childNodes.length&&!element;i++) {
							if(parent.childNodes[i].id == id || parent.childNodes[i].name == id) element = parent.childNodes[i];
						}
					}

					//recurse on sub-layers to find element
					if(parent.layers) var elements = parent.layers;
					else if(parent.childNodes) var elements = parent.childNodes;
					else var elements = new Array();

					for (var i=0;!element && i<elements.length; i++){
						if(elements[i].document) var newparent = elements[i].document;
						else var newparent = elements[i];
						element = MA.find(id, null, newparent);
					}

					return element;
				},

	findImg:		function(id, frame, d) {
				  var img = null;
				  if (!d) {
				    if (frame && top[frame]) d = top[frame].document;
				    else d = document;
				    if (!d) return null;
				  }
				  if (d.images) img = d.images[id];
				  else if (d.getElementById) img = d.getElementById(id);
				  for (var i=0; !img && d.layers && i<d.layers.length; i++){
				    img = MA.findImg(id, null, d.layers[i].document);
				  }
				  return img;
				},


				//returns the x position of a layer
	x:			function(id) {
				  return parseInt(MA.getStyles(id).left);
				},

				//returns the y position of a layer
	y:			function(id) {
				  return parseInt(MA.getStyles(id).top);
				},

				//returns the width of a layer (as specified in the style-sheet or style-tag)
	w:			function(id) {
				  return parseInt(MA.getStyles(id).width);
				},

				//returns the height of a layer (as specified in the style-sheet or style-tag)
	h:			function(id) {
				  return parseInt(MA.getStyles(id).height);
				},



	//=========================================================================================================
	// BASIC FUNCTIONS (a set of simple functions to manipulate layers)
	//=========================================================================================================

				//moves a layer to a specific screen coordinate
	moveTo:			function(id,x,y) {
				  if(document.getElementById) var unit = "px";
				  else var unit = 0;

				  x = parseInt(x);
				  y = parseInt(y);

				  if(!isNaN(x)) MA.getStyles(id).left = x + unit;
				  if(!isNaN(y)) MA.getStyles(id).top = parseInt(y) + unit;
				},

				//clips a layer to specific dimentions
	clipTo:			function(id,x,y,w,h) {
				  if(document.getElementById) var unit = "px";
				  else var unit = 0;

				  if(document.layers) {
				    MA.getStyles(id).clip.top = y;
				    MA.getStyles(id).clip.left = x;
				    MA.getStyles(id).clip.bottom = y+h;
				    MA.getStyles(id).clip.right = x+w;
				  } else
				    MA.getStyles(id).clip="rect("+y+unit+" "+(x+w)+unit+" "+(y+h)+unit+" "+x+unit+")";
				},

	resizeTo:			function(id,w,h) {
				  if(document.getElementById) var unit = "px";
				  else var unit = 0;

				  MA.getStyles(id).height =  parseInt(h) + unit;
				  MA.getStyles(id).width =  parseInt(w) + unit;
				},

				//moves a layer to by a specific number of units
	moveBy:			function(id,x,y) {
				  if(document.getElementById) var unit = "px";
				  else var unit = 0;

				  MA.getStyles(id).left = (MA.x(id) + x) + unit;
				  MA.getStyles(id).top = (MA.y(id) + y) + unit;
				},

				//shows a layer (with the optional ability to fade between states)
	show:			function(id, fade) {
				  var ie55 = (navigator.appVersion.indexOf("MSIE 5.5")>-1 && document.getElementById && !navigator.userAgent.indexOf("Opera")>-1 )?1:0;
				  var ie6 = (navigator.appVersion.indexOf("MSIE 6")>-1 && document.getElementById && !navigator.userAgent.indexOf("Opera")>-1 )?1:0;

				  if((ie55 || ie6) && fade) {
				    MA.getStyles(id).filter = "progid:DXImageTransform.Microsoft.Fade(duration=" + fade + ")";
				    MA.getElement(id).filters[0].apply();
				    MA.getStyles(id).visibility = "visible";
				    MA.getElement(id).filters[0].play();
				  } else {
				    MA.getStyles(id).visibility = "visible";
				  }
				},

				//hides a layer
	hide:			function(id, fade) {
				  if(fade=="") fade=0;
				  var ie55 = (navigator.appVersion.indexOf("MSIE 5.5")>-1 && document.getElementById && !navigator.userAgent.indexOf("Opera")>-1 )?1:0;
				  var ie6 = (navigator.appVersion.indexOf("MSIE 6")>-1 && document.getElementById && !navigator.userAgent.indexOf("Opera")>-1 )?1:0;

				  if((ie55 || ie6) && fade) {
				    MA.getStyles(id).filter = "progid:DXImageTransform.Microsoft.Fade(duration=" + fade + ")";
				    MA.getElement(id).filters[0].apply();
				    MA.getStyles(id).visibility = "hidden";
				    MA.getElement(id).filters[0].play();
				  } else {
				    MA.getStyles(id).visibility = "hidden";
				  }
				},

				//toggles the visibility
	toggle:			function(id, fade) {
				  if(!fade) var fade = 0;
				  if(MA.getStyles(id).visibility == "" || MA.getStyles(id).visibility == "inherit" || MA.getStyles(id).visibility == "show" || MA.getStyles(id).visibility == "visible") MA.hide(id, fade);
				  else MA.show(id, fade);
				},

				//changes the background colour of a layer
	bgColor:		function(id,c) {
				  if(document.layers) MA.getStyles(id).bgColor = c;
				  else MA.getStyles(id).backgroundColor = c;
				},

				//changes the foreground colour of a layer
	color:			function(id,c) {
				  MA.getStyles(id).color = c;
				},



	//=========================================================================================================
	// TIMESLIDE (Moves a layer between 2-points over a specified duration)
	//=========================================================================================================

	moves:			new Array(),
	cancelMoves:		new Array(),
	moving:			new Array(),

	timeSlide:		function(id,x,y,duration,acc2,func2,cancel,timeout) {

					//clean up input - added by MU 23/10/02
					x = parseInt(x);
					y = parseInt(y);
					duration = parseInt(duration);
					acc = parseFloat(acc);
					//end clean up input
				  if(!cancel) var cancel = false;
				  if(!func) var func = "null";
				  if(!timeout) var timeout = 5;
				  if(!acc) var acc = 0;

				  if(!MA.moves[id]) MA.moves[id] = new Array();
				  if(!MA.cancelMoves[id]) MA.cancelMoves[id] = false;
				  if(!MA.moving[id]) MA.moving[id] = false;

				  var startTime = new Date().valueOf();
				  var endTime = startTime + duration;

				  if(!MA.moving[id]) {	//object isn't already moving so start animation
				    MA.moving[id] = true;
				    MA.timeSlideAux(id,MA.x(id),MA.y(id),x,y,acc2,startTime,endTime,func2,cancel,timeout);
				  } else {
				    if(cancel) {		//cancel other moves
				      MA.cancelMoves[id] = true;
				      MA.moves[id] = new Array();
				    }

				    //add this movement to array of movements
				    var strExec = "MA.timeSlide('" + id + "'," + x + "," + y + "," + duration + "," + acc2 + ",'" + func2 + "'," + cancel + "," + timeout + ")";
				    MA.moves[id].push(strExec);
				  }
				},

	timeSlideAux:		function(id,startX,startY,endX,endY,acc3,startTime,endTime,func3,cancel,timeout) {
				if( navigator.appVersion.indexOf("MSIE") == -1) {
					endTime = endTime + 1;
				}
				  var curTime = new Date().valueOf();
				  if(MA.cancelMoves[id]) {
				    MA.moving[id] = false;
				    MA.cancelMoves[id] = false;
				    if(MA.moves[id][0]) eval(MA.moves[id].shift());

				  } else if(curTime >= endTime) {
				    MA.moveTo(id,endX,endY);
				    MA.moving[id] = false;
				    if(func3) eval(func3);
				    if(MA.moves[id][0]) eval(MA.moves[id].shift());

				  } else {
				    var percent = (curTime - startTime) / (endTime - startTime); //percentage of way through animation
				    var startPos = new MA.coord(1,1);
				    var endPos = new MA.coord(0,0);

				    if(acc3!=0) var c1 = new MA.coord(0.5+(acc3/2),0.5-(acc3/2));
				    else c1 = null;
				    var pos = MA.getBezier(percent,startPos,endPos,c1);
				    var stage = pos.y;

				    MA.moveTo(id,((endX-startX)*stage)+startX,((endY-startY)*stage)+startY);

				    var strExec = "MA.timeSlideAux('" + id + "'," + startX + "," + startY + "," + endX + "," + endY + "," + acc3 + "," + startTime + "," + endTime + ",'" + func3 + "'," + cancel + "," + timeout + ")";
				    setTimeout(strExec,timeout);
				  }
				},



	//=========================================================================================================
	// BEZIER SLIDE (Allows you to moves a layer between 2-points, along a curve over a specified duration)
	//=========================================================================================================

	bezierSlide:		function(id,x,y,c1x,c1y,c2x,c2y,duration,acc,func,cancel,timeout) {
				  if(!cancel) var cancel = false;
				  if(!func) var func = "null";
				  if(!timeout) var timeout = 5;
				  if(!acc) var acc = 0;

				  if(!MA.moves[id]) MA.moves[id] = new Array();
				  if(!MA.cancelMoves[id]) MA.cancelMoves[id] = false;
				  if(!MA.moving[id]) MA.moving[id] = false;

				  var startTime = new Date().valueOf();
				  var endTime = startTime + duration;

				  if(!this.moving[id]) {	//object isn't already moving so start animation
				    MA.moving[id] = true;
				    MA.bezierSlideAux(id,MA.x(id),MA.y(id),x,y,c1x,c1y,c2x,c2y,acc,startTime,endTime,func,cancel,timeout);
				  } else {
				    if(cancel) {		//cancel other moves
				      MA.cancelMoves[id] = true;
				      MA.moves[id] = new Array();
				    }
				    //add this movement to array of movements
				    var strExec = "MA.bezierSlide('" + id + "'," + x + "," + y + "," + c1x + "," + c1y + "," + c2x + "," + c2y + "," + duration + "," + acc + ",'" + func + "'," + cancel + "," + timeout + ")";
				    MA.moves[id].push(strExec);
				  }
				},

	bezierSlideAux:		function(id,startX,startY,endX,endY,c1x,c1y,c2x,c2y,acc,startTime,endTime,func,cancel,timeout) {
				  var curTime = new Date().valueOf();
				  if(MA.cancelMoves[id]) {
				    MA.moving[id] = false;
				    MA.cancelMoves[id] = false;
				    if(MA.moves[id][0]) eval(MA.moves[id].shift());

				  } else if(curTime >= endTime) {
				    MA.moveTo(id,endX,endY);
				    MA.moving[id] = false;
				    if(func) eval(func);
				    if(MA.moves[id][0]) eval(MA.moves[id].shift());

				  } else {
				    var percent = (curTime - startTime) / (endTime - startTime); //percentage of way through animation
				    var startPos = new MA.coord(0,0);
				    var endPos = new MA.coord(1,1);

				    if(acc!=0) var c1 = new MA.coord(0.5-(acc/2),0.5+(acc/2));
				    else c1 = null;
				    var pos = MA.getBezier(percent,startPos,endPos,c1);
				    var stage = pos.y;

				    var startPos = new MA.coord(startX,startY);
				    var endPos = new MA.coord(endX,endY);
				    var c1 = new MA.coord(c1x,c1y);
				    var c2 = new MA.coord(c2x,c2y);
				    var pos = MA.getBezier(stage,startPos,endPos,c1,c2);
				    MA.moveTo(id,pos.x,pos.y);

				    var strExec = "MA.bezierSlideAux('" + id + "'," + startX + "," + startY + "," + endX + "," + endY + "," + c1x + "," + c1y + "," + c2x + "," + c2y + "," + acc + "," + startTime + "," + endTime + ",'" + func + "'," + cancel + "," + timeout + ")";
				    setTimeout(strExec,timeout);
				  }
				},



	//=========================================================================================================
	// TIMECLIP (Clips a layer between 2 sizes)
	//=========================================================================================================

	clips:			new Array(),
	cancelClips:		new Array(),
	clipping:		new Array(),

	timeClip:		function(id,x,y,w,h,duration,acc,func,cancel,timeout) {
				  if(!cancel) var cancel = false;
				  if(!func) var func = "null";
				  if(!timeout) var timeout = 5;
				  if(!acc) var acc = 0;

				  if(!MA.clips[id]) MA.clips[id] = new Array();
				  if(!MA.cancelClips[id]) MA.cancelClips[id] = false;
				  if(!MA.clipping[id]) MA.clipping[id] = false;


				  if(!document.layers) {
				    var c = MA.getStyles(id).clip.split('(')[1].split(' ');
  				    for(var i=0;i<4;i++){ c[i] = parseInt(c[i]); }
				  } else var c = new Array();

				  var ct = MA.getStyles(id).clip.top||c[0]||0;
				  var cr = MA.getStyles(id).clip.right||c[1]||0;
				  var cb = MA.getStyles(id).clip.bottom||c[2]||0;
				  var cl = MA.getStyles(id).clip.left||c[3]||0;

				  var startTime = new Date().valueOf();
				  var endTime = startTime + duration;

				  if(!MA.clipping[id]) {	//object isn't already moving so start animation
				    MA.clipping[id] = true;
				    MA.timeClipAux(id,cl,ct,cr-cl,cb-ct,x,y,w,h,acc,startTime,endTime,func,cancel,timeout);
				  } else {
				    if(cancel) {		//cancel other moves
				      MA.cancelclips[id] = true;
				      MA.clips[id] = new Array();
				    }
				    //add this movement to array of movements
				    var strExec = "MA.timeClip('" + id + "'," + x + "," + y + "," + w + "," + h + ","+ duration + "," + acc + ",'" + func + "'," + cancel + "," + timeout + ")";
				    MA.clips[id].push(strExec);
				  }
				},

	timeClipAux:		function(id,startX,startY,startW,startH,endX,endY,endW,endH,acc,startTime,endTime,func,cancel,timeout) {
				  var curTime = new Date().valueOf();
				  if(MA.cancelClips[id]) {
				    MA.clipping[id] = false;
				    MA.cancelClips[id] = false;
				    if(MA.clips[id][0]) eval(MA.clips[id].shift());
				    if(!document.layers) {
				      window.resizeBy(-2,-2);
				      window.resizeBy(2,2);
			            }

				  } else if(curTime >= endTime) {
				    MA.clipTo(id,endX,endY,endW,endH);
				    MA.clipping[id] = false;
				    if(func) eval(func);
				    if(MA.clips[id][0]) eval(MA.clips[id].shift());
				    if(!document.layers) {
				      window.resizeBy(-2,-2);
				      window.resizeBy(2,2);
			            }

				  } else {
				    var percent = (curTime - startTime) / (endTime - startTime); //percentage of way through animation
				    var startPos = new MA.coord(1,1);
				    var endPos = new MA.coord(0,0);

				    if(acc!=0) var c1 = new MA.coord(0.5+(acc/2),0.5-(acc/2));
				    else c1 = null;
				    var pos = MA.getBezier(percent,startPos,endPos,c1);
				    var stage = pos.y;

				    MA.clipTo(id,((endX-startX)*stage)+startX,((endY-startY)*stage)+startY,((endW-startW)*stage)+startW,((endH-startH)*stage)+startH);

				    var strExec = "MA.timeClipAux('" + id + "'," + startX + "," + startY + "," + startW + "," + startH + "," + endX + "," + endY + "," + endW + "," + endH + "," + acc + "," + startTime + "," + endTime + ",'" + func + "'," + cancel + "," + timeout + ")";
				    setTimeout(strExec,timeout);
				  }
				},


	//=========================================================================================================
	// TIMEReSIZE (Resizes as layer)
	//=========================================================================================================

	resizes:		new Array(),
	cancelResize:		new Array(),
	resizing:		new Array(),

	timeResize:		function(id,w,h,duration,acc,func,cancel,timeout) {
				  if(!cancel) var cancel = false;
				  if(!func) var func = "null";
				  if(!timeout) var timeout = 5;
				  if(!acc) var acc = 0;

				  if(!MA.resizes[id]) MA.resizes[id] = new Array();
				  if(!MA.cancelResize[id]) MA.cancelResize[id] = false;
				  if(!MA.resizing[id]) MA.resizing[id] = false;

				  var startTime = new Date().valueOf();
				  var endTime = startTime + duration;

				  if(!MA.resizing[id]) {	//object isn't already moving so start animation
				    MA.resizing[id] = true;
				    MA.timeResizeAux(id,MA.w(id),MA.h(id),w,h,acc,startTime,endTime,func,cancel,timeout);
				  } else {
				    if(cancel) {		//cancel other moves
				      MA.cancelResize[id] = true;
				      MA.resizes[id] = new Array();
				    }

				    //add this movement to array of movements
				    var strExec = "MA.timeResize('" + id + "'," + w + "," + h + "," + duration + "," + acc + ",'" + func + "'," + cancel + "," + timeout + ")";
				    MA.resizes[id].push(strExec);
				  }
				},

	timeResizeAux:		function(id,startW,startH,endW,endH,acc,startTime,endTime,func,cancel,timeout) {

				  var curTime = new Date().valueOf();
				  if(MA.cancelResize[id]) {
				    MA.resizing[id] = false;
				    MA.cancelResize[id] = false;
				    if(MA.resizes[id][0]) eval(MA.resizes[id].shift());

				  } else if(curTime >= endTime) {
				    MA.resizeTo(id,endW,endH);
				    MA.resizing[id] = false;
				    if(func) eval(func);
				    if(MA.resizes[id][0]) eval(MA.resizes[id].shift());

				  } else {
				    var percent = (curTime - startTime) / (endTime - startTime); //percentage of way through animation
				    var startPos = new MA.coord(1,1);
				    var endPos = new MA.coord(0,0);

				    if(acc!=0) var c1 = new MA.coord(0.5+(acc/2),0.5-(acc/2));
				    else c1 = null;
				    var pos = MA.getBezier(percent,startPos,endPos,c1);
				    var stage = pos.y;

				    MA.resizeTo(id,((endW-startW)*stage)+startW,((endH-startH)*stage)+startH);

				    var strExec = "MA.timeResizeAux('" + id + "'," + startW + "," + startH + "," + endW + "," + endH + "," + acc + "," + startTime + "," + endTime + ",'" + func + "'," + cancel + "," + timeout + ")";
				    setTimeout(strExec,timeout);
				  }
				},



	//=========================================================================================================
	// BEZIER (Used for calculations based on a cubic Bezier curve)
	//=========================================================================================================

	B1:			function(t) { return (t*t*t); },
	B2:			function(t) { return (3*t*t*(1-t)); },
	B3:			function(t) { return (3*t*(1-t)*(1-t)); },
	B4:			function(t) { return ((1-t)*(1-t)*(1-t)); },

	coord:			function (x,y) { if(!x) var x=0; if(!y) var y=0; return {x: x, y: y}; },

	getBezier:		function (percent,startPos,endPos,control1,control2) {
				  //if there aren't any extra control points plot a straight line, if there is only 1
				  //make 2nd point same as 1st

				  if(!control2 && !control1) var control2 = new MA.coord(startPos.x + 3*(endPos.x-startPos.x)/4, startPos.y + 3*(endPos.y-startPos.y)/4);
				  if(!control2) var control2 = control1;
				  if(!control1) var control1 = new MA.coord(startPos.x + (endPos.x-startPos.x)/4, startPos.y + (endPos.y-startPos.y)/4);

				  var pos = new MA.coord();
				  pos.x = startPos.x * MA.B1(percent) + control1.x * MA.B2(percent) + control2.x * MA.B3(percent) + endPos.x * MA.B4(percent);
				  pos.y = startPos.y * MA.B1(percent) + control1.y * MA.B2(percent) + control2.y * MA.B3(percent) + endPos.y * MA.B4(percent);

				  return pos;
				},



	//=========================================================================================================
	// SCHEDULER (Acts like a text based timeline, allowing the user to specify when things happen)
	//=========================================================================================================

	state:			0,
	running:		0,
	nextState:		function() { MA.state++; },
	jumpToState:		function(n) { MA.state=n; },
	jobs:			new Array(),

	schedule:		function(code, time, state) {
				  var thisJob = [code,time,state,false];
				  MA.jobs.push(thisJob);
				  //alert(MA.jobs);
				},
	startScheduler:		function() { MA.running=1; MA.idle(); },
	stopScheduler:		function() { MA.running=0; },
	idle:			function() {
				  if(MA.running) {
				    for(var i=0; i<MA.jobs.length; i++) {
				      if(MA.jobs[i][2] == MA.state && !MA.jobs[i][3]) {
				        MA.jobs[i][3] = true;
				        setTimeout(MA.jobs[i][0],MA.jobs[i][1]*1000);
				      }
				    }
				    setTimeout("MA.idle()",50);
				  }
				},



	//=========================================================================================================
	// COOKIES (Allows you to save and retrieve page settings)
	//=========================================================================================================

	getCookie:		function(name, d) {
				  if (!d) var d = null;
				  var arg = name + "=";
				  var alen = arg.length;
				  var clen = document.cookie.length;
				  var i = 0;
				  while (i < clen) {
				    var j = i + alen;
				    if (document.cookie.substring(i, j) == arg) {
				      var 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 d;
				},

	setCookie:		function(name, value, expires) {
				  if (expires) {
				    var exp = new Date();
				    exp.setTime(exp.getTime() + (expires*60*60*1000));
				    expires = exp;
				  }
				  document.cookie = name + "=" + escape(value) + ((expires == null) ? "" : ("; expires=" + expires.toGMTString()));
				},

	deleteCookie:		function(name) {
				  var exp = new Date();
				  exp.setTime (exp.getTime() - 1000);
				  var cval = MA.getCookie (name);
				  document.cookie = name + "=" + cval + "; expires=" + exp.toGMTString();
	},



	//=========================================================================================================
	// IMAGES (Functions for preloading images, and creating rollovers)
	//=========================================================================================================


	images:			new Array(),		//used to store precached images
	rollovers:		new Array(),		//used to store rollovers

				//preloads image(s)
	preload:		function() {
				  for(var i=0; i<arguments.length; i++) {
				    var img = new Image();
				    img.src = arguments[i];
				    MA.images.push(img);
				  }
				},

				//creates a rollover, events are added to "caller" and affect "target"
	makeRollover:		function(target,caller,onImage) {
				  var offImage = MA.findImg(target).src;
				  MA.preload(onImage,offImage);
				  MA.rollovers[caller] = {target: target, on: onImage, off: offImage};
				  MA.getElement(caller).onmouseover = function() {
				    if(MA.rollovers[this.id]) {
				      MA.findImg(MA.rollovers[this.id].target).src = MA.rollovers[this.id].on;
				    }
				  }
				  MA.getElement(caller).onmouseout = function() {
				    if(MA.rollovers[this.id]) {
				      MA.findImg(MA.rollovers[this.id].target).src = MA.rollovers[this.id].off;
				    }
				  }

				  if(document.layers) {
				    MA.getElement(caller).captureEvents(Event.MOUSEOVER);
				    MA.getElement(caller).captureEvents(Event.MOUSEOUT);
				  }
				},

	imgSwap:		function(target,img) {
				  if(MA.findImg(target)) MA.findImg(target).src = img;
				},


	//=========================================================================================================
	// KEYBOARD EVENT HANDLERS
	//=========================================================================================================

	keys:			new Array(),

	handleKeyPress:		function(e) {
				  if(!e) var e = event;
				  if(!e.target) e.target = e.srcElement;

				  if(!e.target.tagName) {
				    var str = e.target.toString();
				    var space = str.indexOf(" ");
				    var tagName = str.substring(1,space);
				  } else var tagName = e.target.tagName

				  if(tagName.toLowerCase() == "input" || tagName.toLowerCase() == "textarea") return true;

				  //get special key states
				  if(document.layers) {
				    MA.keys["alt"] = (e.modifiers & Event.ALT_MASK)!=0;
				    MA.keys["control"] = (e.modifiers & Event.CONTROL_MASK)!=0;
				    MA.keys["shift"] = (e.modifiers & Event.SHIFT_MASK)!=0;
				  } else {
				    MA.keys["alt"] = e.altKey;
				    MA.keys["control"] = e.ctrlKey;
				    MA.keys["shift"] = e.shiftKey;
				  }

				  var keycode = e.keyCode?e.keyCode:e.which;
				  var letter =  String.fromCharCode(keycode);

				  if(MA.keyEvents[letter] != null) {
				    if(MA.keyEvents[letter].prototype) MA.keyEvents[letter](keycode,letter);
				    else eval(MA.keyEvents[letter]);
				  }

				  return true;
				},

	keyEvents:		new Array(),

	addKeyEvent:		function(key,action) {
				  MA.keyEvents[key] = action;
				},



	//=========================================================================================================
	// GRAPHICS (Draws lines etc.)
	//=========================================================================================================
	drawLine:		function(id,x,y) {




				},



	//=========================================================================================================
	// MISC (Random helper functions)
	//=========================================================================================================

				//Opens a new page in current browser window
	redirect:		function(url) { location=url; },

				//Creates a popup window with options to set the appearance
	popup:			function(filename, title, width, height, x, y,scrollbars,statusbar,resize,toolbar) {
				  if(x=='c') x = (screen.width / 2) - (width / 2);
				  if(y=='c') y = (screen.height / 2) - (height / 2);


				  if(scrollbars == null) scrollbars=1;
				  if(statusbar == null) statusbar=0;
				  if(resize == null) resize=0;
				  if(toolbar == null) toolbar=0;

				  NewWindow = window.open(filename, title, "status="+statusbar+",scrollbars="+scrollbars+",resizable="+resize+",toolbar="+toolbar+",menubar="+toolbar+",width="+width+",height="+height+",left="+x+",top="+y);

				  if(!NewWindow.opener) {
				    NewWindow.opener = self;
				  }
				},

				//returns a random number between x and y (integers)
	rand:			function(x,y) { return (round(Math.random()*(y-x)) + x); },

				//converts degrees to radians and vice versa (used in conjunction with the Math object's trig functions)
	degToRad:		function(x) { return ( x/(360/(2*Math.PI)) ); },
	radToDeg:		function(x) { return ( x*(360/(2*Math.PI)) ); },






	Images:			{
				data:		new Array(),
				buffer:		new Array(),
				preload:	function() {
							for(var i=0;i<MA.Images.data.length;i++) {
								MA.Images.buffer = new Image();
								MA.Images.buffer.src = MA.Images.data[i].url;
								window.status = "Preloading images: " + Math.round(100*i/MA.Images.data.length) + "%   (" + MA.Images.data[i].url + ")";
							}
							window.status = "Preloading images: done";
							setTimeout("window.status = '';",2500);
						},
				getImage:	function(name,state) {
							if(state=="") state="normal";
							var out = new Image();
							for(var i=0;i<MA.Images.data.length&&out.src=="";i++) {
								if(MA.Images.data[i].name==name && MA.Images.data[i].state==state) out.src = MA.Images.data[i].url;
							}
							return out;
						}
				},


	writeText:		function(id,text,w,c) {

						if (document.getElementById) {
							x = document.getElementById(id);
							x.innerHTML = text;
						} else if (document.all) {
							x = document.all[id];
							x.innerHTML = text;
						} else if (document.layers) {
							x = MA.find(id);

							text2 = "<table width=" + w + " border=0 cellpadding=0 cellspacing=0><tr><td class='" + c + "'><span class='" + c + "'>" + text + "</span></td></tr></table>";
							x.document.open();
							x.document.write(text2);
							x.document.close();
						}
				},


	// Flash Version Detector  v1.1.5
	// http://www.dithered.com/javascript/flash_detect/index.html
	// code by Chris Nott (chris@NOSPAMdithered.com - remove NOSPAM)
	// with VBScript code from Alastair Hamilton
	//

	// (MUST BE CALLED WHILE PAGE IS LOADING!!!)
	getFlashVersion:	function() {
					var flashVersion = 0;
					var agent = navigator.userAgent.toLowerCase();


					// NS3+, Opera3+, IE5+ Mac (support plugin array):  check for Flash plugin in plugin array
					if (navigator.plugins != null && navigator.plugins.length > 0) {
						var flashPlugin = navigator.plugins['Shockwave Flash'];
						if (typeof flashPlugin == 'object') {
							if (flashPlugin.description.indexOf('7.') != -1) flashVersion = 7;
							else if (flashPlugin.description.indexOf('6.') != -1) flashVersion = 6;
							else if (flashPlugin.description.indexOf('5.') != -1) flashVersion = 5;
							else if (flashPlugin.description.indexOf('4.') != -1) flashVersion = 4;
							else if (flashPlugin.description.indexOf('3.') != -1) flashVersion = 3;
						}
					}

					// IE4+ Win32:  attempt to create an ActiveX object using VBScript
					else if (agent.indexOf("msie") != -1 && parseInt(navigator.appVersion) >= 4 && agent.indexOf("win")!=-1 && agent.indexOf("16bit")==-1) {
						document.write('<scr' + 'ipt language="VBScript"\> \n');
						document.write('on error resume next \n');
						document.write('dim obFlash \n');
						document.write('set obFlash = CreateObject("ShockwaveFlash.ShockwaveFlash.7") \n');
						document.write('if IsObject(obFlash) then \n');
						document.write('flashVersion = 7 \n');
						document.write('else set obFlash = CreateObject("ShockwaveFlash.ShockwaveFlash.6") end if \n');
						document.write('if flashVersion < 7 and IsObject(obFlash) then \n');
						document.write('flashVersion = 6 \n');
						document.write('else set obFlash = CreateObject("ShockwaveFlash.ShockwaveFlash.5") end if \n');
						document.write('if flashVersion < 6 and IsObject(obFlash) then \n');
						document.write('flashVersion = 5 \n');
						document.write('else set obFlash = CreateObject("ShockwaveFlash.ShockwaveFlash.4") end if \n');
						document.write('if flashVersion < 5 and IsObject(obFlash) then \n');
						document.write('flashVersion = 4 \n');
						document.write('else set obFlash = CreateObject("ShockwaveFlash.ShockwaveFlash.3") end if \n');
						document.write('if flashVersion < 4 and IsObject(obFlash) then \n');
						document.write('flashVersion = 3 \n');
						document.write('end if');
						document.write('</scr' + 'ipt\> \n');
					}

					// WebTV 2.5 supports flash 3
					else if (agent.indexOf("webtv/2.5") != -1) flashVersion = 3;

					// older WebTV supports flash 2
					else if (agent.indexOf("webtv") != -1) flashVersion = 2;

					// Can't detect in all other cases
					else {
					flashVersion = flashVersion_DONTKNOW;
					}

					return flashVersion;
				}

}


if(window.Event) document.captureEvents(Event.KEYPRESS);
document.onkeypress = MA.handleKeyPress;


//overwrite MA.hide and MA.show for IE5.5 - just incase they have that weird bug
var ie55 = (navigator.appVersion.indexOf("MSIE 5.5")>-1 && document.getElementById && !navigator.userAgent.indexOf("Opera")>-1 )?1:0;
if(ie55) {
	eval("MA.show=function(id,fade){if(fade) { try{MA.getStyles(id).filter = 'progid:DXImageTransform.Microsoft.Fade(duration=' + fade + ')';MA.getElement(id).filters[0].apply();MA.getStyles(id).visibility = 'visible';MA.getElement(id).filters[0].play();} catch(er) {MA.getStyles(id).visibility = 'visible';} } else {MA.getStyles(id).visibility = 'visible';}}");
	eval("MA.hide=function(id,fade){if(fade) { try{MA.getStyles(id).filter = 'progid:DXImageTransform.Microsoft.Fade(duration=' + fade + ')';MA.getElement(id).filters[0].apply();MA.getStyles(id).visibility = 'hidden';MA.getElement(id).filters[0].play();} catch(er) {MA.getStyles(id).visibility = 'hidden';} } else { MA.getStyles(id).visibility = 'hidden'; }}");
}


//============================================================================================================
// EXTRA ARRAY PROTOTYPES (Since some browsers don't have all the Array functions, we need to add them here)
//============================================================================================================

// Internet Explorer 5 didn't have Push, Pop and Shift so here we create them.
// Split and Join are normally supported by every DHTML capable browser,
// but they were broken in IE5/MacOSX, madness.

// push appends new elements to an array, and returns the new length
if (Array.prototype && !Array.prototype.push) {
	Array.prototype.push = function() {
		for (var i=0; i<arguments.length; i++) this[this.length] = arguments[i];
		return this.length;
	};
}

// pop removes the last element from an array and returns it
if (Array.prototype && !Array.prototype.pop) {
	Array.prototype.pop = function() {
		var lastitem = this.length > 0 ? this[this.length - 1] : undefined;
		if (this.length > 0) this.length--;
		return lastitem;
	};
}

// shift removes the first element from an array and returns it
if (Array.prototype && !Array.prototype.shift) {
	Array.prototype.shift = function() {
		var firstitem = this.length > 0 ? this[0] : undefined;
		for (var i=0; i<this.length-1; i++) this[i] = this[i + 1];
		if (this.length > 0) this.length--;
		return firstitem;
	};
}

// join returns a string value consisting of all the elements of an array
// concatenated together and separated by the separator argument
if (Array.prototype && !Array.prototype.join) {
	Array.prototype.join = function(separator) {
		if (typeof separator != "string") separator = ",";
		var s = "";
		for (var i=0; i<this.length; i++) {
			if (this[i] != null && this[i] != undefined) s += this[i];
			if (i != this.length - 1) s += separator;
		}
		return s;
	};
}
function printMe()
   {
   window.print();
   }