	// MAIN
	// main class-behaviour object
	function ClassBehaviour(){
		/* properties */
			this.handlers			=	new Array();
		/* methods */
			// parse the document for classnames
			this.parseDocument		=	function(node){
											target = (node) ? node : document;
											// get all document nodes
											var allNodes = (target.all) ? target.all : target.getElementsByTagName("*");
											// for all tags
											for(var a=0; a<allNodes.length; a++){
												// if the item has a className
												// if the item has a className
												if(allNodes[a].className){
													// get the classname
													nodeClass = allNodes[a].className;
													// for all behaviours
													for(var b=0; b<this.handlers.length; b++){
														// if the behaviour's name exists in the class name, apply it's events
														if(nodeClass.indexOf(this.handlers[b].name)>-1) this.handlers[b].start(allNodes[a]);
													}
												}
											}
										}
			// (cross)fader and pseudo event handler
			this.fader				=	new Fader;
			// helper functions
			this.utilities			=	new Utilities;
	}
	// create the main class-behaviour object
	var classBehaviour = new ClassBehaviour;
	
	// UTILITIES
		function Utilities(){
			this.screenHeight 		= 	function(){
											return (window.innerHeight) ? window.innerHeight : (document.documentElement.clientHeight) ? document.documentElement.clientHeight : document.body.clientHeight ;
										}
			// return a parameter from the url's query strings
			this.getQueryParameter 	= 	function(paramName, defaultValue){
											// split the query string at the parameter name
											var queryParameters = document.location.search.split(paramName+"=");
											// split the parameter value from the rest of the string
											var queryParameter = (queryParameters.length>1) ? queryParameters[1].split("&")[0] : null ;
											// return the value
											return (queryParameter!=null) ? queryParameter : defaultValue ;
										}
			// returns a string of parameters found in the classname which can be [eval]uated
			this.getClassParameter	=	function(targetNode, paramName, defaultValue){
											// get the class parameter from the classname
											var classParameter = targetNode.className;
											// split the classname between the parameter name
											classParameter = classParameter.split(paramName + '_');
											// split the second piece between spaces and take the first part,  if there are two pieces
											classParameter = (classParameter.length>1) ? classParameter[1].split(' ')[0] : null ;
											// return the value
											return (classParameter!=null) ? classParameter : defaultValue ;
										}
			// get the previous node without worrying about text nodes
			this.nextNode			=	function(node){
											// look for the next html node
											do {
												node = node.nextSibling;
											} while(node.nodeName.indexOf('#text')>-1);
											// return it
											return node;
										}
			// get the next node without worrying about text nodes
			this.previousNode		=	function(node){
											// look for the previous html node
											do {
												node = node.previousSibling;
											} while(node.nodeName.indexOf('#text')>-1);
											// return it
											return node;
										}
			// returns the visible display state needed for this element
			this.getVisibleState	=	function(node){
											// what kind of node is this
											switch(node.nodeName.toLowerCase()){
												case 'table' : visibleState='table' ; break;
												case 'thead' : visibleState='table-header-group' ; break;
												case 'tfoot' : visibleState='table-footer-group' ; break;
												case 'tbody' : visibleState='table-row-group' ; break;
												case 'tr' : visibleState='table-row' ; break;
												case 'td' : visibleState='table-cell' ; break;
												case 'th' : visibleState='table-cell' ; break;
												default : visibleState='block';
											}
											// apply the state
											return (document.all && navigator.userAgent.indexOf('Opera')<0) ? 'block' : visibleState;
										}
		}
		
		function Fader(){
			/* properties */
			/* methods */
			this.getFade	=	function(node){
									var fadeValue = null;
									// get the fade value using the proper method
									if(typeof(node.style.MozOpacity)!='undefined')	fadeValue = Math.round(parseFloat(node.style.MozOpacity)*100);
									if(typeof(node.style.filter)!='undefined')		fadeValue = parseInt(node.filters.alpha.opacity);
									if(typeof(node.style.opacity)!='undefined')		fadeValue = Math.round(parseFloat(node.style.opacity)*100);
									// return the value
									return fadeValue;
								}
			this.setFade	=	function(node, amount){
									// set the fade value using the proper method
									if(typeof(node.style.MozOpacity)!='undefined')	node.style.MozOpacity = amount/100;
									if(typeof(node.style.filter)!='undefined')		node.style.filter = "alpha(opacity=" + amount + ")";
									if(typeof(node.style.opacity)!='undefined')		node.style.opacity = amount/100;
										/*
										filter:alpha(opacity=50);	imageobject.filters.alpha.opacity=opacity
										-moz-opacity: 0.5;			imageobject.style.MozOpacity=opacity/100
										opacity: 0.5;
										-khtml-opacity: 0.5;
										*/
								}
			this.fadeIn		=	function(idIn, step, delay, evalEvent){
									var cf = classBehaviour.fader;
									// get the fading object
									node = document.getElementById(idIn);
									// get the current fade
									fade = cf.getFade(node) + step;
									// if not 100%
									if((fade)<100){
										// set the new fade
										cf.setFade(node, fade);
										// next step
										cf.timeOut = setTimeout("classBehaviour.fader.fadeIn('"+idIn+"',"+step+","+delay+",'"+evalEvent+"')", delay);
									// else
									}else{
										// set the fade to 100%
										cf.setFade(node, 100);
										// trigger the end event
										eval(evalEvent);
									}
								}
			this.fadeOut	=	function(idOut, step, delay, evalEvent){
									var cf = classBehaviour.fader;
									// get the fading object
									node = document.getElementById(idOut);
									// get the current fade
									fade = cf.getFade(node) - step;
									// if not 100%
									if(fade>0){
										// set the new fade
										cf.setFade(node, fade);
										// next step
										cf.timeOut = setTimeout("classBehaviour.fader.fadeOut('"+idOut+"',"+step+","+delay+",'"+evalEvent+"')", delay);
									// else
									}else{
										// set the fade to 100%
										cf.setFade(node, 0);
										// trigger the end event
										eval(evalEvent);
									}
								}
			this.crossFade	=	function(idIn, idOut, amount, step, delay, evalEvent){
									var cf = classBehaviour.fader;
									// if the amount is not the end value yet
									if(amount<=100){
										// set the fade amounts
										if(idIn && idIn!="") cf.setFade(document.getElementById(idIn), amount);
										if(idOut && idOut!="") cf.setFade(document.getElementById(idOut), 100-amount);
										// unhide the new page
										document.getElementById(idIn).style.display = 'block';
										// construct the fade function
										var evalLoop = "classBehaviour.fader.crossFade('"+idIn+"', '"+idOut+"', "+(amount+step)+", "+step+", "+delay+", '"+evalEvent+"')";
										// repeat the fade
										setTimeout(evalLoop, delay);
									}else{
									// else
										// cancel the opacity style
										var node = document.getElementById(idIn);
										if(typeof(node.style.MozOpacity)!='undefined')	node.style.MozOpacity = 'auto';
										if(typeof(node.style.filter)!='undefined')		node.style.filter = 'none';
										if(typeof(node.style.opacity)!='undefined')		node.style.opacity = 'auto';
										// hide the old page
										if(idOut && idOut!="") document.getElementById(idOut).style.display = 'none';
										// trigger the end event
										cf.onEnd(evalEvent);
									}
								}
			/* events */
			this.onEnd		=	function(evalEvent){
									eval(evalEvent);
								}
		}

	// BEHAVIOURS
	// replace in class
		// define this class behaviour
		function ClassMouseHover(){
			/* properties */
			this.name 		= 	'classMouseHover';
			/* methods */
			this.start		=	function(node){
									node.onmouseover = this.addHover;
									node.onmouseout = this.remHover;
								}
			this.hasNoStateClass 	= 	function(objNode){
											return (objNode.className.indexOf('link')<0 && objNode.className.indexOf('hover')<0 && objNode.className.indexOf('active')<0);
										}
			/* events */
			this.addHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var cmh = classBehaviour.classMouseHover;
									// replace link by hover
									objNode.className = (cmh.hasNoStateClass(objNode)) ? 'hover ' + objNode.className : objNode.className.replace('link','hover') ;
									// if there is an image within, replace it with the hover state too
									allImages = objNode.getElementsByTagName('IMG');
									if(allImages.length>0) allImages[0].src = allImages[0].src.replace('_link','_hover');
								}
			this.remHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var cmh = classBehaviour.classMouseHover;
									// replace hover by link
									objNode.className = (cmh.hasNoStateClass(objNode)) ? 'link ' + objNode.className : objNode.className.replace('hover','link') ;
									// if there is an image within, replace it with the hover state too
									allImages = objNode.getElementsByTagName('IMG');
									if(allImages.length>0) allImages[0].src = allImages[0].src.replace('_hover','_link');
								}
			this.addActive 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									var cmh = classBehaviour.classMouseHover;
									// replace link by active
									objNode.className = objNode.className.replace('link','active') ;
									// replace hover by active
									objNode.className = objNode.className.replace('hover','active') ;
									// if there's still no active class
									if(cmh.hasNoStateClass(objNode)) objNode.className = 'active ' + objNode.className;
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.classMouseHover = new ClassMouseHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.classMouseHover;
		
	// make all sub elements fake the :hover attribute with .hover
		// define this class behaviour
		function PseudoHover(){
			/* properties */
			this.name 		= 	'pseudoHover';
			/* methods */
			this.start		=	function(node){
									// get all elements
									allNodes = node.getElementsByTagName('LI');
									// for all elements
									for(var a=0; a<allNodes.length; a++){
										// add the hover event
										classBehaviour.classMouseHover.start(allNodes[a]);
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.pseudoHover = new PseudoHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.pseudoHover;
		
	// replace in src sub-string
		// define this class behaviour
		function SrcMouseHover(){
			/* properties */
			this.name 			= 	'srcMouseHover';
			this.cache 			= new Array();
			/* methods */
			this.start			=	function(node){
										this.cacheImages(node);
										node.onmouseover = this.addHover;
										node.onmouseout = this.remHover;
									}
			this.cacheImages	 = 	function(that) {
										var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
										// if this is not the image, it must be the parent
										if(!objNode.src) objNode = objNode.getElementsByTagName('IMG')[0];
										// replace link by hover
										var cacheIdx = this.cache.length;
										// hover version
										this.cache[cacheIdx] = new Image();
										this.cache[cacheIdx].src = objNode.src.replace('_link','_hover');
										// active version
										this.cache[cacheIdx+1] = new Image();
										this.cache[cacheIdx+1].src = objNode.src.replace('_link','_active');
									}
			/* events */
			this.addActive 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// if this is not the image, it must be the parent
									if(objNode.nodeName!='IMG') objNode = objNode.getElementsByTagName('IMG')[0];
									// replace link by active
									objNode.src = objNode.src.replace('_link','_active');
									// replace hover by active
									objNode.src = objNode.src.replace('_hover','_active');
								}
			this.addHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// if this is not the image, it must be the parent
									if(!objNode.src) objNode = objNode.getElementsByTagName('IMG')[0];
									// replace link by hover
									objNode.src = objNode.src.replace('_link','_hover');
								}
			this.remHover 	= 	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// if this is not the image, it must be the parent
									if(!objNode.src) objNode = objNode.getElementsByTagName('IMG')[0];
									// replace link by hover
									objNode.src = objNode.src.replace('_hover','_link');
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.srcMouseHover = new SrcMouseHover;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.srcMouseHover;
		
	// clear a form element filled with a help text
		// define this class behaviour
		function EmptyOnFocus(){
			/* properties */
			this.name 		= 	'emptyOnFocus';
			/* methods */
			this.start		=	function(node){
									node.onfocus = this.clear;
								}
			/* events */
			this.clear		=	function(that){
									var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
									// clear the contents if this is the first time
									if(objNode.className.indexOf('wasEmptied')<0){
										// clear this field
										objNode.value = '';
										// mark this input as cleared
										objNode.className += ' wasEmptied';
									}
								}
		}
		// add this function to the classbehaviour object
		classBehaviour.emptyOnFocus = new EmptyOnFocus;
		classBehaviour.handlers[classBehaviour.handlers.length] = classBehaviour.emptyOnFocus;
		
	// STARTUP-SEQUENCE
	// start the parsing of classes
	classBehaviour.parseDocument();
