/*	name			: ClassBehaviours, the javascript framework based on class-name parsing	update			: 20080910	author			: Maurice van Creij	dependencies	: classbehaviours.js	info			: http://www.classbehaviours.com/

    This file is part of 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.*/

	// Some markup to avoid graphical glitches	document.writeln(
		'<style type="text/css">.toggleNextNode { cursor : pointer; }</style>' + 
		'<style type="text/css">.hideThisNode { overflow : hidden; visibility : hidden; height : 1px; }</style>' + 		'<style type="text/css">.showThisNode { overflow : hidden; visibility : visible; height : auto; }</style>' + 		'<style type="text/css">.alternative { visibility : hidden; }</style>'
	);
	
	// create the classBehaviours object if it doesn't already
	function ClassBehaviours(){}
	classBehaviours = new ClassBehaviours();
	
		// Parser functions
		function Parser(){
			// status of the parser
			this.waiting		=	false;
			// verify the state of the object
			this.start			=	function(){
										// if the document is complete enough start the behaviours, else wait until everything is loaded
										this.waiting = (classBehaviours.handlers.index.length>0 && document.body) ? this.parseDocument() : classBehaviours.utilities.addEvent(window, 'load', this.parseDocument) ;
									}
			// scan the whole document
			this.parseDocument	=	function(){
										// pass the document object to the parser
										classBehaviours.parser.parseNode(document)
										// return the status
										return false;
									}
			// scan the document object model for target classNames
			this.parseNode		=	function(node){
										// for all childnodes of the given node
										var allNodes = node.getElementsByTagName("*");
										for(var a=0; a<allNodes.length; a++){
											// get its className
											nodeClass = ' ' + allNodes[a].className + ' ';
											// if this node has a className
											if(nodeClass!=null){
												// for all class behaviours
												for(var b=0; b<classBehaviours.handlers.index.length; b++){
													// if the behaviour name is in the className tested node, apply its respective behaviour
													if(nodeClass.indexOf(' ' + classBehaviours.handlers.index[b].name + ' ')>-1) classBehaviours.handlers.index[b].start(allNodes[a]);
												}
											}
										}
									}
		}
		// add this module to the classBehaviours object
		classBehaviours.parser = new Parser;
					// general purpose functions		function Utilities(){
			// returns all nodes of the same class
			this.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;
											}
			// detaries the available room on the screen			this.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			this.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			this.getClassParameter	=	function(targetNode, paramName, defaultValue){											// get the class parameter from the classname											var classParameter = targetNode.className;											// split the classname between the parameter name											classParameter = classParameter.split(paramName + '_');											// 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			this.setClassParameter	=	function(targetNode, paramName, newValue){											oldValue = this.getClassParameter(targetNode, paramName, null);
											if(oldValue!=null) targetNode.className = targetNode.className.replace(paramName+'_'+oldValue, paramName+'_'+newValue);										}			// get the next node without worrying about text nodes			this.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			this.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			this.firstNode			=	function(node, count){											return this.nextNode(node.firstChild, count);										}
			// find the parent node with the given classname
			this.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			this.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
			this.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';
												}
											}
										}
			this.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
			this.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;
										}		}
		// add this module to the classBehaviours object		classBehaviours.utilities = new Utilities;
		
		// decorative fader animations		function Fader(){			// properties			this.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;								}			this.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;									*/								}
			this.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);
								}
			this.setSize	=	function(node, xAmount, yAmount){
									if(xAmount!=null) node.style.width = xAmount + 'px';
									if(yAmount!=null) node.style.height = yAmount + 'px';
								}			// methods
			this.fade 		=	function(id, start, end, step, delay, acceleration, evalOnEnd){
									var cf = 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("classBehaviours.fader.fade('"+id+"',"+value+","+end+","+(step+acceleration)+","+delay+","+acceleration+",'"+evalOnEnd+"')", delay);}
									else 				{eval(evalOnEnd);}
								}
			this.size		=	function(id, start, end, step, delay, acceleration, evalOnEnd){
									var cf = 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("classBehaviours.fader.size('"+id+"',"+value+","+end+","+(step+acceleration)+","+delay+","+acceleration+",'"+evalOnEnd+"')", delay);}
									else 				{eval(evalOnEnd);}
								}
			/* START: legacy functions */			this.fadeIn		=	function(id, step, delay, evalOnEnd, acceleration){
									classBehaviours.fader.fade(id, 0, 100, step, delay, acceleration, evalOnEnd);								}			this.fadeOut	=	function(id, step, delay, evalOnEnd, acceleration){
									classBehaviours.fader.fade(id, 100, 0, step, delay, acceleration, evalOnEnd);								}			this.crossFade	=	function(idIn, idOut, amount, step, delay, evalOnEnd, acceleration){
									classBehaviours.fader.fade(idIn, 0, 100, step, delay, acceleration, evalOnEnd);
									classBehaviours.fader.fade(idOut, 100, 0, step, delay, acceleration, '');								}
			this.grow		=	function(id, step, delay, evalOnEnd, acceleration){
									classBehaviours.fader.size(id, 1, null, step, delay, acceleration, evalOnEnd);
								}
			this.shrink		=	function(id, step, delay, evalOnEnd, acceleration){
									classBehaviours.fader.size(id, null, 1, step, delay, acceleration, evalOnEnd);
								}
			/* END: legacy functions */		}
		// add this module to the classBehaviours object
		classBehaviours.fader = new Fader;
		
		// AJAX interface
		function Ajax(){
			// properties
			this.queue			=	new Array();
			// utilities
			this.getNodeValue	=	function(objNode){
										strValue = (objNode.childNodes.length>0) ? objNode.firstChild.nodeValue : null ;
										return (isNaN(strValue) || strValue==null) ? strValue : parseInt(strValue);
									}
			this.setNodeValue	=	function(objNode,strValue){
										if(objNode.childNodes.length>0){
											objNode.firstChild.nodeValue = strValue;
										}else{
											var objNewNode = ajax.createTextNode(strValue);
											objNode.appendChild(objNewNode);
										}
									}
			this.getChildNumber =	function(objNode){
										var objNodes = objNode.parentNode.childNodes;
										var intTextNodes = 0;
										for(var intA=0; intA<objNodes.length; intA++){
											if(objNodes[intA].nodeName == '#text') intTextNodes += 1;
											if(objNode==objNodes[intA]) return intA - intTextNodes;
										}
										return null;
									}
			this.serialize		=	function serialize(ajax){
										ser = new XMLSerializer();
										str = ser.serializeToString(ajax);
										return(str);
									}
			// methods
			this.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 HttpRequest();
										// set request constants
										this.queue[index].idx			=	index;
										this.queue[index].url			=	url;
										this.queue[index].post			=	post;
										this.queue[index].method		=	(post) ? 'POST' : 'GET' ;
										// request events
										this.queue[index].doOnLoad		=	loadHandler;
										this.queue[index].doOnProgress	=	progressHandler;
										this.queue[index].referObject	=	referingObject;
										// ask the queue handler to handle the next queued item
										this.handleQueue();
									}
			this.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);
											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);
											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();
										}
									}
			this.handleQueue	=	function(){
										queue = 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
			this.progress		=	function(){
										queued = 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(1, queued.referObject);
												// prepare the document
												queued.document = queued.request.responseXML;
												queued.text = queued.request.responseText;
												// trigger the load event
												if(queued.doOnLoad) queued.doOnLoad(queued.document, queued.referObject, queued.text);
												// request the next item in the queue to be handled
												classBehaviours.ajax.handleQueue();
											}else{
												// update optional progress indicator code
												if(queued.doOnProgress) queued.doOnProgress(-1, queued.referObject, queued.request.status);
											}
										}else{
											// update optional progress indicator code
											if(queued.doOnProgress) queued.doOnProgress(queued.request.readyState/4, queued.referObject, 200);
										}
										// return the status if desired
										return queued.request.readyState;
									}
			this.wait			=	function(){
										queued = 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);
										// else try again in a while
										}else{
											setTimeout("ajax.wait()",256);
										}
									}
		}
		
			// prototype http request object
			function HttpRequest(){
				// 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;
			}
		// add this module to the classBehaviours object
		classBehaviours.ajax = new Ajax;
			
		// debug console
		function Console(){
			// porperties
			this.id 		= 	'debugConsole0';
			this.limit 		= 	32;	
			// methods
			this.debug 		= 	function(){
									// create the debug console if it doesn't exist yet
									debugConsole = document.getElementById(classBehaviours.console.id);
									if(debugConsole==null){
										// create a new console node
										newConsole = document.createElement('div');
										newConsole.id = classBehaviours.console.id;
										newText = document.createTextNode('-- newest at top --');
										newConsole.appendChild(newText);
										document.body.appendChild(newConsole);
										debugConsole = document.getElementById(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 = classBehaviours.console.move;
									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>classBehaviours.console.limit) 
										for(var a=allLists.length-1; a>classBehaviours.console.limit; a--)
											removedChild = debugConsole.removeChild(allLists[allLists.length-1]);
								}
			this.clear 		= 	function(){
									// clear the entries
									debugConsole = document.getElementById(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]);
									}
								}
			this.html 		= 	function(string){
									string = '<xmp>' + string + '</xmp>'
									this.debug(string)
								}
			// events
			this.move		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// get the console
									debugConsole = document.getElementById(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';
									}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%';
									}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';
									}
								}
		}
		// add this module to the classBehaviours object
		classBehaviours.console = new Console;
		
		// cookies Library
		function Cookies(){
			// methods
			this.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;
									}
			this.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;
									}
			this.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));
									}
			this.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";
										}
									}
			this.fixDate		=	function(date) {
										var base = new Date(0);
										var skew = base.getTime();
										if (skew > 0)
											date.setTime(date.getTime() - skew);
									}
			this.makeBoolean	=	function(strIn){
										if(strIn=='true'){
											booOut = true;
										}else{
											booOut = false;
										}
										return booOut;
									}
			this.csv2array		=	function(csvIn){
										return csvIn.split(',');
									}
			this.array2csv		=	function(arrIn){
										return ''+arrIn;
									}
		}
		// add this module to the classBehaviours object
		classBehaviours.cookies = new Cookies;
		
		// Handler functions
		function Handlers(){
			this.index 			=	new Array();
		}
		classBehaviours.handlers = new Handlers;
		
			// blinks
			function Blink(){
				// properties
				this.name 		= 	'blink';
				this.nodes 		= 	new Array();
				// methods
				this.start		=	function(node){
										// set the starting class, if not present
										if(node.className.indexOf('blinkon')<0) node.className += " blinkon";
										// make new blink entry
										this.nodes[this.nodes.length] = new Array(node,null,1024);
										// start blink loop
										this.loop(this.nodes.length-1);
									}
				// events
				this.loop		=	function(blinkIndex){
										// what object goes with this index
										blinkObject = this.nodes[blinkIndex][0];
										// toggle the blink class of this object
										blinkObject.className = (blinkObject.className.indexOf('blinkoff')>-1) ? blinkObject.className.replace('blinkoff','blinkon') : blinkObject.className.replace('blinkon','blinkoff');
										// set timeout till the next blink toggle
										this.nodes[blinkIndex][1] = setTimeout('classBehaviours.handlers.blink.loop('+blinkIndex+')',this.nodes[blinkIndex][2]);
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.blink = new Blink;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.blink;
			
			// runs through a sequence of class names
			function AnimatedClassName(){
				// properties
				this.name 		= 	'animatedClassName';
				this.index		=	0;
				this.interval	=	null;
				// methods
				this.start		=	function(node){
										// give an id if the item has none
										node.id = (node.id) ? node.id : this.name + this.index++ ;
										// get the animation properties
										animationDelay = parseInt(classBehaviours.utilities.getClassParameter(node, 'delay', '500'));
										// see if mouse interaction is required
										onlyOnFocus = (classBehaviours.utilities.getClassParameter(node, 'focus', 'no') == 'yes');
										if(onlyOnFocus){
											// set a classname for keeping track of the focus
											node.className += ' interaction_no';
											// set the event handlers
											node.onmouseover = this.play;
											node.onmouseout = this.stop;
											node.onfocus = this.play;
											node.onblur = this.stop;
										}else{
											// start its animation sequence
											this.interval = setInterval('classBehaviours.handlers.animatedClassName.loop("'+node.id+'")', animationDelay);
										}
									}
				// events
				this.play		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// add the interaction marker
										objNode.className = objNode.className.replace('interaction_no', 'interaction_yes');
										// start the animation
										classBehaviours.handlers.animatedClassName.loop(objNode.id);
									}
				this.stop		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// remove the interaction marker
										objNode.className = objNode.className.replace('interaction_yes', 'interaction_no');
									}
				this.loop		=	function(animId){
										animNode = document.getElementById(animId);
										// get the animation properties
										animationStep = parseInt(classBehaviours.utilities.getClassParameter(animNode, 'step', '0'));
										animationLoop = parseInt(classBehaviours.utilities.getClassParameter(animNode, 'loop', '4'));
										animationRepeat = parseInt(classBehaviours.utilities.getClassParameter(animNode, 'repeat', '0'));
										// get the next animation step
										nextAnimationStep = (animationStep<animationLoop) ? animationStep+1 : animationRepeat ;
										// set the next animation step
										animNode.className = animNode.className.replace('step_' + animationStep + ' ', 'step_' + nextAnimationStep + ' ');
										// if this node has the focus, do the animation again, or reset it
										interaction = classBehaviours.utilities.getClassParameter(animNode, 'interaction', null);
										animationDelay = parseInt(classBehaviours.utilities.getClassParameter(animNode, 'delay', '500'));
										if(interaction=='yes'){
											setTimeout('classBehaviours.handlers.animatedClassName.loop("'+animId+'")', animationDelay);
										}else if(interaction=='no'){
											classBehaviours.utilities.setClassParameter(animNode, 'step', '0');
										}
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.animatedClassName = new AnimatedClassName;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.animatedClassName;
			
			// replace in class
			function ClassMouseHover(){
				// properties
				this.name 		= 	'classMouseHover';
				// methods
				this.start		=	function(node){
										node.onmouseover = this.addHover;
										node.onmouseout = this.remHover;
									}
				this.hasNoStateClass 	= 	function(objNode){
												return (objNode.className.indexOf('link')<0 && objNode.className.indexOf('hover')<0 && objNode.className.indexOf('active')<0);
											}
				// events
				this.addHover 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var cmh = classBehaviours.handlers.classMouseHover;
										// replace link by hover
										objNode.className = (cmh.hasNoStateClass(objNode)) ? 'hover ' + objNode.className : objNode.className.replace('link','hover') ;
										// if there is an image within, replace it with the hover state too
										allImages = objNode.getElementsByTagName('IMG');
										if(allImages.length>0) allImages[0].src = allImages[0].src.replace('_link','_hover');
									}
				this.remHover 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var cmh = classBehaviours.handlers.classMouseHover;
										// replace hover by link
										objNode.className = (cmh.hasNoStateClass(objNode)) ? 'link ' + objNode.className : objNode.className.replace('hover','link') ;
										// if there is an image within, replace it with the hover state too
										allImages = objNode.getElementsByTagName('IMG');
										if(allImages.length>0) allImages[0].src = allImages[0].src.replace('_hover','_link');
									}
				this.addActive 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var cmh = classBehaviours.handlers.classMouseHover;
										// replace link by active
										objNode.className = objNode.className.replace('link','active') ;
										// replace hover by active
										objNode.className = objNode.className.replace('hover','active') ;
										// if there's still no active class
										if(cmh.hasNoStateClass(objNode)) objNode.className = 'active ' + objNode.className;
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.classMouseHover = new ClassMouseHover;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.classMouseHover;
			
			// make all sub elements fake the :hover attribute with .hover
			function PseudoHover(){
				// properties
				this.name 		= 	'pseudoHover';
				this.index		=	0;
				this.timeout	=	null;
				// methods
				this.start		=	function(node){
										//for the childnodes of the navigation
										allItems = node.getElementsByTagName('LI');
										for(var a=0; a<allItems.length; a++){
											if(allItems[a].nodeName == 'LI'){
												// add starting properties
												allItems[a].className += (allItems[a].className.indexOf('link')<0) ? ' link' : '' ;
												// add the mouse events
												allItems[a].onmouseover = this.hoverOver;
												allItems[a].onmouseout = this.hoverOff;
											}
										}
									}
				// events
				this.hoverOver	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var psh = classBehaviours.handlers.pseudoHover;
										// cancel the reset time-out
										clearTimeout(psh.timeout);
										// change the classname to show the item in MSIE 6
										objNode.className = objNode.className.replace('link', 'hover');
									}
				this.hoverOff	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var psh = classBehaviours.handlers.pseudoHover;
										// cancel the reset time-out
										clearTimeout(psh.timeout);
										// change the classname to show the item in MSIE 6
										objNode.className = objNode.className.replace('hover', 'link');
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.pseudoHover = new PseudoHover;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.pseudoHover;
		
			// replace in src sub-string
			function SrcMouseHover(){
				// properties
				this.name 			= 	'srcMouseHover';
				this.cache 			= new Array();
				// methods
				this.start			=	function(node){
											this.cacheImages(node);
											node.onmouseover = this.addHover;
											node.onmouseout = this.remHover;
										}
				this.cacheImages	 = 	function(that) {
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// if this is not the image, it must be the parent
											if(!objNode.src) objNode = objNode.getElementsByTagName('IMG')[0];
											// replace link by hover
											var cacheIdx = this.cache.length;
											// hover version
											this.cache[cacheIdx] = new Image();
											this.cache[cacheIdx].src = objNode.src.replace('_link','_hover');
											// active version
											this.cache[cacheIdx+1] = new Image();
											this.cache[cacheIdx+1].src = objNode.src.replace('_link','_active');
										}
				// events
				this.addActive 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// if this is not the image, it must be the parent
										if(objNode.nodeName!='IMG') objNode = objNode.getElementsByTagName('IMG')[0];
										// replace link by active
										objNode.src = objNode.src.replace('_link','_active');
										// replace hover by active
										objNode.src = objNode.src.replace('_hover','_active');
									}
				this.addHover 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// if this is not the image, it must be the parent
										if(!objNode.src) objNode = objNode.getElementsByTagName('IMG')[0];
										// replace link by hover
										objNode.src = objNode.src.replace('_link','_hover');
									}
				this.remHover 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// if this is not the image, it must be the parent
										if(!objNode.src) objNode = objNode.getElementsByTagName('IMG')[0];
										// replace link by hover
										objNode.src = objNode.src.replace('_hover','_link');
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.srcMouseHover = new SrcMouseHover;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.srcMouseHover;
			
			// replace in src sub-string
			function FadeMouseHover(){
				// properties
				this.name 			= 'fadeMouseHover';
				this.index			= 0;
				this.timeOut		= null;
				// methods
				this.start			=	function(node){
											this.setUpFader(node);
										}
				this.setUpFader		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// set the properties of this node
											objNode.id = (objNode.id) ? objNode.id : this.name + this.index++ ;
											objNode.className = objNode.className.replace(this.name, '');
											// clone the image
											clonedNode = objNode.cloneNode(true);
											// set the properties of the clone
											clonedNode.style.position = 'absolute';
											clonedNode.className = clonedNode.className.replace(this.name, 'hover');
											if(clonedNode.src) clonedNode.src = clonedNode.src.replace('_link.','_hover.');
											clonedNode.id = (clonedNode.id) ? clonedNode.id : this.name + this.index++ ;
											// place it before the original icon
											objNode.parentNode.insertBefore(clonedNode, objNode);
											// get the new node as an object
											newNode = classBehaviours.utilities.previousNode(objNode);
											// set the default fade
											classBehaviours.fader.setFade(newNode, 0);
											// set up the events
											newNode.onmouseover = this.addHover;
											newNode.onmouseout = this.remHover;
										}
				// events
				this.addHover 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var fmh = classBehaviours.handlers.fadeMouseHover;
										// if there's no fade active at the moment 
										if(classBehaviours.fader.getFade(objNode)%100==0){
											// fade out the image
											classBehaviours.fader.fadeIn(objNode.id, 20, 50, '');
										// else try again in a bit
										}else{
											fmh.timeOut = setTimeout('classBehaviours.handlers.fadeMouseHover.addHover(document.getElementById("' + objNode.id + '"))',50);
										}
									}
				this.remHover 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var fmh = classBehaviours.handlers.fadeMouseHover;
										// if there's no fade active at the moment 
										if(classBehaviours.fader.getFade(objNode)%100==0){
											// fade out the image
											classBehaviours.fader.fadeOut(objNode.id, 20, 50, '');
										// else try again in a bit
										}else{
											fmh.timeOut = setTimeout('classBehaviours.handlers.fadeMouseHover.remHover(document.getElementById("' + objNode.id + '"))',100);
										}
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.fadeMouseHover = new FadeMouseHover;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.fadeMouseHover;
			
			// hides nodes
			// hide the "hideThisNode" class behaviour by default 
			document.writeln("<style>.hideThisNode{overflow:hidden; visibility:hidden; height:1px;}</style>");
			function HideThisNode(){
				// properties
				this.name 		= 	'hideThisNode';
				// methods
				this.start		=	function(node){
										node.style.overflow = 'hidden';
										node.style.visibility = 'hidden';
										node.style.height = '1px';
										node.className = node.className.replace('showThisNode', 'hideThisNode');
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.hideThisNode = new HideThisNode;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.hideThisNode;
			
			// explicit opposite of a hidden node
			document.writeln("<style>.ShowThisNode{overflow:visible; visibility:visible; height:auto;}</style>");
			function ShowThisNode(){
				// properties
				this.name 		= 	'showThisNode';
				// methods
				this.start		=	function(node){
										node.style.overflow = 'visible';
										node.style.visibility = 'visible';
										node.style.height = 'auto';
										node.className = node.className.replace('hideThisNode', 'showThisNode');
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.showThisNode = new ShowThisNode;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.showThisNode;
			
			// show or hide a node
			document.writeln("<style>.toggleNextNode{cursor:pointer;}</style>");
			function ToggleNextNode(){
				// properties
				this.name 			= 	'toggleNextNode';
				this.step			=	10;
				this.acceleration	=	10;
				this.extra			=	0;
				this.delay			=	10;
				this.index			=	0;
				// methods
				this.start			=	function(node){
											// set the event handlers for the source node
											node.onclick = this.toggle;
											// give this node an id if it doesn't have one yet
											node.id = (node.id) ? node.id : this.name + this.index++ ;
											// is this node marked as "auto", order it to open on a timeout
											autoDelay = classBehaviours.utilities.getClassParameter(node, 'auto', null);
											if(autoDelay){
												this.index++
												node.id = (node.id) ? node.id : this.name + this.index ;
												setTimeout('classBehaviours.handlers.toggleNextNode.toggle(document.getElementById("'+node.id+'"))', autoDelay);
											}
										}
				this.findContainer	=	function(targetLabel, targetRecursion){
											var t2n = classBehaviours.handlers.toggleNextNode;
											// if there was a target recursion, recurse parent nodes
											if(targetRecursion) for(var a=0; a<parseInt(targetRecursion); a++) targetLabel = targetLabel.parentNode;
											// get the next sibling of the label, which should be the container
											targetObject = classBehaviours.utilities.nextNode(targetLabel);
											// give it an ID for reference
											targetObject.id = (targetObject.id) ? targetObject.id : t2n.name + 'Target' + t2n.index++;
											// pass it back
											return targetObject;
										}
				// events
				this.toggle 		= 	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var t2n = classBehaviours.handlers.toggleNextNode;
											// get all information on this node
											targetLabel = objNode;
											targetContainerId = classBehaviours.utilities.getClassParameter(targetLabel, 'id', null);
											targetRecursion = classBehaviours.utilities.getClassParameter(targetLabel, 'parent', null);
											targetClosable = (classBehaviours.utilities.getClassParameter(targetLabel, 'closable', 'yes') == 'yes');
											targetContainer = (targetContainerId) ? document.getElementById(targetContainerId) : t2n.findContainer(targetLabel, targetRecursion) ;
											// if the target container is not marked for hiding or showing, mark it now
											if(targetContainer.className.indexOf('hideThisNode')<0 && targetContainer.className.indexOf('showThisNode')<0) targetContainer.className += ' showThisNode' ;
											// call for the node to grow or shrink
											targetGrows = (targetContainer.className.indexOf('hideThisNode')>-1);
											if(!targetGrows && targetClosable || targetGrows) t2n.update(targetLabel.id, targetGrows);
											// cancel the click
											return false;
										}
				this.update			=	function(id, grows){
											var t2n = classBehaviours.handlers.toggleNextNode;
											// get all information on this node
											targetLabel = document.getElementById(id);
											targetContainerId = classBehaviours.utilities.getClassParameter(targetLabel, 'id', null);
											targetFamily = classBehaviours.utilities.getClassParameter(targetLabel, 'family', null);
											targetRecursion = classBehaviours.utilities.getClassParameter(targetLabel, 'parent', null);
											targetContainer = (targetContainerId) ? document.getElementById(targetContainerId) : t2n.findContainer(targetLabel, targetRecursion) ;
											// get all nodes of this class
											allNodes = classBehaviours.utilities.getElementsByClassName(t2n.name);
											// for every node in the node-list
											for(var a=0; a<allNodes.length; a++){
												// get its properties
												peerLabel = allNodes[a];
												peerContainerId = classBehaviours.utilities.getClassParameter(peerLabel, 'id', null);
												peerFamily = classBehaviours.utilities.getClassParameter(peerLabel, 'family', null);
												peerRecursion = classBehaviours.utilities.getClassParameter(peerLabel, 'parent', null);
												peerContainer = (peerContainerId) ? document.getElementById(peerContainerId) : t2n.findContainer(peerLabel, peerRecursion) ;
												// TARGET: if this node has the same id and is open
												if(peerLabel.id==targetLabel.id){
													// prepare the container
													peerContainer.style.overflow = 'hidden';
													peerContainer.style.visibility = 'visible';
													// open or close the container
													if(!grows)	classBehaviours.fader.size(peerContainer.id, null, 1, t2n.step, t2n.delay, t2n.acceleration, 'classBehaviours.handlers.hideThisNode.start(document.getElementById("'+peerContainer.id+'"))');
													else		classBehaviours.fader.size(peerContainer.id, 1, null, t2n.step, t2n.delay, t2n.acceleration, 'classBehaviours.handlers.showThisNode.start(document.getElementById("'+peerContainer.id+'"))');
													// activate the link
													peerLabel.className = (!grows) ? peerLabel.className.replace('active', 'link') : peerLabel.className.replace('link', 'active');
												}
												// PEERS: if this node belongs to the same family and is open but has a different id
												if(peerFamily==targetFamily && peerFamily!=null && peerContainer.className.indexOf('hideThisNode')<0 && peerContainer!=targetContainer){
													// prepare the container
													peerContainer.style.overflow = 'hidden';
													peerContainer.style.visibility = 'visible';
													// close the container
													classBehaviours.fader.size(peerContainer.id, null, 1, t2n.step ,t2n.delay, t2n.acceleration, 'classBehaviours.handlers.hideThisNode.start(document.getElementById("'+peerContainer.id+'"))');
													// de-activate the link
													peerLabel.className = peerLabel.className.replace('active', 'link');
												}
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.toggleNextNode = new ToggleNextNode;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.toggleNextNode;
							
			// tabbed content
			function TabbedContent(){
				// properties
				this.name 		= 	'tabbedContent';
				// methods
				this.start		=	function(node){
										// get all lists within this node
										allLists = node.getElementsByTagName('ul');
										// get all tabs from the first list
										allTabs = allLists[0].getElementsByTagName('a');
										// store the most likely opened tab
									//		openedTab = allTabs[0];
										openedTab = null;
										// for all tabs
										for(var a=0; a<allTabs.length; a++){
											// get the id this tab refers to
											tabId = allTabs[a].href.split('#')[1];
											// apply onclick events to the referred tab
											allTabs[a].onclick = this.open;
											// apply the starting state of the tab if needed
											if(allTabs[a].className.indexOf('closedTab')<0 && allTabs[a].className.indexOf('openedTab')<0) allTabs[a].className += ' closedTab';
											// apply the starting state of the referred content if needed
											document.getElementById(tabId).style.display = 'none';
											// if this tab is referred to in the page url, remember it as active
											if(document.location.href.indexOf(allTabs[a].href)>-1) openedTab = allTabs[a];
											// if this tab was manualy set
											if(allTabs[a].className.indexOf('openedTab')>-1) openedTab = allTabs[a];
										}
										// if there is a pager list, it'd better be the last one
										pager = (allLists[allLists.length-1].className.indexOf('contentPager')>-1) ? allLists[allLists.length-1] : null;
										if(pager!=null){
											// assign the events for the buttons
											pager.getElementsByTagName('button')[0].onclick = this.previous;
											pager.getElementsByTagName('button')[1].onclick = this.next;
										}
										// open the most likely first tab
										if(openedTab!=null) this.open(openedTab, true);
									}
				// events
				this.next		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var tbd = classBehaviours.handlers.tabbedContent;
										// get the pager information
										pagerInfo = objNode.parentNode.parentNode.getElementsByTagName('span')[0].firstChild.nodeValue;
										// what is the current pagenumber
										currentPage = parseInt(pagerInfo.split('/')[0]);
										// how many pages are there
										totalPages = parseInt(pagerInfo.split('/')[1]);
										// what is the next page
										nextPage = (currentPage<totalPages) ? currentPage + 1 : 1 ;
										// what is the tabs strip
										tabStrip = objNode.parentNode.parentNode.parentNode.getElementsByTagName('ul')[0];
										// get the relevant page from the tab strip
										targetTab = tabStrip.getElementsByTagName('a')[nextPage-1];
										// activate it's click
										tbd.open(targetTab);
									}
				this.previous	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var tbd = classBehaviours.handlers.tabbedContent;
										// get the pager information
										pagerInfo = objNode.parentNode.parentNode.getElementsByTagName('span')[0].firstChild.nodeValue;
										// what is the current pagenumber
										currentPage = parseInt(pagerInfo.split('/')[0]);
										// how many pages are there
										totalPages = parseInt(pagerInfo.split('/')[1]);
										// what is the next page
										previousPage = (currentPage>1) ? currentPage - 1 : totalPages ;
										// what is the tabs strip
										tabStrip = objNode.parentNode.parentNode.parentNode.getElementsByTagName('ul')[0];
										// get the relevant page from the tab strip
										targetTab = tabStrip.getElementsByTagName('a')[previousPage-1];
										// activate it's click
										tbd.open(targetTab);
									}
				this.open		=	function(that, noAnimation){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var tbd = classBehaviours.handlers.tabbedContent;								
				
										// INDEX THE TAB STATES
										// get all tabs
										var allTabs = objNode.parentNode.parentNode.getElementsByTagName('a');
										var prevTab = null;
										var pageNumber = 0;
										// find the current tab
										for(var a=0; a<allTabs.length; a++){
											// rememeber the previous tab
											if(allTabs[a].className.indexOf('openedTab')>-1) prevTab = allTabs[a];
											// count the new pagenumber
											if(allTabs[a]==objNode) pageNumber = a;
										}
		
										// if this is the current tab again
										if(prevTab!=objNode || noAnimation){
										
											// PREVIOUS TAB
											if(prevTab){
												// mark the previous tab as passive
												prevTab.className = prevTab.className.replace('openedTab', 'closedTab');
												// if the tab has an image
												tabImages = prevTab.getElementsByTagName('img');
												if(tabImages.length>0) tabImages[0].src = tabImages[0].src.replace('_active','_link');
												// id the previous tabbed content
												prevContentId = prevTab.href.split('#')[1];
											}else{
												prevContentId = null;
											}
											
											// NEXT TAB
											// mark the next tab as active
											objNode.className = objNode.className.replace('closedTab', 'openedTab');
											// if the tab has an image
											tabImages = objNode.getElementsByTagName('img');
											if(tabImages.length>0) tabImages[0].src = tabImages[0].src.replace('_link','_active').replace('_hover','_active');
											// id the next tabbed content
											nextContentId = objNode.href.split('#')[1];
											
											// FADE ANIMATION
											tabHeight = classBehaviours.utilities.getClassParameter(objNode.parentNode.parentNode.parentNode, 'off', '0');
											isAnimated = (noAnimation) ? 'no' : classBehaviours.utilities.getClassParameter(objNode, 'animated', 'yes') ;
											if(isAnimated=='yes'){
												// make the previous tab float
												if(prevTab) document.getElementById(prevContentId).style.position = 'absolute';
												if(prevTab) document.getElementById(prevContentId).style.display = 'block';
												if(prevTab) document.getElementById(prevContentId).style.top = tabHeight + 'px';
												// make the next tab not float
												document.getElementById(nextContentId).style.position = 'relative';
												document.getElementById(nextContentId).style.display = 'block';
												if(prevTab) document.getElementById(nextContentId).style.top = '0px';
												// order the animation
												if(prevTab) classBehaviours.fader.fade(prevContentId, 100, 0, 1, 10, 1, 'document.getElementById("' + prevContentId + '").style.display = "none";');
												classBehaviours.fader.fade(nextContentId, 0, 100, 1, 10, 1, 'document.getElementById("' + nextContentId + '").style.display = "block";');
											}else{
												if(prevTab) document.getElementById(prevContentId).style.display = 'none';
												document.getElementById(nextContentId).style.display = 'block';
											}
											
											// PAGE NUMBER
											// update page-numbering
											pager = objNode.parentNode.parentNode.parentNode.getElementsByTagName('ul')[objNode.parentNode.parentNode.parentNode.getElementsByTagName('ul').length-1];
											pager.getElementsByTagName('span')[0].firstChild.nodeValue = (pageNumber+1) + '/' + allTabs.length ;
										}
										// cancel the jump to the anchor
										objNode.blur();
										return false;
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.tabbedContent = new TabbedContent;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.tabbedContent;
					
			// replace image with transparent version, invoke activeX background loader
			// preload cosmetic tweak
			if(document.all && (navigator.userAgent.indexOf('MSIE 6.0')>-1 || navigator.userAgent.indexOf('MSIE 5')>-1) && navigator.userAgent.indexOf('Opera')<0)
					document.writeln("<style>img.pngAlpha {visibility:hidden;}</style>");
			function PngAlpha(){
				// properties
				this.name 		= 	'pngAlpha';
				// methods
				this.start		=	function(node){
										this.process(node);
										node.onload = this.process;
									}
				// events
				this.process 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// for the downlevel browser MSIE and the image has not been processed before
										if(
											typeof(objNode.style.filter)!='undefined'
											&& (navigator.userAgent.indexOf('MSIE 6.0')>-1 || navigator.userAgent.indexOf('MSIE 5')>-1)
											&& navigator.userAgent.indexOf('Opera')<0
											&& objNode.src.indexOf('.png')>-1
										){
											// change the image styles
											objNode.style.width		= objNode.width + 'px';
											objNode.style.height	= objNode.height + 'px';
											objNode.style.filter	= "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + objNode.src + "', sizingMethod='crop')";
											// replace the original with the alpha variant
											objNode.src = objNode.src.replace('.png', '.gif');
											objNode.style.visibility = 'visible';
										}
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.pngAlpha = new PngAlpha;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.pngAlpha;
			
			// Open an overlay as a popup window
			function OpenLayerPopUp(){
				// properties
				this.name 		= 	'openLayerPopUp';
				this.popUpClass	=	'layerPopUp';
				this.step		=	10;
				this.begin		=	0;
				this.end		=	50;
				this.index		=	0;
				// methods
				this.start		=	function(node){
										// find the target layer
										targetPopUp = null;
										// the node's open button
										node.onclick = this.load;
										// open the popup immediately if required
										node.id = (node.id) ? node.id : this.name + 'Link' + this.index++ ;
										if(classBehaviours.utilities.getClassParameter(node, 'auto', 'no')=='yes')
											setTimeout('classBehaviours.handlers.openLayerPopUp.load(document.getElementById("'+node.id+'"))', 250);
									}
				this.fadeIn	=	function(id, amount){
										var olp = classBehaviours.handlers.openLayerPopUp;
										node = document.getElementById(id);
										nodes = node.getElementsByTagName('div');
										nodeShadow = nodes[0];
										nodeContent = nodes[1];
										// if the amount is not 50
										if(amount<olp.end){
											// hide the popup content, but show the outside
											node.style.visibility = 'visible';
											nodeContent.style.visibility = 'hidden';
											// set the shadow's fade to the next step
											nodeShadow.style.display = 'block';
											if(typeof(nodeShadow.style.MozOpacity)!='undefined')	nodeShadow.style.MozOpacity = amount/100;
											if(typeof(nodeShadow.style.filter)!='undefined')		nodeShadow.style.filter = "alpha(opacity=" + amount + ")";
											if(typeof(nodeShadow.style.opacity)!='undefined')		nodeShadow.style.opacity = amount/100;
											// show the popup collection
											node.style.display = 'block';
											// repeat the fade
											setTimeout("classBehaviours.handlers.openLayerPopUp.fadeIn('" + id + "'," + (amount+olp.step) + ")",10);
										}else{
											// show the popup content
											nodeContent.style.visibility = 'visible';
										}
									}
				this.fadeOut	=	function(id, amount){
										var olp = classBehaviours.handlers.openLayerPopUp;
										node = document.getElementById(id);
										nodes = node.getElementsByTagName('div');
										nodeShadow = nodes[0];
										nodeContent = nodes[1];
										// if the amount is not 100
										if(amount>olp.begin){
											// hide the popup content
											nodeContent.style.visibility = 'hidden';
											// set the fade to the next step
											if(typeof(nodeShadow.style.MozOpacity)!='undefined')	nodeShadow.style.MozOpacity = amount/100;
											if(typeof(nodeShadow.style.filter)!='undefined')		nodeShadow.style.filter = "alpha(opacity=" + amount + ")";
											if(typeof(nodeShadow.style.opacity)!='undefined')		nodeShadow.style.opacity = amount/100;
											// repeat the fade
											setTimeout("classBehaviours.handlers.openLayerPopUp.fadeOut('" + id + "'," + (amount-olp.step) + ")",10);
										}else{
											// hide the popup content
											node.style.display = 'none';
											// hide the popup's shadow
											nodeShadow.style.display = 'none';
										}
									}
				this.loadUrl	=	function(strXmlUrl, strHrefUrl, strId, strTitle, intStep, intBegin, intEnd){
										var olp = classBehaviours.handlers.openLayerPopUp;
										// create a new link
										newA = document.createElement('a');
										newA.id = strId + 'Opener'
										newA.href = strXmlUrl + '?url=' + strHrefUrl;
										if(strTitle!=null) newA.title = strTitle;
										newA.className = 'openLayerPopUp id_' + strId; 
										if(intStep!=null) newA.className += 'step_' + intStep; 
										if(intBegin!=null) newA.className += 'begin_' + intBegin; 
										if(intEnd!=null) newA.className += 'end_' + intEnd; 
										newA.style.display = 'none';
										document.body.appendChild(newA);
										// trigger it like a click
										olp.load(document.getElementById(strId + 'Opener'), strId);
									}
				// events
				this.load		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var olp = classBehaviours.handlers.openLayerPopUp;
										// get the popup id
										popUpHref = (objNode.href) ? objNode.href : '' ;
										popUpId = (popUpHref.indexOf('#')>-1) ? popUpHref.split('#')[1] : classBehaviours.utilities.getClassParameter(objNode, 'id', 'popUpWithScrollBar') ;
										// if the popup is allready loaded
										popUpObj = document.getElementById(popUpId);
										if(popUpObj){
											olp.show(objNode, popUpId);
										}else{
											classBehaviours.ajax.addRequest(popUpHref, olp.insert, olp.wait, null, objNode);
										}
										// cancel the click
										return false;
									}
				this.wait		=	function(progress, referNode){
										var olp = classBehaviours.handlers.openLayerPopUp;
										// it'd be fun to see a background image behind the link text be the progress-indicator
										referNode.parentNode.style.backgroundPosition = (100-progress*100) +'% 0px';
									}
				this.insert		=	function(importedObj, referNode, importedText){
										var olp = classBehaviours.handlers.openLayerPopUp;
										//  get the popup's id
										olp.instance += 1;
										popUpId = classBehaviours.utilities.getClassParameter(referNode, 'id', olp.name+olp.instance);
										popUpWidth = classBehaviours.utilities.getClassParameter(referNode, 'width', '470');
										popUpHeight = classBehaviours.utilities.getClassParameter(referNode, 'height', '300');
										// make a new node at the end of the page
										newNode = document.createElement('div');
										document.body.appendChild(newNode);
										// get the node and fill it with delicous html
										allDivs = document.getElementsByTagName('div');
										lastDiv = allDivs[allDivs.length-1];
										importedText = (importedText.indexOf('<body>')>-1) ? importedText.split('<body>')[1].split('</body>')[0] : importedText.replace('<?xml version="1.0"?>', '') ;
										importedText = importedText.replace(/{id}/gi, popUpId);
										importedText = importedText.replace(/{title}/gi, referNode.title);
										importedText = importedText.replace(/{url}/gi, referNode.href.split('?url=')[1]);
										importedText = importedText.replace(/{width}/gi, popUpWidth);
										importedText = importedText.replace(/{height}/gi, popUpHeight);
										lastDiv.innerHTML = importedText;
										// apply any classbehaviours
										classBehaviours.parser.parseNode(lastDiv);
										// show the pop-up
										olp.show(referNode, popUpId);
									}
				this.center		=	function(popUpObj){
										if(popUpObj){
											// the dimensions can not be measured with "display:none;"
											popUpObj.style.display = 'block';
											// get the content segment
											popupContent = popUpObj.getElementsByTagName('DIV')[2];
											// how high is the content
											popupHeight = popupContent.offsetHeight;
											// how high is the screen
											screenHeight = (window.innerHeight) ? window.innerHeight : document.documentElement.clientHeight ;
											// center the popup
											popupContent.style.marginTop = (screenHeight>popupHeight) ? Math.round((screenHeight-popupHeight)/2) + 'px' : '30px' ;	
										}
									}
				this.show		=	function(openerObj, popUpId){
										var olp = classBehaviours.handlers.openLayerPopUp;
										var submit = false;
										// adjust the fade parameters if it needs to open instantly
										if(openerObj){
											olp.step = parseInt(classBehaviours.utilities.getClassParameter(openerObj, 'step', 10));
											olp.begin = parseInt(classBehaviours.utilities.getClassParameter(openerObj, 'begin', 0));
											olp.end = parseInt(classBehaviours.utilities.getClassParameter(openerObj, 'end', 50));
										}
										// get the popup
										popUpObj = document.getElementById(popUpId);
										// hide the popup for now
										popUpObj.style.visibility = 'hidden';
										// center the popup
										this.center(popUpObj);
										// if the link had a title and if the popup has a title. put the link title in the popup
										popUpTitles = popUpObj.getElementsByTagName('h1');
										if(openerObj) if(openerObj.title && popUpTitles.length>0) popUpTitles[0].innerHTML = openerObj.title;
										// load a given url in the iframe it it's not there allready
										popUpIframes = popUpObj.getElementsByTagName('iframe');
										if(popUpIframes.length>0 && openerObj.href.indexOf('?url=')>-1){
											if(popUpIframes[0].src!=openerObj.href.split('?url=')[1]) popUpIframes[0].src = openerObj.href.split('?url=')[1];
										}
										// find the close gadget
										popUpClosers = popUpObj.getElementsByTagName('a');
										if(popUpClosers.length>0){
											popUpClosers[0].onclick = olp.hide;
										}
										// remove the scroll bars
										if(navigator.appVersion.indexOf('MSIE 6')>-1 || navigator.appVersion.indexOf('MSIE 5')>-1){
											// manage the scroll positions
											if(popUpObj.className.indexOf('fullHeightPopUp')<0){
												// reset the scroll position
												document.documentElement.scrollLeft = 0;
												document.documentElement.scrollTop = 0;
												// hide the scrollbars if needed
												document.body.parentNode.style.overflow = "hidden";
												// reposition the popup according to the scroll position
												popUpObj.getElementsByTagName('DIV')[2].style.marginTop = Math.round(document.documentElement.scrollTop + (screenHeight-popupHeight)/2) + 'px' ;
											}
											// size the shadow under the popup
											popUpObj.getElementsByTagName('DIV')[0].style.height = document.body.offsetHeight + 'px';
											// hide the selects
											allSelects = document.getElementsByTagName('select');
											for(var a=0; a<allSelects.length; a++) allSelects[a].style.visibility = 'hidden';
										}
										// if there is a popup open already
										if(olp.opened!=null){
											// instantly hide the old one
											document.getElementById(olp.opened).style.display = 'none';
											// instantly show the new one
											document.getElementById(popUpId).style.display = 'block';
											document.getElementById(popUpId).style.visibility = 'visible';
										}else{
											// fade the popup in, but give the contents a little head start
											setTimeout('classBehaviours.handlers.openLayerPopUp.fadeIn("'+popUpId+'", '+olp.begin+')', 1000);
										}
										// remember the open popup
										olp.opened = popUpId;
										// cancel the click
										return submit;
									}
				this.hide		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var olp = classBehaviours.handlers.openLayerPopUp;
										// the popup object
										popUp = objNode;
										while(popUp.className.indexOf(olp.popUpClass)<0){
											popUp = popUp.parentNode;
										}
										// fade the popup out
										olp.fadeOut(popUp.id, olp.end);
										// restore the scroll bars
										if(navigator.appVersion.indexOf('MSIE 6')>-1 || navigator.appVersion.indexOf('MSIE 5')>-1){
											// show the scrollbars
											if(popUp.className.indexOf('fullHeightPopUp')<0) document.body.parentNode.style.overflow = "";
											// show the selects
											allSelects = document.getElementsByTagName('select');
											for(var a=0; a<allSelects.length; a++) allSelects[a].style.visibility = 'visible';
										}
										// clear the iframe contents
										popUpIframes = popUp.getElementsByTagName('iframe');
										if(popUpIframes.length>0){
											popUpIframes[0].src = "";
										}
										// note that nothing is opened
										olp.opened = null;
										// cancel the click
										return false;
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.openLayerPopUp = new OpenLayerPopUp;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.openLayerPopUp;
			
			// replace the contents of the popup
			function ReplaceLayerPopUp(){
				// properties
				this.name 		= 	'replaceLayerPopUp';
				// methods
				this.start		=	function(node){
										// set the event handler for the link
										node.onclick = this.clicked;
									}
				this.wait		=	function(progress, referer){
										// No indicator was designed
									//	debug(progress);
									}
				this.insert		=	function(xmlObj, referer, xmlText){
										// get the root of this popup
										rootNode = classBehaviours.utilities.rootNode(referer, null, null, 'layerPopUp');
										// clean the incoming content
										popUpText = xmlText.split('<!-- cut here -->')[1];
										// insert the new content
										rootNode.innerHTML = popUpText;
										// re-apply the classbehaviour
										classBehaviours.parser.parseNode(rootNode);
										// recenter
										classBehaviours.handlers.openLayerPopUp.center(rootNode);
										// find the close gadget
										popUpClosers = rootNode.getElementsByTagName('a');
										if(popUpClosers.length>0){
											popUpClosers[0].onclick = classBehaviours.handlers.openLayerPopUp.hide;
										}
									}
				// events
				this.clicked 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var rlp = classBehaviours.handlers.replaceLayerPopUp;
										// get the new content from the url
										importUrl = objNode.href;
										classBehaviours.ajax.addRequest(importUrl, rlp.insert, rlp.wait, null, objNode);
										// cancel browser mouse click
										return false;
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.replaceLayerPopUp = new ReplaceLayerPopUp;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.replaceLayerPopUp;
			
			// move the node to the bottom of the document
			function LayerPopUp(){
				// properties
				this.name 		= 	'layerPopUp';
				// methods
				this.start		=	function(node){
										// if this node wasn't moved
										if(node.className.indexOf('doNotMove')<0) this.process(node);
									}
				this.process 	= 	function(objNode){
										// take this node
									 	removedChild = objNode.parentNode.removeChild(objNode);
									 	removedChild.className += ' doNotMove';
										// and put it at the end of the document
										document.body.appendChild(removedChild);
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.layerPopUp = new LayerPopUp;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.layerPopUp;
			
			// use a button to hide the popup layer
			function CloseLayerPopUp(){
				// properties
				this.name 			= 	'closeLayerPopUp';
				// methods
				this.start			=	function(node){
											node.onclick = this.closePopUp;
										}
				this.closePopUp 	= 	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// deal with framesets
											if(parent!=self){
												allPopUps = parent.classBehaviours.utilities.getElementsByClassName('layerPopUp');
												for(var a=0; a<allPopUps.length; a++) parent.classBehaviours.handlers.openLayerPopUp.hide(allPopUps[a]);
											}else{
												// get the root of this popup
												rootNode = classBehaviours.utilities.rootNode(objNode, null, null, 'layerPopUp');
												// close the layer
												classBehaviours.handlers.openLayerPopUp.hide(rootNode);
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.closeLayerPopUp = new CloseLayerPopUp;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.closeLayerPopUp;
							
			// Alternates the classes of a table's rows and columns
			function ZebraTable(){
				// properties
				this.name 		= 	'zebraTable';
				// methods
				this.start		=	function(node){
										this.process(node);
									}
				this.process 	= 	function(objNode){
										var objRows, objCols, intCellNumber;
										// get all table rows
										objRows = objNode.getElementsByTagName('TR');
										// for all table rows
										for(var intRow=0; intRow<objRows.length; intRow++){
											// undo any previous classing
											objRows[intRow].className = objRows[intRow].className.replace('odd','');
											objRows[intRow].className = objRows[intRow].className.replace('even','');
											// add oddrow or evenrow class to the row
											objRows[intRow].className += (intRow%2==0) ? ' odd' : ' even' ;
											// and row and col counters if they're not allready present
											if(objRows[intRow].className.indexOf('row_')<0) objRows[intRow].className += ' row_' + intRow;
											// get all nodes in this row
											objCols = objRows[intRow].childNodes;
											// for every node in the row
											intCellNumber = 0;
											for(var intCol=0; intCol<objCols.length; intCol++){
												// is this a cell or a header
												if(objCols[intCol].nodeName.indexOf('text')<0){
													// undo any previous classing
													objCols[intCol].className = objCols[intCol].className.replace('odd','');
													objCols[intCol].className = objCols[intCol].className.replace('even','');
													// add oddcol or evencol class
													objCols[intCol].className += (intCellNumber%2==0) ? ' odd' : ' even' ;
													// and row and col counters if they're not allready present
													if( objCols[intCol].className.indexOf('col_')<0) objCols[intCol].className += ' col_' + intCellNumber;
													// keep cell numbers
													intCellNumber += 1;
												}
											}
										}
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.zebraTable = new ZebraTable;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.zebraTable;
			
			// Makes the headers of a table click/sortable
			function SortByColumn(){
				// properties
				this.name 		= 	'sortByColumn';
				this.column	=	0;
				// methods
				this.start		=	function(node){
										node.onclick = this.sort;
										// apply the default sort direction style
										if(node.className.indexOf('sorted')<0) node.className += ' unSorted';
									}
				this.forward 	= 	function(rowA,rowB){
										var st = classBehaviours.handlers.sortByColumn;
										var regTags = new RegExp('<(.|\n)+?>','gi');
										// get the string values from the node
										strA = (rowA.childNodes[st.column].childNodes.length == 0) ? ' ' : rowA.childNodes[st.column].innerHTML.replace('---','0,00').replace(regTags,'');
										strB = (rowB.childNodes[st.column].childNodes.length == 0) ? ' ' : rowB.childNodes[st.column].innerHTML.replace('---','0,00').replace(regTags,'');
										// get the numeric values from the node
										intA = parseInt(strA.replace(',',''));
										intB = parseInt(strB.replace(',',''));
										// compare the values for the sort funtion
										if(strA==strB || (navigator.appVersion.indexOf('MSIE 5.0')>-1)){
											// equal
											return 0;
										}else if(isNaN(intA) || isNaN(intB)){
											// compare the textual values
											return (strA<strB) ? 1 : -1 ;
										}else{
											// compare the numeric values
											return intB - intA;
										}
									}
				this.reverse 	= 	function(rowA,rowB){
										var st = classBehaviours.handlers.sortByColumn;
										var regTags = new RegExp('<(.|\n)+?>','gi');
										// get the string values from the node
										strA = (rowA.childNodes[st.column].childNodes.length == 0) ? ' ' : rowA.childNodes[st.column].innerHTML.replace('---','0,00').replace(regTags,'');
										strB = (rowB.childNodes[st.column].childNodes.length == 0) ? ' ' : rowB.childNodes[st.column].innerHTML.replace('---','0,00').replace(regTags,'');
										// get the numeric values from the node
										intA = parseInt(strA.replace(',',''));
										intB = parseInt(strB.replace(',',''));
										// compare the values for the sort funtion
										if(strA==strB || (navigator.appVersion.indexOf('MSIE 5.0')>-1)){
											// equal
											return 0;
										}else if(isNaN(intA) || isNaN(intB)){
											// compare the textual values
											return (strA>strB) ? 1 : -1 ;
										}else{
											// compare the numeric values
											return intA - intB;
										}
									}
				// events
				this.sort 		= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var st = classBehaviours.handlers.sortByColumn;
										// defaults
										sortDirection	= 'sortedForward';
										// find column number
										var objSiblings	= objNode.parentNode.childNodes;
										for(var intA=0; intA<objSiblings.length; intA++){
											// is this a cell of a text-node
											if(objSiblings[intA].nodeName=="TD" || objSiblings[intA].nodeName=="TH"){
												// test if this is the clicked node
												if(objSiblings[intA] == objNode){
													// remember the clicked column
													st.column = intA;
													// toggle the sort direction
													sortDirection = (objSiblings[intA].className.indexOf('sortedForward')>-1) ? 'sortedReverse' : 'sortedForward' ;
													// adjust the sorting direction classname
													objSiblings[intA].className = objSiblings[intA].className.replace('sortedReverse', sortDirection);
													objSiblings[intA].className = objSiblings[intA].className.replace('sortedForward', sortDirection);
													objSiblings[intA].className = objSiblings[intA].className.replace('unSorted', sortDirection);
												}else{
													// unmark any previously sorted column
													objSiblings[intA].className = objSiblings[intA].className.replace('sortedReverse', 'unSorted');
													objSiblings[intA].className = objSiblings[intA].className.replace('sortedForward', 'unSorted');
												}
											}
										}
										// make a nodelist
										var fullTable		= objNode.parentNode.parentNode.parentNode;
										var sortParent		= fullTable.getElementsByTagName('TBODY')[0];
										var nodeList		= sortParent.childNodes;
										var nodeArray		= new Array();
										// for all table rows
										for(var intA=0; intA<nodeList.length; intA++){
											if(nodeList[intA].nodeName.indexOf('TR')>-1){
												// store it in an array
												nodeArray[nodeArray.length] = nodeList[intA];
											}
										}
										// sort the collection using a helper function
										nodeArray = (sortDirection=='sortedForward') ? nodeArray.sort(st.forward) : nodeArray.sort(st.reverse);
										// clear the unsorted nodelist
										for(var intA=0; intA<nodeList.length; intA++){
											if(nodeList[intA].nodeName.indexOf('TR')>-1){
												sortParent.removeChild(nodeList[intA]);
											}
										}
										// append the sorted nodelist
										for(var intA=0; intA<nodeArray.length; intA++){
											sortParent.appendChild(nodeArray[intA]);
										}
										// reapply the zebra effect
										classBehaviours.handlers.zebraTable.process(fullTable);
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.sortByColumn = new SortByColumn;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.sortByColumn;
			
			// Open print dialog
			function OpenAsPrintable(){
				// properties
				this.name 		= 	'openAsPrintable';
				// methods
				this.start		=	function(node){
										node.onclick = this.process;
									}
				this.process 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// If there is a demo popup
										if(document.getElementById('tgtPopTitle')){
											// copy the title to the print popup title
											document.getElementById('tgtPopTitle').innerHTML = document.getElementById('content').getElementsByTagName('h1')[0].innerHTML;
											// copy the content tot the print popup content
											document.getElementById('tgtPopText').innerHTML = (document.getElementById('content').innerHTML.indexOf('</h1>')>-1) ? document.getElementById('content').innerHTML.split('</h1>')[1] : document.getElementById('content').innerHTML.split('</H1>')[1];
											// show the print popup
											classBehaviours.handlers.openLayerPopUp.show(document.getElementById('popup0'));
											// open the print dialog
											setTimeout("window.print();",2048);
										}else{
											window.print();
										}
										// cancel the click
										return false;
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.openAsPrintable = new OpenAsPrintable;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.openAsPrintable;
			
			// Close the window (it's cold)
			function CloseThisWindow(){
				// properties
				this.name 		= 	'closeThisWindow';
				// methods
				this.start		=	function(node){
										node.onclick = this.process;
									}
				this.process 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										window.close();
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.closeThisWindow = new CloseThisWindow;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.closeThisWindow;
			
		     // Jump back to the previous page
		           // define this class behaviour
		           function GoToPrevious(){
		                 // properties
		                 this.name         =     'goToPrevious';
		                 // methods
		                 this.start        =     function(node){
		                                                     node.onclick = this.process;
		                                               }
		                 this.process      =     function(that){
		                                                     var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
		                                                     // open the print dialog
		                                                     window.history.go(-1);
		                                               }
		           }
		           // add this function to the classbehaviour object
		           classBehaviours.handlers.goToPrevious = new GoToPrevious;
		           classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.goToPrevious;
			
			// Fixes the position of an element
			function FixedPosition(){
				// properties
				this.name 		= 	'fixedPosition';
				this.nodes 		= 	new Array();
				// methods
				this.start		=	function(node){
										this.nodes[this.nodes.length] = node;
										if(document.all){
											window.onscroll = this.process;
										}else{
											node.style.position = 'fixed';
										}
									}
				// events
				this.process 	= 	function(){
										var fp = classBehaviours.handlers.fixedPosition;
										// this is only needed in internet explorer
										for(var a=0; a<fp.nodes.length; a++){
											fp.nodes[a].style.marginTop = (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + 'px';
											fp.nodes[a].style.marginLeft = (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + 'px';
										}
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.fixedPosition = new FixedPosition;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.fixedPosition;
			
			// Open links in a popup
			function OpenAsPopUp(){
				// properties
				this.name 		= 	'openAsPopUp';
				this.window		=	null;
				// methods
				this.start		=	function(node){
										node.onclick = this.process;
									}
				// events
				this.process 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var oap = classBehaviours.handlers.openAsPopUp;
										// get the parameters from the classname
										var strWidth 		= 'width=' + classBehaviours.utilities.getClassParameter(objNode, 'width', '630');
										var strHeight 		= ',height=' + classBehaviours.utilities.getClassParameter(objNode, 'height', '385');
										var strLeft			= ',left=' + classBehaviours.utilities.getClassParameter(objNode, 'left', '');
										var strTop			= ',top=' + classBehaviours.utilities.getClassParameter(objNode, 'top', '');
										var strToolbars 	= ',toolbar=' + classBehaviours.utilities.getClassParameter(objNode, 'toolbar', 'no');
										var strScrolling 	= ',scrollbars=' + classBehaviours.utilities.getClassParameter(objNode, 'scrollbars', 'no');
										var strStatus 		= ',status=' + classBehaviours.utilities.getClassParameter(objNode, 'status', 'no');
										var strResize 		= ',resizable=' + classBehaviours.utilities.getClassParameter(objNode, 'resizable', 'yes');
										var strLocation 	= ',location=' + classBehaviours.utilities.getClassParameter(objNode, 'location', 'no');
										var strMenu 		= ',menu=' + classBehaviours.utilities.getClassParameter(objNode, 'menu', 'no');
										var strName 		= classBehaviours.utilities.getClassParameter(objNode, 'name', 'popup');
										// open requested window
										oap.window = window.open(objNode.getAttribute('href'), strName, strWidth+strHeight+strScrolling+strToolbars+strStatus+strResize+strLocation+strMenu+strLeft+strTop);
										oap.window.focus();
										// cancel click
										return false;
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.openAsPopUp = new OpenAsPopUp;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.openAsPopUp;
			
			// Open links in the opener of this window
			function OpenInOpener(){
				// properties
				this.name 		= 	'openInOpener';
				// methods
				this.start		=	function(node){
										node.onclick = this.process;
									}
				// events
				this.process 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// open the href in the opener of this window
										window.opener.location.href = objNode.href;
										// optionaly close the window
										if(classBehaviours.utilities.getClassParameter(objNode, 'closeParent', 'false')=='true') window.close();
										// cancel the link
										return false;
										
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.openInOpener = new OpenInOpener;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.openInOpener;
			
			// Open links in a new window
			function OpenAsWindow(){
				// properties
				this.name 		= 	'openAsWindow';
				// methods
				this.start		=	function(node){
										node.target = "_blank"
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.openAsWindow = new OpenAsWindow;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.openAsWindow;
			
			// Chooses a random increment of an image source
			function SetRandomSrc(){
				// properties
				this.name 		= 	'setRandomSrc';
				// methods
				this.start		=	function(node){
										this.process(node);
									}
				this.process 	= 	function(objNode){
										// get min parameter
										var intMin = parseInt(classBehaviours.utilities.getClassParameter(objNode, 'min', '0'));
										// get max parameter
										var intMax = parseInt(classBehaviours.utilities.getClassParameter(objNode, 'max', '1'));
										// generate random number
										var intRandom = Math.round(Math.random()*(intMax-intMin))+intMin;
										// replace default increment by random number
										if(objNode.src!=null) objNode.src = objNode.src.replace('_0','_'+intRandom);
										objNode.className = objNode.className.replace('_0','_'+intRandom);
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.setRandomSrc = new SetRandomSrc;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.setRandomSrc;
			
			// Chooses a random increment of an image source
			function SetRandomClassName(){
				// properties
				this.name 		= 	'setRandomClassName';
				// methods
				this.start		=	function(node){
										this.process(node);
									}
				this.process 	= 	function(objNode){
										// get min parameter
										var intMin = parseInt(classBehaviours.utilities.getClassParameter(objNode, 'min', '0'));
										// get max parameter
										var intMax = parseInt(classBehaviours.utilities.getClassParameter(objNode, 'max', '1'));
										// generate random number
										var intRandom = Math.round(Math.random()*(intMax-intMin))+intMin;
										// replace default increment by random number
										if(objNode.className!=null) objNode.className = objNode.className.replace('_0','_'+intRandom);
										objNode.className = objNode.className.replace('_0','_'+intRandom);
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.setRandomClassName = new SetRandomClassName;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.setRandomClassName;
			
			// Class a link matching the document's url
			function MatchActiveUrl(){
				// properties
				this.name 					= 	'matchActiveUrl';
				this.index					=	0;
				// methods
				this.start					=	function(node){
													// give this node an id, if it doesn't have one
													node.id = (node.id) ? node.id : this.name + this.index++ ;
													// if this node is not a link, then this must be a tree of links
													allLinks = (node.nodeName!='A') ? node.getElementsByTagName('a') : new Array(node) ;
													// how sensitive is the scoring
													scoreSensitivity = parseInt(classBehaviours.utilities.getClassParameter(node, 'sensitivity', 100)) / 100;
													// scan all links
													activeLink = this.findActiveUrl(allLinks, scoreSensitivity);
													// activate the link and all parents of this link back to the root
													if(activeLink!=null) this.setActiveLinks(activeLink, node.id);
												}
				this.convertAbsToRelUrls 	= 	function(strUrl){
													// is the url a relative path
													if(strUrl.indexOf('/')<0 || strUrl.substr(0,1)=='.' || strUrl.substr(0,1)=='/'){
														// the current absolute path
														strAbs = document.location.href;
														// remove the filename from the end
														strAbs = strAbs.substring(0, strAbs.lastIndexOf('/'));
														// while there are parent markers in the url
														while(strUrl.indexOf('../')==0){
															// remove one level from the absolute path
															strUrl = strUrl.replace('../','');
															// remove one parent marker from the relative path
															strAbs = strAbs.substring(0, strAbs.lastIndexOf('/'));
														}
														// remove all current dir markers from the relative url
														strUrl = strUrl.replace(/\.\//gi, '');
														// add the url to the absolute path
														strUrl = strAbs + '/' + strUrl;
													}
													return strUrl;
												}
				this.compareUrls 			= 	function(strUrlA, strUrlB){
													var intCurScore = 0;
													var intPotScore = 0;
													var intMaxScore = 0;
													var intA,intB;
													// replace most common illegal characters
													strUrlA = strUrlA.replace(/ /gi,"%20");
													strUrlB = strUrlB.replace(/ /gi,"%20");
													// remove anchors
													strUrlA = strUrlA.split('#')[0];
													strUrlB = strUrlB.split('#')[0];
													// make sure both paths are absolute
													strUrlA = this.convertAbsToRelUrls(strUrlA);
													strUrlB = this.convertAbsToRelUrls(strUrlB);
													// split the urls into manageable strings
													var arrUrlA = strUrlA.split(/[?&#\/]/i);
													var arrUrlB = strUrlB.split(/[?&#\/]/i);
													// for every string of UrlA
													for(intA=0; intA<arrUrlA.length; intA++){
														// is the string in the substrings of UrlB
														intB = 0; while(intB<arrUrlB.length && arrUrlA[intA]!=arrUrlB[intB]) intB += 1;
														// if a match was found, add length of string A to current score
														if(intB<arrUrlB.length) intCurScore += arrUrlA[intA].length;
														// add length of string A to potential score
														intPotScore += arrUrlA[intA].length;
													}
													// calcultate maximum score possible
													intMaxScore = strUrlB.length - arrUrlB.length + 1;
													// return the compare-score
													return intCurScore/intPotScore;
												}
				this.findActiveUrl 			= 	function(allLinks, scoreSensitivity){
													// get the url and clean it up
													var strUrl = this.convertAbsToRelUrls(document.location.href);
													// apply a score to every link
													allScores = new Array();
													for(var a=0; a<allLinks.length; a++){
														// get the href and clean it up
														var strHref = this.convertAbsToRelUrls(allLinks[a].getAttribute('href'));
														// was the data bad
														if(strHref!=null){
															// compare score
															var compareScore = this.compareUrls(strUrl, strHref) * this.compareUrls(strHref, strUrl);
															// add it into a list
															allScores[allScores.length] = new Array(compareScore, allLinks[a]);
														}
													}
													// sort the scores
													allScores = allScores.sort();
													// return the highest scoring link, if it is high enough
													return (allScores[allScores.length-1][0]>scoreSensitivity) ? allScores[allScores.length-1][1] : null ;
												}
				this.setActiveLinks			=	function(activeLink, nodeId){
													var cmh = classBehaviours.handlers.classMouseHover;
													var smh = classBehaviours.handlers.srcMouseHover;
													// while the node with the root ID has not been found
													targetNode = activeLink;
													while(targetNode.id!=nodeId){
														// activate this link
														cmh.addActive(targetNode);
														// or the image in it
														targetNodeImages = targetNode.getElementsByTagName('img');
														if(targetNodeImages.length>0) smh.addActive(targetNodeImages[0]);
														// get the parent link
														targetNode = targetNode.parentNode;
													};
													// activate this link
													cmh.addActive(activeLink);
													// or the image in it
													activeLinkImages = activeLink.getElementsByTagName('img');
													if(activeLinkImages.length>0) smh.addActive(activeLinkImages[0]);
												}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.matchActiveUrl = new MatchActiveUrl;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.matchActiveUrl;
			
			// Validate the value of a for element to a predefined regular expression
			function ValidateInput(){
				// properties
				this.name 			= 	'validateInput';
				this.summaryId		=	null;
				this.lastFocus		=	null;
				this.customChecks	=	new CustomChecks;
				// methods
				this.start			=	function(node){
											// was a summary requested?
											this.summaryId = classBehaviours.utilities.getClassParameter(node, 'summaryId', this.summaryId);
											// apply the event to all form-element childnodes
											var nodes = (this.isFormElement(node) || this.isFormButton(node)) ? new Array(node) : node.getElementsByTagName('*');
											for(var a=0; a<nodes.length; a++){
												if(this.isFormElement(nodes[a])){
													// give it the event handler
													nodes[a].onfocus = this.clear;
													nodes[a].onmousedown = this.clear;
													nodes[a].onblur = this.input;
													nodes[a].onchange = this.input;
													// and the parent's classname
													nodes[a].className = node.className;
												}
												if(this.isFormButton(nodes[a])){
													nodes[a].onclick = this.all;
												}
											}
											// if there's a greyed explanation
											hasExplanation = classBehaviours.utilities.getClassParameter(node, 'explanation', 'no');
											if(hasExplanation=='yes'){
												// remove it if a value is restored by a form manager
												setTimeout("classBehaviours.handlers.validateInput.restore('"+node.id+"','"+node.value+"')", 1000);
											}
										}
				this.warning 		=	function(objNode, status){
											var vi = classBehaviours.handlers.validateInput;
											// Show the input warning if this is a suitable form element
											if(objNode.className.indexOf('noWarning')<0)
												objNode.className = (status) ? objNode.className.replace(' validationWarning', '') : objNode.className + ' validationWarning' ;
											// for all inputs with the same name
											allWithSameName = document.getElementsByName(objNode.name);
											for(var b=0; b<allWithSameName.length; b++){
												objNode = allWithSameName[b];
											// Show the foldout warning
												// is the warning node named?
												idWarningNode		= classBehaviours.utilities.getClassParameter(objNode, 'warningId', null);
												// check if the next node is for summaries
												nextNode 			= classBehaviours.utilities.nextNode(objNode);
												// if there's an id given for thewarning message use it. Otherwise use the next node
												objWarningNode		= (idWarningNode) ? document.getElementById(idWarningNode) : nextNode ;
												// show or hide the warning, if the warning node was found
												if(objWarningNode)
													if(objWarningNode.className.indexOf('validationWarning')>-1)
														objWarningNode.style.display = (status) ? 'none' : 'block' ;
											// Highlight the label
												// get all labels
												allLabels = document.getElementsByTagName('label');
												// for all labels
												for(var a=0; a<allLabels.length; a++){
													// if the label matches this input
													if(allLabels[a].getAttributeNode('for').nodeValue == objNode.id){
														// add or remove the warning colour
														if(allLabels[a].parentNode.className.indexOf('noWarning')<0 && allLabels[a].className.indexOf('noWarning')<0) 
															allLabels[a].className = (status) ? allLabels[a].className.replace('validationWarning', '') : allLabels[a].className + ' validationWarning' ;
													}
												}
											}
										}
				this.restore 		=	function(id, value){
											var objNode = document.getElementById(id);
											// if this input has a value which doesn't match the current value, a form manager has restored a value
											if(objNode.value!=value){
												objNode.className = objNode.className.replace('explanation_yes','explanation_no');
											}
										}
				this.isFormButton	=	function(objNode){
											return (
														objNode.getAttribute('type')=='submit' ||
														objNode.getAttribute('type')=='image' ||
														objNode.nodeName=='BUTTON'
											);
										}
				this.isFormElement	=	function(objNode){
											return (
														objNode.getAttribute('type')=='text' || 
														objNode.getAttribute('type')=='password' || 
														objNode.getAttribute('type')=='file' || 
														objNode.getAttribute('type')=='radio' || 
														objNode.getAttribute('type')=='checkbox' || 
														objNode.nodeName=='SELECT' || 
														objNode.nodeName=='TEXTAREA'
											);
										}
				this.summary 		= 	function(objNode){
											var vi = classBehaviours.handlers.validateInput;
											// find the root of the form
											rootNode = classBehaviours.utilities.rootNode(objNode, null, null, 'validateAllInput');
											// is a summary required
											vi.summaryId = classBehaviours.utilities.getClassParameter(rootNode, 'summaryId', null);
											if(vi.summaryId){
												summaryObj = document.getElementById(vi.summaryId);
												summaryTxt = '';
												// for all nodes
												var objSubNodes = rootNode.getElementsByTagName("*");
												for(var a=0; a<objSubNodes.length; a++){
													// if this node a visible warning
													if(objSubNodes[a].className.indexOf('validationWarning')>-1 && objSubNodes[a].style.display=='block'){
														// copy it's contents to the summary text
														summaryTxt += '<li>' + objSubNodes[a].innerHTML + '</li>';
													}
												}
												// add the summary text to the summary
												summaryObj.style.display = (summaryTxt.length>0) ? 'block' : 'none' ;
												summaryObj.getElementsByTagName('div')[0].innerHTML = (summaryTxt.length>0) ? '<ul>' + summaryTxt + '</ul>' : '' ;
											}
										}
				this.ajaxWait		=	function(submitProgress, submitReferer, submitError){
											// inform the user on the progress in the reply area
											submitReferer.innerHTML = (submitProgress<0) ? 'error: ' + submitError : 'sending: ' + Math.round(submitProgress*100) + '%' ;
										}
				this.ajaxReply		=	function(replyObj, replyReferer, replyText){
											// strip and write the reply to the form reply area
											replyReferer.innerHTML = (replyText.indexOf('</body>')>-1) ? replyText.split('<body>')[1].split('</body>')[0] : replyText.split('<root>')[1].split('</root>')[0] ;
											// activate any classbehaviours
											classBehaviours.parser.parseNode(replyReferer);
										}
				// events
				this.clear	=	function(objNode){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var vi = classBehaviours.handlers.validateInput;
									// remember the focus point
									vi.lastFocus = objNode;
									// if there was an explanation provides as a value
									hasExplanation = classBehaviours.utilities.getClassParameter(objNode, 'explanation', 'no');
									if(hasExplanation=='yes'){
										// clear the value
										objNode.value = '';
										// che change the class back to normal
										objNode.className = objNode.className.replace('explanation_yes', 'explanation_no');
									}
								}
				this.all 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var vi = classBehaviours.handlers.validateInput;
									var booPassed = true;
									// if there was a focus point stored use it
									if(vi.lastFocus!=null) objNode = vi.lastFocus;
									// find the form's root
									if(objNode!=null) rootNode = classBehaviours.utilities.rootNode(objNode, null, null, 'validateAllInput');
									// get all subnodes in the form
									var objSubNodes = rootNode.getElementsByTagName("*");
									// for all nodes
									var queryString = '';
									for(var intA=0; intA<objSubNodes.length; intA++){
										// Does this node have the validateInput put class? Invoke the validator function upon it.
										if(objSubNodes[intA].className.toLowerCase().indexOf('validateinput')>-1 && vi.isFormElement(objSubNodes[intA])) 
											booPassed = (vi.input(objSubNodes[intA], false) && booPassed);
										// Note the name and value
										if(objSubNodes[intA].nodeName=='INPUT' || objSubNodes[intA].nodeName=='SELECT' || objSubNodes[intA].nodeName=='TEXTAREA')
											queryString += (objSubNodes[intA].checked || (objSubNodes[intA].type!='radio' && objSubNodes[intA].type!='checkbox')) ? objSubNodes[intA].name + '=' + objSubNodes[intA].value + '&' : '' ;
									}
									// if an ajax submit is required
									replyId = classBehaviours.utilities.getClassParameter(rootNode, 'ajaxReplyId', null);
									submitId = classBehaviours.utilities.getClassParameter(rootNode, 'ajaxReplyUrl', null);
									if(replyId!=null && submitId!=null && booPassed){
										// get the submitted properties
										replyTarget = document.getElementById(replyId);
										submitUrl = (document.getElementById(submitId).nodeName=='FORM') ? document.getElementById(submitId).getAttribute('action') : document.getElementById(submitId).getAttribute('value') ;
										// submit the form using ajax
										classBehaviours.ajax.addRequest(submitUrl + '?' + queryString, vi.ajaxReply, vi.ajaxWait, null, replyTarget);
										// cancel the actual submit
										return false;
									// else
									}else{
										// let the form submit or not
										return booPassed;
									}
								}
				this.input = 	function(that, override){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var vi = classBehaviours.handlers.validateInput;
									// default validator values
									var booEmptyValidator, booValueValidator;
									// get the type of validation required
									strValidatorName	= classBehaviours.utilities.getClassParameter(objNode, 'type', '');
									allowEmpty			= classBehaviours.utilities.getClassParameter(objNode, 'allowEmpty', 'no');
									ifCheckedId			= classBehaviours.utilities.getClassParameter(objNode, 'ifCheckedId', null);
									hasExplanation 		= classBehaviours.utilities.getClassParameter(objNode, 'explanation', 'no');
									// check a special dependency on a parent checkbox
									if(ifCheckedId){
										if(!document.getElementById(ifCheckedId).checked) allowEmpty = 'yes';
									}
									// VALIDATION TESTS
									// empty test	objNode.value!=''
									booEmptyValidator = (allowEmpty=='yes' && (objNode.value=='' || hasExplanation=='yes'));
									// bizarre exception for MSIE 5.0
									if(navigator.appVersion.indexOf('MSIE 5.0')>-1 && strValidatorName=='money') strValidatorName = null;
									// test expressions
									switch(strValidatorName){
										// regular expression tests
										case 'email' : 
											booValueValidator = (objNode.value.match(/^[\w\.\-\,\+]+@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$/)!=null);
											break;
										case 'phone' : 
											booValueValidator = (objNode.value.match(/(^\+[0-9]{2}|^\+[0-9]{2}\(0\)|^\(\+[0-9]{2}\)\(0\)|^00[0-9]{2}|^0)([0-9]{9}$|[0-9\-\s]{10}$)/)!=null); 
											break;
										case 'dutchzipcode' : 
											booValueValidator = (objNode.value.match(/^[0-9]{4}\s{0,1}[a-zA-Z]{2}$/)!=null); 
											break;
										case 'date' : 
											booValueValidator = (objNode.value.match(/^\d{4}\-\d{1,2}\-\d{1,2}$/)!=null);
											// booRegExpValidator = (objNode.value.match(/^\d{1,2}\-\d{1,2}\-(\d{2}|\d{4})$/)!=null); 
											break;
										case 'number' : 
											booValueValidator = (objNode.value.match(/^[0-9]+$/)!=null); 
											break;
										case 'money' :
											booValueValidator = (objNode.value.match(/^[0-9]+(\.[0-9]{1,2})?$/)!=null); 
											break;
										case 'alphanumeric' :
											booValueValidator = (objNode.value.match(/^[a-zA-Z0-9]/)!=null);
											break;
										// custom tests
										case 'bankaccount' :
											booValueValidator = vi.customChecks.bankAccount(objNode);
											break;
										case 'isradiochecked' :
											booValueValidator = vi.customChecks.isRadioChecked(objNode);
											break;
										case 'anyofthesechecked' : 
											booValueValidator = vi.customChecks.anyOfTheseChecked(objNode);
											break;
										case 'text' :
											booValueValidator = (objNode.value!="");
											break;
										case 'repeat' :
											booValueValidator = vi.customChecks.isRepeated(objNode);
											break;
										case 'regexp' : 
											customRegId = classBehaviours.utilities.getClassParameter(objNode,'regxid','myRegExp');
											customRegString = document.getElementById(customRegId).value;
											customRegExp = new RegExp(customRegString);
											booValueValidator = (objNode.value.match(customRegExp)!=null);
											break;
										default :
											booValueValidator = true;
									}
									// does the input validate when the field is not empty or not allowed to be empty
									validates = (!booEmptyValidator) ? (booValueValidator && hasExplanation=='no') : true ;
									// show or hide the warning message based on the validator's match
									vi.warning(objNode, validates);
									// is a summary required?
									vi.summary(objNode);
									// return a pass of fail boolean to whoever may want to know the results of the test
									return (override!=null) ? validates : override;
								}
			}
				function CustomChecks(){
					this.bankAccount 		= 	function(objNode){
													var intDeel, intRest;
													var strInput = objNode.value;
													var intTot=0;
													if (strInput.length!=9){
														return false;
													}else{
														for (i=0; i<strInput.length; i++) intTot += strInput.substr(i,1) * (9 - i);
														intDeel = intTot/11;
														intRest = intTot%11;
														return (intRest==0);
													}
												}
					this.isRadioChecked		=	function(objNode){
													// get all inputs with this name
													allInputs = document.getElementsByTagName('input');
													// for all inputs
													for(var a=0; a<allInputs.length; a++){
														// If the input has the same name. 
														if(allInputs[a].name == objNode.name){
															// If the input is checked set the validator to true
															if(allInputs[a].checked) return true;
														}
													}
													return false;
												}
					this.anyOfTheseChecked	=	function(objNode){
														// default validatie
														anyChecked = false;
														// get all inputs from the parentnode
														allChecks = objNode.parentNode.parentNode.getElementsByTagName('input');
														// for all inputs
														for(var a=0; a<allChecks.length; a++){
															// if this checkbox is checked remember is
															if(allChecks[a].checked) anyChecked = true;
														}
														return anyChecked;
													}
					this.isRepeated			=	function(objNode){
														// default validatie
														wasRepeated = false;
														// get the target field to compare
														repeatedId = classBehaviours.utilities.getClassParameter(objNode, 'id', null);
														// if the id is valid
														if(repeatedId!=null){
															repeatedValue = document.getElementById(repeatedId).value;
															wasRepeated = (repeatedValue==objNode.value);
														}
														// report back
														return wasRepeated;
													}
				}
			// add this function to the classbehaviour object
			classBehaviours.handlers.validateInput = new ValidateInput;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.validateInput;
		
			// Triggers all validateInput class behaviours within a node after the onsubmit event.',
			function ValidateAllInput(){
				// properties
				this.name 		= 	'validateAllInput';
				// methods
				this.start		=	function(node){
										// find the form
									//	formNode = classBehaviours.utilities.rootNode(node, 'FORM', null, null);
										// set the form validation eventhandler
									//	if(node.nodeName=='FORM') node.onsubmit = classBehaviours.handlers.validateInput.all;
										if(node.nodeName=='FORM') classBehaviours.utilities.addEvent(node, 'submit', classBehaviours.handlers.validateInput.all);
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.validateAllInput = new ValidateAllInput;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.validateAllInput;
					
			// Disable form elements during a submit, to avoid multiple submits on slow servers
			function DisableAfterSubmit(){
				// properties
				this.name 		= 	'disableAfterSubmit';
				// methods
				this.start		=	function(node){
										node.onsubmit = this.disable;
										// get all elements in this form
										allNodes = node.getElementsByTagName("*");
										// is this a form using microsoft's postbacks
										if(typeof(__doPostBack)!='undefined'){
											// for all nodes in this form
											for(var a=0; a<allNodes.length; a++){
												// if this form element has a _dopostback
												if(allNodes[a].onchange!=null){
													if(allNodes[a].onchange.toString().indexOf('__doPostBack')>-1){
														// overrule microsoft's postback event
														allNodes[a].onchange = this.disable;
													}
												}
												if(allNodes[a].onclick!=null){
													if(allNodes[a].onclick.toString().indexOf('__doPostBack')>-1){
														// overrule microsoft's postback event
														allNodes[a].onclick = this.disable;
													}
												}
											}
										}
										// if there's also a validation behaviour defined, trigger it
										if(node.className.indexOf('validateAllInput')>-1) classBehaviours.handlers.validateAllInput.start(node);
									}
				// events
				this.disable	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// trigger microsoft's postback
										if(typeof(__doPostBack)!='undefined') __doPostBack(objNode.id, objNode.value);
										// get all elements in this form
										allNodes = document.getElementsByTagName("*");
										// for all nodes in this form
										for(var a=0; a<allNodes.length; a++){
											// if this is a form element
											if(
												allNodes[a].nodeName.indexOf('INPUT')>-1 ||
												allNodes[a].nodeName.indexOf('SELECT')>-1 ||
												allNodes[a].nodeName.indexOf('TEXTAREA')>-1
											){
												// disable the form element
												allNodes[a].disabled = true;
												// deny focus
												allNodes[a].onfocus = blur;
											}
										}
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.disableAfterSubmit = new DisableAfterSubmit;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.disableAfterSubmit;
			
			// Manage all event handlers of an imagemap
			function ImageMap(){
				// properties
				this.name 		= 	'imageMap';
				this.map		=	new Map;
				this.areas		=	new Areas;
				// methods
				this.start		=	function(node){
										// start the storing of the map object
										node.onmouseover = this.map.over;
										this.map.over(node);
										// get all areas in this map
										areas = document.getElementById(this.map.name).getElementsByTagName('area');
										// for all areas in this map
										for(var a=0; a<areas.length; a++){
											// cache it's image equivalent
											this.cache(node.src.replace(this.map.passive, areas[a].id));
											// give the area event handlers
											areas[a].onmouseover = this.areas.over;
											areas[a].onmouseout = this.areas.out;
										}
									}
				// events
				this.cache		= 	function(url) {
											var imp = classBehaviours.handlers.imageMap;
											// preload the image into an array
											imp.map.images[imp.map.images.length] = new Image();
											imp.map.images[imp.map.images.length-1].src = url;
									}
			}
				function Map(){
					// properties
					this.object		=	null;
					this.name		=	null;
					this.passive	=	'default';
					this.images		=	new Array();
					// methods
					this.over		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var imp = classBehaviours.handlers.imageMap;
											// store the currently active map
											imp.map.object = objNode;
											imp.map.name = objNode.getAttributeNode('usemap').value.replace('#','');
										}
				}
				function Areas(){
					// methods
					this.over	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var imp = classBehaviours.handlers.imageMap;
										// apply the area id to the map's source
										imp.map.object.src = imp.map.object.src.replace(imp.map.passive, objNode.id);
									}
					this.out	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var imp = classBehaviours.handlers.imageMap;
										// apply the area id to the map's source
										imp.map.object.src = imp.map.object.src.replace(objNode.id, imp.map.passive);
									}
				}
			
			// add this function to the classbehaviour object
			classBehaviours.handlers.imageMap = new ImageMap;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.imageMap;
			
			// clear a form element filled with a help text
			function EmptyOnFocus(){
				// properties
				this.name 		= 	'emptyOnFocus';
				// methods
				this.start		=	function(node){
										node.onfocus = this.clear;
									}
				// events
				this.clear		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// clear the contents if this is the first time
										if(objNode.className.indexOf('wasEmptied')<0){
											// clear this field
											objNode.value = '';
											// mark this input as cleared
											objNode.className += ' wasEmptied';
										}
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.emptyOnFocus = new EmptyOnFocus;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.emptyOnFocus;
		
			// make a slideshow from a list of images
			function SlideshowList(){
				// properties
				this.name 		= 	'slideshowList';
				this.locked		=	false;
				this.index		=	0;
				// methods
				this.start		=	function(node){
										// get the next and previous buttons
										allButtons = node.getElementsByTagName('button');
										// set the event handlers
										if(allButtons.length>0) allButtons[allButtons.length-1].onclick = this.next;
										if(allButtons.length>1) allButtons[allButtons.length-2].onclick = this.previous;
										// update the instance counter of this class
										this.index += 1;
										// set the default states of the slides
										allSlides = node.getElementsByTagName('li');
										allSlides[0].className += (allSlides[0].className.indexOf('active')<0) ? ' active' : '' ;
										for(var a=0; a<allSlides.length; a++){
											// if the slide doesn't have an id, make one
											allSlides[a].id = (allSlides[a].id) ? allSlides[a].id : 'list' + this.index + 'slide' + a;
											// set the initial display state
											allSlides[a].style.display = (allSlides[a].className.indexOf('active')>-1) ? 'block' : 'none' ;
										}
									}
				/* events */
				this.next		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										if(!classBehaviours.handlers.slideshowList.locked){
											classBehaviours.handlers.slideshowList.locked = true;
											// get all slides
											allSlides = objNode.parentNode.getElementsByTagName('li');
											// default starting position
											var activeSlide = allSlides[0];
											var nextSlide = allSlides[1];
											// look for the active node
											for(var a=0; a<allSlides.length; a++){
												// if this slide is marked active
												if(allSlides[a].className.indexOf('active')>-1){
													// store the active slide
													activeSlide = allSlides[a];
													// store the next slide
													nextSlide = (a<allSlides.length-1) ? allSlides[a+1] : allSlides[0] ;
												}
											}
											// set the display state
											activeSlide.style.position = 'absolute';
											nextSlide.style.position = 'relative';
											// change the classes
											activeSlide.className = activeSlide.className.replace(' active','').replace('active','');
											nextSlide.className += ' active';
											// if the two slides are of the same size
											if(classBehaviours.utilities.getClassParameter(objNode.parentNode, 'sameSize', 'no')=='yes'){
												// fade the next slide over the old one
												classBehaviours.fader.crossFade(nextSlide.id, "", 0, 100, 1, "classBehaviours.handlers.slideshowList.unlock()");
												classBehaviours.fader.crossFade("", activeSlide.id, 0, 5, 10, "classBehaviours.handlers.slideshowList.unlock()");
											}else{
												// cross-fade between the active and next slide
												classBehaviours.fader.crossFade(nextSlide.id, activeSlide.id, 0, 5, 10, "classBehaviours.handlers.slideshowList.unlock()");
											}
										}
									}
				this.previous	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										if(!classBehaviours.handlers.slideshowList.locked){
											classBehaviours.handlers.slideshowList.locked = true;
											// get all slides
											allSlides = objNode.parentNode.getElementsByTagName('li');
											// default starting position
											var activeSlide = allSlides[0];
											var nextSlide = allSlides[allSlides.length-1];
											// look for the active node
											for(var a=0; a<allSlides.length; a++){
												// if this slide is marked active
												if(allSlides[a].className.indexOf('active')>-1){
													// store the active slide
													activeSlide = allSlides[a];
													// store the next slide
													nextSlide = (a>0) ? allSlides[a-1] : allSlides[allSlides.length-1] ;
												}
											}
											// set the display state
											activeSlide.style.position = 'absolute';
											nextSlide.style.position = 'relative';
											// change the classes
											activeSlide.className = activeSlide.className.replace(' active','').replace('active','');
											nextSlide.className += ' active';
											// if the two slides are of the same size
											if(classBehaviours.utilities.getClassParameter(objNode.parentNode, 'sameSize', 'no')=='yes'){
												// fade the next slide over the old one
												classBehaviours.fader.crossFade(nextSlide.id, "", 0, 100, 1, "classBehaviours.handlers.slideshowList.unlock()");
												classBehaviours.fader.crossFade("", activeSlide.id, 0, 5, 10, "classBehaviours.handlers.slideshowList.unlock()");
											}else{
												// cross-fade between the active and next slide
												classBehaviours.fader.crossFade(nextSlide.id, activeSlide.id, 0, 5, 10, "classBehaviours.handlers.slideshowList.unlock()");
											}
										}
									}
				this.unlock	=	function(){
										this.locked = false;
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.slideshowList = new SlideshowList;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.slideshowList;
		
			// Enrich a calendar control
			function DatePicker(){
				// properties
				this.name 		= 	'datePicker';
				this.dateHtml	=	'';
				this.index		=	0;
				// methods
				this.start		=	function(node, nodeId){
										if(node==null) node = document.getElementById(nodeId); 
										// give this node an id if it doesn't have one yet
										this.index += 1;
										node.id = (node.id) ? node.id : this.name + this.index ;
										node.className += ' toggleNextNode';
										// start the toggle event
										classBehaviours.handlers.toggleNextNode.start(node);
										// find the calendar container node
										calendarContainer = classBehaviours.utilities.nextNode(node);
										// import the calendar xml or use the one allready loaded
										if(this.dateHtml==''){
											// report the loading-in-progress of the calender
											this.dateHtml='loading...';
											// find the path to the xml source
											this.dateHtmlSrc = classBehaviours.utilities.nextNode(node).getElementsByTagName('input')[0].value;
											// import it
											classBehaviours.ajax.addRequest(this.dateHtmlSrc, classBehaviours.handlers.datePicker.build, null, null, calendarContainer);
										}else if(this.dateHtml=='loading...'){
											// wait until the loading of the html is finished
											setTimeout('classBehaviours.handlers.datePicker.start(null, "' + node.id + '")', 512);
										}else{
											// continue, using the cached html
											this.build(null, calendarContainer, this.dateHtml);
										}
										// set the event handlers for this node
										node.onclick = this.open;
									}
				this.set		=	function(calendarNode, date){
										dpr = classBehaviours.handlers.datePicker;
										// get the next and previous buttons
										calendarNode.getElementsByTagName('button')[0].onclick = dpr.previous;
										calendarNode.getElementsByTagName('button')[1].onclick = dpr.next;
										// set the month dropdown
										monthNode = calendarNode.getElementsByTagName('select')[0];
										monthNode.selectedIndex = date.getMonth();
										monthNode.onchange = dpr.update;
										// set the year dropdown
										yearSelect = calendarNode.getElementsByTagName('select')[1];
										yearOptions = yearSelect.getElementsByTagName('option');
										currentYear = date.getFullYear();
										if(yearOptions.length==1){
											yearOption = yearOptions[0].cloneNode(true);
											for(var a=currentYear-100; a<currentYear+10; a++ ){
												yearOption = yearSelect.getElementsByTagName('option')[0].cloneNode(true);
												yearOption.value = a;
												yearOption.selected = (a==currentYear) ? 'selected' : '' ;
												yearOption.text = a;
												yearSelect.appendChild(yearOption);
											}
											yearSelect.removeChild(yearSelect.getElementsByTagName('option')[0]);
											yearSelect.onchange = dpr.update;
										}else{
											for(var a=0; a<yearOptions.length; a++) yearOptions[a].selected = (yearOptions[a].value==currentYear) ? 'selected' : '' ;
										}
										// clear out the previous month
										daySlots = calendarNode.getElementsByTagName('td');
										for(var a=0; a<daySlots.length; a++){
											daySlots[a].className = "empty";
											daySlots[a].innerHTML = "";
											daySlots[a].onclick = null;
										}
										// fill the new month
										currentDay = new Date(date.getFullYear(), date.getMonth(), 0);
										nextDay = new Date(date.getFullYear(), date.getMonth(), 1);
										startWeekDay = currentDay.getDay();
										if(startWeekDay>=6) startWeekDay -= 6;
										do{
											// next date
											currentDay = new Date(currentDay.getFullYear(), currentDay.getMonth(), currentDay.getDate()+1);
											nextDay = new Date(nextDay.getFullYear(), nextDay.getMonth(), nextDay.getDate()+1);
											// put the date on the weekday cell
											daySlots[currentDay.getDate()+startWeekDay].innerHTML = currentDay.getDate();
											daySlots[currentDay.getDate()+startWeekDay].className = "";
											daySlots[currentDay.getDate()+startWeekDay].onclick = dpr.pick;
										}while(currentDay.getDate() < nextDay.getDate())
									}
				this.build		=	function(xmlDoc, calendarContainer, txtDoc){
										// store the html
										classBehaviours.handlers.datePicker.dateHtml = txtDoc;
										// clean the imported xhtml
										calendarContainer.innerHTML = txtDoc.replace('<?xml version="1.0"?>', '').replace('<root>', '').replace('</root>', '');
										// apply the events
										classBehaviours.parser.parseNode(calendarContainer);
									}
				// events
				this.open		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var dpr = classBehaviours.handlers.datePicker;
										// close all other calendars
										dpr.close();
										// OBJECTS
										calendar = classBehaviours.utilities.nextNode(objNode);
										// STARTING DATE
										// get the input from the field
										// turn it into a date
										// if the result is a date
											// use it as a start date
										// else
											// take the current date
											theDate = new Date();
										// CONSTRUCT THE CALENDAR AT THE GIVEN DATE
										dpr.set(calendar, theDate);
										// POSITION THE CALENDAR
										// get the position
										screenXpos = (typeof(event)!='undefined') ? event.x : that.layerX;
										screenYpos = (typeof(event)!='undefined') ? event.y : that.layerY;
										// if the position is too close to the edge
										calendarWidth = calendar.firstChild.offsetWidth;
										screenWidth = (window.innerWidth) ? window.innerWidth : document.documentElement.clientWidth ;
										scrolledWidth = (typeof(document.documentElement.scrollLeft)!='undefined') ? document.documentElement.scrollLeft : window.pageXOffset ;
										if(screenXpos+calendarWidth > screenWidth+window.pageXOffset) screenXpos -= calendarWidth;
										// if the position is too close to the bottom
										calendarHeight = calendar.firstChild.offsetHeight;
										screenHeight = (window.innerHeight) ? window.innerHeight : document.documentElement.clientHeight ;
										scrolledHeight = (typeof(document.documentElement.scrollTop)!='undefined') ? document.documentElement.scrollTop : window.pageYOffset ;
										if(screenYpos+calendarHeight+10 > screenHeight+scrolledHeight) screenYpos -= calendarHeight;
										// set the position
										calendar.style.left = screenXpos + 'px';
										calendar.style.top = screenYpos + 'px';
										// SHOW THE CALENDAR
										classBehaviours.handlers.toggleNextNode.toggle(objNode);
										// prepare to close the calendar
										calendar.onmouseover = dpr.cancel;
										calendar.onmouseout	= dpr.wait;
										return false;
									}
				this.wait		=	function(){
										closeCalendarTimeout = setTimeout('classBehaviours.handlers.datePicker.close()',1024);
									}
				this.cancel		=	function(){
										if(typeof(closeCalendarTimeout)!='undefined') clearTimeout(closeCalendarTimeout);
									}
				this.close		=	function(){
										// get all buttons that might have open calendars
										allButtons = document.getElementsByTagName('button');
										for(var a=0; a<allButtons.length; a++){
											if(allButtons[a].className.indexOf('datePicker')>-1) 
												if(classBehaviours.utilities.nextNode(allButtons[a]).className.indexOf('showThisNode')>-1)
													classBehaviours.handlers.toggleNextNode.toggle(allButtons[a]);
										}
									}
				this.update		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var dpr = classBehaviours.handlers.datePicker;
										// get both selectors from the parent node
										selectors = objNode.parentNode.getElementsByTagName('select');
										// get the month
										month = parseInt(selectors[0].value);
										// get the year
										year = parseInt(selectors[1].value);
										// make a date out of it
										theDate = new Date(year, month, 1);
										// update the calendar
										dpr.set(objNode.parentNode.parentNode.parentNode.parentNode,theDate);
									}
				this.next		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var dpr = classBehaviours.handlers.datePicker;
										// get the calendar
										calendar = classBehaviours.utilities.rootNode(objNode, null, null, 'datePicker');
										// get the displayed date
										month = parseInt(calendar.getElementsByTagName('select')[0].value);
										year = parseInt(calendar.getElementsByTagName('select')[1].value);
										// add a month
										theDate = new Date(year,month+1,1);
										// build the calendar
										dpr.set(calendar, theDate);
										return false;
									}
				this.previous	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var dpr = classBehaviours.handlers.datePicker;
										// get the calendar
										calendar = classBehaviours.utilities.rootNode(objNode, null, null, 'datePicker');
										// get the displayed date
										month = parseInt(calendar.getElementsByTagName('select')[0].value);
										year = parseInt(calendar.getElementsByTagName('select')[1].value);
										// subsctract a month
										theDate = new Date(year,month-1,1);
										// build the calendar
										dpr.set(calendar,theDate);
										return false;
									}
				this.pick		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// get the selected day
										dayValue = objNode.innerHTML;
										// get the selected month
										calendarTitle = objNode.parentNode.parentNode.parentNode.getElementsByTagName('caption')[0];
										month = calendarTitle.getElementsByTagName('select')[0];
											// monthValue = month[month.selectedIndex].innerHTML;
										monthValue = parseInt(month.value) + 1;
										// get the selected year
										year = calendarTitle.getElementsByTagName('select')[1];
										yearValue = year[year.selectedIndex].innerHTML;
										// put it in the input field
										targetFields = objNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.getElementsByTagName('input');
										targetFields[0].value = ((dayValue+'').length==1) ? '0' + dayValue  : dayValue;
										targetFields[1].value = ((monthValue+'').length==1) ? '0' + monthValue : monthValue;
										targetFields[2].value = yearValue;
										// close the calendar
										calendarButton = objNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.getElementsByTagName('button')[0];
										classBehaviours.handlers.toggleNextNode.toggle(calendarButton);
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.datePicker = new DatePicker;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.datePicker;
			
			// Center landscape or portrait thumbnails in a defined area
			function CenteredThumbnails(){
				// properties
				this.name 		= 	'centeredThumbnails';
				this.index		=	0;
				// methods
				this.start		=	function(node){
										// count the instance
										this.index += 1;
										// give this node an id if it doesn't have one
										if(node.id != null) node.id = this.name + this.index;
										// center the thumbnail in a short while
										setTimeout('classBehaviours.handlers.centeredThumbnails.process("'+node.id+'")', 10);
									}
				this.process	=	function(nodeId){
										// get the node
										node = document.getElementById(nodeId);
										// get all links in this container
										allLinks = node.getElementsByTagName('a');
										// if this is a single item
										if(allLinks.length==0) allLinks = new Array(node);
										// for all containers
										for(var a=0; a<allLinks.length; a++){
											// get the dimensions of the container
											containerSize = new Array(allLinks[a].offsetWidth, allLinks[a].offsetHeight);
											// get the thumbnail
											thumbnail = allLinks[a].getElementsByTagName('img')[0];
											// get the dimensions of the thumbnail
											thumbnailSize = new Array(thumbnail.offsetWidth, thumbnail.offsetHeight);
											// set the position of the thumbnail
											offsetX = (containerSize[0] - thumbnailSize[0])/2;
											offsetY = (containerSize[1] - thumbnailSize[1])/2;
											thumbnail.style.margin = offsetY + "px " + offsetX + "px " + offsetY + "px " + offsetX + "px";
										}
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.centeredThumbnails = new CenteredThumbnails;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.centeredThumbnails;
			
			// hover the next node near the mouse pointer
			function HoverNextNode(){
				// properties
				this.name 		= 	'hoverNextNode';
				// methods
				this.start		=	function(node){
										// mouse handlers
										if(document.body.className.indexOf('widget')<0){
											node.onmouseover = this.show;
											node.onmouseout = this.hide;
											node.onmousemove = this.place;
										}else{
											node.onmouseover = this.lift;
											node.onmouseout = this.drop;
										}
									}
				// events
				this.lift		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										targetNode = classBehaviours.utilities.nextNode(objNode);
										targetNode.style.zIndex = 1000;
									}
				this.drop		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										targetNode = classBehaviours.utilities.nextNode(objNode);
										targetNode.style.zIndex = 800;
									}
				this.show		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										targetNode = classBehaviours.utilities.nextNode(objNode);
										targetNode.style.visibility = 'visible';
									}
				this.hide		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										targetNode = classBehaviours.utilities.nextNode(objNode);
										targetNode.style.visibility = 'hidden';
									}
				this.place		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										targetNode = classBehaviours.utilities.nextNode(objNode);
										targetNode.style.position = 'absolute';
										targetNode.style.left = (typeof(that)!='undefined') ? (that.layerX) + 'px' : (event.x) + 'px' ;
										targetNode.style.top = (typeof(that)!='undefined') ? (that.layerY) + 'px' : (event.y) + 'px' ;
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.hoverNextNode = new HoverNextNode;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.hoverNextNode;
			
			// Use SwfObject to replace a title with a flash version
			// hide the alternative beforehand
			document.writeln("<style>.flashTitle .flashAlternative{visibility : hidden;}</style>");
			function FlashTitle(){
				// properties
				this.name 			= 	'flashTitle';
				this.index			=	0;
				this.cachedXml		=	'';
				// methods
				this.start			=	function(node){
											// give the node an id of it doesn't have one
											if(!node.id){
												node.id = this.name + this.index;
												this.index += 1;
											}
											// check if there is flash
											requiredVersion = parseInt(classBehaviours.utilities.getClassParameter(node, 'version', '7'));
											if(this.checkForFlash(requiredVersion)){
												// load the source file
												if(this.cachedXml=='') this.loadXml(node)
												else if(this.cachedXml=='loading...') this.retryLater(node)
												else this.processXml(null, node, this.cachedXml);
											}else{
												// make the alternative content visible, just in case it didn't work
												classBehaviours.handlers.flashTitle.showAlt(node);
											}
										}
				this.checkForFlash	=	function(requiredVersion){
											// check if Adobe's flash checking script is available
											return (typeof(DetectFlashVer)!='undefined') ? DetectFlashVer(requiredVersion, 0, 0) : true ;
										}
				this.loadXml		=	function(node){
											classBehaviours.handlers.flashTitle.cachedXml = 'loading...';
											// load the xml file
											loadUrl = node.getElementsByTagName('input')[0].value;
											classBehaviours.ajax.addRequest(loadUrl, this.processXml, this.loadProgress, null, node);
										}
				this.retryLater		=	function(node){
											// wait while loading
											setTimeout('classBehaviours.handlers.flashTitle.start(document.getElementById("' + node.id + '"))', 100);
										}
				this.loadProgress	=	function(progress, referer){
											// if loading fails show the alternative
											if(progress<0) classBehaviours.handlers.flashTitle.showAlt(referer);
										}
				this.processXml		=	function(sourceDoc, node, sourceText){
											// store the xml for re-use
											classBehaviours.handlers.flashTitle.cachedXml = sourceText;
											// set the default values for all parameters
											flashMovie		= "../flash/flashTitle.swf";
											flashWidth		= node.offsetWidth;
											flashHeight		= node.offsetHeight;
											flashWmode		= "Transparent";
											flashScale		= "noScale";
											flashSalign		= "l";
											flashName		= "_" + node.id;
											flashVariables	= "inputText=" + node.innerHTML.replace(/<(.|\n)*?>/gi,"").replace(/^\s+/gi,"").replace(/&/gi,"&");
											// for all childnodes of node which may contain configuration variables
											allInputs = node.getElementsByTagName('input');
											for(var a=0; a<allInputs.length; a++){
												switch(allInputs[a].name){
													case 'movie' 			: flashMovie = allInputs[a].value; break;
													case 'width' 			: flashWidth = allInputs[a].value; break;
													case 'height' 			: flashHeight = allInputs[a].value; break;
													case 'wmode' 			: flashWmode = allInputs[a].value; break;
													case 'scale' 			: flashScale = allInputs[a].value; break;
													case 'salign' 			: flashSalign = allInputs[a].value; break;
													case 'name' 			: flashName = allInputs[a].value; break;
													case 'flashvars' 		: flashVariables += '&' + allInputs[a].value; break;
													default 				: break;
												}
											}
											// if the dimensions are in %, be sure to tell the container
											if(flashWidth.toString().indexOf('%')>-1) node.style.width = flashWidth;
											if(flashHeight.toString().indexOf('%')>-1) node.style.height = flashHeight;
											// load the flash plugin
											sourceText = sourceText.replace('<?xml version="1.0"?>', '');
											sourceText = sourceText.replace(/{movie}/gi, flashMovie);
											sourceText = sourceText.replace(/{width}/gi, flashWidth);
											sourceText = sourceText.replace(/{height}/gi, flashHeight);
											sourceText = sourceText.replace(/{wmode}/gi, flashWmode);
											sourceText = sourceText.replace(/{scale}/gi, flashScale);
											sourceText = sourceText.replace(/{salign}/gi, flashSalign);
											sourceText = sourceText.replace(/{name}/gi, flashName);
											sourceText = sourceText.replace(/{flashvars}/gi, flashVariables);
											node.innerHTML = sourceText;
										}
				this.setFlashVar	=	function(nodeId, varName, varValue){
											// find the proper buried ID
											node = 	(document.getElementById('__'+nodeId)) ? 
														document.getElementById('__'+nodeId) : 
															(document.getElementById('_'+nodeId)) ? 
																document.getElementById('_'+nodeId) : 
																	document.getElementById(nodeId) ;
											// send the parameter to the flash object
											if(typeof(node.SetVariable)!='undefined') node.SetVariable(varName, varValue);
										}
				// events
				this.showAlt		=	function(node){
											allContents = node.getElementsByTagName('*');
											if(allContents.length>0) 
												for(var a=0; a<allContents.length; a++) 
													if(allContents[a].className.indexOf('flashAlternative')>-1) 
														allContents[a].style.visibility = 'visible';
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.flashTitle = new FlashTitle;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.flashTitle;
			
			// Update a slide based on clicks on thumbnails
			function ThumbnailToPhoto(){
				// properties
				this.name 		= 	'thumbnailToPhoto';
				this.thumbnails	=	new Array();
				this.stackTop	=	1;
				// methods
				this.start		=	function(node){
										// add the thumbnail to the index
										this.thumbnails[this.thumbnails.length] = node;
										// set the click event
										node.onclick = this.loadPhoto;
									}
				// events
				this.loadPhoto	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var ttp = classBehaviours.handlers.thumbnailToPhoto;
										// if this is not an active thumbnail
										if(objNode.className.indexOf('active')<0){
											// get the target of this thumbnail
											targetId = classBehaviours.utilities.getClassParameter(objNode, 'id', 'thumbnailTarget');
											// for all thumbnails
											allThumbnails = ttp.thumbnails;
											for(var a=0; a<allThumbnails.length; a++){
												// deactivate the thumbnails with the same target
												thumbnailTargetId = classBehaviours.utilities.getClassParameter(allThumbnails[a], 'id', 'thumbnailTarget')
												if(thumbnailTargetId==targetId) allThumbnails[a].className = allThumbnails[a].className.replace(' active','');
											}
											// activate this thumbnail
											objNode.className += ' active';
											// find the image in the existing target stack
											targetStack = document.getElementById(targetId);
											targetImages = targetStack.getElementsByTagName('img');
											targetImage = null;
											for(var a=0; a<targetImages.length; a++) if(targetImages[a].src==objNode.href) targetImage = targetImages[a];
											// if the image isn't in the stack allready
											if(targetImage==null){
												// create a new image
												clonedImage = targetImages[0].cloneNode(true);
												// place it at the bottom of the stack
												targetStack.insertBefore(clonedImage, targetStack.firstChild);
												// set the properties of the new image
												clonedImage = classBehaviours.utilities.previousNode(targetImages[0]);
												clonedImage.id = null;
												clonedImage.onload = ttp.showPhoto;
												clonedImage.src = objNode.href;
												clonedImage.title = objNode.getElementsByTagName('img')[0].title;
												clonedImage.alt = objNode.getElementsByTagName('img')[0].alt;
											// else
											}else{
												// if this isn't the same slide as the last one, skip to the show function
												ttp.showPhoto(targetImage);
											}
										}
										// cancel the click
										return false;
									}
				this.showPhoto	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var ttp = classBehaviours.handlers.thumbnailToPhoto;
										// fade it out
										classBehaviours.fader.setFade(objNode, 0);
										// put it at the top of the stack
										ttp.stackTop += 1;
										objNode.style.zIndex = ttp.stackTop;
										// fade it in
										objNode.id = (objNode.id==null) ? objNode.id : ttp.name + ttp.stackTop ;
										classBehaviours.fader.fadeIn(objNode.id, 10, 50, null);
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.thumbnailToPhoto = new ThumbnailToPhoto;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.thumbnailToPhoto;
			
			// Turn an element into an HTML-editor
			function RichTextEditor(){
				// properties
				this.name 			= 	'richTextEditor';
				this.containerType	=	'FIELDSET';
				this.buttonType		=	'BUTTON';
				this.stylesheet		=	'';
				this.editorHtml		=	'';
				this.index			=	0;
				this.instances		= 	new Array();
				this.interval		=	null;
				this.resizing		=	false;
				this.bookmark		=	null;
				// methods
				this.start			=	function(node){ 
											// give this node an id if it doesn't have one yet
											if(node.id==null){
												this.index += 1;
												node.id = this.name + this.index ;
											}
											// import the editor if it has not been preloaded
											if(this.editorHtml==''){
												this.editorHtml = 'loading...';
												pathNode = node.getElementsByTagName('INPUT')[0];
												classBehaviours.ajax.addRequest(pathNode.value, this.importXml, this.awaitXml, null, node);
											// if another instance of the editor is loading
											}else if(this.editorHtml=='loading...'){
												setTimeout('classBehaviours.handlers.richTextEditor.start(document.getElementById("'+node.id+'"))', 512);
											// if the editor is allready there
											}else{
												classBehaviours.handlers.richTextEditor.process(node);
											}
										}
				this.awaitXml		=	function(loadStatus, rootNode){
											// debug(loadStatus);
										}
				this.importXml		=	function(toolsXml, rootNode, toolsText){
											var edc = classBehaviours.handlers.richTextEditor;
											// extract the html from the imported xml
											edc.stylesheet = toolsText.split('<stylesheet>')[1].split('</stylesheet>')[0];
											edc.editorHtml = toolsText.split('<editorHtml>')[1].split('</editorHtml>')[0];
											// process the nodes
											edc.process(rootNode);
										}
				this.process		=	function(rootNode){
											var edc = classBehaviours.handlers.richTextEditor;
											// insert the editor html before the textarea
											rootNode.innerHTML = edc.editorHtml + rootNode.innerHTML;
											// prepare the editor
											edc.setCanvas(rootNode);
											edc.setControls(rootNode);
											// add this editor to the instances of editors
											edc.instances[edc.instances.length] = rootNode;
											// sync loop between the textarea and the iframe
											clearInterval(edc.interval);
											edc.interval = setInterval("classBehaviours.handlers.richTextEditor.sync()", 256);
										}
				this.setCanvas		=	function(rootNode){
											var edc = classBehaviours.handlers.richTextEditor;
											// store the container type
											this.containerType = rootNode.nodeName;
											// hide the textarea
											textArea = rootNode.getElementsByTagName('TEXTAREA')[0];
											textArea.id = (textArea.id) ? textArea.id : edc.name + 'Textarea' + this.index;
											textArea.style.display = 'none';
											// show the iframe
											iframe = rootNode.getElementsByTagName('IFRAME')[0];
											iframe.id = (iframe.id) ? iframe.id : edc.name + 'Iframe' + this.index;
											iframe.style.display = 'block';
											// transform the iframe into an editor
											editor = edc.getEditor(iframe.id);
											editor.designMode = 'on';
											// set the initial content
											editor.open();
											editor.write(textArea.value + this.stylesheet);
											editor.close();
											// store the selection when the mouse lifts
											if(editor.selection) editor.onmouseup = this.storeSelect;
										}
				this.setControls	=	function(rootNode){
											// if there's no button bars yet
											toolBars = rootNode.getElementsByTagName('UL');
											if(toolBars.length==2){
												// HTML BUTTON BAR
												// apply the classbehaviours of the button bar
												classBehaviours.parser.parseNode(toolBars[0]);
												// get the buttons
												buttons = toolBars[0].getElementsByTagName('*');
												// for each button in the button bar
												for(var a=0; a<buttons.length; a++){
													// set the event handlers for the edit buttons
													if(buttons[a].className.indexOf('cmd_')>-1){
														if(buttons[a].nodeName=='SELECT') buttons[a].onchange = this.editCommand;
														if(buttons[a].nodeName=='BUTTON') buttons[a].onclick = this.editCommand;
													}
												}
												// show the button bar
												toolBars[0].style.display = 'block';
												
												// TEXT BUTTON BAR
												// apply the classbehaviours of the button bar
												classBehaviours.parser.parseNode(toolBars[1]);
												// get the buttons
												buttons = toolBars[1].getElementsByTagName(this.buttonType);
												// for each button in the button bar and set the event handlers for the edit buttons
												for(var a=0; a<buttons.length; a++)
													if(buttons[a].nodeName=='BUTTON') if(buttons[a].className.indexOf('cmd_')>-1) buttons[a].onclick = this.editCommand;
												// hide the button bar
												toolBars[1].style.display = 'none';
											}
										}
				this.getEditor		=	function(id){
											return (document.getElementById(id).contentDocument) ? 
														document.getElementById(id).contentDocument : 
															document.frames[id].document ;
										}
				this.sync			=	function(){
											var edc = classBehaviours.handlers.richTextEditor;
											// for all instances of this class
											for(var a=0; a<edc.instances.length; a++){
												// get the iframe that may be associated with the editor
												allIframes = edc.instances[a].getElementsByTagName('iframe');
												allTextareas = edc.instances[a].getElementsByTagName('textarea');
												if(allIframes.length>0 && allTextareas.length>0){
													// get the editor from the iframe
													editor = classBehaviours.handlers.richTextEditor.getEditor(allIframes[0].id);
													// if the iframe is replacing the textarea
													if(allTextareas[0].style.display=='none'){
														allTextareas[0].value = editor.documentElement.firstChild.nextSibling.innerHTML.split('<LINK')[0].split('<link')[0];
													// else the textarea will replace the iframe
													}else{
														editor.documentElement.firstChild.nextSibling.innerHTML = allTextareas[0].value + classBehaviours.handlers.richTextEditor.stylesheet;
													}
												}
											}
										}
				this.resize			=	function(container){
												if(!this.resizing){
													// get the editor
													iFrame = container.getElementsByTagName('iframe')[0];
													textArea = container.getElementsByTagName('textarea')[0];
													// what is the mode of the editor
													editor = (textArea.style.display=='none') ? iFrame : textArea;
													// if the editor wasn't marked big
													if(editor.className.indexOf('biggerEditor')<0){
														// mark is as big
														editor.className = 'biggerEditor ' + editor.className;
														// and lock this function
														classBehaviours.handlers.richTextEditor.resizing = true;
														// make the editor twice as big
															// editor.style.height = (editor.offsetHeight * 3) + 'px';
														classBehaviours.fader.grow(editor.id, null, editor.offsetHeight*3, 20, 10, 'classBehaviours.handlers.richTextEditor.resizing=false;');
													//else
													}else{
														// remove it mark
														editor.className = editor.className.replace('biggerEditor', '');
														// and lock this function
														classBehaviours.handlers.richTextEditor.resizing = true;
														// make the editor half as big
															//editor.style.height = Math.round(editor.offsetHeight / 3) + 'px';
														classBehaviours.fader.shrink(editor.id, null, editor.offsetHeight/3, 20, 10, 'classBehaviours.handlers.richTextEditor.resizing=false;');
													}
												}
												// cancel the click
												return false;
											}
				this.closeOption 	=	function(objNode){
											var ecs = classBehaviours.handlers.richTextEditor;
											// find the toggle button
											rootNode = classBehaviours.utilities.rootNode(objNode, 'LI', null, null);
											buttonNode = rootNode.getElementsByTagName(ecs.buttonType)[0];
											// and press it
											if(buttonNode.className.indexOf('toggleNextNode')>-1) buttonNode.onclick(buttonNode);
										}
				// events
				this.storeSelect	=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var ecs = classBehaviours.handlers.richTextEditor;
											// store the selection
											editor = objNode;
											if(editor.selection){
												ecs.bookmark = editor.selection.createRange().getBookmark();
											}
										}
				this.restoreSelect	=	function(editor){
											var ecs = classBehaviours.handlers.richTextEditor;
											// restore the selection
											if(editor.selection){
												if(ecs.bookmark){
													range = editor.documentElement.firstChild.nextSibling.createTextRange();
													range.moveToBookmark(ecs.bookmark);
													range.select();
												}
											}
										}
				this.toggle			=	function(container){
												// get the elements from this editor
												iframes = container.getElementsByTagName('iframe');
												buttonBars = container.getElementsByTagName('ul');
												textareas = container.getElementsByTagName('textarea');
												// if the textearea is invisible
												if(textareas[0].style.display=='none'){
													// hide the button bar
													buttonBars[0].style.display = 'none';
													buttonBars[1].style.display = 'block';
													// hide the iframe
													iframes[0].style.display = 'none';
													// show the textarea
													textareas[0].style.display = 'block';
												}else{
													// show the button bar
													buttonBars[0].style.display = 'block';
													buttonBars[1].style.display = 'none';
													// show the iframe
													iframes[0].style.display = 'block';
													// hide the textarea
													textareas[0].style.display = 'none';
												}
												// cancel the click
												return false;
											}
				this.editCommand		=	function(that){
												var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
												var ecs = classBehaviours.handlers.richTextEditor;
												// get the editor canvas
												container = objNode;
												while(container.nodeName.indexOf(classBehaviours.handlers.richTextEditor.containerType)<0) container = container.parentNode;
												editorId = container.getElementsByTagName('iframe')[0].id;
												editor = ecs.getEditor(editorId);
												// restore the selection if it was lost
												ecs.restoreSelect(editor);
												// get the selected section
												selection = 	(editor.selection) ? editor.selection.createRange().text : 
																	(editor.getSelection) ? editor.getSelection() : 
																		(editor.createRange) ? editor.createRange() : 
																			null ;
												// gather the command parameters
												commandName = classBehaviours.utilities.getClassParameter(objNode, 'cmd', '');
												commandArgument = classBehaviours.utilities.getClassParameter(objNode, 'arg', objNode.value);
												// exceptions
												command = true;
												switch(commandName){
													case 'insertimage' :
														commandArgument = classBehaviours.utilities.previousNode(objNode).value;
														ecs.closeOption(objNode);
														break;
													case 'createlink' :
														commandArgument = classBehaviours.utilities.previousNode(objNode).value;
														ecs.closeOption(objNode);
														break;
													case 'forecolor' :
														ecs.closeOption(objNode);
														break;
													case 'forecolor2' :
														commandArgument = classBehaviours.utilities.previousNode(objNode).value;
														commandName='forecolor';
														ecs.closeOption(objNode);
														break;
													case 'fontname' :
														ecs.closeOption(objNode);
														break;
													case 'fontname2' :
														commandArgument = classBehaviours.utilities.previousNode(objNode).value;
														commandName='fontname';
														ecs.closeOption(objNode);
														break;
													case 'fontsize' :
														ecs.closeOption(objNode);
														break;
													case 'fontsize2' :
														commandArgument = classBehaviours.utilities.previousNode(objNode).value;
														commandName='fontsize';
														ecs.closeOption(objNode);
														break;
													case 'toggle' :
														command = ecs.toggle(container);
														break;
													case 'bigger' :
														command = ecs.resize(container);
														break;
													default : 
														break;
												}
												// execute the command
												if(selection && command) editor.execCommand(commandName, false, commandArgument);
												// cancel the click
												return false;
											}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.richTextEditor = new RichTextEditor;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.richTextEditor;
		
			// Construct an empty stylesheet based on the hierarchy of tags
			function MakeStylesheet(){
				// properties
				this.name 				=	'makeStylesheet';
				this.styleSheet			= 	"\t/* " + document.location.href.split('/')[document.location.href.split('/').length-1] + " */\n";
				this.referenceCss		=	"";
				// methods
				this.start				=	function(node){
												// make a reference stylesheet from the current stylesheets
												this.makeReferenceCss();
												// markup the stylesheet making button
												node.style.position = 'absolute';
												node.style.right = '4px';
												node.style.top = '4px';
												node.onclick = this.showNodeClasses;
												/* how to read stylesheet content
												debug(
													document.styleSheets[0].cssRules[1].selectorText,
													document.styleSheets[0].cssRules[1].cssText,
													document.styleSheets[0].cssRules[1].style.getPropertyValue('font-family')
												);
												*/
											}
				this.makeReferenceCss	=	function(){
												for(var a=0; a<document.styleSheets.length; a++)
													if(document.styleSheets[a].cssRules)
														for(var b=0; b<document.styleSheets[a].cssRules.length; b++)
															this.referenceCss += document.styleSheets[a].cssRules[b].selectorText + ' {}\n\t';
											}
				this.isFormElement		=	function(tagName){
												return (('input,select,textarea,button,INPUT,SELECT,TEXTAREA,BUTTON').indexOf(tagName)>-1);
											}
				this.isClassBehaviours	=	function(newEntry){
												foundHandler = false;
												// for all behaviours, if the behaviour's name exists in the class name, remember it
												if(typeof(newEntry)=='string')
													for(var b=0; b<classBehaviours.handlers.length; b++)
														foundHandler = (newEntry.indexOf(classBehaviours.handlers[b].name)>-1) ? true : foundHandler;
												// report back
												return foundHandler;
											}
				this.isInStylesheet		=	function(newEntry, onlyChanges){
												foundStyle = false;
												// clean the new entry
												newEntry = newEntry.replace(/\t/gi,'').replace(' {}\n','').replace(',','');
												// if the style allready exists in this constructed stylesheet
												foundStyle = (this.styleSheet.indexOf(newEntry)>-1);
												// if the style allready exists in any rule in another stylesheet
												foundStyle = (this.referenceCss.indexOf(newEntry)>-1 && onlyChanges) ? true : foundStyle ;
												// report back
												return foundStyle;
											}
				this.getNodeClasses		=	function(objNode, intRecursion, oldPrefix, onlyChanges, simplified){
												var tagPrefix, idPrefix, classPrefix, newEntry, newSuffix;
												// for every recursion add one tab
												var strTabs = '';
												for(var intB=0; intB<=intRecursion; intB++) strTabs += '\t';
												// for every childnode
												var objChildNodes = objNode.childNodes;
												for(var intA=0; intA<objChildNodes.length; intA++){
													childNode = objChildNodes[intA];
													// reset prefixes
													tagPrefix 		= (childNode.nodeName.indexOf('#')<0) ? childNode.nodeName : '' ;
													idPrefix 		= (childNode.id) ? '#' + childNode.getAttribute('id') : '' ;
													classPrefix 	= (childNode.className) ? '.' + childNode.getAttribute('class') : '' ;
													typePrefix		= '' // (childNode.type) ? childNode.getAttribute('type') : '' ;
													newPrefix 		= '';
													newEntry		= '';
													newSuffix		= '';
													// construct prefixes
													if(tagPrefix!=''){
														tagPrefix 		= childNode.nodeName.toLowerCase();
														idPrefix 		= (!this.isClassBehaviours(idPrefix) && !this.isFormElement(tagPrefix)) ? idPrefix : '' ;
														classPrefix 	= classPrefix.replace(/^\s+|\s+$/g, '').replace(/ /g, '.') ;
														typePrefix		= (typePrefix!='') ? '[type=' + typePrefix + ']' : '' ;
														newPrefix 		= oldPrefix + ' ' + tagPrefix + typePrefix + idPrefix + classPrefix;
														newPrefix 		= (newPrefix.split('#').length>1 && simplified) ? '#' + newPrefix.split('#')[newPrefix.split('#').length-1] : newPrefix ;
														newEntry 		= strTabs + newPrefix + ' {}\n';
														newSuffix 		= (tagPrefix=='a') ? strTabs + newPrefix + ':link,\n' + strTabs + newPrefix + ':visited {}\n' + strTabs + newPrefix + ':hover,\n' + strTabs + newPrefix + ':active {}\n' : '' ;
													}
													// add the new stylesheet entry
													if(!this.isInStylesheet(newEntry, onlyChanges)) this.styleSheet += newEntry + newSuffix;
													// recurse if it this node has childNodes
													if(objChildNodes[intA].childNodes.length>0) this.getNodeClasses(objChildNodes[intA], intRecursion+1, newPrefix, onlyChanges, simplified);
												}
											}
				this.showNodeClasses	=	function(that){
												var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
												var mss = classBehaviours.handlers.makeStylesheet;
												// position it out of the way
												document.body.style.textAlign = 'left';
												document.body.style.background = '#ffffff none';
												document.body.style.color = '#000000';
												document.body.style.fontFamily = 'Sans Serif';
												document.body.style.fontSize = '10pt';
												// are only the changes to the existing stylesheets required?
												onlyChanges = (classBehaviours.utilities.getClassParameter(objNode, 'changesOnly', 'yes')=='yes');
												// is a simplified stylesheet requested
												simplified = (classBehaviours.utilities.getClassParameter(objNode, 'simplified', 'yes')=='yes');
												// get the document root
												documentRoot = (simplified) ? document.body : document ;
												// generate the stylesheet code
												mss.getNodeClasses(documentRoot, 0 , '', onlyChanges, simplified);
												// replace the page with the stylesheet prototype
												document.body.innerHTML = (navigator.userAgent.indexOf('MSIE 6')>-1) ? '<textarea style="width:720px;height:480px;border:solid 1px #000000;">' + mss.styleSheet + '</textarea>' : '<textarea style="position:absolute;left:5%;top:5%;width:90%;height:90%;border:solid 1px #000000;">' + mss.styleSheet + '</textarea>';
											}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.makeStylesheet = new MakeStylesheet;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.makeStylesheet;
			
			// html encode the content of the document
			function HtmlEncode(){
				// properties
				this.name 		= 	'htmlEncode';
				// methods
				this.start		=	function(node){
										// markup the stylesheet making button
										node.style.position = 'absolute';
										node.style.right = '4px';
										node.style.top = '27px';
										node.onclick = this.importDoc;
									}
				// events
				this.importDoc	=	function(){
										// load the document
										classBehaviours.ajax.addRequest(document.location.href, classBehaviours.handlers.htmlEncode.encode, classBehaviours.handlers.htmlEncode.wait, false, null);
									}
				this.wait		=	function(waitStatus){
										
									}
				this.encode		=	function(docXml, referedObj, docTxt){
										// present it back
										document.body.innerHTML = '<textarea id="htmlEncoded" style="position:absolute;left:12.5%;top:12.5%;width:75%;height:75%;border:solid 1px #000000;">' + docTxt + '</textarea>';
										// translate it to blog content
										document.getElementById('htmlEncoded').value = document.getElementById('htmlEncoded').value.replace(/>/gi, '&gt;').replace(/</gi, '&lt;'); // .replace(/\t/gi,'   ');
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.htmlEncode = new HtmlEncode;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.htmlEncode;
			
			// move a link's click event to the parent node
			function ClickOnParent(){
				// properties
				this.name 		= 	'clickOnParent';
				// methods
				this.start		=	function(node){
										// what node is the click supposed to go on?
										parentCount = parseInt(classBehaviours.utilities.getClassParameter(node, "parent", "2"));
										targetNode = node;
										for(var a=0; a<parentCount; a++) targetNode = targetNode.parentNode;
										// get the target of the link
										linkTarget = node.href;
										// set the click event
										targetNode.onclick = this.clicked;
										// set the cursor
										targetNode.style.cursor = 'pointer';
									}
				// events
				this.clicked	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// what is the link
										linkTargets = objNode.getElementsByTagName('A');
										for(var a=0; a<linkTargets.length; a++) if(linkTargets[a].className.indexOf('clickOnParent')>-1) linkTarget = linkTargets[a].href;
										// go to the link
										document.location.href = linkTarget;
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.clickOnParent = new ClickOnParent;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.clickOnParent;
			
			// emulates a scrollbar
			function VirtualScrollbar(){
				// properties
				this.name 		= 	'virtualScrollbar';
				this.interval	=	null;
				// methods
				this.start		=	function(node){
										// set the event handlers for the indicator bar
										node.onmousedown = this.pick;
										node.onmouseup = this.drop;
										node.onmousemove = this.drag;
										node.onmouseout = this.drop;
										document.onmousemove = this.nodrag;
										// set the initial position
										pageId = classBehaviours.utilities.getClassParameter(node, 'id', 'scrollCanvas');
										this.scrollTo(pageId, 0, node);
									}
				this.scrollTo	=	function(id, position, control){
										var vsb = classBehaviours.handlers.virtualScrollbar;
										// normalize the position
										if(position>0) position = 0;
										// what is the scrollable page
										page = document.getElementById(id).getElementsByTagName('div')[0];
										// how high is the page
										pageHeight = page.offsetHeight;
										// how high is the container of the page
										containerHeight = page.parentNode.offsetHeight;
										// don't allow negative scrolling
										if(pageHeight<containerHeight){
											pageHeight = containerHeight;
										}
										// if there's still a distace left to scroll on the bottom shift the page up
										if(navigator.userAgent.indexOf('Safari')>-1){
											page.style.position = 'absolute';
											page.style.top = (position<containerHeight-pageHeight) ? (containerHeight-pageHeight) + 'px' : position + 'px' ;
										}else{
											page.style.marginTop = (position<containerHeight-pageHeight) ? (containerHeight-pageHeight) + 'px' : position + 'px' ;
										}
										// set the position of the indicator
										control.style.backgroundPosition = '0px ' + Math.round(-1.2 * containerHeight * position / pageHeight)  + 'px'
									}
				this.scrollBy	=	function(id, distance, control){
										// what is the scrollable page
										page = document.getElementById(id);
										// how far has the page scrolled up
										if(navigator.userAgent.indexOf('Safari')>-1){
											scrolledHeight = (page.style.top) ? parseInt(page.style.top) : 0 ;
										}else{
											scrolledHeight = (page.style.marginTop) ? parseInt(page.style.marginTop) : 0 ;
										}
										// calculate the new position
										position = scrolledHeight + distance;
										// set the position
										this.scrollTo(id, position);
									}
				// events
				this.pick		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var vsb = classBehaviours.handlers.virtualScrollbar;
										// mark the dragged item as being active
										objNode.className = objNode.className.replace('passive', 'active');
										// initial value
										vsb.drag(objNode);
										// cancel the click
										return false;
									}
				this.drag		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var vsb = classBehaviours.handlers.virtualScrollbar;
										// if the scrollbar is marked as draggable
										if(objNode.className.indexOf('active')>-1){
											// get the click position
											mouseX = (typeof(event)!='undefined') ? event.x : that.layerX ;
											mouseY = (typeof(event)!='undefined') ? event.y : that.layerY ;
											// get the page dimensions
											id = classBehaviours.utilities.getClassParameter(objNode, 'id', 'scrollCanvas');
											page = document.getElementById(id).getElementsByTagName('div')[0];
											// how high is the page
											pageHeight = page.offsetHeight;
											// how high is the container of the page
											containerHeight = page.parentNode.offsetHeight;
											// corelate the mouse-position to the scroll-position
											position = Math.round(-1 * mouseY * (pageHeight-containerHeight) / containerHeight);
											position = position * 1.2 + containerHeight * 0.2;
											// pass the position on to the page
											vsb.scrollTo(id, position, objNode);
										}
										// cancel the click
										return false;
									}
				this.nodrag	=	function(){
										return false;
									}
				this.drop		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var vsb = classBehaviours.handlers.virtualScrollbar;
										// mark the dragged item as being passive
										objNode.className = objNode.className.replace('active', 'passive');
										// cancel the click
										return false;
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.virtualScrollbar = new VirtualScrollbar;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.virtualScrollbar;
		
			// constants/configuration
			function RssSearch(){
				// properties
				this.name 		= 	'rssSearch';
				this.form		=	null;
				this.url 		= 	null;
				this.input 		= 	null;
				this.output 	= 	null;
				this.startIndex	=	0;
				this.endIndex	=	8;
				/* objects */
				this.search		=	new Search;
				this.source		=	new Source;
				// methods
				this.start		=	function(node){
										node.onsubmit = this.doSubmit;
										// get the default values
										this.form		=	document.getElementById('searchform');
										this.url 		= 	document.getElementById('searchsource');
										this.input 		= 	document.getElementById('searchstring');
										this.output 	= 	document.getElementById('searchresults');
									}
				this.find		=	function(start, end){
										// store paging preferences
										if(start!=null) this.startIndex = start;
										if(end!=null) 	this.endIndex = end;
										// lead the source to search
										if(this.source.document==null){
											this.source.load(this.url.value);
										}else{
											// search query
											var query					= this.search.query(this.input.value);
											// search process
											var results					= this.search.results(query, this.source.document);
											// search results
											var summary					= this.search.summary(results, this.startIndex, this.endIndex);
											// write the search summary
											this.output.innerHTML		= summary;
										}
										// cancel the submit
										return false;
									}
				// events
				this.doSubmit	=	function(){
										return classBehaviours.handlers.rssSearch.find();
									}
			}
				function Search(){
					this.sort		=	function(a, b){
											// sort by the first index of the object
											return (isNaN(a[0]) || isNaN(b[0])) ? 0 : b[0]-a[0] ;
										}
					this.query		=	function(searchString){
											// formulate the search string into a regular expression
											return new RegExp(searchString.replace(" ","|"),"gi");
										}
					this.results	=	function(query, doc, docText){
											var contents, titles, descs, text, matchText, matchScore;
											var results = new Array();
											// get all items in the rss feed
											contents = doc.getElementsByTagName('item');
											// for every item
											for(var a=0; a<contents.length; a++){
												// get the nodes
												titles	= contents[a].getElementsByTagName('title');
												descs	= contents[a].getElementsByTagName('description');
												// get the text from the nodes
												text = '';
												if(titles.length>0)		text += titles[0].firstChild.nodeValue;
												if(descs.length>0)		text += descs[0].firstChild.nodeValue;
												// match the query with the item's text
												matchText = text.match(query);
												// if there were hits
												if(matchText!=null){
													// calculate the score (the joined length of the matched array)
													matchScore = matchText.join(' ').length;
													// add the score and the node to the list of search results
													results[results.length] = new Array(matchScore,contents[a]);
												}
											}
											// sort the list of search results
											results = results.sort(this.sort);
											// pass the results back
											return results;
										}
					this.summary	=	function(results, startPage, resultsPerPage){
											var report = '<dl class="items">';
											var links, titles, summaries;
											var link, title, summary;
											// for the selected search results
											var a = startPage * resultsPerPage;
											while(a<results.length && (a+1)%resultsPerPage!=0){
												// link
												links			= results[a][1].getElementsByTagName('link')
												link			= (links.length==0) ? '' : links[0].firstChild.nodeValue;
												// title
												titles			= results[a][1].getElementsByTagName('title')
												title			= (titles.length==0) ? '' : titles[0].firstChild.nodeValue;
												// author
												authors			= results[a][1].getElementsByTagName('author')
												author			= (authors.length>0) ? authors[0].firstChild.nodeValue : '' ;
												// category
												categories		= results[a][1].getElementsByTagName('category')
												category		= (categories.length>0) ? categories[0].firstChild.nodeValue : '' ;
												// pubDate
												pubDates		= results[a][1].getElementsByTagName('pubDate')
												pubDate			= (pubDates.length>0) ? pubDates[0].firstChild.nodeValue.replace(':00 +0100', '') : '' ;
												// part of the description
												summaries		= results[a][1].getElementsByTagName('description')
												if(summaries.length>0){
													summary			= (summaries[0].xml) ? summaries[0].xml : summaries[0].firstChild.nodeValue;
													summary			= summary.replace(/</gi, '<').replace(/>/gi, '>').replace(/<(.|\n)+?>/gi,'');
													summary			= (summaries[0].xml) ? summary.substr(0,64) + '...' : summary.substr(0,128) + '...';
												}else{
													summary			= '';
												}
												// construct report
												report			+= '<dt class="title"><a href="'+link+'">'+title+'</a></dt>\n';
												report			+= '<dd>\n';
												report			+= '	<ul class="information">\n';
												report			+= '		<li class="author">' + author + '</li>\n';
												report			+= '		<li class="category">' + category + '</li>\n';
												report			+= '		<li class="pubDate">' + pubDate + '</li>\n';
												report			+= '	</ul>\n';
												report			+= '	<div class="description"><p>'+summary+'</p></div>\n';
												report			+= '</dd>\n';
												// next item
												a += 1;
											}
											report += '</dl>';
											// if nothing was found
											if(results.length==0){
												// apologize
												report			+= '<p class="error">Sorry, no matches were found</p>';
											// else
											}else{
												var minPages	= 0;
												var maxPages	= Math.round(results.length/resultsPerPage+0.49);
												// page x of n
												report			+= '<ul class="pager">\n';
												report			+= (startPage>minPages) ? '<li class="previous"><a href="#" onclick="return classBehaviours.handlers.rssSearch.find('+(startPage-1)+','+resultsPerPage+')">Previous</a></li>' : '<li class="previous"></li>' ;
												report			+= (startPage<maxPages-1) ? '<li class="next"><a href="#" onclick="return classBehaviours.handlers.rssSearch.find('+(startPage+1)+','+resultsPerPage+')">Next</a></li>' : '<li class="next"></li>' ;
												report			+= '<li class="count">Page '+(startPage+1)+' of '+maxPages + '</li>';
												report			+= '</ul>\n';
											}
											// return the search results
											return report;
										}
				}
				function Source(){
					this.document	=	null;
					this.load		=	function(url){
											classBehaviours.ajax.addRequest(url, classBehaviours.handlers.rssSearch.source.onload, classBehaviours.handlers.rssSearch.source.wait);
										}
					this.wait		=	function(status){
											if(status<0){
												classBehaviours.handlers.rssSearch.output.innerHTML = '<hr /><p>Something went wrong.</p>'
											}else{
												classBehaviours.handlers.rssSearch.output.innerHTML = '<hr /><p>Searching: ' + Math.round(status * 100) + '%</p>';
											}
										}
					this.onload	=	function(root){
											classBehaviours.handlers.rssSearch.source.document = root;
											classBehaviours.handlers.rssSearch.find();
										}
				}
			// add this function to the classbehaviour object
			classBehaviours.handlers.rssSearch = new RssSearch;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.rssSearch;
			
			// displays and updates the nodes of a chat window
			function RssChat(){
				// properties
				this.name 		= 	'rssChat';
				this.index		=	0;
				this.timeout	=	null;
				this.delay		=	4096;
				// methods
				this.start		=	function(node){
										// give the node an id if it doesn't have one
										node.id = (node.id) ? node.id : this.name + this.index++ ;
										// set the button event
										node.getElementsByTagName('button')[0].onclick = this.send;
										// load the feed
										rssUrl = node.getElementsByTagName('input')[0].value;
										rssRnd = '&upd=' + new Date().getTime();
										classBehaviours.ajax.addRequest(rssUrl+rssRnd, this.update, this.wait, null, node.id);
									}
				this.wait		=	function(progress, nodeId, error){
										var node = document.getElementById(nodeId);
										progressNode = node.getElementsByTagName('div')[0];
										progressNode.style.backgroundPosition = (progress<0) ? '0% 100%' : (100-progress*100) +'% 0%' ;
										progressNode.innerHTML = (progress<0) ? 'error: ' + error : Math.round(progress*100) + '% updated' ;
									}
				this.update		=	function(xml, nodeId, txt){
										var node = document.getElementById(nodeId);
										// clear any pending timeout
										clearTimeout(classBehaviours.handlers.rssChat.timeout);
										// update the chat title
										rssHeader = node.getElementsByTagName('h3');
										if(rssHeader.length>0) rssHeader[0].innerHTML = xml.getElementsByTagName('title')[0].firstChild.nodeValue;
										// clear all previous items except the protoype
										previousDts = node.getElementsByTagName('dt');
										previousDds = node.getElementsByTagName('dd');
										for(var a=previousDts.length-1; a>0; a--){
											removedDd = previousDds[a].parentNode.removeChild(previousDds[a]);
											removedDt = previousDts[a].parentNode.removeChild(previousDts[a]);
										}
										// for all chat items
										allItems = xml.getElementsByTagName('item');
										listNode = node.getElementsByTagName('dl')[0];
										for(var a=0; a<allItems.length; a++){
											// get the item properties
											itemAuthor = (allItems[a].getElementsByTagName('author')[0].childNodes.length>0) ? allItems[a].getElementsByTagName('author')[0].firstChild.nodeValue : '' ;
											itemPubDate = (allItems[a].getElementsByTagName('pubDate')[0].childNodes.length>0) ? allItems[a].getElementsByTagName('pubDate')[0].firstChild.nodeValue : '' ;
											itemCategory = (allItems[a].getElementsByTagName('category')[0].childNodes.length>0) ? allItems[a].getElementsByTagName('category')[0].firstChild.nodeValue : '' ;
											itemLink = (allItems[a].getElementsByTagName('link')[0].childNodes.length>0) ? allItems[a].getElementsByTagName('link')[0].firstChild.nodeValue : '' ;
											itemTitle = (allItems[a].getElementsByTagName('title')[0].childNodes.length>0) ? allItems[a].getElementsByTagName('title')[0].firstChild.nodeValue : '' ;
											itemDescription = (allItems[a].getElementsByTagName('description')[0].childNodes.length>0) ? allItems[a].getElementsByTagName('description')[0].firstChild.nodeValue : '' ;
											// format the date
											itemPubDate = (new Date(itemPubDate)).toLocaleString();
											// clone the prototype node
											clonedDt = node.getElementsByTagName('dt')[0].cloneNode(true);
											clonedDd = node.getElementsByTagName('dd')[0].cloneNode(true);
											// modify its contents
											clonedDt.className = clonedDt.className.replace('prototype', '');
											clonedDt.innerHTML = clonedDt.innerHTML.replace(/{author}/gi, itemAuthor).replace(/{pubDate}/gi, itemPubDate).replace(/{category}/gi, itemCategory).replace(/{link}/gi, itemLink).replace(/{title}/gi, itemTitle);
											clonedDd.className = clonedDd.className.replace('prototype', '');
											clonedDd.firstChild.nodeValue = itemDescription;
											// insert it at the top
											listNode.appendChild(clonedDt);
											listNode.appendChild(clonedDd);
										}
										// set the scroll position to the bottom
										listNode.scrollTop = listNode.scrollHeight + 1000;
										// order another update
										rssUrl = node.getElementsByTagName('input')[0].value;
										rssRnd = '&upd=' + '?upd=' + new Date().getTime();
										classBehaviours.handlers.rssChat.timeout = setTimeout('classBehaviours.ajax.addRequest("'+rssUrl+rssRnd+'", classBehaviours.handlers.rssChat.update, classBehaviours.handlers.rssChat.wait, null, "'+nodeId+'")', classBehaviours.handlers.rssChat.delay);
									}
				// events
				this.send		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var rsc = classBehaviours.handlers.rssChat
										// find the root node
										rootNode = classBehaviours.utilities.rootNode(objNode, null, null, rsc.name);
										// get the submitted values
										itemAuthor = rootNode.getElementsByTagName('input')[1].value.replace(';', ':');
										itemPubDate = (new Date()).toUTCString();
										itemCategory = "replies";
										itemLink = document.location.href;
										itemTitle = document.title;
										itemDescription = rootNode.getElementsByTagName('textarea')[0].value;
										// construct the post
										rssPost = "&root=channel&parent=item&indexa=-1&valuesa=author;" + itemAuthor + ";pubDate;" + itemPubDate + ";category;" + itemCategory + ";title;" + itemTitle + ";description;" + itemDescription;
										// make the http request
										rssUrl = rootNode.getElementsByTagName('input')[0].value;
										rssRnd = '&upd=' + '?upd=' + new Date().getTime();
										classBehaviours.ajax.addRequest(rssUrl+rssRnd+rssPost, rsc.update, rsc.wait, null, rootNode.id);
										// clear the textarea
										rootNode.getElementsByTagName('textarea')[0].value = '';
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.rssChat = new RssChat;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.rssChat;
			
			// edit the order of items in select lists
			function ManyToMany(){
				// properties
				this.name 		= 	'manyToMany';
				// methods
				this.start		=	function(node){
										// was the click aimed at the select list
										if(node.nodeName=='SELECT'){
											node.className += ' from_' + node.id;
											node.ondblclick = this.clicked;
										}else{
											node.onclick = this.clicked;
										}
									}
				// events
				this.resetEdit   =	function(id){
				                        textArea = document.getElementById(id.replace('$', ''));
				                        if (textArea.type != 'textarea') return;
				                        selectArea = document.getElementById(id);
				                        textArea.value = '';
				                        for(i = 0; i < selectArea.length; i++)
				                            textArea.value += selectArea.options[i].value + '|' + selectArea.options[i].text + '\n';
				                    }
				this.clicked	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// button settings
										moveSourceId = classBehaviours.utilities.getClassParameter(objNode, 'from', null);
										moveDestinationId = classBehaviours.utilities.getClassParameter(objNode, 'to', null);
										upSourceId = classBehaviours.utilities.getClassParameter(objNode, 'up', null);
										downSourceId = classBehaviours.utilities.getClassParameter(objNode, 'down', null);
										// get the parent nodes
										moveSource = document.getElementById(moveSourceId);
										upSource = document.getElementById(upSourceId);
										downSource = document.getElementById(downSourceId);
										moveDestination = document.getElementById(moveDestinationId);
										// if we're going to move a node
										if(moveSource && moveDestination){
											// get the source node
											sourceNode = (moveSource.selectedIndex>-1) ? moveSource.getElementsByTagName('option')[moveSource.selectedIndex] : null;
											// get the target node
											destinationNode = (moveDestination.selectedIndex>-1) ? moveDestination.getElementsByTagName('option')[moveDestination.selectedIndex] : null;
											// if there is a source node
											if(sourceNode){
												// remove the source node
												removedNode = moveSource.removeChild(sourceNode);
												// insert the source node before the desination node 
												if(destinationNode){
													moveDestination.insertBefore(removedNode, destinationNode.nextSibling);
												}else{
													moveDestination.appendChild(removedNode);
												}
											}
										}
										// if we're going to shift a node up
										if(upSource){
											// get the source node
											upNodes = upSource.getElementsByTagName('option');
											sourceNode = (upSource.selectedIndex>-1) ? upNodes[upSource.selectedIndex] : null;
											destinationNode = (upSource.selectedIndex>0) ? upNodes[upSource.selectedIndex-1] : null ;
											if(sourceNode && destinationNode){
												// remove the source node
												removedNode = upSource.removeChild(sourceNode);
												// insert it at its new place
												upSource.insertBefore(removedNode, destinationNode);
											}
											classBehaviours.handlers.manyToMany.resetEdit(upSource.id);
										}
										// if we're going to shift a node down
										if(downSource){
											// get the source node
											downNodes = downSource.getElementsByTagName('option');
											sourceNode = (downSource.selectedIndex>-1) ? downNodes[downSource.selectedIndex] : null;
											destinationNode = (downSource.selectedIndex<downNodes.length-2) ? downNodes[downSource.selectedIndex+2] : null ;
											if(sourceNode && destinationNode){
												// remove the source node
												removedNode = downSource.removeChild(sourceNode);
												// insert it at its new place
												downSource.insertBefore(removedNode, destinationNode);
											}else if(sourceNode){
												// remove the source node
												removedNode = downSource.removeChild(sourceNode);
												// insert it at its new place
												downSource.appendChild(removedNode);
											}
											classBehaviours.handlers.manyToMany.resetEdit(downSource.id);
										}
										return false;
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.manyToMany = new ManyToMany;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.manyToMany;
					
			// Sort table rows by dragging and dropping
			function DragToSort(){
				// properties
				this.name 			= 	'dragToSort';
				this.moving			=	null;
				this.over			=	null;
				this.offsetX		=	-50;
				this.offsetY		=	1;
				this.timeout		=	null;
				this.allowed		=	true;
				// methods
				this.start			=	function(node){
											// set the offset
											this.offsetX = parseInt(classBehaviours.utilities.getClassParameter(node,'offx', this.offsetX));
											this.offsetY = parseInt(classBehaviours.utilities.getClassParameter(node,'offy', this.offsetY));
											// apply the event handlers to all table rows
											allRows = node.getElementsByTagName('tr');
											for(var a=0; a<allRows.length; a++){
												// drag event handler
												if(allRows[a].parentNode.nodeName=='TBODY') allRows[a].onmousedown = this.pickUp;
												allRows[a].onmouseover = this.trackOver;
												allRows[a].onmouseout = this.trackOut;
												// add the undragged classname
												allRows[a].className += ' notDragged';
											}
											// for all buttons and input  fields in the table
											allInputs = node.getElementsByTagName('input');
											allButtons = node.getElementsByTagName('button');
											allLinks = node.getElementsByTagName('a');
											allSelects = node.getElementsByTagName('selects');
											// set a mouseover that disbles the pickup events
											for(var a=0; a<allInputs.length; a++){	allInputs[a].onmouseover = this.disallow; 	allInputs[a].onmouseout = this.allow;}
											for(var a=0; a<allButtons.length; a++){	allButtons[a].onmouseover = this.disallow; 	allButtons[a].onmouseout = this.allow;}
											for(var a=0; a<allLinks.length; a++){	allLinks[a].onmouseover = this.disallow; 		allLinks[a].onmouseout = this.allow;}
											for(var a=0; a<allSelects.length; a++){	allSelects[a].onmouseover = this.disallow; 	allSelects[a].onmouseout = this.allow;}
											// apply the move events
											document.onmousemove = this.moveAround;
											document.onmouseup = this.dropDown;
											// when dragged off-canvas
											document.onmouseout = this.wait;
										}
				this.disallow		=	function(){
											var dts = classBehaviours.handlers.dragToSort;
											dts.allowed = false;
										}
				this.allow			=	function(){
											var dts = classBehaviours.handlers.dragToSort;
											dts.allowed = true;
										}
				this.dropDown		=	function(){
											var dts = classBehaviours.handlers.dragToSort;
											// if there is an element being dragged
											if(dts.moving){
												// clear the remembered node
												dts.moving.style.position = 'static';
												dts.moving.style.left = 'auto' ;
												dts.moving.style.top = 'auto' ;
												// swap the nodes
												if(dts.over && dts.moving!=dts.over){
													// remove the dragged row
													storedNode = dts.moving.parentNode.removeChild(dts.moving);
													// insert it before the target row
													dts.over.parentNode.insertBefore(storedNode, dts.over);
													// redo the odd and even classes
													dts.reZebra(dts.over);
													// re-apply the classbehaviours
													classBehaviours.parser.parseNode(classBehaviours.utilities.previousNode(dts.over));
												}
												// clear the sources
												dts.moving = null;
												dts.over = null;
											}
											// cancel the mouse event
											return false;
										}
				this.reZebra		=	function(tableRow){
											// get all the siblings to this row
											allRows = tableRow.parentNode.getElementsByTagName('TR');
											for(var a=0; a<allRows.length; a++){
												allRows[a].className = (a%2==0) ? allRows[a].className.replace('even', 'odd') : allRows[a].className.replace('odd', 'even');
											}
										}
				// events
				this.trackOver		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var dts = classBehaviours.handlers.dragToSort;
											// if we are over the table
											if(objNode.parentNode.nodeName=='TBODY'){
												// store the last node the mouse went over
												if(objNode!=dts.moving) dts.over = objNode;
												// highlight the row something is dragged over
												if(dts.moving!=null) objNode.className = objNode.className.replace('notDragged', 'isDraggedOver');
											}
										}
				this.trackOut		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var dts = classBehaviours.handlers.dragToSort;
											// highlight the row something is dragged over
											if(objNode!=dts.moving) objNode.className = objNode.className.replace('isDraggedOver', 'notDragged');
										}	
				this.pickUp			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var dts = classBehaviours.handlers.dragToSort;
											// is the mechanism disabled
											if(dts.allowed){
												// store the picked up object
												dts.moving = objNode;
												// get the mouse position
												scrollX = (document.documentElement.scrollLeft) ? document.documentElement.scrollLeft : document.body.scrollLeft;
												scrollY = (document.documentElement.scrollTop) ? document.documentElement.scrollTop : document.body.scrollTop;
												xPos = (typeof(event)!='undefined') ? event.clientX+scrollX : that.pageX ;
												yPos = (typeof(event)!='undefined') ? event.clientY+scrollY : that.pageY ;
												// pick up the table row
												dts.moving.style.position = 'absolute';
												dts.moving.style.left = (xPos+dts.offsetX) + 'px' ;
												dts.moving.style.top = (yPos+dts.offsetY) + 'px' ;
												// cancel the mouse event
												return false;
											}
										}
				this.moveAround		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var dts = classBehaviours.handlers.dragToSort;
											// cancel the close timeout
											clearTimeout(dts.timeout);
											// if there is an object being dragged
											if(dts.moving){
												// get the mouse position
												scrollX = (document.documentElement.scrollLeft) ? document.documentElement.scrollLeft : document.body.scrollLeft;
												scrollY = (document.documentElement.scrollTop) ? document.documentElement.scrollTop : document.body.scrollTop;
												xPos = (typeof(event)!='undefined') ? event.clientX+scrollX : that.pageX ;
												yPos = (typeof(event)!='undefined') ? event.clientY+scrollY : that.pageY ;
												// move the stored node around with the mouse
												dts.moving.style.position = 'absolute';
												dts.moving.style.left = (xPos+dts.offsetX) + 'px' ;
												dts.moving.style.top = (yPos+dts.offsetY) + 'px' ;
											}
											// cancel the mouse event
											return false;
										}
				this.wait			=	function(){
											var dts = classBehaviours.handlers.dragToSort;
											// set a timeout for resetting the system
											clearTimeout(dts.timeout);
											dts.timeout = setTimeout('classBehaviours.handlers.dragToSort.dropDown()', 250);
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.dragToSort = new DragToSort;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.dragToSort;
			
			// Sort table rows by clicking and dropping
			function ClickToSort(){
				// properties
				this.name 			= 	'clickToSort';
				// methods
				this.start			=	function(node){
											// get the prototype of the arrows
											indicatorArrows = node.getElementsByTagName('span')[0];
											// get the tbody
											theTbody = node.getElementsByTagName('tbody')[0];
											theTbody.className += ' hideIndicators';
											// for all table rows
											allRows = theTbody.getElementsByTagName('tr');
											for(var a=0; a<allRows.length; a++){
												// add a default class
												allRows[a].className += ' link';
												// set its event handlers
												if(navigator.appVersion.indexOf('MSIE 6')>-1){
													allRows[a].onmouseover = this.hoverOver;
													allRows[a].onmouseout = this.hoverOut;
												}
												allRows[a].onclick = this.selectRow;
												// get the first cell you can find
												firstCell = allRows[a].getElementsByTagName('td')[0];
												// clone in the prototype into the cell
												clonedArrows = indicatorArrows.cloneNode(true);
												firstCell.insertBefore(clonedArrows, firstCell.firstChild);
											}
										}
				this.reZebra		=	function(tableRow){
											// get all the siblings to this row
											allRows = tableRow.parentNode.getElementsByTagName('tr');
											for(var a=0; a<allRows.length; a++){
												allRows[a].className = (a%2==0) ? allRows[a].className.replace('even', 'odd') : allRows[a].className.replace('odd', 'even');
											}
										}
				// events
				this.hoverOver		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											objNode.className = objNode.className.replace('link', 'hover');
										}
				this.hoverOut		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											objNode.className = objNode.className.replace('hover', 'link');
										}
				this.selectRow		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var cts = classBehaviours.handlers.clickToSort;
											// get the tbody
											theTbody = objNode.parentNode;
											// if the tbody in hideIndicators mode
											if(theTbody.className.indexOf('hideIndicators')>-1){
												// mark the row as selected
												objNode.className = objNode.className.replace('link', 'active').replace('hover', 'active');
												// activate the indicator arrows
												theTbody.className = theTbody.className.replace('hideIndicators', 'showIndicators');
											// else
											}else{
												// de-activate the indicator arrows
												theTbody.className = theTbody.className.replace('showIndicators', 'hideIndicators');
												// for all rows in there
												theActiveRow = null;
												allRows = theTbody.getElementsByTagName('tr');
												for(var a=0; a<allRows.length; a++){
													// if the row is active
													if(allRows[a].className.indexOf('active')>-1){
														// store it as the source row 
														theActiveRow = allRows[a];
														// remove the active mark
														allRows[a].className = allRows[a].className.replace('active', 'link');
													}
												}
												// switch the source with the target node
												if(theActiveRow!=objNode){
													removedNode = theTbody.removeChild(theActiveRow);
													theTbody.insertBefore(removedNode, objNode);
												}
												// re-zebra
												cts.reZebra(objNode);
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.clickToSort = new ClickToSort;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.clickToSort;
			
			// Link two select lists
			function LinkedSelects(){
				// properties
				this.name 			= 	'linkedSelects';
				// methods
				this.start			=	function(node){
											// get the mouse position
											node.onchange = this.updateLinked;
											// sync the starting selection
											setTimeout('classBehaviours.handlers.linkedSelects.updateLinked(document.getElementById("' + node.id + '"))',100);
										}
				// events
				this.updateLinked	=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var lsl = classBehaviours.handlers.linkedSelects;
											// if there was a selected value
											if(objNode.value!=''){
												// get the target id
												linkedId = classBehaviours.utilities.getClassParameter(objNode, 'id', 'myLinkedSelect');
												// get the target object
												linkedObj = document.getElementById(linkedId);
												// start loading
												classBehaviours.ajax.addRequest(objNode.value, lsl.updateLoaded, lsl.updateProgress, null, linkedObj);
											}
										}
				this.updateProgress	=	function(progressStatus, referingObj){
											// get the first option in the select
											firstOption = referingObj.getElementsByTagName('option')[0];
											firstOption.selected = true;
											// use it as a progress indicator
											firstOption.firstChild.nodeValue = '--- loading: ' + parseInt(progressStatus*100) + '% ---';
										}
				this.updateLoaded	=	function(docXml, refererObj, docTxt){
											// for all the current options
											currentOptions = refererObj.getElementsByTagName('option');
											for(var a=currentOptions.length-1; a>=0; a--){
												removedNode = refererObj.removeChild(currentOptions[a]);
											}
											// for all the imported options
											importedOptions = docXml.getElementsByTagName('option');
											for(var a=0; a<importedOptions.length; a++){
												// replace the option contents
												newOption = document.createElement('option');
												newOptionText = document.createTextNode(importedOptions[a].firstChild.nodeValue);
												newOption.appendChild(newOptionText);
												newOption.value = importedOptions[a].getAttribute("value");
												refererObj.appendChild(newOption);
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.linkedSelects = new LinkedSelects;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.linkedSelects;
			
			// Resize an iframe to accomodate the contents
			function AutoSizeIframe(){
				// properties
				this.name 			= 	'autoSizeIframe';
				// methods
				this.start			=	function(node){
											// set the onload event of the frame
											node.onload = this.resize;
											this.resize();
										}
				// events
				this.resize			=	function(){
											var asi = classBehaviours.handlers.autoSizeIframe;
											// if the frame is loaded, resize all iframes of this class
											allIframes = document.getElementsByTagName('iframe');
											for(var a=0; a<allIframes.length; a++){
												if(allIframes[a].className.indexOf(asi.name)>-1){
													if(window.frames[allIframes[a].name].document.getElementsByTagName('body').length>0){
														if(window.frames[allIframes[a].name].document.getElementsByTagName('body')[0].offsetHeight>0){
															document.getElementById(allIframes[a].id).style.height = (window.frames[allIframes[a].name].document.getElementsByTagName('body')[0].offsetHeight) + 'px';
														}
													}
												}
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.autoSizeIframe = new AutoSizeIframe;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.autoSizeIframe;
			
			// Resize the iframe FROM the iframe
			function AutoSizeFromIframe(){
				// properties
				this.name 			= 	'autoSizeFromIframe';
				// methods
				this.start			=	function(node){
											// set the onload event of the frame
											parent.classBehaviours.handlers.autoSizeIframe.resize();
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.autoSizeFromIframe = new AutoSizeFromIframe;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.autoSizeFromIframe;
			
			// Fetch the links from a list of portfolio templates
			function PortfolioList(){
				// properties
				this.name 			= 	'portfolioList';
				// methods
				this.start			=	function(node){
											// set the onclick event of the button
											allLinks = node.getElementsByTagName('a');
											for(var a=0; a<allLinks.length; a++) allLinks[a].onclick = this.clickItem;
										}
				this.waitForList	=	function(loadStatus, referedNode){
											// update the progress indicator
											referedNode.getElementsByTagName('div')[0].innerHTML = (loadStatus<0) ? '<h1>loading: failed</h1><p>Please try another.</p>' : '<h1>loading: ' + (loadStatus*100) + '%</h1>';
										}
				this.insertTheList	=	function(xmlObj, referedNode, xmlText){
											// if this page is an index list
											sourceUrl = classBehaviours.utilities.previousNode(referedNode).href;
											if(xmlText.indexOf('templates index')>-1 && xmlText.indexOf('<body>')>-1){
												// process the html to add a window opener
												sourceBaseUrl = sourceUrl.replace('/index.html', '');
												importedHtml = xmlText.split('<body>')[1].split('</body>')[0].replace(/href="./gi, 'target="_blank" href="' + sourceBaseUrl);
												// paste the html in place of the progress indicator
												referedNode.getElementsByTagName('div')[0].innerHTML = importedHtml;
											// else open the link normally
											}else{
												document.location.href = classBehaviours.utilities.previousNode(referedNode).href;
											}
										}
				// events
				this.clickItem		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var pfl = classBehaviours.handlers.portfolioList;
											// if the list has not been filled earlier
											if(classBehaviours.utilities.nextNode(objNode)==objNode){
												// construct the list holder
												newDiv = document.createElement('div');
												newDiv.className = 'popUp hideThisNode';
												newBorder = document.createElement('div');
												newBorder.className = 'popUpBorder';
												newTitle = document.createElement('h1');
												newText = document.createTextNode('loading...');
												// show the list holder with a progress indicator
												newTitle.appendChild(newText);
												newBorder.appendChild(newTitle);
												newDiv.appendChild(newBorder);
												objNode.parentNode.appendChild(newDiv);
												// start the loading
												classBehaviours.ajax.addRequest(objNode.href, pfl.insertTheList, pfl.waitForList, null, classBehaviours.utilities.nextNode(objNode));
												// prepare the item for toggleNextNode
												objNode.className += 'toggleNextNode family_portfolio0';
												classBehaviours.handlers.toggleNextNode.start(objNode);
												classBehaviours.handlers.toggleNextNode.toggle(objNode);
											// else
											}else{
												// toggle the list item
												classBehaviours.handlers.toggleNextNode.toggle(objNode);
											}
											// cancel the click
											return false;
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.portfolioList = new PortfolioList;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.portfolioList;
			
			// Manages an artificial scroll bar
			function ArtificialScrollBar(){
				// properties
				this.name 			= 	'artificialScrollBar';
				this.interaction	=	false;
				this.interactor		=	null;
				this.scrollInterval	=	null;
				this.index			=	0;
				// methods
				this.start			=	function(node){
											// give the scrollbar an id if it doesn't have one
											node.id = (node.id) ? node.id : this.name + this.index++ ;
											// get the objects inside
											allDivs = node.getElementsByTagName('DIV');
											// disable the normal scrollbar
											node.style.overflow = 'hidden';
											// show the artificial scrollbar
											allDivs[allDivs.length-5].style.display = 'block';
											// set the canvas event handlers
											node.onmouseover = this.overCanvas;
											node.onmouseout = this.offCanvas;
											// set the detector events
											allDivs[allDivs.length-1].onmousedown = this.onDown;
											allDivs[allDivs.length-1].onmousemove = this.onDrag;
											allDivs[allDivs.length-1].ondrag = this.onDrag;
											document.onmouseup = this.onUp;
											node.onmousewheel = this.onWheel;
											if(window.addEventListener) window.addEventListener('DOMMouseScroll', this.onWheel, false);
											// set the button event handlers
											allDivs[allDivs.length-3].onmousedown = this.buttonDown;
											allDivs[allDivs.length-3].onmouseup = this.buttonOff;
											allDivs[allDivs.length-3].onmouseout = this.buttonOff;
											allDivs[allDivs.length-4].onmousedown = this.buttonUp;
											allDivs[allDivs.length-4].onmouseup = this.buttonOff;
											allDivs[allDivs.length-4].onmouseout = this.buttonOff;
											// start position
											setTimeout('classBehaviours.handlers.artificialScrollBar.moveTo(document.getElementById("'+node.id+'"), 0)', 100);
										}
				this.resize			=	function(rootNode){
											// get the required objects
											allDivs = rootNode.getElementsByTagName('DIV');
											contentNode = allDivs[0];
											indicatorNode = allDivs[allDivs.length-2];
										}
				this.moveTo			=	function(rootNode, position){
											// get the required objects
											allDivs = rootNode.getElementsByTagName('DIV');
											contentNode = allDivs[0];
											indicatorNode = allDivs[allDivs.length-2];
											// size the indicator
											contentToWindowRatio = contentNode.parentNode.offsetHeight / contentNode.offsetHeight;
											scrollBarHeight = indicatorNode.parentNode.offsetHeight;
											indicatorSize = contentToWindowRatio * scrollBarHeight;
											if(!isNaN(indicatorSize)) indicatorNode.style.height = Math.round(indicatorSize) + 'px';
											// if the page is longer than the canvas
											if(contentToWindowRatio<1){
												// set the indicator position
												indicatorSurplus = indicatorSize / 2;
												indicatorPosition = position - indicatorSurplus;
												if(position < indicatorSurplus) indicatorPosition = 0;
												if(indicatorPosition > scrollBarHeight-indicatorSize) indicatorPosition = scrollBarHeight-indicatorSize;
												if(!isNaN(indicatorPosition)) indicatorNode.style.top = Math.round(indicatorPosition) + 'px';
												// set the content position
												scrollBarFraction = (position - indicatorSurplus) / (scrollBarHeight - indicatorSurplus * 2);
												contentOverlap = contentNode.offsetHeight - contentNode.parentNode.offsetHeight;
												contentPosition = scrollBarFraction * contentOverlap;
												if(contentPosition<0) contentPosition = 0;
												if(contentPosition>contentOverlap) contentPosition = contentOverlap;
												if(!isNaN(contentPosition)) contentNode.style.top = Math.round(0 - contentPosition) + "px";
											}
										}
				this.moveBy			=	function(rootNode, distance){
											if(rootNode){
												// get the required objects
												allDivs = rootNode.getElementsByTagName('DIV');
												contentNode = allDivs[0];
												indicatorNode = allDivs[allDivs.length-2];
												// get the current scroll position
												indicatorPosition = (indicatorNode.style.top) ? parseInt(indicatorNode.style.top) : 0 ;
												indicatorSize = (indicatorNode.style.height) ? parseInt(indicatorNode.style.height) : 0 ;
												// set the new scroll position
												this.moveTo(rootNode, indicatorPosition+indicatorSize/2+distance);
											}
										}
				// events
				this.onDown			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var asb = classBehaviours.handlers.artificialScrollBar;
											// activate the controls
											asb.interaction = true;
											// get the interaction location
											mouseY = (typeof(event)!='undefined' && navigator.userAgent.indexOf('Safari')<0) ? event.y : that.layerY ;
											// send the coordinates to the indicator
											asb.moveTo(objNode.parentNode.parentNode, mouseY);
											// cancel the click
											return false;
										}
				this.onDrag			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var asb = classBehaviours.handlers.artificialScrollBar;
											// if the controls are active
											if(asb.interaction){
												// get the interaction location
												mouseY = (typeof(event)!='undefined' && navigator.userAgent.indexOf('Safari')<0) ? event.y : that.layerY ;
												// send the coordinates to the indicator
												asb.moveTo(objNode.parentNode.parentNode, mouseY);
												// cancel the click
												return false;
											}
										}
				this.onUp			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var asb = classBehaviours.handlers.artificialScrollBar;
											// de-activate the controls
											asb.interaction = false;
											// cancel the click
											return false;
										}
				this.buttonUp		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var asb = classBehaviours.handlers.artificialScrollBar;
											// move the scroller 1 step up
											asb.moveBy(asb.interactor, -5);
											// set an interval
											asb.scrollInterval = setInterval("classBehaviours.handlers.artificialScrollBar.moveBy(classBehaviours.handlers.artificialScrollBar.interactor, -5)", 50);
											// cancel the click
											return false;
										}
				this.buttonDown		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var asb = classBehaviours.handlers.artificialScrollBar;
											// move the scroller 1 step down
											asb.moveBy(asb.interactor, 5);
											// set an interval
											asb.scrollInterval = setInterval("classBehaviours.handlers.artificialScrollBar.moveBy(classBehaviours.handlers.artificialScrollBar.interactor, 5)", 50);
											// cancel the click
											return false;
										}
				this.buttonOff		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var asb = classBehaviours.handlers.artificialScrollBar;
											// clear the scrolling interval
											clearInterval(asb.scrollInterval);
											// cancel the click
											return false;
										}
				this.onWheel		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var asb = classBehaviours.handlers.artificialScrollBar;
											// get the scroll distance
											distance = (window.event) ? window.event.wheelDelta/120 : -objNode.detail/3 ; 
											// scroll the page
											asb.moveBy(asb.interactor, -5*distance);
											// cancel the click
											return false;
										}
				this.overCanvas		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var asb = classBehaviours.handlers.artificialScrollBar;
											// store the object hovered over
											asb.interactor = objNode;
										}
				this.offCanvas		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var asb = classBehaviours.handlers.artificialScrollBar;
											// store the object hovered over
											asb.interactor = null;
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.artificialScrollBar = new ArtificialScrollBar;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.artificialScrollBar;
			
			// Use the longdesc url to display a tooltip
			function LongdescToolTip(){
				// properties
				this.name 			= 	'longdescToolTip';
				// methods
				this.start			=	function(node){
											// set the event handlers of the image
											node.onmouseover = this.overImage;
											node.onmouseout = this.offImage;
							//				node.onmousemove = this.moveImage;
										}
				this.waitForDesc	=	function(importProgress, referedNode){
											targetNode = classBehaviours.utilities.previousNode(referedNode);
											targetNode.innerHTML = 'loading: ' + Math.round(importProgress*100) + '%';
										}
				this.insertDesc		=	function(importedObj, referedNode, importedText){
											targetNode = classBehaviours.utilities.previousNode(referedNode);
											targetNode.innerHTML = importedText.split('<body>')[1].split('</body>')[0];;
										}
				// events
				this.overImage		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var ltt = classBehaviours.handlers.longdescToolTip;
											// get the taget node
											targetNode = classBehaviours.utilities.previousNode(objNode);
											// if this node is an existing tooltip
											if(targetNode.nodeName=='DIV' && targetNode.className.indexOf(ltt.name)>-1){
												// show it
												targetNode.style.visibility = 'visible';
											}else{
												// make a new one
												newToolTip = document.createElement('DIV');
												newToolTip.className = ltt.name;
												objNode.parentNode.insertBefore(newToolTip, objNode);
												// order it to be filled
												classBehaviours.ajax.addRequest(objNode.getAttribute('longdesc'), ltt.insertDesc, ltt.waitForDesc, null, objNode);
											}
										}
				this.offImage		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var ltt = classBehaviours.handlers.longdescToolTip;
											// get the next node
											targetNode = classBehaviours.utilities.previousNode(objNode);
											// if this node is an existing tooltip
											if(targetNode.nodeName=='DIV' && targetNode.className.indexOf(ltt.name)>-1){
												// hide it
												targetNode.style.visibility = 'hidden';
											}
										}
				this.moveImage		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var ltt = classBehaviours.handlers.longdescToolTip;
											// get the next node
											targetNode = classBehaviours.utilities.previousNode(objNode);
											// if this node is an existing tooltip
											if(targetNode.nodeName=='DIV' && targetNode.className.indexOf(ltt.name)>-1){
												targetNode.style.position = 'absolute';
												targetNode.style.left = (typeof(that)!='undefined') ? (that.layerX) + 'px' : (event.x) + 'px' ;
												targetNode.style.top = (typeof(that)!='undefined') ?  (that.layerY) + 'px' : (event.y) + 'px' ;
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.longdescToolTip = new LongdescToolTip;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.longdescToolTip;
			
			// Replace a link to external content with the actual content
			function InsertFromFile(){
				// properties
				this.name 			= 	'insertFromFile';
				// methods
				this.start			=	function(node){
											// start loading
											classBehaviours.ajax.addRequest(node.getAttribute('href'), this.insert, this.wait, null, node);
										}
				this.wait			=	function(importProgress, referedNode){
											referedNode.innerHTML = 'loading: ' + Math.round(importProgress*100) + '%';
										}
				this.insert			=	function(importedObj, referedNode, importedText){
											// insert the content before the link
											newDiv = document.createElement('div');
											referedNode.parentNode.insertBefore(newDiv, referedNode);
											insertedNode = classBehaviours.utilities.previousNode(referedNode);
											insertedNode.innerHTML = importedText.split('<body>')[1].split('</body>')[0];
											// activate any classbehaviours in there
											classBehaviours.parser.parseNode(insertedNode);
											// remove the link
											removedNode = referedNode.parentNode.removeChild(referedNode);
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.insertFromFile = new InsertFromFile;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.insertFromFile;
			
			// this keeps a screen element fixed to the scrolling
			function ScrollLock(){
				// properties
				this.name 		= 	'scrollLock';
				this.index		=	0;
				this.timeout	=	null;
				this.objects	=	new Array();
				// methods
				this.start		=	function(node){
										// give this node and id if there isn't any
										node.id = (node.id) ? node.id : this.name + this.index ;
										// store this scrolling object and its offset
										this.objects[this.objects.length] = node;
										// set the scolling event
										window.onscroll = this.scrolled;
									}
				// events
				this.scrolled	=	function(that, noOffset){
										var slc = classBehaviours.handlers.scrollLock;
										// clear the timeout on this function
										clearTimeout(classBehaviours.handlers.scrollLock.timeout);
										// for all scrolling objects
										for(var a=0; a<slc.objects.length; a++){
											// get the scrolling object
											scrollingObject = slc.objects[a];
											// get the scrolling offset
											offset = Math.round(classBehaviours.utilities.getClassParameter(scrollingObject, 'offset', '0'));
											// get the scrolling position
											scrollPos = document.documentElement.scrollTop;
											// reposition the scrolling object
											availableHeight = (window.innerHeight) ? window.innerHeight : document.documentElement.clientHeight ;
											if(scrollPos>=offset && scrollingObject.offsetHeight<availableHeight){
												scrollingObject.style.position = (navigator.appVersion.indexOf('MSIE 6')<0) ? 'fixed' : 'absolute' ;
												scrollingObject.style.marginTop = (navigator.appVersion.indexOf('MSIE 6')<0) ? (-1*offset) + 'px' : (scrollPos-offset) + 'px' ;
											}else{
												scrollingObject.style.position = 'relative';
												scrollingObject.style.marginTop = '0px';
											}
										}
										// order this function to run one last time after scrolling stops
										if(!noOffset) classBehaviours.handlers.scrollLock.timeout = setTimeout('classBehaviours.handlers.scrollLock.scrolled(null, true);', 128);
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.scrollLock = new ScrollLock;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.scrollLock;
		
			// scroll a list of options
			function ScrollList(){
				// properties
				this.name 		= 	'scrollList';
				this.list		=	null;
				this.focus		=	null;
				this.speed		=	1;
				this.idleTimer	=	null;
				// methods
				this.start		=	function(node){
										// add the right event handler to the button
										node.onmousedown = (classBehaviours.utilities.getClassParameter(node, 'scrollDirection', 'forward')=='backward') ? this.startBackward : this.startForward ;
										node.onmouseover = this.cancel;
										node.onmouseup = this.cancel;
										node.onmouseout = this.cancel;
										// prepare the refered list
										id = classBehaviours.utilities.getClassParameter(node, 'id', 'scrollList0');
										this.prepareList(id);
									}
				// events
				this.startBackward	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var sl = classBehaviours.handlers.scrollList;
										// reset all scrolling
										id = sl.reset(objNode);
										// start the scrolling
										sl.scrollBackward(id);
									}
				this.startForward	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var sl = classBehaviours.handlers.scrollList;
										// reset all scrolling
										id = sl.reset(objNode);
										// start the scrolling
										sl.scrollForward(id);
									}
				// methods
				this.idle			=	function(id){
											classBehaviours.handlers.scrollList.speed = 1;
											classBehaviours.handlers.scrollList.scrollForward(id);
										}
				this.prepareList	=	function(id) {
											scroller = document.getElementById(id);
											// if this list has not been prepared before
											if(scroller.className.indexOf('trippled')<0){
												// copy the content twice
												scrollList = scroller.getElementsByTagName('UL')[0];
												scrollList.innerHTML += scrollList.innerHTML + scrollList.innerHTML;
												// set the scroller halfway
												var contentWidth = scrollList.offsetWidth;
												scrollList.style.marginLeft = '-' + Math.round(contentWidth/3) + 'px';
												// mark the list as prepared
												scroller.className += ' trippled';
												// start the idle scrolling
												classBehaviours.handlers.scrollList.idle(id);
											}
										}
				this.reset			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var sl = classBehaviours.handlers.scrollList;
											// clear the idle timer
											clearTimeout(sl.idleTimer);
											// stop the scrolling
											clearTimeout(sl.timeout);
											// reset the speed
											sl.speed = 5;
											// get the target id
											id = classBehaviours.utilities.getClassParameter(objNode, 'id', 'scrollList0');
											// pass the id back
											return id;
										}
				this.cancel		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var sl = classBehaviours.handlers.scrollList;
											// clear the idle timer
											clearTimeout(sl.idleTimer);
											// stop the scrolling
											clearTimeout(sl.timeout);
											// release the focus
											sl.focus = null;
											// wait for a while, then start idle scrolling
											id = classBehaviours.utilities.getClassParameter(objNode, 'id', 'scrollList0');
											sl.idleTimer = setTimeout('classBehaviours.handlers.scrollList.idle("'+id+'")',2000);
										}
				this.scrollBackward	=	function(id){
										var sl = classBehaviours.handlers.scrollList;
										// how high is the container
										var container = document.getElementById(id);
										var borderWidth = container.offsetWidth;
										// how heigh is the content
										var content = container.getElementsByTagName('UL')[0];
										var contentWidth = content.offsetWidth;
										// where is the content
										var contentScroll = (content.style.marginLeft) ? parseInt(content.style.marginLeft) : 0 ;
										// if the contant can still move
										loopPoint = 0
										resetPoint = -1 * Math.round(contentWidth/3);
										if(contentScroll<loopPoint){
											// move it
											content.style.marginLeft = (contentScroll + sl.speed) + 'px';
										// reset it back to the starting position
										}else{
											content.style.marginLeft = (resetPoint - sl.speed) + 'px';
										}
										// next step
										sl.timeout = setTimeout('classBehaviours.handlers.scrollList.scrollBackward("' + id + '")', 40);
									}
				this.scrollForward	=	function(id){
										var sl = classBehaviours.handlers.scrollList;
										// how high is the container
										var container = document.getElementById(id);
										var borderWidth = container.offsetWidth;
										// how heigh is the content
										var content = container.getElementsByTagName('UL')[0];
										var contentWidth = content.offsetWidth;
										// where is the content
										var contentScroll = (content.style.marginLeft) ? parseInt(content.style.marginLeft) : 0 ;
										// if the contant can still move
										loopPoint = -2 * Math.round(contentWidth/3);
										resetPoint = -1 * Math.round(contentWidth/3);
										if(loopPoint<contentScroll){
											// move it
											content.style.marginLeft = (contentScroll - sl.speed) + 'px';
										// reset it back to the starting position
										}else{
											content.style.marginLeft = (resetPoint - sl.speed) + 'px';
										}
										// next step
										sl.timeout = setTimeout('classBehaviours.handlers.scrollList.scrollForward("' + id + '")', 40);
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.scrollList = new ScrollList;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.scrollList;
		
			// handle ondrag events
			function DragAndDrop(){
				// properties
				this.name 		= 	'dragAndDrop';
				this.node		=	null;
				this.grid		=	new Coordinates(16,16);
				this.minPos		=	new Coordinates();
				this.maxPos		=	new Coordinates();
				this.pickup		=	new Coordinates();
				this.mouse		=	new Coordinates();
				this.style		=	new Coordinates();
				this.onMove	=	null;
				// methods
				this.start		=	function(node){
										// events
										node.onmousedown 			= this.pickUp;
										document.onmouseup 			= this.dropDown;
									//	document.onmousemove 		= this.moveAway;
										node.onmousemove 			= this.moveAway;
										// exctract the limits from the class parameters
										this.grid.x	=	parseInt(classBehaviours.utilities.getClassParameter(node, 'gridX', null));
										this.grid.y	=	parseInt(classBehaviours.utilities.getClassParameter(node, 'gridY', null));
										this.minPos.x	=	parseInt(classBehaviours.utilities.getClassParameter(node, 'limitLeft', null));
										this.minPos.y	=	parseInt(classBehaviours.utilities.getClassParameter(node, 'limitTop', null));
										this.maxPos.x	=	parseInt(classBehaviours.utilities.getClassParameter(node, 'limitRight', null));
										this.maxPos.y	=	parseInt(classBehaviours.utilities.getClassParameter(node, 'limitBottom', null));
										// saved position
										this.restore(node);
									}
				this.restore 	= 	function(objNode){
										/*
										var strStyles, arrStyles;
										// retrieve styles string
										strStyles = classBehaviours.cookies.getCookie('dragAndDrop');					
										// were any styles recovered
										if(strStyles!=null){
											arrStyles = strStyles.split(',');
											// does the stored positions match the object
											if(arrStyles[0]==objNode.id && arrStyles.length>2){
												objNode.style.left = arrStyles[1];
												objNode.style.top = arrStyles[2];
											}
										}
										*/
									}
				this.store 		= 	function(objNode){
										/*
										// store styles
										classBehaviours.cookies.setCookie('dragAndDrop', objNode.id + ',' + objNode.style.left + ',' + objNode.style.top, null, '/', null, null);
										*/
									}
				// events
				this.pickUp 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var dnd = classBehaviours.handlers.dragAndDrop;
										// accept no new pickups before dropdown
										if(dnd.pickupObj==null){
											// store the object being picked up
											dnd.node = objNode;
											// store pickup location
											dnd.pickup.x = (typeof(event)!='undefined') ? event.clientX : that.clientX ;
											dnd.pickup.y = (typeof(event)!='undefined') ? event.clientY : that.clientY ;
											dnd.pickup.z = (objNode.style.zIndex=='') ? objNode.style.zIndex : 0;
											// default starting position if none was given
											if(objNode.style.position!='absolute') objNode.style.position = 'absolute';
											if(objNode.style.left=='') objNode.style.left = /*dnd.pickup.x +*/ '0px'; 
											if(objNode.style.top=='') objNode.style.top = /*dnd.pickup.y +*/ '0px';
											// promote z position
											objNode.style.zIndex = 1024;
										}
										// cancel browser mouse handler
										return false;
									}
				this.dropDown 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var dnd = classBehaviours.handlers.dragAndDrop;
										// only if a pickup is active
										if(dnd.node!=null){
											// snap coordinates to grid
											if(dnd.grid.x>0) dnd.node.style.left = Math.round(parseInt(dnd.node.style.left)/dnd.grid.x)*dnd.grid.x + "px";
											if(dnd.grid.y>0) dnd.node.style.top = Math.round(parseInt(dnd.node.style.top)/dnd.grid.y)*dnd.grid.y + "px";
											// restore z position
											dnd.node.style.zIndex = dnd.pickup.z;
											// store the position in a cookie
											dnd.store(dnd.node);
											// release the picked up object
											dnd.node = null;
											// clear pickup location
											dnd.pickup.x = null;
											dnd.pickup.y = null;
											dnd.pickup.z = null;
										}
										// cancel browser mouse handler
										return false;
									}
				this.moveAway 	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var dnd = classBehaviours.handlers.dragAndDrop;
										// only if a pickup is active
										if(dnd.node!=null){
											// mouse position
											dnd.mouse.x = (typeof(event)!='undefined') ? event.clientX : that.clientX ;
											dnd.mouse.y = (typeof(event)!='undefined') ? event.clientY : that.clientY ;
											// current object position
											dnd.style.x = (dnd.node.style.left.indexOf('px')<0) ? 0 : parseInt(dnd.node.style.left) ;
											dnd.style.y = (dnd.node.style.top.indexOf('px')<0) ? 0 : parseInt(dnd.node.style.top) ;
											// calculate new object position
											var newXpos = dnd.style.x + dnd.mouse.x - dnd.pickup.x;
											var newYpos = dnd.style.y + dnd.mouse.y - dnd.pickup.y;
											// limit new object position
											if(newXpos<dnd.minPos.x) newXpos = dnd.minPos.x;
											if(newXpos>dnd.maxPos.x) newXpos = dnd.maxPos.x;
											if(newYpos<dnd.minPos.y) newYpos = dnd.minPos.y;
											if(newYpos>dnd.maxPos.y) newYpos = dnd.maxPos.y;
											// apply new object position
											if(dnd.pickup.x!=null) dnd.node.style.left = newXpos + 'px';
											if(dnd.pickup.y!=null) dnd.node.style.top = newYpos + 'px';
											// update pickup location
											dnd.pickup.x = dnd.mouse.x;
											dnd.pickup.y = dnd.mouse.y;
											// execute custom event handler
											if(dnd.onMove!=null) dnd.onMove(dnd.node);
										}
										// cancel browser mouse handler
										return false;
									}
			}
				function Coordinates(x,y,z){
					this.x = x;
					this.y = y;
					this.z = z;
				}
			// add this function to the classbehaviour object
			classBehaviours.handlers.dragAndDrop = new DragAndDrop;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.dragAndDrop;
		
			// handle the mouseclicks of a slider
			function ValueSlider(){
				// properties
				this.name 		= 	'valueSlider';
				this.active		=	false;
				// methods
				this.start		=	function(node){
										// get the cover layer
										sliderCover = node.getElementsByTagName('div')[1];
										sliderCover.onmousedown = this.onDown;
										sliderCover.onmouseup = this.onUp;
										sliderCover.onmousemove = this.onMove;
										sliderCover.onmouseout = this.onUp;
										// get the form element
										sliderInput = classBehaviours.utilities.nextNode(node);
										sliderInput.onchange = this.onTyped;
										// set the initial value
										if(sliderInput.id){
											setTimeout("classBehaviours.handlers.valueSlider.onTyped(document.getElementById('"+sliderInput.id+"'))", 200);
										}else{
											this.onTyped(sliderInput);
										}
									}
				this.setSlider	=	function(rootNode, sliderSize, inputValue){
										// get the minimum value
										minimumValue = parseFloat(classBehaviours.utilities.getClassParameter(rootNode, 'min', 0));
										// get the maximum value
										maximumValue = parseFloat(classBehaviours.utilities.getClassParameter(rootNode, 'max', 100));
										// get the maximum value
										offsetValue = parseFloat(classBehaviours.utilities.getClassParameter(rootNode, 'off', 0));
										// get the step size
										stepValue = parseFloat(classBehaviours.utilities.getClassParameter(rootNode, 'step', 0));
										// get the handle slack
										slackValue = parseFloat(classBehaviours.utilities.getClassParameter(rootNode, 'slack', 15));
										// apply the offset
										if(sliderSize!=null) sliderSize += offsetValue
										// get the maximum size of the slider
										minimumSize = 1 + slackValue;
										maximumSize = rootNode.offsetWidth - slackValue;
										// calculate the missing size or value
										if(sliderSize==null) sliderSize = Math.round((inputValue) / maximumValue * maximumSize) ;
										if(inputValue==null) inputValue = (sliderSize / maximumSize * (maximumValue - minimumValue)) + minimumValue ;
										// normalize the values
										if(stepValue>0) sliderSize = sliderSize - sliderSize % stepValue;
										if(sliderSize<minimumSize) sliderSize = minimumSize;
										if(sliderSize>maximumSize) sliderSize = maximumSize;
										if(inputValue<minimumValue) inputValue = minimumValue;
										if(inputValue>maximumValue) inputValue = maximumValue;
										// molest the indicator pointer
										if(stepValue>0){
											pointerNode = rootNode.getElementsByTagName('img')[0];
											pointerPrefix = pointerNode.src.substr(0, pointerNode.src.length-5);
											pointerSuffix = pointerNode.src.substr(pointerNode.src.length-4);
											pointerNode.src = pointerPrefix + Math.round(sliderSize/stepValue) + pointerSuffix;
										}
										// set the size of the slider
										rootNode.getElementsByTagName('div')[0].style.width = Math.round(sliderSize + slackValue) + 'px';
										// set the value of the input
										classBehaviours.utilities.nextNode(rootNode).value = (stepValue>0) ? Math.round(inputValue) : inputValue.toFixed(1);
										rootNode.getElementsByTagName('span')[0].innerHTML = inputValue.toFixed(1);
									}
				// events
				this.onDown		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var vsl = classBehaviours.handlers.valueSlider;
										// get the mouse position
										mouseX = (typeof(event)!='undefined' && navigator.userAgent.indexOf('Safari')<0) ? event.x : that.layerX ;
										// set the value
										vsl.setSlider(objNode.parentNode, mouseX, null);
										// mark the function active
										vsl.active = true;
										// cancel the mouse dragging the layer off
										return false;
									}
				this.onUp		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var vsl = classBehaviours.handlers.valueSlider;
										// mark the function inactive
										vsl.active = false;
										// cancel the mouse dragging the layer off
										return false;
									}
				this.onMove		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var vsl = classBehaviours.handlers.valueSlider;
										// if the function is marked active
										if(vsl.active){
											// get the mouse position
											mouseX = (typeof(event)!='undefined' && navigator.userAgent.indexOf('Safari')<0) ? event.x : that.layerX ;
											// set the value
											vsl.setSlider(objNode.parentNode, mouseX, null);
										}
										// cancel the mouse dragging the layer off
										return false;
									}
				this.onTyped	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var vsl = classBehaviours.handlers.valueSlider;
										// get the value
										sliderNode = classBehaviours.utilities.previousNode(objNode);
										inputValue = parseInt(objNode.value);
										// set the slider
										vsl.setSlider(sliderNode, null, inputValue);
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.valueSlider = new ValueSlider;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.valueSlider;
		
			// copy text to the clipboard
			function CopyToClipboard(){
				// properties
				this.name 			= 	'copyToClipboard';
				// methods
				this.start			=	function(node){
											node.onclick = this.copyContents;
										}
				// events
				this.copyContents	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// get the target content
										targetId = classBehaviours.utilities.getClassParameter(objNode, 'id', null);
										if(targetId!=null){
											targetNode = document.getElementById(targetId);
											targetValue = (targetNode.value) ?  targetNode.value : targetNode.innerHTML ;
											if(window.clipboardData){
												window.clipboardData.setData('text', targetValue);
											}else{
												// this doesn't work :(
											//	targetValue = document.selection.createRange();
											//	targetValue.execCommand("Copy");
											}
										}
									}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.copyToClipboard = new CopyToClipboard;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.copyToClipboard;
		
			// replace the content of a section based on a select
			function SelectContent(){
				// properties
				this.name 			= 	'selectContent';
				// methods
				this.start			=	function(node){
											// set the event for either the button or the drop-down
											if(node.nodeName=='SELECT')
												node.onchange = this.loadNew;
											else
												node.onclick = this.loadNew;
											// load the initial content
											this.loadNew(node);
										}
				// events
				this.loadNew		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var sct = classBehaviours.handlers.selectContent;
											// get the url from the select
											newUrl = objNode.value;
											// get the refered source
											var sourceId = classBehaviours.utilities.getClassParameter(objNode, 'from', objNode.id);
											// get the refered target
											var targetId = classBehaviours.utilities.getClassParameter(objNode, 'to', null);
											// request the content
											if(sourceId!=null && targetId!=null && newUrl!='') classBehaviours.ajax.addRequest(document.getElementById(sourceId).value, sct.insertNew, sct.waitForNew, null, document.getElementById(targetId));
											// cancel the click
											if(objNode.nodeName!='select') return false;
										}
				this.waitForNew		=	function(loadStatus, loadReferer, loadError){
											// post the status to the target area
											loadReferer.innerHTML = (loadStatus<0) ? 
																		'<p>Foutmelding: '+loadError+'</p>' : 
																		'<p>Bezig met inladen: '+Math.round(loadStatus*100)+'%</p>';
											
										}
				this.insertNew		=	function(loadedXml, loadedReferer, loadedTxt){
											// make the content invisible
											classBehaviours.fader.setFade(loadedReferer, 0);
											// replace the contents
											loadedReferer.innerHTML = loadedTxt.split('</root>')[0].split('<root>')[1]
											// apply their classbehaviours
											classBehaviours.parser.parseNode(loadedReferer);
											// reveal the contents
											classBehaviours.fader.fadeIn(loadedReferer.id, 10, 100);
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.selectContent = new SelectContent;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.selectContent;
			
			// replace the content of a section based on a select
			function LoadOpml(){
				// properties
				this.name 			= 	'loadOpml';
				// methods
				this.start			=	function(node){
											// get the url
											xmlUrl = node.getElementsByTagName('input')[0].value;
											// load the file
											classBehaviours.ajax.addRequest(xmlUrl, this.insertNew, this.waitForNew, null, node);
										}
				// events
				this.waitForNew		=	function(loadStatus, loadReferer, loadError){
											// debug(loadStatus)
										}
				this.insertNew		=	function(loadedXml, loadedReferer, loadedTxt){
											var listHtml = '';
											// for all the nodes in the file
											allNodes = loadedXml.getElementsByTagName('outline');
											for(var a=0; a<allNodes.length; a++){
												// get the podcast url
												podUrl = allNodes[a].getAttribute('htmlUrl');
												// get the podcast rss feed
												podRss = allNodes[a].getAttribute('xmlUrl');
												// get the title
												podTitle = allNodes[a].getAttribute('text');
												// construct a link
												listHtml += '<li><a href="'+podUrl+'">'+podTitle+'</a>';
												listHtml += (podRss!='') ? ' - <a href="'+podRss+'" class="rss">rss</a></li>' : '</li>' ;
											}
											// insert the links in the list
											loadedReferer.innerHTML = '<ul>' + listHtml + '</ul>';
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.loadOpml = new LoadOpml;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.loadOpml;
		
			// make a button appear disabled
			function DisabledButton(){
				// properties
				this.name 			= 	'disabledButton';
				// methods
				this.start			=	function(node){
											node.onclick = this.cancelClick;
											classBehaviours.fader.setFade(node, 50);
										}
				// events
				this.cancelClick	=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// cancel the click
											return false;
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.disabledButton = new DisabledButton;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.disabledButton;
		
			// make a button appear disabled
			function ParallaxBackground(){
				// properties
				this.name 			= 	'parallaxBackground';
				this.index 			=	0;
				this.focusNode		=	null;
				// methods
				this.start			=	function(node){
											// identify the scroller
											this.index += 1;
											node.id = (node.id) ? node.id : this.name + this.index ;
											scrollerId = classBehaviours.utilities.getClassParameter(node, 'scroller', null);
											scroller = (scrollerId!=null) ? document.getElementById(scrollerId) : window ;
											// add the event handler
											classBehaviours.utilities.addEvent(scroller, 'scroll', this.adjustScroll);
											// keep track of the focus to find the correct scroller (despite Internet Explorer not passing it with the event handler in a sane way)
											if(scroller!=window) scroller.onmouseover = this.storeFocus;
											if(scroller!=window) scroller.onmouseout = this.clearFocus;
										}
				// events
				this.storeFocus		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var pbg = classBehaviours.handlers.parallaxBackground;
											// store the focus
											pbg.focusNode = objNode;
										}
				this.clearFocus		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var pbg = classBehaviours.handlers.parallaxBackground;
											// store the focus
											pbg.focusNode = null;
										}
				this.adjustScroll	=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var pbg = classBehaviours.handlers.parallaxBackground;
											// get the parallax layers from the scroller, use the body by default
											if(pbg.focusNode==null){
												scrollPosition = (document.body.scrollTop) ? document.body.scrollTop : document.documentElement.scrollTop ;
												parallaxLayers = new Array(document.body.id, 10);
											}else{
												scrollPosition = pbg.focusNode.scrollTop;
												parallaxCSV = classBehaviours.utilities.getClassParameter(pbg.focusNode, 'layers', pbg.focusNode.id + ';10');
												parallaxLayers = parallaxCSV.split(';');
											}
											// adjust the background positions
											for(var a=0; a<parallaxLayers.length-1; a+=2){
												backgroundPosition = Math.round(-1 * scrollPosition / parseInt(parallaxLayers[a+1]));
												parallaxLayer = document.getElementById(parallaxLayers[a]);
												parallaxLayer.style.backgroundPosition = '50% ' + backgroundPosition + 'px';
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.parallaxBackground = new ParallaxBackground;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.parallaxBackground;
		
			// Changes a template's skin
			function SkipToNextField(){
				// properties
				this.name 			= 	'skipToNextField';
				// methods
				this.start			=	function(node){
											// apply the counter event to the field
											node.onkeyup = this.count;
										}
				// events
				this.count			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// get the maximum count from the node
											maxCount = classBehaviours.utilities.getClassParameter(objNode, 'count', 2);
											nextId = classBehaviours.utilities.getClassParameter(objNode, 'id', null);
											// get the current count from the node
											curCount = objNode.value.length;
											// if the count is too high
											if(curCount>=maxCount){
												// is there id for the next node?
												if(nextId!=null){
													nextNode = document.getElementById(nextId);
													nextNode.focus();
												// else look for it yourself
												}else{
													// while the next form element has not been found
													notFound = true;
													while(notFound){
														// skip to the next node
														nextNode = classBehaviours.utilities.nextNode(objNode);
														// if this a form element
														if(nextNode.nodeName=='INPUT' || nextNode.nodeName=='TEXTAREA' || nextNode.nodeName=='BUTTON' || nextNode.nodeName=='SELECT'){
															// put the focus on it
															nextNode.focus();
															// break the loop
															notFound = false;
														}
														if(objNode==nextNode){
															// break the loop
															notFound = false;
														}
													}
												}
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.skipToNextField = new SkipToNextField;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.skipToNextField;
		
			// Makes an editable version of a table row
			function EditTableRow(){
				// properties
				this.name 			= 	'editTableRow';
				this.index			=	0;
				// methods
				this.start			=	function(node){
											// set the event handler on the edit button
											node.onclick = this.edit;
										}
				this.importNode		=	function(rowNode, editorUrl){
											var etr = classBehaviours.handlers.editTableRow;
											// create a new TR
											newRow = document.createElement('TR');
											newRow.className = 'edit_here';
											// count the TD's in the parent TR
											colSpans = rowNode.getElementsByTagName('TD').length;
											// create a single new TD with enough colspans an ID and a progress indicator
											newCol = document.createElement('TD');
											newCol.setAttribute('colSpan', colSpans);
											newRow.appendChild(newCol);
											// place the new TR after the current one
											classBehaviours.utilities.insertAfter(rowNode.parentNode, rowNode, newRow);
											// get the address of the new node
											insertedRow = classBehaviours.utilities.nextNode(rowNode);
											// import the URL to the TD
											classBehaviours.ajax.addRequest(editorUrl, etr.insert, etr.wait, null, insertedRow);
										}
				this.wait			=	function(waitProgress, waitReferer, waitError){
											// take the target cell
											targetNode = waitReferer.getElementsByTagName('TD')[0];
											// calculate the className-suffix for the progress
											progressClass = parseInt(waitProgress * 4);
											// insert the update
											targetNode.innerHTML = (waitProgress>-1) ? '<div class="tableRowProgress progress_'+progressClass+'">loading: ' + waitProgress*100 + '%</div>' : '<div class="tableRowProgress progress_'+progressClass+'">error: ' + waitError + '</div>' ;
										}
				this.insert			=	function(insertXml, insertReferer, insertTxt){
											var etr = classBehaviours.handlers.editTableRow;
											// take the target cell
											targetNode = insertReferer.getElementsByTagName('TD')[0];
											// set starting styles for its fade
											targetNode.style.height = '25px';
											targetNode.style.overflow = 'hidden';
											// make up an id for the node
											targetId = etr.name + etr.index++;
											// insert the new HTML
											targetNode.innerHTML = '<div class="tableRowEditor" id="'+targetId+'">' + insertTxt.split('<root>')[1].split('</root>')[0] + '</div>';
											// parse its classbehaviours
											classBehaviours.parser.parseNode(targetNode);
											// try to figure out the target height
											targetHeight = targetNode.getElementsByTagName('div')[1].offsetHeight;
											// set it to grow
											classBehaviours.fader.setFade(document.getElementById(targetId), 0);
											classBehaviours.fader.fadeIn(targetId, 10, 10, '');
											classBehaviours.fader.grow(targetId, -1, targetHeight, 10, 10, 'document.getElementById("'+targetId+'").style.height="auto"', 10);
										}
				this.remove			=	function(rowNode){
											// remove the edit TR after the current one
											insertedRow = classBehaviours.utilities.nextNode(rowNode);
											rowNode.parentNode.removeChild(insertedRow);
										}
				// events
				this.edit			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var etr = classBehaviours.handlers.editTableRow;
											// find the parent TR
											parentRow = classBehaviours.utilities.rootNode(objNode, 'TR');
											// if this is the displayedVersion
											if(classBehaviours.utilities.getClassParameter(parentRow, 'edit', 'no')=='no'){
												// show the editVersion
												classBehaviours.utilities.setClassParameter(parentRow, 'edit', 'yes');
												// if the clicked object came with a URL, import the editor
												if(objNode.getAttribute('href')!=null) etr.importNode(parentRow, objNode.getAttribute('href'));
											// else
											}else{
												// show the displayedVersion
												classBehaviours.utilities.setClassParameter(parentRow, 'edit', 'no');
												// if the clicked object came with a URL, remove the editor
												if(objNode.getAttribute('href')!=null) etr.remove(parentRow);	
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.editTableRow = new EditTableRow;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.editTableRow;
			
			// Reflect changes to input elements to a text container
			function EchoInput(){
				// properties
				this.name 			= 	'echoInput';
				// methods
				this.start			=	function(node){
											// set the event handler on this form element
											node.onchange = this.update;
										}
				// events
				this.update			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// get the id of the target node
											targetId = classBehaviours.utilities.getClassParameter(objNode, 'id', null);
											// if there was no target id, use a neighbouring node
											targetNode = (targetId!=null) ? document.getElementById(targetId) : classBehaviours.utilities.previousNode(objNode) ;
											// fill the target node with the value
											targetNode.innerHTML = objNode.value;
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.echoInput = new EchoInput;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.echoInput;
			
			// Rebuilds the ClassBhaviour library through string replaces
			function RebuildClassBehaviours(){
				// properties
				this.name 			= 	'rebuildClassBehaviours';
				// methods
				this.start			=	function(node){
											// set the event handler on this button element
											node.getElementsByTagName('button')[1].onclick = this.loadJs;
										}
				this.wait			=	function(waitProgress, waitReferer, waitError){
											debug(waitProgress, waitError);
										}
				this.process		=	function(processXml, processReferer, processText){
											// for all check boxes in the parent
											allChecks = processReferer.getElementsByTagName('input');
											for(var a=1; a<allChecks.length; a++){
												// if this checkbox is unchecked
												if(!allChecks[a].checked){
													// get the function name
													functionUrlParts = allChecks[a].parentNode.parentNode.getElementsByTagName('a')[0].href.split('/');
													functionName = functionUrlParts[functionUrlParts.length-1].split('.')[0];
													// get the prototype name
													prototypeName = functionName.split('');
													prototypeName[0] = prototypeName[0].toUpperCase();
													prototypeName = prototypeName.join('');
													// split out the function
													processTextPrefix =  processText.split('function '+prototypeName+'(){')[0];
													processTextSuffix = processText.split('classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.'+functionName+';')[1];
													processText = processTextPrefix + processTextSuffix;
												}
											}
											// encode the string somewhat
											processText = processText.replace(/</g, '&lt;');
											processText = processText.replace(/>/g, '&gt;');
											/*
											// for all classbhaviours
											for(var a=0; a<classBehaviours.handlers.length; a++){
												replaceRegExp = new RegExp("classBehaviours.handlers\\[classBehaviours.handlers.length\\]", "g");
												processText = processText.replace(replaceRegExp, "classBehaviours.handlers.index[classBehaviours.handlers.index.length]");
											}
											// for all classbhaviours
											for(var a=0; a<classBehaviours.handlers.length; a++){
												replaceRegExp = new RegExp("classBehaviours."+classBehaviours.handlers[a].name, "g");
												processText = processText.replace(replaceRegExp, "classBehaviours.handlers."+classBehaviours.handlers[a].name);
											}
											*/
											// report the result
											document.writeln('<textarea cols="1024" rows="500" style="width:100%; height:768px;">' + processText + '</textarea>');
										}
				// events
				this.loadJs			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var rcb = classBehaviours.handlers.rebuildClassBehaviours;
											// get the root node of the behaviour
											rootNode = classBehaviours.utilities.rootNode(objNode, null, null, rcb.name);
											// load the javascript file as text
											classBehaviours.ajax.addRequest('./scripts/classBehaviours.js', rcb.process, rcb.wait, null, rootNode);
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.rebuildClassBehaviours = new RebuildClassBehaviours;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.rebuildClassBehaviours;

			// Periodically updates the browser as a preview window
			function UpdateWhileYouBuild(){
				// properties
				this.name 			= 	'updateWhileYouBuild';
				// methods
				this.start			=	function(node){
											// set the event handler for the scrolling
											classBehaviours.utilities.addEvent(document, 'scroll', this.store);
											classBehaviours.utilities.addEvent(window, 'load', this.restore);
											// refresh the page periodically
											setInterval('document.location.replace(document.location.href)', 2048);
										}
				// events
				this.store			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// store the current scroll position
											document.cookie = 'scrollpos=' + document.documentElement.scrollTop;
										}
				this.restore		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// restore the prevous scroll position
											document.documentElement.scrollTop = parseInt(document.cookie.split('scrollpos=')[1]);
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.updateWhileYouBuild = new UpdateWhileYouBuild;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.updateWhileYouBuild;

			// Process a pre-formatted string
			function CodeExample(){
				// properties
				this.name 			= 	'codeExample';
				// methods
				this.start			=	function(node){
											node.innerHTML = node.innerHTML.replace(/\t/gi, '&nbsp;&nbsp;&nbsp;');
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.codeExample = new CodeExample;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.codeExample;
			
			// Number literary references
			function LitRef(){
				// properties
				this.name 			= 	'litRef';
				this.index			=	1;
				// methods
				this.start			=	function(node){
											// check if the counter needs to be reset
											resetIndex = classBehaviours.utilities.getClassParameter(node, 'reset', null)
											if(resetIndex!=null) this.index = parseInt(resetIndex);
											// set the counter for this reference
											node.innerHTML = this.index++;
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.litRef = new LitRef;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.litRef;
			
			// Transform HTML 5 and XHTML 2 to a lower standard
			function DegradeGracefully(){
				// properties
				this.name 			= 	'degradeGracefully';
				this.firstTime		=	true;
				// methods
				this.start			=	function(node){
											if(this.firstTime && navigator.userAgent.indexOf('MSIE')>-1 || navigator.userAgent.indexOf('Firefox/2')>-1){
												// rewrite the html
												node.innerHTML = node.innerHTML.replace
												(
													/<!DOCTYPE html>/gi, 	'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
												).replace(
													/<HEADER/gi, 			'<div'
												).replace(
													/<SECTION/gi, 			'<div'
												).replace(
													/<ARTICLE/gi, 			'<div'
												).replace(
													/<NAV/gi, 				'<div'
												).replace(
													/<FOOTER/gi, 			'<div'
												).replace(
													/<TIME/gi, 				'<span'
												).replace(
													/<METER/gi, 			'<span'
												).replace(
													/<PROGRESS/gi, 			'<span'
												).replace(
													/<MENU/gi, 				'<ul'
												).replace(
													/<\/HEADER/gi, 			'</div'
												).replace(
													/<\/SECTION/gi, 		'</div'
												).replace(
													/<\/ARTICLE/gi, 		'</div'
												).replace(
													/<\/NAV/gi, 			'</div'
												).replace(
													/<\/FOOTER/gi, 			'</div'
												).replace(
													/<\/TIME/gi, 			'</span'
												).replace(
													/<\/METER/gi, 			'</span'
												).replace(
													/<\/PROGRESS/gi, 		'</span'
												).replace(
													/<\/MENU/gi, 			'</ul'
												) + '<div style="position : absolute; left : 16px; top : 5px; z-index : 10000;">Tada!</div>';
												// restart the classBehaviours
												this.firstTime = false;
												classBehaviours.parser.parseNode(node);
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.degradeGracefully = new DegradeGracefully;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.degradeGracefully;

			// Move a specified node to the location of the click
			function MoveNodeHere(){
				// properties
				this.name 			= 	'moveNodeHere';
				// methods
				this.start			=	function(node){
											// set the button click
											node.onclick = this.move;
										}
				// events
				this.move			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// move the targeted node
											targetNodeId = classBehaviours.utilities.getClassParameter(objNode, 'id', null);
											targetNode = document.getElementById(targetNodeId);
											removedNode = targetNode.parentNode.removeChild(targetNode);
											objNode.parentNode.insertBefore(removedNode, objNode);
											// apply its classbehaviours
											classBehaviours.utilities.previousNode(objNode).style.display = 'block';
											classBehaviours.parser.parseNode(classBehaviours.utilities.previousNode(objNode));
											// cancel the click
											objNode.style.display = 'none';
											return false;
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.moveNodeHere = new MoveNodeHere;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.moveNodeHere;
			
			// Move a specified node to the location of the click
			function ShowInChannelHeader(){
				// properties
				this.name 			= 	'showInChannelHeader';
				// methods
				this.start			=	function(node){
											// set the event handler on the table rows
											allRows = node.getElementsByTagName('tbody')[0].getElementsByTagName('tr');
											for(var a=0; a<allRows.length; a++) allRows[a].onmouseover = this.describe;
										}
				// events
				this.describe		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// find the cell with the title
											sourceTitle = objNode.getElementsByTagName('td')[1].innerHTML;
											sourceTitle = sourceTitle.replace(/<a href/gi, '<a class="clickOnParent" href');
											sourceTitle = '<h1 id="channelTitle">' + sourceTitle + '</h1>';
											// find the cell with the description
											sourceDescription = objNode.getElementsByTagName('td')[2].innerHTML;
											sourceDescription = '<div id="channelDescription">' + sourceDescription + '</div>'
											// put it in the channel header
											document.getElementById('channelHeader').innerHTML = sourceDescription.replace(/<p>/i, sourceTitle + '<p>');
											// process the content
											document.getElementById('channelTitle').style.display = 'block';
											descriptionImages = document.getElementById('channelDescription').getElementsByTagName('img');
											if(descriptionImages.length>0) descriptionImages[0].style.display = 'block';
											// parse the description for behaviours
											classBehaviours.parser.parseNode(document.getElementById('channelHeader'));
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.showInChannelHeader = new ShowInChannelHeader;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.showInChannelHeader;

			// Show the source-code of a linked file
			function ShowSourceCode(){
				// properties
				this.name 			= 	'showSourceCode';
				// methods
				this.start			=	function(node){
											// link event handler
											node.onclick = this.loadFile;
										}
				this.waitForFile	=	function(waitStatus, waitNode, waitError){
											// find the target node
											targetId = classBehaviours.utilities.getClassParameter(waitNode, 'id', 'tbxExampleCode');
											targetNode = document.getElementById(targetId);
											// show the code object
											targetNode.style.display = 'block';
											// set its status
											if(waitStatus>0){
												classBehaviours.fader.setFade(targetNode, waitStatus*100);
												targetNode.innerHTML = 'loading: ' + Math.round(waitStatus * 100) + '%';
											}else{
												classBehaviours.fader.setFade(targetNode, 100);
												targetNode.innerHTML = 'error: ' + waitError;
											}
										}
				this.processFile	=	function(processXml, processNode, processText){
											// find the target node
											targetId = classBehaviours.utilities.getClassParameter(processNode, 'id', 'tbxExampleCode');
											targetNode = document.getElementById(targetId);
											// if the content came from the exception process it first
											if(processText.indexOf('<!-- exampleCode -->')>-1 && processNode.href.indexOf('/xhtml/')>-1){
												processText = processText.split('<!-- exampleCode -->')[1].split('<!-- /exampleCode -->')[0];
											}
											// encode the content
											processText = processText.replace(/>/gi, '&gt;').replace(/</gi, '&lt;').replace(/\t/gi, '&nbsp;&nbsp;&nbsp;');
											// publish the content
											targetNode.innerHTML = '<pre class="codeExample">' + processText + '</pre>';
										}
				// events
				this.loadFile		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											var ssc = classBehaviours.handlers.showSourceCode;
											// process the link for an exception
											targetLink = (objNode.href.indexOf('/xhtml/')>-1) ? document.location.href : objNode.href;
											// load the targeted file
											classBehaviours.ajax.addRequest(targetLink, ssc.processFile, ssc.waitForFile, null, objNode);
											// cancel the click
											return false;
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.showSourceCode = new ShowSourceCode;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.showSourceCode;
			
			// Filter the contents of a table based on a keyword
			function FilterTableContents(){
				// properties
				this.name 			= 	'filterTableContents';
				// methods
				this.start			=	function(node){
											// if this is the button set the click event
											if(node.nodeName == 'BUTTON'){
												node.onclick = this.filter
											// else set the onchange event
											}else{
												node.onchange = this.filter
												node.onkeyup = this.filter;
											}
										}
				// events
				this.filter			=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;										
											// if this is the button get the input field
											if(objNode.nodeName == 'BUTTON') objNode = classBehaviours.utilities.previousNode(objNode);
											// get the value from the input field
											keyWord = objNode.value;
											// for all table rows show or hide the row if it matches the keywords or not
											parentTable = classBehaviours.utilities.rootNode(objNode, 'TABLE');
											allRows = parentTable.getElementsByTagName('tbody')[0].getElementsByTagName('tr');
											for(var a=0; a<allRows.length; a++){
												// if(allRows[a].innerHTML.indexOf(keyWord)>-1) classBehaviours.fader.setFade(allRows[a], 100)
												// else classBehaviours.fader.setFade(allRows[a], 50)
												allRows[a].style.display = (allRows[a].innerHTML.indexOf(keyWord)>-1) ? classBehaviours.utilities.getVisibleState(allRows[a]) : 'none' ;
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.filterTableContents = new FilterTableContents;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.filterTableContents;
			
			// Change a Form's Layout Based on its Values
			function DisplayOnValue(){
				// properties
				this.name 			= 	'displayOnValue';
				this.index			=	0;
				// methods
				this.start			=	function(node){
											// find the refered id
											referedIds = classBehaviours.utilities.getClassParameter(node, 'id', '').split(',');
											for(var a=0; a<referedIds.length; a++){
												if(referedIds[a]!=''){
													referedObj = new Array(document.getElementById(referedIds[a]));
													// if this element is a radio button, get its peers
													if(referedObj[0].type=='radio') referedObj = document.getElementsByName(referedObj[0].name);
													// set its event handlers
													for(var b=0; b<referedObj.length; b++){
														if(referedObj[b].type=='radio'){
															referedObj[b].onclick = this.changed;
															referedObj[b].onchange = this.changed;
														}else{
															referedObj[b].onfocus = this.changed;
															referedObj[b].onchange = this.changed;  
														}
													}
													// delay and check the initial value
													this.update(node);
													node.id = (node.id) ? node.id : this.name + this.index++ ;
													setTimeout('classBehaviours.handlers.displayOnValue.update(document.getElementById("' + node.id + '"))', 256);
												}
											}
										}
				this.update			=	function(objNode){
											// compare element
											compareIds = classBehaviours.utilities.getClassParameter(objNode, 'id', 'undefined').split(',');
											// get the required value
											compareValues = classBehaviours.utilities.getClassParameter(objNode, 'value', 'undefined').split(',');
											// for all id value pairs
											compareDisplay = true;
											for(var a=0; a<compareIds.length; a++){
												if(compareIds[a]!=''){
													// get the refered input
													compareObj = document.getElementById(compareIds[a]);
													// get the input value
													compareValue = compareObj.value;
													// get the checked status (if applicable)
													compareChecked = (typeof(compareObj.checked)!='undefined') ? compareObj.checked : compareValue==compareValues[a] ;
													// decide on the visibility of this form part
													compareDisplay = (compareChecked && compareDisplay);
												}
											}
											// show or hide the form part
											objNode.style.display = (compareDisplay) ? classBehaviours.utilities.getVisibleState(objNode) : 'none';
											// apply new odd and even pattern
											tableNode = classBehaviours.utilities.rootNode(objNode, 'TABLE');
											classBehaviours.handlers.zebraTable.process(tableNode);
										}
				// events
				this.changed		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// find the root of the form
											rootNode = classBehaviours.utilities.rootNode(objNode, 'FIELDSET');
											// run update all elements
											classBehaviours.parser.parseNode(rootNode);
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.displayOnValue = new DisplayOnValue;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.displayOnValue;
			
			// Filter the contents of a table based on a keyword
			function MaxLength(){
				// properties
				this.name 			= 	'maxLength';
				// methods
				this.start			=	function(node){
											// set the event handlers of this element
											node.onkeydown = this.restrict;
											node.onkeyup = this.restrict;
											node.onchange = this.restrict;
											// initial value
											this.restrict(node);
										}
				// events
				this.restrict		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// get the limit value
											lengthLimit = parseInt(classBehaviours.utilities.getClassParameter(objNode, 'max', '140'));
											// get the output indicator
											outputIndicator = classBehaviours.utilities.getClassParameter(objNode, 'id', null);
											// refuse new input if the limit is reached
											keyPress = (typeof(event)!='undefined')? event.keyCode : that.which ;
											if(objNode.value.length==lengthLimit+1 && keyPress!=8 && keyPress!=46) return false;
											// measure the length of the content
											if(objNode.value.length>lengthLimit) objNode.value = objNode.value.substring(0, lengthLimit);
											// update the indicator
											if(outputIndicator!=null) document.getElementById(outputIndicator).innerHTML = lengthLimit - objNode.value.length;
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.maxLength = new MaxLength;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.maxLength;
			
			// Calculate the sum total of a set of input fields
			function SumOfInput(){
				// properties
				this.name 			= 	'sumOfInput';
				// methods
				this.start			=	function(node){
											// if this is the input field
											if(typeof(node.value)!='undefined'){
												// add the events
												node.onchange = this.calculate;
												node.onkeyup = this.calculate;
												// initial value
												this.calculate(node);
											}
										}
				// events
				this.calculate		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// get the target id
											targetId = classBehaviours.utilities.getClassParameter(objNode, 'id', 'frmSumTotal');
											targetNode = document.getElementById(targetId);
											// get all elements with the same classname as this one
											sourceNodes = classBehaviours.utilities.getElementsByClassName('id_' + targetId);
											// for all elements
											totalValue = 0;
											for(var a=0; a<sourceNodes.length; a++){
												// add the values to a total
												inputValue = parseFloat(sourceNodes[a].value);
												totalValue += (isNaN(inputValue)) ? 0 : inputValue;
											}
											// output the total to the target id
											targetNode.innerHTML = totalValue;
											// get the limits
											minValue = parseInt(classBehaviours.utilities.getClassParameter(targetNode, 'min', '0'));
											maxValue = parseInt(classBehaviours.utilities.getClassParameter(targetNode, 'max', '100'));
											// change the class of the id if the limits are reached
											if(totalValue<minValue) targetNode.className = targetNode.className.replace('inLimit','underLimit').replace('overLimit','underLimit')
											else if(totalValue>maxValue) targetNode.className = targetNode.className.replace('inLimit','overLimit').replace('underLimit','overLimit')
											else targetNode.className = targetNode.className.replace('overLimit','inLimit').replace('underLimit','inLimit');
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.sumOfInput = new SumOfInput;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.sumOfInput;

			function PostAction() {
			    // properties
			    this.name = 'postAction';
			    // methods
			    this.start = function(node) {
			        // set the event handlers of this element
			        node.onclick = this.click;
			    }
			    // events
			    this.click = function(that) {
			        var objNode = (typeof (this.nodeName) == 'undefined') ? that : this;
			        // get the limit value
			        document.forms[0].action = 'http://yourzine.tripolis.com/public/forms/Iimlo_QQ3fgavY+WggpKmQ/KzkH7hYz02yMUX93ZGc2EQ/webforms.html';
			        document.forms[0].submit();
			        return;
			    }
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.postAction = new PostAction;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.postAction;


			
			// Use a Sprite-sheet as a Font
			function SpriteFont(){
				// properties
				this.name 			= 	'spriteFont';
				// methods
				this.start			=	function(node){
											if(node.nodeName=='BUTTON')
												node.onclick = this.calibrate
											else
												this.process(node);
										}
				// events
				this.calibrate		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// get the target area
											mapObjId = classBehaviours.utilities.getClassParameter(objNode, 'map', null);
											mapObj = document.getElementById(mapObjId);
											// get the target font
											fontId = classBehaviours.utilities.getClassParameter(objNode, 'font', null);
											fontObj  = document.getElementById(fontId);
											// get the target size
											sizeId = classBehaviours.utilities.getClassParameter(objNode, 'size', null);
											sizeObj = document.getElementById(sizeId);
											// get the target size
											matrixId = classBehaviours.utilities.getClassParameter(objNode, 'matrix', null);
											matrixObj = document.getElementById(matrixId);
											// get the target size
											limitId = classBehaviours.utilities.getClassParameter(objNode, 'limit', '127');
											limitObj = document.getElementById(limitId);
											// for every ascii character in the sprite map
											mapObj.innerHTML = '';
											b = 0;
											for(var a=33; a<parseInt(limitObj.value); a++){
												// put a letter in a span in the title
												newSpan = document.createElement('SPAN');
												if(b%16==0) newSpan.className = 'clear';
												newText = (a!=60 && a!=48) ? document.createTextNode(String.fromCharCode(a)) : document.createTextNode(' ') ;
												newSpan.appendChild(newText);
											//	newSpan.style.border = 'solid 1px red';
												mapObj.appendChild(newSpan);
												b++
											}
											// set the required styles
											mapObj.style.height = ((parseInt(limitObj.value) - 33) / 16 * (parseInt(sizeObj.value) + 8) * 1.3) + 'px';
											mapObj.style.fontFamily = fontObj.value;
											mapObj.style.fontSize = sizeObj.value;
											mapObj.style.lineHeight = '100%';
											// for span in the title
											fontDimensions = '';
											allSpans = mapObj.getElementsByTagName('SPAN');
											for(var a=0; a<allSpans.length; a++){
												// measure its dimensions
												fontDimensions += allSpans[a].offsetWidth + ',';
											}
											fontDimensions += allSpans[0].offsetHeight;
											// store the size lookup table for the user
											matrixObj.value = fontDimensions;
										}
				this.process		=	function(that){
											var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
											// get the size matrix
											sizeMatrixId = classBehaviours.utilities.getClassParameter(objNode, 'matrix', '');
											sizeMatrix = document.getElementById(sizeMatrixId).value.split(',');
											for(var a=0; a<sizeMatrix.length; a++) sizeMatrix[a] = parseInt(sizeMatrix[a]);
											// take the string in this title
											titleChars = objNode.innerHTML.replace(/&amp;/gi, '&').replace(/&gt;/gi, '>').replace(/&lt;/gi, '<').replace(/^\s*/, "").replace(/\s*$/, "");
											objNode.innerHTML = '';
											// for every letter in the title
											for(var a=0; a<titleChars.length; a++){
												// what character are we replacing
												titleChar = titleChars.substring(a, a+1);
												titleNum = titleChar.charCodeAt(0);
									debug(titleChar, titleNum)
												// only allow alphanumerics
												if(titleNum>32){
													// make a span
													newSpan = document.createElement('SPAN');
													// set its dimensions
													newSpan.style.width = (sizeMatrix[titleNum - 33] - 8) + 'px';
													newSpan.style.height = (sizeMatrix[sizeMatrix.length-1] - 8) + 'px';
													// float it
													newSpan.style.float = 'left';
												//	newSpan.style.border = 'solid 1px red';
													// set the background position to position the sprite-sheet
													rowNum = parseInt((titleNum - 33) / 16);
													yPos = parseInt(rowNum * sizeMatrix[sizeMatrix.length-1]);
													xPos = 0;
													for(var b=(rowNum*16); b<(titleNum-33); b++) xPos += sizeMatrix[b];
													newSpan.style.backgroundPosition = '-' + (xPos+8) + 'px -' + (yPos+8) + 'px';
													// include the span
													objNode.appendChild(newSpan);
												}
												if(titleNum==32){
													// make a span
													newSpan = document.createElement('SPAN');
													// set its dimensions
													newSpan.style.width = (sizeMatrix[0] - 8) + 'px';
													newSpan.style.height = (sizeMatrix[sizeMatrix.length-1] - 8) + 'px';
													// float it
													newSpan.style.float = 'left';
												//	newSpan.style.border = 'solid 1px red';
													// set the background position to position the sprite-sheet
													newSpan.style.backgroundPosition = '100% 100%';
													// include the span
													objNode.appendChild(newSpan);
												}
											}
											// add a line-break
											newDiv = document.createElement('DIV');
											newDiv.className = 'clear';
											objNode.appendChild(newDiv);
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.spriteFont = new SpriteFont;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.spriteFont;

	// short-cut wrapper functions
	debug = classBehaviours.console.debug;
		// start the parsing of classes
	classBehaviours.parser.start();
	
