/* eibJS version 1 - generated on 20.3.2008 */
function Ajax(e, q, o) {	
	this.portFix = Ajax.Init.PortFix; // Use the port fix for Safari that adds in port numbers to the absolute URL
	if (e) {
		this.set(e, q, o);
	}
}


Ajax.prototype.set = function(e, q, o) {
	if (typeof o === "string") {
		o = {"canvas": o};
	} else {
		o = o || {};
	}
	// Initialise and reset all parameters
	this.engine			= Ajax.getId();
	this.url			= window.location.href;	// Url to call (defaults to current page Url
	this.param			= "";					// Parameters for Url or post
	this.json			= o.json || Ajax.Init.Json;		// Default Json translation from the response or set auto Json conversion on or off
	this.response		= null;					// The Xhr response
	this.submit			= null;					// Fallback button to submit the form
	this.submitForm		= null;					// The form that contains the submit button
	this.cache			= o.cache || Ajax.Init.Cache;	// Cache Ajax responses
	this.cached			= false;				// Flag that tells you if the response is from the cache or not
	this.timing			= {duration: o.timeout || Ajax.Init.Duration,	// Time to wait before giving up (in seconds)
						   timer: null,		// The timeout counter
						   expired: false};	// Flag for the response timeout
	this.retry			= {count: 0,
						   limit: o.retry || Ajax.Init.Retry};
	this.setMethod(o.method);

	// If the ajax object is set again, reset the current request back to default values
	if (this.request) {
	    var cc = this.complete;
	    this.complete = null;   // ..temporarily void the complete function;
	                            // firefox 2 fires a readyState change on abort()..

		if(this.request.readyState != Ajax.ReadyState.Complete) this.request.abort();
		this.request = null;

		this.complete = cc;     // ..reinstate complete function..
	} else {
		this.request = null;
	}

	// Setup canvas, if it can't find it on the page, give a warning
	if (o.canvas) {
		if (typeof c === "object") {
			this.canvas = c;
		} else {
			this.canvas = document.getElementById(o.canvas);
			if (!this.canvas) {
				Ajax.log("Canvas specified was not found, defaulting adding a canvas to the document body");
				this.canvas = document.createElement("div");
				document.body.appendChild(this.canvas);
				this.canvas = document.body;
			}
		}
	} else {
		Ajax.log("Canvas was not specified");
	}

	// Setup the Url to call and determine the fallback for link or postback
	if (typeof e === "object") {
		this.url = e.href;
	} else if (typeof e === "string") {
		this.url = e;
	}

	if (this.portFix) {
		// Removes :80 from unsecure url and :443 from SSL for Safari
		this.url = this.url.replace(/:80|:443/, "");
	}

	// Check the Url and split up the params from the actual Url
	var qIndex = this.url.indexOf("?");
	if (qIndex != -1) {
		// Add the parameters
		this.addParam(this.url.substr(qIndex + 1));

		// Now replace the Url
		this.url = this.url.substr(0, qIndex + 1);
	}

	// Add the q to the param
	this.addParam(q);
}


Ajax.prototype.setMethod = function(m) {	
	this.method = (m && m.toUpperCase() == Ajax.Method.Post) ? Ajax.Method.Post : Ajax.Method.Get;
};


Ajax.prototype.get = function() {		
	// Check the cache and use value and don't use Xhr
	if (this.cache) {
		this.response = Ajax.Cache.get(this.addUrlParam(this.url, this.param));	
		if (this.response) {
			this.cached = true;
			this.complete();
			return false;
		} 
	} 

	Ajax.log(this.engine + " - Setup successful XHR");
	Ajax.log(this.engine + " - Url = " + this.url);
	Ajax.log(this.engine + " - Parameters = " + this.param);

	// Start the Ajax request
	this.connect();
};


Ajax.prototype.connect = function() {
	// Show object to privileged function
	var o = this;

	// Get the Xhr, if there isn't one then fallback
	if (!this.request) {
		this.request = Ajax.Xhr();
	}
	if (!this.request) { return this.fallback(); }

	// Setup Xhr request parameters
	this.request.open(this.method, this.addUrlParam(this.url, this.param), true);
	this.request.setRequestHeader("If-Modified-Since", "Wed, 02 Nov 2006 00:00:00 GMT");
	this.request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
	this.request.setRequestHeader("Connection", "close");

	// Set up readystate change
	this.request.onreadystatechange = function() {
		o.loader.call(o);
	};

	if (this.method == Ajax.Method.Post) {
		this.request.send(this.param);
	} else {
		this.request.send(null);
	}	
	
	if (!this.timing.timer && this.timing.duration > 0) {
		Ajax.log(this.engine + " - Setup the timer, duration = " + this.timing.duration + "s");
		this.timing.timer = window.setTimeout(function() {
			Ajax.log(o.engine + " - The request has been aborted");
			o.request.abort();
			o.timing.expired = true;
			window.clearTimeout(o.timing.timer);
			o.timing.timer = null;

			// Clean up for IE
			delete o.request;
			o.request = null;
			o.timeout();
			
			// Setup the retries
			o.retry.count++;
			if (o.retry.count <= o.retry.limit) {
				o.connect();
			}
		}, this.timing.duration * 1000);
	}

	// Use here because or differing browser ready states
	this.busy();
};


Ajax.prototype.loader = function() {
	Ajax.log(this.engine + " - Ready state = " + this.request.readyState);
	// Updated version from YUI to replace my use of the try/catch around the entire method
	var httpStatus;
	try {
		if (this.request.status !== undefined && this.request.status !== 0) {
			httpStatus = this.request.status;
		} else {
			httpStatus = Ajax.Status.MOZ_Unavailable;
		}
	}
	catch(e){
		// 13030 (Ajax.Status.MOZ_Unavailable) is the custom code to indicate the condition - it can throw this error: Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIXMLHttpRequest.status]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame 
		httpStatus = Ajax.Status.MOZ_Unavailable;
	}

	if (!this.timing.expired && this.request.readyState == Ajax.ReadyState.Complete && httpStatus != Ajax.Status.Empty) {
		Ajax.log(this.engine + " - Request status = " + httpStatus);
		//Ajax.logl(this.request.responseText); //May something break with large text
		window.clearTimeout(this.timing.timer);
		this.timing.timer = null;

		// Make sure that the HTTP status code in a successful one by checking that it begins with the number 2
		if (httpStatus.toString().charAt(0) === "2" || httpStatus == Ajax.Status.MSIE_OK || httpStatus == Ajax.Status.Found || httpStatus == Ajax.Status.SeeOther) {
			// If the response is found or cached
			this.response = this.request.responseText;
			// Assign the Json to the response 
			if (this.json) {
				this.response = this.getJson();
			}
			// Set the cache
			if (this.cache) {
				Ajax.Cache.set(this.addUrlParam(this.url, this.param), this.response);
			}
			// NEW
			this.retry = 0;

			// Do the complete callback
			this.complete();
		} else if(httpStatus == Ajax.Status.Found || 
				  httpStatus == Ajax.Status.NotFound || 
				  httpStatus == Ajax.Status.ServerError ||
				  httpStatus == Ajax.Status.MOZ_Unavailable) {
			// If the response is errored or not found
			this.error();
		} else {
			// If it's something we weren't expecting
			this.fallback();
		}
	}
};

// * Add and encode parameters to the parameter collection
// * ----------------------------------------------------------------------
// p (string|object(Json) - can use a string value as param name, or pass in a single Json array
// v (string) - if p is a single parameter name, v is its value (optional)
// Eg addParam({"ajax": "true"});
// Eg addParam("ajax", "true");
// Eg addParam("ajax=true");
Ajax.prototype.addParam = function(p, v) { 
	this.param = Core.Url.addParam(p, v, this.param);
};

// * Remove a parameter from the collection
// * ----------------------------------------------------------------------
// p (string) - the parameter to remove
Ajax.prototype.removeParam = function(p) {
	this.param = Core.Url.removeParam(p, this.param);
};





Ajax.prototype.addUrlParam = function(url, p) {
	if (!p) { return url; }
	if (url.indexOf("?") === -1) {
		if (p.charAt(0) === "&") {
			p = p.substring(1);
		}
		return url + "?" + p;
	} else {
		if (p.charAt(0) === "&") {
			p = p.substring(1);
		}
		return url + p;
	}
};

// * Enable or disable caching of ajax object
// * ---------------------------------------------------------------------
// b (bool) - whether to enable caching
Ajax.prototype.setCache = function(s) {
	this.cache = s;
};

// * Set timeout
// * ----------------------------------------------------------------------
// t (int) - timeout wait in seconds, 0 is infinate (timeout is not ten set)
Ajax.prototype.setTimeout = function(t) {
	this.timing.duration = t;
};

// * Set auto Json
// * ----------------------------------------------------------------------
// b (bool) - to use auto Json or not
Ajax.prototype.setJson = function(b) {
	this.json = b;
};

// * Tells you if the response if from the cache or server
// * ----------------------------------------------------------------------
Ajax.prototype.isCached = function() {
	return this.cached;
};

// * Setup the form fallback
// e (object) - the form button to submit the page
Ajax.prototype.setFallback = function(e, f) {
	this.submit = (typeof e === "string") ? document.getElementById(e) : e;
	if (f) {
		this.submitForm = (typeof f === "string") ? document.getElementById(f) : f;
	}
};

// * Convert the Xhr response to json form
// * ----------------------------------------------------------------------
// s (string) - Json data (optional)
Ajax.prototype.getJson = function(s) {
	// If not using own Json string, use the one returned by the Xhr
	return Ajax.toJson((!s) ? this.response : s);
};

// * Busy actions
Ajax.prototype.busy = function() {
	Ajax.log(this.engine + " - Ajax request now in progress");
};

// * Complete actions
Ajax.prototype.complete = function() {
	Ajax.log(this.engine + " - Ajax request has been completed");
	this.canvas.innerHTML = this.response;
};

// * Error actions - if Json fails or a server error / bad response
Ajax.prototype.error = function() {
	Ajax.log(this.engine + " - There has been a problem loading Ajax content");
	//this.fallback();  // [2008-12-17, KS] Removed
};

// * Timeout actions - if the server response takes too long
Ajax.prototype.timeout = function() {
	Ajax.log(this.engine + " - The server response has timed out");
	//this.fallback();  // [2008-12-17, KS] Removed
};

// * Fallback action - attempt to submit the form 
Ajax.prototype.fallback = function() {
	Ajax.log(this.engine + " - Ajax fallback");
	if (this.submit) {
		var submitForm = document.forms[0];
		if (this.submitForm) {
			submitForm = this.submitForm;
		}
		if (submitForm.action.indexOf("?") > -1) {
			submitForm.action += "&";
		} else {
			submitForm.action += "?";
		}
		// This will pick up image button clicks
		submitForm.action += this.submit.id + ".x=true";
		submitForm.submit();
	} else {
		window.location = this.url;
	}
};

// * Setup "constants" - denoted by capital case
// * ----------------------------------------------------------------------

Ajax.Init = {
	Duration: 8,
	MaxLength: 10,
	Retry: 1,
	Cache: true,
	Json: false, // Alwasys use Json when response has been received
	PortFix: false, // Detect and remove the port numbers Safari puts into absolute URLs
	HistoryController: function(key, value) {} // Default handler for the Ajax history listener
};


Ajax.Method = { 
	Get: "GET",
	Post: "POST"
};


Ajax.ReadyState	= { 
	Uninitialised: 0,
	Loading: 1,
	Loaded: 2,
	Interactive: 3,
	Complete: 4 
};


Ajax.Status = { 
	Empty: 0,
	OK: 200,
	Created: 201,
	Accepted: 202,
	NoContent: 204,
	MovedPermanently: 301,
	Found: 302,
	SeeOther: 303,
	NotModified: 304,
	BadRequest: 400,
	Unauthorized: 401,
	Forbidden: 403,
	NotFound: 404,
	MethodNotAllowed: 405,
	RequestTimeout: 408,
	Gone: 410,
	ServerError: 500,
	MOZ_Unavailable: 13030,
	MSIE_OK: 1223,
	MSIE_RequestTimeout: 12002,
	MSIE_DroppedConnection: 12029,
	MSIE_DroppedConnection: 12030,
	MSIE_DroppedConnection: 12031,
	MSIE_ConnectionClosedByServer: 12152
};


Ajax.request = function(e, q, complete, busy) {
	var ajax = new Ajax(e, q);
	if (typeof complete  === "function") {
		ajax.complete = complete;
	}
	if (typeof busy === "function") {
		ajax.busy = busy;
	}
	ajax.get();
	return ajax;
};


Ajax.queue = function(requests, callback) {
	// TODO
};


Ajax.Cache = {
	maxLength: Ajax.Init.MaxLength,
	length: 0,
	hash: [],
	
	setMaxLength: function(l) {
		this.maxLength = l;
	},
	
	set: function(k, data) {
		if (this.hash[k]) {
			Ajax.log("Cache exists - " + k);
			return false;
		} else {
			// Check that the cache item does not exceed the limit
			if (this.maxLength && this.Length == this.maxLength) {
				for (var j in this.hash) {
					this.length--;
					if (this.length == (this.maxLength - 1)) {
						Ajax.log("Popping from the cache - " + j);
						delete this.hash[j];
						break;
					}
				}
			} 
			Ajax.log("Cache adding new - " + k);
			this.hash[k] = data;
			this.length++;
			return true;
		}
	},
	
	get: function(k) {
		var data = this.hash[k];
		if (data) { 
			Ajax.log("Cache exists - " + k);
			return data;
		} else {
			Ajax.log("Cache does not exist - " + k);
			return null;
		}
	},
	
	remove: function(k) {
		var status = false; // True if found and removed, false if not found
		for (var i in this.hash) {
			if (i == k) {
				Ajax.log("Popping from the cache - " + j);
				delete this.hash[j];
				status = true;
				break;
			}
		}
		return status;
	},
	
	empty: function() {
		this.hash = [];
	}
};


Ajax.getId = function() { 
	var d = new Date();
	return d.getMinutes() + d.getSeconds() + Math.floor(Math.random() * 7);
};


Ajax.Xhr = function() {
	var xhr;
	try {
		xhr = new XMLHttpRequest;
		Ajax.Xhr = function() {
			return new XMLHttpRequest;
		};
	}
	catch(e) {
		var msxhr = [
			"MSXML2.XMLHTTP.3.0",
			"MSXML2.XMLHTTP",
			"Microsoft.XMLHTTP"
		];
		for (var i = 0, c = msxhr.length; i < c; i++) {
			try {
				xhr = new ActiveXObject(msxhr[i]);
				Ajax.Xhr = function() {
					return new ActiveXObject(msxhr[i]);
				};
				break;
			}
			catch(e) {}
		}
	}
	return xhr;
};


Ajax.toJson = function(s) {
	return Core.Json.parse(s);
};


Ajax.log = function(o, t) { 
	if (o.canvas) {
		o.canvas.innerHTML += t + "<br />";
	} else {
		var content = document.getElementById("ajax-console");
		if (!content) {
			content = document.createElement("div");
			content.id = "ajax-console";
		}
		content.innerHTML += t + "<br />";
	}
};


Ajax.getReadyState = function(s) {
	for (var i in Ajax.ReadyState) {
		if (s == Ajax.ReadyState[i]) {
			return i;
		}
	}
};


Ajax.getStatus = function(s) {
	for (var i in Ajax.Status) {
		if (s == Ajax.Status[i]) {
			return i;
		}
	}
};


Ajax.Access = {
	enabled: null,
	preferences: null,
	
	read: function(t) {
		if (this.enabled == null) {
			this.get();
		}
		if (this.enabled) {
			// Currently, alert seems the best way to inform screen readers
			alert(t);
		}
	},
	
	set: function(enabled) {
		 Cookie.setValue("AjaxAccessibility", (enabled ? "true" : "false"))
		 this.enabled = enabled;
	},
	
	get: function() {
		this.preferences = Cookie.getValue("AjaxAccessibility");
		if (this.preferences == "true") {
			this.enabled = true;
		} else {
			this.enabled = false;
		}
	},
	
	enable: function() {
		this.set(true);
	},
	
	disable: function() {
		this.set(false);
	}
};


Ajax.History = {
	_tracker: 0,
	
	trigger: function(f) {
		if (this.isLoaded()) { return; }
		dhtmlHistory.addListener(f);
		Ajax.log("New listener added");
	},	
	
	register: function(key, value) {
		if (this.isLoaded()) { return; }
		dhtmlHistory.add(key, value);

		Ajax.log("<b>A history event has been added:</b> [newLocation=" + key + " | historyData=" + value + "]");
	},
	
	set: function(key, value) {
		if (this.isLoaded()) { return; }
		historyStorage.put(key, value);
	},
	
	get: function(key) {
		if (this.isLoaded()) { return; }
		return historyStorage.get(key);
	},
	
	remove: function(key) {
		if (this.isLoaded()) { return; }
		historyStorage.remove(key);
	},
	
	exists: function(key) {
		if (this.isLoaded()) { return; }
		return historyStorage.hasKey(key);
	},
	decodeKey: function(key) {
		return key.replace(/\d/g, "");
	},
	
	encodeKey: function(key) {
		this._tracker++;
		return key + this._tracker;
	},
	
	isLoaded: function() {
		return (!window.dhtmlHistory);
	}
};
function log(msg) {
	var logNode = document.getElementById("logWin");
	var content = "<p>" + msg + "</p>" + logNode.innerHTML;
	logNode.innerHTML = content;
}
function viewObjectState() {
	log("<b>Dumping dhtmlHistory object state</b>");
	for (var key in dhtmlHistory) {
		var val = dhtmlHistory[key];
		if (typeof val !== 'function' && (typeof val !== 'object' || val === null)) {
			log("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>" + key + "</b>: " + dhtmlHistory[key]);
		}
	}
	log("<b>Done dumping dhtmlHistory object state</b>");
	log("<b>Dumping historyStorage object state</b>");
	for (var key in historyStorage) {
		var val = historyStorage[key];
		if (typeof val != 'function' && typeof val != 'object') {
			log("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>" + key + "</b>: " + historyStorage[key]);
		}
	}
	log("<b>Done dumping historyStorage object state</b>");
}
// * Instantiate
// * ----------------------------------------------------------------------
(function() { 
	if (window.dhtmlHistory) {
		window.dhtmlHistory.create({debug: true});
		window.onload = function() {
			dhtmlHistory.initialize();
			dhtmlHistory.addListener(Ajax.Init.HistoryController);
		};
	}
})();


Core.Browser = {
	height : 400,		// Default window height
	width : 600,		// Default window width
	topPos : 0,			// Default window top position
	leftPos : 0,		// Default window left position
	settings : null,	// Popup window settings
	win : null,			// New window object
	winName : "pop",	// Default window name
	// Tests and returns a Url from unkown source
	getURL : function(e) {
		if (typeof e === "object") {
			return e.href
		} else {
			return e;
		}
	},
	// * Opens a new browser window
	// * ----------------------------------------------------------------------
	newPage : function(e, options) {
		return this.openWindow(e, {popup: "window"});
	},
	// * Opens a pop up window
	// * ----------------------------------------------------------------------
	newPopUp : function(e, options) {
		if (options) {
			options.popup = "popup";
		} else {
			options = {popup: "popup"};
		}
		return this.openWindow(e, options);
	},
	// * General new window 
	// * ----------------------------------------------------------------------
	openWindow : function(e, options) {
		// Update the size
		if (options) {
			this.height = (options.height) ? options.height : this.height;
			this.width = (options.width) ? options.width : this.width;
		}

		// Center the window
		this.leftPos = (screen.width) ? (screen.width - this.width) / 2 : 0;
		this.topPos = (screen.height) ? (screen.height - this.height) / 2 : 0;

		// Add the settings if required
		this.settings = (options && options.popup == "popup") ? "height=" + this.height + ",width=" + this.width + ",top=" + this.topPos + ",left=" + this.leftPos + ",scrollbars=yes,noresize" : "";

		// Create the new window
		this.win = window.open(this.getURL(e), (options && options.name) ? options.name : this.winName, this.settings);
		
		// Push the window to the front
		this.win.focus();

		// Cancel the click
		return false;
	},
	// * Assign functions to links that have a matching rel attribute
	// * ----------------------------------------------------------------------
	// a (array) - list of rel names to match
	// f (array) - list of functions to pair up with the rel targets
	hookup: function(a, f) {
		var l = document.getElementsByTagName("a");
		var m = a.length;
		for (var i = 0, c = l.length; i < c; i++){
			for (var j = 0; j < m; j++) {
				if (l[i].getAttribute("rel") == a[j]) {
					l[i].onclick = f[j];
					break;
				}
			}
		}	
	},
	// * Contain method to create an overay or reference another handler 
	// * ----------------------------------------------------------------------
	overlay: function() {

	},
	// * Returns an array of the browser dimensions (external source)
	// * ----------------------------------------------------------------------
	size: function() {
		var xScroll, yScroll;
		if (window.innerHeight && window.scrollMaxY) {	
			xScroll = document.body.scrollWidth;
			yScroll = window.innerHeight + window.scrollMaxY;
		} else if (document.body.scrollHeight > document.body.offsetHeight){ 
			// All but Explorer Mac
			xScroll = document.body.scrollWidth;
			yScroll = document.body.scrollHeight;
		} else { 
			// Explorer Mac, would also work in Explorer 6 Strict, Mozilla and Safari
			xScroll = document.body.offsetWidth;
			yScroll = document.body.offsetHeight;
		}

		var windowWidth, windowHeight;
		if (self.innerHeight) {	
			// All except Explorer
			windowWidth = self.innerWidth;
			windowHeight = self.innerHeight;
		} else if (document.documentElement && document.documentElement.clientHeight) { 
			// Explorer 6 Strict Mode
			windowWidth = document.documentElement.clientWidth;
			windowHeight = document.documentElement.clientHeight;
		} else if (document.body) { 
			// Other Explorers
			windowWidth = document.body.clientWidth;
			windowHeight = document.body.clientHeight;
		}	

		// For small pages with total height less then height of the viewport
		if(yScroll < windowHeight){
			pageHeight = windowHeight;
		} else { 
			pageHeight = yScroll;
		}

		// For small pages with total width less then width of the viewport
		if(xScroll < windowWidth){	
			pageWidth = windowWidth;
		} else {
			pageWidth = xScroll;
		}

		return {"width": pageWidth, "height": pageHeight, "windowWidth": windowWidth, "windowHeight": windowHeight};
	}
};
(function() {
	function _$(e) {
		this.elements = [];
		for (var i = 0, c = e.length, element; i < c; i++) {
			element = e[i];
			if (typeof(element) == "string") {
				element = document.getElementById(element);
			}
			this.elements.push(element);
		}
	}

	_$.prototype = {
		get: function(i) {
			var el = this.elements[0];
			if (i) {
				el = this.elements[i];
			}
			return el;
		},
		each: function(f) {
			for (var i = 0, c = this.elements.length; i < c; i++) {
				f.call(this, this.elements[i]);
			}	
			return this;
		},
		
		custom: function(f) {
			this.each(function(e) {
				f.call(e);
			});
		},
		setId: function(i) {
			this.each(function(e) {
				e.setAttribute("id", i);
			});
			return this; 
		},
		addClass: function(c) {
			this.each(function(e) {
				Library.Dom.addClass(e, c);
			});
			return this;
		},
		removeClass: function(c) {
			this.each(function(e) {
				Library.Dom.addClass(e, c);
			});
			return this;
		},
		setContent: function(t) {
			this.each(function(e) {
				e.innerHTML = t;
			});
			return this;
		},
		insertAfter: function(n) {
			this.each(function(e) {
				Library.Dom.insertAfter(n, e);
			});
			return this;
		},
		empty: function() {
			this.each(function(e) {
				Library.Dom.emptyElement(e);
			});
			return this;
		}
	};

	window.$ = function() {
		return new _$(arguments);
	};
	window.$C = function() {
		return new _$(document.createElement(arguments[0]));
	};
})();

(function() {
	function _$F(e) {
		Core.Form.collect(e[0]);
		this.collection = Core.Form.collection;
		this.values = Core.Form.values;
		return this;
	}

	_$F.prototype = {
		value: function(f) {
			return Core.Form.value(f);
		},
		toQueryString: function() {
			return Core.Form.toQueryString(this.values);
		},
		submit: function() {
			Core.Form.submit(this.collection[0]);
			return this;
		}
	}

	window.$F = function() {
		return new _$F(arguments);
	};
})();var Debug = {
	release : true,
	showAlert : false,
	console : null,
	lineCount : 1,
	init : function() {
		// Check if console exists
		this.console = document.getElementById("console");
		if (!this.console) {
			// Create console
			var debug = document.createElement("div");
			debug.id			= "debug";
			this.console		= document.createElement("div");
			this.console.id		= "console";

			// Create control paragraph
			var togglePara		= document.createElement("p");
			togglePara.id		= "debug-toggle";
			
			// Create hide/show link
			var toggle			= document.createElement("a");
			toggle.innerHTML	= "Debug - Close";
			toggle.href			= "#";
			toggle.onclick		= function() {
				return Debug.toggle(this);
			};
			
			// Create clear link
			var clear			= document.createElement("a");
			clear.innerHTML		= "Clear";
			clear.href			= "#";
			clear.className		= "clear-debug";
			clear.onclick		= function() {
				return Debug.clear(this);
			};
			
			// Add the elements together
			togglePara.appendChild(toggle);
			togglePara.appendChild(clear);
			debug.appendChild(togglePara);
			debug.appendChild(this.console);
			document.body.appendChild(debug);
		}
	},
	// Write a line to the console
	write : function(t, stack, type, pair, tab) {
		// Exit if not debugging
		if (this.release) { return; }

		// Create a console if there isn't one
		if (!this.console) {
			this.init();
		}

		// Work out any tabbing (1-4)
		if (tab) {
			tab = "tab-" + tab;
		}
		
		// Write out the lines
		var line = document.createElement("p");
		line.className = (this.lineCount % 2) ? "alternate " + tab : tab;

		// Add a specific class to the line
		switch (type) {
			case "ajax":
				line.className += " ajax-status";
			break;
			case "ajaxresponse":
				line.className += " ajax-status";
			break;
			case "error":
				line.className += " error-status";
			break;
		}	

		// Add the pair name if specified
		if (pair) {
			var term = document.createElement("strong");
			var termText = document.createTextNode(pair + " - ");
			term.appendChild(termText);
			line.appendChild(term);
		}

		// Add the text line
		var text = document.createTextNode(t);
		if (type == "ajaxresponse") {
			text = document.createTextNode("Response can be viewed below");
		}
		line.appendChild(text);

		// Write to Firebug console	
		if (console && console.debug) {
			console.debug(t);
		}

		// Write out the calling function that contained the Debug request
		if (stack && this.w.caller) {
			this.writeBlock(this.w.caller.toString(), this.w.caller);
		}

		if (type == "ajaxresponse") {
			this.writeBlock(t);
		}

		// Add the line to the console
		if (this.console.firstChild) {
			this.console.insertBefore(line, this.console.firstChild);
		} else {
			this.console.appendChild(line);
		}

		// Update line count
		this.lineCount ++;
	},
	writeBlock : function(t, call) {
		var callHolder = document.createElement("div");
		callHolder.className = "caller";
		var callerLine = document.createElement("p");
		var callerText = document.createTextNode(t);
		if (call) {
			callerLine.innerHTML = "<strong><em>&#x2191;</em> " + t.substring(0, 60) + "...</strong><a href=\"#\" onclick=\"return Debug.caller(this, 'caller-" + this.lineCount + "')\">Show</a>";
		} else {
			callerLine.innerHTML = "<strong><em>&#x2191;</em> " + t.replace(/</g, "&lt;").replace(/>/g, "&gt;").substring(0, 60) + "...</strong><a href=\"#\" onclick=\"return Debug.caller(this, 'caller-" + this.lineCount + "')\">Show</a>";
		}
		
		
		var paraFunction = document.createElement("p");
		paraFunction.id = "caller-" + this.lineCount;
		paraFunction.className = "caller-function";
		if (call) {
			paraFunction.innerHTML = t.toString().replace(/;/g, ";<br />").replace(/{/g, "<br />{<br />").replace(/}/g, "<br />}<br />");
		} else {
			paraFunction.innerHTML = t;
		}
		callHolder.appendChild(callerLine);

		if (call) {
			if (call.arguments.length > 0) {
				var paraParam = document.createElement("dl");
				for (var i = 0, c = call.arguments.length; i < c; i++) {
					paraParam.innerHTML += 	"<dt>" + typeof arguments[i] + " - </dt><dd>" + call.arguments[i] + "</dd>";
				}
				callHolder.appendChild(paraParam);
			}
		}

		callHolder.appendChild(paraFunction);
		if (this.console.firstChild) {
			this.console.insertBefore(callHolder, this.console.firstChild);
		} else {
			this.console.appendChild(callHolder);
		}
	},
	w : function(t, stack, tab) {
		this.write(t, stack, null, false, tab);
	},
	p : function(p, t, stack, tab) {
		this.write(t, false, null, p, 0);
	},
	a : function(t) {
		this.write(t, false, "ajax", "Ajax", 0);
	},	
	al : function(t) {
		this.write(t, false, "ajaxresponse", "Ajax", 0);
	},
	ex : function(t) {
		this.write(t, false, "error", "Exception error", 0);
	},
	// * Hide or show the console
	toggle : function(e) {
		if (this.console.style.display == "block") {
			this.console.style.display = "none";
			e.innerHTML = "Debug - Open";
		} else {
			this.console.style.display = "block";
			e.innerHTML = "Debug - Close";
		}
		return false;
	},
	// Toggle the extra info
	caller : function(e, i) {
		var caller = document.getElementById(i);
		if (caller.style.display == "block") {
			caller.style.display = "none";
		} else {
			caller.style.display = "block";
		}
		return false;
	}
};

Core.Dom = {
	
	Event: {	
		// The collection of events
		onload: [],
		events: {
		    UIEvents: [ "DOMFocusOut", "DOMFocusIn", "DOMActivate"],
		    HTMLEvents: ["load", "unload", "abort", "error", "select", "change", "submit", "reset", "focus", "blur", "resize", "scroll" ],
		    MouseEvents: ["mouseover", "mouseout", "mousedown", "mouseup", "mousemove", "click", "dblclick" ],
		    MutationEvents: ["DOMSubtreeModified", "DOMNodeInserted", "DOMNodeRemoved", "DOMNodeRemovedFromDocument", "DOMNodeInsertedIntoDocument", "DOMAttrModified", "DOMCharacterDataModified"]
		},
		loaded: function() {
			if (arguments.callee.done) {
				return;
			}
			arguments.callee.done = true;
			for (var i = 0; i < Core.Dom.Event.onload.length; i++) {
				Core.Dom.Event.onload[i]();
			}
		},
		
		pageLoad: function(f) {
			var oldonload = window.onload;
			if (typeof window.onload  !== "function") {
				window.onload = f;
			} else {
				window.onload = function() {
					oldonload();
					f();
				}
			}
		},
		
		domLoad: function(f) {
			this.onload.push(f);
			if (document.addEventListener) {
				document.addEventListener("DOMContentLoaded", Core.Dom.Event.loaded, null);
			}
			// Try string match as its faster than RegEx
			//if (/KHTML|WebKit/i.test(navigator.userAgent)) { 
			var agent = navigator.userAgent;
			if (agent.indexOf("KHTML") || agent.indexOf("WebKit")) {
				var _timer = setInterval(function() {
					if (/loaded|complete/.test(document.readyState)) {
						clearInterval(_timer);
						delete _timer;
						Core.Dom.Event.loaded();
					}
				}, 10);
			}
			/*@cc_on @*/
			/*@if (@_win32)
			var proto = "src='javascript:void(0)'";
			if (location.protocol == "https:") proto = "src=//0";
			document.write("<scr"+"ipt id=__ie_onload defer " + proto + "><\/scr"+"ipt>");
			var script = document.getElementById("__ie_onload");
			script.onreadystatechange = function() {
				if (this.readyState == "complete") {
					Core.Dom.Event.loaded();
				}
			};
			/*@end @*/
			this.pageLoad(Core.Dom.Event.loaded);
		},
		
		add: function(e, type, f) {
			if (e.attachEvent) {
				e["e" + type + f] = f;
				e[type + f] = function() {
					e["e" + type + f](window.event);
				}
				e.attachEvent("on" + type, e[type + f]);
			} else {
				e.addEventListener(type, f, false);
			}
		},
		
		remove: function(e, type, f) {
			if (e.detachEvent) {
				e.detachEvent("on" + type, e[type + f]);
				e[type + f] = null;
			} else {
				e.removeEventListener(type, f, false);
			}
		},
		
		raise : function(target, type, datatype, data) {
		    var feature = "Events";   /* ..default event type.. */
		    var e = null;
		    
		    if( typeof target == "string" )  target = document.getElementById(target);
		    if( !target )    return;
		    
		    /* ..determine the type of DOM event..
		    */
		    if( this.events.UIEvents.contains(type) )               feature = "UIEvents";
		    else if( this.events.HTMLEvents.contains(type) )        feature = "HTMLEvents";
		    else if( this.events.MouseEvents.contains(type) )       feature = "MouseEvents";
		    else if( this.events.MutationEvents.contains(type) )    feature = "MutationEvents";
		    /* ..we want to make sure the browser supports DOM level 2 events
		     * and resort to another method if it doesn't..
		     */
	        if( feature != null && document.implementation.hasFeature(feature, "2.0") ) {
	            e = document.createEvent( feature );
	            if( feature == "MouseEvents" )    e.initMouseEvent(type, true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
	            else    e.initEvent( type, true, false );
	        } else if( document.createEvent ) {
                e = document.createEvent( "Events" );
                e.initEvent( type, true, false ); 
	        } else if( document.createEventObject ) {
		        e = document.createEventObject();
		    } else  /* ..what gives?.. */
		        return;
		        
		    e.datatype = datatype;
		    e.data = data;

		    if( target.dispatchEvent )  target.dispatchEvent( e );
		    else if( target.fireEvent ) target.fireEvent( "on" + type, e );
		},
		
		cancel: function(e) {
			if(!e) {
				var e = window.event;
			}
			e.cancelBubble = true;
			e.returnValue = false;
			if (e.stopPropagation) {
				e.stopPropagation();
				e.preventDefault();
			}
			return false;
		},
		
		keycode: function(evt) {
			return evt.keyCode ? evt.keyCode : evt.which ? evt.which : evt.charCode;

		}
	},		
	
	emptyElement: function(e) {
		if (e) {
			while (e.firstChild) {
				e.removeChild(e.firstChild);
			}
		}
	},
	
	insertAfter: function(referenceNode, node) {
		var parent = referenceNode.parentNode;
		parent.insertBefore(node, referenceNode.nextSibling);
	},
	
	removeClass: function(e, cssClass) {
		if (e.className) {
			// Split up the class names
			var classList = e.className.split(" ");

			// Go through and remove the class from the array
			for (var i = 0; i < classList.length; i++) {
				if (classList[i] === cssClass) {
					classList.splice(i, 1);
					break;
				}
			}

			// Add the new array list to the element
			e.className = classList.join(" ");
		}
	},
	
	addClass: function(e, cssClass) {
		if (e.className) {
			e.className += " " + cssClass;
		} else {
			e.className = cssClass;
		}
	},
	
	getParentNode: function(e) {
		var node = null;
		if (e && e.parentNode) {
			while (e.parentNode.nodeType != 1) {
				e = e.parentNode;
				node = e;
			}
			return (!node) ? e.parentNode : node;
		}
	},
	
	getNextSibling: function(e) {
		var node = null;
		if (e && e.nextSibling) {
			while (e.nextSibling.nodeType != 1) {
				e = e.nextSibling;
				node = e;
			}
			return (node) ? e.nextSibling : node;
		}
	},
	
	getPreviousSibling: function(e) {
		var node = null;
		if (e && e.previousSibling) {
			while (e.previousSibling.nodeType != 1) {
				e = e.previousSibling;
			}
			return  e.previousSibling;
		}
		return (node) ? e.previousSibling : node;
	},
	
	getFirstChild: function(e) {
		this.getChild(e, 1);
	},
	
	getChild: function(e, n) {
		if (e) {
			for (var i = 0, c = e.childNodes.length, j = 0; i < c; i++) {
				if (e.childNodes[i].nodeType == 1) {
					if (n == j) {
						break;
					}
					++j;
				}
			}
			return e.childNodes[i];
		}
		return null;	
	},
	
	getStyle: function(e, styleRule) {
		var styleValue = "";
		if (document.defaultView && document.defaultView.getComputedStyle){
			styleValue = document.defaultView.getComputedStyle(e, "").getPropertyValue(styleRule);
		}
		else if (e.currentStyle) {
			try {
				styleRule = styleRule.replace(/\-(\w)/g, function(strMatch, p1) {
					return p1.toUpperCase();
				});
				styleValue = e.currentStyle[styleRule];
			}
			catch(e) {
				// Used to prevent an error in IE 5.0
			}
		}
		return styleValue;
	}
};

(function() {
	if (Config && Config.init && Config.load) {
		// This loads up the DOM load functionality using the method defined above
		Core.Dom.Event.domLoad(Config.init);

		// And this loads up the page load functionality
		Core.Dom.Event.pageLoad(Config.load);
	}
})();

(function() {
	function _$A(e) {
		this.tween = new Easing({
			"start": 100, 
			"duration": this.duration, 
			"finish": 0, 
			"method": Core.Fx.Easing.sineInOut, 
			"action": function() {
				Core.Fx.opacity(box, this.position);
			},
			"callback": function() {
			}
		});
		return this;
	}
	_$A.prototype = {};

	window.$A = function() {
		return new _$A(arguments);
	};
})();


Core.Fx = {
	Tween: {
		timer: null,	// The timer for framerates
		counter: 0,		// Help generate a unique Id for each event added
		engine: [],		// Contains reference to the owner
		owner: [],		// The collection of objects to pass in as a reference
		action: [],		// The function associated with the owner object and the engine Id
		sweep: [],		// List of finished events ready to be removed
		// Set up the timer to emulate frames
		init: function() {
			// Setup the framerate emulation
			this.timer = setInterval("Core.Fx.Tween.play();", Config.Fx.framerate);
		},
		play: function() {
			// Loop through and excute the collection of actions
			for (var i = 0, j, c = this.engine.length; i < c; i++) {        
				j = this.engine[i];

				// Check that the action is a valid function
				if (typeof this.action[i] === "function") {
					this.action[i].call(this.owner[i]);
				}
			}
			this.clean();
		},
		clean: function() {
			// This is a little complicated and not the most efficient way - but it works for now
			// Go through the collection of the items to remove
			for (var i = 0, c = this.sweep.length, j; i < c; i++) {
				j = this.sweep[i];
				this.engine.splice(j, 1);
				this.owner.splice(j, 1);
				this.action.splice(j, 1);
				
				// If the item to remove IS NOT the first, decrement the indexes in the engine array after the item to remove
				if (j > k) {
					for (var k = this.engine.length; j > k; k--) {
						this.engine[k] = this.engine[k] - 1;
					}
					
				} else {
					// If the item to remove IS the first, decrement the indexes so that they correspond to the corrent engine
					for (var x = 0, y = this.sweep.length; x < y; x++) {
						this.sweep[x] = this.sweep[x] - 1;
					}
				}
			}

			// If there are no elements left the engine on this iteration, stop the timer as there is nothing left
			if (this.engine.length == 0) {
				this.stop();
			}

			// Reset the removal collection
			this.sweep = [];
		},
		stop: function() {
			// Stop and cancel the timer
			clearInterval(this.timer);
			this.timer = null;
		},
		add: function(o, f) {
			// Add the object, function, and Id to the arrays
			var i = this.owner.length;
			this.engine[i] = this.counter;
			this.owner[i] = o;
			this.action[i] = f;

			// Once added, if the timer isn't active, start it up
			if (!this.timer) {
				this.init();
			}

			// Increment the counter for the next addition
			this.counter++;

			// Return the Id of the engine that was just added
			return this.counter - 1;
		},
		remove: function(i) {
			// Can't remember why I put this if statement here - perhaps if the animation was cancelled/reset before it was finished don't add a duplicate value
			if (this.engine.contains(i)) {
				this.sweep[this.sweep.length] = this.engine.indexOf(i);
			}
		},
		// Unused but used to store debug lines
		debug: function() {

		}
	},
	Easing: {
		linearInOut: function(t, b, c, d) {
			return c * t/d + b;
		},
		quadIn: function(t, b, c, d) {
			return c * (t/=d) * t + b;
		},
		quadOut: function(t, b, c, d) {
			return -c * (t/=d)*(t-2) + b;
		},
		quadInOut: function(t, b, c, d) {
			if ((t/=d/2) < 1) return c/2*t*t + b;
			return -c/2 * ((--t)*(t-2) - 1) + b;
		},
		cubicIn: function(t, b, c, d) {
			return c * Math.pow (t/d, 3) + b;
		},
		cubicOut: function(t, b, c, d) {
			return c * (Math.pow (t/d-1, 3) + 1) + b;
		},
		cubicInOut: function(t, b, c, d) {
			if ((t/=d/2) < 1)
			return c/2 * Math.pow (t, 3) + b;
			return c/2 * (Math.pow (t-2, 3) + 2) + b;
		},
		quarticIn: function(t, b, c, d) {
			return c * Math.pow (t/d, 4) + b;
		},
		quarticOut: function(t, b, c, d) {
			return -c * (Math.pow (t/d-1, 4) - 1) + b;
		},
		quarticInOut: function(t, b, c, d) {
			if ((t/=d/2) < 1)
			return c/2 * Math.pow (t, 4) + b;
			return -c/2 * (Math.pow (t-2, 4) - 2) + b;
		},
		quinticIn: function(t, b, c, d) {
			return c * Math.pow (t/d, 5) + b;
		},
		quinticOut: function(t, b, c, d) {
			return c * (Math.pow (t/d-1, 5) + 1) + b;
		},
		quinticInOut: function(t, b, c, d) {
			if ((t/=d/2) < 1)
			return c/2 * Math.pow (t, 5) + b;
			return c/2 * (Math.pow (t-2, 5) + 2) + b;
		},
		sineIn: function(t, b, c, d) {
			return c * (1 - Math.cos(t/d * (Math.PI/2))) + b;
		},
		sineOut: function(t, b, c, d) {
			return c * Math.sin(t/d * (Math.PI/2)) + b;
		},
		sineInOut: function(t, b, c, d) {
			return c/2 * (1 - Math.cos(Math.PI*t/d)) + b;
		},
		expoIn: function(t, b, c, d) {
			return c * Math.pow(2, 10 * (t/d - 1)) + b;
		},
		expoOut: function(t, b, c, d) {
			return c * (-Math.pow(2, -10 * t/d) + 1) + b;
		},
		expoInOut: function(t, b, c, d) {
			if ((t/=d/2) < 1)
			return c/2 * Math.pow(2, 10 * (t - 1)) + b;
			return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
		},
		circIn: function(t, b, c, d) {
			return c * (1 - Math.sqrt(1 - (t/=d)*t)) + b;
		},
		circOut: function(t, b, c, d) {
			return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
		},
		circInOut: function(t, b, c, d) {
			if ((t/=d/2) < 1)
			return c/2 * (1 - Math.sqrt(1 - t*t)) + b;
			return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
		}
	},
	
	opacity: function(e, o) {
		e.style.opacity			= (o / 100);
		e.style.MozOpacity		= (o / 100);
		e.style.KhtmlOpacity	= (o / 100);
		e.style.filter			= "alpha(opacity=" + o + ")";
	}
};


function Tween(options) {
	this.setup = false;
	this.set(options);
}

Tween.prototype.getPosition = function() {
	return this.position;
};

Tween.prototype.set = function(options) {
	// If being reset, remove the existing Id from the Timer
	if (this.Id) {
		Timer.remove(this.Id);
	}

	// Must have the following properties of the tween is pointless
	if (options && typeof options.start !== "undefined"  && typeof(options.finish) != "undefined" && options.action) {
		this.wait			= null; // The delay timer
		this.time			= 0; // The count for timing - based on the number of iterations of the the timer
		this.framerate		= options.framerate || Config.Fx.framerate; // The framerate for each interation
		this.duration		= options.duration || Config.Fx.duration; // The duration (max number of iterations)
		this.method			= options.method || Core.Fx.Easing.sineInOut; // The easing method
		this.begin			= options.start;  // The start position
		this.finish			= options.finish; // The position to finish
		this.speed			= options.speed || 5; // The speed or time to tween
		this.change			= this.finish - this.begin; // The difference of the transition
		this.position		= this.begin; // The current transition position
		this.callback		= options.callback || null;
		this.toggable		= false; // Switched to true if the toggle() function is called
		this.action			= options.action;
		this.Id				= null; // Id to control the tween and remove from the Tween object

		this.active	= false;

		// Calculate VERY rough timing in seconds - timing will vary across browsers
		this.duration = (this.framerate * this.duration) + this.framerate;

		// Confirm that we have setup the properties
		this.setup = true;

		// Setup an initial delay
		if (options.delay) {
			this.delay(options.delay, function() { this.start(); });
		}
	}
};

Tween.prototype.tween = function() {
	// Calculate the tween
	this.position = parseInt(this.method.call(this, this.time++, this.begin, this.change, this.duration));
		
	// Perform the action for each tween iteration
	this.action.call(this);

	// If the time exceeds the duration (the easing calculation should be done), stop the tween
	if (this.time > this.duration) {
		this.stop();
	} 
};


Tween.prototype.play = function() {
	if (this.setup) {
		this.active = true;
		this.Id = Core.Fx.Tween.add(this, this.tween);
	}
};


Tween.prototype.toggle = function() {
	//this.toggable = true;
	//this.swap();
	this.play();
};

Tween.prototype.swap = function() {
	// Reset the properties
	this.time		= 0;
	this.finish		= this.begin;
	this.begin		= this.position;
	this.change		= this.finish - this.begin;
};


Tween.prototype.reverse = function(options) {
	// Reset the properties
	this.swap();
	this.callback	= (options && options.callback) ? options.callback : null;

	// Setup an initial delay
	if (options && options.delay) {
		this.delay(options.delay, function() { this.play(); });
	} else {
		// Now start the reversed tween
		this.play();
	}
};


Tween.prototype.stop = function(cancel) {
	this.active = false; 
	Core.Fx.Tween.remove(this.Id);
	
	this.active = false;
	cancel = (typeof cancel === "undefined") ? false : cancel;
	if (this.callback && !cancel) {
		this.callback.call(this);
	}
};


Tween.prototype.delay = function(time, callback) {
	if (time > 0) {
		var o = this;
		this.wait = setTimeout(function() { callback.call(o); }, time * 1000);
	} else {
		callback.call(this);
	}
};

Tween.Easing = {
	linearInOut: function(t, b, c, d) {
		return c * t/d + b;
	},
	quadIn: function(t, b, c, d) {
		return c * (t/=d) * t + b;
	},
	quadOut: function(t, b, c, d) {
		return -c * (t/=d)*(t-2) + b;
	},
	quadInOut: function(t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t + b;
		return -c/2 * ((--t)*(t-2) - 1) + b;
	},
	cubicIn: function(t, b, c, d) {
		return c * Math.pow (t/d, 3) + b;
	},
	cubicOut: function(t, b, c, d) {
		return c * (Math.pow (t/d-1, 3) + 1) + b;
	},
	cubicInOut: function(t, b, c, d) {
		if ((t/=d/2) < 1)
		return c/2 * Math.pow (t, 3) + b;
		return c/2 * (Math.pow (t-2, 3) + 2) + b;
	},
	quarticIn: function(t, b, c, d) {
		return c * Math.pow (t/d, 4) + b;
	},
	quarticOut: function(t, b, c, d) {
		return -c * (Math.pow (t/d-1, 4) - 1) + b;
	},
	quarticInOut: function(t, b, c, d) {
		if ((t/=d/2) < 1)
		return c/2 * Math.pow (t, 4) + b;
		return -c/2 * (Math.pow (t-2, 4) - 2) + b;
	},
	quinticIn: function(t, b, c, d) {
		return c * Math.pow (t/d, 5) + b;
	},
	quinticOut: function(t, b, c, d) {
		return c * (Math.pow (t/d-1, 5) + 1) + b;
	},
	quinticInOut: function(t, b, c, d) {
		if ((t/=d/2) < 1)
		return c/2 * Math.pow (t, 5) + b;
		return c/2 * (Math.pow (t-2, 5) + 2) + b;
	},
	sineIn: function(t, b, c, d) {
		return c * (1 - Math.cos(t/d * (Math.PI/2))) + b;
	},
	sineOut: function(t, b, c, d) {
		return c * Math.sin(t/d * (Math.PI/2)) + b;
	},
	sineInOut: function(t, b, c, d) {
		return c/2 * (1 - Math.cos(Math.PI*t/d)) + b;
	},
	expoIn: function(t, b, c, d) {
		return c * Math.pow(2, 10 * (t/d - 1)) + b;
	},
	expoOut: function(t, b, c, d) {
		return c * (-Math.pow(2, -10 * t/d) + 1) + b;
	},
	expoInOut: function(t, b, c, d) {
		if ((t/=d/2) < 1)
		return c/2 * Math.pow(2, 10 * (t - 1)) + b;
		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
	},
	circIn: function(t, b, c, d) {
		return c * (1 - Math.sqrt(1 - (t/=d)*t)) + b;
	},
	circOut: function(t, b, c, d) {
		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
	},
	circInOut: function(t, b, c, d) {
		if ((t/=d/2) < 1)
		return c/2 * (1 - Math.sqrt(1 - t*t)) + b;
		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
	}
};

Core.Form = {
	// Create empty query string
	queryString: "",
	// Store the collection request for the $F object
	collection: null,
	// Store the parameter collection
	values: [], // Stores a name value pair of collected form elements
	
	getParams: function() {
		return this.values;
	},
	
	setValue: function(n, v) {
		this.values[n] = v;
	},
	
	emptyValues: function() {
		this.values = [];
	},
	
	value: function(f) {
		if (f) {
			for (var i in this.values) if (this.values.hasOwnProperty(i)) {
				f.call(this, i, this.values[i]);
			}	
		}
		return this.values;
	},
	
	toQueryString: function(o) {
		var qs = "", values = o || this.values;
		// Check to make sure this doesn't include the extended array objects
		for (var i in values) if (values.hasOwnProperty(i)) {
				qs += "&" + encodeURIComponent(i) + "=" + encodeURIComponent(values[i]);
		}	
		// Remove the initial &
		return qs.substring(1);
	},
	
	collect: function(collection, container) {
		this.collection = collection;
		// Reset the querystring collection
		this.emptyValues();
		var v, container;
		
		// Determine if the collection is an array or null value
		if (typeof collection === "object") {
			container = (!container || container.nodeType === 9) ? document : document.getElementById(container);
			for (var i = 0, c = collection.length; i < c; i++) {
				v = this.getValue(collection[i], container);	
			}
		} else {
			container		= document.getElementById(collection);

			// Using this instead of the form.elements[] collection as we may only want certain form elements within a container
			var inputItem	= container.getElementsByTagName("input");
			var selectItem	= container.getElementsByTagName("select");	
			var textItem	= container.getElementsByTagName("textarea");
			
			for (var i = 0, c = inputItem.length; i < c; i++) {
				this.getValue(inputItem[i], inputItem[i].id, true);	
			}
			for (var i = 0, c = selectItem.length; i < c; i++) {
				this.getValue(selectItem[i], selectItem[i].id, true);	
			}
			for (var i = 0, c = textItem.length; i < c; i++) {
				this.getValue(textItem[i], textItem[i].id, true);	
			}
		}
		return v;
	},
	
	getValue: function(e, container, collectValues) {	
		this.collectValues = (collectValues);
		// Set the element to collect from either name or DOM object
		var el = (typeof e === "string") ? document.getElementById(e) : e;
		if (!el) {
			// If the element cannot be found assume it is a radio button name and try looking for them
			var wrapper = (!container || container.nodeType === 9) ? document : document.getElementById(container);
			var input = wrapper.getElementsByTagName("input");
			for (var i = 0, c = input.length; i < c; i++) {
				if (input[i].name && input[i].name === e) {
					return this.getValue(input[i].id, container, collectValues)
				}
			}
		} else {
			// Set the container to collect a radio button selected value or default to searchgin through the entire body
			container = (!container || container == "document") ? document : document.getElementById(container);

			// Reset the values
			var n = el.id, v = null;
		
			switch (el.nodeName.toLowerCase()) {
				case "input":
					switch (el.getAttribute("type").toLowerCase()) {
						case "text":
							v = el.value;
						break;
						case "checkbox":
							if (el.checked) {
								v = el.value;
							}
						break;
						case "radio":
							n = el.name;
							var button = container.getElementsByTagName("input");
							for (var j = 0, d = button.length; j < d; j++) {
								if (button[j].name == el.name && button[j].checked) {
									v = button[j].value;
									break;
								}
							}	
						break;
						case "password":
							v = el.value;
						break;
						case "hidden":
							v = el.value;
						break;
					}
				break;
				case "select":
					if (el.multiple) {
						l = [];
						for (var j = 0, d = el.length; j < d; j++) {
							if (el.options[j].selected) {
								l.push(el.options[j].value);
							}
						}
						v = l.join("|");
					} else {
						v = el.value;
					}
				break;
				case "textarea":
					v = el.value;
				break;
			}
			
			// Make sure that all the name and value pairs are there before using them
			if (n != null && n != "" && v != null && v != "") {
				this.setValue(n, v);
				if (this.collectValues) {
					return this.addQueryString(n, v);
				} else {
					return v;
				}
			} else {
				return v;
			}
		}
	},
	// Add a new set
	addQueryString: function(param, value) {
		var preffix = (this.queryString.length > 0) ? "&" : "" ;
		this.params += preffix + encodeURIComponent(param) + "=" + encodeURIComponent(value);
	},
	clickOnce: function() {

	},
	
	assignButton: function(e, el) {
		var code;
		if (!e)
		{
		    e = window.event;
		}
		
		if (e.keyCode) {
			code = e.keyCode;
		} else if (e.which) {
			code = e.which;
		}
		if (code == 13) {
			return this.submit(el);
		}
		return true;
	},
	
	submit : function(e) {
		if (typeof e !== "object") {
			e = document.getElementById(e);
		}
		e.click();
		return false;
	},
	
	DropDown: {
		
		create: function(name, value, selected) {
			return this.populate(document.createElement("select"), name, value, selected);
		},	
		
		populate: function(e, name, value, selected) {
			if (!e) { return; }	
			Utils.Dom.emptyElement(e);
			for (var i = 0, c = name.length; i < c; i++) {
				e.options[i] = new Option(name[i], value[i]);
				if (value[i] == selected) {
					e.options[i].selected = true;
				}
			}
			return e;
		},
		
		createJson: function(data, selected) {
			return this.populateJson(document.createElement("select"), name, value, selected);
		},
		
		populateJson: function(e, data, selected) {	
			// Just check to make sure it's valid
			if (!e) { return; }	
			Utils.Dom.emptyElement(e);
			for (var i = 0, c = data.length; i < c; i++) {
				e.options[i] = new Option(data[i].property, data[i].value);
				if (selected && json[i].value == selected) {
					e.options[i].selected = true;
				}
			}
			return e;
		},
		
		updateOption: function (e, name, value) {
			if (!e) { return; }
			for (var i = 0, c = e.options.length; i < c; i++) {
				if (e.options[i].value == value) {
					e.options[i].innerHTML = name;
				}
			}
		},
		
		removeOption : function (e, value) {
			if (!e) { return; }
			for (var i = 0, c = e.options.length; i < c; i++) {
				if (e.options[i].value == value) {
					e.removeChild(e.options[i]);
					break;
				}
			}
		}
	},
	Style: {
		// Disable elements in a container
		// e (string|object) - Id of containter to search through
		disable : function(e) {
			this.toggleForm(e, ["input", "select", "textarea"], {"disabled": true});
		},
		// Enable elements in a container
		// e (string|object) - Id of containter to search through
		enable : function(e) {
			this.toggleForm(e, ["input", "select", "textarea"], {"disabled": false});
		},
		// Toggle a group of form elements
		// e (string|object) - Id of containter to search through
		// el (array) - elements to use
		// options (array literal) - {disabled: true, visibility: true, display: true}
		toggle : function(e, el, options) {
			e = (typeof e === "object") ? e : document.getElementById(e);
			if (el.inArray("input")) {
				this.toggleElements(e, "input", options);
			}
			if (el.inArray("select")) {
				this.toggleElements(e, "select", options);
			}
			if (el.inArray("textarea")) {
				this.toggleElements(e, "textarea", options);
			}
		},	
		// Toggle a group of form elements
		// e (string|object) - Id of containter to search through
		// node (array) - array of element nodes to loop through ["input", "select", "textarea"]
		// options (array literal) - {disabled: true, visibility: true, display: true}
		toggleElements : function(e, node, options) {
			e = (typeof e === "object") ? e : document.getElementById(e);
			// Get the collection
			var nodes = e.getElementsByTagName(node);
			for (var i = 0, c = nodes.length; i < c; i++) {
				this.toggleElement(nodes[i], options);
			}
		},
		// Toggle a form element
		// e (object|object) - item to change
		// options (array literal) - {disabled: true, visibility: true, display: true}
		toggleElement : function(e, options) {
			e = (typeof e === "object") ? e : document.getElementById(e);
			// Check that there are options
			if (options) {
				// Check that there is an absence of a value
				if (typeof options.visibility !== "undefined") {
					// Hide it if there is no non-computed value
					if (options.visibility == null) {
						e.style.visibility = (e.style.display == "" || e.style.display == "visible") ? "hidden" : "visible";
					} else {
						e.style.visibility = (options.visibility) ? "visible" : "hidden";
					}
				}
				if (typeof options.disabled !== "undefined") {	
					e.disabled = options.disabled;
					// Change mouse to make it appear unclickable
					if (typeof options.disabled !== "undefined") {	
						if (options.disabled) {
							e.style.cursor = "default";
						} else {
							e.style.cursor = "";
						}
					}
					
					// Fade the input if it is an image button
					if (e.getAttribute("type") == "image") {
						Fx.opacity(e, (options.disabled) ? 50 : 100)
					}
				}
				if (typeof options.display !== "undefined") {
					// Hide it if there is no non-computed value	
					e.style.display = (e.style.display == "" || e.style.display == "block") ? "none" : "";
				}
			}
		}
	}
};

Core.Utils = {	
	
	flickerFix: function() {
		try {
			document.execCommand("BackgroundImageCache", false, true);
		} catch(e) {}
	}
};


Core.Cache = {
	maxLength: 0, // 0 means that there is no limit
	length: 0,
	hash: [],
	
	setMaxLength: function(length) {
		this.maxLength = length;
	},
	
	set: function(k, data) {
		if (this.hash[k]) {
			// Cache exists - k;
			return false;
		} else {
			// Check that the cache item does not exceed the limit
			if (this.maxLength && this.Length == this.maxLength) {
				for (var j in this.hash) {
					this.length--;
					if (this.length == (this.maxLength - 1)) {
						// Popping from the cache - j
						delete this.hash[j];
						break;
					}
				}
			} 
			// Cache adding new - k
			this.hash[k] = data;
			this.length++;
			return true;
		}
	},
	
	get: function(k) {
		var data = this.hash[k];
		if (data) { 
			// Cache exists - k
			return data;
		} else {
			// Cache does not exist - k
			return null;
		}
	},
	
	remove: function(k) {
		var status = false; // True if found and removed, false if not found
		for (var i in this.hash) {
			if (i == k) {
				// Popping from the cache - j
				delete this.hash[k];
				status = true;
				break;
			}
		}
		return status;
	},
	
	empty: function() {
		this.hash = [];
	}
};


Core.Json = {
	
	serialize: function(json) {
		return json; // TODO?
	},
	
	parse: function(s) {
		return this.parseSimple(s, true);
	},
	
	parseSimple: function(s, secure) {
		var json = undefined;
		// Check for correctness
		if (s && s.length > 0) {
			// Try to convert to Json
			try {
				// Check that the Json is not a security threat
				if (secure) {
					if (this.parseSecure(s, true)) {
						// Return undefined for failed Json / Json that is not secure
						json = eval("(" + s + ")");
					}
				} else {
					json = eval("(" + s + ")");
				}
			} catch(e) {
				// Undefined for failed Json 
				json = undefined;
			}
		} else {
			// Return null for empty Json
			json = null;
		}
		return json;
	},
	
	parseSecure: function(s, success) {
		if (/^[\],:{}\s]*$/.test(s.replace(/\\./g, '@').
		replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
		replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
			if (success) {
				return true;
			} else {
				return this.parseSimple(s, false);
			}
		} else {
			// throw new SyntaxError("Cannot parse JSON");
			// Return undefined for failed Json 
			return undefined;
		}
	}
};


Core.String = {	
	 
	convertToBoolean: function(s) {
		return (s.toUpperCase() === "TRUE");
	},
	
	format: function(s) {
		if (arguments.length >  1) {
			// Expose variable to closure
			var args = arguments;
			
			// Find and replace all the placeholders (max 9 for now)
			var t = s.replace(/\{[0-9]\}/g, function(match) {
				// Add one as the first argument is the placeholder string
				var i = parseInt(match.charAt(1)) + 1;
				
				// Check that the array has the index
				if (args[i]) {
					return args[i];
				} else {
					return "";
				}
			});
		}
		return t;
	},
	
	trim: function(s) {
		return s.replace(/^\s+|\s+$/g, "");
	},
	
	toHTML: function(s) {
		return s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, "\"");
	}
};

Core.Image = {
	gallery: [],				// The list of iamges to preload
	cache: [],				// The array of preloaded images
	cacheProgress: 0,		// Count of processed images
	cacheLength: 0,			// Total of images in the preload call array
	cacheCallback: null,	// Function to perform is the 
	error: [],			// The array of images that have errored
	
	_load: function(a) {
		var i = new Image(), o = this;
		i.onload = function() {
			Core.Image._loadComplete.call(o);
		}
		i.onerror = function() {
			Core.Image.error.push(i.src);
			Core.Image._loadComplete.call(o);
		};
		i.onabort = function() {
			Core.Image.error.push(i.src);
			Core.Image._loadComplete.call(o);
		};
		i.src = a;
		this.cache[this.cache.length] = i;
	},
	
	preload: function(a, f) {
		this.gallery = [];
		this.cacheLength = 0;
		this.cacheProgress = 0;
		this.cacheError = [];
		this.cache = [];

		this.cacheCallback = f;
		if (typeof a === "string") {
			this.cacheLength = 1;
			this.gallery.push(a);
			this._load(a);
		} else {
			this.cacheLength = a.length;
			for (var i = 0; i < this.cacheLength; i++) {
				this.gallery.push(a[i]);
				this._load(a[i]);
			}
		}
	},
	
	_loadComplete: function() {
		this.cacheProgress++;
		if (this.cacheProgress == this.cacheLength) {
			if (this.cacheCallback) {
				this.cacheCallback.call(this);
			}
		}
	},
	
	swap: function(e, el, cache) {
		if (typeof el === "string") {
			el = document.getElementById(el);
		}
		var s = el.src, t = el.src.replace(".", "-o.");
		
		// Preload the image if required (true by default)
		if (typeof cache === "undefined" || cache) {
			this.preload(t);
		}

		// Do the mouseover events
		e.onmouseover = function() {
			el.src = t;
		}
		e.onmouseout = function() {
			el.src = s;
		}
		el.src = t;
	}
};


Core.Debug = {
	canvas: "content", // Set the canvas to put the trace to
	
	log: function(p, v) {
		var line = "";
		var c = (arguments.length == 2) ? v : p;
		switch (typeof c) {
			case "string":
				line = c;
			break;
			case "object":
				if (c instanceof Array) {
					for (var i = 0, ix = c.length; i < ix; i++) {
						line += ", " + c[i];
					}
				}
				if (c instanceof Object) {
					for (var i in c) {
						line += ", " + i;
					}
				}
				line = line.substring(1);
			break;
		}
		return (arguments.length == 2) ? "<strong>" + p + ": </strong>" + line : line;
	},
	
	trace: function(p, v) {
		var log = document.getElementById("debug-list");
		if (!log) {
			console = document.createElement("div");
			console.className = "debug";

			var log = document.createElement("ol");
			log.id = "debug-list";
			console.appendChild(log);

			var content = document.getElementById(this.canvas);
			content.appendChild(console);
		}
		var item = document.createElement("li");
		if (arguments.length == 1) {
			v = this.log(v);
		} else {
			v = this.log(p, v);
		}
		item.innerHTML = v;
		log.appendChild(item);
	}
};


Array.prototype.contains = function(value) {
	var i = this.length;
	if (i > 0) {
		do {
			if (this[i] === value) {
				return true;
			}
		} while (i--);
	}
	return false;
};


Array.prototype.indexOf = function(value) {
	for (var i = 0, c = this.length; i < c; i++) {
		if (this[i] == value) {
			return i;
		}
	}
	return -1;
};


Array.prototype.remove = function(index) {
	for (var i = 0, c = this.length; i < c; i++){
		if (index == i) {
			this.splice(i, 1);
		}
	}
};


/** BEGIN: GOOGLE MAPS INTERFERENCE
*/
//Array.prototype.unshift = function(item) {
//	// Create a new last element
//	this[this.length] = null;
//	for(var i = 1, c = this.length; i < c; i++) {
//		// Shift elements upwards
//		this[i] = this[i - 1]; 
//	}
//	this[0] = item;
//};
//
//Array.prototype.shift = function() {
//	for(var i = 1, c = this.length; i < c; i++) {
//		// Shift element downwards
//		this[i - 1] = this[i] 
//	}
//	this.length = this.length - 1;
//};
/** END: GOOGLE MAPS INTERFERENCE
*/


Array.prototype.clear = function() {
	this.length = 0;
};


Array.prototype.sort = function() {
	var tmp;
	for(var i = 0, c = this.length; i < c; i++) {
		for(var j = 0, d = this.length; j < d; j++) {
			if(this[i] < this[j]) {
				tmp = this[i];
				this[i] = this[j];
				this[j] = tmp;
			}
		}
	}
};


Array.prototype.unique = function() {
	var a = [];
	this.sort();
	for(var i = 0, c = this.length; i < c; i++) {
		if(this[i] !== this[i + 1]) {
			a[a.length] = this[i];
		}
	}
	return a;
};
 

Array.prototype.lastIndexOf = function(value) {
	var i = this.length;
	while(i--) {
		if(this[i] === value) {
			return i;
		}
	}
	return -1;
};

Site.register = function(f, page) {
	if (typeof f === "function") {
		if (page) {
			Core.Dom.Event.pageLoad(f);
		} else {
			Core.Dom.Event.domLoad(f);
		}
	}
};


Site.namespace = function(n) {
	var namespaces = n.split(".");
	this.setNamespace(namespaces, this, 0);
};


Site.setNamespace = function(namespace, name, i) {
	if (i < namespace.length) {
		if (typeof name[namespace[i]] !== "object") {
			name[namespace[i]] = {};
		}
		this.setNamespace(namespace, name[namespace[i]], ++i);
	}
};

Site.Temp = {};

Site.Page = {};

Site.Global = {};

Core.Url = {
	
	qs: function(param, url) {
		if (!url) {
			url = this.page;
		}
		if (url.indexOf("?") != -1) {
			var qs = url.substring(url.indexOf("?") + 1);
			var pairs = qs.split("&");
			var hash = new Array(), count = 0, key, value, pair;
			for (var i = 0, c = pairs.length; i < c; i++) {
				pair = pairs[i].split("=");
				if (param && param == pair[0]) {
					return pair[1].toString();
				}
				hash[pair[0]] = pair[1];
				count++;
			}
			if (count > 0) {
				return hash;
			} else {
				return null;
			}
		}
	},
	
	protocol: function() {
		var url = location.protocol;
		return url.substring(0, url.indexOf(":")).toUpperCase();
	},
	
	isSecure: function() {
		return (this.protocol() === "HTTPS");
	},
	
	absoluteWebPath: function(url) {
		var protocol = Config.absoluteHttpPath;
		if (this.isSecure()) {
			protocol = Config.absoluteHttpsPath;
		}
		return (url) ? protocol + "/" + url : protocol;
	},	
	
	redirect: function(url, t) {
		if (t) {
			self.setTimeout("self.location.href = '" + url + "';", t * 1000);
		} else {
			self.location.href = url;
		}
	},
	
	refresh: function() {
		location.reload(true);
	},		
	
	removeParam: function(p, url) {
		url			= url || "";
		var pos		= url.indexOf("?");
		var href	= (pos != -1) ? url.substring(0, pos + 1) : "";	
		var query	=  url.substring(pos + 1);
		var params	= query.split("&");
		query = "";

		// Create new list built on the values we DO want
		for (var i = 0, c = params.length; i < c; i++) {
			var param = params[i];
			if (param.substring(0, param.indexOf("=")) !== p) {
				query += "&" + param;
			}
		}

		// Assign new value and trim the first & character
		query = query.substring(1);
		return href + query;
	},
	
	replaceParam: function(p, v, url) {
		if (!url) {
			url = location.href;
		}
		if (url.indexOf(p) > 0) {
			var firstPart = url.substring(0, url.indexOf(p) + p.length + 1);
			var secondPart = url.substring(url.indexOf(p) + p.length + 1);

			// Send back the new Url
			if (secondPart.indexOf("&") > 0) {
				secondPart = secondPart.substring(secondPart.indexOf("&"));
				return firstPart + encodeURIComponent(v) + secondPart;
			} else {
				return firstPart + encodeURIComponent(v);
			}
		} else {
			return url;
		}
	},
	
	addParam: function(p, v, url) {
		// Exit if empty
		if (p == null || p == "") { return; }
		//if (!url) { url = location.href; }

		// If p is JSON, loop through and add the params
		if (typeof p === "object") {
			for (var value in p) if (p.hasOwnProperty(value)) {
				url += "&" + encodeURIComponent(value) + "=" + encodeURIComponent(p[value]);
			}
		} else if (typeof p === "string") {
			if (v) {
				// If p and v are strings, add the params
				url += "&" + encodeURIComponent(p) + "=" + encodeURIComponent(v);
			} else {
				// If p is just a string then add it
				url += "&" + p;
			}
		}

		// Clean the parameters up
		if (url.charAt(0) === "&") {
			url = url.substring(1);
		}
		return url;
	}
};

/* Validation
------------------------------*/
var Validation = {

    // * 
	// isNumeric - tests the input is a numeric value
	// ----------------------------------------------------------------------
	isNumeric: function(input) {
		var validCharacters = "0123456789.";
		var isNumber = true;
		var character;
		for (var i = 0, c = input.length; i < c && isNumber == true; i++) { 
			character = input.charAt(i); 
			if (validCharacters.indexOf(character) == -1) {
				isNumber = false;
				break;
			}
		}
		return isNumber;
	}
};


Core.AlternativeImage = 
{
    theImage : new Array(),
    theSrc : new Array(),
    init : function(folder, missingFolder)  
    {
        var imgs = document.getElementsByTagName('img');

        for (i=0; i<imgs.length; i++) 
        {
            //image to add the onerror event
            var img = imgs[i];

            //path of the image
            var imgSrc = img.src;

            //index of the first character of the container folder name
            var folderBegin = imgSrc.lastIndexOf(folder);

            if (folderBegin == -1)
            {
                continue;
            }

            //index of the first character of the missing image file name
            var imgBegin = folderBegin + folder.length + 1;

            //index of the last character of the missing image file name
            var imgEnd = imgSrc.lastIndexOf('/');

            //length of the missing image file name
            var imgSize = imgSrc.substring(imgBegin, imgEnd);

            //iamge type
            var extension = imgSrc.substring(imgSrc.lastIndexOf('.'));

            //the path to the missing image file
            var onerr = imgSrc.substring(0, imgBegin) + missingFolder + '/' + imgSize + extension;

            //the images are already loaded, so the onerror event has already been fired
            //create a new image object, attach the onerror event to a function and on event fire replace the 
            //src of the original img tag with the missing image path   
            var oImage = new Image;
            this.theImage[img.id] = img;
            this.theSrc[img.id] = onerr;
            oImage.id = img.id;
            oImage.onerror = this.onError;
            oImage.src = imgSrc;
        }
    },
    onError : function()
    {
        Core.AlternativeImage.theImage[this.id].src = Core.AlternativeImage.theSrc[this.id];
    }
};

Core.Search = 
{
    init : function()
    {
        var txtSearch = document.getElementById("textSearch");
        if (txtSearch)
        {
	        txtSearch.onkeydown = function (oEvent) 
	        {
	            Core.Form.assignButton(oEvent, "searchSubmit");
	        }
        }
        
        txtSearch = document.getElementById("textRefinedSearch");
        if (txtSearch)
        {
	        txtSearch.onkeydown = function (oEvent) 
	        {
	            Core.Form.assignButton(oEvent, "searchRefinedSubmit");
	        }
        }
    }
};
