/*
name			: Class Behaviour
update			: 20070705
author			: Maurice van Creij
dependencies		: lib_classbehaviour.js
info				: http://www.woollymittens.nl/content/details.asp?id=20040805133501
*/
	// MAIN
	// main class-behaviour object
	function ClassBehaviour(){
		/* properties */
			this.handlers			=	new Array();
		/* methods */
			// parse the document for classnames
			this.parseDocument		=	function(node){
											target = (node) ? node : document;
											// get all document nodes
											var allNodes = (target.all) ? target.all : target.getElementsByTagName("*");
											// for all tags
											for(var a=0; a<allNodes.length; a++){
												// if the item has a className
												if(allNodes[a].className){
													// get the classname
													nodeClass = allNodes[a].className;
													// for all behaviours
													for(var b=0; b<this.handlers.length; b++){
														// if the behaviour's name exists in the class name, apply it's events
														if(nodeClass.indexOf(this.handlers[b].name)>-1) this.handlers[b].start(allNodes[a]);
													}
												}
											}
										}
			// (cross)fader and pseudo event handler
			this.fader				=	new Fader;
			// helper functions
			this.utilities			=	new Utilities;
	}
	// create the main class-behaviour object
	var classBehaviour = new ClassBehaviour;
	
	// UTILITIES
		function Utilities(){
			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 ;
										}
			// returns a string of parameters found in the classname which can be [eval]uated
			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 ;
										}
			// get the previous node without worrying about text nodes
			this.nextNode			=	function(node){
											// look for the next html node
											do {
												node = node.nextSibling;
											} while(node.nodeName.indexOf('#text')>-1);
											// return it
											return node;
										}
			// get the next node without worrying about text nodes
			this.previousNode		=	function(node){
											// look for the previous html node
											do {
												node = node.previousSibling;
											} while(node.nodeName.indexOf('#text')>-1);
											// return it
											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;
										}
		}
		
		function Fader(){
			/* properties */
			/* methods */
			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.fadeIn		=	function(idIn, step, delay, evalEvent){
									var cf = classBehaviour.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("classBehaviour.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){
									var cf = classBehaviour.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("classBehaviour.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){
									var cf = classBehaviour.fader;
									// if the amount is not the end value yet
									if(amount<=100){
										// set the fade amounts
										if(idIn && idIn!=""){
											// unhide the new page
											document.getElementById(idIn).style.display = 'block';
											// set the fade amount
											cf.setFade(document.getElementById(idIn), amount);
										}
										if(idOut && idOut!=""){
											// 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 = "classBehaviour.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!="") document.getElementById(idOut).style.display = 'none';
										// trigger the end event
										cf.onEnd(evalEvent);
									}
								}
			/* events */
			this.onEnd		=	function(evalEvent){
									eval(evalEvent);
								}
		}
		
	// BEHAVIOURS
	// blinks
		// define this class behaviour
		function Blink(){
			/* properties */
			this.name 		= 	'blink';
			this.nodes 	= 	new Array();
			/* methods */
			this.start		=	function(node){
									// set the starting class, if not present
									if(node.className.indexOf('blinkon')<0) node.className += " blinkon";
									// make new blink entry
									this.nodes[this.nodes.length] = new Array(node,null,1024);
									// start blink loop
									this.loop(this.nodes.length-1);
								}
			/* events */
			this.loop		=	function(blinkIndex){
									// what object goes with this index
									blinkObject = this.nodes[blinkIndex][0];
									// toggle the blink class of this object
									blinkObject.className = (blinkObject.className.indexOf('blinkoff')>-1) ? blinkObject.className.replace('blinkoff','blinkon') : blinkObject.className.replace('blinkon','blinkoff');
									// set timeout till the next blink toggle
									this.nodes[blinkIndex][1] = setTimeout('classBehaviour.blink.loop('+blinkIndex+')',this.nodes[blinkIndex][2]);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.blink = new Blink;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.blink;
		
	// replace in class
		// define this class behaviour
		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 = classBehaviour.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 = classBehaviour.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 = classBehaviour.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
		classBehaviour.classMouseHover = new ClassMouseHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.classMouseHover;
		
	// make all sub elements fake the :hover attribute with .hover
		// define this class behaviour
		function PseudoHover(){
			/* properties */
			this.name 		= 	'pseudoHover';
			/* methods */
			this.start		=	function(node){
									// get all elements
									allNodes = node.getElementsByTagName('LI');
									// for all elements
									for(var a=0; a<allNodes.length; a++){
										// add the hover event
										classBehaviour.classMouseHover.start(allNodes[a]);
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.pseudoHover = new PseudoHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.pseudoHover;
		
	// replace in src sub-string
		// define this class behaviour
		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
		classBehaviour.srcMouseHover = new SrcMouseHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.srcMouseHover;
		
	// replace in src sub-string
		// define this class behaviour
		function FadeMouseHover(){
			/* properties */
			this.name 			= 'fadeMouseHover';
			this.cache 			= new Array();
			this.count			= 0;
			this.timeOut		= null;
			/* methods */
			this.start			=	function(node){
										this.cacheImages(node);
										// node.onload = this.setUpFader;
										this.setUpFader(node);
									}
			this.setUpFader		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var fmh = classBehaviour.fadeMouseHover;
										// give this image an id, if it doesn't have one
										if(!objNode.id) objNode.id = 'fadingImage' + fmh.count;
										fmh.count += 1;
										// set the active version of the image source as a background-image of the container
										objNode.parentNode.style.backgroundImage = 'url(' + objNode.src.replace('_link','_hover') + ')';
										// set the image as a block element
										objNode.parentNode.style.display = 'block';
										objNode.parentNode.style.width = objNode.width + 'px';
										objNode.parentNode.style.height = objNode.height + 'px';
										// set the default fade
										classBehaviour.fader.setFade(objNode, 100);
										// set up the events
										objNode.onmouseover = fmh.addHover;
										objNode.onmouseout = fmh.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');
									}
			/* events */
			this.addHover 	= 	function(that, id){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var fmh = classBehaviour.fadeMouseHover;
									// if an id is passed. It overrides the event node
									if(id) objNode = document.getElementById(id);
									// if there's no fade active at the moment // fade out the image
									if(classBehaviour.fader.getFade(objNode)%100==0){
										classBehaviour.fader.fadeOut(objNode.id, 20, 50, '');
									// else try again in a bit
									}else{
										// fmh.timeOut = setTimeout("classBehaviour.fadeMouseHover.addHover(null, '" + objNode.id + "')",50);
									}
								}
			this.remHover 	= 	function(that, id){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var fmh = classBehaviour.fadeMouseHover;
									// if an id is passed. It overrides the event node
									if(id) objNode = document.getElementById(id);
									// if there's no fade active at the moment // fade in the image
									if(classBehaviour.fader.getFade(objNode)%100==0){
										classBehaviour.fader.fadeIn(objNode.id, 20, 50, '');
									// else try again in a bit
									}else{
										fmh.timeOut = setTimeout("classBehaviour.fadeMouseHover.remHover(null, '" + objNode.id + "')",50);
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.fadeMouseHover = new FadeMouseHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.fadeMouseHover;
		
	// hides nodes
		// hide the "hideThisNode" class behaviour by default 
		document.writeln("<style>.hideThisNode{overflow:hidden; visibility:hidden; height:1px;}</style>");
		// define this class behaviour
		function HideThisNode(){
			/* properties */
			this.name 		= 	'hideThisNode';
			/* methods */
			this.start		=	function(node){
									node.style.overflow = 'hidden';
									node.style.visibility = 'hidden';
									node.style.height = '1px';
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.hideThisNode = new HideThisNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.hideThisNode;
		
	// explicit opposite of a hidden node
		// define this class behaviour
		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';
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.showThisNode = new ShowThisNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.showThisNode;
		
	// show or hide a node
		// define this class behaviour
		document.writeln("<style>.toggleNextNode{cursor:pointer;}</style>");
		function ToggleNextNode(){
			/* properties */
			this.name 		= 	'toggleNextNode';
			this.nodes		=	new Array();
			this.step		=	10;
			this.delay		=	10;
			this.index		=	0;
			/* methods */
			this.start		=	function(node){
									// set the event handlers for the source node
									node.onclick = this.toggle;
									// add this node to the node list
									this.nodes[this.nodes.length] = node;
									// give this node an id if it doesn't have one yet
									node.id = (node.id) ? node.id : this.name + this.nodes.length ;
									// is this node marked as "auto", order it to open on a timeout
									autoDelay = classBehaviour.utilities.getClassParameter(node, 'auto', null);
									if(autoDelay){
										this.index++
										node.id = (node.id) ? node.id : this.name + this.index ;
										setTimeout('classBehaviour.toggleNextNode.toggle(document.getElementById("'+node.id+'"))', autoDelay);
									}
								}
			this.shrink	=	function(label, container, finished){
									var t2n = classBehaviour.toggleNextNode;
									// deactivate the label
									label.className = label.className.replace('active','link');
									label.parentNode.className = label.parentNode.className.replace('active','link');
									// if the container isn't shrunk completely
									if(container.offsetHeight>t2n.step){
										// height before
										heightBefore = container.style.height;
										// reduce its height by an amount
										container.style.overflow = 'hidden';
										container.style.visibility = 'visible';
										container.style.height = (container.offsetHeight - t2n.step) + 'px';
										// height after
										heightAfter = container.style.height;
										// the resizing isnt' working
										if(heightBefore==heightAfter){
											// skip straight to the end situation
											container.style.overflow = 'hidden';
											container.style.visibility = 'hidden';
											container.style.height = '1px';
											container.className = container.className.replace('showThisNode','hideThisNode');
										// else
										}else{
											// mark the function as unfinished
											finished = false;
										}
									}else{
										// close the container
										container.style.overflow = 'hidden';
										container.style.visibility = 'hidden';
										container.style.height = '1px';
										container.className = container.className.replace('showThisNode','hideThisNode');
									}
									// return the state
									return finished;
								}
			this.grow		=	function(label, container, finished){
									var t2n = classBehaviour.toggleNextNode;
									// activate the label
									label.className = label.className.replace('link','active').replace('hover','active');
									label.parentNode.className = label.parentNode.className.replace('link','active').replace('hover','active');
									// measure the height of all the childnodes of the container
									totalHeight = 0;
									contents = container.childNodes;
									for(var a=0; a<contents.length; a++){
										totalHeight += (contents[a].offsetHeight) ? contents[a].offsetHeight : 0 ;
									}
									// if the container isn't grown completely
									if(container.offsetHeight<totalHeight-t2n.step){
										// height before
										heightBefore = container.style.height;
										// increase its height by an amount
										container.style.overflow = 'hidden';
										container.style.visibility = 'visible';
										container.style.height = (container.offsetHeight + t2n.step) + 'px';
										// height after
										heightAfter = container.style.height;
										// the resizing isnt' working
										if(heightBefore==heightAfter){
											// skip straight to the end situation
											container.style.overflow = 'visible';
											container.style.visibility = 'visible';
											container.style.height = 'auto';
											container.className = container.className.replace('hideThisNode','showThisNode');
										// else
										}else{
											// mark the function as unfinished
											finished = false;
										}
									}else{
										// open the container
										container.style.overflow = 'visible';
										container.style.visibility = 'visible';
										container.style.height = 'auto';
										container.className = container.className.replace('hideThisNode','showThisNode');
									}
									// return the state
									return finished;
								}
			/* events */
			this.toggle 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var t2n = classBehaviour.toggleNextNode;
									// get all information on this node
									targetLabel = objNode;
									targetContainerId = classBehaviour.utilities.getClassParameter(targetLabel, 'id', null);
									targetContainer = (targetContainerId) ? document.getElementById(targetContainerId) : classBehaviour.utilities.nextNode(targetLabel) ;
									targetGrows = (targetContainer.className.indexOf('hideThisNode')>-1);
									// call for the node to update
									t2n.update(targetLabel.id, targetGrows);
									// cancel the click
									return false;
								}
			this.update	=	function(id, grows){
									var t2n = classBehaviour.toggleNextNode;
									// finished marker
									finished = true;
									// get all information on this node
									targetLabel = document.getElementById(id);
									targetContainerId = classBehaviour.utilities.getClassParameter(targetLabel, 'id', null);
									targetContainer = (targetContainerId) ? document.getElementById(targetContainerId) : classBehaviour.utilities.nextNode(targetLabel) ;
									targetFamily = classBehaviour.utilities.getClassParameter(targetLabel, 'family', null);
									// for every node in the node-list
									for(var a=0; a<t2n.nodes.length; a++){
										// get its family
										peerLabel = t2n.nodes[a];
										peerContainerId = classBehaviour.utilities.getClassParameter(peerLabel, 'id', null);
										peerContainer = (peerContainerId) ? document.getElementById(peerContainerId) : classBehaviour.utilities.nextNode(peerLabel) ;
										peerFamily = classBehaviour.utilities.getClassParameter(peerLabel, 'family', null);
										// 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){
											// close the container one step
											finished = this.shrink(peerLabel, peerContainer, finished);
										// else if this node has the same id and is open
										}else if(peerLabel.id==targetLabel.id && !grows){
											// close the container one step
											finished = this.shrink(targetLabel, targetContainer, finished);
										// else 
										}else if(peerLabel.id==targetLabel.id && grows){
											// open the container one step
											finished = this.grow(targetLabel, targetContainer, finished);
										}
									}
									// if any step marked the function as unfinished
									if(!finished){
										// repeat it
										setTimeout("classBehaviour.toggleNextNode.update('"+id+"',"+grows+")", t2n.delay);
									}else{
										// notify the iframe resizer to update its size if needed
										if(document.body.className.indexOf('resizeIframe')>-1) classBehaviour.resizeIframe.delay();
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.toggleNextNode = new ToggleNextNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.toggleNextNode;
		
	// tabbed content
		// define this class behaviour
		function TabbedContent(){
			/* properties */
			this.name 		= 	'tabbedContent';
			/* methods */
			this.start		=	function(node){
									// get all tabs
									allTabs = node.getElementsByTagName('a');
									// store the most likely opened tab
									openedTab = allTabs[0];
									// for all tabs
									for(var a=0; a<allTabs.length; a++){
										// get the id this tab refers to
										tabId = allTabs[a].href.split('#')[1];
										// apply onclick events to the referred tab
										allTabs[a].onclick = this.open;
										// apply the starting state of the tab if needed
										if(allTabs[a].className.indexOf('closedTab')<0 && allTabs[a].className.indexOf('openedTab')<0) allTabs[a].className += ' closedTab';
										// apply the starting state of the referred content if needed
										document.getElementById(tabId).style.display = 'none';
										// if this tab is referred to in the page url, remember it as active
										if(document.location.href.indexOf(allTabs[a].href)>-1) openedTab = allTabs[a];
										// if this tab was manualy set
										if(allTabs[a].className.indexOf('openedTab')>-1) openedTab = allTabs[a];
									}
									// if there is a pager
									pager = document.getElementById(classBehaviour.utilities.getClassParameter(node, 'pagerId', 'none'));
									if(pager){
										// assign the events for the buttons
										pager.getElementsByTagName('a')[0].onclick = this.previous;
										pager.getElementsByTagName('a')[1].onclick = this.next;
									}
									// open the most likely first tab
									this.open(openedTab, true);
								}
			/* events */
			this.next		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tbd = classBehaviour.tabbedContent;
									// get the pager information
									pagerInfo = objNode.parentNode.parentNode.getElementsByTagName('span')[0].firstChild.nodeValue;
									// what is the current pagenumber
									currentPage = parseInt(pagerInfo.split('/')[0]);
									// how many pages are there
									totalPages = parseInt(pagerInfo.split('/')[1]);
									// what is the next page
									nextPage = (currentPage<totalPages) ? currentPage + 1 : 1 ;
									// what is the tabs strip
									tabStrip = document.getElementById(classBehaviour.utilities.getClassParameter(objNode.parentNode.parentNode, 'tabsId', 'none'));
									if(tabStrip){
										// get the relevant page from the tab strip
										targetTab = tabStrip.getElementsByTagName('a')[nextPage-1];
										// activate it's click
										tbd.open(targetTab);
									}
								}
			this.previous	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tbd = classBehaviour.tabbedContent;
									// get the pager information
									pagerInfo = objNode.parentNode.parentNode.getElementsByTagName('span')[0].firstChild.nodeValue;
									// what is the current pagenumber
									currentPage = parseInt(pagerInfo.split('/')[0]);
									// how many pages are there
									totalPages = parseInt(pagerInfo.split('/')[1]);
									// what is the next page
									previousPage = (currentPage>1) ? currentPage - 1 : totalPages ;
									// what is the tabs strip
									tabStrip = document.getElementById(classBehaviour.utilities.getClassParameter(objNode.parentNode.parentNode, 'tabsId', 'none'));
									if(tabStrip){
										// get the relevant page from the tab strip
										targetTab = tabStrip.getElementsByTagName('a')[previousPage-1];
										// activate it's click
										tbd.open(targetTab);
									}
								}
			this.open		=	function(that, noAnimation){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tbd = classBehaviour.tabbedContent;								
			
									// INDEX THE TAB STATES
									// get all tabs
									var allTabs = objNode.parentNode.parentNode.getElementsByTagName('a');
									var prevTab = null;
									var pageNumber = 0;
									// find the current tab
									for(var a=0; a<allTabs.length; a++){
										// rememeber the previous tab
										if(allTabs[a].className.indexOf('openedTab')>-1) prevTab = allTabs[a];
										// count the new pagenumber
										if(allTabs[a]==objNode) pageNumber = a;
									}

									// if this is the current tab again
									if(prevTab!=objNode || noAnimation){
									
										// PREVIOUS TAB
										if(prevTab){
											// mark the previous tab as passive
											prevTab.className = prevTab.className.replace('openedTab', 'closedTab');
											// if the tab has an image
											tabImages = prevTab.getElementsByTagName('img');
											if(tabImages.length>0) tabImages[0].src = tabImages[0].src.replace('_active','_link');
											// id the previous tabbed content
											prevContentId = prevTab.href.split('#')[1];
										}
										
										// NEXT TAB
										// mark the next tab as active
										objNode.className = objNode.className.replace('closedTab', 'openedTab');
										// if the tab has an image
										tabImages = objNode.getElementsByTagName('img');
										if(tabImages.length>0) tabImages[0].src = tabImages[0].src.replace('_link','_active').replace('_hover','_active');
										// id the next tabbed content
										nextContentId = objNode.href.split('#')[1];
										
										// FADE ANIMATION
										isAnimated = (noAnimation) ? 'no' : classBehaviour.utilities.getClassParameter(objNode, 'animated', 'yes') ;
										if(isAnimated=='yes'){
											// make the previous tab float
											document.getElementById(prevContentId).style.position = 'absolute';
											document.getElementById(prevContentId).style.top = '0px';
											// make the next tab no float
											document.getElementById(nextContentId).style.position = 'relative';
											// order the animation
											classBehaviour.fader.crossFade(nextContentId, prevContentId, 0, 10, 50, null);
										}else{
											if(prevTab) document.getElementById(prevContentId).style.display = 'none';
											document.getElementById(nextContentId).style.display = 'block';
										}
										
										// PAGE NUMBER
										// update page-numbering
										pager = document.getElementById(classBehaviour.utilities.getClassParameter(objNode.parentNode.parentNode, 'pagerId', 'none'));
										if(pager){
											pager.getElementsByTagName('span')[0].firstChild.nodeValue = (pageNumber+1) + '/' + allTabs.length ;
										}
										
									}
									// cancel the jump to the anchor
									return false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.tabbedContent = new TabbedContent;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.tabbedContent;
				
	// replace image with transparent version, invoke activeX background loader
		// define this class behaviour
		function PngAlpha(){
			/* properties */
			this.name 		= 	'pngAlpha';
			/* methods */
			this.start		=	function(node){
									/*event*/;
									this.process(node);
									node.onload = this.process;
								}
			/* events */
			this.process 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// if the image has been processed before
									if(objNode.src.indexOf('_alpha')<0){
										// alpha image url
										var strAlphaSrc = objNode.src.replace(/\.png|\.jpg|\.gif/gi,"_alpha.png");
										// for the downlevel browser MSIE
										if(typeof(objNode.style.filter)!='undefined'){
											// change the image styles
											objNode.style.width		= objNode.width + 'px';
											objNode.style.height	= objNode.height + 'px';
											objNode.style.filter	= "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + strAlphaSrc + "', sizingMethod='crop')";
											// get the path to the image folder
											var strPathSrc = '';
											var arrPathSrc = objNode.src.split('/');
											for(var intA=0; intA<arrPathSrc.length-1; intA++){strPathSrc += arrPathSrc[intA] + '/'};
											// replace the original with the alpha variant
											objNode.src = strPathSrc + '_alpha.png';
										// for the rest of the world
										}else{
											// replace the image source with the alpha channel version
											objNode.src = strAlphaSrc;
										}
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.pngAlpha = new PngAlpha;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.pngAlpha;
		
	// Replaces all png's in the container with gif alternatives in Internet Explorer 6 and lower.
		// preload cosmetic tweak
		if(document.all && (navigator.userAgent.indexOf('MSIE 6.0')>-1 || navigator.userAgent.indexOf('MSIE 5')>-1) && navigator.userAgent.indexOf('Opera')<0)
				document.writeln("<style>.pngAlternative img, img.pngAlternative {visibility:hidden;}</style>");
		// define this class behaviour
		function PngAlternative(){
			/* properties */
			this.name 		= 	'pngAlternative';
			this.lastNode	=	null;
			this.lastNext	=	null;
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			/* events */
			this.process	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// if this is a crappy browser
									if
									(
										(navigator.userAgent.indexOf('MSIE 6.0')>-1 || navigator.userAgent.indexOf('MSIE 5')>-1)
										&& navigator.userAgent.indexOf('Opera')<0
									)
									{
										// get all image tags
										var allImages = objNode.getElementsByTagName('img');
										// if there were no images in this tag, it probably IS the image
										if(allImages.length==0) allImages = new Array(objNode);
										// for all images
										for(var a=0; a<allImages.length; a++){
											// replace it with it's gif alternative
											allImages[a].src = allImages[a].src.replace('.png', '.gif');
											allImages[a].style.visibility = 'visible';
										}
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.pngAlternative = new PngAlternative;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.pngAlternative;
		
	// Open an overlay as a popup window
		// define this class behaviour
		function OpenLayerPopUp(){
			/* properties */
			this.name 		= 	'openLayerPopUp';
			this.step		=	10;
			this.begin		=	0;
			this.end		=	50;
			/* methods */
			this.start		=	function(node){
									// find the target layer
									targetPopUp = null;
									// process the node
									this.process(node);
									// the node's open button
									node.onclick = this.show;
									// open the popup immediately if required
									if(classBehaviour.utilities.getClassParameter(node, 'auto', 'no')=='yes') this.show(node);
								}
			this.fadeIn	=	function(id, amount){
									var olp = classBehaviour.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
										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("classBehaviour.openLayerPopUp.fadeIn('" + id + "'," + (amount+olp.step) + ")",10);
									}else{
										// show the popup content
										nodeContent.style.visibility = 'visible';
									}
								}
			this.fadeOut	=	function(id, amount){
									var olp = classBehaviour.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("classBehaviour.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';
									}
								}
			/* events */
			this.process	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// prepare the popup's layout
								}
			this.show		=	function(that, id){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var olp = classBehaviour.openLayerPopUp;
									var submit = false;
									// adjust the fade parameters if it needs to open instantly
									olp.step = parseInt(classBehaviour.utilities.getClassParameter(objNode, 'step', 10));
									olp.begin = parseInt(classBehaviour.utilities.getClassParameter(objNode, 'begin', 0));
									olp.end = parseInt(classBehaviour.utilities.getClassParameter(objNode, 'end', 50));
									// is this a link with an href
									popUpId = (id) ? id : classBehaviour.utilities.getClassParameter(objNode, 'id', 'popup0') ;
									// get the popup object
									popUp = (popUpId) ? document.getElementById(popUpId) : objNode;
									// position the popup
										// the dimensions can not be measured with "display:none;"
										popUp.style.visibility = 'hidden';
										popUp.style.display = 'block';
										// get the content segment
										popupContent = popUp.getElementsByTagName('DIV')[2];
										// how high is the content
										popupHeight = popupContent.offsetHeight;
										// how high is the screen
										screenHeight = popupContent.parentNode.offsetHeight;
										// center the popup
										popupContent.style.marginTop = Math.round((screenHeight-popupHeight)/2) + 'px' ;
										// the dimensions can not be measured with "display:none;"
										popUp.style.visibility = 'visible';
										popUp.style.display = 'block';
									// if there is an iframe in the popup load the url into it
									popUpIframes = popUp.getElementsByTagName('iframe');
									popUpTitles = popUp.getElementsByTagName('h1');
									if(popUpIframes.length>0){
										// is an href supplied
										if(objNode.href){
											// if the link had a title and if the popup has a title. put the link title in the popup
											if(objNode.title && popUpTitles.length>0) popUpTitles[0].innerHTML = objNode.title;
											// load the href in the iframe
											popUpIframes[0].src = objNode.href;
										// is this a form submit
										}else if(objNode.nodeName=="BUTTON" || objNode.nodeName=="INPUT"){
											// find the form this button belongs to
											formNode = objNode.parentNode;
											while(formNode.nodeName!='FORM') formNode = formNode.parentNode;
											// change the form to submit to the iframe
											formNode.target = popUpIframes[0].id;
											// then change it back for the other sumbit buttons
											setTimeout("document.getElementById('"+formNode.id+"').target='_self';",512);
											// allow the function to submit
											submit = true;
										}
									}
									// find the close gadget
									popUpCloser = popUp.getElementsByTagName('a')[0];
									popUpCloser.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(popUp.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
											popUp.getElementsByTagName('DIV')[2].style.marginTop = Math.round(document.documentElement.scrollTop + (screenHeight-popupHeight)/2) + 'px' ;
										}
										// size the shadow under the popup
										popUp.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';
									}
									// fade the popup in
									olp.fadeIn(popUp.id, olp.begin);
									// mark the body with a class
									document.body.className += " hasLayerPopUp";
									// cancel the click
									return submit;
								}
			this.hide		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var olp = classBehaviour.openLayerPopUp;
									// the popup object
									popUp = objNode.parentNode.parentNode.parentNode;
									// fade the popup out
									olp.fadeOut(popUp.id, 50);
									// 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 = "auto";
										// show the selects
										allSelects = document.getElementsByTagName('select');
										for(var a=0; a<allSelects.length; a++) allSelects[a].style.visibility = 'visible';
									//}
									// unmark the body class
									document.body.className = document.body.className.replace(" hasLayerPopUp", "");
									// clear the iframe contents
									popUpIframes = popUp.getElementsByTagName('iframe');
									if(popUpIframes.length>0){
										popUpIframes[0].src = "";
									}
									// cancel the click
									return false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.openLayerPopUp = new OpenLayerPopUp;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.openLayerPopUp;
		
	// handle ondrag events
		// define this class behaviour
		function DragAndDrop(){
			/* properties */
			this.name 		= 	'dragAndDrop';
			this.node		=	null;
			this.grid		=	new Coordinates(16,16);
			this.minPos	=	new Coordinates();
			this.maxPos	=	new Coordinates();
			this.pickup	=	new Coordinates();
			this.mouse		=	new Coordinates();
			this.style		=	new Coordinates();
			this.onMove	=	null;
			/* methods */
			this.start		=	function(node){
									// event
									node.onmousedown 			= this.pickUp;
									document.onmouseup 			= this.dropDown;
										// document.onmousemove 		= this.moveAway;
									node.onmousemove 			= this.moveAway;
									// exctract the limits from the class parameters
									this.grid.x	=	parseInt(classBehaviour.utilities.getClassParameter(node, 'gridX', null));
									this.grid.y	=	parseInt(classBehaviour.utilities.getClassParameter(node, 'gridY', null));
									this.minPos.x	=	parseInt(classBehaviour.utilities.getClassParameter(node, 'limitLeft', null));
									this.minPos.y	=	parseInt(classBehaviour.utilities.getClassParameter(node, 'limitTop', null));
									this.maxPos.x	=	parseInt(classBehaviour.utilities.getClassParameter(node, 'limitRight', null));
									this.maxPos.y	=	parseInt(classBehaviour.utilities.getClassParameter(node, 'limitBottom', null));
									// saved position
									this.restore(node);
								}
			this.restore 	= 	function(objNode){
									// is lib_cookies available
									if(typeof(setCookie)!='undefined'){
										var strStyles, arrStyles;
										// retrieve styles string
										strStyles = getCookie('dragposition');					
										// were any styles recovered
										if(strStyles!=null){
											arrStyles = strStyles.split(',');
											// does the stored positions match the object
											if(arrStyles[0]==objNode.id && arrStyles.length>2){
												objNode.style.left = arrStyles[1];
												objNode.style.top = arrStyles[2];
											}
										}
									}
								}
			this.store 		= 	function(objNode){
									// is lib_cookies available
									if(typeof(setCookie)!='undefined'){
										// store styles
										setCookie('dragposition', objNode.id + ',' + objNode.style.left + ',' + objNode.style.top, null, '/', null, null);
									}
								}
			/* events */
			this.pickUp 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dnd = classBehaviour.dragAndDrop;
									// accept no new pickups before dropdown
									if(dnd.pickupObj==null){
										// store the object being picked up
										dnd.node = objNode;
										// store pickup location
										dnd.pickup.x = (typeof(event)!='undefined') ? event.clientX : that.clientX ;
										dnd.pickup.y = (typeof(event)!='undefined') ? event.clientY : that.clientY ;
										dnd.pickup.z = (objNode.style.zIndex=='') ? objNode.style.zIndex : 0;
										// default starting position if none was given
										if(objNode.style.position!='absolute') objNode.style.position = 'absolute';
										if(objNode.style.left=='') objNode.style.left = /*dnd.pickup.x +*/ '0px'; 
										if(objNode.style.top=='') objNode.style.top = /*dnd.pickup.y +*/ '0px';
										// promote z position
										objNode.style.zIndex = 1024;
									}
									// cancel browser mouse handler
									return false;
								}
			this.dropDown 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dnd = classBehaviour.dragAndDrop;
									// only if a pickup is active
									if(dnd.node!=null){
										// snap coordinates to grid
										if(dnd.grid.x>0) dnd.node.style.left = Math.round(parseInt(dnd.node.style.left)/dnd.grid.x)*dnd.grid.x + "px";
										if(dnd.grid.y>0) dnd.node.style.top = Math.round(parseInt(dnd.node.style.top)/dnd.grid.y)*dnd.grid.y + "px";
										// restore z position
										dnd.node.style.zIndex = dnd.pickup.z;
										// store the position in a cookie
										dnd.store(dnd.node);
										// release the picked up object
										dnd.node = null;
										// clear pickup location
										dnd.pickup.x = null;
										dnd.pickup.y = null;
										dnd.pickup.z = null;
									}
									// cancel browser mouse handler
									return false;
								}
			this.moveAway 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dnd = classBehaviour.dragAndDrop;
									// only if a pickup is active
									if(dnd.node!=null){
										// mouse position
										dnd.mouse.x = (typeof(event)!='undefined') ? event.clientX : that.clientX ;
										dnd.mouse.y = (typeof(event)!='undefined') ? event.clientY : that.clientY ;
										// current object position
										dnd.style.x = (dnd.node.style.left.indexOf('px')<0) ? 0 : parseInt(dnd.node.style.left) ;
										dnd.style.y = (dnd.node.style.top.indexOf('px')<0) ? 0 : parseInt(dnd.node.style.top) ;
										// calculate new object position
										var newXpos = dnd.style.x + dnd.mouse.x - dnd.pickup.x;
										var newYpos = dnd.style.y + dnd.mouse.y - dnd.pickup.y;
										// limit new object position
										if(newXpos<dnd.minPos.x) newXpos = dnd.minPos.x;
										if(newXpos>dnd.maxPos.x) newXpos = dnd.maxPos.x;
										if(newYpos<dnd.minPos.y) newYpos = dnd.minPos.y;
										if(newYpos>dnd.maxPos.y) newYpos = dnd.maxPos.y;
										// apply new object position
										if(dnd.pickup.x!=null) dnd.node.style.left = newXpos + 'px';
										if(dnd.pickup.y!=null) dnd.node.style.top = newYpos + 'px';
										// update pickup location
										dnd.pickup.x = dnd.mouse.x;
										dnd.pickup.y = dnd.mouse.y;
										// execute custom event handler
										if(dnd.onMove!=null) dnd.onMove(dnd.node);
									}
									// cancel browser mouse handler
									return false;
								}
		}
			function Coordinates(x,y,z){
				this.x = x;
				this.y = y;
				this.z = z;
			}
		// add this function to the classbehaviour object
		classBehaviour.dragAndDrop = new DragAndDrop;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.dragAndDrop;
		
	// Correlate a dragable object to an input value
		// define this class behaviour
		function SliderInput(){
			/* properties */
			this.name 			= 	'sliderInput';
			this.allowNudge	=	true;
			/* methods */
			this.start			=	function(node){
										// event
										node.parentNode.onclick	= this.nudgeInput;
										// get the target Id
										valueToId =	classBehaviour.utilities.getClassParameter(node, 'valueToId', null);
										// get the object
										valueToObject = document.getElementById(valueToId);
										// assign the event handler
										valueToObject.onchange = this.inputToSlider;
										// add the drag and drop classbehaviour and give it out event handlers
										classBehaviour.dragAndDrop.onMove = this.sliderToInput;
										classBehaviour.dragAndDrop.start(node); 
										// trigger the starting value
										this.inputToSlider(valueToObject);
										// allow nudging
										this.allowNudge = true;
									}
			/* events */
			this.inputToSlider = 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var sli = classBehaviour.sliderInput;
										// get the the slider to sync with from the classname
										sliderTarget = objNode;
										sliderButtonId = classBehaviour.utilities.getClassParameter(sliderTarget, 'valueFromId', null);
										sliderButton = document.getElementById(sliderButtonId);
										// get the limit values from the slider
										curValue	=	parseFloat(sliderTarget.value);
										minValue	=	parseFloat(classBehaviour.utilities.getClassParameter(sliderButton, 'minValue', null));
										maxValue	=	parseFloat(classBehaviour.utilities.getClassParameter(sliderButton, 'maxValue', null));
										minPos		=	parseInt(classBehaviour.utilities.getClassParameter(sliderButton, 'limitLeft', null));
										maxPos		=	parseInt(classBehaviour.utilities.getClassParameter(sliderButton, 'limitRight', null));
										// correct improper input
										if(isNaN(curValue)){
											curValue = Math.round((maxValue-minValue)/2 + minValue);
											sliderTarget.value = curValue;
										}
										// apply limits
										if(curValue>maxValue){curValue = maxValue; sliderTarget.value = curValue;}
										if(curValue<minValue){curValue = minValue; sliderTarget.value = curValue;}
										// adjust slider
										sliderButton.style.left 	= 	Math.round(
																			(curValue - minValue) / (maxValue - minValue) * (maxPos - minPos) + minPos
																		) + 'px';
									}
			this.sliderToInput	= 	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var dnd = classBehaviour.dragAndDrop;
										var sli = classBehaviour.sliderInput;
										// disable the onclick on the sliderTrack 
										sli.allowNudge = false ;
										// get the the input field to sync with from the classname
										sliderButton	=	objNode;
										sliderTargetId	=	classBehaviour.utilities.getClassParameter(sliderButton, 'valueToId', null);
										sliderTarget	=	document.getElementById(sliderTargetId);
										// get the limit values from the slider
										curValue	=	parseFloat(sliderTarget.value);
										minValue	=	parseFloat(classBehaviour.utilities.getClassParameter(sliderButton, 'minValue', null));
										maxValue	=	parseFloat(classBehaviour.utilities.getClassParameter(sliderButton, 'maxValue', null));
										minPos		=	parseInt(classBehaviour.utilities.getClassParameter(sliderButton, 'limitLeft', null));
										maxPos		=	parseInt(classBehaviour.utilities.getClassParameter(sliderButton, 'limitRight', null));
										// translate the slider value to the input box
										sliderTarget.value 	= 	Math.round(
																	(dnd.style.x - dnd.minPos.x) / (dnd.maxPos.x - dnd.minPos.x) * 
																	(maxValue - minValue) + minValue
																);
									}
			this.nudgeInput	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var dnd = classBehaviour.dragAndDrop;
										var sli = classBehaviour.sliderInput;
										// if nudging is allowed
										if(sli.allowNudge){
											// slider objects
											sliderTrack		=	objNode;
											sliderButton	=	sliderTrack.getElementsByTagName('div')[0];
											sliderTargetId	=	classBehaviour.utilities.getClassParameter(sliderButton, 'valueToId', null);
											sliderTarget	=	document.getElementById(sliderTargetId);
											// slider limits
											minPos			=	parseInt(classBehaviour.utilities.getClassParameter(sliderButton, 'limitLeft', null));
											maxPos			=	parseInt(classBehaviour.utilities.getClassParameter(sliderButton, 'limitRight', null));
											minValue		=	parseFloat(classBehaviour.utilities.getClassParameter(sliderButton, 'minValue', null));
											maxValue		=	parseFloat(classBehaviour.utilities.getClassParameter(sliderButton, 'maxValue', null));
											// click position
											clickX = (typeof(event)!='undefined') ? event.x : that.layerX ;
											// slider position
											sliderX = (sliderButton.style.left.indexOf('px')<0) ? 0 : parseInt(sliderButton.style.left) ;
											// nudge the value of the slider closer towards the click
											newValue = Math.round(parseInt(sliderTarget.value) + ((clickX - sliderX) / (maxPos - minPos) * (maxValue - minValue)) / 2);
											// apply limits
											if(newValue>maxValue){newValue = maxValue; sliderTarget.value = curValue;}
											if(newValue<minValue){newValue = minValue; sliderTarget.value = curValue;}
											// adjust slider and input
											sliderTarget.value			=	newValue;
											sliderButton.style.left 	= 	Math.round(
																				(newValue - minValue) / (maxValue - minValue) * (maxPos - minPos) + minPos
																			) + 'px';
										// else the nudging was locked
										}else{
											// unlock the nudging
											sli.allowNudge = true;
										}
									}
		}
		// add this function to the classbehaviour object
		classBehaviour.sliderInput = new SliderInput;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.sliderInput;
		
	// show contents as code
		// define this class behaviour
		function ShowAsCode(){
			/* properties */
			this.name 		= 	'showAsCode';
			/* methods */
			this.start		=	function(node){
									/* event */
									this.process(node);
								}
			this.process 	= 	function(objNode){
									// replace html tags
									objNode.innerHTML = objNode.innerHTML.replace(/</gi,"&lt;").replace(/>/gi,"&gt;\n").replace(/ /gi,"&nbsp;").replace(/\t/gi,"&nbsp;&nbsp;&nbsp;").replace(/\n/gi,"<br />");
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.showAsCode = new ShowAsCode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.showAsCode;
		
	// Add a className to a tag using the query parameter "class"',
		// define this class behaviour
		function AddQueryToClassName(){
			/* properties */
			this.name 		= 	'addQueryToClassName';
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			this.process	= 	function(objNode){
									// get the query parameter
									var strQueryParameter = classBehaviour.utilities.getQueryParameter("class");
									// add to front of classNames
									if(strQueryParameter!=null) objNode.className = strQueryParameter + ' ' + objNode.className;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.addQueryToClassName = new AddQueryToClassName;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.addQueryToClassName;
		
	// Add a suffix to an image source using the query parameter "src"',
		// define this class behaviour
		function AddQueryToSrc(){
			/* properties */
			this.name 		= 	'addQueryToSrc';
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			this.process 	= 	function(objNode){
									// get the query parameter
									var strQueryParameter = classBehaviour.utilities.getQueryParameter("src")
									// add to front of classNames
									if(strQueryParameter!=null) objNode.src = objNode.src.replace('.','_'+strQueryParameter+'.');
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.addQueryToSrc = new AddQueryToSrc;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.addQueryToSrc;
		
	// Resizes the window to avoid a scrollbar
		// define this class behaviour
		function ResizeToFit(){
			/* properties */
			this.name 		= 	'resizeToFit';
			/* methods */
			this.start		=	function(node){
									node.onload = this.process;
									this.process(node);
								}
			/* events */
			this.process 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// measure the content
									containerWidth = (window.innerWidth) ? window.innerWidth : (document.documentElement.clientWidth) ? document.documentElement.clientWidth : document.body.clientWidth ;
									requiredWidth = document.body.offsetWidth;
									containerHeight = (window.innerHeight) ? window.innerHeight : (document.documentElement.clientHeight) ? document.documentElement.clientHeight : document.body.clientHeight ;
									requiredHeight = document.body.offsetHeight;
									// max dimensions
									requiredWidth = (requiredWidth<screen.availWidth) ? requiredWidth : screen.availWidth;
									requiredHeight = (requiredHeight<screen.availHeight) ? requiredHeight : screen.availHeight;
									// resize the window
									window.resizeTo(requiredWidth,requiredHeight);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.resizeToFit = new ResizeToFit;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.resizeToFit;
		
	// Resizes the iframe to avoid a scrollbar
		// define this class behaviour
		function ResizeIframe(){
			/* properties */
			this.name 		= 	'resizeIframe';
			/* methods */
			this.start		=	function(node){
									onload = this.delay;
									
								}
			this.process 	= 	function(){
									// fetch the iframe
									var iframes = window.parent.document.getElementsByTagName('iframe');
									var iframe = (iframes.length>0) ? iframes[iframes.length-1] : null;
									// if there was an iframe
									if(iframe){
										// measure content
										containerHeight = (window.innerHeight) ? window.innerHeight : (document.documentElement.clientHeight) ? document.documentElement.clientHeight : document.body.clientHeight ;
										requiredHeight = document.body.offsetHeight;
										// resize the iframe
										iframe.style.height = requiredHeight + 'px';
									}
								}
			/* events */
			this.delay		=	function(){
									setTimeout('classBehaviour.resizeIframe.process()',500);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.resizeIframe = new ResizeIframe;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.resizeIframe;
		
	// Resizes the window to avoid a scrollbar
		// define this class behaviour
		function FitToWindow(){
			/* properties */
			this.name 		= 	'fitToWindow';
			/* methods */
			this.start		=	function(node){
									node.onresize = this.process;
									this.process(node);
								}
			/* events */
			this.process 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// while the scroll position is not 0
									var intWhileCount = 0;
									do{
										// scroll the document by 1 pixel
										window.scrollTo(1,1);
										// measure the scroll position			
										intScrollX = (typeof(document.body.scrollLeft)!='undefined') ?  document.body.scrollLeft : window.pageXOffset ;
										intScrollY = (typeof(document.body.scrollTop)!='undefined') ? document.body.scrollTop : window.pageYOffset ;
										// if the scroll position is not 0
										if(intScrollX==0){
											// was a height specified
											if(objNode.style.width=='') objNode.style.width = '100px';
											// make the container larger
											objNode.style.width = (parseInt(objNode.style.width) + 32) + 'px';
										}
										if(intScrollY==0){
											// was a height specified
											if(objNode.style.height=='') objNode.style.height = '100px';
											// make the container larger
											objNode.style.height = (parseInt(objNode.style.height) + 32) + 'px';
										}
										// count the steps
										intWhileCount += 1;
									}while((intScrollX==0 || intScrollY==0) && intWhileCount<32);	
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.fitToWindow = new FitToWindow;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.fitToWindow;
		
	// Alternates the classes of a table's rows and columns
		// define this class behaviour
		function ZebraTable(){
			/* properties */
			this.name 		= 	'zebraTable';
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			this.process 	= 	function(objNode){
									var objRows, objCols, intCellNumber;
									// get all table rows
									objRows = objNode.getElementsByTagName('TR');
									// for all table rows
									for(var intRow=0; intRow<objRows.length; intRow++){
										// undo any previous classing
										objRows[intRow].className = objRows[intRow].className.replace('odd','');
										objRows[intRow].className = objRows[intRow].className.replace('even','');
										// add oddrow or evenrow class to the row
										objRows[intRow].className += (intRow%2==0) ? ' odd' : ' even' ;
										// and row and col counters if they're not allready present
										if(objRows[intRow].className.indexOf('row_')<0) objRows[intRow].className += ' row_' + intRow;
										// get all nodes in this row
										objCols = objRows[intRow].childNodes;
										// for every node in the row
										intCellNumber = 0;
										for(var intCol=0; intCol<objCols.length; intCol++){
											// is this a cell or a header
											if(objCols[intCol].nodeName.indexOf('text')<0){
												// undo any previous classing
												objCols[intCol].className = objCols[intCol].className.replace('odd','');
												objCols[intCol].className = objCols[intCol].className.replace('even','');
												// add oddcol or evencol class
												objCols[intCol].className += (intCellNumber%2==0) ? ' odd' : ' even' ;
												// and row and col counters if they're not allready present
												if( objCols[intCol].className.indexOf('col_')<0) objCols[intCol].className += ' col_' + intCellNumber;
												// keep cell numbers
												intCellNumber += 1;
											}
										}
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.zebraTable = new ZebraTable;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.zebraTable;
		
	// Makes the headers of a table click/sortable
		// define this class behaviour
		function SortColumn(){
			/* properties */
			this.name 		= 	'sortColumn';
			this.column	=	0;
			/* methods */
			this.start		=	function(node){
									node.onclick = this.sort;
									// apply the default sort direction style
									if(node.className.indexOf('sorted')<0) node.className += ' unSorted';
								}
			this.forward 	= 	function(rowA,rowB){
									var st = classBehaviour.sortColumn;
									var regTags = new RegExp('<(.|\n)+?>','gi');
									// get the string values from the node
									strA = (rowA.childNodes[st.column].childNodes.length == 0) ? ' ' : rowA.childNodes[st.column].innerHTML.replace('---','0,00').replace(regTags,'');
									strB = (rowB.childNodes[st.column].childNodes.length == 0) ? ' ' : rowB.childNodes[st.column].innerHTML.replace('---','0,00').replace(regTags,'');
									// get the numeric values from the node
									intA = parseInt(strA.replace(',',''));
									intB = parseInt(strB.replace(',',''));
									// compare the values for the sort funtion
									if(strA==strB || (navigator.appVersion.indexOf('MSIE 5.0')>-1)){
										// equal
										return 0;
									}else if(isNaN(intA) || isNaN(intB)){
										// compare the textual values
										return (strA<strB) ? 1 : -1 ;
									}else{
										// compare the numeric values
										return intB - intA;
									}
								}
			this.reverse 	= 	function(rowA,rowB){
									var st = classBehaviour.sortColumn;
									var regTags = new RegExp('<(.|\n)+?>','gi');
									// get the string values from the node
									strA = (rowA.childNodes[st.column].childNodes.length == 0) ? ' ' : rowA.childNodes[st.column].innerHTML.replace('---','0,00').replace(regTags,'');
									strB = (rowB.childNodes[st.column].childNodes.length == 0) ? ' ' : rowB.childNodes[st.column].innerHTML.replace('---','0,00').replace(regTags,'');
									// get the numeric values from the node
									intA = parseInt(strA.replace(',',''));
									intB = parseInt(strB.replace(',',''));
									// compare the values for the sort funtion
									if(strA==strB || (navigator.appVersion.indexOf('MSIE 5.0')>-1)){
										// equal
										return 0;
									}else if(isNaN(intA) || isNaN(intB)){
										// compare the textual values
										return (strA>strB) ? 1 : -1 ;
									}else{
										// compare the numeric values
										return intA - intB;
									}
								}
			/* events */
			this.sort 		= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var st = classBehaviour.sortColumn;
									// defaults
									sortDirection	= 'sortedForward';
									// find column number
									var objSiblings	= objNode.parentNode.childNodes;
									for(var intA=0; intA<objSiblings.length; intA++){
										// is this a cell of a text-node
										if(objSiblings[intA].nodeName=="TD" || objSiblings[intA].nodeName=="TH"){
											// test if this is the clicked node
											if(objSiblings[intA] == objNode){
												// remember the clicked column
												st.column = intA;
												// toggle the sort direction
												sortDirection = (objSiblings[intA].className.indexOf('sortedForward')>-1) ? 'sortedReverse' : 'sortedForward' ;
												// adjust the sorting direction classname
												objSiblings[intA].className = objSiblings[intA].className.replace('sortedReverse', sortDirection);
												objSiblings[intA].className = objSiblings[intA].className.replace('sortedForward', sortDirection);
												objSiblings[intA].className = objSiblings[intA].className.replace('unSorted', sortDirection);
											}else{
												// unmark any previously sorted column
												objSiblings[intA].className = objSiblings[intA].className.replace('sortedReverse', 'unSorted');
												objSiblings[intA].className = objSiblings[intA].className.replace('sortedForward', 'unSorted');
											}
										}
									}
									// make a nodelist
									var fullTable		= objNode.parentNode.parentNode.parentNode;
									var sortParent		= fullTable.getElementsByTagName('TBODY')[0];
									var nodeList		= sortParent.childNodes;
									var nodeArray		= new Array();
									// for all table rows
									for(var intA=0; intA<nodeList.length; intA++){
										if(nodeList[intA].nodeName.indexOf('TR')>-1){
											// store it in an array
											nodeArray[nodeArray.length] = nodeList[intA];
										}
									}
									// sort the collection using a helper function
									nodeArray = (sortDirection=='sortedForward') ? nodeArray.sort(st.forward) : nodeArray.sort(st.reverse);
									// clear the unsorted nodelist
									for(var intA=0; intA<nodeList.length; intA++){
										if(nodeList[intA].nodeName.indexOf('TR')>-1){
											sortParent.removeChild(nodeList[intA]);
										}
									}
									// append the sorted nodelist
									for(var intA=0; intA<nodeArray.length; intA++){
										sortParent.appendChild(nodeArray[intA]);
									}
									// reapply the zebra effect
									if(fullTable.className.indexOf('zebraTable')>-1) classBehaviour.zebraTable.process(fullTable);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.sortColumn = new SortColumn;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.sortColumn;
		
	// Open print dialog
		// define this class behaviour
		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
										classBehaviour.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
		classBehaviour.openAsPrintable = new OpenAsPrintable;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.openAsPrintable;
		
	// Close the window (it's cold)
		// define this class behaviour
		function CloseThisWindow(){
			/* properties */
			this.name 		= 	'closeThisWindow';
			/* methods */
			this.start		=	function(node){
									node.onclick = this.process;
								}
			this.process 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									window.close();
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.closeThisWindow = new CloseThisWindow;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.closeThisWindow;
		
      // Jump back to the previous page
            // define this class behaviour
            function GoToPrevious(){
                  /* properties */
                  this.name         =     'goToPrevious';
                  /* methods */
                  this.start        =     function(node){
                                                      node.onclick = this.process;
                                                }
                  this.process      =     function(that){
                                                      var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
                                                      // open the print dialog
                                                      window.history.go(-1);
                                                }
            }
            // add this function to the classbehaviour object
            classBehaviour.goToPrevious = new GoToPrevious;
            classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.goToPrevious;
		
	// Make dropdown menu
		// define this class behaviour
		function DropDownMenu(){
			/* properties */
			this.name 		= 	'dropDownMenu';
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			this.recurse 	= 	function(objParentNode){
									var cmh = classBehaviour.classMouseHover;
									var tnn = classBehaviour.toggleNextNode;
									// mark the node as active
									cmh.addActive(objParentNode);
									// add active class to the anchor
									if(objParentNode.getElementsByTagName('A').length>0) cmh.addActive(objParentNode.getElementsByTagName('A')[0]);
									// replace image source for active version
									if(objParentNode.getElementsByTagName('IMG').length>0)  tnn.toggleNext(objParentNode.getElementsByTagName('IMG')[0]);
									// next recursion to same node type
									if(objParentNode.nodeName == objParentNode.parentNode.parentNode.nodeName) this.recurse(objParentNode.parentNode.parentNode);
								}
			this.process 	= 	function(objNode){
									var mau = classBehaviour.matchActiveUrl;
									var objNodes, objMatch, objNextNode;
									// apply default settings to all LIs
									objNodes = objNode.getElementsByTagName('LI');
									for(var intNode=0; intNode<objNodes.length; intNode++){
										// hideThisNode
										if(objNodes[intNode].className.indexOf('link')<0 && objNodes[intNode].className.indexOf('active')<0) objNodes[intNode].className += ' link';
									}
									// apply default settings to all IMGs
									objNodes = objNode.getElementsByTagName('IMG');
									for(var intNode=0; intNode<objNodes.length; intNode++){
										// if this node has children
										if(objNodes[intNode].parentNode.getElementsByTagName('UL').length>0){
											// set a starting value for the open and closed toggle
											objNodes[intNode].parentNode.getElementsByTagName('UL')[0].style.display  = 'none';
											// rename the image to indicate it's subnodes.
											objNodes[intNode].src = objNodes[intNode].src.replace('_child', '_parent');
										}
										// toggleNextNode
										objNodes[intNode].onclick = this.togglePeers;
									}
									// apply default settings to all As
									objNodes = objNode.getElementsByTagName('A');
									for(var intNode=0; intNode<objNodes.length; intNode++){
										// if the item has no valid link
										if(objNodes[intNode].href.indexOf("#")==objNodes[intNode].href.length-1){
											// make it the link of it's first child
											objNodes[intNode].href = objNodes[intNode+1].href
										}
										// use matchActiveUrl to find active items OR use the ones marked manualy
										objMatch = (mau.process(objNodes[intNode]) || objNodes[intNode].className.indexOf('active')>-1) ? objNodes[intNode] : objMatch ;
									}
									// recurse back the last matching node
									if(objMatch!=null) this.recurse(objMatch.parentNode);
								}
			this.togglePeers=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tnn = classBehaviour.toggleNextNode;
									// get all the peers of this node
									allPeers = objNode.parentNode.parentNode.childNodes;
									// for all peers
									for(var a=0; a<allPeers.length; a++){
										// if the peer is no textnode and not the target node
										if(allPeers[a].nodeName.toLowerCase().indexOf('li')>-1 && objNode.parentNode!=allPeers[a]){
											// if the peer has a submenu toggle
											subToggles = allPeers[a].getElementsByTagName('img');
											if(subToggles.length>0){
												// if the node is opened
												if(subToggles[0].src.indexOf('active')>-1){
													// close it
													tnn.toggleNext(subToggles[0]);
												}
											}
										}
									}
									// toggle the current noce
									tnn.toggleNext(objNode);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.dropDownMenu = new DropDownMenu;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.dropDownMenu;
		
	// Make foldout menu
		// define this class behaviour
		function FoldOutMenu(){
			/* properties */
			this.name 		= 	'foldOutMenu';
			this.timeout	=	null;
			this.delay		=	1024;
			this.foldIns 	= 	new Array();
			this.activeNode =	null;
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			this.process 	= 	function(objNode){
									var objNodes, objMatch;
									var mau = classBehaviour.matchActiveUrl;
									// apply events to all LIs
									objNodes = objNode.getElementsByTagName('LI');
									for(var intNode=0; intNode<objNodes.length; intNode++){
										// mouseover events
										objNodes[intNode].onmouseover	= this.addHover;
										objNodes[intNode].onmouseout	= this.remHover;
									}
									// apply default settings to all As
									objNodes = objNode.getElementsByTagName('A');
									for(var intNode=0; intNode<objNodes.length; intNode++){
										// if the item has no valid link
										if(objNodes[intNode].href.indexOf("#")==objNodes[intNode].href.length-1){
											// make it the link of it's first child
											objNodes[intNode].href = objNodes[intNode+1].href
										}
										// use matchActiveUrl to find active items OR use the ones marked manualy
										objMatch = (mau.process(objNodes[intNode]) || objNodes[intNode].className.indexOf('active')>-1) ? objNodes[intNode] : objMatch ;
									}
									// recurse back the last matching node
									if(objMatch!=null){
										this.recurse(objMatch.parentNode);
									}
								}
			this.recurse 	= 	function(objParentNode){
									var cmh = classBehaviour.classMouseHover;
									// add active class to the anchor
									if(objParentNode.getElementsByTagName('A').length>0) cmh.addActive(objParentNode.getElementsByTagName('A')[0]);
									// store the active node
									this.activeNode = objParentNode;
									// add the active src to any image in the node
									imgNodes = objParentNode.getElementsByTagName('img');
									if(imgNodes.length>0) imgNodes[0].src = imgNodes[0].src.replace('_link','_active');
									// next recursion to same node type
									if(objParentNode.nodeName == objParentNode.parentNode.parentNode.nodeName) this.recurse(objParentNode.parentNode.parentNode);
								}
			/* events */
			this.addHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var cmh = classBehaviour.classMouseHover;
									var fom = classBehaviour.foldOutMenu;
									// if a delay is required
									if(fom.delay>0){
										// cancel the timeout on the delayed mouseevents
										clearTimeout(fom.timeout);
										// handle the delayed mouseouts
										while(fom.foldIns.length>0){
											// change the stored active node to "active"
											if(fom.activeNode!=null) if(fom.activeNode.getElementsByTagName('IMG').length>0) fom.activeNode.getElementsByTagName('IMG')[0].src = fom.activeNode.getElementsByTagName('IMG')[0].src.replace('_link','_active');
											// change the src of a child image
											imgNodes = fom.foldIns[fom.foldIns.length-1].getElementsByTagName('img');
											if(imgNodes.length>0) imgNodes[0].src = imgNodes[0].src.replace('_active','_link');
											// remove the active classes from every item to be folded in
											cmh.remHover(fom.foldIns[fom.foldIns.length-1]);
											fom.foldIns.length = fom.foldIns.length - 1;
										}
										// restore all select form elements
										allSelects = document.getElementsByTagName('SELECT');
										if(document.all){
											for(var a=0; a<allSelects.length; a++){
												allSelects[a].style.visibility = 'visible';
											}
										}
									}
									// is the node exists
									if(objNode!=null){
										// emulate the parent node's mouseout event
										cmh.addHover(objNode);
										// change the stored active node to "link"
										if(fom.activeNode!=null) if(fom.activeNode.getElementsByTagName('IMG').length>0) fom.activeNode.getElementsByTagName('IMG')[0].src = fom.activeNode.getElementsByTagName('IMG')[0].src.replace('_active','_link');
										// change the src of a child image
										imgNodes = objNode.getElementsByTagName('img');
										if(imgNodes.length>0) imgNodes[0].src = imgNodes[0].src.replace('_link','_active');
										// hide all select form elements
										allSelects = document.getElementsByTagName('SELECT');
										if(document.all){
											for(var a=0; a<allSelects.length; a++){
												allSelects[a].style.visibility = 'hidden';
											}
										}
									}
								}
			this.remHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var cmh = classBehaviour.classMouseHover;
									var fom = classBehaviour.foldOutMenu;
									// if no delay is required
									if(fom.delay==0){
										// emulate the parent node's mouseout event
										cmh.remHover(objNode);
										// change the stored active node to "active"
										if(fom.activeNode!=null){}
										// change the src of a child image
										imgNodes = objNode.getElementsByTagName('img');
										if(imgNodes.length>0) imgNodes[0].src = imgNodes[0].src.replace('_active','_link');
										// restore all select form elements
										allSelects = document.getElementsByTagName('SELECT');
										if(document.all){
											for(var a=0; a<allSelects.length; a++){
												allSelects[a].style.visibility = 'visible';
											}
										}
									}else{
										// cancel the timeout on the delayed mouseevents
										clearTimeout(fom.timeout);
										// store the mouseout for delayed closing
										fom.foldIns[fom.foldIns.length] = objNode;
										// order a delayed handling of the saved up mouseouts
										fom.timeout = setTimeout('classBehaviour.foldOutMenu.addHover()',fom.delay);
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.foldOutMenu = new FoldOutMenu;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.foldOutMenu;
		
	// Remove this tag if it's found to be empty
		// define this class behaviour
		function RemoveIfEmpty(){
			/* properties */
			this.name 		= 	'removeIfEmpty';
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			this.process 	= 	function(objNode){
									// doesn't this node have child nodes?
									if(objNode.childNodes.length==0){
										// remove the node
										objNode.parentNode.removeChild(objNode);
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.removeIfEmpty = new RemoveIfEmpty;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.removeIfEmpty;
		
	// Fixes the position of an element
		// define this class behaviour
		function FixedPosition(){
			/* properties */
			this.name 		= 	'fixedPosition';
			this.nodes 		= 	new Array();
			/* methods */
			this.start		=	function(node){
									this.nodes[this.nodes.length] = node;
									if(document.all){
										window.onscroll = this.process;
									}else{
										node.style.position = 'fixed';
									}
								}
			/* events */
			this.process 	= 	function(){
									var fp = classBehaviour.fixedPosition;
									// this is only needed in internet explorer
									for(var a=0; a<fp.nodes.length; a++){
										fp.nodes[a].style.marginTop = (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + 'px';
										fp.nodes[a].style.marginLeft = (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + 'px';
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.fixedPosition = new FixedPosition;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.fixedPosition;
		
	// Open links in a popup
		// define this class behaviour
		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 = classBehaviour.openAsPopUp;
									// get the parameters from the classname
									var strWidth 		= 'width=' + classBehaviour.utilities.getClassParameter(objNode, 'width', '630');
									var strHeight 		= ',height=' + classBehaviour.utilities.getClassParameter(objNode, 'height', '385');
									var strLeft			= ',left=' + classBehaviour.utilities.getClassParameter(objNode, 'left', '');
									var strTop			= ',top=' + classBehaviour.utilities.getClassParameter(objNode, 'top', '');
									var strToolbars 	= ',toolbar=' + classBehaviour.utilities.getClassParameter(objNode, 'toolbar', 'no');
									var strScrolling 	= ',scrollbars=' + classBehaviour.utilities.getClassParameter(objNode, 'scrollbars', 'no');
									var strStatus 		= ',status=' + classBehaviour.utilities.getClassParameter(objNode, 'status', 'no');
									var strResize 		= ',resizable=' + classBehaviour.utilities.getClassParameter(objNode, 'resizable', 'yes');
									var strLocation 	= ',location=' + classBehaviour.utilities.getClassParameter(objNode, 'location', 'no');
									var strMenu 		= ',menu=' + classBehaviour.utilities.getClassParameter(objNode, 'menu', 'no');
									var strName 		= classBehaviour.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
		classBehaviour.openAsPopUp = new OpenAsPopUp;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.openAsPopUp;
		
	// Open links in the opener of this window
		// define this class behaviour
		function OpenInOpener(){
			/* properties */
			this.name 		= 	'openInOpener';
			/* methods */
			this.start		=	function(node){
									node.onclick = this.process;
								}
			/* events */
			this.process 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// open the href in the opener of this window
									window.opener.location.href = objNode.href;
									// optionaly close the window
									if(classBehaviour.utilities.getClassParameter(objNode, 'closeParent', 'false')=='true') window.close();
									// cancel the link
									return false;
									
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.openInOpener = new OpenInOpener;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.openInOpener;
		
	// Open links in a new window
		// define this class behaviour
		function OpenAsWindow(){
			/* properties */
			this.name 		= 	'openAsWindow';
			/* methods */
			this.start		=	function(node){
									node.target = "_blank"
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.openAsWindow = new OpenAsWindow;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.openAsWindow;
		
	// Chooses a random increment of an image source
		// define this class behaviour
		function SetRandomSrc(){
			/* properties */
			this.name 		= 	'setRandomSrc';
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			this.process 	= 	function(objNode){
									// get min parameter
									var intMin = parseInt(classBehaviour.utilities.getClassParameter(objNode, 'min', '0'));
									// get max parameter
									var intMax = parseInt(classBehaviour.utilities.getClassParameter(objNode, 'max', '1'));
									// generate random number
									var intRandom = Math.round(Math.random()*(intMax-intMin))+intMin;
									// replace default increment by random number
									if(objNode.src!=null) objNode.src = objNode.src.replace('_0','_'+intRandom);
									objNode.className = objNode.className.replace('_0','_'+intRandom);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.setRandomSrc = new SetRandomSrc;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.setRandomSrc;
		
	// Chooses a random increment of an image source
		// define this class behaviour
		function SetRandomClassName(){
			/* properties */
			this.name 		= 	'setRandomClassName';
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			this.process 	= 	function(objNode){
									// get min parameter
									var intMin = parseInt(classBehaviour.utilities.getClassParameter(objNode, 'min', '0'));
									// get max parameter
									var intMax = parseInt(classBehaviour.utilities.getClassParameter(objNode, 'max', '1'));
									// generate random number
									var intRandom = Math.round(Math.random()*(intMax-intMin))+intMin;
									// replace default increment by random number
									if(objNode.className!=null) objNode.className = objNode.className.replace('_0','_'+intRandom);
									objNode.className = objNode.className.replace('_0','_'+intRandom);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.setRandomClassName = new SetRandomClassName;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.setRandomClassName;
		
	// Class a link matching the document's url
		// define this class behaviour
		function MatchActiveUrl(){
			/* properties */
			this.name 		= 	'matchActiveUrl';
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			this.convertAbsToRelUrls 	= 	function(strUrl){
												// is the url a relative path
												if(strUrl.indexOf('/')<0 || strUrl.substr(0,1)=='.' || strUrl.substr(0,1)=='/'){
													// the current absolute path
													strAbs = document.location.href;
													// remove the filename from the end
													strAbs = strAbs.substring(0, strAbs.lastIndexOf('/'));
													// while there are parent markers in the url
													while(strUrl.indexOf('../')==0){
														// remove one level from the absolute path
														strUrl = strUrl.replace('../','');
														// remove one parent marker from the relative path
														strAbs = strAbs.substring(0, strAbs.lastIndexOf('/'));
													}
													// remove all current dir markers from the relative url
													strUrl = strUrl.replace(/\.\//gi,'');
													// add the url to the absolute path
													strUrl = strAbs + '/' + strUrl;
												}
												return strUrl;
											}
			this.compareUrls 	= 	function(strUrlA,strUrlB){
										var intCurScore = 0;
										var intPotScore = 0;
										var intMaxScore = 0;
										var intA,intB;
										// replace most common illegal characters
										strUrlA = strUrlA.replace(/ /gi,"%20");
										strUrlB = strUrlB.replace(/ /gi,"%20");
										// remove anchors
										strUrlA = strUrlA.split('#')[0];
										strUrlB = strUrlB.split('#')[0];
										// make sure both paths are absolute
										strUrlA = this.convertAbsToRelUrls(strUrlA);
										strUrlB = this.convertAbsToRelUrls(strUrlB);
										// split the urls into manageable strings
										var arrUrlA = strUrlA.split(/[?&#\/]/i);
										var arrUrlB = strUrlB.split(/[?&#\/]/i);
										// for every string of UrlA
										for(intA=0; intA<arrUrlA.length; intA++){
											// is the string in the substrings of UrlB
											intB = 0; while(intB<arrUrlB.length && arrUrlA[intA]!=arrUrlB[intB]) intB += 1;
											// if a match was found, add length of string A to current score
											if(intB<arrUrlB.length) intCurScore += arrUrlA[intA].length;
											// add length of string A to potential score
											intPotScore += arrUrlA[intA].length;
										}
										// calcultate maximum score possible
										intMaxScore = strUrlB.length - arrUrlB.length + 1;
										// return the compare-score
										return intCurScore/intPotScore;
									}
			this.process 	= 	function(objNode){
									var cmh = classBehaviour.classMouseHover;
									var smh = classBehaviour.srcMouseHover;
									// get parent recursion
									var intToParent	= parseInt(classBehaviour.utilities.getClassParameter(objNode, 'toParent', '0'));
									// get parent href
									var intFromParent = parseInt(classBehaviour.utilities.getClassParameter(objNode, 'fromParent', '0'));
									// get the url and clean it up
									var strUrl = this.convertAbsToRelUrls(document.location.href);
									// get the href and clean it up
									var strHref = (intFromParent>0) ? this.convertAbsToRelUrls(objNode.parentNode.getAttribute('href')) : this.convertAbsToRelUrls(objNode.getAttribute('href')) ;
									// was the data bad
									if(strHref!=null){
										// compare score
										var ftlCompareScore = this.compareUrls(strUrl, strHref) * this.compareUrls(strHref, strUrl);
										// if the href matches the url 
										if(ftlCompareScore==1){
											// add the active class to the target item
											cmh.addActive(objNode);
											if(objNode.nodeName=='IMG') smh.addActive(objNode);
											// if a parent node also needs to be marked
											if(intToParent>0){
												// get the relevant parent node
												for(var intA=0; intA<intToParent; intA++) objNode = objNode.parentNode;
												// if the href matches the url
												if(ftlCompareScore==1){
													// add the active class to the parent item
													cmh.addActive(objNode);
												}
											}
											// report a match
											return true;
										}
									}
									// report no match
									return false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.matchActiveUrl = new MatchActiveUrl;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.matchActiveUrl;
		
	// Triggers all validateInput class behaviours within a node after the onsubmit event.',
		// define this class behaviour
		function ValidateAllInput(){
			/* properties */
			this.name 		= 	'validateAllInput';
			/* methods */
			this.start		=	function(node){
									// set the form validation eventhandler
									node.onsubmit = classBehaviour.validateInput.all;
									// if there's a place for a summary store the id
									classBehaviour.validateInput.summaryId = classBehaviour.utilities.getClassParameter(node, 'summaryId', null);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.validateAllInput = new ValidateAllInput;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.validateAllInput;
		
	// Validate the value of a for element to a predefined regular expression
		// define this class behaviour
		function ValidateInput(){
			/* properties */
			this.name 		= 	'validateInput';
			this.summaryId	=	null;
			/* methods */
			this.start	=	function(node){
								// was a summary requested?
								this.summaryId = classBehaviour.utilities.getClassParameter(node, 'summaryId', this.summaryId);
								// apply the event to all form-element childnodes
								var nodes = (this.isFormElement(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].onblur = this.input;
										nodes[a].onchange = this.input;
										// if the form is small enough one could revalidate the whole thing at every change
											//nodes[a].onblur = this.all;
											//nodes[a].onchange = this.all;
										// and the parent's classname
										nodes[a].className = node.className;
									}
								}
								// if there's a greyed axplanation
								hasExplanation = classBehaviour.utilities.getClassParameter(node, 'explanation', 'no');
								if(hasExplanation=='yes'){
									// remove it if a value is restored by a form manager
									setTimeout("classBehaviour.validateInput.restore('"+node.id+"','"+node.value+"')", 1000);
								}
							}
			this.all 	= 	function(that){
								var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
								var vi = classBehaviour.validateInput;
								var booPassed = true;
								// get all subnodes in the form
									//var objSubNodes = objNode.getElementsByTagName("*") ;
									var objSubNodes = document.getElementsByTagName("*") ;
								// for all nodes
								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);
								}
								// is a summary required
								if(vi.summaryId){
									summaryObj = document.getElementById(vi.summaryId);
									summaryTxt = '';
									// for all nodes
									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!='none'){
											// copy it's contents to the summary text
											summaryTxt += '<li>' + objSubNodes[a].innerHTML + '</li>';
										}
									}
									// add the summary text to the summary
									summaryObj.innerHTML = (summaryTxt.length>0) ? '<ul>' + summaryTxt + '</ul>' : '' ;
								}
								// is the form valid enough?
								return booPassed;
							}
			this.input = 	function(that, override){
								var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
								var vi = classBehaviour.validateInput;
								// default validator values
								var booEmptyValidator, booValueValidator;
								// get the type of validation required			
								strValidatorName	= classBehaviour.utilities.getClassParameter(objNode, 'type', '');
								allowEmpty			= classBehaviour.utilities.getClassParameter(objNode, 'allowEmpty', 'no');
								ifCheckedId			= classBehaviour.utilities.getClassParameter(objNode, 'ifCheckedId', null);
								hasExplanation 		= classBehaviour.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.bankAccount(objNode);
											break;
										case 'isradiochecked' :
											booValueValidator = vi.isRadioChecked(objNode);
											break;
										case 'anyofthesechecked' : 
											booValueValidator = vi.anyOfTheseChecked(objNode);
											break;
										case 'text' :
											booValueValidator = (objNode.value!="");
											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);
								// return a pass of fail boolean to whoever may want to know the results of the test
								return (override!=null) ? validates : override;
							}
			this.warning =	function(objNode, status){
								var vi = classBehaviour.validateInput;
								// 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		= classBehaviour.utilities.getClassParameter(objNode, 'warningId', null);
									// check if the next node is for summaries
									nextNode 			= (objNode.nextSibling.nodeName.indexOf("text")<0) ? objNode.nextSibling : objNode.nextSibling.nextSibling ;
									// 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){
                                                if(status){
                                                    allLabels[a].className =  allLabels[a].className.replace(/\s?warning/g,'');
                                                }else{
                                                    allLabels[a].className += ' warning';
                                                }
                                            }

											
											
											//if(allLabels[a].parentNode.className.indexOf('noWarning')<0 && allLabels[a].className.indexOf('noWarning')<0) allLabels[a].className = (status) ? '' : 'warning' ;
										}
									}
								}
							}
			this.clear	=	function(objNode){
								var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
								// if there was an explanation provides as a value
								hasExplanation = classBehaviour.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.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');
								}
							}
			/* utility functions */
			this.isFormElement		=	function(objNode){
											return (objNode.nodeName=='INPUT' || objNode.nodeName=='SELECT' || objNode.nodeName=='TEXTAREA');
										}
			/* custom validation functions */
			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
		classBehaviour.validateInput = new ValidateInput;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.validateInput;
		
	// Disable form elements during a submit, to avoid multiple submits on slow servers
		// define this class behaviour
		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) classBehaviour.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
		classBehaviour.disableAfterSubmit = new DisableAfterSubmit;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.disableAfterSubmit;
		
	// Manage all event handler for an imagemap
		// define this class behaviour
		function ImageMap(){
			// properties
			this.name 		= 	'imageMap';
			this.map		=	new Map;
			this.areas		=	new Areas;
			// methods
			this.start		=	function(node){
									// start the storing of the map object
									node.onmouseover = this.map.over;
									this.map.over(node);
									// get all areas in this map
									areas = document.getElementById(this.map.name).getElementsByTagName('area');
									// for all areas in this map
									for(var a=0; a<areas.length; a++){
										// cache it's image equivalent
										this.cache(node.src.replace(this.map.passive, areas[a].id));
										// give the area event handlers
										areas[a].onmouseover = this.areas.over;
										areas[a].onmouseout = this.areas.out;
									}
								}
			// events
			this.cache		= 	function(url) {
										var imp = classBehaviour.imageMap;
										// preload the image into an array
										imp.map.images[imp.map.images.length] = new Image();
										imp.map.images[imp.map.images.length-1].src = url;
								}
		}
			function Map(){
				// properties
				this.object	=	null;
				this.name		=	null;
				this.passive	=	'nederland';
				this.images		=	new Array();
				// methods
				this.over		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var imp = classBehaviour.imageMap;
										// store the currently active map
										imp.map.object = objNode;
										imp.map.name = objNode.getAttributeNode('usemap').value.replace('#','');
									}
			}
			function Areas(){
				// methods
				this.over	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var imp = classBehaviour.imageMap;
									// apply the area id to the map's source
									imp.map.object.src = imp.map.object.src.replace(imp.map.passive, objNode.id);
								}
				this.out	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var imp = classBehaviour.imageMap;
									// apply the area id to the map's source
									imp.map.object.src = imp.map.object.src.replace(objNode.id, imp.map.passive);
								}
			}
		
		// add this function to the classbehaviour object
		classBehaviour.imageMap = new ImageMap;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.imageMap;
		
	// Enforces minimal height of a container
		// define this class behaviour
		function MinHeight(){
			/* properties */
			this.name 		= 	'minHeight';
			this.adjusts 	= 	new Array();
			this.timeout 	= 	null;
			/* methods */
			this.start		=	function(node){
									// immediate event
									this.process(node);
									// store object for later resize
									this.adjusts[this.adjusts.length] = node;
									window.onresize = this.delay;
								}
			this.adjust	 	= 	function(){
									for(var intA=0; intA<this.adjusts.length; intA++){
										this.adjusts[intA].style.height = 'auto';
										this.process(this.adjusts[intA]);
									}
								}
			/* events */
			this.delay 		= 	function(){
									clearTimeout(classBehaviour.minHeight.timeout);
									// maxWidth might want to re-adjusted too
									classBehaviour.minHeight.timeout = setTimeout('classBehaviour.minHeight.adjust();classBehaviour.maxWidth.adjust();',  256);
								}
			this.process 	= 	function(objNode){
									// get the height parameters
									var strMinHeight, strOffSet;		
									strMinHeight	= classBehaviour.utilities.getClassParameter(objNode, 'height', '100pct');
									strOffSet		= classBehaviour.utilities.getClassParameter(objNode, 'heightOffset', '0px');
									// get the current document and window dimensions
									var intDocHeight, intCanvasHeight;
									intDocHeight	= document.body.scrollHeight;
									intCanvasHeight	= (typeof(window.innerHeight)!='undefined') ? window.innerHeight : document.body.offsetHeight ;
									// adjust target container to fill the difference in dimensions
									var intMinHeight= (strMinHeight.indexOf('pct')>-1) ? Math.round(intCanvasHeight * parseInt(strMinHeight) / 100) : parseInt(strMinHeight) ;
									var intOffSet	= (strOffSet.indexOf('pct')>-1) ? Math.round(intCanvasHeight * parseInt(strOffSet) / 100) : parseInt(strOffSet) ;
									// set the page's minimum height
									if(document.all){
										intOffSet -= 1;
										objNode.style.height = (intMinHeight - intOffSet) + 'px';
									}else{
										objNode.style.minHeight = (intMinHeight - intOffSet) + 'px';
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.minHeight = new MinHeight;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.minHeight;
		
	// Enforces maximal width of a container
		// define this class behaviour
		function MaxWidth(){
			/* properties */
			this.name 		= 	'maxWidth';
			this.adjusts 	= 	new Array();
			/* methods */
			this.start		=	function(node){
									// immediate event
									this.process(node);
									// store object for later resize
									this.adjusts[this.adjusts.length] = node;
									window.onresize = this.delay;
								}
			this.adjust	 	= 	function(){
									for(var intA=0; intA<this.adjusts.length; intA++){
										this.adjusts[intA].style.width = 'auto';
										this.process(this.adjusts[intA]);
									}
								}
			/* events */
			this.delay 		= 	function(){
									clearTimeout(classBehaviour.maxWidth.timeout);
									// minHeight might want to re-adjusted too
									classBehaviour.minHeight.timeout = setTimeout('classBehaviour.minHeight.adjust();classBehaviour.maxWidth.adjust();',  256);
								}
			this.process 	= 	function(objNode){
									// get the width parameters
									var strMaxWidth, strOffSet;
									strMaxWidth		= classBehaviour.utilities.getClassParameter(objNode, 'width', '100pct');
									strOffSet		= classBehaviour.utilities.getClassParameter(objNode, 'widthOffset', '0px');
									// get the current document and window dimensions
									var intDocWidth, intCanvasWidth;
									intDocWidth		= document.body.scrollWidth;
									intCanvasWidth	= (typeof(window.innerWidth)!='undefined') ? window.innerWidth : document.body.offsetWidth ;
									// adjust target container to fill the difference in dimensions
									var intMaxWidth	= (strMaxWidth.indexOf('pct')>-1) ? Math.round(intCanvasWidth * parseInt(strMaxWidth) / 100) : parseInt(strMaxWidth) ;
									var intOffSet	= (strOffSet.indexOf('pct')>-1) ? Math.round(intCanvasWidth * parseInt(strOffSet) / 100) : parseInt(strOffSet) ;
									objNode.style.width = (intDocWidth>intMaxWidth) ? (intMaxWidth - intOffSet) + 'px' : 'auto' ;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.maxWidth = new MaxWidth;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.maxWidth;
		
	// Scroll the list items of a container
		// define this class behaviour
		function ListScroller(){
			/* properties */
			this.name 		= 	'listScroller';
			this.object	=	null;
			this.dimensions =	new Coordinates();
			this.limits	=	new Coordinates();
			this.speed		=	new Coordinates();
			this.distance	=	new Coordinates();
			this.delay		=	null;
			this.interval	=	null;
			/* methods */
			this.start		=	function(node){
									// make a new instance of the scroller object
									this.object			= node;
									this.dimensions.x	= parseInt(classBehaviour.utilities.getClassParameter(node, 'width', '112'));
									this.dimensions.y	= parseInt(classBehaviour.utilities.getClassParameter(node, 'height', '120'));
									this.speed.x		= -1 * parseInt(classBehaviour.utilities.getClassParameter(node, 'left', '2'));
									this.speed.y		= -1 * parseInt(classBehaviour.utilities.getClassParameter(node, 'top', '0'));
									this.delay			= parseInt(classBehaviour.utilities.getClassParameter(node, 'delay', '64'));
									this.distance.x		= 0;
									this.distance.y		= 0;
									// clone the list items for double buffering
									var scrollList		= this.object.getElementsByTagName('UL')[0];
									var scrollItems		= scrollList.getElementsByTagName('LI');
									var itemsMax		= scrollItems.length;
									for(var a=0; a<itemsMax; a++){
										var new_node = scrollItems[a].cloneNode(true);
										scrollList.appendChild(new_node); 
									}
									// note the scrolling limits
									this.limits.x	= this.dimensions.x * itemsMax;
									this.limits.y	= this.dimensions.y * itemsMax;
									// set prerequisite styles
										//	UL settings
										scrollList.style.width	= (this.dimensions.x * 2 * itemsMax) + 'px';
										scrollList.style.height	= (this.dimensions.y * 2 * itemsMax) + 'px';
										// LI settings
										for(var a=0; a<scrollItems.length; a++){
											scrollItems[a].style.width	= this.dimensions.x + 'px';
											scrollItems[a].style.height	= this.dimensions.y + 'px';
										}
									// set the mouseover events
									this.object.onmouseout	= this.scroll;
									this.object.onmouseover = this.pause;
									// if there are direction controls give them events
									if(document.getElementById('prevControl')) document.getElementById('prevControl').onclick = this.goLeft;
									if(document.getElementById('nextControl')) document.getElementById('nextControl').onclick = this.goRight;
									// initiate the scroll interval
									this.scroll();
								}
			this.step		=	function(){
									var scrollCanvas =	this.object.getElementsByTagName('UL')[0];
									// calculate the new positions - loop on the right
									if(this.speed.x<=0) newLeftPos	=	(this.distance.x <= -1*this.limits.x) ? '0px' : (this.distance.x + this.speed.x) + 'px';
									if(this.speed.y<=0) newTopPos		=	(this.distance.y <= -1*this.limits.y) ? '0px' : (this.distance.y + this.speed.y) + 'px';
									// loop on the right
									if(this.speed.x>0) newLeftPos		=	(this.distance.x > 0) ? (-1*this.limits.x + this.speed.x) + 'px' : (this.distance.x + this.speed.x) + 'px';
									if(this.speed.y>0) newTopPos		=	(this.distance.y > 0) ? (-1*this.limits.y + this.speed.y) + 'px' : (this.distance.y + this.speed.y) + 'px';
									// update styles
									scrollCanvas.style.left	= newLeftPos;
									scrollCanvas.style.top	= newTopPos;
									// update stored positions
									this.distance.x			=	parseInt(newLeftPos);
									this.distance.y			=	parseInt(newTopPos);
									// cancel something
									return 0;
								}
			/* events */
			this.goLeft	=	function(){
									var lsc = classBehaviour.listScroller;
									// set the scrolling
									lsc.speed.x = Math.abs(lsc.speed.x);
									// cancel the click
									return false;
								}
			this.goRight	=	function(){
									var lsc = classBehaviour.listScroller;
									// set the scrolling
									lsc.speed.x = -1 * Math.abs(lsc.speed.x);
									// cancel the click
									return false;
								}
			this.scroll		=	function(){
									classBehaviour.listScroller.interval = setInterval('classBehaviour.listScroller.step()', classBehaviour.listScroller.delay);
									return 0;
								}
			this.pause		=	function(){
									clearInterval(classBehaviour.listScroller.interval);
									return 0;
								}
		}
		/* allready defined elsewhere
			function Coordinates(x,y,z){
				this.x = x;
				this.y = y;
				this.z = z;
			}
		*/
		// add this function to the classbehaviour object
		classBehaviour.listScroller = new ListScroller;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.listScroller;
		
/* TODO: controls for the scroller
	<li><a href="?3" id="prevControl"><img alt="Vorige" src="../images/movieGallery_previous_link.gif"/></a></li>
	<li><a href="?4" id="nextControl"><img alt="Volgende" src="../images/movieGallery_next_link.gif"/></a></li>
*/
		
		
	// Toggle hidden siblings when clicking this node
		// define this class behaviour
		function ToggleHiddenSiblings(){
			/* properties */
			this.name 		= 	'toggleHiddenSiblings';
			this.lastNode	=	null;
			this.lastNext	=	null;
			/* methods */
			this.start		=	function(node){
									node.onclick = this.process;
								}
			/* events */
			this.process	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// If this node is a real check box
									var prefState = null;
									if(objNode.getAttribute('type')=='checkbox'){
										// take it's state for hiding or showing
										prefState = objNode.checked;
									}
									// from this node upwards, find the tbody or the table
									var testNode = objNode.parentNode;
									while(
										testNode.nodeName.toLowerCase()!='tbody' && 
										testNode.nodeName.toLowerCase()!='table' && 
										testNode.nodeName.toLowerCase()!='div' && 
										testNode.nodeName.toLowerCase()!='fieldset' && 
										testNode.nodeName.toLowerCase()!='body'
									){
										testNode = testNode.parentNode;
									}
									var allNodes = testNode.getElementsByTagName('*');
									// for the nodes within
									for(var a=0; a<allNodes.length; a++){
										// check if it is part of the hiding/showing action
										if(allNodes[a].className.indexOf('hideThisNode')>-1){
											// take the prefered state from the current state if the original node wasn't a checkbox
											if(prefState==null) prefState = (allNodes[a].style.display=='none') ? true : false ;
												// show of hide the sibling
												if(prefState){
													// show thenode using the correct visible state
													node.style.display = classBehaviour.utilities.getVisibleState(node);
												}else{
													allNodes[a].style.display = 'none';
												}
										}
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.toggleHiddenSiblings = new ToggleHiddenSiblings;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.toggleHiddenSiblings;
		
	// display the title of an image in a popup layer
		// define this class behaviour
		function TitleMouseHover(){
			// properties
			this.name 			= 	'titleMouseHover';
			this.cache 		= 	new Array();
			this.limitRight	=	9999;
			this.limitLeft		=	0;
			this.mouseX		=	0;
			this.mouseY		=	0;
			// methods
			this.start			=	function(node){
											this.cacheImages(node);
											node.onmouseover = this.addHover;
											node.onmouseout = this.remHover;
											node.onmousemove = this.positionHover;
											// set limits
											this.limitRight = parseInt(classBehaviour.utilities.getClassParameter(node, 'limitRight', '9999'));
											this.limitLeft = parseInt(classBehaviour.utilities.getClassParameter(node, 'limitLeft', '0'));
											// start mouse position manager, if present
											//if(setMouseHandler) setMouseHandler('hoverCanvas');
									}
			this.cacheImages	 = 	function(that) {
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// 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.positionHover	=	function(that){
										tmh = classBehaviour.titleMouseHover;
										objHover = document.getElementById('hoverTitle');
										// mouse position
										tmh.mouseX = (typeof(event)!='undefined') ? event.clientX : that.clientX ;
										tmh.mouseY = (typeof(event)!='undefined') ? event.clientY : that.clientY ;
										// label position
										objHover.style.left = (tmh.mouseX>tmh.limitRight) ? tmh.limitRight + 'px' : tmh.mouseX + 'px';
										objHover.style.top =  tmh.mouseY + 'px';
									}
			this.addActive 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// 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 ;
									var objHover = document.getElementById('hoverTitle');
									// replace link by hover
									objNode.src = objNode.src.replace('_link','_hover');
									// fill the label with the contents of the title attribute
									objHover.innerHTML = objNode.title.replace('{img:','<img src="').replace('}','" class="left"/>');
									// show the title div
									objHover.style.display = 'block';
								}
			this.remHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// replace link by hover
									objNode.src = objNode.src.replace('_hover','_link');
									// hide the title div
									objHover = document.getElementById('hoverTitle');
									objHover.style.display = 'none';
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.titleMouseHover = new TitleMouseHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.titleMouseHover;
		
	// Add or remove display:none; onclick
		// define this class behaviour
		function AdjustSize(){
			// properties
			this.name 		= 	'adjustSize';
			// methods 
			this.start		=	function(){
									window.onresize = this.resize;
									this.resize();
								}
			// events
			this.delay		=	function(){
			
								}
			this.resize	= 	function(){
									// measure window size
									winWidth = (document.all) ? document.body.offsetWidth : window.innerWidth ;
									winHeight = (document.all) ? document.body.offsetHeight : window.innerHeight ;
									// adjust the classname according to the size
									if(winWidth>1024){
										document.body.className = document.body.className.replace('small','large').replace('medium','large');
									}else if(winWidth<800){
										document.body.className = document.body.className.replace('medium','small').replace('large','small');
									}else{
										document.body.className = document.body.className.replace('small','medium').replace('large','medium');
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.adjustSize = new AdjustSize;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.adjustSize;
		
	// Allows a file upload element to recieve fake markup
		// define this class behaviour
		function FileBrowser(){
			// properties
			this.name 		= 	'fileBrowser';
			this.fileElement	=	null;
			this.textElement	=	null;
			this.buttonElement	=	null;
			// methods 
			this.start			=	function(node){
										allInputs = node.getElementsByTagName('input');
										// get the form elements
										this.fileElement = allInputs[0];
										this.textElement = allInputs[1];
										this.buttonElement = allInputs[2];
										// when the file is entered
										this.fileElement.onchange = this.transfer;
										this.fileElement.onmouseover = this.addHover;
										this.fileElement.onmouseout = this.remHover;
									}
			// events
			this.addHover		=	function(){
										fb = classBehaviour.fileBrowser;
										fb.buttonElement.onmouseover();
									}
			this.remHover		=	function(){
										fb = classBehaviour.fileBrowser;
										fb.buttonElement.onmouseout();
									}
			this.transfer		=	function(){
										fb = classBehaviour.fileBrowser;
										fb.textElement.value = fb.fileElement.value;
									}
		}
		// add this function to the classbehaviour object
		classBehaviour.fileBrowser = new FileBrowser;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.fileBrowser;
		
	// sizes an element according to a value
		// define this class behaviour
		function ChartValue(){
			// properties 
			this.name 			= 	'chartValue';
			// methods 
			this.start			=	function(node){
										widthValue = parseInt(classBehaviour.utilities.getClassParameter(node, 'value', '0'));
										widthValue -= 1;
										if(widthValue<1) widthValue = 1;
										node.style.width = (widthValue-1) + '%';
									}
		}
		// add this function to the classbehaviour object
		classBehaviour.chartValue = new ChartValue;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.chartValue;
		
	// Copies selected text to a target container
		// define this class behaviour
		function TextSelection(){
			// properties 
			this.name 			= 	'textSelection';
			// methods 
			this.start			=	function(node){
										node.onmouseup = this.process;
									}
			// events
			this.process		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// get the target field
										var target = document.getElementById(classBehaviour.utilities.getClassParameter(objNode, 'id', 'selectedText'));
										// get the text selection
										var selected;
										if(window.getSelection){
											selected = window.getSelection();
										}else if(document.selection){
											selected = document.selection.createRange().text;
										}
										// copy the text to the target field
										if(target) target.value = selected;
										
									}
		}
		// add this function to the classbehaviour object
		classBehaviour.textSelection = new TextSelection;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.textSelection;
		
	// Shows elements based on the state of a related radio button or checkbox
		// define this class behaviour
		function DisplayIfChecked(){
			// properties
			this.name 		= 	'displayIfChecked';
			this.timeout	= 	null;
			// methods 
			this.start		=	function(node){
									node.onclick = this.delay;
									node.onchange = this.delay;
									this.delay(node);
								}
			// events
			this.delay  	=   function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var hsic = classBehaviour.displayIfChecked;
									// cancel the previous timeout
								//	clearTimeout(hsic.timeout);
									// wait a little while for MSIE
									hsic.timeout = setTimeout("classBehaviour.displayIfChecked.toggle('" + objNode.id + "')", 100);
								}
			this.toggle		= 	function(id){
									// source object
									var objNode = document.getElementById(id);
									// get all inputs
									var allInputs = document.getElementsByTagName('input');
									// for all inputs
									for(var a=0; a<allInputs.length; a++){
										// if this is a radio and it belong to the same named group
										if(allInputs[a].name==objNode.name){
											// get the target id
											targetId = classBehaviour.utilities.getClassParameter(allInputs[a], 'id', 'displayThisIdIfChecked');
											targetObj = document.getElementById(targetId);
											// hide the targetnode if checked
											if(targetObj){
												targetObj.style.display = (allInputs[a].checked) ? classBehaviour.utilities.getVisibleState(targetObj) : 'none' ;
											}
										}
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.displayIfChecked = new DisplayIfChecked;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.displayIfChecked;
		
	// fade the element in
		// define this class behaviour
		function FadeElement(){
			/* properties */
			this.name 		= 	'fadeElement';
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			this.set		=	function(id, amount){
									var node = document.getElementById(id);
									// 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.get		=	function(id){
									var fadeValue = null;
									var node = document.getElementById(id);
									// 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;
								}
			/* events */
			this.process	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// the node need an id
									if(objNode.id==''){
										objNode.id = 'fader' + Math.round(Math.random()*10000);
									}
									// fade parameters
									id		= objNode.id;
									wait	= parseInt(classBehaviour.utilities.getClassParameter(objNode, 'wait', '1024'));
									start	= parseInt(classBehaviour.utilities.getClassParameter(objNode, 'start', '0'));
									// start value
									this.set(objNode.id, start);
									// start the fade
									setTimeout("classBehaviour.fadeElement.loop('"+ id +"')", wait);
								}
			this.loop		=	function(id){
									var fe = classBehaviour.fadeElement;
									var objNode = document.getElementById(id);
									// fade parameters
									end			= parseInt(classBehaviour.utilities.getClassParameter(objNode, 'end', '100'));
									step		= parseInt(classBehaviour.utilities.getClassParameter(objNode, 'step', '10'));
									increment	= parseInt(classBehaviour.utilities.getClassParameter(objNode, 'increment', '5'));
									next		= fe.get(id) + increment;
									// set next fade status
									fe.set(id, next);
									// order a new step if needed
									if(next<end) setTimeout("classBehaviour.fadeElement.loop('" + id + "')", step);
								}
			this.crossFade	=	function(idOut, idIn, amount){
									var fe = classBehaviour.fadeElement;
									// if the amount is not 50
									if(amount<=100){
										// set the fade amounts
										fe.set(idIn, amount);
										fe.set(idOut, 100-amount);
										// unhide the new page
										document.getElementById(idIn).style.display = 'block';
										// repeat the fade
										setTimeout("classBehaviour.fadeElement.crossFade('" + idOut + "','" + idIn + "'," + (amount+10) + ")",50);
									}else{
									// else
										// hide the old page
										document.getElementById(idOut).style.display = 'none';
										// unlock the controls
										classBehaviour.fadeElement.locked = false;
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.fadeElement = new FadeElement;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.fadeElement;
		
	// make a decorative popup from a longdesc
		// define this class behaviour
		function ShowLongDesc(){
			/* properties */
			this.name 		= 	'showLongDesc';
			/* methods */
			this.start		=	function(node){
									// apply the event handler to the link
									loadXmlDoc(node.getAttribute('longdesc') + '?rnd='+Math.round(Math.random()*10000), this.load, this.wait, false, node);
									node.onmouseover = this.show;
									node.onmouseout = this.hide;
								}
			/* events */
			this.over		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var sld = classBehaviour.showLongDesc;
									// if this node doesn't have a display-node
									if(objNode.previousSibling.className != 'longDesc'){
										// make an AJAX call using the longdesc from the link
											loadXmlDoc(objNode.getAttribute('longdesc') + '?rnd='+Math.round(Math.random()*10000), sld.load, sld.wait, false, objNode);
									}else{
										// just show the link
										sld.show(objNode)
										// cancel click on the link
										return false;
									}
								}
			this.wait		=	function(status, targetObject){
									/* debug(status, targetObject.nodeName); */
								}
			this.load		=	function(xmlReply, targetObject){
									var sld = classBehaviour.showLongDesc;
									var objNode = targetObject;
									// create a display-node right after the link-node
									var displayNode = document.createElement('span');
									// add the replied xml content to the new node
									displayNode.innerHTML = xmlReply.getElementsByTagName('body')[0].firstChild.nodeValue;
									// apply a markup class to the new node
									displayNode.className = 'longDesc';
									// give the original link a special markup
									objNode.className += ' longDesc';
									objNode.parentNode.insertBefore(displayNode, objNode);
								}
			this.show		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// show the displaynode
									if(objNode.previousSibling.className=='longDesc') objNode.previousSibling.style.display = 'block';
								}
			this.hide		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// hide the node
									if(objNode.previousSibling.className=='longDesc') objNode.previousSibling.style.display = 'none';
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.showLongDesc = new ShowLongDesc;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.showLongDesc;
		
/* TODO: document this */
	// Toggle nodes of a certain class
		// define this class behaviour
		function ToggleMarkedNodes(){
			/* properties */
			this.name 		= 	'toggleMarkedNodes';
			this.lastNode	=	null;
			this.lastNext	=	null;
			/* methods */
			this.start		=	function(node){
									node.onclick = this.process;
								}
			/* events */
			this.process	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// toggleMarkedNodes id_myNodeList openText_Open_the_list closeText_Close_the_list
									
									listId = classBehaviour.utilities.getClassParameter(objNode, 'id', 'myNodeList');
									openText = classBehaviour.utilities.getClassParameter(objNode, 'openText', 'Show more...').replace(/_/gi,' ');
									closeText = classBehaviour.utilities.getClassParameter(objNode, 'closeText', 'Show less...').replace(/_/gi,' ');
									
									// get all nodes from the list
									allNodes = document.getElementById(listId).childNodes;
									// for every node in the list
									for(var a=0; a<allNodes.length; a++){
										// is it marked for hiding, show it if hidden, hide it if visible
										if(allNodes[a].className) 
											if(allNodes[a].className.indexOf('markedNode')>-1) 
												allNodes[a].style.display = (allNodes[a].style.display!='none') ? 'none' : 'block' ;
									}
									// if the button is set to open, set is to close, else, set it to open
									if(objNode.nodeName=='A'){
										objNode.firstChild.nodeValue = (objNode.firstChild.nodeValue==openText) ? closeText : openText;
									}else if(objNode.nodeName=='INPUT'){
										objNode.value = (objNode.value==openText) ? closeText : openText;
									}
									
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.toggleMarkedNodes = new ToggleMarkedNodes;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.toggleMarkedNodes;
		
	// Update a slide based on clicks on thumbnails
		// define this class behaviour
		function ThumbnailToPhoto(){
			/* properties */
			this.name 		= 	'thumbnailToPhoto';
			this.busy		=	false;
			/* methods */
			this.start		=	function(node){
									// set the event for this thumbnail
									node.onclick = this.showPhoto;
									// set the doublebuffer initial state
									var targetId = classBehaviour.utilities.getClassParameter(node, 'id', 'photoTarget');
									document.getElementById(targetId).getElementsByTagName('img')[0].style.display = 'block';
									document.getElementById(targetId).getElementsByTagName('img')[1].style.display = 'none';
								}
			/* events */
			this.showPhoto	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var ttp = classBehaviour.thumbnailToPhoto;
									// get the display buffers
									var targetId = classBehaviour.utilities.getClassParameter(objNode, 'id', 'photoTarget');
									bufferA = document.getElementById(targetId).getElementsByTagName('img')[0];
									bufferB = document.getElementById(targetId).getElementsByTagName('img')[1];
									// get the active buffer 
									bufferIn = (bufferA.style.display=='none') ? bufferA : bufferB;
									bufferOut = (bufferIn==bufferA) ? bufferB : bufferA ;
									// get the target values from the thumbnail
									targetAlt = objNode.getElementsByTagName('img')[0].alt;
									targetSrc = objNode.href;
									// if there is no fade in progress and the target os not the same as the current image
									if(!ttp.busy && targetSrc!=bufferOut.src){
										// lock this function
										ttp.busy = true;
										// set the new source for the image from the clicked thumbnail
										bufferIn.alt = targetAlt;
										bufferIn.src = targetSrc;
										// call the fader after the image has loaded
										bufferIn.onload = 	new function(){
																// trigger the crossfade
																classBehaviour.fader.crossFade(bufferIn.id, bufferOut.id, 0, 10, 50, 'classBehaviour.thumbnailToPhoto.unlock()');
															};
									}
									// cancel the click
									return false;
								}
			this.unlock		=	function(){
									classBehaviour.thumbnailToPhoto.busy = false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.thumbnailToPhoto = new ThumbnailToPhoto;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.thumbnailToPhoto;
		
	// Update a slide based on clicks on radio-buttons
		// define this class behaviour
		function RadioToPhoto(){
			/* properties */
			this.name 		= 	'radioToPhoto';
			/* methods */
			this.start		=	function(node){
									node.onclick = this.setImage;
								}
			/* events */
			this.setImage	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// where is the target
									targetId = classBehaviour.utilities.getClassParameter(objNode, 'id', 'photoTarget');
									// set the source
									document.getElementById(targetId).src = objNode.value;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.radioToPhoto = new RadioToPhoto;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.radioToPhoto;
		
	// clear a form element filled with a help text
		// define this class behaviour
		function EmptyOnFocus(){
			/* properties */
			this.name 		= 	'emptyOnFocus';
			/* methods */
			this.start		=	function(node){
									node.onfocus = this.clear;
								}
			/* events */
			this.clear		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// clear the contents if this is the first time
									if(objNode.className.indexOf('wasEmptied')<0){
										// clear this field
										objNode.value = '';
										// mark this input as cleared
										objNode.className += ' wasEmptied';
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.emptyOnFocus = new EmptyOnFocus;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.emptyOnFocus;
		
	// Make fading menu
		// define this class behaviour
		function FadingMenu(){
			/* properties */
			this.name 		= 	'fadingMenu';
			this.current 	=	null;
			this.always		=	null;
			this.locked		=	false;
			this.timeout	=	null;
			this.index		=	0;
			/* methods */
			this.start		=	function(node){
									this.process(node);
								}
			this.process 	= 	function(objNode){
									var objNodes, objMatch;
									// apply events to all LIs
									objNodes = objNode.childNodes;
									for(var a=0; a<objNodes.length; a++){
										if(objNodes[a].nodeName=="LI"){
											// if this LI has a link and submenus evident by their links
											objLinks = objNodes[a].getElementsByTagName('A');
											if(objLinks.length>0){
												// default classname
												objLinks[0].className += (objLinks[0].className.indexOf('link')<0 || objLinks[0].className.indexOf('active')<0) ? ' link' : '' ;
												// mouseover events
												objLinks[0].onmousemove	= this.open;
												// store the last link marked active
												this.always = (objLinks[0].className.indexOf('active')>-1) ? objLinks[0] : this.always ;
											}
											// if this LI has a child UL, 
											objLists = objNodes[a].getElementsByTagName('UL');
											if(objLists.length>0){
												// give it a random id
												this.index++;
												objLists[0].id = 'sub_' + this.index;
												// delay the closing of the menu when over subitems
												objLinks = objLists[0].getElementsByTagName('A');
												for(var b=0; b<objLinks.length; b++) objLinks[b].onmouseover = this.cancel;
											}
										}
									}
									// global close event
									objNode.onmouseout	= this.delay;
									// open the starting node
									this.open(this.always, true);
								}
			/* events */
			this.open 		= 	function(that, noFade){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var fm = classBehaviour.fadingMenu;
									// cancel the closing timer
									clearTimeout(fm.timeout);
									// if not locked
									if(!fm.locked && objNode!=fm.current){
										// PREVIOUS MENU
										if(fm.current){
											// deactivate the link
											fm.current.className = fm.current.className.replace('hover','link');
											// deactivate the image
				//							linkImage = fm.current.getElementsByTagName('IMG')[0];
				//							linkImage.src = linkImage.src.replace('_hover','_link');
											// store the sub-menu
											linkMenu = fm.current.parentNode.getElementsByTagName('UL');
											fadeCloseId = (linkMenu.length>0) ? linkMenu[0].id : '' ;
										}else{
											fadeCloseId = '';
										}
										// OPEN NEW MENU
										if(objNode){
											// deactivate the link
											objNode.className = objNode.className.replace('link','hover');
											// activate the image
				//							linkImage = objNode.getElementsByTagName('IMG')[0];
				//							linkImage.src = linkImage.src.replace('_link','_hover');
											// store the sub-menu
											linkMenu = objNode.parentNode.getElementsByTagName('UL');
											fadeOpenId = (linkMenu.length>0) ? linkMenu[0].id : '' ;
										}
										// store the current link 
										fm.current = objNode;
										// SET THE FADE
										if(noFade){
											if(fadeOpenId!='') document.getElementById(fadeOpenId).style.display = 'block';
											if(fadeCloseId!='') document.getElementById(fadeCloseId).style.display = 'none';
										}else{
											fm.locked = true;
											classBehaviour.fader.crossFade(fadeOpenId, fadeCloseId, 0, 10, 20, 'classBehaviour.fadingMenu.locked=false;');
										}
									}
								}
			this.cancel	=	function(){
									var fm = classBehaviour.fadingMenu;
									// clear the previous delay
									clearTimeout(fm.timeout);
								}
			this.delay		=	function(){
									var fm = classBehaviour.fadingMenu;
									// clear the previous delay
									clearTimeout(fm.timeout);
									// delay the closing
									fm.timeout = setTimeout('classBehaviour.fadingMenu.close()', 512);
								}
			this.close 		= 	function(){
									var fm = classBehaviour.fadingMenu;
									// if not locked
									if(!fm.locked){
										fm.open(fm.always);
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.fadingMenu = new FadingMenu;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.fadingMenu;
		
	// scroll every element into view
		// starting style
		document.writeln('<style>.scrollIn {visibility : hidden;}</style>')
		// define this class behaviour
		function ScrollIn(){
			/* properties */
			this.name 		= 	'scrollIn';
			/* methods */
			this.start		=	function(node){
									// for all nodes in the list
									var allNodes = node.getElementsByTagName('li');
									for(var a=0; a<allNodes.length; a++){
										// move the node it's length back and an additional factor
										allNodes[a].style.marginLeft = ((a - allNodes.length) * 60 - 240) + 'px';
									}
									// make the list visible
									node.style.visibility = 'visible';
									// start the animation loop
									this.loop(node.id);
								}
			/* events */
			this.loop		=	function(id){
									var repeat = false;
									var offset = 0;
									// for all nodes in the list
									var allNodes = document.getElementById(id).getElementsByTagName('li');
									for(var a=0; a<allNodes.length; a++){
										offSet = parseInt(allNodes[a].style.marginLeft);
										// if the offset isn't 0
										if(offSet<0){
											// reduce the offset
											allNodes[a].style.marginLeft = (offSet + 5) + 'px';
											// order a next step
											repeat = true;
										}
									}
									// repeat the loop
									setTimeout('classBehaviour.scrollIn.loop("'+id+'")',10);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.scrollIn = new ScrollIn;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.scrollIn;
		
	// scroll a list of options
		// define this class behaviour
		function ScrollList(){
			/* properties */
			this.name 		= 	'scrollList';
			this.list		=	null;
			this.focus		=	null;
			this.speed		=	1;
			this.idleTimer	=	null;
			/* methods */
			this.start		=	function(node){
									// add the right event handler to the button
									node.onmousedown = (classBehaviour.utilities.getClassParameter(node, 'scrollDirection', 'down')=='up') ? this.startUp : this.startDown ;
									node.onmouseover = this.cancel;
									node.onmouseup = this.cancel;
									node.onmouseout = this.cancel;
									// prepare the refered list
									id = classBehaviour.utilities.getClassParameter(node, 'id', 'scrollList0');
									this.prepareList(id);
								}
			/* events */
			this.startUp	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var sl = classBehaviour.scrollList;
									// reset all scrolling
									id = sl.reset(objNode);
									// start the scrolling
									sl.scrollUp(id);
								}
			this.startDown	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var sl = classBehaviour.scrollList;
									// reset all scrolling
									id = sl.reset(objNode);
									// start the scrolling
									sl.scrollDown(id);
								}
			/* methods */
			this.idle			=	function(id){
										classBehaviour.scrollList.speed = 1;
										classBehaviour.scrollList.scrollDown(id);
									}
			this.prepareList	=	function(id) {
										scroller = document.getElementById(id);
										// if this list has not has not been prepared before
										if(scroller.className.indexOf('doubled')<0){
											// copy the content twice
											scrollList = scroller.getElementsByTagName('UL')[0];
											scrollList.innerHTML += scrollList.innerHTML + scrollList.innerHTML;
											// set the scroller halfway
											var contentWidth = scrollList.offsetWidth;
											scrollList.style.marginLeft = '-' + Math.round(contentWidth/3) + 'px';
											// mark the list as prepared
											scroller.className += ' doubled';
											// start the idle scrolling
											classBehaviour.scrollList.idle(id);
										}
									}
			this.reset			=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var sl = classBehaviour.scrollList;
										// clear the idle timer
										clearTimeout(sl.idleTimer);
										// stop the scrolling
										clearTimeout(sl.timeout);
										// reset the speed
										sl.speed = 5;
										// get the target id
										id = classBehaviour.utilities.getClassParameter(objNode, 'id', 'scrollList0');
										// set the mouseover
										objNode.src = objNode.src.replace('_link','_hover');
										// pass the id back
										return id;
									}
			this.cancel		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var sl = classBehaviour.scrollList;
										// clear the idle timer
										clearTimeout(sl.idleTimer);
										// stop the scrolling
										clearTimeout(sl.timeout);
										// release the focus
										sl.focus = null;
										// reset the mouseover
										objNode.src = objNode.src.replace('_hover','_link');
										// wait for a while, then start idle scrolling
										id = classBehaviour.utilities.getClassParameter(objNode, 'id', 'scrollList0');
										sl.idleTimer = setTimeout('classBehaviour.scrollList.idle("'+id+'")',2000);
									}
			this.scrollUp	=	function(id){
									var sl = classBehaviour.scrollList;
									// how high is the container
									var container = document.getElementById(id);
									var borderWidth = container.offsetWidth;
									// how heigh is the content
									var content = container.getElementsByTagName('UL')[0];
									var contentWidth = content.offsetWidth;
									// where is the content
									var contentScroll = (content.style.marginLeft) ? parseInt(content.style.marginLeft) : 0 ;
									// if the contant can still move
									loopPoint = 0
									resetPoint = -1 * Math.round(contentWidth/3);
									if(contentScroll<loopPoint){
										// move it
										content.style.marginLeft = (contentScroll + sl.speed) + 'px';
									// reset it back to the starting position
									}else{
										content.style.marginLeft = (resetPoint - sl.speed) + 'px';
									}
									// next step
									sl.timeout = setTimeout('classBehaviour.scrollList.scrollUp("' + id + '")', 40);
								}
			this.scrollDown	=	function(id){
									var sl = classBehaviour.scrollList;
									// how high is the container
									var container = document.getElementById(id);
									var borderWidth = container.offsetWidth;
									// how heigh is the content
									var content = container.getElementsByTagName('UL')[0];
									var contentWidth = content.offsetWidth;
									// where is the content
									var contentScroll = (content.style.marginLeft) ? parseInt(content.style.marginLeft) : 0 ;
									// if the contant can still move
									loopPoint = -2 * Math.round(contentWidth/3);
									resetPoint = -1 * Math.round(contentWidth/3);
									if(loopPoint<contentScroll){
										// move it
										content.style.marginLeft = (contentScroll - sl.speed) + 'px';
									// reset it back to the starting position
									}else{
										content.style.marginLeft = (resetPoint - sl.speed) + 'px';
									}
									// next step
									sl.timeout = setTimeout('classBehaviour.scrollList.scrollDown("' + id + '")', 40);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.scrollList = new ScrollList;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.scrollList;
		
	// manage the customization budget
		// define this class behaviour
		function CustomizeList(){
			/* properties */
			this.name 		= 	'customizeList';
			this.list		=	null;
			/* methods */
			this.start		=	function(node){
									// store the list
									this.list = node;
									// get all the form elements in the list
									allInputs = node.getElementsByTagName('input');
									// for all for elements
									for(var a=0; a<allInputs.length; a++){
										// if this elements is a radiobutton
										if(allInputs[a].getAttribute('type')=='radio'){
											// add the event handler
											allInputs[a].onchange = this.redraw;
										}
									}
									// calculate the total price
									this.redraw();
								}
			/* events */
			this.redraw		=	function(){
									var czl = classBehaviour.customizeList;
									// get the default price
									var totalPrice = parseInt(document.getElementById('customizeBase').value);
									var optionsList = '';
									// get all lists
									allLists = czl.list.getElementsByTagName('ul');
									// for all lists
									for(var a=0; a<allLists.length; a++){
										// get all list items
										allItems = allLists[a].getElementsByTagName('input');
										// for all list items
										for(var b=0; b<allItems.length; b++){
											// if the list item is checked
											if(allItems[b].checked){
												// highlight the item
												allItems[b].parentNode.parentNode.className = allItems[b].parentNode.parentNode.className.replace('passive', 'active');
												// add the price difference
												totalPrice += parseInt(allItems[b].parentNode.getElementsByTagName('input')[1].value);
												// add the option to the options list
												optionsList += '<li><span>' + allItems[b].parentNode.getElementsByTagName('label')[0].innerHTML + '</span></li>'
											// else
											}else{
												// remove the highlight
												allItems[b].parentNode.parentNode.className = allItems[b].parentNode.parentNode.className.replace('active', 'passive');
											}
										}
									}
									// post the total price
										document.getElementById('customizePrice').innerHTML = totalPrice.toFixed(2);
										// document.getElementById('customizePrice').innerHTML = totalPrice.toLocaleString();
									// post the options list
									document.getElementById('customizeList').innerHTML = optionsList;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.customizeList = new CustomizeList;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.customizeList;
		
	// make a slideshow from a list of images
		// define this class behaviour
		function SlideshowList(){
			/* properties */
			this.name 		= 	'slideshowList';
			this.locked	=	false;
			/* methods */
			this.start		=	function(node){
									// get the next and previous buttons
									allButtons = node.getElementsByTagName('button');
									// set the event handlers
									if(allButtons.length>0) allButtons[allButtons.length-1].onclick = this.next;
									if(allButtons.length>1) allButtons[allButtons.length-2].onclick = this.previous;
									// set the default states of the slides
									allSlides = node.getElementsByTagName('li');
									allSlides[0].className += (allSlides[0].className.indexOf('active')<0) ? ' active' : '' ;
									for(var a=0; a<allSlides.length; a++) 
										allSlides[a].style.display = (allSlides[a].className.indexOf('active')>-1) ? 'block' : 'none' ;
								}
			/* events */
			this.next		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									if(!classBehaviour.slideshowList.locked){
										classBehaviour.slideshowList.locked = true;
										// get all slides
										allSlides = objNode.parentNode.getElementsByTagName('li');
										// default starting position
										var activeSlide = allSlides[0];
										var nextSlide = allSlides[1];
										// look for the active node
										for(var a=0; a<allSlides.length; a++){
											// if the slide doesn't have an id, make one
											allSlides[a].id = (allSlides[a].id) ? allSlides[a].id : 'slide' + a;
											// if this slide is marked active
											if(allSlides[a].className.indexOf('active')>-1){
												// store the active slide
												activeSlide = allSlides[a];
												// store the next slide
												nextSlide = (a<allSlides.length-1) ? allSlides[a+1] : allSlides[0] ;
											}
										}
										// set the display state
										activeSlide.style.position = 'absolute';
										nextSlide.style.position = 'relative';
										// change the classes
										activeSlide.className = activeSlide.className.replace(' active','').replace('active','');
										nextSlide.className += ' active';
										// fade between the active and next slide
										classBehaviour.fader.crossFade(nextSlide.id, activeSlide.id, 0, 5, 10, "classBehaviour.slideshowList.unlock()");
									}
								}
			this.previous	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									if(!classBehaviour.slideshowList.locked){
										classBehaviour.slideshowList.locked = true;
										// get all slides
										allSlides = objNode.parentNode.getElementsByTagName('li');
										// default starting position
										var activeSlide = allSlides[0];
										var nextSlide = allSlides[allSlides.length-1];
										// look for the active node
										for(var a=0; a<allSlides.length; a++){
											// if the slide doesn't have an id, make one
											allSlides[a].id = (allSlides[a].id) ? allSlides[a].id : 'slide' + a;
											// if this slide is marked active
											if(allSlides[a].className.indexOf('active')>-1){
												// store the active slide
												activeSlide = allSlides[a];
												// store the next slide
												nextSlide = (a>0) ? allSlides[a-1] : allSlides[allSlides.length-1] ;
											}
										}
										// set the display state
										activeSlide.style.position = 'absolute';
										nextSlide.style.position = 'relative';
										// change the classes
										activeSlide.className = activeSlide.className.replace(' active','').replace('active','');
										nextSlide.className += ' active';
										// fade between the active and next slide
										classBehaviour.fader.crossFade(nextSlide.id, activeSlide.id, 0, 5, 10, "classBehaviour.slideshowList.unlock()");
									}
								}
			this.unlock	=	function(){
									this.locked = false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.slideshowList = new SlideshowList;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.slideshowList;
		
	// Enrich a calendar control
		// define this class behaviour
		function DatePicker(){
			/* properties */
			this.name 			= 	'datePicker';
			this.monthNames 	= 	new Array('januari','februari','maart','april','mei','juni','juli','augustus','september','oktober','november','december');
			this.dateHtml		=	'<div class="dateBorder">\n'+
									'	<ul class="controls">\n'+
									'		<li><button class="previous srcMouseHover"><img alt="Previous Month" src="../images/icon_prev_link.png"/></button></li>\n'+
									'		<li><button class="next srcMouseHover"><img alt="Next Month" src="../images/icon_next_link.png"/></button></li>\n'+
									'	</ul>\n'+
									'	<table class="dateTable">\n'+
									'		<caption>\n'+
									'			<select id="month4" name="month4" class="month">\n'+
									'				<option value="0">jan</option>\n'+
									'				<option value="1">feb</option>\n'+
									'				<option value="2">mar</option>\n'+
									'				<option value="3">apr</option>\n'+
									'				<option value="4">mei</option>\n'+
									'				<option value="5">jun</option>\n'+
									'				<option value="6">jul</option>\n'+
									'				<option value="7">aug</option>\n'+
									'				<option value="8">sep</option>\n'+
									'				<option value="9">okt</option>\n'+
									'				<option value="10">nov</option>\n'+
									'				<option value="11">dec</option>\n'+
									'			</select>\n'+
									'			<select id="year4" name="year4" class="year">\n'+
									'				<option value="2007" selected="selected">2007</option>\n'+
									'			</select>\n'+
									'		</caption>\n'+
									'		<thead>\n'+
									'			<tr>\n'+
									'				<th scope="col">z</th>\n'+
									'				<th scope="col">m</th>\n'+
									'				<th scope="col">d</th>\n'+
									'				<th scope="col">w</th>\n'+
									'				<th scope="col">d</th>\n'+
									'				<th scope="col">v</th>\n'+
									'				<th scope="col">z</th>\n'+
									'			</tr>\n'+
									'		</thead>\n'+
									'		<tbody>\n'+
									'			<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td><td>{5}</td><td>{6}</td></tr>\n'+
									'			<tr><td>{7}</td><td>{8}</td><td>{9}</td><td>{10}</td><td>{11}</td><td>{12}</td><td>{13}</td></tr>\n'+
									'			<tr><td>{14}</td><td>{15}</td><td>{16}</td><td>{17}</td><td>{18}</td><td>{19}</td><td>{20}</td></tr>\n'+
									'			<tr><td>{21}</td><td>{22}</td><td>{23}</td><td>{24}</td><td>{25}</td><td>{26}</td><td>{27}</td></tr>\n'+
									'			<tr><td>{28}</td><td>{29}</td><td>{30}</td><td>{31}</td><td>{32}</td><td>{33}</td><td>{34}</td></tr>\n'+
									'			<tr><td>{35}</td><td>{36}</td><td>{37}</td><td>{38}</td><td>{39}</td><td>{40}</td><td>{41}</td></tr>\n'+
									'		</tbody>\n'+
									'	</table>\n'+
									'</div>';
			/* methods */
			this.start		=	function(node){
									classBehaviour.toggleNextNode.start(node);
									// construct the calendar html
									this.build(node);
									// set the event handlers for this node
									node.onclick = this.open;
								}
			this.set		=	function(calendarNode, date){
									dpr = classBehaviour.datePicker;
									// get the next and previous buttons
									calendarNode.getElementsByTagName('button')[0].onclick = dpr.previous;
									calendarNode.getElementsByTagName('button')[1].onclick = dpr.next;
									// set the month dropdown
									monthNode = calendarNode.getElementsByTagName('select')[0];
									monthNode.selectedIndex = date.getMonth();
									monthNode.onchange = dpr.update;
									// set the year dropdown
									yearSelect = calendarNode.getElementsByTagName('select')[1];
									yearOptions = yearSelect.getElementsByTagName('option');
									currentYear = date.getFullYear();
									if(yearOptions.length==1){
										yearOption = yearOptions[0].cloneNode(true);
										for(var a=currentYear-100; a<currentYear+10; a++ ){
											yearOption = yearSelect.getElementsByTagName('option')[0].cloneNode(true);
											yearOption.value = a;
											yearOption.selected = (a==currentYear) ? 'selected' : '' ;
											yearOption.text = a;
											yearSelect.appendChild(yearOption);
										}
										yearSelect.removeChild(yearSelect.getElementsByTagName('option')[0]);
										yearSelect.onchange = dpr.update;
									}else{
										for(var a=0; a<yearOptions.length; a++) yearOptions[a].selected = (yearOptions[a].value==currentYear) ? 'selected' : '' ;
									}
									// clear out the previous month
									daySlots = calendarNode.getElementsByTagName('td');
									for(var a=0; a<daySlots.length; a++){
										daySlots[a].className = "empty";
										daySlots[a].innerHTML = "";
										daySlots[a].onclick = null;
									}
									// fill the new month
									currentDay = new Date(date.getFullYear(), date.getMonth(), 1);
									nextDay = new Date(date.getFullYear(), date.getMonth(), 2);
									startWeekDay = currentDay.getDay()-1;
									while(currentDay.getDate() < nextDay.getDate()){
										// put the date on the weekday cell
										daySlots[currentDay.getDate()+startWeekDay].innerHTML = currentDay.getDate();
										daySlots[currentDay.getDate()+startWeekDay].className = "";
										daySlots[currentDay.getDate()+startWeekDay].onclick = dpr.pick;
										// next date
										currentDay = new Date(currentDay.getFullYear(), currentDay.getMonth(), currentDay.getDate()+1);
										nextDay = new Date(nextDay.getFullYear(), nextDay.getMonth(), nextDay.getDate()+1);
									}
								}
			this.build		=	function(node){
									calendar = classBehaviour.utilities.nextNode(node);
									calendar.innerHTML = this.dateHtml;
									classBehaviour.parseDocument(calendar);
								}
			/* events */
			this.open		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dpr = classBehaviour.datePicker;
									// OBJECTS
									calendar = classBehaviour.utilities.nextNode(objNode);
									// STARTING DATE
									// get the input from the field
									// turn it into a date
									// if the result is a date
										// use it as a start date
									// else
										// take the current date
										date = new Date();
									// CONSTRUCT THE CALENDAR AT THE GIVEN DATE
									dpr.set(calendar, date);
									// POSITION THE CALENDAR
									// get the position
									screenXpos = (typeof(event)!='undefined') ? (event.clientX) : (that.pageX);
									screenYpos = (typeof(event)!='undefined') ? (event.clientY) : (that.pageY);
									// if the position is too close to the edge
									calendarWidth = calendar.firstChild.offsetWidth;
									screenWidth = (window.innerWidth) ? window.innerWidth : (document.documentElement.clientWidth) ? document.documentElement.clientWidth : document.body.clientWidth ;
									if(screenXpos+calendarWidth > screenWidth+window.pageXOffset) screenXpos -= calendarWidth;
									// if the position is too close to the bottom
									calendarHeight = calendar.firstChild.offsetHeight;
									screenHeight = (window.innerHeight) ? window.innerHeight : (document.documentElement.clientHeight) ? document.documentElement.clientHeight : document.body.clientHeight ;
									if(screenYpos+calendarHeight+10 > screenHeight+window.pageYOffset) screenYpos -= calendarHeight;
									// set the position
									calendar.style.left = screenXpos + 'px';
									calendar.style.top = screenYpos + 'px';
									// SHOW THE CALENDAR
									classBehaviour.toggleNextNode.toggle(objNode);
								}
			this.update	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dpr = classBehaviour.datePicker;
									// get both selectors from the parent node
									selectors = objNode.parentNode.getElementsByTagName('select');
									// get the month
									month = parseInt(selectors[0].value);
									// get the year
									year = parseInt(selectors[1].value);
									// make a date out of it
									date = new Date(year, month, 1);
									// update the calendar
									dpr.set(objNode.parentNode.parentNode.parentNode.parentNode,date);
								}
			this.next		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dpr = classBehaviour.datePicker;
									// get the calendar
									calendar = objNode.parentNode.parentNode.parentNode.parentNode;
									// get the displayed date
									month = parseInt(objNode.parentNode.parentNode.parentNode.getElementsByTagName('select')[0].value);
									year = parseInt(objNode.parentNode.parentNode.parentNode.getElementsByTagName('select')[1].value);
									// add a month
									date = new Date(year,month+1,1);
									// build the calendar
									dpr.set(calendar,date);
								}
			this.previous	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dpr = classBehaviour.datePicker;
									// get the calendar
									calendar = objNode.parentNode.parentNode.parentNode.parentNode;
									// get the displayed date
									month = parseInt(objNode.parentNode.parentNode.parentNode.getElementsByTagName('select')[0].value);
									year = parseInt(objNode.parentNode.parentNode.parentNode.getElementsByTagName('select')[1].value);
									// subsctract a month
									date = new Date(year,month-1,1);
									// build the calendar
									dpr.set(calendar,date);
								}
			this.pick		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// get the selected day
									dayValue = objNode.innerHTML;
									// get the selected month
									calendarTitle = objNode.parentNode.parentNode.parentNode.getElementsByTagName('caption')[0];
									month = calendarTitle.getElementsByTagName('select')[0];
										// monthValue = month[month.selectedIndex].innerHTML;
									monthValue = parseInt(month.value) + 1;
									// get the selected year
									year = calendarTitle.getElementsByTagName('select')[1];
									yearValue = year[year.selectedIndex].innerHTML;
									// put it in the input field
									targetFields = objNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.getElementsByTagName('input');
									targetFields[0].value = ((dayValue+'').length==1) ? '0' + dayValue  : dayValue;
									targetFields[1].value = ((monthValue+'').length==1) ? '0' + monthValue : monthValue;
									targetFields[2].value = yearValue;
									// close the calendar
									calendarButton = objNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.getElementsByTagName('button')[0];
									classBehaviour.toggleNextNode.toggle(calendarButton);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.datePicker = new DatePicker;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.datePicker;
		
	// Center landscape or portrait thumbnails in a defined area
		// define this class behaviour
		function CenteredThumbnails(){
			/* properties */
			this.name 		= 	'centeredThumbnails';
			/* methods */
			this.start		=	function(node){
									// get all links in this container
									allLinks = node.getElementsByTagName('a');
									// if this is a single item
									if(allLinks.length==0) allLinks = new Array(node);
									// for all containers
									for(var a=0; a<allLinks.length; a++){
										// get the dimensions of the container
										containerSize = new Array(allLinks[a].offsetWidth, allLinks[a].offsetHeight);
										// get the thumbnail
										thumbnail = allLinks[a].getElementsByTagName('img')[0];
										// get the dimensions of the thumbnail
										thumbnailSize = new Array(thumbnail.offsetWidth, thumbnail.offsetHeight);
										// set the position of the thumbnail
										offsetX = (containerSize[0] - thumbnailSize[0])/2;
										offsetY = (containerSize[1] - thumbnailSize[1])/2;
										thumbnail.style.margin = offsetY + "px " + offsetX + "px " + offsetY + "px " + offsetX + "px";
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.centeredThumbnails = new CenteredThumbnails;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.centeredThumbnails;
		
	// hover the next node near the mouse pointer
		// define this class behaviour
		function HoverNextNode(){
			/* properties */
			this.name 		= 	'hoverNextNode';
			/* methods */
			this.start		=	function(node){
									// mouse handlers
									node.onmouseover = this.show;
									node.onmouseout = this.hide;
									node.onmousemove = this.place;
								}
			/* events */
			this.show		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									targetNode = classBehaviour.utilities.nextNode(objNode);
									targetNode.style.visibility = 'visible';
								}
			this.hide		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									targetNode = classBehaviour.utilities.nextNode(objNode);
									targetNode.style.visibility = 'hidden';
								}
			this.place		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									targetNode = classBehaviour.utilities.nextNode(objNode);
									targetNode.style.position = 'absolute';
									targetNode.style.left = (typeof(event)!='undefined') ? (event.x) + 'px' : (that.layerX) + 'px' ;
									targetNode.style.top = (typeof(event)!='undefined') ? (event.y) + 'px' : (that.layerY) + 'px' ;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.hoverNextNode = new HoverNextNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.hoverNextNode;
		
	// show specific content as a floating layer
		// define this class behaviour
		function FloatingDescription(){
			/* properties */
			this.name 		= 	'floatingDescription';
			this.display	=	document.getElementById('floatingDescription');
			/* methods */
			this.start		=	function(node){
									// set the mouse interaction
									node.onmouseover = this.show;
									node.onmouseout = this.hide;
									node.onmousemove = this.place;
									// extra for Safari
									node.onmousedown = this.place;
									document.onclick = this.hide;
								}
			/* events */
			this.show		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var fdn = classBehaviour.floatingDescription;
									// get the desired content from the active node
									likelyContainers = objNode.getElementsByTagName('div');
									for(var a=0; a<likelyContainers.length; a++)
										if(likelyContainers[a].className.indexOf('description')>-1)
											descriptionHtml = likelyContainers[a].innerHTML;
									// fill the floating description
									fdn.display.innerHTML = descriptionHtml;
									// show the floating display
									fdn.display.style.visibility = 'visible';
								}
			this.hide		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var fdn = classBehaviour.floatingDescription;
									// hide the floating display
									fdn.display.style.visibility = 'hidden';
								}
			this.place		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var fdn = classBehaviour.floatingDescription;
									// get an optional width
									width = parseInt(classBehaviour.getClassParameter(objNode, 'width', '-1'));
									fdn.display.style.width = (width>0) ? width + 'px' : 'auto' ;
									// get the position
									screenXpos = (typeof(event)!='undefined') ? (event.clientX) : (that.pageX);
									screenYpos = (typeof(event)!='undefined') ? (event.clientY) : (that.pageY);
									// if the position is too close to the edge
									screenWidth = (window.innerWidth) ? window.innerWidth : (document.documentElement.clientWidth) ? document.documentElement.clientWidth : document.body.clientWidth ;
									if(screenXpos>screenWidth-fdn.display.offsetWidth) screenXpos -= fdn.display.offsetWidth;
									// if the position is too close to the bottom
									screenHeight = (window.innerHeight) ? window.innerHeight : (document.documentElement.clientHeight) ? document.documentElement.clientHeight : document.body.clientHeight ;
									labelHeight = document.getElementById('floatingDescription').offsetHeight;
									if(screenYpos+labelHeight+10>screenHeight) screenYpos -= labelHeight;
									// reposition the floating display
									fdn.display.style.position = 'absolute';
									fdn.display.style.left = screenXpos + 'px' ;
									fdn.display.style.top = screenYpos + 'px' ;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.floatingDescription = new FloatingDescription;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.floatingDescription;
		
	// Use SwfObject to replace a title with a flash version
		// hide the alternative beforehand
		document.writeln("<style>.flashTitle .alternative{visibility : hidden;}</style>");
		// define this class behaviour
		function FlashTitle(){
			/* properties */
			this.name 		= 	'flashTitle';
			this.index		=	0;
			/* methods */
			this.start		=	function(node){
									// give the node an id of it doesn't have one
									if(!node.id){
										node.id = 'flashTitle' + this.index;
										this.index += 1;
									}
									// delay the loading of the flash
									classBehaviour.flashTitle.process(node.id);
								}
			this.process	=	function(id){
									node = document.getElementById(id);
									// set the default values for all parameters
									flashMovie		= "../flash/title.swf";
									flashWidth		= node.offsetWidth;
									flashHeight		= node.offsetHeight;
									flashVersion	= "7";
									flashBuild		= "0";
									flashWmode		= "Transparent";
									flashScale		= "noScale";
									flashSalign		= "l";
									flashName		= "_" + id;
									flashVariables	= "lorem=ipsum&dolor=sit amet";
									// for all childnodes of node which may contain configuration variables
									for(var a=0; a<node.childNodes.length; a++){
										if(node.childNodes[a].className == "movie") flashMovie = node.childNodes[a].value;
										if(node.childNodes[a].className == "width") flashWidth = node.childNodes[a].value;
										if(node.childNodes[a].className == "height") flashHeight = node.childNodes[a].value;
										if(node.childNodes[a].className == "majorversion") flashVersion = node.childNodes[a].value;
										if(node.childNodes[a].className == "build") flashBuild = node.childNodes[a].value;
										if(node.childNodes[a].className == "wmode") flashWmode = node.childNodes[a].value;
										if(node.childNodes[a].className == "scale") flashScale = node.childNodes[a].value;
										if(node.childNodes[a].className == "salign") flashSalign = node.childNodes[a].value;
										if(node.childNodes[a].className == "name") flashName = node.childNodes[a].value;
										if(node.childNodes[a].className == "flashvars") flashVariables = node.childNodes[a].value;
									}
									// 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;
									// get the alternative to the flash content and filter a title from it
									flashVariables = "inputText=" + node.innerHTML.replace(/<(.|\n)*?>/gi,"").replace(/^\s+/gi,"") + "&" + flashVariables;
									// load the flash plugin for "UFO"
									if(UFO){
										var FO = { 
											movie			: flashMovie,
											width			: flashWidth, 
											height			: flashHeight,
											majorversion	: flashVersion, 
											build			: flashBuild, 
											wmode			: flashWmode,
											scale			: flashScale,
											salign			: flashSalign,
											id				: flashName,
											name			: flashName,
											flashvars		: flashVariables
										}
										UFO.create(FO, node.id);
									}
								}
			/* events */
		}
		// add this function to the classbehaviour object
		classBehaviour.flashTitle = new FlashTitle;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.flashTitle;
		
/* TODO: document this */
	// Defines something a layer popup and automaticaly opens it after a set time
		// define this class behaviour
		function ThumbnailToPhoto(){
			/* properties */
			this.name 		= 	'thumbnailToPhoto';
			this.busy		=	false;
			this.index		=	0;
			this.cache		=	new Array();
			/* methods */
			this.start		=	function(node){
									// set the event for this thumbnail
									node.onclick = this.showPhoto;
									// get the target id
									var targetId = classBehaviour.utilities.getClassParameter(node, 'id', 'photoTarget');
									var target = document.getElementById(targetId);
									// double the display buffer if there's only one
									var buffers = target.getElementsByTagName('div');
									if(buffers.length==1){
										var newBuffer = buffers[0].cloneNode(true);
										target.appendChild(newBuffer);
										buffers = target.getElementsByTagName('div');
									}
									// give the buffers default id if they haven't got any
									if(!buffers[0].id || buffers[1].id){
										buffers[0].id = 'thumbnailTarget' + this.index;
										buffers[1].id = 'thumbnailTarget' + this.index + 1;
										this.index += 2;
									}
									// set the initial view state
									buffers[0].style.display = 'block';
									buffers[1].style.display = 'none';
									// cache the referenced image
									allowCache = (classBehaviour.utilities.getClassParameter(node, 'cache', 'yes')=='yes') ? true : false ;
									if(allowCache){
										cacheIndex = this.cache.length;
										this.cache[cacheIndex] = new Image();
										this.cache[cacheIndex].src = node.href;
									}
								}
			/* events */
			this.showPhoto	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var ttp = classBehaviour.thumbnailToPhoto;
									// set the thumbnails to passive
									thumbnails = objNode.parentNode.parentNode.getElementsByTagName('img');
									for(var a=0; a<thumbnails.length; a++) thumbnails[a].src = thumbnails[a].src.replace('_active','_link');
									// set the thumbnails' links to passive
									thumblinks = objNode.parentNode.parentNode.getElementsByTagName('a');
									for(var a=0; a<thumblinks.length; a++) thumblinks[a].className = thumblinks[a].className.replace('active','link');
									// set the active thumbnail
									thumbnail = objNode.getElementsByTagName('img')[0];
									thumbnail.src = thumbnail.src.replace('_link','_active').replace('_hover','_active');
									// set the active thumbnails' linl
									thumblink = objNode;
									thumblink.className = thumblink.className.replace('link','active').replace('hover','active');
									// get the display buffers
									var targetId = classBehaviour.utilities.getClassParameter(objNode, 'id', 'photoTarget');
									bufferA = document.getElementById(targetId).getElementsByTagName('div')[0];
									bufferB = document.getElementById(targetId).getElementsByTagName('div')[1];
									// get the active buffer 
									bufferIn = (bufferA.style.display=='none') ? bufferA : bufferB;
									bufferOut = (bufferIn==bufferA) ? bufferB : bufferA ;
									// get the target values from the thumbnail
									targetAlt = thumbnail.alt;
									targetSrc = objNode.href;
									// if there is no fade in progress and the target os not the same as the current image
									if(!ttp.busy && targetSrc!=bufferOut.src){
										// position the incoming element 
										bufferOut.style.position = 'absolute';
										bufferOut.style.top = '0px';
										bufferOut.style.left = '0px';
										bufferOut.style.zIndex = '2000';
										bufferIn.style.position = 'relative';
										bufferIn.style.zIndex = '1000';
										// lock this function
										ttp.busy = true;
										// set the new source for the image from the clicked thumbnail
										bufferIn.getElementsByTagName('span')[0].innerHTML = targetAlt;
										bufferIn.getElementsByTagName('img')[0].src = targetSrc;
										// call the fader after the image has loaded
										bufferIn.getElementsByTagName('img')[0].onload = 	new function(){
																								// trigger the crossfade
																								classBehaviour.fader.crossFade(bufferIn.id, bufferOut.id, 0, 10, 50, 'classBehaviour.thumbnailToPhoto.unlock()');
																							};
									}
									// cancel the click
									return false;
								}
			this.unlock		=	function(){
									classBehaviour.thumbnailToPhoto.busy = false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.thumbnailToPhoto = new ThumbnailToPhoto;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.thumbnailToPhoto;
		
	// Turn an element into an HTML-editor
		// define this class behaviour
		function EditableContents(){
			/* properties */
			this.name 			= 	'editableContents';
			this.containerType	=	'FIELDSET';
			this.buttonType	=	'BUTTON';
			this.stylesheet	=	'<link href="../styles/markup.css" type="text/css" rel="StyleSheet">';
			this.htmlToolBar	=	'<li><button class="cmd_toggle srcMouseHover"><img alt="Text" src="../images/cmd_toggleHtml_link.png"/></button></li>\n'+
									'<li><button class="cmd_bigger srcMouseHover"><img alt="Resize" src="../images/cmd_bigger_link.png"/></button></li>\n'+
									'<li><button class="cmd_redo srcMouseHover"><img alt="Redo" src="../images/cmd_redo_link.png"/></button></li>\n'+
									'<li><button class="cmd_undo srcMouseHover"><img alt="Undo" src="../images/cmd_undo_link.png"/></button></li>\n'+
									'<li class="disabled"><button class="cmd_copy srcMouseHover"><img alt="Copy" src="../images/cmd_copy_link.png"/></button></li>\n'+
									'<li class="disabled"><button class="cmd_cut srcMouseHover"><img alt="Cut" src="../images/cmd_cut_link.png"/></button></li>\n'+
									'<li class="disabled"><button class="cmd_paste srcMouseHover"><img alt="Paste" src="../images/cmd_paste_link.png"/></button></li>\n'+
									'<li class="disabled"><button class="cmd_delete srcMouseHover"><img alt="Delete" src="../images/cmd_delete_link.png"/></button></li>\n'+
									'<li><button class="cmd_formatblock arg_h1 srcMouseHover"><img alt="H1" src="../images/cmd_h1_link.png"/></button></li>\n'+
									'<li><button class="cmd_formatblock arg_h2 srcMouseHover"><img alt="H2" src="../images/cmd_h2_link.png"/></button></li>\n'+
									'<li><button class="cmd_formatblock arg_h3 srcMouseHover"><img alt="H3" src="../images/cmd_h3_link.png"/></button></li>\n'+
									'<li><button class="cmd_formatblock arg_p srcMouseHover"><img alt="P" src="../images/cmd_p_link.png"/></button></li>\n'+
									'<li><button class="cmd_bold srcMouseHover"><img alt="Bold" src="../images/cmd_bold_link.png"/></button></li>\n'+
									'<li><button class="cmd_italic srcMouseHover"><img alt="Italic" src="../images/cmd_italic_link.png"/></button></li>\n'+
									'<li><button class="cmd_underline srcMouseHover"><img alt="Underline" src="../images/cmd_underline_link.png"/></button></li>\n'+
									'<li><button class="cmd_insertorderedlist srcMouseHover"><img alt="Ordered List" src="../images/cmd_insertorderedlist_link.png"/></button></li>\n'+
									'<li><button class="cmd_insertunorderedlist srcMouseHover"><img alt="Unordered List" src="../images/cmd_insertunorderedlist_link.png"/></button></li>\n'+
									'<li><button class="cmd_outdent srcMouseHover"><img alt="Outdent" src="../images/cmd_outdent_link.png"/></button></li>\n'+
									'<li><button class="cmd_indent srcMouseHover"><img alt="Indent" src="../images/cmd_indent_link.png"/></button></li>\n'+
									'<li><button class="cmd_unlink srcMouseHover"><img alt="Unlink" src="../images/cmd_unlink_link.png"/></button></li>\n'+
									'<li>\n'+
									'	<button class="toggleNextNode"><img alt="Link" src="../images/cmd_createlink_link.png"/></button>\n'+
									'	<span class="hideThisNode">\n'+
									'		<input type="text" value="http://"/><button class="cmd_createlink"><img alt="Insert" src="../images/cmd_insert_link.png"/></button>\n'+
									'	</span>\n'+
									'</li>\n'+
									'<li class="disabled">\n'+
									'	<button class="toggleNextNode"><img alt="Image" src="../images/cmd_insertimage_link.png"/></button>\n'+
									'	<span class="hideThisNode">\n'+
									'		<input type="text" value="http://"/><button class="cmd_insertimage"><img alt="Insert" src="../images/cmd_insert_link.png"/></button>\n'+
									'	</span>\n'+
									'</li>';
			this.textToolBar	=	'<li><button class="cmd_toggle srcMouseHover"><img alt="HTML" src="../images/cmd_toggleText_link.png"/></button></li>\n'+
									'<li><button class="cmd_bigger srcMouseHover"><img alt="Resize" src="../images/cmd_bigger_link.png"/></button></li>';
			this.index			=	0;
			this.interval		=	null;
			this.resizing		=	false;
			/* methods */
			this.start			=	function(node){
										// prepare the editor
										this.setCanvas(node);
										this.setControls(node);
										// sync loop between the textarea and the iframe
										clearInterval(this.interval);
										this.interval = setInterval("classBehaviour.editableContents.sync()", 256);
									}
			this.setCanvas		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// store the container type
										this.containerType = objNode.parentNode.nodeName;
										// get the textarea
										textArea = objNode;
										// hide the textarea
										textArea.style.display = 'none';
										// if there's no iframe, make one
										iframes = objNode.parentNode.getElementsByTagName('iframe');
										if(iframes.length==0){
											// add an iframe to the canvas
											newIframe = document.createElement('iframe');
											newIframe.id = this.name + this.index;
											newIframe.setAttribute("frameBorder", "0");
											newIframe.setAttribute("scrolling", "auto");
											objNode.parentNode.insertBefore(newIframe, objNode.nextSibling);
										}else{
											this.index++;
											newIframe = iframes[0];
											newIframe.id = this.name + this.index;
											newIframe.style.display = 'block';
										}
										// transform the iframe into an editor
										editor = this.getEditor(newIframe.id);
										editor.designMode = 'on';
										// set the initial content
										editor.open();
										editor.write(textArea.value + this.stylesheet);
										editor.close();
									}
			this.setControls	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										
										// get the button bars
										buttonBars = objNode.parentNode.getElementsByTagName('ul');
										// HTML BUTTON BAR
										// get the html editor button bar
										buttonBar = buttonBars[0];
										// fill it with the html toolbar prototype
										buttonBar.innerHTML = this.htmlToolBar;
										classBehaviour.parseDocument(buttonBar);
										// get the buttons
										buttons = buttonBar.getElementsByTagName(this.buttonType);
										// for each button in the button bar
										for(var a=0; a<buttons.length; a++)
											// set the event handlers for the edit buttons
											if(buttons[a].className.indexOf('cmd_')>-1) buttons[a].onmousedown = this.editCommand;
										// show the button bar
										buttonBar.style.display = 'block';
										
										// TEXT BUTTON BAR
										// get the text editor button bar
										buttonBar = buttonBars[1];
										// fill it with the html toolbar prototype
										buttonBar.innerHTML = this.textToolBar;
										classBehaviour.parseDocument(buttonBar);
										// get the buttons
										buttons = buttonBar.getElementsByTagName(this.buttonType);
										// for each button in the button bar
										for(var a=0; a<buttons.length; a++)
											// set the event handlers for the edit buttons
											if(buttons[a].className.indexOf('cmd_')>-1) buttons[a].onmousedown = this.editCommand;
										// hide the button bar
										buttonBar.style.display = 'none';
									}
			this.getEditor		=	function(id){
										return (document.getElementById(id).contentDocument) ? 
													document.getElementById(id).contentDocument : 
														document.frames[id].document ;
									}
			this.sync			=	function(){
										// for all textareas
										allTextareas = document.getElementsByTagName('textarea');
										for(var a=0; a<allTextareas.length; a++){
											// if it's part of this class
											if(allTextareas[a].className.indexOf('editableContents')>-1){
												// update the textarea from the iframe editor
												editorId = allTextareas[a].parentNode.getElementsByTagName('iframe')[0].id;
												editor = classBehaviour.editableContents.getEditor(editorId);
												// if the iframe is replacing the textarea
												if(allTextareas[a].style.display=='none'){
													allTextareas[a].value = editor.documentElement.firstChild.nextSibling.innerHTML.split('<LINK')[0].split('<link')[0];
												}else{
													editor.documentElement.firstChild.nextSibling.innerHTML = allTextareas[a].value + classBehaviour.editableContents.stylesheet;
												}
											}
										}
									}
			this.resize		=	function(container){
										if(!this.resizing){
											// get the editor
											iFrame = container.getElementsByTagName('iframe')[0];
											textArea = container.getElementsByTagName('textarea')[0];
											// what is the mode of the editor
											editor = (textArea.style.display=='none') ? iFrame : textArea;
											// if the editor wasn't marked big
											if(editor.className.indexOf('biggerEditor')<0){
												// mark is as big
												editor.className = 'biggerEditor ' + editor.className;
												// and lock this function
												classBehaviour.editableContents.resizing = true;
												// make the editor twice as big
													// editor.style.height = (editor.offsetHeight * 3) + 'px';
												classBehaviour.fader.grow(editor.id, null, editor.offsetHeight*3, 20, 10, 'classBehaviour.editableContents.resizing=false;');
											//else
											}else{
												// remove it mark
												editor.className = editor.className.replace('biggerEditor', '');
												// and lock this function
												classBehaviour.editableContents.resizing = true;
												// make the editor half as big
													//editor.style.height = Math.round(editor.offsetHeight / 3) + 'px';
												classBehaviour.fader.shrink(editor.id, null, editor.offsetHeight/3, 20, 10, 'classBehaviour.editableContents.resizing=false;');
											}
										}
									}
			/* events */
			this.toggle		=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var ecs = classBehaviour.editableContents;
										// get the editor's container
										container = objNode.parentNode.parentNode.parentNode;
										// get the elements from this editor
										iframes = container.getElementsByTagName('iframe');
										buttonBars = container.getElementsByTagName('ul');
										textareas = container.getElementsByTagName('textarea');
										// if the textearea is invisible
										if(textareas[0].style.display=='none'){
											// hide the button bar
											buttonBars[0].style.display = 'none';
											buttonBars[1].style.display = 'block';
											// hide the iframe
											iframes[0].style.display = 'none';
											// show the textarea
											textareas[0].style.display = 'block';
										}else{
											// show the button bar
											buttonBars[0].style.display = 'block';
											buttonBars[1].style.display = 'none';
											// show the iframe
											iframes[0].style.display = 'block';
											// hide the textarea
											textareas[0].style.display = 'none';
										}
									}
			this.editCommand	=	function(that){
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										var ecs = classBehaviour.editableContents;
										// get the editor canvas
										container = objNode;
										while(container.nodeName.indexOf(classBehaviour.editableContents.containerType)<0) container = container.parentNode;
										editor = ecs.getEditor(container.getElementsByTagName('iframe')[0].id) ;
										// get the selected section
										selection = 	(editor.selection) ? editor.selection.createRange().text : 
															(editor.getSelection) ? editor.getSelection() : 
																(editor.createRange) ? editor.createRange() : 
																	null ;
										// gather the command parameters
										commandName = classBehaviour.utilities.getClassParameter(objNode, 'cmd', '');
										commandArgument = classBehaviour.utilities.getClassParameter(objNode, 'arg', '');
										// exceptions
										switch(commandName){
											case 'insertimage' : commandArgument = classBehaviour.utilities.previousNode(objNode).value; break;
											case 'createlink' : commandArgument = classBehaviour.utilities.previousNode(objNode).value; break;
											default : break;
										}
										if(commandName=='toggle') classBehaviour.editableContents.toggle(objNode);
										if(commandName=='bigger') classBehaviour.editableContents.resize(container);
										// execute the command
										if(selection) editor.execCommand(commandName, false, commandArgument);
									}
		}
		// add this function to the classbehaviour object
		classBehaviour.editableContents = new EditableContents;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.editableContents;
		
	// Clone the previous node to after this one
		// define this class behaviour
		function ClonePreviousNode(){
			/* properties */
			this.name 		= 	'clonePreviousNode';
			/* methods */
			this.start		=	function(node){
									// set the event for this button
									node.onclick = this.clone;
								}
			/* events */
			this.clone	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var cpn = classBehaviour.clonePreviousNode;
									// get the previous node or the targetted node
									sourceId = classBehaviour.utilities.getClassParameter(objNode, 'id', null);
									sourceNode = (sourceId) ? document.getElementById(sourceId) : classBehaviour.utilities.previousNode(objNode);
									// clone the contents
									newNode = sourceNode.cloneNode(true);
									// add the cached contents before this button
									objNode.parentNode.insertBefore(newNode, objNode);
									// (maybe) execute the clasbehaviours again
									classBehaviour.parseDocument(classBehaviour.utilities.previousNode(objNode));
									// cancel the click
									return false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.clonePreviousNode = new ClonePreviousNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.clonePreviousNode;	
		
	// Change the order of page elements
		// define this class behaviour
		function MoveParentNode(){
			/* properties */
			this.name 		= 	'moveParentNode';
			/* methods */
			this.start		=	function(node){
									// set the event for this button
									node.onclick = this.move;
								}
			/* events */
			this.move	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var mpn = classBehaviour.clonePreviousNode;
									// up or down?
									goingDown = (classBehaviour.utilities.getClassParameter(objNode,'move','down')=='down');
									// how deep is the button in the moving node
									nodeDepth = parseInt(classBehaviour.utilities.getClassParameter(objNode,'parent','1'));
									for(var a=0; a<nodeDepth; a++) objNode = objNode.parentNode;
									// the node before which this one is to be inserted
									targetNode = 	(goingDown) ? 
														classBehaviour.utilities.nextNode(objNode).nextSibling : 
															classBehaviour.utilities.previousNode(objNode);
									// what is the container node
									containerNode = objNode.parentNode;
									// remove the parent node
									cachedNode = containerNode.removeChild(objNode);
									// insert the node in it's new location
									containerNode.insertBefore(cachedNode, targetNode);
									// re-init the classbehaviours within
									classBehaviour.parseDocument(classBehaviour.utilities.previousNode(targetNode));
									// cancel the click
									return false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.moveParentNode = new MoveParentNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.moveParentNode;
		
	// change the focus to a table row
		// define this class behaviour
		function FocusRow(){
			/* properties */
			this.name 		= 	'focusRow';
			/* methods */
			this.start		=	function(node){
									node.onclick = this.highlight;
									// add events to all cells
									for(var a=0; a<node.childNodes.length; a++) if(node.childNodes[a].nodeName!='#text') node.childNodes[a].onmousedown = this.highlight;
									// add events to all form elements
									inputs = node.getElementsByTagName('*');
									for(var a=0; a<inputs.length; a++) if(inputs[a].nodeName!='#text') inputs[a].onfocus = this.highlight;
									// add events to all iframes
									iframes = node.getElementsByTagName('iframe');
									for(var a=0; a<iframes.length; a++) iframes[a].onmousedown = this.highlight;
								}
			/* events */
			this.highlight	=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var frw = classBehaviour.focusRow;
									// find the row
									parentRow = objNode;
									while(parentRow.nodeName!='TR') parentRow = parentRow.parentNode;
									// find the previous node
									peerRows = parentRow.parentNode.getElementsByTagName('TR');
									previousRow = null;
									for(var a=0; a<peerRows.length; a++){
										// if the row is marked as active, take it as the previous row
										if(peerRows[a].className.indexOf('active')>-1) previousRow = peerRows[a];
									}
									// deactivate the previous row
									if(previousRow) if(parentRow!=previousRow) previousRow.className = previousRow.className.replace('active','link');
									// add the active class
									parentRow.className = parentRow.className.replace('link','active');
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.focusRow = new FocusRow;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.focusRow;
		
	// calculates a total of several input fields
		// define this class behaviour
		function TotalOfNumbers(){
			/* properties */
			this.name 		= 	'totalOfNumbers';
			/* methods */
			this.start		=	function(node){
									// is this an input field
									if(node.nodeName=="INPUT"){
										// give it the onchange handler
										node.onkeyup  = this.calculate;
										node.onblur  = this.calculate;
									}
								}
			/* events */
			this.calculate = 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// what is the family group
									totalFamily = classBehaviour.utilities.getClassParameter(objNode, 'family', 'default');
									// for all inputs
									total = 0;
									allInputs = document.getElementsByTagName('INPUT');
									for(var a=0; a<allInputs.length; a++){
										// if this is the same family // add it to a total
										added = parseFloat(allInputs[a].value);
										if(classBehaviour.utilities.getClassParameter(allInputs[a], 'family', null)==totalFamily && !isNaN(added)) total += added;
									}
									// what is the target node
									totalTarget = classBehaviour.utilities.getClassParameter(objNode, 'target', null);
									// add the total to the target node
									if(totalTarget) document.getElementById(totalTarget).innerHTML = total;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.totalOfNumbers = new TotalOfNumbers;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.totalOfNumbers;
		
	// turns an unordered list into a tree menu
		// define this class behaviour
		function TreeMenu(){
			/* properties */
			this.name 		= 	'treeMenu';
			this.index		=	0;
			/* methods */
			this.start		=	function(node){
									// number this list
									this.index += 1;
									c = this.index;
									// for all list items
									var activeLink;
									var allListParents = node.getElementsByTagName('ul');
									for(var b=-1; b<allListParents.length; b++){
										var allListItems = (b<0) ? node.getElementsByTagName('li') : allListParents[b].getElementsByTagName('li');
										for(var a=0; a<allListItems.length; a++){
											// LIST ITEM
											allListItems[a].className += (allListItems[a].className.indexOf('link')<0 || allListItems[a].className.indexOf('active')<0) ? ' link' : '' ;
											// TOGGLE
											// if there is no toggle switch
											itemTogglers = allListItems[a].getElementsByTagName('span');
											if(itemTogglers.length==0){
												// make a toggle switch
												newToggle = document.createElement('span');
												allListItems[a].insertBefore(newToggle, allListItems[a].firstChild);
												// refresh the list
												itemTogglers = allListItems[a].getElementsByTagName('span');
											}
											// if the node has child-nodes
											childNodes = allListItems[a].getElementsByTagName('ul');
											if(childNodes.length>0){
												// give the childnodes an id
												childNodes[0].id = this.name + c + b + a;
												// make it a toggle switch
												itemTogglers[0].className = "link id_" + childNodes[0].id;
												// should the previous branch close
												if(classBehaviour.utilities.getClassParameter(node, 'closePrevious', 'yes')=='yes')
													itemTogglers[0].className += " family_group" + c + b;
												// add the toggle event handler
												itemTogglers[0].onclick = classBehaviour.toggleNextNode.toggle;
												// hide the child nodes
												childNodes[0].className = 'hideThisNode';
												// prepare the toggler
												classBehaviour.toggleNextNode.start(itemTogglers[0]);
											// else
											}else{
												// make it a normal switch
												itemTogglers[0].className = "passive";
											}
											// LINK
											// get the link in this item
											itemLinks = allListItems[a].getElementsByTagName('a');
											// store the active link if it's the same as the document location
											if(itemLinks.length>0){
												isActive = classBehaviour.matchActiveUrl.process(itemLinks[0]);
												// recurse simulated clicks up all of its parents
												if(isActive) this.recurse(itemLinks[0].parentNode);
											}
										}
									}
								}
			this.recurse	=	function(container){
									var tmn = classBehaviour.treeMenu;
									// get the toggle button
									var itemTogglers = container.getElementsByTagName('span');
									// toggle it
									if(itemTogglers.length>0) if(itemTogglers[0].className.indexOf('link')>-1) classBehaviour.toggleNextNode.toggle(itemTogglers[0]);
									// get parent of this container
									var parentContainer = container.parentNode.parentNode;
									// if it's another container
									if(parentContainer.nodeName == "LI")
										// recurse
										tmn.recurse(parentContainer);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.treeMenu = new TreeMenu;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.treeMenu;
		
	// Matches the height of a group of elements
		// define this class behaviour
		function MatchHeight(){
			/* properties */
			this.name 		= 	'matchHeight';
			this.groups		=	new Array(
									// new Array('groupName', node, node, node);
								);
			/* methods */
			this.start		=	function(node){
									// what group does this node belong to
									nodeGroup = classBehaviour.utilities.getClassParameter(node, 'group', '0');
									// find this group in the list
									groupIndex = -1;
									for(var a=0; a<this.groups.length; a++) if(this.groups[a][0]==nodeGroup) groupIndex=a;
									// if it doesn't exist make it
									if(groupIndex<0){
										this.groups[this.groups.length] = new Array(nodeGroup, node);
									// else
									}else{
										// store the node in it's group
										this.groups[groupIndex][this.groups[groupIndex].length] = node;
									}
									// equalize the heights
									this.resize();
								}
			this.resize		=	function(){
									// for all groups
									for(var a=0; a<this.groups.length; a++){
										// remember the heighest node in this group
										nodeHeight = 0;
										for(var b=1; b<this.groups[a].length; b++) 
											if(nodeHeight<this.groups[a][b].offsetHeight) 
												nodeHeight=this.groups[a][b].offsetHeight;
										// set all nodes to that height
										for(var b=1; b<this.groups[a].length; b++) 
											if(nodeHeight!=this.groups[a][b].offsetHeight)
												if(this.groups[a][b].style.minHeight){
													heightOffset = parseInt(classBehaviour.utilities.getClassParameter(this.groups[a][b], 'offset', '0'));
													this.groups[a][b].style.minHeight = (nodeHeight + heightOffset) + 'px'
												}else{
													heightOffset = parseInt(classBehaviour.utilities.getClassParameter(this.groups[a][b], 'offset', '0'));
													this.groups[a][b].style.height = (nodeHeight + heightOffset) + 'px'
												};
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.matchHeight = new MatchHeight;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.matchHeight;
		
	// Construct an empty stylesheet based on the hierarchy of tags
//		document.writeln('<button class="makeStylesheet" style="position : absolute; left : 0px; top : 0px;">Click to create stylesheet.</button>');
		// define this class behaviour
		function MakeStylesheet(){
			/* properties */
			this.name 				=	'makeStylesheet';
			this.styleSheet			= 	"/* " + document.location.href.split('/')[document.location.href.split('/').length-1] + " */\n";
			this.referenceCss		=	"";
			this.rootObject			= 	document.body;
			/* methods */
			this.start				=	function(node){
											// make a reference stylesheet from the current stylesheets
											this.makeReferenceCss();
											// set the click event of the button
											node.onclick = this.showNodeClasses;
											/*
											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++)
												for(var b=0; b<document.styleSheets[a].cssRules.length; b++)
													this.referenceCss += document.styleSheets[a].cssRules[b].selectorText + ' {}\n\t';
										}
			this.isFormElement		=	function(node){
											return (('INPUT,SELECT,TEXTAREA,BUTTON').indexOf(node.nodeName)>-1);
										}
			this.isClassBehaviour	=	function(newEntry){
											foundHandler = false;
											// for all behaviours, if the behaviour's name exists in the class name, apply it's events
											for(var b=0; b<classBehaviour.handlers.length; b++)
												foundHandler = (newEntry.indexOf(classBehaviour.handlers[b].name)>-1) ? true : foundHandler;
											// report back
											return foundHandler;
										}
			this.isInStylesheet		=	function(newEntry){
											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) ? true : foundStyle ;
											// report back
											return foundStyle;
										}
			this.getNodeClasses		=	function(objNode, intRecursion, prefix){
											var strTabs = '';
											var idPrefix, classPrefix, tagPrefix, addPrefix;
											var newEntry = '';
											// for every recursion add one tab
											for(var intB=0; intB<intRecursion; intB++) strTabs += '\t';
											// get the child nodes
											var objChildNodes = objNode.childNodes;
											// for every childnode
											for(var intA=0; intA<objChildNodes.length; intA++){
												// reset prefixes
												idPrefix = '';
												classPrefix = '';
												tagPrefix = '';
												addPrefix = '';
												// if it has an id, but is not a form element
												if(typeof(objChildNodes[intA].id)!='undefined' && !this.isFormElement(objChildNodes[intA])){
													if(objChildNodes[intA].id!=''){
														// add class to stylesheet prototype
														newEntry = strTabs + '#' + objChildNodes[intA].id + ' {}\n';
															// strStyleSheet += strTabs + prefix + '#' + objChildNodes[intA].id + ' {}\n'
														// add this style only if there's not double
														if(!this.isInStylesheet(newEntry)) this.styleSheet += newEntry;
														// update the prefix
														idPrefix = '#' + objChildNodes[intA].id;
													}
												}
												// if it has a className
												if(typeof(objChildNodes[intA].className)!='undefined'){
													if(objChildNodes[intA].className!=''){
														// split the classnames
														allClasses = objChildNodes[intA].className.split(' ');
														// for all classes
														for(var b=allClasses.length-1; b>=0; b--){
															// add class to stylesheet prototype
															newEntry = strTabs + prefix + objChildNodes[intA].nodeName.toLowerCase() + '.' + allClasses[b] + ' {}\n';
															// add this style only if there's not double
															if(!this.isInStylesheet(newEntry) && !this.isClassBehaviour(newEntry)){
																// update the prefix
																this.styleSheet += newEntry;
																// if the last entry was a link
																if(objChildNodes[intA].nodeName=='A'){
																	// repeat it four times with the mouseover states
																	this.styleSheet += '\t' + strTabs + prefix + objChildNodes[intA].nodeName.toLowerCase() + '.' + allClasses[b] + ':link,\n';
																	this.styleSheet += '\t' + strTabs + prefix + objChildNodes[intA].nodeName.toLowerCase() + '.' + allClasses[b] + ':visited {}\n';
																	this.styleSheet += '\t' + strTabs + prefix + objChildNodes[intA].nodeName.toLowerCase() + '.' + allClasses[b] + ':hover,\n';
																	this.styleSheet += '\t' + strTabs + prefix + objChildNodes[intA].nodeName.toLowerCase() + '.' + allClasses[b] + ':active {}\n';
																	// and jump further in
																	intRecursion += 1;
																}
															}
															// update the prefix
															classPrefix = objChildNodes[intA].nodeName.toLowerCase() + '.' + allClasses[b];
														}
													}
												}
												// if it has neither
												if(
													objChildNodes[intA].className=='' && 
													(objChildNodes[intA].id=='' || this.isFormElement(objChildNodes[intA])) && 
													objChildNodes[intA].nodeName.indexOf('text')<0 && 
													objChildNodes[intA].nodeName.indexOf('comment')<0
												){
													// add class to stylesheet prototype
													newEntry = strTabs + prefix + objChildNodes[intA].nodeName.toLowerCase() + ' {}\n';
													// add this style only if there's not double
													if(!this.isInStylesheet(newEntry)){
														this.styleSheet += newEntry;
														// if the last entry was a link
														if(newEntry.indexOf(' a {}')>-1){
															// repeat it four times with the mouseover states
															this.styleSheet += '\t' + newEntry.replace('a {}','a:link,');
															this.styleSheet += '\t' + newEntry.replace('a {}','a:visited {}');
															this.styleSheet += '\t' + newEntry.replace('a {}','a:hover,');
															this.styleSheet += '\t' + newEntry.replace('a {}','a:active {}');
															// and jump further in
															intRecursion += 1;
														}
													}
													// update the prefix
													tagPrefix = objChildNodes[intA].nodeName.toLowerCase();
												}
												// if it has childNodes
												if(objChildNodes[intA].childNodes.length>0){
													// update the prefix
													if(idPrefix){
														addPrefix = idPrefix + ' ';
													}else if(classPrefix){
														addPrefix = prefix + classPrefix + ' ';
													}else if(tagPrefix){
														addPrefix = prefix + tagPrefix + ' ';
													}
													// recurse
													this.getNodeClasses(objChildNodes[intA], intRecursion+1, addPrefix);
												}
											}
										}
			this.showNodeClasses	=	function(){
											var mss = classBehaviour.makeStylesheet;
											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 = '12pt';
											mss.getNodeClasses(mss.rootObject, 0 , '');
											document.body.innerHTML = '<pre>' + mss.styleSheet + '</pre>';
										}
		}
		// add this function to the classbehaviour object
		classBehaviour.makeStylesheet = new MakeStylesheet;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.makeStylesheet;
		
	// move a link's click event to the parent node
		// define this class behaviour
		function ClickOnParent(){
			/* properties */
			this.name 		= 	'clickOnParent';
			/* methods */
			this.start		=	function(node){
									// what node is the click supposed to go on?
									parentCount = parseInt(classBehaviour.utilities.getClassParameter(node, "parent", "1"));
									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;
								}
			/* 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
		classBehaviour.clickOnParent = new ClickOnParent;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.clickOnParent;
		
	// emulates a scrollbar
		// define this class behaviour
		function VirtualScrollbar(){
			/* properties */
			this.name 		= 	'virtualScrollbar';
			this.interval	=	null;
			/* methods */
			this.start		=	function(node){
									// set the event handlers for the indicator bar
									node.onmousedown = this.pick;
									node.onmouseup = this.drop;
									node.onmousemove = this.drag;
									node.onmouseout = this.drop;
									document.onmousemove = this.nodrag;
									// set the initial position
									pageId = classBehaviour.utilities.getClassParameter(node, 'id', 'scrollCanvas');
									this.scrollTo(pageId, 0, node);
								}
			this.scrollTo	=	function(id, position, control){
									var vsb = classBehaviour.virtualScrollbar;
									// normalize the position
									if(position>0) position = 0;
									// what is the scrollable page
									page = document.getElementById(id).getElementsByTagName('div')[0];
									// how high is the page
									pageHeight = page.offsetHeight;
									// how high is the container of the page
									containerHeight = page.parentNode.offsetHeight;
									// don't allow negative scrolling
									if(pageHeight<containerHeight){
										pageHeight = containerHeight;
									}
									// if there's still a distace left to scroll on the bottom shift the page up
									if(navigator.userAgent.indexOf('Safari')>-1){
										page.style.position = 'absolute';
										page.style.top = (position<containerHeight-pageHeight) ? (containerHeight-pageHeight) + 'px' : position + 'px' ;
									}else{
										page.style.marginTop = (position<containerHeight-pageHeight) ? (containerHeight-pageHeight) + 'px' : position + 'px' ;
									}
									// set the position of the indicator
									control.style.backgroundPosition = '0px ' + Math.round(-1.2 * containerHeight * position / pageHeight)  + 'px'
								}
			this.scrollBy	=	function(id, distance, control){
									// what is the scrollable page
									page = document.getElementById(id);
									// how far has the page scrolled up
									if(navigator.userAgent.indexOf('Safari')>-1){
										scrolledHeight = (page.style.top) ? parseInt(page.style.top) : 0 ;
									}else{
										scrolledHeight = (page.style.marginTop) ? parseInt(page.style.marginTop) : 0 ;
									}
									// calculate the new position
									position = scrolledHeight + distance;
									// set the position
									this.scrollTo(id, position);
								}
			/* events */
			this.pick		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var vsb = classBehaviour.virtualScrollbar;
									// mark the dragged item as being active
									objNode.className = objNode.className.replace('passive', 'active');
									// initial value
									vsb.drag(objNode);
									// cancel the click
									return false;
								}
			this.drag		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var vsb = classBehaviour.virtualScrollbar;
									// if the scrollbar is marked as draggable
									if(objNode.className.indexOf('active')>-1){
										// get the click position
										mouseX = (typeof(event)!='undefined') ? event.x : that.layerX ;
										mouseY = (typeof(event)!='undefined') ? event.y : that.layerY ;
										// get the page dimensions
										id = classBehaviour.utilities.getClassParameter(objNode, 'id', 'scrollCanvas');
										page = document.getElementById(id).getElementsByTagName('div')[0];
										// how high is the page
										pageHeight = page.offsetHeight;
										// how high is the container of the page
										containerHeight = page.parentNode.offsetHeight;
										// corelate the mouse-position to the scroll-position
										position = Math.round(-1 * mouseY * (pageHeight-containerHeight) / containerHeight);
										position = position * 1.2 + containerHeight * 0.2;
										// pass the position on to the page
										vsb.scrollTo(id, position, objNode);
									}
									// cancel the click
									return false;
								}
			this.nodrag	=	function(){
									return false;
								}
			this.drop		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var vsb = classBehaviour.virtualScrollbar;
									// mark the dragged item as being passive
									objNode.className = objNode.className.replace('active', 'passive');
									// cancel the click
									return false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.virtualScrollbar = new VirtualScrollbar;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.virtualScrollbar;
		
/* /TODO */
	// STARTUP-SEQUENCE
	// start the parsing of classes
	classBehaviour.parseDocument();
