/*
name			: Class Behaviour
update			: 20051129
author			: Xander Bindt, Frank van Rooijen, Maurice van Creij
dependencies		: lib_classbehaviour.js
info				: http://www.woollymittens.nl/content/details.asp?id=20040805133501

history
20051129		: a radio button checker was added to the form validator
20051121		: dropDownMenu now closes peer nodes before opening a new branch
20051118		: foldoutMenu was further stabilized, addressing problems with the delayed fold-back
20051031		: drag and drop's horizontal position can be correlated to a form value
20050819	: all code was changed to object oriented, for modularity
20050810	: fixed the onclick events on node toggling images in the dropDownMenu
20050705	: drag and drop works better with miltiple layers
20050511		: no prior updates report

notes
1. Replace "link" in class
   class="classMouseHover"
2. Replace "link" in src
   class="srcMouseHover"
3. Add display:none; on parse
   class="hideThisNode"
   class="showThisNode"
4. Add or remove display:none; onclick
   class="toggleNextNode [closePrevious_no id_myId useParent_1]"
   (Everything between [brackets] is optional. Leave out the [brackets] in the classname)
   closePrevious = close the previous node, before opening a new one (default: no)  
   id = Override the next node with an ID (default: none)   
   useParent = Use the parent node as a starting point for finding the target node
5. Add display:none; to parent node
   class="closeParentNode [parent_0]"
   parent = amount of recursions to use as a parent
6. Replace image with transparent version, invoke directX background loader
   class="pngAlpha"
7. Handle ondrag events
   class="dragAndDrop [limitTop_0 limitRight_100 limitBottom_100 limitLeft_0 gridX_16 gridY_16]"
   gridX = grid rounding in the X axis
   gridY = grid rounding in the Y axis
   limitTop = top limit 
   limitRight = right limit
   limitBottom = bottom limit 
   limitLeft = left limit
 8. Open links in a popup
   class="openAsPopUp [width_400 height_300 toolbar_yes scrollbars_yes resizable_yes status_yes location_yes menubar_yes name_myname]"
   width = width (default: automatic)
   height = height (default: automatic)
   toolbar = toolbars (default: no)
   scrollbars = Scrollbars (default: no)
   resizable = Resizable (default: no)
   status = Status bar (default: no)
   location = Location bar (default: no)
   menubar = Menus (default: no)
   name = Window name (default: popup)
9. Shows the contents of a container as raw code
   class="showAsCode"
10. Chooses a random increment of an image source
   class="setRandomSrc [min_0 max_1]"
   min = minimum (default: 0)
   max = maximum (default: 1)
11. Class a link matching the document's url
   class="matchActiveUrl [toParent_0 fromParent_0]"
   toParent = Apply class to parent (default: 0)
   fromParent = Take the HREF from parent (default: 0)
12 Add a className to a tag using the query parameter "class"
   class="addQueryToClassName"
13 Add a suffix to an image source using the query parameter "src"
   class="addQueryToSrc"
14 Validate the value of a for element to a predefined regular expression
   form class="validateAllInput [summaryId_summary0]"
   input class="validateInput [type_email allowEmpty_no warningId_error0 noWarning]"
   (Everything between [brackets] is optional. Leave out the [brackets] in the classname)
   type = validator type (email,phone,dutchzipcode,date,number,money,bankaccount,alphanumeric,notempty,isradiochecked)
   allowEmpty = Allow the field to be empty (default: no)
   warningId = use an Id for the error message instead of the next node
   noWarning = Don't hightlight this label as a validation warning
   ifCheckedId = This validation is only active when the refered id is checked
   explanation = There's explanation text in the field until it's clicked for the first time
15 Triggers all validateInput class behaviours within a node after the onsubmit event.
   class="validateAllInput"
16 Resizes the window to avoid a scrollbar
   class="resizeToFit"
17 Alternates the classes of a table's rows and columns
   class="zebraTable"
18 Makes the headers of a table click/sortable
   class="sortColumn"
19 Enforces minimal height of a container
   class="minHeight [height_100pct heightOffset_100px]"
   height = height + unit (default: no minimum. units: pct, px)
   heightOffset = offset + unit (default: 0. units pct, px)
20 Enforces maximal width of a container
   class="maxWidth [width_768px widthOffset_100px]"
   width = width + unit (default: no minimum. units: pct, px)
   widthOffset = offset + unit (default: 0. units pct, px)
21 Blinks
   class="blink"
22 Open a print dialog
   class="openAsPrintable"
23 Apply the relevant event handlers for a dropdown menu
   class="dropDownMenu"
24 Apply the relevant event handlers for a foldout menu
   class="foldOutMenu"
25 Scroll the list items of a container
   class="listScroller [width_256 height_96 left_1 top_0 delay_0]"
   width = distance to travel for one element (default: 256)
   height = distance to travel for one element (default: 75)
   left = horizontal speed (default: 2 pixel per second)
   top = vertical speed (default: 0 pixel per second)
   delay = delay after each element (default: 64 miliseconds)
26 Remove this tag if it's found to be empty
   class="removeIfEmpty"
27 Fixes the position of an element, relative to the screen. This compensates for MSIE's lack of CSS2 compliance.
   class="fixedPosition"
28 Enlarges a container to the largest size, without scrolling
   class="resizeToFit"
29 Toggle hidden siblings when clicking this node
   class="toggleHiddenSiblings"
30 Open links in the opener of this window
   class="openInOpener[closeParent_true]"
   closeParent = Close the popup after opening this link the in the opener
31 Open links in a new window
   class="openAsWindow"
32 Correlate a dragable object to an input value
   div class="sliderInput [valueToId_myInputField minValue_0 maxValue_100]"
   input class="[valueFromId_slider0]"
   valueToId = The input field converted position values will be transported to
   valueFromId = Placed as a classname in the input field to reference back to the slider
   minValue = minimum x conversion value
   maxValue = maximum x conversion value
33 Tabbed content
   ul class="tabbedContent"
   div class="contentTab"
34 CloseThisWindow
   class="CloseThisWindow"
35 Manage all event handler for an imagemap
   class="imageMap"
36 Allows a file upload element to recieve fake markup
   class="fileBrowser"
37 Sizes an element according to a value
   class="chartValue [value_50]"
   value = the value the chart is supposed to indicate (default 100%)
38 Copies selected text to a target container
   class="textSelection [id_selectedText]"
   id = Target element for the text (default: selectedText)
39 Shows elements based on the state of a related radio button or checkbox
   class="displayIfChecked id_displayThisIdIfChecked"
   id = Target element to hide of show
40 Disable form elements during a submit, to avoid multiple submits on slow servers
   class="disableAfterSubmit"
*/

	// main class-behaviour object
	function ClassBehaviour(){
		/* properties */
			this.handlers			=	new Array();
		/* methods */
			// 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 ;
										}
			// parse the document for classnames
			this.parseDocument		=	function(){
											// get all document nodes
											var allNodes = (document.all) ? document.all : document.getElementsByTagName("*");
											// for all tags
											for(var a=0; a<allNodes.length; a++){
												// get the classname
												nodeClass = allNodes[a].className;
												// if there was a classname
												if(nodeClass!=''){
													// 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]);
													}
												}
											}
										}
			// 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;
										}
	}
	// create the main class-behaviour object
	var classBehaviour = new ClassBehaviour;

	// 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') ;
								}
			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') ;
								}
			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;
		
	// 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 ;
										// 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 ;
									// 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 ;
									// replace link by hover
									objNode.src = objNode.src.replace('_link','_hover');
								}
			this.remHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// 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;
		
	// add display='none'; on parse
		// define this class behaviour
		function HideThisNode(){
			/* properties */
			this.name 		= 	'hideThisNode';
			/* methods */
			this.start		=	function(node){
									node.style.display = 'none';
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.hideThisNode = new HideThisNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.hideThisNode;
		
	// affirms the visibility status in regard to toggles
		// define this class behaviour
		function ShowThisNode(){
			/* properties */
			this.name 		= 	'showThisNode';
			/* methods */
			this.start		=	function(node){
									// apply the visible state
									node.style.display = classBehaviour.getVisibleState(node);
									// fill the "previous node" parameters of a related object
									classBehaviour.toggleNextNode.lastNode = node;
// TODO: untested test for childnodes
									// if this isn't the first node
									if(node.parentNode.childNodes[0] != node){
										// pick the previousnode
										objPreviousNode = (node.previousSibling.nodeName.indexOf("text")<0) ? node.previousSibling : node.previousSibling.previousSibling ;
										// store it as the 'previous' toggle
										if(objPreviousNode!=null) classBehaviour.toggleNextNode.lastNext = objPreviousNode;
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.showThisNode = new ShowThisNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.showThisNode;
		
	// add display='none'; to parent node
		// define this class behaviour
		function CloseParentNode(){
			/* properties */
			this.name 		= 	'closeParentNode';
			/* methods */
			this.start		=	function(node){
									/*event*/;
									node.onclick = this.process;
								}
			/* events */
			this.process 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tnn = classBehaviour.toggleNextNode;
									// get the desired parent recursion
									targetParent = parseInt(classBehaviour.getClassParameter(objNode, 'parent', '0'));
									objTarget = objNode.parentNode;
									for(var a=0; a<targetParent; a++) objTarget = objTarget.parentNode;
									// hide the parent node
									objTarget.style.display = 'none';
									// restore previous node's click state
									if(tnn.lastNext!=null && tnn.lastNext!=objNode) tnn.lastNext.className = tnn.lastNext.className.replace('active','link');
									// cancel onclick event
									return false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.closeParentNode = new CloseParentNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.closeParentNode;
		
	// 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 + "')";
											// 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;

	// 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;
									// exctract the limits from the class parameters
									this.grid.x	=	parseInt(classBehaviour.getClassParameter(node, 'gridX', null));
									this.grid.y	=	parseInt(classBehaviour.getClassParameter(node, 'gridY', null));
									this.minPos.x	=	parseInt(classBehaviour.getClassParameter(node, 'limitLeft', null));
									this.minPos.y	=	parseInt(classBehaviour.getClassParameter(node, 'limitTop', null));
									this.maxPos.x	=	parseInt(classBehaviour.getClassParameter(node, 'limitRight', null));
									this.maxPos.y	=	parseInt(classBehaviour.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.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.getClassParameter(sliderTarget, 'valueFromId', null);
										sliderButton = document.getElementById(sliderButtonId);
										// get the limit values from the slider
										curValue	=	parseFloat(sliderTarget.value);
										minValue	=	parseFloat(classBehaviour.getClassParameter(sliderButton, 'minValue', null));
										maxValue	=	parseFloat(classBehaviour.getClassParameter(sliderButton, 'maxValue', null));
										minPos		=	parseInt(classBehaviour.getClassParameter(sliderButton, 'limitLeft', null));
										maxPos		=	parseInt(classBehaviour.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.getClassParameter(sliderButton, 'valueToId', null);
										sliderTarget	=	document.getElementById(sliderTargetId);
										// get the limit values from the slider
										curValue	=	parseFloat(sliderTarget.value);
										minValue	=	parseFloat(classBehaviour.getClassParameter(sliderButton, 'minValue', null));
										maxValue	=	parseFloat(classBehaviour.getClassParameter(sliderButton, 'maxValue', null));
										minPos		=	parseInt(classBehaviour.getClassParameter(sliderButton, 'limitLeft', null));
										maxPos		=	parseInt(classBehaviour.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.getClassParameter(sliderButton, 'valueToId', null);
											sliderTarget	=	document.getElementById(sliderTargetId);
											// slider limits
											minPos			=	parseInt(classBehaviour.getClassParameter(sliderButton, 'limitLeft', null));
											maxPos			=	parseInt(classBehaviour.getClassParameter(sliderButton, 'limitRight', null));
											minValue		=	parseFloat(classBehaviour.getClassParameter(sliderButton, 'minValue', null));
											maxValue		=	parseFloat(classBehaviour.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.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.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 ;
									var objIframe = window.parent.document.getElementById('resizeToFit');
									var intScrollX, intScrollY, intWinWidth, intWinHeight, intMaxWidth, intMaxHeight;
									// max dimensions
									intMaxWidth = (objIframe!=null) ? 9999 : screen.availWidth;
									intMaxHeight = (objIframe!=null) ? 9999 : screen.availHeight;
									// 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 = (document.all) ?  document.body.scrollLeft : window.pageXOffset ;
										intScrollY = (document.all) ? document.body.scrollTop : window.pageYOffset ;
										// measure window size
										intWinWidth = (document.all) ? document.body.offsetWidth : window.innerWidth ;
										intWinHeight = (document.all) ? document.body.offsetHeight : window.innerHeight ;
										// if the scroll position is not 0
										if(intScrollX>0){
											// make the window larger
											window.resizeBy(32,0);
											// make the iframe larger
											if(objIframe!=null && !document.all) objIframe.style.width = (objIframe.style.width=='') ? '64px' : (parseInt(objIframe.style.width) + 32) + 'px';
										}
										if(intScrollY>0){
											// make the window larger
											window.resizeBy(0,32);
											// make the iframe larger
											if(objIframe!=null && !document.all) objIframe.style.height = (objIframe.style.height=='') ? '64px' : (parseInt(objIframe.style.height) + 32) + 'px';
										}
										// count the steps
										intWhileCount += 1;
									}while((intScrollX>0 || intScrollY>0) && intWinWidth<intMaxWidth && intWinHeight<intMaxHeight && intWhileCount<32);
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.resizeToFit = new ResizeToFit;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.resizeToFit;
		
	// 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 ;
// TODO: exchange stylesheet with print stylesheet
									// open the print dialog
									window.print();
								}
		}
		// 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) 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) 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.getClassParameter(objNode, 'width', '');
									var strHeight 		= ',height=' + classBehaviour.getClassParameter(objNode, 'height', '');
									var strLeft			= ',left=' + classBehaviour.getClassParameter(objNode, 'left', '');
									var strTop			= ',top=' + classBehaviour.getClassParameter(objNode, 'top', '');
									var strToolbars 	= ',toolbar=' + classBehaviour.getClassParameter(objNode, 'toolbar', 'no');
									var strScrolling 	= ',scrollbars=' + classBehaviour.getClassParameter(objNode, 'scrollbars', 'no');
									var strStatus 		= ',status=' + classBehaviour.getClassParameter(objNode, 'status', 'no');
									var strResize 		= ',resizable=' + classBehaviour.getClassParameter(objNode, 'resizable', 'yes');
									var strLocation 	= ',location=' + classBehaviour.getClassParameter(objNode, 'location', 'no');
									var strMenu 		= ',menu=' + classBehaviour.getClassParameter(objNode, 'menu', 'no');
									var strName 		= classBehaviour.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.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.getClassParameter(objNode, 'min', '0'));
									// get max parameter
									var intMax = parseInt(classBehaviour.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;
		
	// Add or remove display:none; onclick
		// define this class behaviour
		function ToggleNextNode(){
			/* properties */
			this.name 		= 	'toggleNextNode';
			this.lastNode	=	null;
			this.lastNext	=	null;
			/* methods */
			this.start		=	function(node){
									node.onclick = this.toggleNext;
								}
			/* events */
			this.toggleThis = 	function(that, strClosePrevious){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tnn = classBehaviour.toggleNextNode;
									// restore previous node
									if(tnn.lastNode!=null && tnn.lastNode!=objNode && strClosePrevious=='yes') tnn.lastNode.style.display = 'none';
									// toggle node's visibility
									objNode.style.display = (objNode.style.display=='none') ? classBehaviour.getVisibleState(objNode) : 'none' ;
									// remember last node
									tnn.lastNode = objNode;	
								}
			this.toggleNext = 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tnn = classBehaviour.toggleNextNode;
									// get parent recursion
									var intParentRecursion = parseInt(classBehaviour.getClassParameter(objNode,'useParent','0'));
									var objParentNode = objNode;
									for(var a=0; a<intParentRecursion; a++) objParentNode = objParentNode.parentNode;
									// check if a previousnode needs closing
									var strClosePrevious = classBehaviour.getClassParameter(objNode,'closePrevious','no');
									// get optional id
									var strCloseId = classBehaviour.getClassParameter(objNode, 'id', null);
									// determine the next node
									var objNextNode;
									if(strCloseId!=null){
										objNextNode = document.getElementById(strCloseId);
									}else if(objParentNode.nextSibling){
										objNextNode = (objParentNode.nextSibling.nodeName.indexOf("text")<0) ? objParentNode.nextSibling : objParentNode.nextSibling.nextSibling ;
									}
									// if there is a next node
									if(objNextNode!=null){
										// toggle it's visibility
										tnn.toggleThis(objNextNode, strClosePrevious);
										// If the next node has been hidden
										if(objNextNode.style.display=='none'){
											// restore current node's click state
											objNode.className = objNode.className.replace('active','link');
											if(objNode.src!=null) objNode.src = objNode.src.replace('active','link');
											// do the same to the parent node
//											objNode.parentNode.className = objNode.parentNode.className.replace('active','link');
										}else{
											// mark current node as active
											objNode.className = objNode.className.replace('link','active');
											objNode.className = objNode.className.replace('hover','active');
											if(objNode.src!=null) objNode.src = objNode.src.replace('link','active');
											if(objNode.src!=null) objNode.src = objNode.src.replace('hover','active');
											// do the same to the parent node
//											objNode.parentNode.className = objNode.parentNode.className.replace('link','active');
//											objNode.parentNode.className = objNode.parentNode.className.replace('hover','active');
											// restore previous node's click state
											if(tnn.lastNext!=null && tnn.lastNext!=objNode && strClosePrevious=='yes'){
												tnn.lastNext.className = tnn.lastNext.className.replace('active','link');
												if(objNode.src!=null) tnn.lastNext.src = tnn.lastNext.src.replace('active','link');
												// do the same to the parent node
//												tnn.lastNext.parentNode.className = tnn.lastNext.parentNode.className.replace('active','link');
											}
										}
										// remember last node
										tnn.lastNext = objNode;
									}
									// cancel onclick event
									return false;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.toggleNextNode = new ToggleNextNode;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.toggleNextNode;
		
	// 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.getClassParameter(objNode, 'toParent', '0'));
									// get parent href
									var intFromParent = parseInt(classBehaviour.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.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.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;
									}
								}
							}
			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]) && 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){
								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.getClassParameter(objNode, 'type', '');
								allowEmpty			= classBehaviour.getClassParameter(objNode, 'allowEmpty', 'no');
								ifCheckedId			= classBehaviour.getClassParameter(objNode, 'ifCheckedId', null);
								hasExplanation 		= classBehaviour.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 'notempty' :
											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 validates;
							}
			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.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.className.indexOf('validationWarning')>-1) objWarningNode.style.display = (status) ? 'none' : 'block' ;
								// Highlight the label
									// get all labels
									allLabels = document.getElementsByTagName('label');
									// for all labels
									for(var a=0; a<allLabels.length; a++){
										// if the label matches this input
										if(allLabels[a].getAttributeNode('for').nodeValue == objNode.id){
											// add or remove the warning colour
											if(allLabels[a].parentNode.className.indexOf('noWarning')<0 && allLabels[a].className.indexOf('noWarning')<0) allLabels[a].className = (status) ? '' : 'warning' ;
										}
									}
								}
							}
			this.clear	=	function(objNode){
								var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
								// if there was an explanation provides as a value
								hasExplanation = classBehaviour.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');
								}
							}
			/* 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;
										}
		}
		// add this function to the classbehaviour object
		classBehaviour.validateInput = new ValidateInput;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.validateInput;
		
	// 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.getClassParameter(objNode, 'height', '100pct');
									strOffSet		= classBehaviour.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.getClassParameter(objNode, 'width', '100pct');
									strOffSet		= classBehaviour.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.getClassParameter(node, 'width', '256'));
									this.dimensions.y	= parseInt(classBehaviour.getClassParameter(node, 'height', '75'));
									this.speed.x		= -1 * parseInt(classBehaviour.getClassParameter(node, 'left', '2'));
									this.speed.y		= -1 * parseInt(classBehaviour.getClassParameter(node, 'top', '0'));
									this.delay			= parseInt(classBehaviour.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;
									// initiate the scroll interval
									this.scroll();
								}
			this.step		=	function(){
									var scrollCanvas		=	this.object.getElementsByTagName('UL')[0];
									// update styles
									scrollCanvas.style.left	=	(Math.abs(this.distance.x)>=Math.abs(this.limits.x)) ? '0px' : (this.distance.x + this.speed.x) + 'px';
									scrollCanvas.style.top	=	(Math.abs(this.distance.y)>=Math.abs(this.limits.y)) ? '0px' : (this.distance.y + this.speed.y) + 'px';
									// update stored positions
									this.distance.x			=	parseInt(scrollCanvas.style.left);
									this.distance.y			=	parseInt(scrollCanvas.style.top);
									return 0;
								}
			/* events */
			this.scroll		=	function(){
									classBehaviour.listScroller.interval = setInterval('classBehaviour.listScroller.step()', classBehaviour.listScroller.delay);
									return 0;
								}
			this.pause		=	function(){
									clearInterval(classBehaviour.listScroller.interval);
									return 0;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.listScroller = new ListScroller;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.listScroller;
		
	// 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.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;

	// blinks
		// define this class behaviour
		function TabbedContent(){
			/* properties */
			this.name 		= 	'tabbedContent';
			this.tab		=	null;
			this.content	=	null;
			/* methods */
			this.start		=	function(node){
									// get all tabs
									allTabs = node.getElementsByTagName('a');
									// for all tabs
									for(var a=0; a<allTabs.length; a++){
										// events handlers	
											// onclick events to the tabs
											allTabs[a].onclick = this.open;
										// default settings
											// default tab settings
											if(allTabs[a].className=='') allTabs[a].className = 'link';
											// default tab content settings
											tabId = allTabs[a].href.split('#')[1];
											document.getElementById(tabId).parentNode.parentNode.style.display = 'none';
										// active settings
											// if the anchor of the tab is in the url, mark the tab active
											if(document.location.href.indexOf('#'+tabId)>-1) allTabs[a].className = 'active';
											// if a tab is active, open it as if it were clicked upon
											if(allTabs[a].className.indexOf('active')>-1) this.open(allTabs[a]);
									}
								}
			/* events */
			this.open		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tbd = classBehaviour.tabbedContent;
									// previous tab
									if(tbd.tab!=null){
										// mark the previous tab as passive
										tbd.tab.className = 'link';
										// hide the previous tabbed content
										tbd.content.style.display = 'none';
									}
									// what is the next tab
										tbd.tab = objNode;
										tbd.content = document.getElementById(objNode.href.split('#')[1]).parentNode.parentNode;
									// next tab
										// mark the next tab as active
										tbd.tab.className = 'active';
										// show the next tabbed content
										tbd.content.style.display = 'block';
									// 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 in src sub-string
		// 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.getClassParameter(node, 'limitRight', '9999'));
											this.limitLeft = parseInt(classBehaviour.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;

	// 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;

	// 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.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.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.getClassParameter(allInputs[a], 'id', 'displayThisIdIfChecked');
											targetObj = document.getElementById(targetId);
											// hide the targetnode if checked
											if(targetObj){
												targetObj.style.display = (allInputs[a].checked) ? classBehaviour.getVisibleState(targetObj) : 'none' ;
											}
										}
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.displayIfChecked = new DisplayIfChecked;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.displayIfChecked;
		
	// 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,'');
									// 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;
		
		// start the parsing of classes
		classBehaviour.parseDocument();
