/*
PUBLIC METHODS :

getVal 		: 
   * @description gets value of a form element ,
   * @method getVal
   * @public
   * @static
   * @param {string || object}  form element, name or id
   * @return {string} value  
setVal 		: 
   * @description sets value of a form element ,
   * @method setVal
   * @public
   * @static
   * @param {string || object}  form element, name or id
   * @param {string}  value
		
setHTML		:
   * @description sets html in specified element ,
   * @method setHTML
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name
   * @return void   
		
getHTML		:
   * @description gets html content of specified element ,
   * @method getHTML
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name
   * @return void   
		
getRef 		:
   * @description returns an object with reference to an element ,
   * @method getRef
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name
   * @return void   

setStyle	:
   * @description sets the css-style properties of specified element ,
   * @method setStyle
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name
   * @param {string}  css property
   * @return {string} css value 
					  
getStyle	:
   * @description returns the css-style propertie of specified element ,
   * @method getStyle
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name
   * @param {string}  css property
   * @param {string}  css value
   * @return void  
		
doShow		: 
   * @description sets the display or visibility property of a specified element to visible,
   * @method doShow
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name
   * @param {int}  time, if specified the displayed element will disappear after the time-value im ms
   * @return void
   
doHide		:
   * @description sets the display or visibility property of a specified element to hide,
   * @method doHide
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name
   * @return void
doShowHide	:
   * @description toggles the display or visibility property of a specified element ,
   * @method doShowHide
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name
   * @return void
					  
addClass	: 
   * @description adds a specified css-class to an element ,
   * @method addClass
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name
   * @param {string}  classname, specified in HTML-document or linked css-document
   * @return void
   
addStylesheet	: 
   * @description adds a specified css-stylesheet to document ,
   * @method addStylesheet
   * @public
   * @static
   * @param {string}  stylesheet url
   * @return void
					  
setFocus 	:
   * @description sets focus to a specified element ,
   * @method setFocus
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name
   * @return void

URIencode 	:
   * @description URIencodes [utf-8] a string  with parameters
   * @method URIencode
   * @public
   * @static
   * @param {string}  URI string
   * @return {string} encoded string
   
selectText 	:
   * @description selects a range of text in input-element
   * @method selectText
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name of textbox
   * @param {int}  startIndex
   * @param {int}  stopIndex
   * @return void
   
posX 	:
   * @description calculates left coordinates dom-element
   * @method posX
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name of element
   * @return {int}  left position
   
posY 	:
   * @description calculates top coordinates dom-element
   * @method posY
   * @public
   * @static
   * @param {string || object}  document element , id, tag, name of element
   * @return {int}  top position

URIencode 	: 
   * @description URIencodes [utf-8] an escaped string  with parameters
   * @method URIencode
   * @public
   * @static
   * @param {string} decoded string
   * @return {string} URI string
URIdecode 	: 
   * @description URIdecodes [utf-8] an unescaped string
   * @method URIdecode
   * @public
   * @static
   * @param {string}  URI string
   * @return {string} decoded string
encode_utf8 	: 
   * @description encodes [utf-8] a string
   * @method encode_utf8
   * @public
   * @static
   * @param {string}  string
   * @return {string} encoded string
   
decode_utf8 	: 
   * @description decodes [utf-8] a string
   * @method decode_utf8
   * @public
   * @static
   * @param {string}  string
   * @return {string} decoded string
   
base64encode 	: 
   * @description base64encodes  a string
   * @method base64encode
   * @public
   * @static
   * @param {string}  string
   * @return {string} encoded string  
   
base64decode 	: 
   * @description base64decodes  a string
   * @method base64decode
   * @public
   * @static
   * @param {string}  string
   * @return {string} decoded string 

safeHTML		:
   * @description encodes html for posting as url
   * @method safeHTML
   * @public
   * @static
   * @param {string}  HTML
   * @return void
   
safeURI 		: 
   * @description encodes uri-component to base64 decoded JSON-string for sending as url
   * @method safeURI
   * @public
   * @static
   * @param {string}  uri
   * @return {string} decoded string
   
safeObjToURI 		: 
   * @description encodes JSON object to base64 decoded JSON-string for sending as url
   * @method safeObjToURI
   * @public
   * @static
   * @param {string}  obj
   * @return {string} decoded string
   ==========================================
   USE PHP FUNCTION :
   function uri2json($data,$b_JSON=false){
		$data=base64_decode($data);
		$data=urldecode($data);
		if(!$b_JSON){
			return $data;
		}
		else {
			return json_decode($data);
		}
	}
   =========================================
isArray		:
   * @description returns true if typeof object is array
   * @method isArray
   * @public
   * @static
   * @param {obj}  array
   * @return {boolean} true or false

isNumber		:
   * @description returns true if typeof object is number
   * @method isNumber
   * @public
   * @static
   * @param {obj}  number
   * @return {boolean} true or false
   
inStr		:
   * @description returns true if needle is in haystack
   * @method inStr
   * @public
   * @static
   * @param {string} needle
   * @param {string} haystack   
   * @return {boolean} true or false

getExacType		:
   * @description returns  type of parameter
   * @method getExactType
   * @public
   * @static
   * @param {obj}  inputobject
   * @return {string} type
   
removeHTMLTags	:
   * @description removes all html tags from parameter
   * @method removeHTMLTags
   * @public
   * @static
   * @param {string}  html
   * @return {string} text, no tags
   
intOnly 	:
   * @description returns true if argument is integer
   * @method intOnly
   * @public
   * @static
   * @param {string}  testvalue from field
   * @return {boolean} true or false
   
goTo 	:
   * @description redirection to url
   * @method goTo
   * @public
   * @static
   * @param {string}  url  , if only filename (no slashes)then root is added
   * @param {string}  get  , if specified get is added as parameter {root}{url}?d={get}
   * @param {string}  d    , if true get is added as uri component
   * @return void

objToKey 	:
   * @description returns array with objectkeys
   * @method objToKey
   * @public
   * @static
   * @param {object}  object
   * @return {array} array with keys

winOpen :
   * @description creates new browserwindow
   * @method winOpen
   * @public
   * @static
   * @param {object}    root        : {string}, [if not specified then root is determined from server-info]
						url         : {string},
						name        : 'win_'+Math.floor(Math.random()*10000),[random name]
						options     : 'menubar=1,resizable=1,scrollbars=1,width=600,height=850'
   * @return {object}	window
   

getLocation :
   * @description returns a extended location object
   * @method getLocation
   * @public
   * @static
   * @param {string}  href
   * @param {string}  param
   * @return {obj}  locationobject :		
				
	d.protocol
	d.host
	d.hostname
	d.pathname
	d.port
	d.reload
	d.place
	d.assign
	d.hash
	d.search
	//base object
	d.root
    d.base
	d.hashobject
	d.searchobject
   *
			
objToKey : 
   * @description returns an array with the object keys
   * @method objToKey
   * @public
   * @static
   * @param {object}  object to be converted
   * @return {array}  array with numeric keys, values are object keys
		
objFlip :
   * @description returns an object with keys and values switched
   * @method objFlip
   * @public
   * @static
   * @param {object}   object to be converted
   * @return {object}  object with oldvalues=>oldkeys
		
objToURL :
   * @description returns a uri-component string
   * @method objToURL
   * @public
   * @static
   * @param {object}   object to be converted to URI
   * @return {string}  URI string

URLtoObj :
   * @description returns an object derived from an URI, seperators are ? and #
   * @method URLtoObj
   * @public
   * @static
   * @param {string}   URI to be converted
   * @param {string}   seperator 1
   * @param {string}   separator 2
   * @return {object}  object name=>value pairs 

//see also Dough Crockford's JSON page www.json.org  
JSONparse :
   * @description parses a JSON string into an object
   * @method JSONparse
   * @public
   * @static
   * @param {string}   string to be converted
   * @param {boolean}  revive
   * @return {object}  object		
		
JSONtoString :
   * @description converst a JSON object into a JSON string
   * @method JSONtoString
   * @public
   * @static
   * @param {object}   object to be converted
   * @return {string}  JSON string		
		
		
/*		
 * cookies, no need for explanation i guess ;-)
 
 * setCookie : function(name, value, expires, path, domain, secure)

 * getCookie : function(name)
		
 * unsetCookie : function(name, path, domain, secure)
		
/* subcookies utilities
		
 * setSubcookie : function(name, subName, value, expires, path, domain, secure)
		
 * setallSubcookie : function(name, subcookies, expires, path, domain, secure)
	
 * getSubcookie : function(name, subName)
		
 * getallSubcookie : function(name)
		
 * unsetSubcookie : function(name, subName, path, domain, secure)
		
 * unsetallSubcookie : function(name, path, domain, secure)

getGlobals	:
   * @description    maps global interface object to local variabeles  ,
   * @method getGlobals
   * @public
   * @static
   * @param {object} | object with variabele names to map
   *                 | ['local var01', 'local var02', '>>' , 'local var03'] {array}
   *                 | '>>' skips one global var for mapping
   * @return {object} mapped local object
   
numberToCurrency 		: 
   * @description format string to currency ,
   * @method numberToCurrency
   * @public
   * @static
   * @param {number}  number
   * @return {string}  formatted string	

mailTo 		: 
   * @description javascript mailto link  ,
   * @method mailTo
   * @public
   * @static
   * @param {object}  	object with maildata
						{ 	"email":{emailadress},
							"subject":{subject},
							"body":{message text}
						}
   * @return {void}	   
   
objXHR 		: 
   * @description returns a crossbrowser XML HTTP Request object,
   * @method objXHR
   * @public
   * @static
   * @return {object}  XML HTTP Request object		

XHRsubmit 		: 
   * @description straightforward XML HTTP Request connection,
   * @method XHRsubmit
   * @public
   * @static
   * @param {string}	url
   * @param {string}	data  post data UIR component
   * @param {string}	mode  post or get
   * @return {object}  XML HTTP Request Result object	   

  //loggerfuncties---------------------------------------
		
assert :
   * @description sets loggermessage according to passed condition
   * @method assert
   * @public
   * @static
   * @param {object}  condition,  usually a function to evaluate
   * @return {string} message to be displayed
		
echo :
   * @description displays message to loggerwindow  example : Util.echo(oResponse, false, 'form.js saveSuccessResult regel 105');
   * loggerwindow can be closed onclick
   * @method echo
   * @public
   * @static
   * @param {string}  item to be displayed
   * @return {boolean} obligated : add,  if argument = true then items will be added to loggerwindow content
   * @param {string}  sender, format document, function, linenumber (eg : 'form.js saveSuccessResult regel 105')
   * @return void

logInit :
   * @description starts logging , generates loggerwindow
   * @method logInit
   * @public
   * @static
   * @param {boolean} || {string} if true then position = relative, loggerwindow is added after normal content. if false or omitted then loggerwindow is draggable,
								  if 'console' then logger output to firebug console,  if 'popup' then logger output to ajax popup window.
   * @return void

*/

//object functies------------------------------------------------
/*
extend :
   * @description extends an object with the properties and methods of another object
   * @method extend
   * @public
   * @static
   * @param {obj}  input
   * @param {obj}  extended object
   * @return {obj} extended object
   
inspect :
   * @description inspect an object by looping  inspect : function(obj, maxLevels, level)
   * @method inspect
   * @public
   * @static
   * @param {obj}  object to be inspected
   * @param {int}  maxLevels, depth of iteration
   * @param {int}  level  startlevel
   * @return {string} html with objectstructure as unordered list  
   
inheritprototype :
   * @description attaches an objects protoype to another, restoring the constructor, useful for constuctor stealing inherit pattern
   * @method inheritprototype
   * @public
   * @static
   * @param {obj}  subtype object
   * @param {obj}  supertype object
   * @return {void} 
   
length :
   * @description returns length of object [number of properties and methods]
   * @method length
   * @public
   * @static
   * @param {obj}  object
   * @return {number}  objectlength
   
   
   
*/

var Util = (function(){
	//PRIVATE STATIC CONSTANTS
	
	var ROOT     /*: string*/ = 'http://localhost/JAVASCRIPT/',
		UTIL     /*: string*/ ='js/utils/';//to do; vanuit loggerOptions

	var CNT_DEBUGGER       /*: string*/ = 'cnt_debugger_message',
		CNT_DEBUGGER_TXT   /*: string*/ = 'cnt_debugger_txt',
		IMG_DEBUGGER_CLEAR /*: string*/ = ROOT+UTIL+'img/clear.gif',
		IMG_DEBUGGER_CLOSE /*: string*/ = ROOT+UTIL+'img/close.gif',
		LOGGERSTYLE_URL    /*: string*/ = ROOT+UTIL+'logger/logger.css';
	
	//PRIVATE STATIC VARS
	var _is_debugger  /*: boolean*/ = false,//true als debugger is geïnitialiseerd
		_is_onscreen  /*: boolean*/ = true,//true als debugger output naar screen
		_is_popup     /*: boolean*/ = false;//true als debugger output naar popup
	
	//PRIVATE STATIC METHODS
	
	
	var _utf8 = {
	
	
	
		encode : function(sPlaintext){
			
			var plaintext = sPlaintext,
				SAFECHARS = "0123456789" +					// Numeric
							"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +	// Alphabetic
							"abcdefghijklmnopqrstuvwxyz" +
							"-_.!~*'()",					// RFC2396 Mark characters
				HEX = "0123456789ABCDEF",
				encoded = "";
				
			for (var i = 0; i < sPlaintext.length; i++ ) {
				var ch = sPlaintext.charAt(i);
				if (ch == " ") {
					encoded += "+";				// x-www-urlencoded, rather than %20
				} 
				else if (SAFECHARS.indexOf(ch) != -1) {
					encoded += ch;
				} 
				else {
					var charCode = ch.charCodeAt(0);
					if (charCode > 255) {
                        /*
						alert( "Unicode Character '" 
								+ ch 
								+ "' cannot be encoded using standard URL encoding.\n" +
								  "(URL encoding only supports 8-bit characters.)\n" +
								  "A space (+) will be substituted." );
                        */
                        
						//encoded += "+";
                        encoded += '|&#'+charCode+';|';
					} 
					else {
						encoded += "%";
						encoded += HEX.charAt((charCode >> 4) & 0xF);
						encoded += HEX.charAt(charCode & 0xF);
					}
				}
			} // for
			return encoded;
		},
	 
		decode : function(sEncoded){
		   
		   var 	encoded = sEncoded,
				HEXCHARS = "0123456789ABCDEFabcdef",
				plaintext = "";
				
		   var i = 0;
		   while (i < encoded.length) {
			   var ch = encoded.charAt(i);
			   if (ch == "+") {
				   plaintext += " ";
				   i++;
			   } 
			   else if (ch == "%") {
					if (i < (encoded.length-2) 
							&& HEXCHARS.indexOf(encoded.charAt(i+1)) != -1 
							&& HEXCHARS.indexOf(encoded.charAt(i+2)) != -1 ) {
						plaintext += unescape( encoded.substr(i,3) );
						i += 3;
					} 
					else {
						//alert( 'Foute escape combinatie bij ...' + encoded.substr(i) );
						plaintext+="%[ERROR]";
						i++;
					}
				} 
				else {
				   plaintext += ch;
				   i++;
				}
			} // while
            
            function convert(value){
                if(_inStr('|&#',value) ){
                    var result='',arr,sub,one,two,code;
                    arr = value.split('|&');
                    for(key in arr){
                    
                        sub=arr[key].split(';|')
                        sub[0]?one=sub[0]:one='';
                        sub[1]?two=sub[1]:two='';
                        
                        if( $.inStr('#',one) && one.length>1 ){
                            code=parseInt( sub[0].replace('#','') );
                            if(typeof(code)==='number'){
                                one=String.fromCharCode(code);
                            }
                        }
                        result+=one+two;
                    }
                    return result;
                }
                else return value;
            };
		   plaintext=convert(plaintext);
		   return plaintext;
		}
	};
    
	var _addListener = function(elem, evtType, callback) {
        if (elem.addEventListener) {
            elem.addEventListener(evtType, callback, false);
        } 
		else if (elem.attachEvent) {
            elem.attachEvent("on" + evtType, callback);
        } 
		else {
            elem["on" + evtType] = callback;
        }
    };
	
	
  
    var _removeListener = function(elem, evtType, callback){
        if (elem.removeEventListener) {
          elem.removeEventListener(evtType, callback, false);
        } 
		else if (elem.detachEvent) {
          elem.detachEvent("on" + evtType, callback, false);
        }
		else {
			elem["on" + evtType] = null;
		}
    };
	
	var _getEvent = function(event){
        return event || window.event;
    };
	
	var _getTarget = function(event){
        return event.target || event.srcElement;
    };
	
	//functies vanwege loggerwindow drag
	var _offsetX, _offsetY;
	
	var _startDrag = function(event){
		event=_getEvent(event);
		var t=_getTarget(event);
		
		if(t.id==CNT_DEBUGGER){
			_addListener(t, 'mousemove', _handleMove);
			_addListener(t, 'mouseup', _stopDrag);
			var mouse={};
			mouse.x = event.pageX || event.clientX; 
			mouse.y = event.pageY || event.clientY;
			_offsetX = mouse.x - parseInt(t.style.left);
			_offsetY = mouse.y - parseInt(t.style.top);
		}
		
	};
	
	var _stopDrag = function(event){
		event=_getEvent(event);
		var t=_getTarget(event);
		
		if(t.id==CNT_DEBUGGER){
			_removeListener(t, "mousemove", _handleMove);
			_removeListener(t, "mouseup", _stopDrag);
		}
		
	};
	
	var _handleMove = function(event){
		event=_getEvent(event);
		var t=_getTarget(event);
		
		if(t.id==CNT_DEBUGGER){
			var x,y,mouse={};
			mouse.x = event.pageX || event.clientX; 
			mouse.y = event.pageY || event.clientY;
			x = mouse.x - _offsetX;
			t.style.left = x + "px";
			y = mouse.y - _offsetY;
			t.style.top = y + "px";
		}
	};
	
	var _getViewport = function(){
        if (self.innerWidth)
    	{
    		frameWidth = self.innerWidth;
    		frameHeight = self.innerHeight;
    		scroll_left = pageXOffset;
    		scroll_top = pageYOffset;
    	}
    	else if (document.documentElement && document.documentElement.clientWidth)
    	{
    		frameWidth = document.documentElement.clientWidth;
    		frameHeight = document.documentElement.clientHeight;
    		scroll_left = document.documentElement.scrollLeft;
    		scroll_top = document.documentElement.scrollTop;
    		
    	}
    	else if (document.body)
    	{
    		frameWidth = document.body.clientWidth;
    		frameHeight = document.body.clientHeight;
    		scroll_left = document.body.scrollLeft;
    		scroll_top = document.body.scrollTop;
    	}
    	else {return false;}
    	var centerX = frameWidth/2 + scroll_left;
    	var centerY = frameHeight/2 + scroll_top;
    	return{
    	   "width"     : frameWidth,
    	   "height"    : frameHeight,
    	   "scrleft"   : scroll_left,
    	   "scrtop"    : scroll_top,
    	   "centX"      : centerX,
    	   "centY"      : centerY
    	};
    	
    	
        

	
	
	};
	
	var _mail = function(oJson){
	        if( typeof(oJson)==='string' ){
	        eval("var obj = " + oJson);
	    }
	    else{
	        var obj = oJson;
	    }
	        var mailto_link = 'mailto:'+obj.email+'?subject='+obj.subject+'&body='+obj.message;
	        var win = window.open(mailto_link,'emailWindow', 'left=50000,top=50000,width=0,height=0'); 
            if (win && win.open &&!win.closed){
                win.close();
            }     
	};
    
    var _print = function(elementId){

        var printContent = o.getRef(elementId),
            windowUrl = 'about:blank',
            uniqueName = new Date(),
            windowName = 'Print' + uniqueName.getTime(),
            printWindow = window.open(windowUrl, windowName, 'left=50000,top=50000,width=0,height=0');

        printWindow.document.write(printContent.innerHTML);
        printWindow.document.close();
        printWindow.focus();
        printWindow.print();
        printWindow.close();
    };

	
	var _arrayToObj = function(aIn,bsMode /*{boolean}||{string}*/){
		/* array  a[1]='aaaa',  a[2]='bbbb'  etc
		 * bsMode : { 1 : 'aaaa', 2 : 'bbbb'}
		 * reverse : { 'aaaa' : 1,  'bbbb' : 2} equal keys => value with original highest key
         * bsMode = {string}  : { 'aaaa' : {string},  'bbbb' : {string}}
		*/
		
		var len=aIn.length,
			oRet={},
			t=0;
        if(typeof(bsMode)==='undefined'){bsMode=''}
        if(typeof(bsMode)==='boolean'){
            for(t;t<len;t++){
                if(bsMode){
                    oRet[t]=aIn[t];
                }
                else{
                    oRet[ aIn[t] ]=t;
                }
            }
        }
        else{//string,number,object
            for(t;t<len;t++){
                oRet[ aIn[t] ]= bsMode; 
            }
        }
		
		return oRet;
	};
	
	var _objToArray = function(obj){
	    
		var aKey=[],
		    aValue=[],
		    t=0;
		for(name in obj){
			aKey[t]=name;
			aValue[t]=obj[name];
			t++;
		}
		return {"key" : aKey, "val" : aValue};
		
	};
    
    var _arrayMerge = function(destination, source){
        var oSource=_arrayToObj(source),
            oDestination=_arrayToObj(destination);    
        oBject.extend(oDestination, oSource);
        return _objToArray(oDestination).key;
    

    
    };
	
	var _strToObj = function(sIn, sSep, bNumberKey){
		//default separator=" + "
		var aStr=[];
		
		if(sIn==='' || typeof(sIn)!=='string'){
			return {};
		}
		switch(typeof(sSep)){
			case 'boolean' :
				bNumberKey=sSep;
				sSep='+';
				break;
				
			case 'undefined' :
				sSep='+';
				break;
		}
		aStr=sIn.split(sSep);
		return _arrayToObj(aStr, bNumberKey);
	};
	
	var _serialize = function(obj, maxLevels, level){
		    var str = '', 
		        type, 
		        msg;
			// Don't touch, we start iterating at level zero
			if(level == null)  level = 0;
			if(maxLevels == null) maxLevels = 1;
			
			if(maxLevels < 1)     
				return '&error=level_gt_zero';

			// We start with a non null object
			if(obj == null)
			return '&error=object_is_null';
			// End Input Validations

			// Start iterations for all objects in obj
			for(property in obj){
			  try
			  {
				  // Show "property" and "type property"
				  type =  typeof(obj[property]);
                  switch (type) {
                      case 'function' :
                        obj[property]='function';
                        break;
                      case 'string' :
                        
                        break;
                      case 'object' :
        
                        break;
                  }
                  if( !(type=='function' || type=='object' ) ){
                     str += '&' +property + (   (obj[property]==null)?(': =null'):( '='+ obj[property] )   ); 
                  }
                  
				  // We keep iterating if this property is an Object, non null
				  // and we are inside the required number of levels
				  if((type == 'object') && (obj[property] != null) && (level+1 < maxLevels))
				  str += _serialize(obj[property], maxLevels, level+1);
			  }
			  catch(err){
				// Is there some properties in obj we can't access? Print it red.
				if(typeof(err) == 'string') msg = err;
				else if(err.message)        msg = err.message;
				else if(err.description)    msg = err.description;
				else                        msg = 'unknown';

				str += '&error_' + property + '= ' + msg;
			  }
			}
			return str;
		};
		
		
		var _serializePHP = function(sMelding, iLevels){
			var m='', txt, sender, levels,type;
			
			typeof(sSender)== 'undefined' ? sender='' : sender=sSender;
			typeof(iLevels)== 'undefined' ? levels=1 : levels=iLevels;
			
			type=o.getExactType(sMelding);
			
			switch(type){
				case 'String' :
				case 'Number' :
					m=sMelding+'<br><br>';
					break;
				case 'Object' :
					m='<br><br><b> object ['+oBject.length(sMelding)+']</b><br>'
					m+=_inspect(sMelding,levels);//object inspect met maxlevels
					break;
				case 'Undefined' :
					m='type = undefined';
					break;
					
			}
			
			
			
			function _inspect(obj, maxLevels, level){
					  var str = '', type,proptype,exacttype, msg;

						// Start Input Validations
						// Don't touch, we start iterating at level zero
						if(level == null)  level = 0;

						// At least you want to show the first level
						if(maxLevels == null) maxLevels = 1;
						if(maxLevels < 1)     
							return '<font color="red">Error: Levels number must be > 0</font><br><br>';

						// We start with a non null object
						if(obj == null)
						return '<font color="red">Error: Object <b>NULL</b></font><br><br>';
						// End Input Validations
						
						// Each Iteration must be indented
						str += '<ul>';
						// Start iterations for all objects in obj
						for(property in obj){
						  try
						  {
							  // Show "property" and "type property"
							  
								type=o.getExactType(obj[property]);
								var lengte='',display='';
								
								display=obj[property];
								
								if( (type == 'Array') ){
									lengte=' ['+obj[property].length+']';
									display='';
								}
								if( (type == 'Object') ){
									lengte=' ['+oBject.length(obj[property])+']';
									display='';
								}
							  
							  
							  proptype = typeof(property)

							  str += '<li>(' + proptype + ') ' + property + 
									 ( (obj[property]==null)?(': <b>null</b>'):('&nbsp;:<span style="color:green;font-size:0.9em;">&nbsp;('+type+''+lengte+')&nbsp;'+display+'</span>')) + '</li>';

							  // We keep iterating if this property is an Object, non null
							  // and we are inside the required number of levels
							  if((type == 'Object'  || type=='Array') && (obj[property] != null) && (level+1 < maxLevels)) {
								str += _inspect(obj[property], maxLevels, level+1);
							  }
						  }
						  catch(err){
							// Is there some properties in obj we can't access? Print it red.
							if(typeof(err) == 'string') msg = err;
							else if(err.message)        msg = err.message;
							else if(err.description)    msg = err.description;
							else                        msg = 'Unknown';

							str += '<li><font color="red">(Error) ' + property + ': ' + msg +'</font></li>';
						  }
						}

						  // Close indent
						  str += '</ul>';

						return str;
					};

		
			return m;
			
		};
		
		var _getURLbase = function(href){
		
			var host={},
				o={},
				parts,isQ,isH;
			
			isQ=href.indexOf('?');
			if(isQ > -1){
				href=href.substr(0,isQ);
			}
			isH=href.indexOf('#');
			if(isH > -1){
				href=href.substr(0,isH);
			}
			try
			{
				//root
				parts=href.split('/');
				parts.pop();
				o.root=parts.join('/')+'/';
				//protocol
				parts=href.split('//');
				o.protocol=parts[0];
				//host,hostname
				host=parts[1].split('/');
				o.host=host.shift();
				o.hostname=o.host;
				//pathname
				o.pathname='/'+host.join('/');
				//base
				o.base=o.protocol+'//'+o.host+'/';
				return o;
			}
			catch(e){
				return '';
			}
		};
		
	var _getURLparam = function(href,fix){
			//href [#name1=value1&name2=value2] naar object { name1 : value1, name2 : value2 }
			if(!href){
				href=window.location.href;
			}
			var re={},obj={},qu;
			var p={ '?':'#','#':'?'};
			re.resultobject=[];
			if(href.indexOf(fix)> -1){
				qu=href.split(fix)[1];
				if(qu.indexOf(p[fix]) > -1){
					re.resultstring=qu.substr(0,qu.indexOf(p[fix]));
				}
				else{
					re.resultstring=qu;
				}
				obj=o.URLtoObj(re.resultstring);
				oBject.extend(re.resultobject,obj);
			}
			re.href=href;
			return re;
		};
		
		
    var _getGlobals = function(obj){//global object is GL
		   
		    if(typeof(obj)==='undefined'){
		        return GL;
		    }
		    if(obj instanceof Object || obj instanceof Array){
		        var ret={},t=0;
		        
		        for(name in GL){
		            if( typeof(obj[t])!=='undefined'){
		              if(obj[t]!=='>>'){
		                  ret[obj[t]]=GL[name];
		              }
		              t++;
		            }
		            else{
		                ret[name]=GL[name];
		            }
		        }
		        return ret;
		    }
	};
    
    var _setGlobals = function(obj){
        
        for(name in GL){
	    if( typeof(obj[name])!=='undefined'){
	               GL[name]=obj[name];
	           }
	       }
    };
    
    var _getLocalStorage = function(){
    
        if (typeof localStorage == "object"){
            return localStorage;
        } else if (typeof globalStorage == "object"){
            return globalStorage[location.host];
        } else {
            throw new Error("Local storage not available.");
        }
    };
    
    var _getClientKeys = function(seed){
        var globals = _getGlobals(),
            oSafe   = {
                        "useragent"      : o.getUserAgent()  
                      },
        oSafe=oBject.extend(oSafe,globals);
        typeof(seed)!=='undefined' ? oSafe.seed=seed:void(0);
        oSafe.hash=MD5.hex_md5(_serialize(oSafe));
        
        return oSafe;
    };
    
    var _baseConvert = {
    
        d2h : function(j){
        
            var hexchars =  "0123456789ABCDEF";
            var hv = "";
            for (var i=0; i< 4; i++)
              {
                k = j & 15;
                hv = hexchars.charAt(k) + hv;
                j = j >> 4;
              }
            return hv;  
        },

        h2d : function(value){
          var j = value.toUpperCase();
          var d = 0;
          var ch = ' ';
          var hexchars =  "0123456789ABCDEF";
          while (j.length < 4) j = 0 + j;
          for (var i = 0; i < 4; i++)
            {
              ch = j.charAt(i);
              d = d*16 + hexchars.indexOf(ch); 
            }
            return d;
        }
    };
		
	//JSON---------------------------
	var _JSON = {
		
		stringify: function (arg) {
			var c, i, l, s = '', v;

			switch (typeof arg) {
			case 'object':
				if (arg) {
					if (arg.constructor == Array) {
						for (i = 0; i < arg.length; ++i) {
							v = this.stringify(arg[i]);
							if (s) {
								s += ',';
							}
							s += v;
						}
						return '[' + s + ']';
					} else if (typeof arg.toString != 'undefined') {
						for (i in arg) {
							v = arg[i];
							if (typeof v != 'undefined' && typeof v != 'function') {
								v = this.stringify(v);
								if (s) {
									s += ',';
								}
								s += this.stringify(i) + ':' + v;
							}
						}
						return '{' + s + '}';
					}
				}
				return 'null';
			case 'number':
				return isFinite(arg) ? String(arg) : 'null';
			case 'string':
				l = arg.length;
				s = '"';
				for (i = 0; i < l; i += 1) {
					c = arg.charAt(i);
					if (c >= ' ') {
						if (c == '\\' || c == '"') {
							s += '\\';
						}
						s += c;
					} else {
						switch (c) {
							case '\b':
								s += '\\b';
								break;
							case '\f':
								s += '\\f';
								break;
							case '\n':
								s += '\\n';
								break;
							case '\r':
								s += '\\r';
								break;
							case '\t':
								s += '\\t';
								break;
							default:
								c = c.charCodeAt();
								s += '\\u00' + Math.floor(c / 16).toString(16) +
									(c % 16).toString(16);
						}
					}
				}
				return s + '"';
			case 'boolean':
				return String(arg);
			default:
				return 'null';
			}
		},
		parse: function (text,revive) {
			var at = 0,
				ch = ' ';
				
			(typeof(revive)=='undefined')? revive=false:void(0);

			function error(m) {
				throw {
					name: 'JSONError',
					message: m,
					at: at - 1,
					text: text
				};
			}

			function next() {
				ch = text.charAt(at);
				at += 1;
				return ch;
			}

			function white() {
				while (ch) {
					if (ch <= ' ') {
						next();
					} else if (ch == '/') {
						switch (next()) {
							case '/':
								while (next() && ch != '\n' && ch != '\r') {}
								break;
							case '*':
								next();
								for (;;) {
									if (ch) {
										if (ch == '*') {
											if (next() == '/') {
												next();
												break;
											}
										} else {
											next();
										}
									} else {
										error("Unterminated comment");
									}
								}
								break;
							default:
								error("Syntax error");
						}
					} else {
						break;
					}
				}
			}

			function string() {
				var i, s = '', t, u;

				if (ch == '"') {
outer:          while (next()) {
						if (ch == '"') {
							next();
							return s;
						} else if (ch == '\\') {
							switch (next()) {
							case 'b':
								s += '\b';
								break;
							case 'f':
								s += '\f';
								break;
							case 'n':
								s += '\n';
								break;
							case 'r':
								s += '\r';
								break;
							case 't':
								s += '\t';
								break;
							case 'u':
								u = 0;
								for (i = 0; i < 4; i += 1) {
									t = parseInt(next(), 16);
									if (!isFinite(t)) {
										break outer;
									}
									u = u * 16 + t;
								}
								s += String.fromCharCode(u);
								break;
							default:
								s += ch;
							}
						} else {
							s += ch;
						}
					}
				}
				error("Bad string");
			}

			function array() {
				var a = [];

				if (ch == '[') {
					next();
					white();
					if (ch == ']') {
						next();
						return a;
					}
					while (ch) {
						a.push(value());
						white();
						if (ch == ']') {
							next();
							return a;
						} else if (ch != ',') {
							break;
						}
						next();
						white();
					}
				}
				error("Bad array");
			}

			function object() {
				var k, o = {};

				if (ch == '{') {
					next();
					white();
					if (ch == '}') {
						next();
						return o;
					}
					while (ch) {
						k = string();
						white();
						if (ch != ':') {
							break;
						}
						next();
						o[k] = value();
						white();
						if (ch == '}') {
							next();
							return o;
						} else if (ch != ',') {
							break;
						}
						next();
						white();
					}
				}
				error("Bad object");
			}

			function number() {
				var n = '', v;
				if (ch == '-') {
					n = '-';
					next();
				}
				while (ch >= '0' && ch <= '9') {
					n += ch;
					next();
				}
				if (ch == '.') {
					n += '.';
					while (next() && ch >= '0' && ch <= '9') {
						n += ch;
					}
				}
				if (ch == 'e' || ch == 'E') {
					n += 'e';
					next();
					if (ch == '-' || ch == '+') {
						n += ch;
						next();
					}
					while (ch >= '0' && ch <= '9') {
						n += ch;
						next();
					}
				}
				v = +n;
				if (!isFinite(v)) {
					////error("Bad number");
				} else {
					return v;
				}
			}

			function word() {
				switch (ch) {
					case 't':
						if (next() == 'r' && next() == 'u' && next() == 'e') {
							next();
							return true;
						}
						break;
					case 'f':
						if (next() == 'a' && next() == 'l' && next() == 's' &&
								next() == 'e') {
							next();
							return false;
						}
						break;
					case 'n':
						if (next() == 'u' && next() == 'l' && next() == 'l') {
							next();
							return null;
						}
						break;
				}
				error("Syntax error");
			}

			function value() {
				white();
				switch (ch) {
					case '{':
						return object();
					case '[':
						return array();
					case '"':
						return string();
					case '-':
						return number();
					default:
						return ch >= '0' && ch <= '9' ? number() : word();
				}
			}
			
			if(revive){
				return eval( value())
			}
			else {
				return value();
			}
		}
	};
	
//base64
    var _txtToCharCode = function(value){
		var result='',arr,code;
		
        arr = value.split('');
        for(key in arr){
            code=arr[key].charCodeAt(0);
            if( code==32||(code>47&&code<58)||(code>67&&code<91)||(code>96&&code<123) ){//only A-Z, a-z, 0-9, space
                result+=arr[key];
            }
            else{
                result+='&#'+arr[key].charCodeAt(0)+';';
            }
        }
		return result;
    };
    
    var _charcodeToTxt = function(value){
		var result='',arr,sub,one,two,code;
		
        arr = value.split('&');
        for(key in arr){
        
            sub=arr[key].split(';')
            sub[0]?one=sub[0]:one='';
            sub[1]?two=sub[1]:two='';
            
            if( _inStr('#',one) && one.length>1 ){
                code=parseInt( sub[0].replace('#','') );
                if(typeof(code)==='number'){
                    one=String.fromCharCode(code);
                }
            }
            result+=one+two;
        }
		return result;
    };

	var _base64 = {
	
		keyStr : "ABCDEFGHIJKLMNOP" +
				 "QRSTUVWXYZabcdef" +
				 "ghijklmnopqrstuv" +
				 "wxyz0123456789+/" +
				 "=",

	   encode : function(input,safe) {
		  var output = "";
          if(input===''){
              return '';
          }
		  var chr1, chr2, chr3 = "";
		  var enc1, enc2, enc3, enc4 = "";
		  var i = 0;
          if(safe){
              input=_txtToCharCode(input);
          }
		  do {
			 chr1 = input.charCodeAt(i++);
			 chr2 = input.charCodeAt(i++);
			 chr3 = input.charCodeAt(i++);

			 enc1 = chr1 >> 2;
			 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			 enc4 = chr3 & 63;

			 if (isNaN(chr2)) {
				enc3 = enc4 = 64;
			 } else if (isNaN(chr3)) {
				enc4 = 64;
			 }

			 output = output +
				this.keyStr.charAt(enc1) +
				this.keyStr.charAt(enc2) +
				this.keyStr.charAt(enc3) +
				this.keyStr.charAt(enc4);
			 chr1 = chr2 = chr3 = "";
			 enc1 = enc2 = enc3 = enc4 = "";
		  } while (i < input.length);

		  return output;
	   },

	   decode : function(input, safe) {
			  var output = "";
              if(input===''){
                  return '';
              }
			  var chr1, chr2, chr3 = "";
			  var enc1, enc2, enc3, enc4 = "";
			  var i = 0;

			  // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
			  var base64test = /[^A-Za-z0-9\+\/\=]/g;
			  if (base64test.exec(input)) {
				 alert("There were invalid base64 characters in the input text.\n" +
					   "Valid base64 characters are A-Z, a-z, 0-9, +, /, and =\n" +
					   "Expect errors in decoding.");
			  }
			  input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

			 do 
			 {
				 enc1 = this.keyStr.indexOf(input.charAt(i++));
				 enc2 = this.keyStr.indexOf(input.charAt(i++));
				 enc3 = this.keyStr.indexOf(input.charAt(i++));
				 enc4 = this.keyStr.indexOf(input.charAt(i++));

				 chr1 = (enc1 << 2) | (enc2 >> 4);
				 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
				 chr3 = ((enc3 & 3) << 6) | enc4;

				 output = output + String.fromCharCode(chr1);

				 if (enc3 != 64) {
					output = output + String.fromCharCode(chr2);
				 }
				 if (enc4 != 64) {
					output = output + String.fromCharCode(chr3);
				 }

				 chr1 = chr2 = chr3 = "";
				 enc1 = enc2 = enc3 = enc4 = "";

			} while (i < input.length);
            
            if(safe){
                output=_charcodeToTxt(output);
            }
			return output;
		}
	};
	
	var _createXHR = function(){
            if (typeof XMLHttpRequest != "undefined"){
                _createXHR = function(){
                    return new XMLHttpRequest();
                };
            } else if (typeof ActiveXObject != "undefined"){
                _createXHR = function(){                    
                    if (typeof arguments.callee.activeXString != "string"){
                        var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0",
                                        "MSXML2.XMLHttp"];
                
                        for (var i=0,len=versions.length; i < len; i++){
                            try {
                                var xhr = new ActiveXObject(versions[i]);
                                arguments.callee.activeXString = versions[i];
                                return xhr;
                            } catch (ex){
                                //skip
                            }
                        }
                    }
                
                    return new ActiveXObject(arguments.callee.activeXString);
                };
            } else {
                _createXHR = function(){
                    throw new Error("No XHR object available.");
                };
            }
            
            return _createXHR();
    };
	
	var _postLoggerData = function(url,data,mode){
		var xhr = _createXHR();
		xhr.onreadystatechange = function () {
			if (xhr.readyState == 4) {
				if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
					xhr.data=xhr.responseText;
					return xhr;
				}
				else {
					xhr.error=xhr.status;
					return xhr;
				}
			}            
        };
		  
        xhr.open("post", url, true);
		xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 
		data=o.safeHTML(data);
        xhr.send("mode="+mode+"&data="+data);
	};
	
	var _postData = function(url,data,mode){
		typeof(mode)=='undefined'?mode='get':void(0);
		typeof(data)=='undefined'?data=null:void(0);
		var xhr = _createXHR(),
			send,
			obj=xhr;
		xhr.onreadystatechange = function (event) {
			if (xhr.readyState == 4) {
				if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
					xhr.data=xhr.responseText;
					return xhr;
				}
				else{
					xhr.error=xhr.status;
					return xhr;
				}
			}            
        };
		 
        xhr.open(mode, url, true);
		xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		if(data===null){
			send=null;
		}
		else{
			data=o.safeHTML(data);
			send="data="+data;
		}
        xhr.send(send);
	};
	//cookies
	var _cookie = {

		get: function (name){
			var cookieName = encodeURIComponent(name) + "=",
				cookieStart = document.cookie.indexOf(cookieName),
				cookieValue = null;
				
			if (cookieStart > -1){
				var cookieEnd = document.cookie.indexOf(";", cookieStart)
				if (cookieEnd == -1){
					cookieEnd = document.cookie.length;
				}
				cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));
			} 

			return cookieValue;
		},
		
		set: function (name, value, expires, path, domain, secure) {
			var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value);
		
			if (expires instanceof Date) {
				cookieText += "; expires=" + expires.toGMTString();
			}
		
			if (path) {
				cookieText += "; path=" + path;
			}
		
			if (domain) {
				cookieText += "; domain=" + domain;
			}
		
			if (secure) {
				cookieText += "; secure";
			}
		
			document.cookie = cookieText;
			return cookieText;
		},
		
		unset: function (name, path, domain, secure){
			this.set(name, "", new Date(0), path, domain, secure);
			return null;
		}

	};
	
	var _subcookie = {

		get: function (name, subName){
			var subCookies = this.getAll(name);
			if (subCookies){
				return subCookies[subName];
			} else {
				return null;
			}
		},
		
		getAll: function(name){
			var cookieName = encodeURIComponent(name) + "=",
				cookieStart = document.cookie.indexOf(cookieName),
				cookieValue = null,
				result = {};
				
			if (cookieStart > -1){
				var cookieEnd = document.cookie.indexOf(";", cookieStart)
				if (cookieEnd == -1){
					cookieEnd = document.cookie.length;
				}
				cookieValue = document.cookie.substring(cookieStart + cookieName.length, cookieEnd);
				
				if (cookieValue.length > 0){
					var subCookies = cookieValue.split("&");
					
					for (var i=0, len=subCookies.length; i < len; i++){
						var parts = subCookies[i].split("=");
						result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
					}
		
					return result;
				}  
			} 

			return null;
		},
		
		set: function (name, subName, value, expires, path, domain, secure) {
		
			var subcookies = this.getAll(name) || {};
			subcookies[subName] = value;
			this.setAll(name, subcookies, expires, path, domain, secure);

		},
		
		setAll: function(name, subcookies, expires, path, domain, secure){
		
			var cookieText = encodeURIComponent(name) + "=";
			var subcookieParts = new Array();
			
			for (var subName in subcookies){
				if (subName.length > 0 && subcookies.hasOwnProperty(subName)){
					subcookieParts.push(encodeURIComponent(subName) + "=" + encodeURIComponent(subcookies[subName]));
				}
			}
			
			if (subcookieParts.length > 0){
				cookieText += subcookieParts.join("&");
					
				if (expires instanceof Date) {
					cookieText += "; expires=" + expires.toGMTString();
				}
			
				if (path) {
					cookieText += "; path=" + path;
				}
			
				if (domain) {
					cookieText += "; domain=" + domain;
				}
			
				if (secure) {
					cookieText += "; secure";
				}
			} else {
				cookieText += "; expires=" + (new Date(0)).toGMTString();
			}
		
			document.cookie = cookieText;        
			return cookieText;
		},
		
		unset: function (name, subName, path, domain, secure){
			var subcookies = this.getAll(name);
			if (subcookies){
				delete subcookies[subName];
				this.setAll(name, subcookies, null, path, domain, secure);
			}
		},
		
		unsetAll: function(name, path, domain, secure){
			this.setAll(name, null, new Date(0), path, domain, secure);
		}

	};
    
    var _inStr = function(n,h){
        return h.indexOf(n)!=-1;
    };
    
    var _inArray = function(n,h){
        var r=false;
        for(k in h){
            if(n===h[k]) r=true;
        }
        return r;
    };
	//=======================================================
	//PUBLIC METHODS
	
	var o = {
    
        GL : {},//global object
	
		getVal 		: function(id){ return this.getRef(id).value; },
		
		setVal 		: function(id,cn){ this.getRef(id) ? this.getRef(id).value=cn : void(0); },
		
		setHTML		: function(id,cn){ this.getRef(id) ? this.getRef(id).innerHTML=cn : void(0); },
		
		getHTML		: function(id){ 
							if(this.getRef(id)){
								return this.getRef(id).innerHTML
							}
							else {
								return false;
							}
					},
					
		getRef 		: function(obj){
							
							if(typeof obj == "string"){
								obj=obj.replace('#','');
								if( document.getElementById(obj)){
									return document.getElementById(obj);
								}
								else if(document.getElementsByName(obj)[0]){
											return document.getElementsByName(obj)[0];
									  }
									  else if(document.getElementsByTagName(obj)[0]){
											return document.getElementsByTagName(obj)[0];
									  }
									  else {
											return false;
									  }
							} 
							else {
								return obj;
							}
					  },
		
		setStyle	: function(obj,style,value){
		                
		                if(typeof(value)==='number'){
		                    value+='px';
		                }
                        try{
                            this.getRef(obj).style[style]= value;
                        } catch(e){}
					  },
					  
		getStyle	: function(obj,style){
                        try{
                            return this.getRef(obj).style[style];
                        }
                        catch(e){}
					  },
		
		doShow		: function(o,time){
						var that=this;
						var show=function(){ that.setStyle(o,'display','block');}
						var hide=function(){ that.doHide(o);}
				
						if(time)
						{
							show();
							setTimeout(hide,time);
						} else {
							show();
						}
					  },
			
		doHide		: function(o){
						this.setStyle(o,'display','none');
					  },
					  
		doShowHide	: function(o,flgVisible){//visible
						if(flgVisible){
							if( this.getStyle(o,'visibility')=='' || this.getStyle(o,'visibility')=='visible'  ){
								this.setStyle(o,'visibility','visible');
							}
							else{
								this.setStyle(o,'visibility','hidden');
							}
						}
						else{
							if( this.getStyle(o,'display')=='' || this.getStyle(o,'display')=='none'  ){
								this.setStyle(o,'display','block');
							}
							else{
								this.setStyle(o,'display','none');
							}
						}
					  },
					  
		addClass	: function(o,className){
						this.getRef(o).className=className;
					  },
					  
		addStylesheet : function(url){
							if(document.createStyleSheet) {
								document.createStyleSheet(url);
							}
							else {
								var sheet=document.createElement('link');
								sheet.rel='stylesheet';
								sheet.href=url;
								this.getRef('head').appendChild(sheet);
							}
					  },
					  
		setFocus	: function(o) {
						this.getRef(o).focus();
					  },
					  
		selectText	: function(textbox, startIndex, stopIndex) {
							var textbox=this.getRef(textbox);
							if(!stopIndex){
								var stopIndex=parseInt(textbox.value.length);
							}
							if (textbox.setSelectionRange){
								textbox.setSelectionRange(startIndex, stopIndex);
							} else if (textbox.createTextRange){
								var range = textbox.createTextRange();
								range.collapse(true);
								range.moveStart("character", startIndex);
								range.moveEnd("character", stopIndex - startIndex);
								range.select();                    
							}
							textbox.focus();
						},
					  
		//======== helpers ===========

		posX	 	: function(obj){
						var o = this.getRef(obj),
							curleft = 0;

						  if (o.offsetParent)  {
							while (o.offsetParent) {
							  curleft += o.offsetLeft;
							  o = o.offsetParent;
							}
						  }
						  else if (o.x){
							curleft += o.x;
						  }
						  return curleft;
		},

		posY		: function(obj) {
						var o = this.getRef(obj),
							curtop = 0;

						  if (o.offsetParent)  {
							while (o.offsetParent) {
							  curtop += o.offsetTop;
							  o = o.offsetParent;
							}
						  }
						  else if (o.y){
							curtop += o.y;
						  }
						  return curtop;
		},
						
        getViewport : function(){
            return _getViewport();
        },

		URIencode : function (string) {
			return escape(_utf8.encode(string));
		},

		URIdecode : function (string) {
			return _utf8.decode(unescape(string));
		},
		
		encode_utf8 : function(s){
			return _utf8.encode(s);
		},
		
		decode_utf8 : function(s){
			return _utf8.decode(s);
		},
		
		base64encode : function(str,safe){
			return _base64.encode(str,safe);
		},
		
		base64decode : function(str,safe){
			return _base64.decode(str,safe);
		},
        
        txtToCharCode : function(txt){
            return _txtToCharCode(txt);
        },
        
        charCodeToTxt : function(code){
            return _charcodeToTxt(code);
        },

		safeHTML : function(html){
			return _base64.encode( _utf8.encode(html) );
		},

		safeURI : function(uri,mode){
            typeof(mode)==='undefined'||mode==='' ||!mode ? mode='false':void(0);
			uri=this.URLtoObj(uri);//make object
			uri=_JSON.stringify(uri);//object to string
            switch(mode){
                case 'base64':
                    uri=_base64.encode(uri);//base64encode
                    break;
                case 'base64safe':
                    uri=_base64.encode(uri,true);//base64encode
                    break;
            }
			return uri;
		},
		
		safeObjToURI : function(obj){
			var uri=_JSON.stringify(obj);//object to string
			uri=_base64.encode(uri);//base64encode
			return uri;
		},
		
		isArray : function(array){ 
			return !!(array && array.constructor == Array); 
		},
		
		isNumber : function(x){ 
			return ( (typeof x === typeof 1) && (null !== x) && isFinite(x) );
		},
		
		in_str : function(needle,haystack){
			return _inStr(needle,haystack);
		},
        
        in_array : function(needle,haystack){
            return _inArray(needle,haystack);
        },
		
		getExactType : function(obj) {
			var nativeType=(typeof(obj)).slice(0,1).toUpperCase() + (typeof(obj)).slice(1);
			try {
				if (obj.constructor) {
					var strType;
					strType = obj.constructor.toString().match(/function (\w*)/)[1];
					if (strType.replace(' ','') == '') strType = 'n/a';			//Mozilla needs this
					if ( ! (strType in oc(['Array','Boolean','Date','Enumerator','Error','Function','Number','RegExp','String','VBArray'])) ) {
						strType = 'Object';
					}
					return strType;
				} else {//native
					return nativeType;
				}
			} catch(e) {
				return nativeType;
			}
			
			function oc(a) {
				var o = {};
				for(var i=0;i<a.length;i++) {
					o[a[i]]='';
				}
				return o;
			}
		},
		
		objToArray : function(oInput){
		    return _objToArray(oInput);
		},

		arrayToObj : function(aInput,bNumberKey){//returns {"key" : aKey, "val" : aValue}
			return _arrayToObj(aInput,bNumberKey);
		},
        
        array_merge : function(destination, source){
            return _arrayMerge(destination, source);
        },
	
		strToObj : function(sInput, sSeparator, bNumberKey){
			return _strToObj(sInput, sSeparator, bNumberKey);
		},
		
		removeHTMLTags : function(strInputCode){
				var result;
				strInputCode = strInputCode.replace(/&(lt|gt);/g, function (strMatch, p1){
					return (p1 == "lt")? "<" : ">";
				});
				result=strInputCode;
				result=result.replace(/(&nbsp;)/g, ' ');
				result=result.replace(/<ul>/g, '\n');
				result=result.replace(/<li>/g, '\t');
				result=result.replace(/<\/li>/g, '\n');
				result=result.replace(/<\/ul>/g, '\n\n');
				result=result.replace(/<\/?[^>]+(>|$)/g, "");	
				
				return result;	
		},

		/*
stringFormat example:
document.write( String.format( "no tokens<br />" ) );
document.write( String.format( "one token, no args ({0})<br />" ) );
document.write( String.format( "one token, one args ({0})<br />", "arg1" ) );
document.write( String.format( "one tokens, two args ({0})<br />", "arg1", "arg2" ) );
document.write( String.format( "two tokens, two args ({0},{1})<br />", "arg1", "arg2" ) );
document.write( String.format( "two tokens swapped, two args ({1},{0})<br />", "arg1", "arg2" ) );
document.write( String.format( "four tokens interwoven, two args ({0},{1},{0},{1})<br />", "arg1", "arg2" ) );
*/

        stringFormat : function( text ){
        
            //check if there are two arguments in the arguments list
            if ( arguments.length <= 1 )
            {
                //if there are not 2 or more arguments there's nothing to replace
                //just return the original text
                return text;
            }
            //decrement to move to the second argument in the array
            var tokenCount = arguments.length - 2;
            for( var token = 0; token <= tokenCount; token++ )
            {
                //iterate through the tokens and replace their placeholders from the original text in order
                text = text.replace( new RegExp( "\\{" + token + "\\}", "gi" ),
                                                        arguments[ token + 1 ] );
            }
            return text;
        },
		intOnly : function(event){
			var key;
			var keychar;
			 
			if (window.event){
			   key = window.event.keyCode;
			}
			else if(e){
			   key = event.which;
			}
			else{
			   return true;
			}
			keychar = String.fromCharCode(key);
			
			if ((key==null) || (key==0) || (key==8) || (key==9) || (key==13) || (key==27) ){
			   return true;
			}
			else if ((("0123456789").indexOf(keychar) > -1)){
			   return true;
			}
			else{
			   return false;
			}
		},
		
		goTo : function (url,get,d){
			if(get){
				var location=this.getLocation();
				if( url.indexOf('/') == -1){
					url=location.root+url;
				}
				if(!d){
					url=url+'?d=';
				}
				url=url+get;
			}
			window.location.replace(url);
		},

		winOpen : function (param){
		    var obj={  root        : '',
		               url         : '',
		               name        : 'win_'+Math.floor(Math.random()*10000),
		               options     : 'menubar=1,resizable=1,scrollbars=1,width=600,height=850'
		        };
			if(obj.root==''){	
				obj.root=_getURLbase(obj.url);
			}
		    oBject.extend(obj,param);
	        return window.open(obj.root+obj.url ,obj.name,obj.options);
        },
        
        //print content of element
        printThis : function(id){
            _print(id);
        },
		
		getLocation : function(href,param){
			var d={},
				loc=document.location,
				part,
				hs,
				qu,
				ur={};
			
			if(href){
				d.href=href;
			}
			else{
				d.href=loc.href;
			}
			//searchobject en hashobject
			qu = _getURLparam(d.href,'?');
			hs = _getURLparam(d.href,'#');
			ur = _getURLbase(d.href);
			
			if(href){
				
				d.protocol=ur.protocol;
				d.host=ur.host;
				d.hostname=ur.hostname;
				d.pathname=ur.pathname;
				d.port=loc.port;
				d.reload=loc.reload;
				d.replace=loc.replace;
				d.assign=loc.assign;
				d.hash='#'+hs.resultstring;
				d.search='?'+qu.resultstring;
			}
			else{
				d=loc;
			}
			//root
			
			
			//base
			d.root=ur.root;
            d.base=ur.base;
			d.hashobject=hs.resultobject;
			d.searchobject=qu.resultobject;
			
			if(param){
				return d[param];
			}
			else {
				return d;
			}
			
		},
		
		objToKey : function(obj){
			var aKey=[],t=0;
			for(name in obj){
				aKey[t]=name;
				t++;
			}
			return aKey;
		},
		
		
		objFlip : function(obj){
			var oRev={},
				type=this.getExactType(obj);
				
			switch(type){
				case 'Number' :
				case 'String' :
					oRev[obj]=0;
					break;
					
				case 'Array'  :
				case 'Object' :
					for(var key in obj){
						oRev[obj[key]]=key;
			
					}
					break;
				default 	  :
					return obj;
					break;
			
			}
			
			return oRev;
		},
		
		objToURL : function(obj, maxLevels, level) {
	       return _serialize(obj, maxLevels, level);
		},
		
		URLtoObj : function(url, sep1, sep2){
			var re={},qu,le,js,arr=[];
			if(typeof(sep1)==='string') url=url.split(sep1)[1];
			url=url.replace('?','&');
			url=url.replace('#','&');
            url=decodeURIComponent(url);
			qu=url.split('&');
			le=qu.length;
			
			for(var t=0;t<=le;t++){
				if(qu[t] && qu[t].indexOf('=')> -1){
					js=qu[t].split('=');
					if(js[1] && typeof(sep2)==='string' && js[1].indexOf(sep2)> -1){
						js[1]=js[1].split(sep2);
					}
                    //array detect
                    if(js[1] && js[0].indexOf('[]')> -1){
                        js[0]=js[0].split('[')[0];
                        
                        if(typeof( arr[js[0]])==='undefined'){
                            arr[js[0]]= [];
                        }
                        arr[js[0]].push(js[1]);
                        js[0]=null;   
                    }
                    if(js[0]){
                        re[js[0]]=js[1];
                    } 
				}  
			}
            //add arrayfields
            for(name in arr){
                re[name]=arr[name];
            }
			return re;
		},
		
		serializePHP :function(obj, maxLevels){
		
			return _serializePHP(obj, maxLevels);
		},
		
		JSONparse : function(str,revive){
			return _JSON.parse(str,revive);
		},
		
		JSONtoString : function(obj){
			return _JSON.stringify(obj);
		},
		
		//cookies--------------------------------------------
		setCookie : function(name, value, expires, path, domain, secure) {
			return _cookie.set(name, value, expires, path, domain, secure);
		},

		getCookie : function(name) {
			return _cookie.get(name);
		},

		unsetCookie : function(name, path, domain, secure) {
			return _cookie.unset(name, path, domain, secure);
		},
		
		setSubcookie : function(name, subName, value, expires, path, domain, secure){
			_subcookie.set(name, subName, value, expires, path, domain, secure);
		},
		
		setallSubcookie : function(name, subcookies, expires, path, domain, secure){
			return _subcookie.setAll(name, subcookies, expires, path, domain, secure);
		},
		
		getSubcookie : function(name, subName){
			return _subcookie.get(name, subName);
		},
		
		getallSubcookie : function(name){
			return _subcookie.getAll(name);
		},
		
		unsetSubcookie : function(name, subName, path, domain, secure){
			_subcookie.unset(name, subName, path, domain, secure);
		},
		
		unsetallSubcookie : function(name, path, domain, secure){
			_subcookie.unsetAll(name, path, domain, secure);
		},
		
		getGlobals : function(obj){
		    return _getGlobals(obj);
		},
        
        setGlobals : function(obj){
		    return _setGlobals(obj);
		},
        
        getClientKeys : function(seed){
            return _getClientKeys(seed);
        },
		
		getUserAgent : function(){
	       return navigator.userAgent.replace(/ /gi,"").toLowerCase(); 
	    },
        
        decToHex : function(value){
            return _baseConvert.d2h(value);
        },
        
        hexToDec : function(value){
            return _baseConvert.h2d(value);
        },
	
		numberToCurrency : function (fnumber,separator){
			var num = (fnumber+'').replace(',','.');
			num = Math.round(num*100)/100;
            if(typeof(num)!=='number' || isNaN(num)){
                num=0;
            }
			var numText = num + '';
			if((num) == Math.round(num)){
				//No decimals? Add .00
				numText += ".00";
			}
			else if((num*10) == Math.round(num*10)){
				//If 1 decimal only, add 0
				numText += "0";
			}
			if(separator==='.'){
			     return numText;
			}
			else{
                 return numText.replace('.',',');
			}
		},
		
		mailTo : function (obj) {
		    //alert(obj);
	       _mail(obj);
		},
        
        getLocalStorage : function(){
            return _getLocalStorage();
        },
		
		objXHR : function(){
			return _createXHR();
		},
		
		XHRsubmit : function(){
			return _postData();
		},
	   
		//loggerfuncties---------------------------------------
		
		assert : function(oCondition, sMelding){
			var m=sMelding;
			if(!oCondition){
				this.echo(m);
			}
		},
		
		echo : function(sMelding, bAdd, sSender, iLevels,oDisplay){
			var m, txt, sender, levels, time, output,type,display;
			var pos=_getViewport();
			//alert('width='+pos.width +' ,height='+ pos.height+' ,scrleft='+ pos.scrleft +' ,scrtop='+ pos.scrtop);
			
			typeof(sSender)== 'undefined' ? sender='' : sender=sSender;
			typeof(iLevels)== 'undefined' ? levels=1 : levels=iLevels;
            typeof(oDisplay)== 'undefined' ? display={} : display=oDisplay;
			
			type=Util.getExactType(sMelding);
			
			time=new Date();
			//types : 'Array','Boolean','Date','Enumerator','Error','Function','Number','RegExp','String','VBArray'
			switch(type){
				case 'String'     :
				case 'Number'     :
				case 'Date'       :
				case 'Enumerator' :
				case 'Error'      :
				case 'RegExp'     :
				case 'Boolean'    :
					m=type+':'+sMelding+'<br><br>';
					break;
					
				case 'Object' :
					m='<br><br><b> Object ['+oBject.length(sMelding)+']</b><br>'
					m+=oBject.inspect(sMelding,levels,0,display);//object inspect met maxlevels
					break;
					
				case 'Array' :	
					m='<br><br><b> Array ['+oBject.length(sMelding)+']</b><br>'
					m+=oBject.inspect(sMelding,levels,0,display);//object inspect met maxlevels
					break;
					
				case 'Function' :
					m='<br><br><b> Function ['+oBject.length(sMelding)+']</b><br>'
					m+=oBject.inspect(sMelding,levels,0,display);//object inspect met maxlevels
					break;
					
				case 'undefined' :
					m='type = Undefined : '+sMelding;
					break;
				default :
					m='type = Undefined : '+sMelding;
					break;
					
			}

			if(_is_debugger){
				if(!_is_onscreen && !_is_popup){ //naar javascriptconsole [firefox firebug]
					output= time+' --> '+sender+' : \n\n'+m;
					output=this.removeHTMLTags(output);
					console.debug(output);
				}
				else if(!_is_popup && _is_onscreen){//inline
					
						if(bAdd){
							txt=this.getHTML(CNT_DEBUGGER_TXT);
							txt!='' ? m=txt + time+ ' --> '+sender+' : ' + m + '\n' : m=time+' --> '+sender+' : \n\n' + m + '\n';
							this.setHTML(CNT_DEBUGGER_TXT, m);
							this.setStyle(CNT_DEBUGGER,"top",pos.scrtop+50);	
							this.doShow(CNT_DEBUGGER);		
						}
						else {
							this.setHTML(CNT_DEBUGGER_TXT, time+' --> '+sender+' : \n\n'+m);
							this.setStyle(CNT_DEBUGGER,"top",pos.scrtop+50);		
							this.doShow(CNT_DEBUGGER);	
						}
					}
					else if(_is_popup && !_is_onscreen) {//popup
							var sAdd='';
							try
							{
								bAdd?sAdd='true':sAdd='false';
								//create popup
								if( this.getCookie('logger') != 'open' ){
									loggerWindow=this.winOpen({//to do; vanuit loggerOptions
											root		:  ROOT+UTIL,
											url			: 'logger/logger.html',
											name	    : 'loggerWindow',
											options     : 'menubar=1,resizable=1,scrollbars=1,width=960,height=850'
										});
									
									this.setCookie('logger','open');
									sAdd='false';//erase previous content on restart
								}
								
								m=time+' --> '+sender+' : \n\n'+m;
								//send output
								_postLoggerData( ROOT+UTIL+"logger/setLoggerData.php",m,sAdd );	
							}
							catch(e){
								_postLoggerData( ROOT+UTIL+"logger/setLoggerData.php",e,'error' );
							}
					}
			}
		},
		
		logInit : function(sMode){//to do : loggerOptions object
			if(sMode=='console'){
				_is_onscreen=false;
				_is_popup=false;
			}
			if(sMode=='popup'){
				_is_onscreen=false;
				_is_popup=true;
				_postLoggerData( ROOT+UTIL+"logger/setLoggerData.php",'','clear' );//CLEAR LOGGERFILE to do; vanuit loggerOptions
				this.setCookie('logger','init');
			}
			var body = this.getRef('body'),
				div = document.createElement('div'),
				show = document.createElement('div'),
				close = document.createElement('img'),
				clear = document.createElement('img');
			div.setAttribute('id', CNT_DEBUGGER);
			show.setAttribute('id', CNT_DEBUGGER_TXT);
			div.style.display='none';
			
			if(sMode=='relative'){
				div.style.position='relative';
				div.style.marginTop='20px';
				div.style.marginLeft='100px';
				div.style.color='black';
			}
			else {
				div.style.position='absolute';
				div.style.zIndex='1000000';
				div.style.top='100px';
				div.style.left='50px';
				div.style.color='black';
				
				div.onmousedown=function(event){
					_startDrag(event);
				}
			}
			close.onclick=function(){
							Util.doHide(CNT_DEBUGGER);
						}
			clear.onclick=function(){
							Util.doHide(CNT_DEBUGGER);
							Util.setHTML(CNT_DEBUGGER_TXT, '');	
						}
			body.appendChild(div);
			
			close.setAttribute('src', IMG_DEBUGGER_CLOSE);
			clear.setAttribute('src', IMG_DEBUGGER_CLEAR);
            close.setAttribute('alt', '[ close ]');
			clear.setAttribute('alt', '[close and clear]  ');
		
			div.appendChild(close);
			div.appendChild(clear);
			div.appendChild(show);
			
			_is_debugger=true;
			
			this.addStylesheet(LOGGERSTYLE_URL);
		},
        
        logger  : {
        
            LOGGERDEFAULTCOLLAPSE :[
                'parentNode',
                'childNodes',
                'classList',
                'attributes',
                'offsetParent',
                'children',
                'style',
                'ownerDocument',
                'lastChild',
                'firstChild',
                'previousSibling',
                'firstElementChild',
                'lastElementChild',
                'previousElementSibling',
                'nextSibling',
                '0','1','2','3','4','5','6','7','8','9'
            ],
            
            showHide : function(id){
                o.doShowHide(id);
                var btn = 'btn_'+id
                    txt = o.getHTML(btn);
                if(txt==='[+]&nbsp;expand&nbsp;'){
                    o.setHTML(btn,'[-]collapse');
                }
                else{
                    o.setHTML(btn,'[+]&nbsp;expand&nbsp;');
                }
            }
        
        }
		
	};
	return o;
})();

//OBJECT EXTENTIONS EN TOOLS
var oBject = (function(){

	var _object = function(o){
            function F(){}
            F.prototype = o;
            return new F();
    };
    
    var _index = 0;
        
	var o = {
	
		extend : function(destination, source) {
		  for (property in source) {
			destination[property] = source[property];
		  }
		  return destination;
		},

		inspect : function(obj, maxLevels, level, oDisplay,hidden,property,first){
		  var str = '', type, msg;

			// Start Input Validations
			// Don't touch, we start iterating at level zero
			if(level == null)  level = 0;
            _index++;
            //extend here oDisplay with default collapsed item-array ['firstChild','lastChild' etc..]
            oDisplay=Util.array_merge(oDisplay, Util.logger.LOGGERDEFAULTCOLLAPSE);
            //alert(oDisplay);
			// At least you want to show the first level
			if(maxLevels == null) maxLevels = 1;
			if(maxLevels < 1)     
				return '<font color="red">Error: Levels number must be > 0</font><br><br>';

			// We start with a non null object
			if(obj == null)
			return '<font color="red">Error: Object <b>NULL</b></font><br><br>';
			// End Input Validations

			// Each Iteration must be indented
            if(hidden){
                str += '<ul id="'+property+first+'_'+(level-1)+(_index)+'" class="toggle" style="display:none">';
            }
            else{
                str += '<ul>';
            }
			

			// Start iterations for all objects in obj
			for(property in obj){
			  try {
				// Show "property" and "type property"
							  
				type=Util.getExactType(obj[property]);
				var lengte='',display='';
								
				display=obj[property];
                
				level===0?first=property:void(0);				
				if( (type == 'Array') ){
					lengte=' ['+obj[property].length+']';
					display='';
					}
					if( (type == 'Object') ){
						lengte=' ['+oBject.length(obj[property])+']';
						display='';
					}
					if( (type == 'Function') ){
						display='';
					}
                   
                    if(typeof(oDisplay)!=='undefined' && Util.in_array(property,oDisplay ) && type!=='Function'){
                        if(level<maxLevels-1){
                            display='   <i id="btn_'+property+first+'_'+level+(_index+1)+'" style="text-decoration:underline" onclick="Util.logger.showHide(\''
                                        +property+first+'_'+level+(_index+1)+'\')">[+]&nbsp;expand&nbsp;</i>'; 
                        }
                        else{
                            display=''; 
                        }
                        hidden=true;
                    }
                    else{
                        hidden=false;
                    }
                    
					str += '<li>' + property + ( (obj[property]==null)?(': <b>null</b>'):('&nbsp;:<span style="color:green;font-size:0.9em;">&nbsp;('+
                            type+''+lengte+')&nbsp;'+display+'</span>')) + '</li>';

					// We keep iterating if this property is an Object, non null
					// and we are inside the required number of levels
					
                    if((type == 'Object'  || type=='Array' ) && (obj[property] != null) && (level+1 < maxLevels)) {
						str += this.inspect(obj[property], maxLevels, level+1, oDisplay,hidden,property,first);
                    }
			}
			catch(err){
				// Is there some properties in obj we can't access? Print it red.
				if(typeof(err) == 'string') msg = err;
				else if(err.message)        msg = err.message;
				else if(err.description)    msg = err.description;
				else                        msg = 'Unknown';

				str += '<li><font color="red">(Error) ' + property + ': ' + msg +'</font></li>';
			  }
			}

			  // Close indent
			  str += '</ul>';

			return str;
		},
		
		inheritPrototype : function(subType, superType){
			var prototype = _object(superType.prototype);   //create object
			prototype.constructor = subType;               //augment object
			subType.prototype = prototype;                 //assign object
		},
		
		length :  function(obj) {
			var size = 0, key;
			for (key in obj) {
				//if (obj.hasOwnProperty(key)) size++;
				size++;
			}
			return size;
		}
	
	};
	
	return o;

})();

var GL = {};//global interface object
var $U = {};//utility shortcut
