

/*
	name			: ClassBehaviours, the javascript framework based on class-name parsing
	update			: 9.11.9
	author			: Maurice van Creij, Marc Molenwijk
	dependencies	: jquery.classbehaviours.js
	info			: http://www.classbehaviours.com/

    This file is part of jQuery.classBehaviours.

    ClassBehaviours is a javascript framework based on class-name parsing.
    Copyright (C) 2008  Maurice van Creij

    ClassBehaviours is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ClassBehaviours is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ClassBehaviours. If not, see http://www.gnu.org/licenses/gpl.html.
*/

	// create the jQuery object if it doesn't already exist
	if(typeof(jQuery)=='undefined') jQuery = function(){};

	// create the root classbehaviours object if it doesn't already exist
	if(typeof(jQuery.classBehaviours)=='undefined') jQuery.classBehaviours = function(){};

	// create the handlers child object if it doesn't already exist
	if(typeof(jQuery.classBehaviours.handlers)=='undefined') jQuery.classBehaviours.handlers = function(){}

	// AJAX interface
	jQuery.classBehaviours.ajax = {
		// properties
		queue: new Array(),
		// utilities
		getNodeValue: function(node){
			// get the text value from a node if there is one
			strValue = (node.childNodes.length>0) ? node.firstChild.nodeValue : null ;
			// return it as text or a number
			return (isNaN(strValue) || strValue==null) ? strValue : parseInt(strValue);
		},
		setNodeValue: function(node,strValue){
			// if this node already has a textNode
			if(node.childNodes.length>0){
				// set the value of the existing textNode
				node.firstChild.nodeValue = strValue;
			}else{
				// or make a new textNode
				var objNewNode = ajax.createTextNode(strValue);
				node.appendChild(objNewNode);
			}
		},
		getChildNumber: function(node){
			var nodes = node.parentNode.childNodes;
			// look for the matching node in a list of childNodes
			var intTextNodes = 0;
			for(var intA=0; intA<nodes.length; intA++){
				// count the amount of text nodes
				if(nodes[intA].nodeName == '#text') intTextNodes += 1;
				// return the found node and substract the amount of text nodes
				if(node==nodes[intA]) return intA - intTextNodes;
			}
			// return null if no match was found
			return null;
		},
		serialize: function(node, inner){
			// if the standard method is valid
			if(typeof(XMLSerializer)!='undefined'){
				nodeXml = (new XMLSerializer()).serializeToString(node);
			}
			// if this is MSIE and XML was given
			else if(node.xml!=null){
				nodeXml = node.xml;
			}
			// if this is MSIE and a whole document was given
			else if(node.getElementsByTagName('HTML').length>0){
				nodeXml = '<!DOCTYPE html><HTML>' + node.getElementsByTagName('HTML')[0].innerHTML + '</HTML>';
			}
			// if this is MSIE and an HTML4 fragment was given
			else if(node.innerHTML!=null && node.innerHTML!=''){
				nodeXml = '<' + node.nodeName + ' class="' + node.className + '" id="' + node.id + '">' + node.innerHTML + '</' + node.nodeName + '>';
			}
			// if this is MSIE and an HTML5 fragment was given
			else {
				// pick parent nodes until a node is found for which the innerHTML actually works
				nodeXml = '';
				nodeRoot = node;
				while(nodeRoot!=nodeRoot.parentNode && nodeXml==''){
					// try the next parent
					nodeRoot = nodeRoot.parentNode;
					// get the innerHTML of that
					nodeXml = nodeRoot.innerHTML;
				}
				// to find the tag name of the string, look for the id in the string
				idIndex = nodeXml.indexOf('id="' + node.id + '"');
				if(idIndex<0) idIndex = nodeXml.indexOf('id=' + node.id + ' ');
				if(idIndex<0) idIndex = nodeXml.indexOf('id=' + node.id + '>');
				// split the string before this position
				tagName = nodeXml.substring(0, idIndex);
				// find the last < and split it after
				openTagIndex = tagName.lastIndexOf('<');
				tagName = tagName.substring(openTagIndex+1);
				// find the first ' ' and split it before
				tagName = tagName.substring(0, tagName.lastIndexOf(' '));
				// split the string after the id position
				endTags = nodeXml.substring(idIndex);
				// while the close tag was not found and the string did not end
				charCount = openTagIndex + 1;
				tagCount = 1;
				tries = 0;
				while(tagCount>0 && tries<5){
					// look forward through the string to count similar tags
					nextStart = nodeXml.indexOf('<' + tagName, charCount);
					if(nextStart==-1) nextStart = 1000000;
					nextClose = nodeXml.indexOf('</' + tagName + '>', charCount);
					if(nextClose==-1) nextClose = 1000000;
					// if you find a similar opening tag add 1 to the count
					if(nextStart<nextClose){
						tagCount += 1;
						charCount = nextStart + 1;
					}
					// if you find a similar closing tag substract 1 from the count
					if(nextClose<nextStart){
						tagCount -= 1;
						charCount = nextClose + 1;
					}
					// if the count reaches 0 the proper closing tag was found
					tries += 1;
				}
				// cut off the rest of the string using the character counter
				closeTagIndex = nextClose + tagName.length + 3;
				// return the resulting clip
				nodeXml = nodeXml.substring(openTagIndex, closeTagIndex);
			}
			// remove the outer tag if required
			if(inner){
				// split after first > and before last <
				nodeXml = nodeXml.substring(nodeXml.indexOf('>')+1, nodeXml.lastIndexOf('<'));
			}
			// give the extracted element back
			return nodeXml;
		},
		deserialize: function(text){
			newElement = document.createElement('DIV');
			newElement.innerHTML = text;
			return newElement;
		},
		defaultProgress: function(progressStatus, progressNode, progressError){
			// fill the refered node with a progress report
			progressNode.innerHTML = (progressStatus>-1) ? 'Loading: ' + Math.round(progressStatus * 100) + '%' : 'Error: ' + progressError ;
		},
		defaultLoad: function(loadXml, loadNode, loadText){
			// fill the refered node with the returned html string
			loadNode.innerHTML = loadText.split('<body>')[1].split('</body>')[0];
		},
		getPostValues: function(node, nodeId){
			// use the id if needed
			if(nodeId!=null) node = document.getElementById(nodeId);
			// get all elements of this form
			formNode = jQuery.classBehaviours.utilities.rootNode(node, 'FORM');
			rootNode = jQuery.classBehaviours.utilities.rootNode(node, 'FIELDSET');
			allNodes = rootNode.getElementsByTagName('*');
			postValues = '';
			// see if we can do anything to make it easier for .NET
	        // .NET replaces the last _ with a $ for eventtarget validation
	        eventTarget = '';
	        split = node.id.split("_");
	        if (split.length > 1) {
	            for (var a = 0; a < split.length; a++)
	                if (split[a] != '')
	                eventTarget += (a == split.length - 1 ? '$' + split[a] : '_' + split[a]);
	        }
	        else eventTarget = node.id;
	        postValues = '__EVENTTARGET=' + eventTarget + '&';
			// for all elements
			for(var a=0; a<allNodes.length; a++){
				// build the query string from the name and value pairs
				if(
					allNodes[a].nodeName=='INPUT' ||
					allNodes[a].nodeName=='SELECT' ||
					allNodes[a].nodeName=='TEXTAREA'
				)
					if(
						allNodes[a].getAttribute('type')!='submit' &&
						allNodes[a].getAttribute('type')!='image' &&
						allNodes[a].getAttribute('type')!='button' &&
						allNodes[a].getAttribute('type')!='reset'
					)
						//  Add all except the viewstate and eventtarget (.NET)
						if(allNodes[a].name!='__VIEWSTATE' && allNodes[a].name!='__EVENTTARGET')
							postValues += (allNodes[a].checked || (allNodes[a].type!='radio' && allNodes[a].type!='checkbox')) ?
								allNodes[a].name + '=' + escape(allNodes[a].value) + '&' :
								'';
			}
			// add the value of the pressed button
			if(node.nodeName == 'BUTTON' || node.getAttribute('type')=='submit' || node.getAttribute('type')=='button') postValues += node.id + '=' + node.value + '&';
			// add the cookie value too
			if (document.cookie != null) postValues += document.cookie.replace(/; /gi, "&");
			// return the values
			return postValues;
		},
		// methods
		addRequest: function(url, loadHandler, progressHandler, post, referingObject){
			// get the first free slot in the que
			index = this.queue.length;
			// add new request to the end of the que
			this.queue[index] = new this.HttpRequest();
			// set request constants
			this.queue[index].idx			=	index;
			this.queue[index].url			=	url;
			this.queue[index].post			=	post;
			this.queue[index].method		=	(post!=null) ? 'POST' : 'GET' ;
			// request events
			this.queue[index].doOnLoad		=	loadHandler;
			this.queue[index].doOnProgress	=	progressHandler;
			this.queue[index].referObject	=	referingObject;
			// request properties
			this.queue[index].time			=	new Date();
			// ask the queue handler to handle the next queued item
			this.handleQueue();
			// return false
			return false;
		},
		makeRequest: function(queued){
			// branch for native XMLHttpRequest object
			if(window.XMLHttpRequest){
				queued.request = new XMLHttpRequest();
				queued.request.onreadystatechange = this.progress;
				queued.request.open(queued.method, queued.url, true);
				if(queued.method == 'POST'){
					queued.request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
					queued.request.setRequestHeader("Content-length", queued.post.length);
					queued.request.setRequestHeader("Connection", "close");
				}
				queued.request.send(queued.post);
			// branch for IE/Windows ActiveX version
			}else if(window.ActiveXObject){
				queued.request = new ActiveXObject("Microsoft.XMLHTTP");
				queued.request.onreadystatechange = this.progress;
				queued.request.open(queued.method, queued.url, true);
				if(queued.method == 'POST'){
					queued.request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
					queued.request.setRequestHeader("Content-length", queued.post.length);
					queued.request.setRequestHeader("Connection", "close");
				}
				queued.request.send(queued.post);
			// if all else fails: load the document in an iFrame
			}else if(window.frames){
				// create an iframe to read the document in
					objIframe = document.createElement("IFRAME");
					objIframe.src = queued.url;
					objIframe.id = "feedimport0";
					objIframe.name = "feedimport0";
					objIframe.style = "visibility : invisible; position : absolute; left : -1600px; top : -1600px;";
					//objIframe.onload = ajax_load; // Doesn't work in Opera
				// append the iframe to the document
					document.body.appendChild(objIframe);
				// wait for the iframe to load
				this.wait();
			}
		},
		handleQueue: function(){
			queue = jQuery.classBehaviours.ajax.queue;
			// if the first item in the queue is a completed request
			if(queue.length>0){
				if(queue[0].ready==4 /*&& ajax.queue[0].status==200*/){
					// remove the completed request
					queue.reverse();
					queue.length = queue.length - 1;
					queue.reverse();
				}
			}
			// if the first item in the queue isn't allready in progress
			if(queue.length>0){
				if(!(queue[0].ready<4 && queue[0].ready!=null)){
					this.makeRequest(queue[0]);
				}
			}
		},
		// events
		progress: function(){
			queued = jQuery.classBehaviours.ajax.queue[0];
			// remember the readyState
			queued.ready = queued.request.readyState;
			// only if req shows "complete"
			if(queued.request.readyState == 4){
				// remember the status
				queued.status = queued.request.status;
				// only if "OK"
				if(queued.request.status == 200 || queued.request.status == 304){
					// update optional progress indicator code
					if(queued.doOnProgress) queued.doOnProgress(4, queued.referObject, queued.request.status, queued.time);
					// get the imported text
					queued.text = queued.request.responseText;
					// get the imported document
					queued.document = queued.request.responseXML;
					// if the document is empty use a deserialized version of the text instead
					if(queued.document==null) queued.document = jQuery.classBehaviours.ajax.deserialize(queued.text)
					else if(queued.document.childNodes.length==0) queued.document = jQuery.classBehaviours.ajax.deserialize(queued.text);
					// trigger the load event
					if(queued.doOnLoad) queued.doOnLoad(queued.document, queued.referObject, queued.text, queued.time);
					// request the next item in the queue to be handled
					jQuery.classBehaviours.ajax.handleQueue();
				}else{
					// update optional progress indicator code
					if(queued.doOnProgress) queued.doOnProgress(-1, queued.referObject, queued.request.status, queued.time);
				}
			}else{
				// update optional progress indicator code
				if(queued.doOnProgress) queued.doOnProgress(queued.request.readyState, queued.referObject, 200, queued.time);
			}
			// return the status if desired
			return queued.request.readyState;
		},
		wait: function(){
			queued = jQuery.classBehaviours.ajax.queue[0];
			// if the xml document has loaded in the iframe
			if(window.frames["feedimport0"]){
				// define the xml document object
				queued.document = window.frames["feedimport0"].document;
				queued.text = window.frames["feedimport0"].document.body.innerHTML;
				// what to do after the xml document loads
				queued.doOnLoad(queued.document, queued.referObject, queued.text, queued.time);
			// else try again in a while
			}else{
				setTimeout("ajax.wait()",256);
			}
		}
	}
		// prototype http request object
		jQuery.classBehaviours.ajax.HttpRequest = function(){
			// request constants
			this.idx			=	null;
			this.url			=	null;
			this.post			=	null;
			this.method			=	'GET';
			// request events
			this.doOnLoad		=	null;
			this.doOnProgress	=	null;
			this.referObject	=	null;
			// request properties
			this.request		=	null;
			this.document		=	null;
			this.text			=	null;
			this.ready			=	null;
			this.status			=	null;
			this.time			=	null;
		}

	// debug console
	jQuery.classBehaviours.console = {
		// porperties
		id: 'debugConsole0',
		limit: 32,
		// methods
		debug: function(){
			// create the debug console if it doesn't exist yet
			debugConsole = document.getElementById(jQuery.classBehaviours.console.id);
			if(debugConsole==null){
				// create a new console node
				newConsole = document.createElement('div');
				newConsole.id = jQuery.classBehaviours.console.id;
				newText = document.createTextNode('-- newest at top --');
				newConsole.appendChild(newText);
				document.body.appendChild(newConsole);
				debugConsole = document.getElementById(jQuery.classBehaviours.console.id);
			}
			// set the console's properties
			if(debugConsole.style.background=='') 	debugConsole.style.background = '#ffffff url(../images/button_passive.png) no-repeat 0px 0px';
			if(debugConsole.style.border=='') 		debugConsole.style.border = 'solid 1px #000000';
			if(debugConsole.style.bottom=='') 		debugConsole.style.bottom = 'auto';
			if(debugConsole.style.height=='') 		debugConsole.style.height = (navigator.userAgent.indexOf('MSIE 6')>-1) ? '580px' : '98%' ;
			if(debugConsole.style.left=='') 		debugConsole.style.left = 'auto';
			if(debugConsole.style.overflow=='') 	debugConsole.style.overflow = 'auto';
			if(debugConsole.style.padding=='') 		debugConsole.style.padding = '1% 1% 1% 1%';
			if(debugConsole.style.position=='') 	debugConsole.style.position = (navigator.userAgent.indexOf('MSIE 6')>-1) ? 'absolute' : 'fixed' ;
			if(debugConsole.style.right=='') 		debugConsole.style.right = '-1px';
			if(debugConsole.style.top=='') 			debugConsole.style.top = '-1px';
			if(debugConsole.style.width=='') 		debugConsole.style.width = '128px';
			debugConsole.onclick = jQuery.classBehaviours.console.move;
			jQuery.classBehaviours.fader.setFade(debugConsole, 75);
			// send all the incoming arguments to the debug console
			newList = document.createElement('ul');
			for(var a=0; a<arguments.length; a++){
				// create a list item for each argument
				newListItem = document.createElement('li');
				newListText = document.createTextNode(arguments[a]);
				newListItem.appendChild(newListText);
				newList.appendChild(newListItem);
			}
			debugConsole.insertBefore(newList, debugConsole.firstChild);
			// if there are too many enties, remove a few
			allLists = debugConsole.getElementsByTagName('ul');
			if(allLists.length>jQuery.classBehaviours.console.limit)
				for(var a=allLists.length-1; a>jQuery.classBehaviours.console.limit; a--)
					removedChild = debugConsole.removeChild(allLists[allLists.length-1]);
		},
		clear: function(){
			// clear the entries
			debugConsole = document.getElementById(jQuery.classBehaviours.console.id);
			if(debugConsole!=null){
				allLists = debugConsole.getElementsByTagName('ul');
				for(var a=allLists.length-1; a>=0; a--)
					removedChild = debugConsole.removeChild(allLists[allLists.length-1]);
			}
		},
		html: function(string){
			string = '<xmp>' + string + '</xmp>'
			this.debug(string)
		},
		// events
		move: function(that){
			var node = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the console
			debugConsole = document.getElementById(jQuery.classBehaviours.console.id);
			// toggle through several console positions
			if(debugConsole.style.right == '-1px' && debugConsole.style.width == '128px'){
				debugConsole.style.bottom = 'auto';
				debugConsole.style.height = (navigator.userAgent.indexOf('MSIE 6')>-1) ? '580px' : '98%' ;
				debugConsole.style.left = '-1px';
				debugConsole.style.right = 'auto';
				debugConsole.style.top = '-1px';
				debugConsole.style.width = '128px';
				debugConsole.style.zIndex = '100000';
			}else if(debugConsole.style.left == '-1px' && debugConsole.style.width == '128px'){
				debugConsole.style.bottom = '-1px';
				debugConsole.style.height = '128px';
				debugConsole.style.left = '-1px';
				debugConsole.style.right = 'auto';
				debugConsole.style.top = 'auto';
				debugConsole.style.width = '98%';
				debugConsole.style.zIndex = '100000';
			}else if(debugConsole.style.bottom == '-1px' && debugConsole.style.width == '98%'){
				debugConsole.style.bottom = 'auto';
				debugConsole.style.height = (navigator.userAgent.indexOf('MSIE 6')>-1) ? '580px' : '98%' ;
				debugConsole.style.left = 'auto';
				debugConsole.style.right = '-1px';
				debugConsole.style.top = '-1px';
				debugConsole.style.width = '128px';
				debugConsole.style.zIndex = '100000';
			}
		}
	}

	// cookies Library
	jQuery.classBehaviours.cookies = {
		// methods
		getDaysFromNow: function(intDays){
			var dateCurrent = new Date();
			var intCurrent = Date.parse(dateCurrent);
			var intPeriod = intDays*24*60*60*1000;
			var datePeriodInFuture = new Date(intCurrent+intPeriod);
			return datePeriodInFuture;
		},
		setCookie: function(name, value, expires, path, domain, secure) {
			var curCookie = name + "=" + escape(value) +
				((expires) ? "; expires=" + expires.toGMTString() : "") +
				((path) ? "; path=" + path : "") +
				((domain) ? "; domain=" + domain : "") +
				((secure) ? "; secure" : "");
			document.cookie = curCookie;
		},
		getCookie: function(name) {
			var dc = document.cookie;
			var prefix = name + "=";
			var begin = dc.indexOf("; " + prefix);
			if (begin == -1) {
				begin = dc.indexOf(prefix);
				if (begin != 0) return null;
			}else{
				begin += 2;
			}
			var end = document.cookie.indexOf(";", begin);
			if (end == -1)
				end = dc.length;
			return unescape(dc.substring(begin + prefix.length, end));
		},
		deleteCookie: function(name, path, domain) {
			if (getCookie(name)) {
				document.cookie = name + "=" +
				((path) ? "; path=" + path : "") +
				((domain) ? "; domain=" + domain : "") +
				"; expires=Thu, 01-Jan-70 00:00:01 GMT";
			}
		},
		fixDate: function(date) {
			var base = new Date(0);
			var skew = base.getTime();
			if (skew > 0)
				date.setTime(date.getTime() - skew);
		},
		makeBoolean: function(strIn){
			if(strIn=='true'){
				booOut = true;
			}else{
				booOut = false;
			}
			return booOut;
		},
		csv2array: function(csvIn){
			return csvIn.split(',');
		},
		array2csv: function(arrIn){
			return ''+arrIn;
		}
	}

	// decorative fader animations
	jQuery.classBehaviours.fader = {
		// properties
		getFade: function(node){
			var fadeValue = null;
			if(node!=null){
				// get the fade value using the proper method
				if(typeof(node.style.MozOpacity)!='undefined')	fadeValue = Math.round(parseFloat(node.style.MozOpacity)*100);
				if(typeof(node.style.filter)!='undefined')		fadeValue = parseInt(node.filters.alpha.opacity);
				if(typeof(node.style.opacity)!='undefined')		fadeValue = Math.round(parseFloat(node.style.opacity)*100);
			}
			// return the value
			return fadeValue;
		},
		setFade: function(node, amount){
			if(node!=null){
				// set the fade value using the proper method
				if(typeof(node.style.MozOpacity)!='undefined')	node.style.MozOpacity = amount/100;
				if(typeof(node.style.filter)!='undefined')		node.style.filter = "alpha(opacity=" + amount + ")";
				if(typeof(node.style.opacity)!='undefined')		node.style.opacity = amount/100;
			}
			/*
			filter:alpha(opacity=50);	imageobject.filters.alpha.opacity=opacity
			-moz-opacity: 0.5;			imageobject.style.MozOpacity=opacity/100
			opacity: 0.5;
			-khtml-opacity: 0.5;
			*/
		},
		getSize: function(node){
			// measure the height of the container
			var nodeWidth = node.offsetWidth;
			var nodeHeight = node.offsetHeight;
			// measure the height of all the childnodes of the container
			var totalWidth = 0;
			var totalHeight = 0;
			var contents = node.childNodes;
			for(var a=0; a<contents.length; a++){
				totalWidth += (contents[a].offsetWidth) ? contents[a].offsetWidth : 0 ;
				totalHeight += (contents[a].offsetHeight) ? contents[a].offsetHeight : 0 ;
			}
			// pass back the largest number
			return new Array(nodeWidth, nodeHeight, totalWidth, totalHeight);
		},
		setSize: function(node, xAmount, yAmount){
			if(xAmount!=null) node.style.width = xAmount + 'px';
			if(yAmount!=null) node.style.height = yAmount + 'px';
		},
		// methods
		fade: function(id, start, end, step, delay, acceleration, evalOnEnd){
			var cf = jQuery.classBehaviours.fader;
			// get the target node
			target = document.getElementById(id);
			// get the start value if missing
			if(start==null) 		start = cf.getFade(target);
			if(end==null) 			end = 100;
			if(step==null) 			step = 1;
			if(delay==null) 		delay = 10;
			if(acceleration==null) 	acceleration = 1;
			if(evalOnEnd==null) 	evalOnEnd = '';
			// calculate the new value
			if(start<end)		{value = (start+step>end) ? end : start+step ;}
			else if(start>end)	{value = (start-step<end) ? end : start-step ;}
			// set the fade
			cf.setFade(target, value);
			// order the next step
			if(value!=end) 		{setTimeout("jQuery.classBehaviours.fader.fade('"+id+"',"+value+","+end+","+(step+acceleration)+","+delay+","+acceleration+",'"+evalOnEnd+"')", delay);}
			else 				{eval(evalOnEnd);}
		},
		size: function(id, start, end, step, delay, acceleration, evalOnEnd){
			var cf = jQuery.classBehaviours.fader;
			// get the target node
			target = document.getElementById(id);
			// get the start value if missing
			if(start==null) 		start = cf.getSize(target)[1];
			if(end==null) 			end = cf.getSize(target)[3];
			if(step==null) 			step = 10;
			if(delay==null) 		delay = 10;
			if(acceleration==null) 	acceleration = 10;
			if(evalOnEnd==null) 	evalOnEnd = '';
			// calculate the new value
			if(start<end)		{value = (start+step>end) ? end : start+step ;}
			else if(start>end)	{value = (start-step<end) ? end : start-step ;}
			// set the fade
			cf.setSize(target, null, value);
			// order the next step
			if(value!=end) 		{setTimeout("jQuery.classBehaviours.fader.size('"+id+"',"+value+","+end+","+(step+acceleration)+","+delay+","+acceleration+",'"+evalOnEnd+"')", delay);}
			else 				{eval(evalOnEnd);}
		},
		/* START: legacy functions */
		fadeIn: function(id, step, delay, evalOnEnd, acceleration){
			jQuery.classBehaviours.fader.fade(id, 0, 100, step, delay, acceleration, evalOnEnd);
		},
		fadeOut: function(id, step, delay, evalOnEnd, acceleration){
			jQuery.classBehaviours.fader.fade(id, 100, 0, step, delay, acceleration, evalOnEnd);
		},
		crossFade: function(idIn, idOut, amount, step, delay, evalOnEnd, acceleration){
			jQuery.classBehaviours.fader.fade(idIn, 0, 100, step, delay, acceleration, evalOnEnd);
			jQuery.classBehaviours.fader.fade(idOut, 100, 0, step, delay, acceleration, '');
		},
		grow: function(id, step, delay, evalOnEnd, acceleration){
			jQuery.classBehaviours.fader.size(id, 1, null, step, delay, acceleration, evalOnEnd);
		},
		shrink: function(id, step, delay, evalOnEnd, acceleration){
			jQuery.classBehaviours.fader.size(id, null, 1, step, delay, acceleration, evalOnEnd);
		}
		/* END: legacy functions */
	}

	// general purpose functions
	jQuery.classBehaviours.utilities = {
		// returns all nodes of the same class
		getElementsByClassName: function(className, node){
			// use the whole body if no target was provided
			target = (node!=null) ? node : document ;
			// make an empty array for the results
			var foundNodes = new Array();
			// for all elements in the parent node
			var allNodes = (target.all) ? target.all : target.getElementsByTagName("*");
			for(var a=0; a<allNodes.length; a++){
				// if the item has a className
				if(allNodes[a].className){
					// process the classname
					nodeClass = allNodes[a].className + ' ';
					// add it to the results if the classname was found
					if(nodeClass.indexOf(className+' ')>-1) foundNodes[foundNodes.length] = allNodes[a];
				}
			}
			// return the list
			return foundNodes;
		},
		// emulates getElementById for XML documents
		getXmlElementById: function(id, doc, echo){
			// default value
			node = null ;
			// if a valid id was given
			if(id!=null){
				// look through all nodes
				allNodes = doc.getElementsByTagName('*');
				// until you find one with the right ID
				var a = 0;
				while(node==null && a<allNodes.length){
					if(allNodes[a].getAttribute('id')==id){
						node = allNodes[a];
					}
					a += 1;
				}
			}
			// return the cleaned content
			return (echo && node==null) ? doc : node;
		},
		// places a sibling node after a given node
		insertAfter: function(parentNode, siblingNode, newNode){
			nextNode = jQuery.classBehaviours.utilities.nextNode(siblingNode);
			if(nextNode==siblingNode) parentNode.appendChild(newNode)
			else parentNode.insertBefore(newNode, nextNode);
		},
		// detaries the available room on the screen
		screenHeight: function(){
			return (window.innerHeight) ? window.innerHeight : (document.documentElement.clientHeight) ? document.documentElement.clientHeight : document.body.clientHeight ;
		},
		// return a parameter from the url's query strings
		getQueryParameter: function(paramName, defaultValue){
			// split the query string at the parameter name
			var queryParameters = document.location.search.split(paramName+"=");
			// split the parameter value from the rest of the string
			var queryParameter = (queryParameters.length>1) ? queryParameters[1].split("&")[0] : null ;
			// return the value
			return (queryParameter!=null) ? queryParameter : defaultValue ;
		},
		// gets the value of a parameter from a className
		getClassParameter: function(targetNode, paramName, defaultValue){
			if(targetNode!=null){
				// get the class parameter from the classname
				var classParameter = targetNode.className;
				// split the classname between the parameter name
				classParameter = (classParameter!=null) ? classParameter.split(paramName + '_') : new Array();
				// split the second piece between spaces and take the first part,  if there are two pieces
				classParameter = (classParameter.length>1) ? classParameter[1].split(' ')[0] : null ;
				// return the value
				return (classParameter!=null) ? classParameter : defaultValue ;
			}
		},
		// sets the value of a parameter from a className
		setClassParameter: function(targetNode, paramName, newValue){
			if(targetNode!=null){
				// create a default value, if there isn't one
				if(targetNode.className.indexOf(' ' + paramName + '_')<0) targetNode.className += ' ' + paramName + '_0';
				// get the old value
				oldValue = this.getClassParameter(targetNode, paramName, null);
				// replace the old value
				if(oldValue!=null) targetNode.className = targetNode.className.replace(paramName+'_'+oldValue, paramName+'_'+newValue);
			}
		},
		// get the next node without worrying about text nodes
		nextNode: function(node, count){
			testNode = node;
			if(count==null) count = 1;
			// look for the next html node
			for(var a=0; a<count; a++){
				do {
					testNode = testNode.nextSibling;
					if(testNode==null) testNode = node;
				}while(testNode.nodeName.indexOf('#text')>-1);
			}
			// return it
			return testNode;
		},
		// get the previous node without worrying about text nodes
		previousNode: function(node, count){
			testNode = node;
			if(count==null) count = 1;
			// look for the previous html node
			for(var a=0; a<count; a++){
				do {
					testNode = testNode.previousSibling;
					if(testNode==null) testNode = node;
				}while(testNode.nodeName.indexOf('#text')>-1);
			}
			// return it
			return testNode;
		},
		// get the first real child node without worrying about text nodes
		firstNode: function(node, count){
			return this.nextNode(node.firstChild, count);
		},
		// find the parent node with the given classname
		rootNode: function(node, rootTag, rootId, rootClass){
			// try parent nodes until you find the one which meets the conditions
			rootFound = false;
			while(!rootFound && node.nodeName!='BODY'){
				rootFound = (rootTag && node.nodeName) ? (node.nodeName.indexOf(rootTag)>-1) : rootFound ;
				rootFound = (rootId && node.id) ? (node.id.indexOf(rootId)>-1) : rootFound ;
				rootFound = (rootClass && node.className) ? (node.className.indexOf(rootClass)>-1) : rootFound ;
				node = (!rootFound) ? node.parentNode : node;
			}
			// pass it back
			return node;
		},
		// returns the visible display state needed for this element
		getVisibleState: function(node){
			// what kind of node is this
			switch(node.nodeName.toLowerCase()){
				case 'table' : visibleState='table' ; break;
				case 'thead' : visibleState='table-header-group' ; break;
				case 'tfoot' : visibleState='table-footer-group' ; break;
				case 'tbody' : visibleState='table-row-group' ; break;
				case 'tr' : visibleState='table-row' ; break;
				case 'td' : visibleState='table-cell' ; break;
				case 'th' : visibleState='table-cell' ; break;
				default : visibleState='block';
			}
			// apply the state
			return (document.all && navigator.userAgent.indexOf('Opera')<0) ? 'block' : visibleState;
		},
		// hide select form elements for graphic glitches in certain browsers
		hideSelects: function(node){
			if(
				navigator.userAgent.indexOf('MSIE 6')>-1 ||
				(navigator.userAgent.indexOf('Firefox/2')>-1 && navigator.userAgent.indexOf('Mac')>-1)
			){
				allSelects = (node) ? node.getElementsByTagName('SELECT') : document.getElementsByTagName('SELECT') ;
				for(var a=0; a<allSelects.length; a++){
					allSelects[a].style.visibility = 'hidden';
				}
			}
		},
		showSelects: function(node){
			if(
				navigator.userAgent.indexOf('MSIE 6')>-1 ||
				(navigator.userAgent.indexOf('Firefox/2')>-1 && navigator.userAgent.indexOf('Mac')>-1)
			){
				allSelects = (node) ? node.getElementsByTagName('SELECT') : document.getElementsByTagName('SELECT') ;
				for(var a=0; a<allSelects.length; a++){
					allSelects[a].style.visibility = 'visible';
				}
			}
		},
		// adds an event-handler the proper way
		addEvent: function(node, eventName, eventHandler){
			if(node.addEventListener) 	node.addEventListener(eventName, eventHandler, false)
			else if(node.attachEvent) 	node.attachEvent("on"+eventName, eventHandler)
			else 						node["on"+eventName] = eventHandler;
			return true;
		}
	}

	// Parser functions
	jQuery.classBehaviours.parser = {
		// status of the parser
		waiting: false,
		// verify the state of the object
		start: function(){
			// if the document is complete enough start the behaviours, else wait until everything is loaded
			var handlersCount = 0;
			for (b in jQuery.classBehaviours.handlers) handlersCount++;
			this.waiting = (handlersCount>0 && document.body) ? this.parseDocument() : jQuery.classBehaviours.utilities.addEvent(window, 'load', this.parseDocument) ;
		},
		// scan the whole document
		parseDocument: function(){
			// pass the document object to the parser
			jQuery.classBehaviours.parser.parseNode(document);
			// return the status
			return false;
		},
		// scan the document object model for target classNames
		parseNode: function(node){
			// for all childnodes of the given node
			var allNodes = node.getElementsByTagName("*");
			for(var a=0; a<allNodes.length; a++){
				// process the classnames of the node
				this.processNode(allNodes[a]);
			}
			// do the same for the parent node
			this.processNode(node);
		},
		// recursive version of the same function
		parseNode: function(node){
			// process the node
			parseChildNodes = (node.className!=null) ? this.processNode(node) : true ;
			// parse any childnodes
			if(parseChildNodes) for(var a=0; a<node.childNodes.length; a++) this.parseNode(node.childNodes[a]);
		},
		// process the classnames of the node
		processNode: function(node){
			// get its className
			nodeClass = ' ' + node.className + ' ';
			// for all class behaviours
			for(b in jQuery.classBehaviours.handlers){
				// if the behaviour name is in the className tested node
				if(nodeClass.indexOf(' ' + jQuery.classBehaviours.handlers[b].name + ' ')>-1){
					// apply its respective behaviour
					jQuery.classBehaviours.handlers[b].start(node);
				}
			}
			// decide if to continue parsing deeper into this branch
			return (nodeClass.indexOf('doNotParse')<0);
		}
	}

	// short-cut wrapper functions
	debug = jQuery.classBehaviours.console.debug;
	getXmlElementById = jQuery.classBehaviours.utilities.getXmlElementById;
	getElementsByClassName = jQuery.classBehaviours.utilities.getElementsByClassName;

	// add this addon to the jQuery object
	if(typeof(jQuery.fn)!='undefined'){
		// set the event handler for this jQuery method
		$(document).ready(
			function(){
// TODO: at the moment this is handled by the individual classbehaviours modules, until this proves too slow
//				$.classBehaviours.parser.parseDocument()
			}
		);
	}else{
		// start the (backup) parsing of classes if the main jQuery library is not available
		jQuery.classBehaviours.parser.start()
	}

