/* collection of inline scripts */

/*
name			: Class Behaviour
update			: 20051005
author			: Frank van Rooijen, Maurice van Creij
dependencies	: lib_classbehaviour.js
info			: http://www.woollymittens.nl/content/details.asp?id=20040805133501

history
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]"
   (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)
5. Add display:none; to parent node
   class="closeParentNode"
6. Replace image with transparent version, invoke directX background loader
   class="pngAlpha"
7. Handle ondrag events
   class="dragAndDrop"
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
   class="validateInput [type_email allowEmpty_0]"
   (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 empty (default: 0)
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="sortTable"
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 Transform title-attributes into floating layers.
    class="deluxeTitles"
*/

	// 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]);
													}
												}
											}
										}
	}
	// 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){
									// 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;
										default : visibleState='block';
									}
									// apply the state
									node.style.display = visibleState;
									// fill the "previous node" parameters of a related object
									classBehaviour.toggleNextNode.lastNode = node;
									objPreviousNode = (node.previousSibling.nodeName.indexOf("text")<0) ? node.previousSibling : node.previousSibling.previousSibling ;
									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){
									// hide all select form elements
										allSelects = document.getElementsByTagName('SELECT');
										if(document.all){
											for(var a=0; a<allSelects.length; a++){
												allSelects[a].style.visibility = 'visible';
											}
										}

									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var tnn = classBehaviour.toggleNextNode;
									// hide the parent node
									objNode.parentNode.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.pickup		=	new Coordinates();
			/* methods */
			this.start		=	function(node){
									/*event*/;
									node.onmousedown = this.pickUp;
									document.onmouseup = this.dropDown;
									document.onmousemove = this.moveAway;
									// 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 = (document.all) ? event.x : that.layerX ;
										dnd.pickup.y = (document.all) ? event.y : that.layerY ;
										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 + 'px';
										if(objNode.style.top=='') objNode.style.top = dnd.pickup.y + 'px';
										// 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
										eventX = (document.all) ? event.x : that.layerX ;
										eventY = (document.all) ? event.y : that.layerY ;
										// current object position
										var styleX = (dnd.node.style.left.indexOf('px')<0) ? 0 : parseInt(dnd.node.style.left) ;
										var styleY = (dnd.node.style.top.indexOf('px')<0) ? 0 : parseInt(dnd.node.style.top) ;
										// new object position
										if(dnd.pickup.x!=null) dnd.node.style.left = (styleX+eventX-dnd.pickup.x) + 'px';
										if(dnd.pickup.y!=null) dnd.node.style.top = (styleY+eventY-dnd.pickup.y) + 'px';
										// update pickup location (for some browsers)
										if(document.all) dnd.pickup.x = eventX;
										if(document.all) dnd.pickup.y = eventY;
										// 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;

	// 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 SortTable(){
			/* properties */
			this.name 		= 	'sortTable';
			this.intSortCol = null;
			this.strSortRowTag = null;
			this.strSortColTag = null;
			/* methods */
			this.start		=	function(node){
									node.onclick = this.sort;
								}
			this.forward 	= 	function(objA,objB){
									var intCompare = 0;
									// get the string values from the nodes
									strA = (objA.getElementsByTagName(strSortColTag)[intSortCol].childNodes.length == 0) ? ' ' : objA.getElementsByTagName(strSortColTag)[intSortCol].innerHTML;
									strB = (objB.getElementsByTagName(strSortColTag)[intSortCol].childNodes.length == 0) ? ' ' : objB.getElementsByTagName(strSortColTag)[intSortCol].innerHTML;
									// get the numeric values from the nodes
									intA = parseInt(strA);
									intB = parseInt(strB);
									// 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)){
										// remove any tags that might be in the way
										var regTags = new RegExp('<(.|\n)+?>','gi');
										strA = strA.replace(regTags,'');
										strB = strB.replace(regTags,'');
										// compare the textual values
										return (strA>strB) ? 1 : -1 ;
									}else{
										// compare the numeric values
										return intB - intA;
									}
								}
			this.reverse 	= 	function(objA,objB){
									var intCompare = 0;
									// get the string values from the nodes
									strA = (objA.getElementsByTagName(strSortColTag)[intSortCol].childNodes.length == 0) ? ' ' : objA.getElementsByTagName(strSortColTag)[intSortCol].innerHTML;
									strB = (objB.getElementsByTagName(strSortColTag)[intSortCol].childNodes.length == 0) ? ' ' : objB.getElementsByTagName(strSortColTag)[intSortCol].innerHTML;
									// get the numeric values from the nodes
									intA = parseInt(strA);
									intB = parseInt(strB);
									// 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)){
										// remove any tags that might be in the way
										var regTags = new RegExp('<(.|\n)+?>','gi');
										strA = strA.replace(regTags,'');
										strB = strB.replace(regTags,'');
										// 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.sortTable
									// defaults
									intSortCol		= 0;
									strSortRowTag	= 'TR';
									strSortColTag	= 'TD';
									strSortDir		= 'forwardSorted';
									// Find column number
									var objSiblings	= objNode.parentNode.getElementsByTagName(objNode.nodeName);
									for(var intA=0; intA<objSiblings.length; intA++){
										// test if this is the clicked node
										if(objSiblings[intA] == objNode){
											intSortCol = intA;
											strSortDir = (objSiblings[intA].className.indexOf('forwardSorted')>-1) ? 'reverseSorted' : 'forwardSorted' ;
											objSiblings[intA].className += ' '+strSortDir;
										}
										// unmark any previously sorted column
										objSiblings[intA].className = objSiblings[intA].className.replace('forwardSorted','');
										objSiblings[intA].className = objSiblings[intA].className.replace('reverseSorted','');
									}
									// make a nodelist
									var objNodeTable	= (objNode.parentNode.parentNode.nodeName != 'TABLE') ? objNode.parentNode.parentNode.parentNode : objNode.parentNode.parentNode ;
									var objNodeRoot		= objNode.parentNode.parentNode ;
									var objNodeList		= objNodeRoot.getElementsByTagName(strSortRowTag);
									var arrNodeList		= new Array();
									// for all table rows (except the header)
									for(var intA=0; intA<objNodeList.length; intA++){
										if(objNodeList[intA].getElementsByTagName('TH').length<1){
											arrNodeList[arrNodeList.length] = objNodeList[intA];
										}
									}
									// sort the collection using a helper function
									arrNodeList = (strSortDir=='forwardSorted') ? arrNodeList.sort(st.forward) : arrNodeList.sort(st.reverse);
									// clear the unsorted nodelist
									for(var intA=0; intA<objNodeList.length; intA++){
										if(objNodeList[intA].getElementsByTagName('TH').length<1){
											objNodeRoot.removeChild(objNodeList[intA]);
										}
									}
									// append the sorted nodelist
									for(var intA=0; intA<arrNodeList.length; intA++){
										objNodeRoot.appendChild(arrNodeList[intA]);
									}
									// reapply the zebra effect
									if(objNodeTable.className.toLowerCase().indexOf('zebratable')>-1) classBehaviour.zebraTable.process(objNodeTable);
									// mark the newly sorted column
									objNode.className += ' ' + strSortDir;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.sortTable = new SortTable;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.sortTable;

	// 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;

      // 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 tnn = classBehaviour.toggleNextNode;
									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 = tnn.toggleNext;
									}
									// 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);
								}
		}
		// 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');
											cmh.remHover(fom.foldIns[fom.foldIns.length-1]);
											fom.foldIns.length = fom.foldIns.length - 1;
										}
									}
									// 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');
									}else{
										// 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);
									}
									// 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';
										}
									}
								}
		}
		// 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 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);
									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;

	// 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') ? 'block' : 'none' ;
									// remember last node
									tnn.lastNode = objNode;
								}
			this.toggleNext = 	function(that){
						// 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';
											}
										}

									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){
									node.onsubmit = classBehaviour.validateInput.all;
								}
		}
		// 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';
			/* methods */
			this.start		=	function(node){
									node.onblur = this.input;
								}

			this.all 		= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var vi = classBehaviour.validateInput;
									var booPassed = true;
									// get all subnodes
									var objSubNodes = (objNode.all) ? objNode.all : objNode.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) booPassed = (vi.input(objSubNodes[intA]) && booPassed);
									}
									// is the form valid enough?
									return booPassed;
								}
			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.input 		= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var vi = classBehaviour.validateInput;
									// default validator values
									var booEmptyTest,booBooValidator,booRegExpValidator, regExpValidator,booFuncValidator;
									// get the warning message
									var objWarningNode = (objNode.nextSibling.nodeName.indexOf("text")<0) ? objNode.nextSibling : objNode.nextSibling.nextSibling ;
									// get the type of validation required
									strValidatorName	= classBehaviour.getClassParameter(objNode, 'type', '');
									intAllowEmpty		= parseInt(classBehaviour.getClassParameter(objNode, 'allowEmpty', '0'));
									// empty test
									booEmptyTest = (intAllowEmpty==1 && objNode.value=='') ? true : false ;
									// boolean test
									switch(strValidatorName){
// TODO: need to check all radio buttons in one family
										case 'isradiochecked' :
											booBooValidator = true;
										default :
											booBooValidator = true;
									}
									// regular expression test
									if(navigator.appVersion.indexOf('MSIE 5.0')>-1 && strValidatorName=='money') strValidatorName = null;
									switch(strValidatorName){
										case 'email' :
											booRegExpValidator = (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' :
											booRegExpValidator = (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' :
											booRegExpValidator = (objNode.value.match(/^[0-9]{4}\s{0,1}[a-zA-Z]{2}$/)!=null);
											break;
										case 'date' :
											booRegExpValidator = (objNode.value.match(/^\d{4}\-\d{1,2}\-\d{1,2}$/)!=null);
											break;
										case 'number' :
											booRegExpValidator = (objNode.value.match(/^[0-9]+$/)!=null);
											break;
										case 'money' :
											booRegExpValidator = (objNode.value.match(/^[0-9]+(\.[0-9]{1,2})?$/)!=null);
											break;
										case 'alphanumeric' :
											booRegExpValidator = (objNode.value.match(/^[a-zA-Z0-9]/)!=null);
											break;
										default :
											booRegExpValidator = true;
									}
									// custom test
									switch(strValidatorName){
										case 'bankaccount' :
											booFuncValidator = vi.bankaccount(objNode);
											break;
										case 'notempty' :
											booFuncValidator = (objNode.value!="");
											break;
										default :
											booFuncValidator = true;
									}
									// close the error message by default
									objWarningNode.style.display = 'none';
									// show or hide the warning message based on the validator's match
									if(!booEmptyTest)objWarningNode.style.display = (booBooValidator && booRegExpValidator && booFuncValidator) ? 'none' : 'inline' ;
									// return a pass of fail boolean to whoever may want to know the results of the test
									return !(objWarningNode.style.display=='inline');
								}
		}
		// 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 ;
												// pick the node-type and it's corresponding visible state


												// show of hide the sibling
												if(prefState){
													var visibleState;
													switch(allNodes[a].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;
														default : visibleState='block';
													}
													// show thenode using the correct visible state
													allNodes[a].style.display = (document.all) ? 'block' : visibleState;
												}else{
													allNodes[a].style.display = 'none';
												}

										}
									}
								}

		}
		// add this function to the classbehaviour object
		classBehaviour.toggleHiddenSiblings = new ToggleHiddenSiblings;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.toggleHiddenSiblings;

	// Transform title-attributes into floating layers.
		// define this class behaviour
		function DeluxeTitles(){
			/* properties */
			this.name 		= 	'deluxeTitles';
			/* methods */
			this.start		=	function(node){
									// get all nodes within
									allNodes = node.getElementsByTagName('*');
									// for all nodes withing this one
									for(var a=allNodes.length-1; a>=0; a--){
										if(allNodes[a].title!='' && allNodes[a].childNodes.length>0 && allNodes[a].nodeName=='TD'){
											this.process(allNodes[a]);
											allNodes[a].className += ' deluxeTitleButton';
											allNodes[a].onclick = this.show;
										}
									}
								}
			/* events */
			this.process	=	function(node){
									// make a new new child-node
									popupNode = document.createElement('div');
									// give the child-node a classname
									popupNode.className = 'deluxeTitleText';
									// add a new text-node, with the title of the parent node, to the child-node
									popupText = document.createTextNode(node.title);
									// we don't need the old title anymore
									node.title = "";
									// fill the child-node with the text-node
									popupNode.appendChild(popupText);
									// put the node in the parentnode
									node.appendChild(popupNode);
								}
			this.show		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var dlt = classBehaviour.deluxeTitles;
									// hide all visible titles
									dlt.hideAll();
									// for all nodes in this parent
									for(var a=0; a<objNode.childNodes.length; a++){
										// find the one with the special class
										if(objNode.childNodes[a].className){
											if(objNode.childNodes[a].className.indexOf('deluxeTitleText')>-1){
												// make it visible
												objNode.childNodes[a].style.display = (objNode.childNodes[a].style.display=='block') ? 'none' : 'block';
												// give it a mouseover
												objNode.childNodes[a].onmousedown = dlt.hideAll;
											}
										}
									}
								}
			this.hideAll	=	function(){
									// get all nodes
									allNodes = document.getElementsByTagName("*");
									// for all nodes
									for(var a=0; a<allNodes.length; a++){
										// find the ones with the special class
										if(allNodes[a].className){
											if(allNodes[a].className.indexOf('deluxeTitleText')>-1){
												// make it invisible
												allNodes[a].style.display = 'none';
											}
										}
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.deluxeTitles = new DeluxeTitles;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.deluxeTitles;

		// start the parsing of classes
		classBehaviour.parseDocument();
