/*************************************************************************************************************
enformiaUtils.js

general purpose javascript functions


how to use:
===========
include this script in the page:
		<!-- utils script. instanciate a window level object enUtils-->
		&lt;script language="JavaScript" type="text/javascript"
			src="../Static/Include/enformiaUtils.js"&gt;&lt;/script&gt;

the script will create an object named enUtils (or window.enUtils)
	all functions are the object's methods result=enUtils.fnName();

enUtils functions
=================
name					description
----					-----------

general
--------
isSet						is parame set
isEmpty						is parame empty
isNum						is numeric
isInteger					is integer
isArray						is element an array
isObject					is element an object
ntz							make sure param is not null or undefined
toBoolean					get boolean value
enEscape					js escape + replace for + to %2B (to suit with Java)
isEscaped					check if value is url escaped
safeEscape					make sure value is url escaped. do not escape if already escaped
compareVals 				compare values by type

String functions
---------
getNthIndexOf 				get the nth position of an expression
startsWith					check if a string starts with another string
endsWith					check if a string ends with another string


getRadioValue 				get selected value of radio buttons group
setRadioValue 				set value of radio buttons group
getValueOf 					get element's value
setValueOf 					set element's value

openPopupWindow 			open a window and set it's focus
openPopupWindowWithShift	check if ShiftKey is pressed and then call to openPopupWindow 
closeOnEsc 					close window on escape
areValuesEqual 				check if value tst is equal to value vals
setSelectedOptions 			set selected options is select element to one or more values in vals
setPageTitle				set the title of the document
absoluteRedirect			redirect to a given url - handle popup and hidden pages
setWinLocation				load the window with specific url
getBody						get body object
setBodyStyle 				set body style attribute

DOM elemnets functions
-------------------------
objectOrGetId 				get object by id
getTableTbody				for a given table the function returns reference to its TBODY elemnt(even if no such tag in the HTML source)
getElTr						for a given element in a table returns a reference to the TR element.
getElTable					for a given element in a table returns a reference to the table element
getWindowPos				get window position and dimentions
getCompatMode				get compatability mode
getElementsByTagsNames		returns an array of all the child nodes of an element filtered by a list of tagNames.

Cross browsers events functions
---------------------------------
evtGetCBEvent				build a cross browser event object
evtAddEvent					attach event to element - cross browser
evtRemoveEvent				remove event from element - cross browser
evtAddEventByTagName 		attach event to elements by their tag name
appendEvent 				append event to an existing one (deprecated)

Gui functions
--------------
elmntContetsChangeGui		gets a tag like div,table or form and disables/enables all the controlls in it
elmntToggleClass			toggle class name of an element
elmntShowHide				toggles element's display style - shows or hides the element
elmntShowHideAdvanced		toggles elements display by tag name and container
elmntIsVisible				is element visible
setPreviewImg				set preview image by an attribute in a select element
setZIndex					Set zIndex property
elmntResize					gets an elemenet id and changes the width and heigt styles.
elmntShiftBy				gets an elemenet id and moves it by specified pixels (relative movement)
elmntMove					gets an elemenet id and locate in a new posotion (absolute movement) 
							+ optional resize it
elmntAbsPos					gets an elemenet id and calc the absolute position of it 
							*absolute=relative to upper-left window's corner.
elmntActualHeight			get actual height
elmntActualWidth			get actual width
elmntBackupChildChecks		backup element's child checkboxes and options values. goes with elmntRestoreChildChecks
							and used when dynamically switching elements in the document
elmntRestoreChildChecks		restore element's child checkboxes and options values
elmntSelectFirst 			select the first element in the document
elmntSelect 				select a given element
elmntGetParentByTagName 	search for parent element by tag name
elmntRemove					remove element
elmntScrollIntoView			scroll to the element so it's visible
elmntSetInnerText			set element inner text
elmntImportForSubmit		import elements between forms before submit
elmntToggleAdvancedOptions 	show and hide advanced options

floating iFrame	(hidden iframe, that will serve as popup)
------------------------------------------------------------------
ifrShowFloatingIfr
ifrCalcFloatingPosotion		claculates the relative position of the div to an element
ifrKeepInWindow				makes changes in the div position if he fets out of the window
ifrHandleAttributes			insert for an iframe the src value or writes the html itself
getIfrFromDiv				search for an iframe in a div container, returns the iframe if found, else the passed element.
ifrCreate					create an iframe with id & name of the passed parameter- FOR IE5.5 ONLY!

array functions
---------------
isInArray					get item and array, and check if the item exists in the array
doubleArray					double one dimension array into two dimension array
								ex: arr{item1,item2,...}-->>arr{{item1,item1},{item2,item2},...}

date functions
---------------
getDateFromElements			get a date object from date elements (yy, mm, dd, ..)
formatAsDateTime			formats a date according to custom/default pattern.

query string
------------
addQueryStringParam			add query string parameter to path
addQueryStringParamToEnd	append param value pair to end of path
getQueryString				get query string on client side
getQueryStringParam			parse a specific query string parameter on the client side
getBaseUrl 					get base url from window location
getFolderFromUrl			get the folder from the url
getFileFromUrl 				get the file from the url
qryStringToArray      		convert qry string into a 2 dimention array (encodes values)
qryStringFromArray    		convert a 2 dimention array to a query string (encodes values)
separatedListToArray  		convert a separated list into a 1 dimention array
separatedListFromArray  	convert a 1 dimention array into a separated list

executing in hidden frame 
--------------------------
(your page should have an iframe or layer, or be part of a frameset with a hidden one)

execAsync					run async exec and flag the form if passed
execAsyncFrame				run async exec and flag the form if passed - a hidden frame in a frameset
callbackAsync				runs the callback function. called from the hidden frame
clearIFrameSrc				called from container page: clear iframe location - refresh would run it again
clearCurrFrameSrc			called from frame: clear iframe location - refresh would run it again
flagFormAsync				flag form for async execution
isExecAsync					check if form may be submitted - if not during async execution
execAsyncOnComboChange 		run async exec on combo change
getParentWin				returns the parent window
defaultCallBack				a general purpos call back function
confirmActionHidden			confirm action in a hidden frame

limit text area length
-----------------------
limitTextLength 			limit length in textarea - onkeypress
chunkTextLength				limit length in textarea - onblur

limit input
-----------------------
limitInputInteger 			limit input to integers only
limitInputNumeric			limit input to numeric only

list functions - for use in assigning items between lists
----------------------------------------------------------

listMoveSelectedItems		move selected item between lists
listSortItems				sort list items
listReplaceItems			replace 2 items within a list
listAllItems				list all items into a text element
listMoveOptions 			move selected options in list
listRefillM2MLists 			refill 2 selects for Many to Many connections
listRefillList				refills a givven list.

tables functions
-------------------------------------------------------------
tblSortTableEvt 			sort table - for use from event
tblSortTableByEl			sort table - by an element in a header td
tblSortTable 				sort table
tblMoveTableRow				move a row in a table in a desired direction (up/down)
tblSwitchTableRows			switch table rows
tblGetRowIndex				returns the tr index in the tbody.rows collection
tblReassignRowsClass		re assign classes to rows (odd / even)		
tblReassignSortStatus 	set sort status image

ticker (scrolling messages)
---------------------------------------------------------------
ticGlobal					global ticker object
ticNs4marquee 				build ns 4 elements
ticNs4slide 				build ns 4 elements
ticNs6marquee 				build ns 6 elements
ticNs6slide 				build ns 6 elements
ticInit 					init ticker
ticWriteElements 			write eleemnts - called when the page is written		


Drag & Drop functions
---------------------------------------------------------------
GENERAL:
	in order for an elemnt to be dragable it must have:
	1. attribute enaDragable="1"
	2. style="position:absolute"
	3. If the element has border, it must be numeric.
	4. on the page load run the dragInit();
FUNCTIONS: 
dragInit:					init function to set the global variable & attach functions to documnet events
dragCatch:					private function (start drag).
dragSetSelectedElmnt:		private function (put draged elemnt in memory)
dragRelease:				end drag - clear memory + put last position in memory
dragIt:						private function (dragging)

Coookies function
---------------------------------------------------------------
setCookie					Function to create or update a cookie.
getCookie					Function to return the value of the cookie specified by "name" (null if not found)
deleteCookie				Function to delete a cookie. (Sets expiration date to start of epoch)

*************************************************************************************************************/

//enUtils construstor function
function enUtilsConstrustor()
{
	
	/*---------------------------------------------------------------------------------------
		general
	---------------------------------------------------------------------------------------*/

	//is parame set
	var isSet=function(prm)
	{
		var und;
		return(prm!=und && prm!=null);
	}
	this.isSet=isSet;
	
	//is parame empty (undefined / null /  "")
	var isEmpty=function(prm)
	{
		return(!isSet(prm) || ((typeof prm).toLowerCase()=="string" && prm.length==0));
	}
	this.isEmpty=isEmpty;

	//is numeric
	var isNum=function (v)
	{
		if(isEmpty(v))return false;
		return (v.toString() && !/\D/.test(v));
	}
	this.isNum=isNum;
	
	//is integer
	var isInteger=function (sValue,bSigned)
	{
		if(isEmpty(sValue))return false;
		var re=new RegExp("^"+((bSigned)?"[\\-\\+]?":"")+"\\d+$");
		return re.test(sValue);
	}
	this.isInteger=isInteger;
	
	//is element an array
	var isArray=function(elmnt)
	{
		if(!isSet(elmnt))return false;
		return (elmnt.constructor==Array);
	}
	this.isArray=isArray;
	
	//is element an object
	var isObject=function(elmnt)
	{
		if(!isSet(elmnt))return false;
		return (elmnt.constructor==Object || typeof elmnt == "object");
	}
	this.isObject=isObject;
	
	//make sure param is not null or undefined
	var ntz=function(prm,def)
	{
		if(!isSet(def))def="";
		return(isEmpty(prm)?def:prm);
	}
	this.ntz=ntz;
	
	//get boolean value
	var toBoolean=function(prm,def)
	{
		if(!isSet(def))def=false;		
		if(prm==true || prm==1)
			return true;
		if(prm==false || prm==0)
			return false;
		prm=ntz(prm).toLowerCase();
		if(prm=="true" || prm=="1")
			return true;
		if(prm=="false" || prm=="0")
			return false;
		return def;
	}
	this.toBoolean=toBoolean;
	
	//js escape + replace for + to %2B (to suit with Java)
	var enEscape=function(prm)
	{
		prm=escape(prm);//javascript escape
		prm=prm.replace(/\+/g,"%2B");//replace + with %2B (ie & ns6+ does not do it)
		return prm;
	}
	this.enEscape=enEscape;
	//check if value is url escaped
	var isEscaped=function(prm)
	{
		return prm!=unescape(prm);
	}
	this.isEscaped=isEscaped;
	
	//make sure value is url escaped. do not escape if already escaped
	var safeEscape=function(prm)
	{
		if(isEscaped(prm))return prm;
		else return escape(prm);
	}
	this.safeEscape=safeEscape;
	
	/*
		compare values by type
		params:
			val1 - first val
			val2 - 2nd val
			type - compare type: numeric / date@format / text (def)
				the @format part in date is optional.
				format may be mm/dd/yyyy, dd/mm/yyyy or '-' instead of '/'
		returns:
			0 if equal, 1 if val1>val2, -1 else
	*/
	var compareVals=function(val1,val2,type)
	{
		if(isEmpty(type))type="text";
		type=type.toLowerCase();
		if(type=="numeric")
		{
			val1=1*val1;
			val2=1*val2;
		}
		else if(type.indexOf("date")==0)
		{
			var fmt="";
			//check for date format
			if(type.indexOf("@")!=-1)
			{
				fmt=type.split("@")[1];
			}
			//if(!isEmpty(fmt))
			if(fmt!="")
			{
				var dt=isSet(enValidation) ? enValidation.isDate(val1,fmt,true) : null;
				val1=dt?dt.getTime():null;
				dt=isSet(enValidation) ? enValidation.isDate(val2,fmt,true) : null;
				val2=dt?dt.getTime():null;	
			}
			//free format (based on Date.parse())
			else
			{
				val1=Date.parse(val1);
				val2=Date.parse(val2);
			}
		}

		if(val1==val2)return 0;
		if(val1>val2)return 1;
		else return -1;
	}
	this.compareVals=compareVals;

	/*
		get the nth position of an expression
		params:
			text - text to search
			expr - expression to find
			n - nth position
		returns - pos, or -1 if not found
	*/
	var getNthIndexOf=function(text,expr,n)
	{
		if(isEmpty(text)||isEmpty(expr)||!isNum(n))return -1;
		var pos=0;
		var len=expr.length;
		for(var i=1;i<=n;i++)
		{
			pos=text.indexOf(expr,pos+len);
			if(pos==-1)return -1;
		}
		return pos;
	}
	this.getNthIndexOf=getNthIndexOf;
	
	/*
	check if a string starts with another string
	*/
	var startsWith=function(str,prefix)
	{
		var preLen=prefix.length;
		var strLen=str.length;
		if(preLen>str.length) return false;
		return(str.substr(0,preLen)==prefix)
	}
	this.startsWith=startsWith;
	/*
	check if a string ends with another string
	*/
	var endsWith=function(str,suffix)
	{
		var sufLen=suffix.length;
		var strLen=str.length;
		if(sufLen>str.length) return false;
		return(str.substr(strLen-sufLen,sufLen)==suffix)
	}
	this.endsWith=endsWith;
	
	//get selected value of radio buttons group
	var getRadioValue=function(r){
		if(isEmpty(r))return null;
		r=objectOrGetId(r);
		//check if an array
		var len=r.length;
		if(len>0)
		{
			if(r[0].type!="radio")return null;
			//loop through multiple options
			for(var intLoop=0;intLoop<r.length;intLoop++)
			{
				if(r[intLoop].checked) return r[intLoop].value;
			}
		}
		else 
		{
			if(r.type!="radio")return null;
			if(r.checked)
			{
				return isSet(r.value) ? r.value : true;
			}
		}
		return null;
	}
	//expose
	this.getRadioValue=getRadioValue;
	
	//set value of radio buttons group
	var setRadioValue=function(r,value)
	{
		if(isEmpty(r))return false;
		r=objectOrGetId(r);
		//check if an array
		var len=r.length;
		if(len>0)
		{
			if(r[0].type!="radio")return false;
			//loop through multiple options
			for(var intLoop=0;intLoop<r.length;intLoop++)
			{
				if(r[intLoop].value==value)
				{
					r[intLoop].checked=true;
					return true;
				}
			}
		}
		else 
		{
			if(r.type!="radio")return false;
			r.checked=value?true:false;
			return true;
		}
		return false;
	}
	//expose
	this.setRadioValue=setRadioValue;
	
	/*
		get element's value
		oElement may be an element or an array of radio
	*/
	var getValueOf=function(oElement)
	{
		oElement=objectOrGetId(oElement);
		if(isEmpty(oElement))return null;
		//check if an array and element type (radio only)
		var len=oElement.length;
		if(len>0 && oElement[0].type=="radio") return getRadioValue(oElement);
		return _getValueOf(oElement);
	}
	//expose
	this.getValueOf=getValueOf;
	
	var _getValueOf=function(oElement)
	{
		var sReturnValue = null;
		if(!oElement)return sReturnValue;
		switch (oElement.type){
			case "text" : case "textarea" : case "file" : case "password" : case "hidden" :
				sReturnValue = oElement.value;
				break;
			case "select-one" :			
				sReturnValue = oElement.options[oElement.selectedIndex].value;
				break;
			case "select-multiple" :
				var i,c=0, iOptions = oElement.options.length;
				for(i=0; i<iOptions; i++){
					if(oElement.options[i].selected){
						c++;
						if(c==1)sReturnValue="";
						if(c>1)sReturnValue+=",";
						sReturnValue+=oElement.options[i].value;
					}
				}
				break;
			case "radio" : case "checkbox" :
				if(oElement.checked)
				{
					sReturnValue = oElement.value ? oElement.value : true;
				}else sReturnValue=false;
				break;
		}
		return sReturnValue;
	}	
	
	//set element's value
	var setValueOf=function(oElement,value)
	{
		if(isEmpty(oElement))return false;
		oElement=objectOrGetId(oElement);
		//check if an array and element type (radio only)
		var len=oElement.length;
		if(len>0 && oElement[0].type=="radio") return setRadioValue(oElement,value);
		return _setValueOf(oElement,value);
	}
	this.setValueOf=setValueOf;
	var _setValueOf=function(oElement,value)
	{
		if(!isSet(oElement))return false;
		oElement=objectOrGetId(oElement);
		switch (oElement.type)
		{
			case "text" : case "textarea" : case "file" : case "password" : case "hidden" :
				oElement.value=value;
				break;
			case "select-one" : case "select-multiple" :
				setSelectedOptions(oElement,value);
				break;
			case "radio" : case "checkbox" :
				oElement.checked=(value?true:false);
				break;
		}
		return true;
	}	

			
	/*
	open a window and set it's focus
		path - url to open
		target - target window name (def 'enDefaultTarget')
		atts - optional atts string
		width - win width, when atts is null
		height - win height, when atts is null
		retWin - return the window object (def false)
		center - center in window (def true)
		newIfExsists - if there is a window in that name, open in new window (def false)
	adds the following params:
		enaPopup - in popup page
		enaRand - random value (to enformce refresh)
	*/
	var openPopupWindow=function(path,target,atts,width,height,retWin,center,newIfExsists)
	{
		//def size
		if(isEmpty(width) || !isInteger(width))width="500";
		if(isEmpty(height) || !isInteger(height))height="480";
		//center in window
		if(!isSet(center))center=true;
		if(!isSet(newIfExsists))newIfExsists=false;
		var centerPos="";

		//center in window
		if(center)
		{
			var winPos=getWindowPos(window.top);
			var left=0.5*(winPos.width-parseInt(width));
			var top=0.5*(winPos.height-parseInt(height));
			if(left>=0)centerPos+=",left="+left;
			if(top>=0)centerPos+=",top="+top;
		}
		
		//build attributes
		if(isEmpty(atts))
		{
			atts="width="+width;
			atts+=",height="+height;
			if(center)atts+=centerPos;
			atts+=",resizable=1,status=1,menubar=0,scrollbars=1,fullscreen=0";
		}
		//insert default width, height and pos
		else
		{
			if(atts.toLowerCase().indexOf("width=")==-1)atts+=",width="+width;
			if(atts.toLowerCase().indexOf("height=")==-1)atts+=",height="+height;		
			if(center && atts.toLowerCase().indexOf("top=")==-1 
				&& atts.toLowerCase().indexOf("left=")==-1)atts+=centerPos;				
		}
		
		//add popup and random parameter to path
		path=enUtils.addQueryStringParam(path,"enaPopup","1");
		path=enUtils.addQueryStringParam(path,"enaRand",Math.random());

		//def target
		if(isEmpty(target))target="enDefaultTarget";

		//handle the case when the caller is a popup with name = target
		if(newIfExsists)
			if(window.name==target || window.top.name==target)target="_blank";
		try
		{
			if(this.openedPopup.name==target && this.attsPopup!=atts) 
			{
				this.openedPopup.close();
			}
		}
		catch(e){}
		
		this.attsPopup = atts ;		
		
		this.openedPopup=window.open(path,target,atts);
		this.openedPopup.focus();
		if(retWin)return this.openedPopup;
	}
	//expose
	this.openPopupWindow=openPopupWindow;
	
	/*
	check if the shiftKey is pressed and then 
	call to openPopupWindow
	*/	
	var openPopupWindowWithShift=function(e)
	{
		e=enUtils.evtGetCBEvent(e);	
		var currPath=e.currentTarget.getAttribute("href");
		var currWidth=e.currentTarget.getAttribute("enWidth");
		var currHeight=e.currentTarget.getAttribute("enHeight");
		var target=e.currentTarget.getAttribute("target");
		if(isEmpty(target)) target="enDefaultTarget"
		var currTarget=e.shiftKey?"_blank":target;	
		e.cancelEvent(false);
		openPopupWindow(currPath,currTarget,null,currWidth,currHeight)
	}
	//expose
	this.openPopupWindowWithShift=openPopupWindowWithShift;
		
	/*
	close window on escape
	how to use: enUtils.evtAddEvent(document,"keyup",enUtils.closeOnEsc);
	*/
	var closeOnEsc=function(e)
	{		
		//get event
		var e=evtGetCBEvent(e);
		//get ascii code
		if(e.keyCode==27)window.top.close();
	}
	this.closeOnEsc=closeOnEsc;
	
	//check if value tst is equal to value vals
	//or to any of the values in array vals[]
	var areValuesEqual=function(tst,vals){
		if(tst==null || vals==null)return false;
		if(vals.constructor==Array){
			for(var i=0;i<vals.length;i++){
				if(tst==vals[i])return true;
			}
		}else{
			return(tst==vals);
		}
		return false;
	}
	//expose
	this.areValuesEqual=areValuesEqual;
	
	/*
		set selected options is select element to
		one or more values in vals
		selected options are set as default selected - remain selected after for reset
		is slct allows multiple selection vals may be an array. else
		only first matching value is selected
		parameters:
			slct - a select element reference (or id)
			vals - a value or an array of values
		example:
			setSelectedOptions(document.forms['frmTest'].cboTest,'3');
			setSelectedOptions(document.forms['frmTest'].cboTest1,new Array('2','4'));
	*/
	var setSelectedOptions=function(slct,vals){
		//validation
		slct=objectOrGetId(slct);
		if(isEmpty(slct))return;
		if(slct.type.indexOf("select")==-1)return;
		if(vals==null)return;
		var opts=slct.options;
		//are multiple selection allowed?
		var multi=(slct.type=="select-multiple");
		//check each option
		for(var i=0;i<opts.length;i++){
			if(areValuesEqual(opts[i].value,vals)){
				opts[i].selected=true;
				opts[i].defaultSelected=true;
				if(!multi)return;
			}
		}
	}
	//expose
	this.setSelectedOptions=setSelectedOptions;	
	
	//set the title of the document
	var setPageTitle=function(title)
	{
		document.title=title;
	}
	//expose
	this.setPageTitle=setPageTitle;
	
	/*
		redirect to a given url - handle popup and hidden pages
		if popup - redirect opener and close popup
		if frame on a page  - redirect top
		params:
			url - redirect to
				special option:
				$reload$ - reload page
				$close$ - close all windows
			noRand - do not add random param (def false)
	*/
	var absoluteRedirect=function(url,noRand)
	{
		if(isEmpty(url))return;
		var rwin=null;
		var closeWin=url.toLowerCase()=="$close$";
		var reloadWin=url.toLowerCase()=="$reload$";
		//check if popup
		var owin=window.top.opener;
		if(!isEmpty(owin) && !owin.top.closed)
		{
			//get top of opener
			rwin=owin.top;
			try
			{
				//if opener changed url u get access denied exception..
				var execStr="";
				if(closeWin)execStr="window.close();";
				else if(reloadWin)execStr="window.location.reload();";
				else execStr="enUtils.setWinLocation(null,'"+url+"'"+ (noRand ? ",true" : "") +");";

				rwin.setTimeout(execStr,1000);
			}catch(e){}
			window.top.close();
		}
		else
		{
			rwin=window.top;
			//redirect / close
			if(closeWin)rwin.close();
			else if(reloadWin)rwin.location.reload();
			else setWinLocation(rwin,url,noRand);
		}
	}
	this.absoluteRedirect=absoluteRedirect;
	
	/*
		load the window with specific url
		params:
				win - window Object (if null use the current window)
				url - the url that will be ib the new window
				noRand - if add the random parameter to the url
	*/
	var setWinLocation=function(win,url,noRand)
	{
		var rwin=null;
		if(!isSet(win)) 
		{
			rwin=window;
		}	
		else
		{
			rwin=win	
		}	
		//add random param
		if(!noRand)url=enUtils.addQueryStringParam(url,"enaRand",Math.random());
		//redirect
		rwin.location.href=url;
	}
	this.setWinLocation=setWinLocation;
				
	/*
		get body object
		params:
				win - window Object (if null use the current window)
	*/
	var getBody=function(win)
	{
		if(isEmpty(win))win=window;
		var b=null;
		b=win.document.getElementsByTagName("BODY").item(0);
		if(isEmpty(b))b=document.body;
		return b;
	}
	this.getBody=getBody;
	
	/*
		set body style attribute
		params:
				win - window Object (if null use the current window)
				attrName - name of attribute
				attrVal - value to assign
	*/
	var setBodyStyle=function(win,attrName,attrVal)
	{
		//validation
		if(isEmpty(attrName) || isEmpty(attrVal))return;
		var bdy=getBody(win);
		if(!isEmpty(bdy))
		{
			try
			{
				eval("bdy.style."+attrName+"='"+attrVal+"'");
			}
			catch(e){}
		}
	}
	this.setBodyStyle=setBodyStyle;
	
	/*--------------------------------------------------------------------------------------
		DOM elemnets functions
	---------------------------------------------------------------------------------------*/
	//get object by id
	var objectOrGetId=function(oElement,type)
	{
		if(isEmpty(oElement))return null;
		type=ntz(type);
		if(typeof oElement!='object')
		{
			switch(type.toLowerCase())
			{
				//when we use names
				case "img":
					oElement=document.images[oElement];
					break;		
				case "form":
					oElement=document.forms[oElement];
					break;
				case "id":
				default:
					oElement=document.getElementById(oElement);
					break;				
			}
		}	
		return oElement;
	}
	this.objectOrGetId=objectOrGetId;
	
	//for a given table the function returns reference to its TBODY elemnt
	//	(even if no such tag in the HTML source)
	var getTableTbody=function(tbl)
	{
		tbl=objectOrGetId(tbl);
		//check for a table
		if(tbl.nodeName!="TABLE")return null;
		
		var tblChildCol=tbl.childNodes;
		var tblTbody=null;
		for(var i=0;i<tblChildCol.length;i++)
		{
			if(tblChildCol[i].nodeName=="TBODY")tblTbody=tblChildCol[i];
		}
		return tblTbody;
	}
	this.getTableTbody=getTableTbody;
	/*
	for a given element in a table gets returns a reference to the TR element.
	return the null if no tr is found
	*/
	var getElTr=function (el)
	{
		var tr=objectOrGetId(el);
		while(tr.nodeName!="TR")
		{
			tr=tr.parentNode;
			if(tr.nodeName=="BODY")return null;
		}
		return tr;
	}
	this.getElTr=getElTr;
	/*
	for a given element in a table gets returns a reference to the TABLE element.
	return the null if no tr is found
	*/
	var getElTable=function(el)
	{
		var table=objectOrGetId(el);
		while(table.nodeName!="TABLE")
		{
			table=table.parentNode;
			if(table.nodeName=="BODY")return null;
		}
		return table;
	}
	/*
		get window position and dimentions
		params:
			win - window to get (def current window)
		return:
			an object with thw following fields:
			obj.left
			obj.top
			obj.width
			obj.height
			obj.right
			obj.bottom
	*/
	var getWindowPos=function(win)
	{
		if(isEmpty(win))win=window;
		var out=new Object();
		/*
		ie 6.0 behaves differently in Back Compatability mode
		it uses documentElement instead of body
		*/
		var b=getBody(win);
		var compMode=getCompatMode(win);
		if(!isEmpty(compMode) && ntz(compMode).toLowerCase()!="backcompat")
			b=document.documentElement;
		out.left = (enBS.ie) ? b.scrollLeft   : win.pageXOffset;
		out.top = (enBS.ie) ? b.scrollTop    : win.pageYOffset;
		out.width = (enBS.ie) ? b.clientWidth  : win.innerWidth;
		out.height= (enBS.ie) ? b.clientHeight : win.innerHeight;
		out.right = (out.left + out.width);
		out.bottom = (out.top + out.height);
		return out;
	}
	this.getWindowPos=getWindowPos;
	
	/*
		get compatability mode
		works for ie 6 and up, others return null
		params:
			win - window to get (def current window)
	*/
	var getCompatMode=function(win)
	{
		if(isEmpty(win))win=window;
		var doc=win.document;
		var comp=null;
		if(isSet(doc.compatMode))comp=doc.compatMode;
		return comp;
	}
	this.getCompatMode=getCompatMode;
	/*
		returns an array of all the child nodes of an element filtered by a list of tagNames.
		params:
			el - The father element id or object.
			tagNamesList - a list of all tagNames
			sep - list separator  (default comma).
	*/
	var getElementsByTagsNames=function(el,tagNamesList,sep)
	{
		var els=new Array();
		//handle input paramrs
		el=objectOrGetId(el);
		if(isEmpty(sep))sep=",";
		if(isEmpty(tagNamesList))return els;
		var tags=separatedListToArray(tagNamesList,sep);

		var tmpCol=null;var i;var j;
		for(i=0;i<tags.length;i++)
		{
			tmpCol=el.getElementsByTagName(tags[i]);
			for(j=0;j<tmpCol.length;j++)
			{
				els[els.length]=tmpCol[j];
			}
		}
		return els;
		
	}
	this.getElementsByTagsNames=getElementsByTagsNames;
	/*--------------------------------------------------------------------------------------
		Cross browsers events functions
	---------------------------------------------------------------------------------------*/
	/*
	build a cross browser event object
	params:
		e - an event object
	returns:
			en object with cross browser properties
	REMARK: NS bug: donot try to read the cancelBubble property, after this you can't change it.
	*/
	var evtGetCBEvent=function (e)
	{
		//validate e
		e=e?e:window.event;
		//if(isEmpty(e)) return null;
		var evt=new Object();		
		evt.origEvent=e;
		//flag
		var winEvt=(window.event);
		//the same
		evt.type=e.type;
		evt.screenX=e.screenX;
		evt.screenY=e.screenY;
		evt.clientX=e.clientX;
		evt.clientY=e.clientY;
		evt.button=e.button;
		/*
			ascii code
			in NS it's different in keyup/down (keyCode) and keypress (charCode)
		*/
		evt.keyCode=e.keyCode;
		if(!winEvt && (!isInteger(evt.keyCode) || parseInt(evt.keyCode)==0))
			evt.keyCode=e.charCode;
		
		evt.altKey=e.altKey;
		evt.shiftKey=e.shiftKey;
		evt.ctrlKey=e.ctrlKey;
		
		//merged
		evt.target=winEvt?e.srcElement:e.target;
		evt.currentTarget=winEvt?e.srcElement:e.currentTarget;
		
		//help: Sets or retrieves the x/y-coordinate of the mouse pointer's position 
		//		relative to the object firing the event.
		var pos=elmntAbsPos(evt.target);
		evt.offsetX=winEvt?e.offsetX:(evt.clientX - pos.left);
		evt.offsetY=winEvt?e.offsetY:(evt.clientY - pos.top);
		//methods		
		evt.setCancelBubble=function(cancel)
		{
			evt.origEvent.cancelBubble=cancel;
		}
		//cancel event
		evt.cancelEvent=function()
		{
			if(!winEvt)
			{
				with(evt.origEvent)
				{
					if(cancelable)
					{
						preventDefault();
						stopPropagation();
					}
				}
			}
			else
			{
				evt.origEvent.returnValue=false;
			}
		}
		return evt;
	}
	this.evtGetCBEvent=evtGetCBEvent;
	
	/*
		attach event to element - cross browser
		params:
			el - an element reference
			type - event type (without 'on' prefix)
			fn - a function reference
			capture - capture or bubble - def false (only ns)
		return:
			true/false			
	*/
	var evtAddEvent=function (el,type,fn,capture)
	{
		//validation on el,type,fn
		if(isEmpty(el) || isEmpty(type) || isEmpty(fn))return false;
		el=objectOrGetId(el);
		if(el.addEventListener)
		{
			//default value for capture - false
			if(!isSet(capture)) capture=false;
			el.addEventListener(type,fn,capture);
			return true;			
		}
		else if(el.attachEvent)
		{
			return el.attachEvent('on'+type,fn);
		}
		else return false;		
	}
	this.evtAddEvent=evtAddEvent;
	
	/*
		remove event from element - cross browser
		params:
			el - an element reference
			type - event type (without 'on' prefix)
			fn - a function reference
			capture - capture or bubble (only ns)
		return:
			true/false
	*/
	var evtRemoveEvent=function (el,type,fn,cupture)
	{
		//validation on el,type,fn
		if(isEmpty(el) || isEmpty(type) || isEmpty(fn))return false;
		el=objectOrGetId(el);
		
		if(el.removeEventListener)
		{
			//default value for capture - false
			if(!isSet(capture)) capture=false;			
			el.removeEventListener(type,fn,capture);
			return true;			
		}
		else if(el.deattachEvent)
		{
			return el.deattachEvent('on'+type,fn);
		}
		else return false;		
	}
	this.evtRemoveEvent=evtRemoveEvent;
	
	/*
		attach event to elements by their tag name
		params:
			fn - function to attach
			evt - event
			tagName - tag name to filter by
			elementsContainer - container to search in (optional, defaulr document)			
			attrName - attribute to filter by
			attrValue - value of attribute
	*/
	var evtAddEventByTagName=function(fn,evt,tagName,elementsContainer,attrName,attrValue)
	{
		var elementsContainer=objectOrGetId(elementsContainer);
		if(isEmpty(elementsContainer))elementsContainer=document;
		//filter by tag name
		var itemsCollection=elementsContainer.getElementsByTagName(tagName);
		var el;
		//loop on elements
		for(var i=0;i<itemsCollection.length;i++)
		{
			//filter by attribute
			el=itemsCollection[i];
			if(isEmpty(attrName) || el.getAttribute(attrName)==attrValue)
			{
				enUtils.evtAddEvent(el,evt,fn);
			}
		}
	}
	//expose
	this.evtAddEventByTagName=evtAddEventByTagName;
	
	/*
		append event to an existing one
		params:
			evtName	- event name as string ("window.onload")
			fn		- fn to attach
			before	- optional, append fn before or after existing event (if any). def false.
		REM: deprecated - use evtAddEvent instead
	*/
	var appendEvent=function(evtName,fn,before){
		switch(evtName.toLowerCase()){
			case "window.onload":
				var oldFn=window.onload;
				if((typeof oldFn).toLowerCase()=="function"){
					if(before){
						window.onload=function(){
							fn();
							oldFn();			
						}
					}else{
						window.onload=function(){
							oldFn();
							fn();			
						}
					}
				}else{
					window.onload=fn;
				}
				break;
			case "window.onresize":
				var oldFn=window.onresize;
				if((typeof oldFn).toLowerCase()=="function"){
					if(before){
						window.onresize=function(){
							fn();
							oldFn();			
						}
					}else{
						window.onresize=function(){
							oldFn();
							fn();			
						}
					}
				}else{
					window.onresize=fn;
				}
				break;
			case "document.onkeyup":
				var oldFn=document.onkeyup;
				if((typeof oldFn).toLowerCase()=="function"){
					if(before){
						document.onkeyup=function(){
							fn();
							oldFn();			
						}
					}else{
						document.onkeyup=function(){
							oldFn();
							fn();			
						}
					}
				}else{
					document.onkeyup=fn;
				}
				break;				
		}
	}
	//expose
	this.appendEvent=appendEvent;
	
	
	/*---------------------------------------------------------------------------------------
		Gui functions
	---------------------------------------------------------------------------------------*/
	/*gets a tag like div,table or form and disables/enables all the controlls contained in it
		params:
		fatherElmnt: the container tag (the element itself:document.getElementById('elmntId')).
		attr: disabled, readOnly, display, visibility (this is case sensative)
		val: whatever this attribute may get (true,false,none,'' etc...
		isRecursive: whether to go over the children elements (def=true)
		*REMARKS*:	1) controlls are of type: input, select, textarea and button.
					2) readOnly property affects INPUT type="text/password" and TEXTAREA only.
	*/
	var elmntContetsChangeGui = function (fatherElmnt,attr,val,isRecursive)
	{
		if(!isSet(fatherElmnt))return;
		fatherElmnt=objectOrGetId(fatherElmnt);
		if(isEmpty(fatherElmnt))return;

		//default isRecursive
		if(enUtils.isEmpty(isRecursive))isRecursive=true;
		var myTagName=""
		var childsCol=fatherElmnt.childNodes;
		if(attr.toLowerCase()=="disabled")
		{
			fatherElmnt.disabled=val;
			if(isRecursive)
			{
				for (var i=0;i<childsCol.length;i++)
				{
					myTagName=childsCol[i].tagName;
					if(myTagName=="SELECT" || myTagName=="TEXTAREA" || myTagName=="BUTTON")childsCol[i].disabled=val;
					else if(childsCol[i].childNodes.length>0) elmntContetsChangeGui(childsCol[i],attr,val);
					else if(myTagName=="INPUT")	childsCol[i].disabled=val;
				}
			}
		}
		else if (attr.toLowerCase()=="readonly")
		{
			fatherElmnt.readOnly=val;
			if(isRecursive)
			{
				for (var i=0;i<childsCol.length;i++)
				{
					myTagName=childsCol[i].tagName;
					if(myTagName=="SELECT" || myTagName=="TEXTAREA" || myTagName=="BUTTON")childsCol[i].readOnly=val;
					else if(childsCol[i].childNodes.length>0) elmntContetsChangeGui(childsCol[i],attr,val);
					else if(myTagName=="INPUT")	childsCol[i].readOnly=val;
				}
			}
		}
		else if (attr.toLowerCase()=="display")
		{
			fatherElmnt.style.display=val;
			if(isRecursive)
			{
				for (var i=0;i<childsCol.length;i++)
				{
					myTagName=childsCol[i].tagName;
					if(myTagName=="SELECT" || myTagName=="TEXTAREA" || myTagName=="BUTTON")childsCol[i].style.display=val;
					else if(childsCol[i].childNodes.length>0) elmntContetsChangeGui(childsCol[i],attr,val);
					else if(myTagName=="INPUT")	childsCol[i].style.display=val;
				}
			}
		}
		else if (attr.toLowerCase()=="visibility")
		{
			fatherElmnt.style.visibility=val;
			if(isRecursive)
			{
				for (var i=0;i<childsCol.length;i++)
				{
					myTagName=childsCol[i].tagName;
					if(myTagName=="SELECT" || myTagName=="TEXTAREA" || myTagName=="BUTTON")childsCol[i].style.visibility=val;
					else if(childsCol[i].childNodes.length>0) elmntContetsChangeGui(childsCol[i],attr,val);
					else if(myTagName=="INPUT")	childsCol[i].style.visibility=val;
				}	
			}
		}
	}
	//expose
	this.elmntContetsChangeGui=elmntContetsChangeGui;		

	/*
		toggle class name of an element
		params:
			elmnt - element refrence or id
			restore - resore orig class (def false)
			newClassName - class name to assign
	*/
	var elmntToggleClass=function (elmnt,restore,newClassName)
	{
		elmnt = objectOrGetId(elmnt);
		if(isEmpty(elmnt))return;
		if(!isSet(restore))restore=false;		

		//switch (save last state first)
		var last=elmnt.enLastClassName;
		elmnt.enLastClassName=elmnt.className;
		if(restore)
		{
			elmnt.className=(isEmpty(last)?"":last);
		}
		else elmnt.className=newClassName;	
	}
	//expose
	this.elmntToggleClass=elmntToggleClass;
	
	/*
		toggles element's display style - shows or hides the element
		params:
			elmnt - element refrence or id
			show - optional show or hide flag (true (def) / false)
			hiddenClassName - optional class name to hide element (def 'hiddenEl')
	*/

	var elmntShowHide=function (elmnt,show,hiddenClassName)
	{
		elmnt = objectOrGetId(elmnt);
		if(isEmpty(elmnt))return;
		if(!isSet(hiddenClassName))hiddenClassName="hiddenEl";
		var currShown=(elmnt.className!=hiddenClassName);	
		if(!isSet(show))show=(!currShown);		
		if(show==currShown)return;
		
		elmntToggleClass(elmnt,show,hiddenClassName);
	}
	//expose
	this.elmntShowHide=elmntShowHide;

	/*
		toggles elements display by tag name and container
		used mainly to prevent elements from hiding floating divs (menus)
		params:
			show - optional show or hide flag (true (def) / false)
			elTags - element tags comma separated list, or an array (def select,object)
			container - optional container element (def document)
	*/
	var elmntShowHideAdvanced=function (show,elTags,container)
	{
		//default
		if(isEmpty(elTags))elTags=["select","object"];
		if(isEmpty(container))container=document;
		//loop on all tags
		if(!isArray(elTags))elTags=separatedListToArray(elTags);
		var els=null;
		for(var i=0;i<elTags.length;i++)
		{
			els=container.getElementsByTagName(elTags[i].toUpperCase());
			if(isEmpty(els))continue;
			for(var j=0;j<els.length;j++)
			{
				//if hidden when trying to hide - mark as always hidden
				if(!show && els[j].style.visibility=="hidden")
					els[j].enOrigHidden=true;
				else if(!els[j].enOrigHidden)
					els[j].style.visibility= show ? "visible" : "hidden";
			}
		}
	}
	//expose
	this.elmntShowHideAdvanced=elmntShowHideAdvanced;
	
	//is element visible (does not check parents)
	var elmntIsVisible=function(elmnt)
	{
		elmnt = objectOrGetId(elmnt);
		if(isEmpty(elmnt))return false;
		return (elmnt.className!="hiddenEl" && 
			elmnt.style.display!="none" && 
			elmnt.style.visibility!="hidden");
	}
	this.elmntIsVisible=elmntIsVisible;
	
	/*
		set preview image by an attribute in a select element
		params:
			slct - select element ot id
			attrName - name of attribute
			img - image element or id
			hideBlank - hide blank image (def true)
	*/
	var setPreviewImg=function(slct,attrName,img,hideBlank)
	{
		slct = objectOrGetId(slct);
		if(isEmpty(slct))return;
		if(slct.type.indexOf("select")==-1)return;
		img = objectOrGetId(img);
		if(isEmpty(img))return;
		if(!isSet(hideBlank))hideBlank=true;
		
		//inner function - clear image
		var clearImage=function()
		{
			var blankPath=getBaseUrl() + "Static/Images/blank.gif";
			img.src=blankPath;
			if(hideBlank)elmntShowHide(img,false);
		}
		
		//if no elements, or no attribute - clear image
		if(slct.selectedIndex==-1)
		{
			clearImage();
			return;
		}
		var imgPath = slct.options[slct.selectedIndex].getAttribute(attrName);
		if(isEmpty(imgPath))
		{
			clearImage();
		}
		else 
		{
			img.src = imgPath ;
			elmntShowHide(img,true);
		}
	}
	this.setPreviewImg=setPreviewImg;
	
	/*
		set the Z index proprty for an object
		params:
			elmnt: DOM element or id of element.
			zOrder: the value
	*/
	var setZIndex=function(elmnt, zOrder) 
	{
		elmnt=objectOrGetId(elmnt);
		if(isEmpty(elmnt))return;
		elmnt.style.zIndex = zOrder
	}
	this.setZIndex=setZIndex;
	
	//gets an element id and the width and height to give the elemenet (will be in pixels).
	//if ommitting the width & height: like display:none.
	var elmntResize = function (elmnt,width,height)
	{
		if(!isSet(elmnt))return;
		if(typeof elmnt!='object')fatherElmnt=document.getElementById(elmnt);
		if(!elmnt) return;
		if (!isSet(width)) width=0;
		if (!isSet(height)) height=0;
		elmnt.style.width=parseInt(width) + "px";
		elmnt.style.height=parseInt(height) + "px";
	}
	//expose
	this.elmntResize=elmntResize;
	//shift the element from its current locations by the givven params.
	var elmntShiftBy = function (elmnt,incX,incY)
	{
		if(!isSet(elmnt))return;
		if(typeof elmnt!='object')fatherElmnt=document.getElementById(elmnt);
		if(!elmnt) return;
		if (!isSet(incX)) incX=0;
		if (!isSet(incY)) incY=0;
		elmnt.style.left= parseInt(elmnt.style.left) + parseInt(incX) + "px";
		elmnt.style.top=  parseInt(elmnt.style.top) + parseInt(incY) + "px";
	}
	//expose
	this.elmntShiftBy=elmntShiftBy;
	
	//shift the element to a new location (relative to its container)
	//optional parameters: width & height
	var elmntMove = function (elmnt,posX,posY,width,height)
	{
		var elmnt=objectOrGetId(elmnt);
		if(!elmnt) return;
		if (!isSet(posX)) width="0";
		if (!isSet(posY)) height="0";
		elmnt.style.left=parseInt(posX) + "px";
		elmnt.style.top=parseInt(posY) + "px";
		if(isSet(width))elmnt.style.width=parseInt(width) + "px";
		if(isSet(height))elmnt.style.height=parseInt(height) + "px";
	}
	//expose
	this.elmntMove=elmntMove;
	
	/*
		get absolute posotion and size
		params:
			el - element or id
		returns:
			an object with thw following fields (in pixels):
				obj.left
				obj.top
				obj.width
				obj.height
				obj.right
				obj.bottom
	*/
	var elmntAbsPos=function (el)
	{
		//return an element absolute position
		var elmnt=objectOrGetId(el);
		if(!elmnt) return;
		var pos =new Object;
		//get width and height
		pos.width=elmnt.offsetWidth;
		pos.height=elmnt.offsetHeight;
		//get left and top
		pos.left = 0;
		pos.top = 0;
		/*
			ie 5.0 counts the body as well with the full win width...
			so we need to stop on body
		*/
		while(elmnt!=null && elmnt.nodeName!="BODY"){
			pos.left += elmnt.offsetLeft;
			pos.top += elmnt.offsetTop;
			elmnt=elmnt.offsetParent;
		}		
		//right and bottom
		pos.right = (pos.left + pos.width);
		pos.bottom = (pos.top + pos.height);
		return pos;
	}
	//expose
	this.elmntAbsPos=elmntAbsPos;
	
	//get actual height
	var elmntActualHeight=function(el)
	{
		el=objectOrGetId(el);
		return el.offsetHeight;
	}
	this.elmntActualHeight=elmntActualHeight;
	
	//get actual width
	var elmntActualWidth=function(el)
	{
		el=objectOrGetId(el);
		return el.offsetWidth;
	}
	this.elmntActualWidth=elmntActualWidth;

	/*
		backup element's child checkboxes and options values.
		goes with elmntRestoreChildChecks
		and used when dynamically switching elements in the document
		params:
			el - an element or element id
			attName - optional. attribute name to use for backuping values (def enBackupChildChecks)
		returns:
			an array holding checkbox and radio elements and their value
			the same value is set into the element's enBackupChildChecks property
	*/
	var elmntBackupChildChecks=function(el,attName)
	{
	 	//validate el
	 	if(isEmpty(el))return null;
	 	el=objectOrGetId(el);
	 	if(isEmpty(attName))attName="enBackupChildChecks";
	 	var bu=[];
	 	var counter=0;
	 	var els=el.getElementsByTagName("INPUT");
	 	for(var i=0;i<els.length;i++)
	 	{
		  	switch(els[i].type)
		  	{
		   		case "checkbox": case "radio":
		    		bu[counter]=[els[i],els[i].checked];
		    		counter++;
		  	} 
		 }
		 //save in element's attribute
		 el[attName]=bu;
		 return bu;
	}
	this.elmntBackupChildChecks=elmntBackupChildChecks;
	
	/*
		restore element's child checkboxes and options values
		params:
			el - an element or element id
			bu - an array holding checkbox and radio elements and their value (optional)
				if not passed - retrieved from the element's enBackupChildChecks property
			attName - optional. attribute name to use for restoring values (def enBackupChildChecks)
	*/ 	 		
	var elmntRestoreChildChecks=function(el,bu,attName)
	{
		 //validate el
		 if(isEmpty(el))return null;
		 el=objectOrGetId(el);
		 if(isEmpty(attName))attName="enBackupChildChecks";
		 if(!(!isEmpty(bu) && isArray(bu)))
		 {
		 	//restore from element
		 	bu=el[attName];
		 }
		 //validate bu
		 if(!(!isEmpty(bu) && isArray(bu)))return;
		 //assign values 
		 for(var i=0;i<bu.length;i++)
		 {
		  	bu[i][0].checked=bu[i][1];
		 }
	}
	this.elmntRestoreChildChecks=elmntRestoreChildChecks;
	
	/*
		select the first element in the document
		searches for the first form and first element that is not:
			select, button, hidden, disabled or redonly
		jumps over any form or element with a property of enNoAutoFocus=1
	*/
	var elmntSelectFirst=function()
	{
		try
		{
			//get first element in first form
			var frm=null;
			var el=null;
			var elType=null;
			//loop on all forms
			for(var f=0;f<document.forms.length;f++)
			{
				frm=document.forms[f];
				if(frm.getAttribute("enNoAutoFocus")!="1")
				{
					//search for the first visible and editable element
					for(var i=0;i<frm.elements.length;i++)
					{
						el=frm.elements[i];
						elType=el.type;
						//on textarea and text only
						if(!el.disabled && !el.readOnly 
							//&& "@hidden@button@submit@reset@".indexOf("@"+elType+"@")==-1
							//&& elType.indexOf("select")==-1
							&& "@text@textarea@".indexOf("@"+elType+"@")!=-1
							&& el.getAttribute("enNoAutoFocus")!="1")
						{
							elmntSelect(el);
							return;
						}
					}
				}
			}
		}catch(e){}
	}
	this.elmntSelectFirst=elmntSelectFirst;
	
	//select a given element
	var elmntSelect=function(el)
	{
		try
		{
			el=enUtils.objectOrGetId(el);
			el.focus();
			el.select();
		}catch(e){}
	}
	this.elmntSelect=elmntSelect;
	
	/*
		search for parent element by tag name
		params:
			item - item (or id) to start with
			tag - tag name to search for parent by
		returns - parent element or null, if none
	*/
	var elmntGetParentByTagName=function(item,tag)
	{
		item=objectOrGetId(item);
		if(isEmpty(item) || isEmpty(tag))return null;
		tag=tag.toLowerCase();
		while(!isEmpty(item))
		{
			if(item.nodeName.toLowerCase()==tag)return item;
			item=item.parentNode;
		}
		return null;
	}
	this.elmntGetParentByTagName=elmntGetParentByTagName;
	
	//remove element
	var elmntRemove=function(el)
	{
		el=objectOrGetId(el);
		try
		{
			el.parentNode.removeChild(el);
		}catch(e){}
	}
	this.elmntRemove=elmntRemove;
	
	/*
		scroll to the element so it's visible
		params:
			el - element or id
			relVer - vartical related position of the element on the screen:
				top - top of the element is at the top of the window (default)
				bottom - buttom of the element is at the buttom of the window
				center - center of the screen
			relHor - horizontal related position of the element on the screen:
				left - left of the element is at the left of the window (default)
				right - right of the element is at the right of the window
				center - center of the screen
	*/
	var elmntScrollIntoView=function(el,relVer,relHor)
	{
		el=objectOrGetId(el);
		if(isEmpty(el))return;
		relVer=ntz(relVer,"top");
		relVer=relVer.toLowerCase();
		relHor=ntz(relHor,"left");
		relHor=relHor.toLowerCase();
		var posLeft=0, posTop=0;
		//get element position
		var pos=elmntAbsPos(el);

		//get window dims
		var winPos=getWindowPos();
		
		
		/*
		alert("pos:\ntop:"+pos.top+"\nleft:"+pos.left+"\nwidth:"+pos.width+"\nheight:"+pos.height
			+"\nright:"+pos.right+"\nbottom:"+pos.bottom
			+"\n\nwindow:\ntop:"+winPos.top+"\nleft:"+winPos.left+"\nwidth:"+winPos.width
			+"\nheight:"+winPos.height+"\nright:"+winPos.right+"\nbottom:"+winPos.bottom);		
		*/
		
		
		//scrolling position
		//vertical
		switch(relVer)
		{
			case "bottom":
				//pos.bottom-winPos.height
				posTop=parseInt(pos.bottom)-parseInt(winPos.height);
				break;
			case "center":
				//0.5*(winPos.height-pos.height)
				posTop=0.5*(parseInt(winPos.height)-parseInt(pos.height));
				break;
			case "top":
			default:
				posTop=pos.top;		
		}
		//horizontal
		switch(relHor)
		{
			case "right":
				//pos.right-winPos.width
				posLeft=parseInt(pos.right)-parseInt(winPos.width);
				break;
			case "center":
				//0.5*(winPos.width-pos.width)
				posLeft=0.5*(parseInt(winPos.width)-parseInt(pos.width));
				break;
			case "left":
			default:
				posLeft=pos.left;
		}
		//defaults - focus top and left
		if(parseInt(posLeft)<0)posLeft=pos.left;
		if(parseInt(posTop)<0)posTop=pos.top;
		
		
		//alert(posLeft+":"+posTop);
		
		
		//scroll into view
		window.scrollTo(posLeft, posTop);
		//window.scrollBy(posLeft, posTop);
	}
	this.elmntScrollIntoView=elmntScrollIntoView;
	
	/*
		set element inner text
		params:
			el - element (or id)
			text - text to insert
	*/
	var elmntSetInnerText=function(el,text)
	{
		el=objectOrGetId(el);
		if(!isEmpty(el))
		{
			//remove all content
			var len=el.childNodes.length;
			for(var i=len-1;i>-1;i--)
			{
				el.removeChild(el.childNodes[i]);
			}
			//create and append new node
			el.appendChild(document.createTextNode(text));
		}		
	}	
	this.elmntSetInnerText=elmntSetInnerText;
	
	/*
		import elements between forms before submit
		params:
			frmSrc - source form or name
			frmTarget - target form or name
			types - an array of allowed types (def all)
		return: true/false
	*/
	var elmntImportForSubmit=function(frmSrc,frmTarget,types)
	{
		frmSrc=objectOrGetId(frmSrc,"form");
		frmTarget=objectOrGetId(frmTarget,"form");
		if(isEmpty(frmSrc) || isEmpty(frmTarget))return false;
		var alltypes=isEmpty(types);
		var el=null;
		var srcEl=null;
		var elsLen=frmSrc.elements.length;
		for(var i=0;i<elsLen;i++)
		{
			srcEl=frmSrc[i];
			//filter types
			if(alltypes || isInArray(srcEl.type,types))
			{
				el=srcEl.cloneNode(true);
				//handle select default value
				if(el.type=="select-one")
				{
					el.selectedIndex=srcEl.selectedIndex;
				}
				//checkbox needs special handling
				if(el.type=="checkbox")
				{
					el=document.createElement("INPUT");
					el.type="hidden";
					el.name= srcEl.name;
					el.value= srcEl.checked ? srcEl.value : "";
				}
				//hide control
				el.style.display="none";
				//append
				frmTarget.appendChild(el);
			}
		}
		return true;
	}	
	this.elmntImportForSubmit=elmntImportForSubmit;
	
	/*
		show and hide advanced options
		
		params:
			cmd - command button element or id
			flg - show / hide
			
		the cmd element should have the following attributes:
			enVisible - is advanced visible now? (1/0 optional)
			enRelatedEls - comma separated list of element ids to show/hide
			enTitle - the basic title to use (optional, def 'Advanced')
	*/
	var elmntToggleAdvancedOptions=function(cmd,flg)
	{
		//get advanced button
		var advancedEl=objectOrGetId(cmd);
		if(isEmpty(advancedEl))return;
		//check state
		var visible=toBoolean(advancedEl.getAttribute("enVisible"));
		//sync with flg
		if(!isSet(flg))flg=!visible;
		//show related elements
		var relatedElIds=advancedEl.getAttribute("enRelatedEls");
		if(isEmpty(relatedElIds))return;
		var relatedEls=relatedElIds.split(",");
		for(var i=0;i<relatedEls.length;i++)
		{
			elmntShowHide(relatedEls[i],flg);
		}
		//sync advancedEl
		advancedEl.setAttribute("enVisible",(flg?"1":"0"));
		//title
		var title=advancedEl.getAttribute("enTitle");
		if(isEmpty(title))title=enMsg.get("general.advanced");
		title+=flg ? " <<" : " >>";
		advancedEl.value=title;
	}
	this.elmntToggleAdvancedOptions=elmntToggleAdvancedOptions;
			
	/*--------------------------------------------------------------------------------------
		floating div
	---------------------------------------------------------------------------------------*/
	/*
	desc: The only function to be called from the page. positions & switches the divs visibillity.
	parameters:
		ifr: id or object of the iframe.
		elmnt: id or object is the relative object.
		ifrParams: an object with possible properties (will be passed to ifrHandleAttributes):
			position: Where to locate the floating div, relative to the element.
			shiftDir: Which direction, relative to the element, to shift the div to.
			shiftByPercent: the shift in px will be calcuting by percentage of the element dimentions
			ifrSrc: could be source file name or the html itself 
					(if ommited ifrHandleAttributes will do nothing)
			ifrWidth: width of the iframe
			ifrHeight: height of the iframe
			isSrcFile: true->ifrSrc is a file name, else ifrSrc will be written to the document
			appendToIfr: when true AND isSrcFile=false ifrSrc will be added to the document
			showHide:	 this willover ride the toggle functionality
			skipKeepInWin if true will not change location according to window(default=false)
	return value: none.
	*/
	var ifrShowFloatingIfr=function(ifr,elmnt,ifrParams)
	{
		var oIfr=objectOrGetId(ifr);
		//show or hide
		var sh=(isSet(ifrParams)&&isSet(ifrParams.showHide))?ifrParams.showHide:'';
		if(isEmpty(sh))
			sh=(isEmpty(oIfr) || isEmpty(oIfr.style) || oIfr.style.visibility=="hidden") ? 'show' : 'hide';
		
		if(sh=='hide' && !isEmpty(oIfr))
		{
			oIfr.style.visibility="hidden";
		}
		else
		{
			if(ifrParams && !ifrHandleAttributes(ifr,ifrParams))return;
			//if we just created the iframe get a holg of it again
			if(!oIfr) oIfr=objectOrGetId(ifr);
			if(!isSet(ifrParams))ifrParams=new Object;
			if(!elmnt) return;
			var ifrPos=ifrCalcFloatingPosotion(elmnt,ifr,ifrParams);
			oIfr.style.top	= ifrPos.top;
			oIfr.style.left = ifrPos.left;
			oIfr.style.visibility="visible";
		}
	}
	this.ifrShowFloatingIfr=ifrShowFloatingIfr;
	
	/*
	desc: claculates the ifr left & top values according to 
		  the elmnt positoin and the passed parameters.
	parameters:
		see function  ifrShowFloatingIfr parameters.
	return value: ifrPos(object with top,left properties)
	*/
	var ifrCalcFloatingPosotion=function(elmnt,ifr,ifrParams){
		//divPos.left/top/width/height
		var ifrPos=new Object;
		ifrPos.left=0;
		ifrPos.top=0;
		ifrPos.width=0;
		ifrPos.height=0;
		//check params
		if (isEmpty(elmnt) || isEmpty(ifr)) {
			//alert(enMsg.get("enUtils.noElements"))
			return ifrPos;
		}
		if(isEmpty(ifrParams.position))  ifrParams.position="right";
		if(isEmpty(ifrParams.shiftDir))  ifrParams.shiftDir="down";
		if(isEmpty(ifrParams.shiftByPercent))  ifrParams.shiftByPercent="0";
		
		var oElmnt=objectOrGetId(elmnt);
		//elmntPos.left/top/width/height
		var elmntPos=elmntAbsPos(oElmnt);
		var oDiv=objectOrGetId(ifr);
		ifrPos.width=oDiv.offsetWidth;
		ifrPos.height=oDiv.offsetHeight;
		//check for that for percent the value is a number
		if(!isNum(ifrParams.shiftByPercent)){
				//return defalts 0,0
				return ifrPos;
		}
		params=ifrParams.position.toLowerCase()+"@"+ifrParams.shiftDir.toLowerCase();
		ifrParams.shiftByPercent=parseFloat(ifrParams.shiftByPercent);			
		//calc div position
		switch(params)
		{
			case "bottom@right":
				ifrPos.left=elmntPos.left+ifrParams.shiftByPercent/100*elmntPos.width;
				ifrPos.top=elmntPos.top+elmntPos.height;
				break;
			case "bottom@left":
				ifrPos.left=elmntPos.left+(1-ifrParams.shiftByPercent/100)*elmntPos.width-ifrPos.width;
				ifrPos.top=elmntPos.top+elmntPos.height;
				break;
			case "top@right":
				ifrPos.left=elmntPos.left+ifrParams.shiftByPercent/100*elmntPos.width;
				ifrPos.top=elmntPos.top-ifrPos.height;
				break;
			case "top@left":
				ifrPos.left=elmntPos.left+(1-ifrParams.shiftByPercent/100)*elmntPos.width-ifrPos.width;
				ifrPos.top=elmntPos.top-ifrPos.height;
				break;
			case "right@down":
				ifrPos.left=elmntPos.left+elmntPos.width;
				ifrPos.top=elmntPos.top+ifrParams.shiftByPercent/100*elmntPos.height;
				break;
			case "right@up":
				ifrPos.left=elmntPos.left+elmntPos.width;
				ifrPos.top=elmntPos.top+(1-ifrParams.shiftByPercent/100)*elmntPos.height-ifrPos.height
				break;
			case "left@down":
				ifrPos.left=elmntPos.left-ifrPos.width;
				ifrPos.top=elmntPos.top+ifrParams.shiftByPercent/100*elmntPos.height;
				break;
			case "left@up":
				ifrPos.left=elmntPos.left-ifrPos.width;
				ifrPos.top=elmntPos.top+(1-ifrParams.shiftByPercent/100)*elmntPos.height-ifrPos.height;
				break;																					
			default:
				return ifrPos;
		}
		if(!ifrParams.skipKeepInWin)
		{
			ifrPos=ifrKeepInWindow(elmntPos,ifrPos);
		}
		return ifrPos;
	}	
	this.ifrCalcFloatingPosotion=ifrCalcFloatingPosotion;
	/*
	desc: checks the the ifr in the visible arae of the window, if not fixes the position.
	parameters:
		elmntPos: object with the elmnt height,width,left and top.
		ifrPos: object with the iframe height,width,left and top.
	return value: ifrPos(object with top,left properties)
	*/
	var ifrKeepInWindow=function (elmntPos,ifrPos){
		if(!elmntPos || !ifrPos) return;
		var winPos=getWindowPos();
		
		var WindowLeftEdge=winPos.left;
		var WindowTopEdge=winPos.top;
		var WindowWidth=winPos.width;
		var WindowHeight=winPos.height;
		var WindowRightEdge=winPos.right;
		var WindowBottomEdge=winPos.bottom;
		
		var divLeftEdge = ifrPos.left;
		var divRightEdge = divLeftEdge + ifrPos.width;
		var divTopEdge = ifrPos.top;
		var divBottomEdge = divTopEdge + ifrPos.height;
		
		var elmntLeftEdge=elmntPos.left;
		var elmntRightEdge = elmntLeftEdge + elmntPos.width;
		var elmntTopEdge = elmntPos.top;
		var elmntBottomEdge = elmntTopEdge + elmntPos.height;
		var out;
		if (divRightEdge > WindowRightEdge) {
			out=divLeftEdge-elmntRightEdge;
			if(out>=-1)
				ifrPos.left =elmntLeftEdge-ifrPos.width;
			else
				ifrPos.left =elmntLeftEdge-out-ifrPos.width
		}
		if (divLeftEdge < WindowLeftEdge) {
			out=elmntLeftEdge-divRightEdge;
			if(out>=-1)
				ifrPos.left =elmntRightEdge;
			else
				ifrPos.left =elmntRightEdge+out;
		} 
		if (divBottomEdge > WindowBottomEdge) {
			out=divTopEdge-elmntBottomEdge;
			if(out>=-1)
				ifrPos.top =elmntTopEdge-ifrPos.height;
			else
				ifrPos.top =elmntTopEdge-out-ifrPos.height;
		}
		if (divTopEdge<WindowTopEdge){
			out=elmntTopEdge-divBottomEdge;
			if(out>=-1)
				ifrPos.top =elmntBottomEdge;
			else
				ifrPos.top =elmntBottomEdge+out;
		}
		return ifrPos;
	}
	this.ifrKeepInWindow=ifrKeepInWindow;
	/*
	desc: 
		handle the ifr content by adding the src attribue(file) or writing into its output stream. 
		if it doesn't exist, tries to creats the iframe
	parameters:
		see function  ifrShowFloatingIfr parameters.
	return value: true/false
	*/
	var ifrHandleAttributes=function (ifr,ifrParams)
	{
		var retVal=false;
		var oIfr=objectOrGetId(ifr);
		//if there is no iframe call ifrCreate
		if (!oIfr)
		{
			//try to create it
			oIfr=ifrCreate(ifr);
			if(!oIfr) return retVal;

			//set floating menu attributes
			oIfr.style.position="absolute";
			oIfr.style.zIndex="5000";
			oIfr.setAttribute("frameborder","0");
			oIfr.style.visibility="hidden";
		}
		//handle attributes:
		oIfr.style.width=isNum(ifrParams.ifrWidth)?ifrParams.ifrWidth+"px":100+"px";
		oIfr.style.height=isNum(ifrParams.ifrHeight)?ifrParams.ifrHeight+"px":100+"px";
		
		//if no srcText the iframe exsist and has a source
		var ifrSrc=ifrParams.ifrSrc;
		if(isEmpty(ifrSrc))
		{
			retVal = true;
		}
		else
		{
			//for the src attribute we need to check if the iframe has a div container, and if so replace the two.
			oIfr=getIfrFromDiv(oIfr);
			//use src attribute or document.write
			if(ifrParams.isSrcFile)
			{
				document.getElementById(oIfr.id).src=ifrSrc;
				retVal=true;
			}
			else
			{
				var wincol=window.frames;
				for(var i=0;i<wincol.length;i++)
				{
					if(wincol[i].name==oIfr.name)
					{
						var ifrDoc=wincol[i].document;
						if(!ifrParams.appendToIfr)
						{
							ifrDoc.open();
							ifrDoc.write(ifrSrc);
							ifrDoc.close();
						}
						else ifrDoc.write(ifrSrc);
						retVal=true;
					}
				}
			}
		}
		return retVal;
	}
	this.ifrHandleAttributes=ifrHandleAttributes;
	/*
		for the floatong iframes that have a div container,
		all the src actions will be done on the iframe abd not the container.
		if no match (not a DIV container OR no iframe child found) returns the divEl
	*/
	var getIfrFromDiv=function (divEl)
	{
		var ifr=divEl;
		if(divEl.tagName=="DIV")
		{
			var divChilds=divEl.childNodes;
			for(i=0;i<divChilds.length;i++)
			{
				if(divChilds[i].tagName=="IFRAME")
				{
					ifr=divChilds[i];
					break;
				}
			}
		}
		return ifr;
	}
	this.getIfrFromDiv=getIfrFromDiv;
	/*
	---		WORKS IN IE5.5 up ONLY	   ---
	desc: client side iframe creation
	parameters:
		ifrIdName: string that will be the name & id of the iframe
	return value: iframe object
	*/
	var ifrCreate=function (ifrIdName)
	{
		var oIfr=null;
		//try to create. does not work on all browsers
		try
		{
			//extract ifrParams
			oIfr=document.createElement("<iframe name="+ifrIdName+"></iframe>");
			oIfr.setAttribute("id",ifrIdName);
			oIfr.setAttribute("frameborder","0");
			oIfr.setAttribute("scrolling","no");
			oIfr.setAttribute("style","visibility:hidden;position:absolute;z-index:50001;width:0px;height:0px");
	
			//append to end of document		
			document.getElementsByTagName("BODY").item(0).appendChild(oIfr);
		}
		catch(e){}
		return oIfr;
	}
	this.ifrCreate=ifrCreate;
	
	/*---------------------------------------------------------------------------------------
		Array functions
	---------------------------------------------------------------------------------------*/
	//is item exist in array
	var isInArray=function (val,arr)
	{
	    if(isEmpty(val) || isEmpty(arr))return false;
		for(var i=0;i<arr.length;i++)
		{
			if(val==arr[i])return true;
		}
		return false;
	}
	//expose
	this.isInArray=isInArray;
	
	//double one dimension array into two dimension array
	//ex: arr{item1,item2,...}-->>arr{{item1,item1},{item2,item2},...}
	var doubleArray=function (arr){
		var dblArr=new Array(arr.length);
		for(var i=0;i<arr.length;i++)
		{
			var tmp=new Array(2)
			tmp[0]=arr[i];
			tmp[1]=arr[i];
			dblArr[i]=tmp;
		}
		return dblArr;
	}
	//expose
	this.doubleArray=doubleArray;
	
	/*---------------------------------------------------------------------------------------
		date functions
	---------------------------------------------------------------------------------------*/
	/*
		get a date object from date elements (yy, mm, dd, ..)
		params:
			frm - form or form name
			elBaseName - base name of element
		return a date objevt, or null
	*/
	var getDateFromElements=function(frm,elBaseName)
	{
		frm=objectOrGetId(frm,"form");
		if(isEmpty(frm))return null;
		var getDatePart=function(suffix)
		{
			var elName=elBaseName+suffix;
			var el=frm.elements[elName];
			if(!isEmpty(el))return getValueOf(el);
		}
		//get date parts
		var yy=ntz(getDatePart("_YY"),0);
		var mm=ntz(getDatePart("_MM"),0);
		var dd=ntz(getDatePart("_DD"),0);
		var hh=ntz(getDatePart("_HO"),0);
		var mi=ntz(getDatePart("_MI"),0);
		var se=ntz(getDatePart("_SE"),0);
		if(yy+mm+dd+hh+mi+se==0)
		{
			return null;
		}
		else
		{
			if(mm>0)mm--;
			return new Date(yy,mm,dd,hh,mi,se);
		}
	}
	this.getDateFromElements=getDateFromElements;
	/*
		formats a date according to custom/default pattern.
		supprted formats:
			date:	dd-MMMM-yyyy; MMMM dd,yyyy; yyyy-MM-dd;
					dd-MM-yyyy; MM-dd-yyyy; dd/MM/yyyy; MM/dd/yyyy; 
			time:	h:mm:ss; hh:mm:ss; h:mm:ss a; hh:mm:ss a; H:mm:ss; HH:mm:ss;
					*where h:1-12; H:0-23;hh/HH: leading zero;a: AM/PM 
		params:
			date		js date object.
			dataType	number that represent datetime(6),date(11), time(12)
			format		date format pattern
			timeFormat	time format pattern
	*/
	var formatAsDateTime=function(date,dataType,format,timeFormat)
	{
		//inner function for leading zero foramt
		var padZero=function(num)
		{
			return ((num <= 9) ? ("0" + num) : num);
		}
		var retVal="";
		//handle parameters
		if(!date.getTime)return retVal;
		if(dataType!=6 && dataType!=11 && dataType!=12)dataType=6;
		format=ntz(format,"MMMM dd,yyyy");
		timeFormat=ntz(timeFormat,"HH:mm:ss")
		//parse the date
		var year = date.getFullYear();
		var month =  padZero(date.getMonth()+1);
		var day  = padZero(date.getDate());
		var hour=date.getHours();
		var minute=padZero(date.getMinutes());
		var second=padZero(date.getSeconds());
		//handle dates
		var formatedDate="";
		if(dataType==6 || dataType==11)
		{
			switch (format)
			{
				case "dd-MMMM-yyyy":
				{
					formatedDate=day+"-"+enMsg.get("enCalendar.months."+(date.getMonth()+1))+"-"+year;
					break;
				}
				case "MMMM dd,yyyy":
				{
					formatedDate=enMsg.get("enCalendar.months."+(date.getMonth()+1))+" "+day+","+year;
					break;
				}
				case "yyyy-MM-dd":
				{
					formatedDate=year+"-"+month+"-"+day;
					break;
				}
				case "dd-MM-yyyy":
				{
					formatedDate=day+"-"+month+"-"+year;
					break;
				}
				case "MM-dd-yyyy":
				{
					formatedDate=month+"-"+day+"-"+year;
					break;
				}
				
				case "dd/MM/yyyy":
				{
					formatedDate=day+"/"+month+"/"+year;
					break;
				}
				case "MM/dd/yyyy":
				{
					formatedDate=month+"/"+day+"/"+year;
					break;
				}
			}
		}
		//handle time
		var formatedTime="";
		var a=null;
		if(dataType==6 || dataType==12)
		{
			switch (timeFormat)
			{
				case "h:mm:ss":
				{
					if(hour>12)
						hour=hour-12;
					formatedTime=hour+":"+minute+":"+second;
					break;
				}
				case "hh:mm:ss":
				{
					if(hour>12)
						hour=hour-12;
					formatedTime=padZero(hour)+":"+minute+":"+second;
					break;
				}
				case "h:mm:ss a":
				{
					hour=(hour>12)?hour-12:hour;
					a=(hour>=12)?enMsg.get("enCalendar.pm"):enMsg.get("enCalendar.am")
					formatedTime=hour+":"+minute+":"+second+" "+a;
					break;
				}
				case "hh:mm:ss a":
				{
					hour=(hour>12)?hour-12:hour;
					a=(hour>=12)?enMsg.get("enCalendar.pm"):enMsg.get("enCalendar.am")
					formatedTime=padZero(hour)+":"+minute+":"+second+" "+a;
					break;
				}
				case "H:mm:ss":
				{
					formatedTime=hour+":"+minute+":"+second;
					break;
				}
				
				case "HH:mm:ss":
				{
					formatedTime=padZero(hour)+":"+minute+":"+second;
					break;
				}
			}
		}
		switch(dataType)
		{
			case 6: retVal=formatedDate+" "+formatedTime;break;
			case 11: retVal=formatedDate;break;
			case 12: retVal=formatedTime;break;
		}
		return retVal;
	}
	this.formatAsDateTime=formatAsDateTime;
	/*---------------------------------------------------------------------------------------
		query string
	---------------------------------------------------------------------------------------*/

	//add query string parameter to path
	var addQueryStringParam=function(path,prmName,prmVal)
	{
		//validation
		if(isEmpty(path) || isEmpty(prmName))return path;
		prmVal=ntz(prmVal);
		prmName=safeEscape(prmName);
		prmVal=safeEscape(prmVal);
		
		//check if parameter is in the path or no query string
		if(path.indexOf("?"+prmName+"=")==-1 && path.indexOf("&"+prmName+"=")==-1)
		{
			return addQueryStringParamToEnd(path,prmName+"="+prmVal);
		}
		//if param is in the string - remove it
		else
		{
			var posQ=path.indexOf("?");
			var qs=path.substring(posQ+1);
			path=path.substring(0,posQ);
			var prs=qs.split("&");
			var pr;
			var newQs="";
			for(var i=0;i<prs.length;i++){
				pr=prs[i].split("=");
				if(pr[0]==prmName)newQs+="&"+prmName+"="+prmVal;
				else newQs+="&"+prs[i];
			}
			return addQueryStringParamToEnd(path,newQs);
		}
	}
	this.addQueryStringParam=addQueryStringParam;
	
	//append param value pair to end of path
	var addQueryStringParamToEnd=function(path,prmAndVal)
	{
		//validation
		if(isEmpty(path) || isEmpty(prmAndVal))return path;
		
		var bfr=path.substring(path.length-1);
		//has ?
		var hasQ=(path.indexOf("?")!=-1);

		if(hasQ)bfr="&";
		else bfr="?";
		var out=path+bfr+prmAndVal;
		out=out.replace(/&+/g,"&");
		out=out.replace(/\?&+/g,"?");
		out=out.replace(/\?+/g,"?");
		return out;
	}
	this.addQueryStringParamToEnd=addQueryStringParamToEnd;
	
	//get query string on client side
	var getQueryString=function(fname){
		var qs;
		if(document.layers && !isEmpty(fname)){
			if(!isSet(fname))return "";
			if(!document.layers[fname])return "";
			qs=document.layers[fname].src;
		}else{
			qs=window.location.href;
		}
		var pos=qs.indexOf("?");
		if(pos==-1 || pos==qs.length){
			return "";
		}else{
			return qs.substring(pos+1);
		}
	}
	this.getQueryString=getQueryString;
	
	//parse a specific query string parameter on the client side
	//u may need to add unescape somewhere ...
	var getQueryStringParam=function(pname,qs,fname){
		if(!isSet(qs))qs=getQueryString(fname);
		var prs=qs.split("&");
		var pr;
		for(var i=0;i<prs.length;i++){
			pr=prs[i].split("=");
			if(pr[0]==pname)return pr[1];
		}
		return null;
	}
	this.getQueryStringParam=getQueryStringParam;
	
	/*
		get base url (application root)
		params:
			win - window to examine. optional. if ommited gets the current window
	*/
	var getBaseUrl=function(win)
	{
		if(isEmpty(win))win=window;
		if(isEmpty(win.enApplication))return "../";
		return win.enApplication.getBaseUrl();
	}
	this.getBaseUrl=getBaseUrl;
	
	/*
	    isJavascriptUrl     is javascript url?
		params:
			url - url to check
	*/
	var isJavascriptUrl=function(url)
	{
		return(ntz(url).toLowerCase().indexOf("javascript:")==0);
	}
	this.isJavascriptUrl=isJavascriptUrl;

	/*
		get the folder from the url
		params:
			url - url to parse
		return - the folder part
		example - folder1/folder2/file.jsp?querystring -> folder1/folder2
	*/
	var getFolderFromUrl=function(url)
	{
		if(!isSet(url))return "";
		//find '?' if any
		var pos=url.indexOf("?");
		if(pos!=-1)url=url.substring(0,pos);
		pos=url.lastIndexOf("/");
		if(pos!=-1)url=url.substring(0,pos);
		return url;
	}
	this.getFolderFromUrl=getFolderFromUrl;

	/*
		get the file from the url
		params:
			url - url to parse
		return - the file part
		example - folder1/folder2/file.jsp?querystring -> file.jsp
	*/
	var getFileFromUrl=function(url)
	{
		if(!isSet(url))return "";
		//find '?' if any
		var pos=url.indexOf("?");
		if(pos!=-1)url=url.substring(0,pos);
		pos=url.lastIndexOf("/");
		if(pos!=-1)url=url.substring(pos+1);
		return url;
	}
	this.getFileFromUrl=getFileFromUrl;

	//convert qry string into a 2 dimention array (decode values)
	var qryStringToArray=function(qs)
	{
		if(isEmpty(qs))return null;
		//break by '&'
		var pairs=qs.split("&");
		var pair,o=new Array();		
		var length = pairs.length;
		if(length>0)
		{	
			for (var i=0;i<length;i++)
			{
				o[i]=new Array();
				//break by '='
				pair = pairs[i].split("=");
				for(var j=0;j<2;j++)
				{
					o[i][j] = unescape(pair[j]);
					o[i][j] = unescape(pair[j]);
				}
			}		
		}
		return o;
	}
	this.qryStringToArray=qryStringToArray;
  
  	//convert a 2 dimention array to a query string (encodes values)
	var qryStringFromArray=function(ary)
  	{
		if(isEmpty(ary))return null;
		var o="";
		var len=ary.length;
		for(var i=0;i<len;i++)
		{
			o+=escape(ary[i][0]);
			o+="=";
			o+=escape(ary[i][1]);
			if(i+1<len)o+="&";
	   	}
	   	return o;
  	}
	this.qryStringFromArray=qryStringFromArray;
	
	//convert a separated list into a 1 dimention array
	// default seperator: comma
  	var separatedListToArray=function(sl,sep)
	{
		if(isEmpty(sl))return null;
		//default seperator
		if(isEmpty(sep)) sep=",";
    	//break by sep
    	var items=sl.split(sep);
    	var o=new Array();
    	var length = items.length;
		for (var i=0;i<length;i++)
    	{
			o[i]=items[i];
    	}
    	return o;
  	}	
	this.separatedListToArray=separatedListToArray;

	//convert a 1 dimention array into a separated list
	// default seperator: comma
	var separatedListFromArray=function(ary,sep)
  	{
	    if(isEmpty(ary))return null;
		//default seperator
		if(isEmpty(sep)) sep=",";
	    var o="";
	    var len=ary.length;
	    for(var i=0;i<len;i++)
	    {
      		o+=ary[i];
      		if(i+1<len)o+=sep;
    	}
    	return o;
 	}
	this.separatedListFromArray=separatedListFromArray;

	/*---------------------------------------------------------------------------------------
		executing in hidden frame
	---------------------------------------------------------------------------------------*/
	
	/*
		run async exec and flag the object if passed
		params:
			fname - iframe name
			path - path to open
			flagObj - object to flag
			checkAsync - check if already running (needs flagObj, def true)
	*/
	var execAsync=function(fname,path,flagObj,checkAsync)
	{
		if(fname==null || path==null)return;
		if(!isSet(checkAsync))checkAsync=true;
		//add random and hidden parameter to path
		path=enUtils.addQueryStringParam(path,"enaHidden","1");
		path=addQueryStringParam(path,"enRand",Math.random());
		//set an async flag
		if(!isEmpty(flagObj))
		{
			if(checkAsync)
			{
				if(isExecAsync(flagObj))return;
			}
			else flagFormAsync(flagObj);
		}
		//exec
		if(document.layers)
		{
			document.layers[fname].src=path;
		}
		else
		{
			//make sure it's loaded
			var f=document.getElementById(fname);
			if(f)window.open(path,fname);
		}
	}
	this.execAsync=execAsync;
	
	/*
		run async exec and flag the form if passed - n hidden frame in a frameset
		params:
			fname - frame name
			path - path to open
			flagObj - object to flag
			checkAsync - check if already running (needs flagObj, def true)
	*/
	var execAsyncFrame=function(fname,path,flagObj,checkAsync){
		if(fname==null || path==null)return;
		//add random and hidden parameter to path
		path=enUtils.addQueryStringParam(path,"enaHidden","1");
		path=addQueryStringParam(path,"enRand",Math.random());
		//set an async flag
		if(!isEmpty(flagObj))
		{	
			if(checkAsync)
			{
				if(isExecAsync(flagObj))return;
			}
			else flagFormAsync(flagObj);
		}
		//exec
		parent.frames[fname].location.href=path;
	}
	this.execAsyncFrame=execAsyncFrame;

	// runs the callback function. called from the hidden frame
	var callbackAsync=function(win,fnname,cbprm){
		if(!isSet(fnname) || !isSet(win))return;
		var fn=eval("win."+fnname);
		//if a function - run it
		if(typeof fn=="function")fn(cbprm);
	}
	this.callbackAsync=callbackAsync;

	//called from container page: clear iframe location - refresh would run it again
	var clearIFrameSrc=function(fname){
		if(!document.layers)
		{
			//make sure it's loaded
			var f=document.getElementById(fname);
			if(f)window.frames[fname].location.href="about:blank";
		}
	}
	this.clearIFrameSrc=clearIFrameSrc;
	
	//called from frame: clear iframe location - refresh would run it again
	var clearCurrFrameSrc=function(){
		if(!document.layers)
		{
			window.location.href="about:blank";
		}													
	}
	this.clearCurrFrameSrc=clearCurrFrameSrc;

	/*
		flag async execution
		assignes 'enAsyncExecution' property to the flagObj passed
		params:
			flagObj - object to flag, id or object ref
				may use '$window$' and '$document$' as well
			flag - 	flag or lowwer the flag (def true)
			useProgress - show progress bar (def enApplication.global.useProgressBar)
			disableButton - disable buttons while executing (def enApplication.global.disableButtonOnExecute)
	*/
	var flagFormAsync=function(flagObj,flag,useProgress,disableButton)
	{
		//ref flagObj
		if(flagObj.toLowerCase)
		{
			switch(flagObj.toLowerCase())
			{
				case "$window$":
					flagObj=window;
					break;
				case "$document$":
					flagObj=document;
					break;
				default:
					flagObj=objectOrGetId(flagObj);
			}
		}
		if(!isSet(flag))flag=true;		
		flag=(flag?1:0);
		if(flagObj)
		{
			//inc or zero async count
			if(isEmpty(flagObj.enAsyncExecution) || flag==0)
			{
				//handle progress bar
				if(!isSet(useProgress))
					useProgress=isSet(enApplication) && enApplication.global.useProgressBar;
				if(useProgress && isSet(enApplication))
				{
					if(flag==0)enApplication.hideProgressaBar();
					else if(isEmpty(flagObj.enAsyncExecution))
						enApplication.showProgressaBar();
				}
				//handle disable buttons
				if(!isSet(disableButton))
					disableButton=isSet(enApplication) && enApplication.global.disableButtonOnExecute;
				if(disableButton && isSet(enApplication))
				{
					if(flag==0)enApplication.toggleDisableButtonList(false);
					else if(isEmpty(flagObj.enAsyncExecution))
						enApplication.toggleDisableButtonList(true);
				}
				//assign flag
				flagObj.enAsyncExecution=flag?1:null;
			}
			else flagObj.enAsyncExecution++;
		}
	}
	this.flagFormAsync=flagFormAsync;
	
	/*
		check if there is an async execution running
		params:
			flagObj - object to check, id or object ref
				may use '$window$' and '$document$' as well
			silent - alert the user or not (def false)
			msg - alternative msg to use
			trials - no of trials before allowing to discard the current execution
			dontflag - do not flag flagObj if not flaged (def false)
				between trials flagFormAsync() is called to inc the trialds count
				if flagObj is not flaged flagFormAsync() is called to flag it,
				unless dontflag is true
	*/
	var isExecAsync=function(flagObj,silent,msg,trials,dontflag)
	{
		//if object is empty then it is not executing
		if(isEmpty(flagObj))return false;
		//ref flagObj
		if(flagObj.toLowerCase)
		{
			switch(flagObj.toLowerCase())
			{
				case "$window$":
					flagObj=window;
					break;
				case "$document$":
					flagObj=document;
					break;
				default:
					flagObj=objectOrGetId(flagObj);
			}
		}
		//no of trials before allowing resubmit
		if(!isInteger(trials))trials=3;
		//custom msg
		if(!msg)msg=enMsg.get("enUtils.currProccess");
		var ret=false;
		
		//if object is empty then it is not executing
		if(isEmpty(flagObj))return false;
		if(flagObj.enAsyncExecution>0 && flagObj.enAsyncExecution<trials)
		{
			if(!silent) alert(enMsg.get("enUtils.currProccess")); //alert(msg); 
			ret=true;
		}		
		else if(flagObj.enAsyncExecution>=trials)
		{
			if(!silent)
			{
				if(confirm(msg+enMsg.get("enUtils.reProccess")))
				{
					//clear the flag
					flagFormAsync(flagObj,false);
				}
				else
				{
					ret=true;
				}
			}
		}

		//flag / inc the flag on flagObj
		if(!dontflag)flagFormAsync(flagObj);
		return ret;
	}
	this.isExecAsync=isExecAsync;
	
	/*
		run async exec on combo change
		params:
			fname - iframe name
			path - path to open
			flagObj - object to flag
			checkAsync - check if already running (needs flagObj, def true)
			cbo - selected filter type (combo box)
			paramName - request param to append
			cellId - cell id to reload. if ommited, the page is reloaded
	*/
	var execAsyncOnComboChange=function (fname,path,flagObj,checkAsync,cbo,paramName)
	{
		if(isEmpty(fname)||isEmpty(cbo)||isEmpty(path)||isEmpty(paramName))return;
		if(cbo.options.selectedIndex==-1)return;
		//add param value
		path=enUtils.addQueryStringParam(path,paramName,getValueOf(cbo));
		execAsync(fname,path,flagObj,checkAsync);
	}
	this.execAsyncOnComboChange=execAsyncOnComboChange;
				
	//returns the parent window
	//asuming we are in a ifraem or ilayer and called from the parent window
	var getParentWin=function(){
		return document.layers?window:window.parent;
	}
	this.getParentWin=getParentWin;
	
	/*
		a general purpos call back function
		handles a prm object (all props are optional):
			prm.status		- success/ fail - boolean
			prm.closeWin		- close the window(usefull in popups) - boolean
			prm.closeAbs		- close all windows absolute (boolean)
			
			prm.reload		- reload window location - boolean
			prm.reloadOpener	- reload opener window location - boolean
			prm.reloadAbs	- reload window ablolutly - boolean
			
			prm.cbflag		- id of object that holds the flag.
				if flag is on window or document, just path '$window$' or '$document$'
			
			prm.successUrl	- redirect on success (when reload is false)
			prm.errUrl		- redirect on fail (when reload is false)
			prm.absUrl		- redirect ablolutly - boolean
			
			prm.successMsg	- msg on success
			prm.errMsg		- msg on fail
			
			prm.delRow		- id of element to delete (or a coma separated list)
			prm.reassignClassOdd - odd row class name - used when ressigning classes after client side delete
			prm.reassignClassEvan - even row class name - used when ressigning classes after client side delete
			
			prm.scriptSuccess - script to run when success
			prm.scriptFail - script to run when fails
			prm.reloadCellId - reload cell on the opener.top, or top, if no opener (on success)
			prm.reloadCellsZone - same, by zone name (@ delimited list of zone names)
			prm.reloadCellComponent - same, by component name (@ delimited list of component names)
		
		how to use:
			if u need to lowwer the flag, write your function on your page:
			function myCallBack(prm)
			{
				//lowwer the flag
				enUtils.flagFormAsync(myForm/window,false);
				enUtils.defaultCallBack(prm);
			}
			and pass request parameter cbfn=myCallBack
			else, pass request parameter cbfn=enUtils.defaultCallBack
	*/
	var defaultCallBack=function(prm)
	{
		//lower flag
		if(!isEmpty(prm.cbflag))
		{
			var flgObj=null;
			switch(prm.cbflag.toLowerCase())
			{
				case "$window$":
					flgObj=window;
					break;
				case "$document$":
					flgObj=document;
					break;
				default:
					flgObj=objectOrGetId(prm.cbflag);
			}
			//lower the flag
			if(!isEmpty(flgObj))flagFormAsync(flgObj,false);
		}
		
		//msg to user and redirection
		if(prm.status)
		{
			if(!isEmpty(prm.delRow))
			{
				//loop on all ids and remove them
				var ids=unescape(prm.delRow).split(",");				
				var row;
				//containing table
				var tbl;
				for(var i=0;i<ids.length;i++)
				{
					row=objectOrGetId(ids[i]);
					if(isEmpty(tbl))tbl=elmntGetParentByTagName(row,"TABLE");
					if(!isEmpty(row))row.parentNode.removeChild(row);
				}		
				//reassign table rows
				tblReassignRowsClass(tbl,prm.reassignClassOdd,prm.reassignClassEvan);
			}
			if(!isEmpty(prm.successMsg))alert(prm.successMsg);
			if(!prm.reload && !prm.reloadAbs && !isEmpty(prm.successUrl))
			{
				//handle javascript urls
				if(isJavascriptUrl(prm.successUrl))
				{
					try
					{
						eval(prm.successUrl);
					}catch(e){}
				}
				else
				{
					if(prm.absUrl)absoluteRedirect(prm.successUrl);
					else setWinLocation(window,prm.successUrl);
				}
			}
			
			//reload cells
			if(!isEmpty(ntz(prm.reloadCellId)+ntz(prm.reloadCellsZone)+ntz(prm.reloadCellComponent)))
			{
				//locate the base window to reload cells in (stop when has enApplication.global.isHomePage)
				var baseWin=null;
				if(window.top.opener && !(window.top.enApplication && window.top.enApplication.global.isHomePage))
					baseWin=window.top.opener.top;
				else baseWin=window.top;
				//if reload runs in the same iframe - need a delay
				var useDelay=(baseWin==window);
				
				if(!isEmpty(prm.reloadCellId) && isInteger(prm.reloadCellId))
				{
					if(useDelay)
						baseWin.setTimeout("enApplication.reloadCell("+prm.reloadCellId+",true);",parseInt(Math.random()*50));
					else if(isSet(baseWin.enApplication))
						baseWin.enApplication.reloadCell(prm.reloadCellId,true);
				}
				if(!isEmpty(prm.reloadCellsZone))
				{
					if(useDelay)
						baseWin.setTimeout("enApplication.reloadCell(enApplication.getCellsByZone('"+prm.reloadCellsZone+"'),true);",parseInt(Math.random()*50));
					else if(isSet(baseWin.enApplication))
						baseWin.enApplication.reloadCell(baseWin.enApplication.getCellsByZone(prm.reloadCellsZone),true);
				}
				if(!isEmpty(prm.reloadCellComponent))
				{
					if(useDelay)
						baseWin.setTimeout("enApplication.reloadCell(enApplication.getCellsByComponent('"+prm.reloadCellComponent+"'),true);",parseInt(Math.random()*50));
					else if(isSet(baseWin.enApplication))
						baseWin.enApplication.reloadCell(baseWin.enApplication.getCellsByComponent(prm.reloadCellComponent),true);
				}
			}
			//eval script
			try
			{
				eval(prm.scriptSuccess);
			}
			catch(e){}
		}
		else
		{
			if(!isEmpty(prm.errMsg))alert(prm.errMsg);
			if(!prm.reload && !prm.reloadAbs && !isEmpty(prm.errUrl))
			{
				//handle javascript urls
				if(isJavascriptUrl(prm.errUrl))
				{
					try
					{
						eval(prm.errUrl);
					}catch(e){}
				}
				else
				{
					if(prm.absUrl)absoluteRedirect(prm.errUrl);
					else setWinLocation(window,prm.errUrl);
				}
			}
			//eval script
			try
			{
				eval(prm.scriptFail);
			}
			catch(e){}
		}
		
		//reloding the page
		if(prm.reloadAbs)
		{
			absoluteRedirect("$reload$");
		}
		else
		{
			if(prm.reload)window.location.reload(true);
			//reloading opener window
			if(prm.reloadOpener)
			{
				if(window.top.opener && !window.top.opener.closed)
				{
					/*
					there is a bug in ie: 
						when closing the popup and reloading the opener
						at the same time we get a GPF
						so, we use a timeout to make sure that the reload is done after
						the popup is closed
					*/
					try
					{
						//if opener changed url u get access denied exception..
						window.top.opener.setTimeout("location.reload(true)",1000);
					}catch(e){}
				}
			}
		}
		//closing the window
		if(prm.closeAbs) absoluteRedirect("$close$");
		else if(prm.closeWin) window.top.close();
	}
	this.defaultCallBack=defaultCallBack;
	
	/*
		confirm action in a hidden frame
		params:
			URL	- url to run
			fname - frame name (def fraExec)
			actionName - action for message (def 'delete')
			item - item name
			customMsg - msg		
	*/
	var confirmActionHidden=function(URL,fname,actionName,item,customMsg)
	{
		if(isEmpty(URL))return false;
		if(isEmpty(fname))fname="fraExec";

		//def action
		if(isEmpty(actionName))actionName="delete";
		actionName=ntz(enMsg.get("general.action."+actionName),actionName);
		var msg=customMsg;
		if(isEmpty(msg))
		{
			if(isEmpty(item))
			{
				msg=enMsg.get("enUtils.delSomeItem").replace("~1~",actionName);
			}
			else
			{
				//msg="Are you sure you want to "+actionName+" item "+item+" ?";
				msg=enMsg.get("enUtils.delItem").replace("~1~",actionName).replace("~2~",item);
			}
		}
		//confirm and perform
		var ret=confirm(msg);
		if(ret) 
		{
			//check if currently processing and flag
			execAsync(fname,URL,fname);
		}
		return ret;
	}
	this.confirmActionHidden=confirmActionHidden;

	/*---------------------------------------------------------------------------------------
		limit text area length
	---------------------------------------------------------------------------------------*/
	
	/*
	limitTextLength limit length in textarea - for NS 6.0 and IE 5.0+
	how to use:
		1. place attribute on the textarea - maxlen
		2. place attribute enMsg, if needs custom message
		3. attach the onkeypress and onchange events
		<textarea id="txtTest" maxlength="10" enMgs="The text you have entered exceeds the field's maximum allowed length (10)."></textarea>
		<script language="JavaScript"><!--
		//attach textarea events
		enUtils.evtAddEvent(document.getElementById("txtTest"),"keypress",enUtils.limitTextLength);
		enUtils.evtAddEvent(document.getElementById("txtTest"),"change",enUtils.chunkTextLength);
		//--></script>
	params:
		none
	*/
	var limitTextLength=function(e)
	{
		//get event
		e=evtGetCBEvent(e);
		var el=e.target;
		if(isEmpty(el))return true;
		var maxlen=el.getAttribute("maxlength");
		if(isEmpty(maxlen))return true;

		//get ascii code
		var asciiCode=e.keyCode;
		if(el.value.length>=maxlen)
		{
			//allow backspace,del,home,end,arrows
			if(asciiCode!=8 && asciiCode!=46 && (asciiCode<35 || asciiCode>40))
			{
				e.cancelEvent();
				return false;
			}
		}
		return true;
	}
	this.limitTextLength=limitTextLength;
	/*
		limit length after the control content changes
		to use a custom message set an attribute enMsg
		should be attached to onchange event
	*/
	var chunkTextLength=function(e)
	{
		e=evtGetCBEvent(e);
		var el=e.currentTarget ;
		el=objectOrGetId(el);
		if(isEmpty(el))return;
		var maxlen=el.getAttribute("maxlength");
		var msg=el.getAttribute("enMsg");
		if(isEmpty(maxlen))return;
		var len=el.value.length;
		if(len<=maxlen)return true;

		if(msg!="$NOMSG$")
		{
			if(!isSet(msg))msg=enMsg.get("enUtils.truncatedText");
			alert(msg+ " ("+maxlen+")");
		}
		el.value=el.value.substring(0,maxlen);
		el.focus();
		return true;
	}
	this.chunkTextLength=chunkTextLength;
	
	
	/*---------------------------------------------------------------------------------------
		limit input
	---------------------------------------------------------------------------------------*/
	/*
	limit input to integers only
	how to use:
		enUtils.evtAddEvent(document.getElementById("txtName"),"keypress",enUtils.limitInputInteger);
	*/
	var limitInputInteger=function(e)
	{
		//get event
		e=evtGetCBEvent(e);
		var el=e.target;
		if(isEmpty(el))return true;
		//get ascii code
		var asciiCode=e.keyCode;
		/*
			allow backspace,del,tab,enter,home,end,arrows,numbers and minus
			do not allow shift key
		*/
		if(asciiCode!=8 && asciiCode!=9 && asciiCode!=13 && 
			(asciiCode<48 || asciiCode>57) || asciiCode==39)
		{
			//minus - only at start
			if(!(asciiCode==45 && el.value.length==0))
			{
				e.cancelEvent();
				return false;
			}
		}
		return true;
	}
	this.limitInputInteger=limitInputInteger;
	
	/*
	limit input to numeric only
	how to use:
		enUtils.evtAddEvent(document.getElementById("txtName"),"keypress",enUtils.limitInputNumeric);
	*/
	var limitInputNumeric=function(e)
	{
		//get event
		e=evtGetCBEvent(e);
		var el=e.target;
		if(isEmpty(el))return true;
		//get ascii code
		var asciiCode=e.keyCode;
		//allow backspace,del,tab,enter,home,end,arrows, numbers , dots and minus
		if(asciiCode!=8 && asciiCode!=9 && asciiCode!=13 &&
			(asciiCode<48 || asciiCode>57) || asciiCode==39)
		{
			//minus - only at start; dot only once
			if(!(asciiCode==45 && el.value.length==0) && !(asciiCode==46 && el.value.indexOf(".")==-1))
			{
				e.cancelEvent();
				return false;
			}
		}
		return true;
	}
	this.limitInputNumeric=limitInputNumeric;

	/*---------------------------------------------------------------------------------------
		list functions - for use in assigning items between lists
	---------------------------------------------------------------------------------------*/

	/*
		move selected item between lists
		params:
			fromObj - src list element or id
			toObj - target list element or id
			sort[optional] - sort items by text, def:true.
			keepSelected - keep options selected after swap (def false)?
			silent - do not notify user if no items are selected (def true)
			msg - a message to use when no option is selected.
				if ommited - default msg is used
				if $NOMSG$ - no message
		returns:true/false		
	*/
	var listMoveSelectedItems=function(fromObj,toObj,sort,keepSelected,silent,msg)
	{
		fromObj=objectOrGetId(fromObj);
		toObj=objectOrGetId(toObj);
		if(!isSet(sort))sort=true;
		//if not is set(keepSelected) - def false
		if(!isSet(keepSelected))keepSelected=false;
		if(!isSet(silent))silent=true;
		
		//any items to move ?
		if(fromObj.options.selectedIndex==-1)
		{
			//alert user to select an option
			if(!silent)
			{
				//alert(!isEmpty(msg)?msg:"No items are selected");
				alert(!isEmpty(msg)?msg:enMsg.get("enUtils.noItems"));				
			}
			return false;
		}

		//first move to end (because having problems with ie 5.0)
		listMoveOptions(fromObj,'bottom',true,'$NOMSG$');
		var op;

		for(selIndex=0;selIndex<fromObj.length;selIndex++)
		{			
			if (fromObj.options[selIndex].selected)
			{
				//move the option as an object
				op=fromObj.options[selIndex--];
				toObj.appendChild(op);
				if(!keepSelected)op.selected=false;
			}
		}
		//sort
		if(sort)listSortItems(toObj);
		return true;
	}
	//expose
	this.listMoveSelectedItems=listMoveSelectedItems;
	
	/*
		sort list items
		params:
			list - a list element ref or id
			asc - true=ascending(def), false=descending.
			val - true=compare by optoin value, false=compare by option text(def).
			byAttr - sort by attribute
	*/
	var listSortItems=function(list,asc,val,byAttr)
	{
		list=objectOrGetId(list);
	    var i,j,bestValue,bestJ,bestOption,found;
		var min=0;
		var max=list.options.length-1;
		var attr=(!isEmpty(byAttr));
		var currVal;
		//default ascending
		if(!isSet(asc))asc=true;
		for(i=min;i<=max;i++)
		{
			if(val)bestValue=list.options[i].value.toLowerCase();
			else bestValue=list.options[i].text.toLowerCase();
	    	bestJ=i;
	    	for(j=i+1;j<=max;j++)
			{
				//get value
	    		if(attr)
				{
					currVal=list.options[j].getAttribute(byAttr);
					if(!isEmpty(currVal) && currVal.toLowerCase)currVal=currVal.toLowerCase();
	    		}
				else if(val)
				{
					currVal=list.options[j].value.toLowerCase();
	    		}else{
					currVal=list.options[j].text.toLowerCase();
	    		}
				//compare
				if(currVal<bestValue&&asc||currVal>bestValue&&!asc)
				{
        			bestValue=currVal;
        			bestJ=j;
    			}
	    	}
			//switch
			if(bestJ!=i)listReplaceItems(list,i,bestJ);
		}
		return true;	
	}
	//expose
	this.listSortItems=listSortItems;
	
	/*
		replace 2 items within a list
		params:
			lst - a list element ref or id
			i - index of first option
			j - index of 2nd option
			keepSelected - keep options selected after swap (def true)?
		returns:true/false
	*/	
	var listReplaceItems=function(lst,i,j,keepSelected)
	{
		if(i==j)return true;
		lst=objectOrGetId(lst);
		
		//if not is set(keepSelected) - def true
		if(!isSet(keepSelected))keepSelected=true;
	
		var opti=lst.options[i];
		var optj=lst.options[j];
		if(i<j)lst.insertBefore(optj,opti);
		else lst.insertBefore(opti,optj);
		if(!keepSelected)opti.selected=false;
		return true;
	}
	//expose
	this.listReplaceItems=listReplaceItems;
	
	/*
		list all items in a list into a text element
		params:
			list - a list element ref or id
			txt - a text element ref or id
			sep - separator (Optional, def '#')
			selectedOnly - list only selected options (Optional, def false)
			wrapWithSep - use sep on ends too (Optional, def false)
		returns:list of item values
	*/
	var listAllItems=function(list,txt,sep,selectedOnly,wrapWithSep)
	{
		list=objectOrGetId(list);
		if(!isEmpty(txt))txt=objectOrGetId(txt);
		//def values
		if(isEmpty(sep))sep="#";
		if(!isSet(selectedOnly))selectedOnly=false;
		if(!isSet(wrapWithSep))wrapWithSep=false;
		
		var bfr="";
		var len=list.options.length;
		var op;
		for(var i=0;i<len;i++)
		{
			op=list.options[i];
			if(op.selected||!selectedOnly)
			{
				bfr+=op.value;
				if(i<len-1)bfr+=sep;
			}
		}
		if(wrapWithSep && bfr.length>0) bfr=sep + bfr + sep;
		if(txt)	setValueOf(txt,bfr);
		return bfr;
	}
	//expose
	this.listAllItems=listAllItems;
	
	/*
		move selected options in list
		handles multiple selections as well
		
		params:
			lst - a list element or it's id
			dir - one of the following:
				top - top (first)
				up - up 1 step (def)
				down - down 1 step
				bottom - bottom (last)
			keepSelected - maintain selection (def true)
			silent - do not notify user if no items are selected (def true)
			msg - a message to use when no option is selected.
				if ommited - default msg is used
				if $NOMSG$ - no message
		returns:true/false		
	*/
	function listMoveOptions(lst,dir,keepSelected,silent,msg)
	{
		lst=objectOrGetId(lst);	
		if(!isSet(silent))silent=true;
		var ops=lst.options;
		if(ops.selectedIndex==-1)
		{
			//alert user to select an option
			if(!silent)
			{
				alert(!isEmpty(msg)?msg:enMsg.get("enUtils.noItems"));
			}
			return false;
		}
		var len=ops.length;
		
		//validate dir
		if(!dir)dir="up";
		dir=dir.toLowerCase();
		if("@top@up@down@bottom@".indexOf("@"+dir+"@")==-1)dir="up";
		
		//if not is set(keepSelected) - def true
		if(keepSelected!=false)keepSelected=true;
	
		//loop on all items and move selected ones
		var selectedIxs,ix;
		switch(dir)
		{
			case "top":
				selectedIxs=new Array();
				ix=0;
				//reverse loop
				for(var i=len-1;i>=0;i--)
				{
					//save selected options
					if(ops[i].selected)
					{
						selectedIxs[ix++]=i;
					}
				}
				for(var i=0;i<selectedIxs.length;i++)
				{
					//Crawl to top step by step
					for(var j=selectedIxs[i];j+i>0;j--)
					{
						listReplaceItems(lst,j+i,j+i-1,keepSelected);
					}
				}
				break;
			case "up":
				for(var i=0;i<len;i++)
				{
					if(ops[i].selected)listReplaceItems(lst,i,i==0?i:i-1,keepSelected);
				}
				break;
			case "down":
				//reverse loop
				for(var i=len-1;i>=0;i--)
				{
					if(ops[i].selected)listReplaceItems(lst,i,i==len-1?i:i+1,keepSelected);
				}
				break;
			case "bottom":
				selectedIxs=new Array();
				ix=0;
				for(var i=0;i<len;i++)
				{
					//save selected options
					if(ops[i].selected)
					{
						selectedIxs[ix++]=i;
					}
				}
				for(var i=0;i<selectedIxs.length;i++)
				{
					//Crawl to end step by step
					for(var j=selectedIxs[i];j-i<len-1;j++)
					{
						listReplaceItems(lst,j-i,j-i+1,keepSelected);
					}
				}
				break;
		}
		return true;
	}
	//expose
	this.listMoveOptions=listMoveOptions;
	
	//refill 2 selects for Many to Many connections
	/*
	parameters:
	arrValTxtOptions:array of arrays(2) where index [0]=option's value 
				  and index [1]=option's text.
	arrValsBelong: array of values (can be part or all of the values in arrValTxtOptions) 
	slctBelong:name of a list control.
	slctNotBelong:name of a list control.
	
	functionality:
	the function goes over all arrValTxtOptions, for each it looks if exists in arrValsBelong,
	if so this option will be created in slctBelong, else in slctNotBelong.	
	
	how to use:
	enUtils.listRefillM2MLists(fullList,belongList,document.forms['frmTest'].slct1,document.forms['frmTest'].slct2);
	*/
	var listRefillM2MLists=function (arrValTxtOptions, arrValsBelong, slctBelong, slctNotBelong){
		//check for corect controls
		if(!slctBelong || !slctNotBelong || (slctBelong==slctNotBelong))return;
		if(slctBelong.type.indexOf('select')==-1)return;
		if(slctNotBelong.type.indexOf('select')==-1)return;
		//variables
		var val,txt,optElement;
		var optValTxt=new Array(2);
		//clear the lists
		var optsBelong=slctBelong.options;
		optsBelong.length=0;
		var optsNotBelong=slctNotBelong.options;
		optsNotBelong.length=0;
		//start looping the full list (arrValTxtOptions)
		for (var i=0;i<arrValTxtOptions.length;i++)
		{
			optValTxt=arrValTxtOptions[i];
			optElement=new Option(optValTxt[1],optValTxt[0]);
			if (isInArray(optValTxt[0],arrValsBelong))
			{
				optsBelong[optsBelong.length]=optElement;
			}
			else
			{
				optsNotBelong[optsNotBelong.length]=optElement;
			}
		}
	}
	//expose
	this.listRefillM2MLists=listRefillM2MLists;
	
	//listRefillList: refill a list with new values
	/*
	parameters:
	slctElmnt: the select element to be refilled
	arrValTxtOptions:array of arrays(2) where index [0]=option's value 
				  and index [1]=option's text.
	clean[optional]: true(def)/false param, indicates whether to delete existing options
	SlctdItems[optional]: array of all values or a list seperated by @ to be selected .
	sort[optional]: sort items by text, def:true.
	*/
	var listRefillList=function(slctElmnt,arrValTxtOptions,clean,SlctdItems,sort){
		//check valid params
		if(!isSet(slctElmnt))return;
		if(!isSet(sort))sort=true;
		slctElmnt=objectOrGetId(slctElmnt);
		if(isEmpty(slctElmnt))return;
		if(typeof slctElmnt!='object')slctElmnt=document.getElementById(slctElmnt);
		if(slctElmnt.type.indexOf('select')==-1)return;
		//vars
		var slctElmntOptions = slctElmnt.options;
		var optElement;
		var optValTxt=new Array(2);
		//clean if necessary
		if(!isSet(clean)) clean=true;
		if(clean)
		{
			slctElmntOptions.length=0;
		}
		//handle SlctdItems
		if(isSet(SlctdItems))
		{
			var arrSlctdItems=new Array();
			arrSlctdItems=typeof SlctdItems=='string'?SlctdItems.split('@'):SlctdItems;
		}
		//refill
		for (var i=0;i<arrValTxtOptions.length;i++)
		{
			optValTxt=arrValTxtOptions[i];
			optElement=new Option(optValTxt[1],optValTxt[0]);
			//add
			slctElmntOptions[slctElmntOptions.length]=optElement;
			//mark selected
			if (isSet(SlctdItems) && arrSlctdItems.length>0 && isInArray(optValTxt[0],arrSlctdItems))
			{
				optElement.selected=true;
				optElement.defaultSelected=true;
			}
		}
		//sort the list
		if(sort)listSortItems(slctElmnt);
	}
	//expose
	this.listRefillList=listRefillList;

	/*---------------------------------------------------------------------------------------
		table functions
	---------------------------------------------------------------------------------------*/

	/*	move a row in a table in a desired direction (up/down)
		params:
			el - the tr element or an element in the tr (id or element).
			dir - the move direction: up/down.
			bSwitchClasses - (booloen)whether to change the trs classes (for use in Zebra tables)
	*/
	var tblMoveTableRow=function(el,dir,bSwitchClasses)
	{
		//step 1: get the desired tr 
		var tr=getElTr(el);
		if(isEmpty(tr)) return;
		//step 2: get the tbody
		//find the table
		var tbl=getElTable(tr);
		if(isEmpty(tbl)) return;
		var tblTbody=enUtils.getTableTbody(tbl);
		if(enUtils.isEmpty(tblTbody))return;
		//step 3:claculate the indexes
		var idxFrom=enUtils.tblGetRowIndex(tblTbody,tr);
		var idxTo=(dir=="down")?idxFrom+1:idxFrom-1;
		//keep in table
		if(idxTo<0||idxTo>tblTbody.rows.length-1)return;
		//switch
		enUtils.tblSwitchTableRows(tblTbody,idxFrom,idxTo,bSwitchClasses);
	}
	this.tblMoveTableRow = tblMoveTableRow;	
	/*
		switch table rows
		params:
			tbody - tbody ref
			iFirst - index of first row
			iSnd - index of 2nd row
			bSwitchClasses - (booloen)whether to change the trs classes (for use in Zebra tables)
	*/
	var tblSwitchTableRows=function(tbody,iFirst,iSnd,bSwitchClasses)
	{
		if(iFirst==iSnd)return;
		if(!isSet(bSwitchClasses))bSwitchClasses=false;
		if(iFirst>iSnd)
		{
			var tmp=iFirst;
			iFirst=iSnd;
			iSnd=tmp;
		}
		var tr1=tbody.rows[iFirst];
		var tr2=tbody.rows[iSnd];

		//backup check and radio state
		elmntBackupChildChecks(tr1);
		elmntBackupChildChecks(tr2);
		
		//switch
		tbody.insertBefore(tr2,tr1);
		if(iSnd==tbody.rows.length-1)tbody.appendChild(tbody.rows[iFirst+1]);
		else tbody.insertBefore(tbody.rows[iFirst+1],tbody.rows[iSnd+1]);
		
		//restore check and radio state
		elmntRestoreChildChecks(tr1);
		elmntRestoreChildChecks(tr2);
		
		//switch rows classes
		if(bSwitchClasses)
		{
			try
			{
				var tmpClass=tr1.className;
				tr1.className=tr2.className;
				tr2.className=tmpClass;
			}
			catch(e){}
		}
	}
	this.tblSwitchTableRows=tblSwitchTableRows;
	/*
	returns the tr index in the tbody.rows collection
	params:
		tbdy: the table body(id/el)
		tr: the desired tr(id/el)
	*/
	var tblGetRowIndex=function (tbdy,tr)
	{
		tbdy=objectOrGetId(tbdy);
		tr=objectOrGetId(tr);
		var idx=null;
		for(var i=0;i<tbdy.rows.length;i++)
		{
			if(tbdy.rows[i]==tr)
			{	
				idx=i;
				break;
			}
		}
		return idx;
	}
	this.tblGetRowIndex=tblGetRowIndex;
	/*
		sort table
		params:
			tbl - a table or id
			col - col to sort (index)
			asc - ascending order (def true)
			type - sort type text (def)/numeric
			elType - eleemnt type in wich the value id (def empty)
				text / file / textarea / checkbox / button / submit / select
			bSwitchClasses - (booloen)whether to change the trs classes (for use in Zebra tables)
					def = true
	*/
	var tblSortTable=function(tbl,col,asc,type,elType,bSwitchClasses){
		/*---------------- internal function ---------------------------------------------*/
		/*
			get td's value - returns element value in lower case
			params:
				td - td element
				type - type of element: 
					text / file / textarea / checkbox / button / submit / select
					def none (get td content)
			returns:
				td or element value in lower case
		*/
		var getTDVal=function(td,type)
		{
			var tag="",out="";	
			//no special type - return td content
			if(isEmpty(type))
			{
				out=td.childNodes[0].nodeValue;
			}
			else
			{
				type=type.toLowerCase();
				if("@text@file@checkbox@button@submit@".indexOf("@"+type+"@")!=-1)
				{
					tag="input";
				}
				else tag=type;
				
				//get item reference
				var items,item,itemType;
				items=td.getElementsByTagName(tag);
				if(isEmpty(items))return "";				
				for (var i=0;i<items.length;i++)
				{
					itemType=items[i].type.toLowerCase();
					if(itemType==type || type=="select" && itemType.indexOf(type)!=-1)
					{
						item=items[i];
						break;
					}
				}
				//get value
				if(type=="select")
				{
					if(item.selectedIndex==-1)out="";
					else out=item[item.selectedIndex].text;
				}
				else out=getValueOf(item);
			}
			if(isEmpty(out))return "";
			return out.toLowerCase();
		}
		/*---------------- /internal function ---------------------------------------------*/
		var i,j,bestValue,currVal,bestJ,cmpr;
		var min=0;
		//def val
		if(!isSet(asc))asc=true;		
		tbl=objectOrGetId(tbl);
		//assuming a single TBODY
		var rows=tbl.tBodies[0].rows;
		var max=rows.length-1;
		for(i=min;i<=max;i++)
		{
			bestValue=getTDVal(rows[i].cells[col],elType);
	    	bestJ=i;
	    	for(j=i+1;j<=max;j++)
			{
				currVal=getTDVal(rows[j].cells[col],elType);
	    		cmpr=compareVals(currVal,bestValue,type);    	
	    		if(cmpr==-1&&asc||cmpr==1&&!asc)
				{
	        		bestValue=currVal;
	        		bestJ=j;
	        	}
	    	}
			//switch
			if(!isSet(bSwitchClasses))bSwitchClasses=true;
			if(bestJ!=i)tblSwitchTableRows(tbl.tBodies[0],i,bestJ,bSwitchClasses);
		}		
		//reassign images
		tblReassignSortStatus(tbl);
	}
	this.tblSortTable=tblSortTable;

	/*
		sort table - by an element in a header td
		params:
			el - an element or id (td or its child)
	*/
	var tblSortTableByEl=function(el)
	{
		el=objectOrGetId(el);
		//get td element
		var td=elmntGetParentByTagName(el,"TD");
		//get current sort order and flip
		var asc=toBoolean(td.getAttribute("enSortedAsc"));
		if(!isSet(asc))asc=true;
		else asc=!asc;
		
		var type=td.getAttribute("enSortType");
		//if type is '$nosort$' - exit
		if(ntz(type).toLowerCase()=="$nosort$")return;
		
		var elType=td.getAttribute("enSortElementType");
		//switch row classes?
		var switchClasses=td.getAttribute("enSwitchClasses");
		//if not in td level try the tr level
		if(isEmpty(switchClasses))
		{
			var tdTr=elmntGetParentByTagName(td,"TR");
			if(!isEmpty(tdTr))switchClasses=tdTr.getAttribute("enSwitchClasses");
		}
		switchClasses=toBoolean(switchClasses,false);
		//clear all other TD's SortedAsc
		for(var i=0;i<td.parentNode.cells.length;i++)
		{
			td.parentNode.cells[i].removeAttribute("enSortedAsc");
		}
		//mark new order
		td.setAttribute("enSortedAsc",asc);
		//sort
		tblSortTable(elmntGetParentByTagName(td,"TABLE"),td.cellIndex,asc,type,elType,switchClasses);
	}
	this.tblSortTableByEl=tblSortTableByEl;
	
	// sort table - for use from event
	var tblSortTableEvt=function(e)
	{
		var evt=evtGetCBEvent(e);				
		//get el from event		
		var el=evt.target;
		tblSortTableByEl(el);	
		//stop bubling
		evt.setCancelBubble(true);
	}
	this.tblSortTableEvt=tblSortTableEvt;

	/*
		re assign classes to rows (odd / even)		
		params:
			el - tbl or child of table, or id
			odd - class for odd (def table attribute enaClassOdd, or 'odd')
			even - class for even (def table attribute enaClassEven, or 'even')
	*/
	var tblReassignRowsClass=function(el,odd,even)
	{
		//get tbl object
		el=objectOrGetId(el);
		if(isEmpty(el))return;
		if(el.nodeName.toLowerCase()!="table")el=elmntGetParentByTagName(el,"TABLE");
		if(isEmpty(el))return;
		var tbl=el;
		//class names
		if(isEmpty(odd))
			odd=ntz(tbl.getAttribute("enaClassOdd"),"odd");
		if(isEmpty(even))
			even=ntz(tbl.getAttribute("enaClassEven"),"even");
		//make the rows odd and even...
		var rows=tbl.rows;
		var lastClass=odd;
		//table has 2 rows atleast?
		if(rows.length<2)return;
		//check if table uses odd/even class
		if(rows[1].className!=odd && rows[1].className!=even)return;
		for(var i=1;i<rows.length;i++)
		{
			rows[i].className=lastClass;
			lastClass=(lastClass==odd) ? even : odd;
		}
	}
	this.tblReassignRowsClass=tblReassignRowsClass;
	
	/*
	set sort status image and class
		images should be set with hidden style at start
		imag names should be sortedUp.gif / sortedDown.gif, or set in TR attributes enImgSortUp,enImgSortDown
		image path should be set in TR attribute enImgPath
		td class names should be set in TR attributes enTdClassSorted,enTdClassUnsorted
		
	params:
		el: td or tr or table element (or id)
	*/
	var tblReassignSortStatus=function (el)
	{
		//get td/tr object
		el=objectOrGetId(el);
		if(isEmpty(el))return;
		if(el.nodeName.toLowerCase()=="td")
		{
			el=elmntGetParentByTagName(el,"TR");
			if(isEmpty(el))return;
		}
		if(el.nodeName.toLowerCase()=="table")el=el.rows[0];
		if(el.nodeName.toLowerCase()!="tr")return;
		//get tr attributes
		var imgPath=el.getAttribute("enImgPath");
		var imgSortedUp=el.getAttribute("enImgSortUp");
		var imgSortedDown=el.getAttribute("enImgSortDown");
		var tdClassSorted=el.getAttribute("enTdClassSorted");
		var tdClassUnsorted=el.getAttribute("enTdClassUnsorted");
		var handleImages=!(isEmpty(imgPath) || isEmpty(imgSortedUp) || isEmpty(imgSortedDown));
		var handleClasses=!(isEmpty(tdClassSorted));

		if(!handleImages && !handleClasses)return;
		var imgs=null;
		//hide all sort state images
		if(handleImages)
		{
			imgs=el.getElementsByTagName("IMG");
			for(var i=0;i<imgs.length;i++)
			{
				if(toBoolean(imgs[i].getAttribute("enSortState")))
					elmntShowHide(imgs[i],false);
			}
		}
		//internal function to find sort state image
		var getSortStateImg=function(td)
		{
			var imgs=td.getElementsByTagName("IMG");
			for(var i=0;i<imgs.length;i++)
			{
				if(toBoolean(imgs[i].getAttribute("enSortState")))
					return imgs[i];
			}
			return null;
		}

		//loop on all TDs
		var td=null,sorted=null,asc=false;
		for(var i=0;i<el.cells.length;i++)
		{
			td=el.cells[i];
			sorted=td.getAttribute("enSortedAsc");
			if(!isEmpty(sorted))
			{
				if(handleImages)
				{
					asc=toBoolean(sorted);
					//set img
					var img=getSortStateImg(td);
					if(!isEmpty(img))
					{
						img.setAttribute("src",
							asc ? imgPath+imgSortedUp : imgPath+imgSortedDown);
						elmntShowHide(img,true);
					}
				}
				if(handleClasses)
				{
					td.className=tdClassSorted;
				}
			}
			else if(handleClasses)
			{
				td.className=tdClassUnsorted;
			}
		}
	}
	this.tblReassignSortStatus=tblReassignSortStatus;

	/*---------------------------------------------------------------------------------------
		ticker (scrolling messages)
	---------------------------------------------------------------------------------------*/
	//global object
	var ticGlobal=new Object();
	//scroller width
	ticGlobal.width=300;
	//scroller height
	ticGlobal.height=100;
	//scroller's speed;
	ticGlobal.speed=2;
	ticGlobal.ns4layer=null;
	ticGlobal.ns6div=null;
	ticGlobal.sizeup=null;
	ticGlobal.wholeMessage=null;
	ticGlobal.baseName="";
	this.ticGlobal=ticGlobal;
	
	//build ns 4 elements
	var ticNs4marquee=function(whichlayer)
	{
		ticGlobal.ns4layer=eval(whichlayer);
		ticGlobal.ns4layer.document.write(ticGlobal.wholeMessage);
		ticGlobal.ns4layer.document.close();
		ticGlobal.sizeup=ticGlobal.ns4layer.document.height;
		ticGlobal.ns4layer.top-=ticGlobal.sizeup;
		ticNs4slide();
	}
	this.ticNs4marquee=ticNs4marquee;
	
	//build ns 4 elements
	var ticNs4slide=function()
	{
		if (ticGlobal.ns4layer.top>=ticGlobal.sizeup*(-1))
		{
			ticGlobal.ns4layer.top-=ticGlobal.speed;
			setTimeout("enUtils.ticNs4slide()",100);
		}
		else
		{
			ticGlobal.ns4layer.top=ticGlobal.height;
			ticNs4slide();
		}
	}
	this.ticNs4slide=ticNs4slide;
	
	//build ns 6 elements
	var ticNs6marquee=function(whichdiv)
	{
		ticGlobal.ns6div=eval(whichdiv);
		ticGlobal.ns6div.innerHTML=ticGlobal.wholeMessage;
		ticGlobal.ns6div.style.top=ticGlobal.height;
		ticGlobal.sizeup=ticGlobal.height;
		ticNs6slide();
	}
	this.ticNs6marquee=ticNs6marquee;
	
	//build ns 6 elements
	var ticNs6slide=function()
	{
		if (parseInt(ticGlobal.ns6div.style.top)>=ticGlobal.sizeup*(-1))
		{
			ticGlobal.ns6div.style.top=parseInt(ticGlobal.ns6div.style.top)-ticGlobal.speed;
			setTimeout("enUtils.ticNs6slide()",100);
		}
		else
		{
			ticGlobal.ns6div.style.top=ticGlobal.height;
			ticNs6slide();
		}
	}
	this.ticNs6slide=ticNs6slide;
	
	/*
		init ticker
		how to use:
			attach to the onload event:
			enUtils.evtAddEvent(window,"load",enUtils.ticInit);
	*/
	var ticInit=function()
	{
		//if ie - exit
		if (enBS.ie) return;
		//if ns 6+
		if (enBS.ns6up)
		{
			var ns6slider=document.getElementById(ticGlobal.baseName+"ns6slider");
			ns6slider.style.visibility="show";
			ticNs6marquee(ns6slider);
		}
		//if ns 4
		else if(enBS.ns4)
		{
			var ns4slider=eval("document."+ticGlobal.baseName+"ns4slider1");
			ns4slider.visibility="show";
			ticNs4marquee(eval("ns4slider.document."+ticGlobal.baseName+"ns4slider2"));
		}
	}
	this.ticInit=ticInit;
	
	/*
		write eleemnts - called when the page is written
		params:
			wholeMessage - the complete message
			baseName - basic name to use (prefix for all related names and ids)			
			width
			height
			speed
	*/
	var ticWriteElements=function(wholeMessage,baseName,width,height,speed)
	{
		//set global params
		ticGlobal.wholeMessage=wholeMessage;
		ticGlobal.baseName=baseName;
		ticGlobal.width=width;
		ticGlobal.height=height;
		ticGlobal.speed=speed;
		
		//ie
		if (enBS.ie)
		{
			document.writeln('<marquee id="'+baseName+'ieslider" scrollAmount="'+speed+'" width="'+width+'" height="'+height+'" direction="up">');
			document.writeln(wholeMessage);
			var ieslider=document.all[baseName+"ieslider"];
			ieslider.onmouseover=new Function("document.all."+baseName+"ieslider.scrollAmount=0");
			ieslider.onmouseout=new Function("if (document.readyState=='complete') document.all."+baseName+"ieslider.scrollAmount="+speed);
			document.write('</marquee>');
		}
		//ns 6+
		if (enBS.ns6up)
		{
			document.write('<div style="position:relative;overflow:hidden;width:'+width+';height:'+height+';clip:rect(0 '+2+width+' '+2+height+' 0);" onMouseover="ticGlobal.speed=0;" onMouseout="ticGlobal.speed='+speed+'">');
			document.write('<div id="'+baseName+'ns6slider" style="position:relative;width:&{width};">');
			document.write('</div></div>');
		}
	}
	this.ticWriteElements=ticWriteElements;
	
	/****************************************
	*****		DRAG & DROP FUNCTIONS	*****
	****************************************/
	/*
		GENERAL:
			in order for an elemnt to be dragable it must have:
			1. attribute enaDragable="1"
			2. style="position:absolute"
			3. If the element has border, it must be numeric.
			4. on the page load run the dragInit();
	*/
	/*
	init function to set the global variable & attach functions to documnet events
	*/
	var dragInit=function() 
	{
		// assign functions to each of the events (works for both Navigator and IE)
		enUtils.evtAddEvent(document,"mousedown",dragCatch);
		enUtils.evtAddEvent(document,"mousemove",dragIt);
		enUtils.evtAddEvent(document,"mouseup",dragRelease);
		//define a variables in global that will hold the draged elemnt & its props
		if(!enApplication.global.drag)enApplication.global.drag=new Object();
		enApplication.global.drag.selectedObj=null;
		enApplication.global.drag.objBorder=0;
		enApplication.global.drag.offsetX=null;
		enApplication.global.drag.offsetY=null;
	}
	this.dragInit=dragInit;
	// put dragged object & its properties in memory
	var dragCatch=function(e) 
	{
		var evnt=enUtils.evtGetCBEvent(e);
		dragSetSelectedElmnt(evnt);
		if (enApplication.global.drag.selectedObj) 
		{
			// set globals that remember where the click is in relation to the
			// top left corner of the element so we can keep the element-to-cursor
			// relationship constant throughout the drag
			enApplication.global.drag.offsetX = evnt.offsetX+enApplication.global.drag.objBorder;
			enApplication.global.drag.offsetY = evnt.offsetY+enApplication.global.drag.objBorder;
		}
		// block mouseDown event from forcing Mac to display
		// contextual menu.
		return false;
	}
	// put dragged object (if dragable) in memory
	var dragSetSelectedElmnt=function(evnt) 
	{
		// use event model to get the targeted element
		var dragObj = evnt.target;
		dragObj=objectOrGetId(dragObj);
		// make sure it's a draggble object
		if (dragObj.getAttribute && dragObj.getAttribute("enaDragable") == 1) 
		{
			//get the border of the element
			enApplication.global.drag.selectedObj = dragObj;
			var border=parseInt(dragObj.style.borderWidth);
			if(isNaN(border))border=0;
			enApplication.global.drag.objBorder=border;
			return;
		}
		// the user probably clicked on the background
		enApplication.global.drag.selectedObj = null;
		return;
	}
	/*
		Restore elements and globals to initial values
		+ put last position in memory & cookies
	*/
	var dragRelease=function(e) 
	{
		//if the release is from htis window - move the dragObj to the cursor.
		if(e!=null)
		{
			var evnt=enUtils.evtGetCBEvent(e);
			if (enApplication.global.drag.selectedObj) 
			{
				enUtils.elmntMove(enApplication.global.drag.selectedObj, 
								  evnt.clientX - enApplication.global.drag.offsetX,
								  evnt.clientY - enApplication.global.drag.offsetY);
			}
		}
		if(enApplication.global.drag.selectedObj!=null)
		{
			//for the main focus: keep last position
			var dragObj=objectOrGetId(enApplication.global.drag.selectedObj);
			if(dragObj.id=="divMainFocus")
			{
				enApplication.global.drag.focusLastLeft=dragObj.style.left;
				enApplication.global.drag.focusLastTop=dragObj.style.top;
				//set in cookies
				var exp=new Date();
				//30 dyas
				exp.setTime (exp.getTime() + (30 * 24 * 60 * 60 * 1000));
				setCookie("enaFocusLastLeft",enApplication.global.drag.focusLastLeft,exp);
				setCookie("enaFocusLastTop",enApplication.global.drag.focusLastTop,exp);
			}
		}
		enApplication.global.drag.selectedObj = null
		
	}
	this.dragRelease=dragRelease;
	// Drag the picked element
	var dragIt=function(e) 
	{
		// operate only if an is selected
		if (enApplication.global.drag.selectedObj) 
		{
			var evnt=enUtils.evtGetCBEvent(e);
			enUtils.elmntMove(enApplication.global.drag.selectedObj, 
							  evnt.clientX - enApplication.global.drag.offsetX,
							  evnt.clientY - enApplication.global.drag.offsetY)
			// prevent further system response to dragging in IE
			return false
		}
	}
	/*****	END OF DRAG & DROP FUNCTIONS	*****/
	
	/*****	COOKIES FUNCTIONS	*****/
	
	/*
		Function to create or update a cookie.
		params:
			name - String object containing the cookie name.
			value - String object containing the cookie value.  May contain any valid string characters.
			[expires] - Date object containing the expiration data of the cookie. If omitted or null or invalid date, expires the cookie at the end of the current session.
			[path] - String object indicating the path for which the cookie is valid. If omitted or null, uses the path of the calling document.
			[domain] - String object indicating the domain for which the cookie is valid.  If omitted or null, uses the domain of the calling document.
			[secure] - Boolean (true/false) value indicating whether cookie transmission requires a secure channel (HTTPS).  
	*/
	var setCookie = function(name,value,expires,path,domain,secure) 
	{
		if(isEmpty(name) || isEmpty(value))return;
		var cookieStr=name + "=" + escape (value);
		if(!isEmpty(expires))cookieStr+="; expires=" + expires.toGMTString();
		if(!isEmpty(path))cookieStr+="; path=" + path;
		if(!isEmpty(domain))cookieStr+="; domain=" + domain;
		if(secure)cookieStr+="; secure";
		document.cookie = cookieStr;
	}
	this.setCookie=setCookie;
	/*
		Function to return the value of the cookie specified by "name".
		name:	String object containing the cookie name.
		returns:String object containing the cookie value, or null if the cookie does not exist.
	*/
	var getCookie = function(name)
	{
		var arg = name + "=";
		var alen = arg.length;
		var clen = document.cookie.length;
		var i = 0;
		while (i < clen) 
		{
		  	var j = i + alen;
	    	if (document.cookie.substring(i, j) == arg)
		    	return getCookieVal (j);
		    i = document.cookie.indexOf(" ", i) + 1;
	    	if (i == 0) break; 
		}
		return null;
	}
	this.getCookie = getCookie;
	/*
		"Internal" function to return the decoded value of a cookie
	*/
	var getCookieVal = function(offset)
	{
		var endstr = document.cookie.indexOf (";", offset);
		if (endstr == -1)
			endstr = document.cookie.length;
		return unescape(document.cookie.substring(offset, endstr));
	}
	/*
		Function to delete a cookie. (Sets expiration date to start of epoch)
		name: 	String object containing the cookie name
		path:	String object containing the path of the cookie to delete.  This MUST
				be the same as the path used to create the cookie, or null/omitted if
				no path was specified when creating the cookie.
		domain:	String object containing the domain of the cookie to delete.  This MUST
				be the same as the domain used to create the cookie, or null/omitted if
				no domain was specified when creating the cookie.
	*/
	var deleteCookie =function (name,path,domain) 
	{
	  	if (getCookie(name)) 
		{
	    	document.cookie = name + "=" +
				((path) ? "; path=" + path : "") +
				((domain) ? "; domain=" + domain : "") +
			      "; expires=Thu, 01-Jan-70 00:00:01 GMT";
	  	}
	}
	this.deleteCookie=deleteCookie;
}//end of construstor function

//instanciate object
if(!window.enUtils)window.enUtils=new enUtilsConstrustor();