/*	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;
											}
			// determines 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;									// 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){									// 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
									nodeWidth = node.offsetWidth;
									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';
								}
			this.getClip	=	function(){}
			this.setClip	=	function(){}			// 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 = 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.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);}
								}
			this.clip		=	function(id, start, end, step, delay, acceleration, evalOnEnd){}
			/* START: legacy functions */			this.fadeIn		=	function(idIn, step, delay, evalEvent, acceleration){									var cf = classBehaviours.fader;									// get the fading object									node = document.getElementById(idIn);									// get the current fade									fade = cf.getFade(node) + step;									// if not 100%									if((fade)<100){										// set the new fade										cf.setFade(node, fade);										// next step										cf.timeOut = setTimeout("classBehaviours.fader.fadeIn('"+idIn+"',"+step+","+delay+",'"+evalEvent+"')", delay);									// else									}else{										// set the fade to 100%										cf.setFade(node, 100);										// trigger the end event										eval(evalEvent);									}								}			this.fadeOut	=	function(idOut, step, delay, evalEvent, acceleration){									var cf = classBehaviours.fader;									// get the fading object									node = document.getElementById(idOut);									// get the current fade									fade = cf.getFade(node) - step;									// if not 100%									if(fade>0){										// set the new fade										cf.setFade(node, fade);										// next step										cf.timeOut = setTimeout("classBehaviours.fader.fadeOut('"+idOut+"',"+step+","+delay+",'"+evalEvent+"')", delay);									// else									}else{										// set the fade to 100%										cf.setFade(node, 0);										// trigger the end event										eval(evalEvent);									}								}			this.crossFade	=	function(idIn, idOut, amount, step, delay, evalEvent, acceleration){									var cf = classBehaviours.fader;									// if the amount is not the end value yet									if(amount<=100){										// set the fade amounts										if(idIn!=null && idIn!=""){											// unhide the new page											document.getElementById(idIn).style.display = 'block';											// set the fade amount											cf.setFade(document.getElementById(idIn), amount);										}										if(idOut!=null && idOut!="" && idOut!="null"){											// unhide the new page											document.getElementById(idOut).style.display = 'block';											// set the fade amount											cf.setFade(document.getElementById(idOut), 100-amount);										}										// construct the fade function										var evalLoop = "classBehaviours.fader.crossFade('"+idIn+"', '"+idOut+"', "+(amount+step)+", "+step+", "+delay+", '"+evalEvent+"')";										// repeat the fade										setTimeout(evalLoop, delay);									}else{									// else										// cancel the opacity style										if(idIn && idIn!=""){
											var node = document.getElementById(idIn);											if(typeof(node.style.MozOpacity)!='undefined')	node.style.MozOpacity = 'auto';											if(typeof(node.style.filter)!='undefined')		node.style.filter = 'none';											if(typeof(node.style.opacity)!='undefined')		node.style.opacity = 'auto';
										}										// hide the old page										if(idOut && idOut!="" && idOut!="null") document.getElementById(idOut).style.display = 'none';										// trigger the end event										cf.onEnd(evalEvent);									}								}
			this.grow		=	function(idIn, step, delay, evalEvent, acceleration){
									var cf = classBehaviours.fader;									// get the fading object									node = document.getElementById(idIn);									// get the current size									xSize = 0; // cf.getSize(node)[0] + step;									ySize = cf.getSize(node)[1] + step;
									// get the maximum size									xMax = 0; // cf.getSize(node)[2];									yMax = cf.getSize(node)[3];									// if not 100%									if(xSize<xMax || ySize<yMax){										// set the new size										cf.setSize(node, xSize, ySize);										// next step										cf.timeOut = setTimeout("classBehaviours.fader.grow('"+idIn+"',"+step+","+delay+",'"+evalEvent+"')", delay);									// else									}else{										// trigger the end event										eval(evalEvent);									}
								}
			this.shrink		=	function(idOut, step, delay, evalEvent, acceleration){
									var cf = classBehaviours.fader;									// get the fading object									node = document.getElementById(idOut);									// get the current size									xSize = 0; // cf.getSize(node)[0] - step;									ySize = cf.getSize(node)[1] - step;									// if not 100%									if(xSize>0 || ySize>0){										// set the new size										cf.setSize(node, xSize, ySize);										// next step										cf.timeOut = setTimeout("classBehaviours.fader.grow('"+idOut+"',"+step+","+delay+",'"+evalEvent+"')", delay);									// else									}else{										// trigger the end event										eval(evalEvent);									}
								}
			this.reveal		=	function(id, width, height, step, delay, evalEvent){
									var cf = classBehaviours.fader;
									// get the current values and convert them into numbers
									panelStyle = document.getElementById(id).style.clip;
									panelClip = (panelStyle!='') ? panelStyle.replace('rect(', '').replace(')', '').replace(/,/gi, '').split(' ') : new Array(0,0,0,0) ;
									for(var a=0; a<4; a++) panelClip[a] = (panelClip[a]=='auto') ? 9999 : parseInt(panelClip[a]) ;
									// update the clip amount
									panelClip[0] = panelClip[0];
									panelClip[1] = (panelClip[1]<width) ? panelClip[1]+step : width ;
									panelClip[2] = (panelClip[2]<height) ? panelClip[2]+step : height ;
									panelClip[3] = panelClip[3];
									// update the clipping settings
									panelTop = panelClip[0] + 'px';
									panelRight = (width<0) ? 'auto' : panelClip[1] + 'px';
									panelBottom = (height<0) ? 'auto' : panelClip[2] + 'px';
									panelLeft = panelClip[0] + 'px';
									// if the end situation wasn't reached yet
									if(panelClip[1]<width || panelClip[2]<height){
										// set the new clipping
										document.getElementById(id).style.clip = 'rect('+panelTop+' '+panelRight+' '+panelBottom+' '+panelLeft+')';
										// order the next step
										setTimeout('classBehaviours.fader.reveal("'+id+'", '+width+', '+height+', '+delay+', '+step+')', delay);
									}else{
										// set the default clipping
										document.getElementById(id).style.clip = 'rect(auto auto auto auto)';
										// trigger the end event
										cf.onEnd(evalEvent);
									}
								}
			this.vanish		=	function(id, evalEvent){
									var cf = classBehaviours.fader;
									// update the clipping settings
									parentPanel = document.getElementById(id);
									parentPanel.style.clip = 'rect(0px 0px 0px 0px)';
									// trigger the end event
									cf.onEnd(evalEvent);
								}			// events			this.onEnd		=	function(evalEvent){									eval(evalEvent);								}
			/* 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_active.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.color=='') 		debugConsole.style.color = '#000000';
									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;
					
			// 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;
					
			// 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;
						
			// 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';
													if(peerContainer.getElementsByTagName("ul").length>0 && !document.all) peerContainer.getElementsByTagName('ul')[0].style.overflow = 'hidden';
													// 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+'")); if(document.getElementById("'+peerContainer.id+'").getElementsByTagName("ul").length>0 && !document.all) document.getElementById("'+peerContainer.id+'").getElementsByTagName("ul")[0].style.overflow = "auto"');
												}
												// 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';
													if(peerContainer.getElementsByTagName("ul").length>0 && !document.all) peerContainer.getElementsByTagName('ul')[0].style.overflow = 'hidden';
													// close the container
													classBehaviours.fader.size(peerContainer.id, null, 1, t2n.step ,t2n.delay, t2n.acceleration, 'classBehaviours.handlers.hideThisNode.start(document.getElementById("'+peerContainer.id+'"))');
												}
											}
										}
			}
			// add this function to the classbehaviour object
			classBehaviours.handlers.toggleNextNode = new ToggleNextNode;
			classBehaviours.handlers.index[classBehaviours.handlers.index.length] = classBehaviours.handlers.toggleNextNode;
							
			// 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;
						
			// 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;
							
			// 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;
						
			// 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 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;
						
			// 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.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 '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;
													}
				}
			// 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;
									}
			}
			// 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;
			
			// 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;
					
			// 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;
								
	// short-cut wrapper functions
	debug = classBehaviours.console.debug;
		// start the parsing of classes
	classBehaviours.parser.start();
	
