
/*
name			: Class Behaviour
update			: 20050705
author			: Frank van Rooijen, Maurice van Creij
dependencies	: lib_classbehaviour.js
info			: http://www.woollymittens.nl/content/details.asp?id=20040805133501

history
20050705		: drag and drop works better with miltiple layers
20050511		: no prior updates report

notes
1. Replace "link" in class
   class="classMouseHover link"
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[_CPno]"
   (Everything between [brackets] is optional. Leave out the [brackets] in the classname)
   CP = close the previous node, before opening a new one (default: no)   
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[_WI400][_HE300][_TByes][_SCyes][_RSyes][_STyes][_LOyes][_MEyes][_NMmyname]"
   WI = width (default: automatic)
   HE = height (default: automatic)
   TB = toolbars (default: no)
   SC = Scrollbars (default: no)
   RS = Resizable (default: no)
   ST = Status bar (default: no)
   LO = Location bar (default: no)
   ME = Menus (default: no)
   NM = 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[_MN0][_MX1]"
   MN = minimum (default: 0)
   MX = maximum (default: 1)
11. Class a link matching the document's url
   class="matchActiveUrl[_TP0][_FP0]"
   TP = Apply class to parent (default: 0)
   FP = 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[_TY]"
   (Everything between [brackets] is optional. Leave out the [brackets] in the classname)
   TY = validator type (email,phone,dutchzipcode,date,number,money,bankaccount,alphanumeric,notempty,(isradiochecked))
   AE = 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[_HE100pct][_OF100px]"
   HE = height + unit (default: no minimum. units: pct, px)
   OF = offset + unit (default: 0. units pct, px)
20 Enforces maximal width of a container
   class="maxWidth[_WI768px][_OF100px]"
   WI = width + unit (default: no minimum. units: pct, px)
   OF = 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[_DX256][_DY96][_SX1][_SY0][_DE0]"
   DX = distance to travel for one element (default: 256)
   DY = distance to travel for one element (default: 75)
   SX = horizontal speed (default: 2 pixel per second)
   SY = vertical speed (default: 0 pixel per second)
   DE = 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"
*/

/* 
TODO: sizable table
*/


	// constants/configuration
		if(typeof(intDragAndDropGridWidth)=='undefined')	var intDragAndDropGridWidth = 16;
		if(typeof(intDragAndDropGridHeight)=='undefined')	var intDragAndDropGridHeight = 16;
		if(typeof(strTransparentImg)=='undefined')			var strTransparentImg = '_alpha.png';
	// primary functions - functionality
		// returns a string of parameters found in the classname which can be [eval]uated
		function getClassParameter(objNode,strClassNameHint){
			// get the className
			var arrClassNames = objNode.className.split(' '); var strClass; var intClass = 0;
			while(strClass==null && intClass<arrClassNames.length){
				strClass = (arrClassNames[intClass].toLowerCase().indexOf(strClassNameHint.toLowerCase())>-1) ? arrClassNames[intClass] : null;
				intClass += 1;
			}
			// if the classname is valid
			if(strClass!=null){
				// get class parameters
				var arrClassParams = strClass.split('_'); var evalParams = '';
				for(var intParam=1; intParam<arrClassParams.length; intParam++){
					evalParams += "var " + arrClassParams[intParam].substr(0,2) + "= '" + arrClassParams[intParam].substr(2) + "';";
				}
			}
			return evalParams;
		}
		// return a parameter from the url's query strings
		function getQueryParameter(strParamName){
			// split the query string at the parameter name
			var arrQueryParameter = document.location.search.split(strParamName+"=");
			// split the parameter value from the rest of the string
			var strQueryParameter = (arrQueryParameter.length>1) ? arrQueryParameter[1].split("&")[0] : null ;
			// return the value
			return strQueryParameter;
		}
	// secondary function - constructors
		function parseForClasses(){
			var strClass, arrClass
			// get all elements
			var objAll = (document.all) ? document.all : document.getElementsByTagName("*");
			// for all elements
			for(var intA=0; intA<objAll.length; intA++){
				// get the element's class attribute
				strClass = objAll[intA].className;
				// if there is a class
				if(strClass!=null){	
					// split the class attribute into classes
					arrClass = strClass.split(' ');
					// for all sub-classes
					for(var intB=0; intB<arrClass.length; intB++){
						// choose known classes
						switch(arrClass[intB].toLowerCase()){
							// replace in class
							case "classmousehover" :
								objAll[intA].onmouseover = addClassHover;
								objAll[intA].onmouseout = remClassHover;
								//objAll[intA].onclick = addClassActive;
								break;
							// replace in src sub-string
							case "srcmousehover" :
								cacheSrcHover(objAll[intA]);
								objAll[intA].onmouseover = addSrcHover;
								objAll[intA].onmouseout = remSrcHover;
								break;
							// add display='none'; on parse
							case "hidethisnode" : 
								/*event*/;
								objAll[intA].style.display = 'none';
								break;
							// affirms the visibility status in regard to toggles
							case "showthisnode" : 
								/*event*/;
								objAll[intA].style.display = 'block';
								objLastOpened = objAll[intA];
								break;
							// add display='none'; to parent node
							case "closeparentnode" : 
								/*event*/;
								objAll[intA].onclick = closeParentNode;
								break;
							// replace image with transparent version, invoke activeX background loader
							case "pngalpha" : 
								/*event*/;
								pngAlpha(objAll[intA]);
								objAll[intA].onload = pngAlpha;
								break;
							// handle ondrag events
							case "draganddrop" : 
								/*event*/;
								objAll[intA].onmousedown = dragPickUp;
//								objAll[intA].onmouseup = dragDropDown;
//								objAll[intA].onmousemove = dragMoveAway;
								document.onmouseup = dragDropDown;
								document.onmousemove = dragMoveAway;
								// saved position
								dragRestore(objAll[intA]);
								break;
							// show contents as code
							case "showascode" : 
								/* event */
								showAsCode(objAll[intA]);
								break;
							// Add a className to a tag using the query parameter "class"',
							case "addquerytoclassname" :
								addQueryToClassName(objAll[intA]);
								break;
							// Add a suffix to an image source using the query parameter "src"',
							case "addquerytosrc" :
								addQueryToSrc(objAll[intA]);
								break;
								
							// Triggers all validateInput class behaviours within a node after the onsubmit event.',
							case "validateallinput" :
								objAll[intA].onsubmit = validateAllInput;
								break;
							// Resizes the window to avoid a scrollbar
							case "resizetofit" :
								objAll[intA].onload = resizeToFit;
								resizeToFit(objAll[intA]);
								break;
							// Resizes the window to avoid a scrollbar
							case "fittowindow" :
								objAll[intA].onresize = fitToWindow;
								fitToWindow(objAll[intA]);
								break;
							// Alternates the classes of a table's rows and columns
							case "zebratable" :
								zebraTable(objAll[intA]);
								break;
							// Makes the headers of a table click/sortable
							case "sorttable" :
								objAll[intA].onclick = sortTable;
								break;
							// Blink
							case "blink" :
								blink(objAll[intA]);
								break;
							// Open print dialog
							case "openasprintable" :
								objAll[intA].onclick = openAsPrintable;
								break;
							// Make dropdown menu
							case "dropdownmenu" :
								dropDownMenu(objAll[intA]);
								break;
							// Make foldout menu
							case "foldoutmenu" :
								foldOutMenu(objAll[intA]);
								break;
							// Remove this tag if it's found to be empty
							case "removeifempty" :
								removeIfEmpty(objAll[intA]);
								break;
							// Fixes the position of an element
							case "fixedposition" :
								fixedObjects[fixedObjects.length] = objAll[intA];
								if(document.all) window.onscroll = fixedPosition;
								break;
							default :
								/*event*/;
						}
						// check for parsable classes
						if(arrClass[intB].toLowerCase().indexOf("openaspopup")>-1) objAll[intA].onclick = openAsPopup;
						if(arrClass[intB].toLowerCase().indexOf("setrandomsrc")>-1) setRandomSrc(objAll[intA]);
						if(arrClass[intB].toLowerCase().indexOf("togglenextnode")>-1) objAll[intA].onclick = toggleNextNode;
						if(arrClass[intB].toLowerCase().indexOf("matchactiveurl")>-1) matchActiveUrl(objAll[intA]);
						if(arrClass[intB].toLowerCase().indexOf("validateinput")>-1) objAll[intA].onblur = validateInput;
						if(arrClass[intB].toLowerCase().indexOf("minheight")>-1){
							// immediate event
							minHeight(objAll[intA]);
							// store object for acter resize
							arrHeightAdjusts[arrHeightAdjusts.length] = objAll[intA];
							window.onresize = setDimensionsDelay;
						}
						if(arrClass[intB].toLowerCase().indexOf("maxwidth")>-1){
							// immediate event
							maxWidth(objAll[intA]);
							// store object for acter resize
							arrWidthAdjusts[arrWidthAdjusts.length] = objAll[intA];
							window.onresize = setDimensionsDelay;
						}
						if(arrClass[intB].toLowerCase().indexOf("listscroller")>-1) listScroller(objAll[intA]);
					}
				}
			}
		}
	// ternary function - event handlers
		function openAsPrintable(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
// TODO: exchange stylesheet with print stylsheet
			// open the print dialog
			window.print();
		}
			// blink helpers
			function blinkLoop(intToBlink){
				objToBlink = arrBlink[intToBlink][0];
				objToBlink.className = (objToBlink.className.indexOf('blinkoff')>-1) ? objToBlink.className.replace('blinkoff','blinkon') : objToBlink.className.replace('blinkon','blinkoff');
				arrBlink[intToBlink][1] = setTimeout('blinkLoop('+intToBlink+')',arrBlink[intToBlink][2]);
			}
		var arrBlink = new Array();
		function blink(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// make new blink entry
			arrBlink[arrBlink.length] = new Array(objNode,null,1024);
			// start blink loop
			blinkLoop(arrBlink.length-1)
		}
			// resize helpers
			arrHeightAdjusts = new Array();
			arrWidthAdjusts = new Array();
			function setDimensions(){
				for(var intA=0; intA<arrHeightAdjusts.length; intA++){
					arrHeightAdjusts[intA].style.height = 'auto';
					minHeight(arrHeightAdjusts[intA]);
				}
				for(var intA=0; intA<arrWidthAdjusts.length; intA++){
					arrWidthAdjusts[intA].style.width = 'auto';
					maxWidth(arrWidthAdjusts[intA]);
				}
			}
			// delay for the resize function to avoid jittering interface
			var setDimensionsTimeout = null;
			function setDimensionsDelay(){
				clearTimeout(setDimensionsTimeout);
				setDimensionsTimeout = setTimeout('setDimensions()',256);	
			}
		function minHeight(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the height parameters
			var strValidatorName, strMinHeight, strOffSet;		
			eval(getClassParameter(objNode,'minHeight'));
			strMinHeight	= (typeof(HE)!='undefined') ? HE : null ;
			strOffSet		= (typeof(OF)!='undefined') ? OF : null ;
			// 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(intDocHeight<=intCanvasHeight) objNode.style.height = (intMinHeight - intOffSet) + 'px';*/ 
			if(document.all){
				intOffSet -= 1;
				objNode.style.height = (intMinHeight - intOffSet) + 'px';
			}else{
				objNode.style.minHeight = (intMinHeight - intOffSet) + 'px';
			}
		}
		function maxWidth(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the width parameters
			var strValidatorName, strMaxWidth, strOffSet;		
			eval(getClassParameter(objNode,'maxWidth'));
			strMaxWidth		= (typeof(WI)!='undefined') ? WI : null ;
			strOffSet		= (typeof(OF)!='undefined') ? OF : null ;
			// 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' ;
		}
			// sort helpers
			function sortNodesForward(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;
				}
			}
			function sortNodesReverse(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;
				}
			}
		var intSortCol, strSortRowTag, strSortColTag;
		function sortTable(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// 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' ;
				}
				// 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(sortNodesForward) : arrNodeList.sort(sortNodesReverse);
			// 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) zebraTable(objNodeTable);
			// mark the newly sorted column
			objNode.className += ' ' + strSortDir;
		}
		function zebraTable(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			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;
					}
				}
			}
		}
		function resizeToFit(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);
		}
		function fitToWindow(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);	
		}
		function validateAllInput(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			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 = (validateInput(objSubNodes[intA]) && booPassed);
			}
			// is the form valid enough?
			return booPassed;
		}
			// custom validation functions
			function validate_bankaccount(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);
				}
			}
		function validateInput(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// 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			
			eval(getClassParameter(objNode,'validateInput'));
			strValidatorName	= (typeof(TY)!='undefined') ? TY : '' ;
			intAllowEmpty		= (typeof(AE)!='undefined') ? parseInt(AE) : 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 = validate_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' : 'block' ;
			// return a pass of fail boolean to whoever may want to know the results of the test
			return !(objWarningNode.style.display=='block');
		}
		function addQueryToClassName(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the query parameter
			var strQueryParameter = getQueryParameter("class");
			// add to front of classNames
			if(strQueryParameter!=null) objNode.className = strQueryParameter + ' ' + objNode.className;
		}
		function addQueryToSrc(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the query parameter
			var strQueryParameter = getQueryParameter("src")
			// add to front of classNames
			if(strQueryParameter!=null) objNode.src = objNode.src.replace('.','_'+strQueryParameter+'.');
		}
		var objPopup;
		function openAsPopup(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the parameters from the classname
			eval(getClassParameter(objNode,'openAsPopUp'));
			// get width parameter
			var strWidth		= (typeof(WI)!='undefined') ? 'width='+WI : '' ;
			// get height parameter
			var strHeight		= (typeof(HE)!='undefined') ? ',height='+HE : '' ;
			// get toolbar string
			var strToolbars		= (typeof(TB)!='undefined') ? ',toolbar='+TB : ',toolbar=no' ;
			// get scrolling string
			var strScrolling	= (typeof(SC)!='undefined') ? ',scrollbars='+SC : ',scrollbars=no' ;
			// get status string
			var strStatus		= (typeof(ST)!='undefined') ? ',status='+ST : ',status=no' ;
			// get resizable string = 
			var strResize		= (typeof(RS)!='undefined') ? ',resizable='+RS : ',resizable=no' ;
			// get resizable string = 
			var strLocation		= (typeof(LO)!='undefined') ? ',location='+LO : ',location=no' ;
			// get resizable string = 
			var strMenu			= (typeof(ME)!='undefined') ? ',menu='+ME : ',menu=no' ;
			// window name
			var strName			= (typeof(NM)!='undefined') ? NM : 'popup' ;
			// open requested window
			objPopup = window.open(objNode.getAttribute('href'), strName, strWidth+strHeight+strScrolling+strToolbars+strStatus+strResize+strLocation+strMenu);
			objPopup.focus();
			// cancel click
			return false;
		}
		function setRandomSrc(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the parameters from the classname
			eval(getClassParameter(objNode,'setRandomSrc'));
			// get min parameter
			var intMin		= (typeof(MN)!='undefined') ? parseInt(MN) : 0 ;
			// get max parameter
			var intMax		= (typeof(MX)!='undefined') ? parseInt(MX) : 1 ;
			// generate random number
			var intRandom = Math.round(Math.random()*(intMax-intMin))+intMin;
			// replace default increment by random number
			objNode.src = objNode.src.replace('_0','_'+intRandom);
		}
			function hasNoStateClass(objNode){
				return (objNode.className.indexOf('link')<0 && objNode.className.indexOf('hover')<0 && objNode.className.indexOf('active')<0);
			}
		function addClassHover(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// replace link by hover
			objNode.className = (hasNoStateClass(objNode)) ? 'hover ' + objNode.className : objNode.className.replace('link','hover') ;
		}
		function remClassHover(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// replace hover by link
			objNode.className = (hasNoStateClass(objNode)) ? 'link ' + objNode.className : objNode.className.replace('hover','link') ;
		}
		function addClassActive(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// 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(hasNoStateClass(objNode)) objNode.className = 'active ' + objNode.className;
		}
			// helper functions for srcMouseHover
			var arrCachedImages = new Array();
			function cacheSrcHover(that) {
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// replace link by hover
				var intCachedImageIdx = arrCachedImages.length;
				// hover version
				arrCachedImages[intCachedImageIdx] = new Image();
				arrCachedImages[intCachedImageIdx].src = objNode.src.replace('link','hover');
				// active version
				arrCachedImages[intCachedImageIdx+1] = new Image();
				arrCachedImages[intCachedImageIdx+1].src = objNode.src.replace('link','active');
			}
		function addSrcActive(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');
		}
		function addSrcHover(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// replace link by hover
			objNode.src = objNode.src.replace('link','hover');
		}
		function remSrcHover(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// replace link by hover
			objNode.src = objNode.src.replace('hover','link');
		}
			// helper function for 
			var objLastOpened;
			function toggleThisNode(that, strClosePrevious){
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// restore previous node
				if(objLastOpened!=null && objLastOpened!=objNode && strClosePrevious=='yes') objLastOpened.style.display = 'none';
				// toggle node's visibility
				objNode.style.display = (objNode.style.display=='none') ? 'block' : 'none' ;
				// remember last node
				objLastOpened = objNode;	
			}
		var objLastToggled;
		function toggleNextNode(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// make sure there's a next node
			if(objNode.nextSibling){
				// determine the next node
				var objNextNode = (objNode.nextSibling.nodeName.indexOf("text")<0) ? objNode.nextSibling : objNode.nextSibling.nextSibling ;
				// if there is a next node
				if(objNextNode!=null){
					// get the parameters from the classname
					eval(getClassParameter(objNode,'toggleNextNode'));
					// get parent recursion
					var strClosePrevious = (typeof(CP)!='undefined') ? CP : 'no' ;
					// toggle it's visibility
					toggleThisNode(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');
					}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');
						// restore previous node's click state
						if(objLastToggled!=null && objLastToggled!=objNode && strClosePrevious=='yes'){
							objLastToggled.className = objLastToggled.className.replace('active','link');
							objLastToggled.src = objLastToggled.src.replace('active','link');
						}
					}
					// remember last node
					objLastToggled = objNode;
				}
			}
			// cancel onclick event
			return false;
		}
		function closeParentNode(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// hide the parent node
			objNode.parentNode.style.display = 'none';
			// restore previous node's click state
			if(objLastToggled!=null && objLastToggled!=objNode) objLastToggled.className = objLastToggled.className.replace('active','link');
			// cancel onclick event
			return false;
		}
		function pngAlpha(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 downloeve 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 + strTransparentImg;
				// for the rest of the world
				}else{
					// replace the image source with the alpha channel version
					objNode.src = strAlphaSrc;
				}
			}
		}
			// drag and drop helper functions
			function dragRestore(that){
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// 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];
						}
					}
				}
			}
			function dragStore(that){
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// is lib_cookies available
				if(typeof(setCookie)!='undefined'){
					// store styles
					setCookie('dragposition', objNode.id + ',' + objNode.style.left + ',' + objNode.style.top, null, '/', null, null);
				}
			}
		var objPickup, intPickupX, intPickupY, intPickupZ;
		function dragPickUp(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// accept no new pickups before dropdown
			if(objPickup==null){
				// store the object being picked up
				objPickup = objNode;
				// store pickup location
				intPickupX = (document.all) ? event.x : that.layerX ;
				intPickupY = (document.all) ? event.y : that.layerY ;
				intPickupZ = (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 = intPickupX + 'px'; 
				if(objNode.style.top=='') objNode.style.top = intPickupY + 'px';
				// promote z position
				objNode.style.zIndex = 1024;
			}
			// cancel browser mouse handler
			return false;
		}
		var intGridX=intDragAndDropGridWidth; var intGridY=intDragAndDropGridHeight;
		function dragDropDown(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// only if a pickup is active
			if(objPickup!=null){
				// snap coordinates to grid
				if(intGridX>0) objPickup.style.left = Math.round(parseInt(objPickup.style.left)/intGridX)*intGridX + "px";
				if(intGridY>0) objPickup.style.top = Math.round(parseInt(objPickup.style.top)/intGridY)*intGridY + "px";
				// restore z position
				objPickup.style.zIndex = intPickupZ;
				// store the position in a cookie
				dragStore(objPickup);
				// release the picked up object
				objPickup = null;
				// clear pickup location
				intPickupX = null;
				intPickupY = null;
				intPickupZ = null;
			}
			// cancel browser mouse handler
			return false;
		}
		function dragMoveAway(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// only if a pickup is active
			if(objPickup!=null){
				// mouse position
				intEventX = (document.all) ? event.x : that.layerX ;
				intEventY = (document.all) ? event.y : that.layerY ;
				// current object position
				var intStyleX = (objPickup.style.left.indexOf('px')<0) ? 0 : parseInt(objPickup.style.left) ;
				var intStyleY = (objPickup.style.top.indexOf('px')<0) ? 0 : parseInt(objPickup.style.top) ;
				// new object position
				if(intPickupX!=null) objPickup.style.left = (intStyleX+intEventX-intPickupX) + 'px';
				if(intPickupY!=null) objPickup.style.top = (intStyleY+intEventY-intPickupY) + 'px';
				// update pickup location (for some browsers)
				if(document.all) intPickupX = intEventX;
				if(document.all) intPickupY = intEventY;
				// cancel browser mouse handler
				return false;
			}
		}
		function showAsCode(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// 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 />");
		}
			// helper functions for matchActiveUrl()
			function convertAbsToRelUrls(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;
			}
			function compareUrls(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 = convertAbsToRelUrls(strUrlA);
				strUrlB = 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;
			}
		function matchActiveUrl(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the parameters from the classname
			eval(getClassParameter(objNode,'matchActiveUrl'));
			// get parent recursion
			var intToParent	= (typeof(TP)!='undefined') ? parseInt(TP) : 0 ;
			// get parent href
			var intFromParent = (typeof(FP)!='undefined') ? parseInt(FP) : 0 ;
			// get the url and clean it up
			var strUrl = convertAbsToRelUrls(document.location.href);
			// get the href and clean it up
			var strHref = (intFromParent>0) ? convertAbsToRelUrls(objNode.parentNode.getAttribute('href')) : convertAbsToRelUrls(objNode.getAttribute('href')) ;
			// was the data bad
			if(strHref!=null){
				// compare score
				var ftlCompareScore = compareUrls(strUrl, strHref) * compareUrls(strHref, strUrl);
				// if the href matches the url 
				if(ftlCompareScore==1){
					// add the active class to the target item
					addClassActive(objNode);
					if(objNode.nodeName=='IMG') addSrcActive(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
							addClassActive(objNode);
						}
					}
					// report a match
					return true;
				}
			}
			// report no match
			return false;
		}
			function recurseActiveNode(objParentNode){
				// mark the node as active
				addClassActive(objParentNode);
				// add active class to the anchor
				if(objParentNode.getElementsByTagName('A').length>0) addClassActive(objParentNode.getElementsByTagName('A')[0]);
				// replace image source for active version
				if(objParentNode.getElementsByTagName('IMG').length>0)  toggleNextNode(objParentNode.getElementsByTagName('IMG')[0]);
				// next recursion to same node type
				if(objParentNode.nodeName == objParentNode.parentNode.parentNode.nodeName) recurseActiveNode(objParentNode.parentNode.parentNode);
			}
		function dropDownMenu(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			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 = toggleNextNode;
			}
			// apply default settings to all As
			objNodes = objNode.getElementsByTagName('A');
			for(var intNode=0; intNode<objNodes.length; intNode++){
				// use matchActiveUrl to find active items OR use the ones marked manualy
				objMatch = (matchActiveUrl(objNodes[intNode]) || objNodes[intNode].className.indexOf('active')>-1) ? objNodes[intNode] : objMatch ;
			}
			// recurse back the last matching node
			if(objMatch!=null) recurseActiveNode(objMatch.parentNode);
		}
			function addClassHoverProxy(that){
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// emulate the parent node's mouseout event
				addClassHover(objNode);
			}
			function remClassHoverProxy(that){
				var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
				// emulate the parent node's mouseout event
				remClassHover(objNode);
			}
		function foldOutMenu(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			var objNodes, objMatch;
			// apply events to all LIs
			objNodes = objNode.getElementsByTagName('LI');
			for(var intNode=0; intNode<objNodes.length; intNode++){
				// mouseover events
				objNodes[intNode].onmouseover	= addClassHoverProxy;
				objNodes[intNode].onmouseout	= remClassHoverProxy;
			}
		}
			function Scroller(){
				// parameters
				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;
				// functions
				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;
										}
				this.start			=	function(){
											scroller.interval		= setInterval('scroller.step()',scroller.delay);
											return 0;
										}
				this.stop			=	function(){
											clearInterval(scroller.interval);
											return 0;
										}
			}
				function Coordinates(){
					this.x = 0;
					this.y = 0;
				}
		var scroller = new Scroller();
		function listScroller(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// get the parameters from the classname
			eval(getClassParameter(objNode,'listScroller'));
			// make a new instance of the scroller object
			scroller.object			= objNode;
			scroller.dimensions.x	= (typeof(DX)!='undefined') ? parseInt(DX) : 256 ;
			scroller.dimensions.y	= (typeof(DY)!='undefined') ? parseInt(DY) : 75 ;
			scroller.speed.x		= (typeof(SX)!='undefined') ? -1 * parseInt(SX) : -2 ;
			scroller.speed.y		= (typeof(SY)!='undefined') ? -1 * parseInt(SY) : 0 ;
			scroller.delay			= (typeof(DE)!='undefined') ? parseInt(DE) : 64 ;
			// clone the list items for double buffering
			var scrollList			= scroller.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
			scroller.limits.x		= scroller.dimensions.x * itemsMax;
			scroller.limits.y		= scroller.dimensions.y * itemsMax;
			// set prerequisite styles
				//	UL settings
				scrollList.style.width		= (scroller.dimensions.x * 2 * itemsMax) + 'px';
				scrollList.style.height		= (scroller.dimensions.y * 2 * itemsMax) + 'px';
				// LI settings
				for(var a=0; a<scrollItems.length; a++){
					scrollItems[a].style.width	= scroller.dimensions.x + 'px';
					scrollItems[a].style.height	= scroller.dimensions.y + 'px';
				}
			// set the mouseover events
			scroller.object.onmouseover		= scroller.stop;
			scroller.object.onmouseout		= scroller.start;
			// initiate the scroll interval
			scroller.start();
		}
		function removeIfEmpty(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// doesn't this node have child nodes?
			if(objNode.childNodes.length==0){
				// remove the node
				objNode.parentNode.removeChild(objNode);
			}
		}
		var fixedObjects = new Array();
		function fixedPosition(that){
			var objNode = (typeof(this.nodeName)=='undefined') ? that : this ;
			// this is only needed in internet explorer
			for(var a=0; a<fixedObjects.length; a++){
				fixedObjects[a].style.marginTop = (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + 'px';
				fixedObjects[a].style.marginLeft = (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft) + 'px';
			}
		}
	// events
		//onload = parseForClasses;
		parseForClasses();
