 if (!astonlib)
{
	var astonlib = 
	{
	    version: '2.31c-darex'
	};
}

/*** these methods/objects use neither jQuery nor other 3d-party library, 
so you can use them in frontends, too. ***/

String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,'');
}


String.prototype.startsWith=function(str)
{
	return this.indexOf(str)==0;
}


String.prototype.endsWith=function(str)
{
	return this.lastIndexOf(str)+str.length==this.length;
}


String.prototype.contains=function(str)
{
	return this.indexOf(str)>=0;
}


//split str1<separator>str2 into 2 element array (finds only first/last occurrence of <separator>)
String.prototype.split2=function(separator, last)
{
	last=Function.getArg(last,false);
	var pos=last ? this.lastIndexOf(separator) : this.indexOf(separator);
	var arr=[];
	if (pos>0)
	{
		arr.push(this.substr(0,pos));
		arr.push(this.substr(pos+1));
	}
	else
	{
		arr.push(this);
	}
	
	return arr;
}


//verify, if string should be JSON sequence
String.prototype.isJSON=function()
{
	var c1=this.charAt(0);
	var c2=this.charAt(this.length-1);
	return this.length>1 && ((c1=='{' && c2=='}') || (c1=='[' && c2==']') || (c1=='"' && c2=='"') || (c1=="'" && c2=="'"));
}


// check, if object is string ('typeof()' or 'instanceof String' don't work as expected in some situations)
String.prototype.__String=true;
String.isInstance=function(obj)
{
	return !isEmpty(obj) && isSet(obj.__String);
}


// evaluate JSON and return data, if string represents JSON sequence
String.getJSON=function(str)
{
	if (!String.isInstance(str))
	{
		return str;
	}

	return str.isJSON() ? eval('('+str+')') : str;
}

String.prototype.getJSON=function()
{
	return String.getJSON(this);
}


// decimal-separator aware conversion function
String.prototype.toDecimal=function()
{
  var result={};
  
  strValue=this.trim();
  
  if (strValue.length==0)
  {
  	strValue='0';
	}
	else if (str!==str*1)
	{
		return null;
	}
	  
	if (strValue.contains(','))
	{ 
		strValue.replace(',','.');
		result.decimal=',';
	}
	else
	{
		result.decimal='.';
	}	
	
	result.value=parseFloat(strValue);
	if (isNaN(result.value))
	{
		return null;
	}
	
	return result;
}


// decimal-separator aware conversion function
String.fromDecimal=function(decimalValue)
{
	var strValue=decimalValue.value.toString();
	return strValue.replace('.', decimalValue.decimal);
}


String.prototype.escape=function(uri)
{
	uri=Function.getArg(uri);
	return uri ? encodeURI(this) : encodeURIComponent(this);
}


String.prototype.unescape=function(uri)
{
	uri=Function.getArg(uri);
	return (uri ? decodeUri(this) : decodeURIComponent(this)).replace(/\+/g, ' ');
}



Array.prototype.copy=function(data)
{
	return this.slice(0);
}


Array.prototype.splice2=function()
{
	var result=this.copy();
	result.splice.apply(result, arguments);
	return result;
}



// get object method with prefix
Object.getMethod=function(obj, methodName, prefix)
{
	if (prefix)
	{
		methodName=prefix+methodName.charAt(0).toUpperCase()+methodName.substr(1);
	}
	
	return obj[methodName];
}



// if argument is null or undefined, return default value, otherwise return argument or its new-value
Function.getArg=function(arg, defValue, newValue, checkNull)
{
	checkNull= isSet(checkNull) ? checkNull : true;
	if (!isSet(arg) || (checkNull && isNull(arg)))
	{
		return defValue;
	}
	else
	{
		return isSet(newValue) ? newValue : arg;
	}
}



astonlib.isSet=function(v)
{
	return v!==undefined;
}
isSet=astonlib.isSet;


astonlib.isNull=function(v)
{
	return v===null;
}
isNull=astonlib.isNull;


astonlib.isEmpty=function(v, checkString)
{
	checkString=Function.getArg(checkString, false);
	return !isSet(v) || isNull(v) || (checkString && v==''); 
}
isEmpty=astonlib.isEmpty;



astonlib.Debug = {
	varDump: function(data, msg, level)
	{
		var MAX_LEVEL=10;
		
		msg=Function.getArg(msg,'');
		level=Function.getArg(level, 0);
		
		if (level>MAX_LEVEL)
		{
			return '';
		}
		
		var dataMsg='';
		if (!isSet(data))
		{
			dataMsg='undefined';
		}
		else if (String.isInstance(data))
		{
			dataMsg='"'+data+'"';
		}
		else if (typeof(data)=='object')
		{
			if (data==null)
			{
				dataMsg='null';
			}
			else
			{
				var arr=[];
				if (window.jQuery && data instanceof jQuery)
				{
					data.each(function(){
						arr.push(this.id=='' ? '<none>' : this.id);
					});
				}
				else
				{
					var iterType= isSet(data.length)?'[]':'{}';
								
					var pad='\r\n';
					for (var i=0; i<=level; i++, pad+='   ');
								
					dataMsg+= iterType.charAt(0)+' ';
					astonlib.Data.each(data, function(value, key){
						arr.push(pad+key+':'+varDump(value, false, level+1));
					});
				}
			
				dataMsg+=arr.join(',')+pad+iterType.charAt(1);
			}
		}
		else 
		{
			if (data.toString)
			{
				dataMsg=data.toString();
			}
			else
			{
				dataMsg='<unknown>'
			}
		}
		
		if (String.isInstance(msg))
		{
			if (msg)
			{
				msg+=': ';
			}
			alert(msg+dataMsg);
		}
		else if (!msg)
		{
			return dataMsg;
		}
	}
}
varDump=astonlib.Debug.varDump;



astonlib.Data = {
	QUERY_METHOD_PREFIX: 'astonlib.Data.',
	
	executeQuery: function(query, queryMethodPrefix)
	{
		return astonlib.Data.parseQuery(query, queryMethodPrefix).call();
	},
		
	parseQuery: function(query, queryMethodPrefix)
	{
		var OP_NEGATION='!';
		var SEPAR_OBJ='.';
	
		if (typeof(query)=='function')
		{
			var callback=query;
		}
		else if (typeof(query)=='object' && query)
		{
			queryMethodPrefix=Function.getArg(queryMethodPrefix, astonlib.Data.QUERY_METHOD_PREFIX);
			var methods=[];
			astonlib.Data.each(query, function(args, methodName) {
				if (methodName.startsWith(OP_NEGATION))
				{
					methodName=methodName.substr(1);
					var negation=true;
				}
				else
				{
					var negation=false;
				}
				
				var arr=methodName.split2(SEPAR_OBJ, true);
				var obj=arr[0];
				if (obj!='')
				{
					obj=obj.substr(0,1).toUpperCase()+obj.substr(1);
				}
				
				var methodName=arr[1];
								
				if (methodName.length>0)
				{
					container=eval(queryMethodPrefix+obj);
					
					if (container)
					{
						var method=container[methodName];
					
						if (method)
						{
							methods.push({method: method,
										args: args ? args : [], 
										negation: negation});
						}
					}
				}
			});
			
			var callback=function(el, index, level)
			{
				result = container.__filter ? true: undefined; 
				astonlib.Data.each(methods, function()
				{
					var subResult=undefined;
					//subResult=this.method.apply(el, this.args.splice2(this.args.length, 0, el, index, level));
					subResult=this.method.apply(el, this.args);
					
					if (container.__filter)
					{
						if (this.negation ? subResult==true : subResult==false)
						{
							result=false;
							return false;
						}
						else if (isNull(subResult))
						{
							result=null;
							return false;
						}
					}
					else if (container.__get)
					{
						result=subResult;
						return false;
					}
					else if (container.__each)
					{
						if (subResult==false)
						{
							result=false;
							return false;
						}
					}
				});
				
				return result;
			}
		}
		else 
		{
			var callback=undefined;
		}
		
		return callback;
	},

	Filter: {__filter: true},
	Each: {__each: true},
	Get: {__get: true},
	
	// iterate (with recursion & filtering) through object
	each: function(obj, eachQuery, filterQuery, recursion, lengthProp, level)
	{
		if (!isSet(obj))
		{
			return;
		}
			
		eachQuery=astonlib.Data.parseQuery(eachQuery);
		filterQuery=Function.getArg(astonlib.Data.parseQuery(filterQuery), function(){return true;});
		recursion=Function.getArg(recursion, false);
		lengthProp=Function.getArg(lengthProp, 'length');
		level=Function.getArg(level, 0);
		
		var doIteration=function(obj, index)
		{		
			if (filterQuery.call(obj, obj, index, level) && eachQuery.call(obj, obj, index, level)==false)
			{
				return false;
			}
			else
			{
				if (recursion && typeof(obj)=='object' && obj && astonlib.Data.each((recursion==true) ? obj : obj[recursion], eachQuery, filterQuery, recursion, lengthProp, level+1)==false) 
				{
					return false;
				}
			}
		}
		
		if (typeof(obj)=='object' && obj)
		{
			if (isEmpty(obj[lengthProp]))
			{
				for (var i in obj)
				{
					// skip prototyped properties
					var skip=false;
					for (var j in Object.prototype)
					{
						if (j==i) 
						{
							skip=true;
							break;
						}
					}
					
					// do iteration
					if (!skip && doIteration(obj[i],i)==false) 
					{
						return false;
					}
				}
			}
			else
			{
				for (var i=0; i<obj[lengthProp]; i++)
				{
					if (doIteration(obj[i],i)==false) 
					{
						return false;
					}
				}
			}
		}
		else
		{
			if (doIteration(obj, 0)==false)
			{
				return false;
			}
		}
	},


	// get (filtered) set of elements from collection 
	get: function(obj, filterQuery, getQuery, recursion, iterator, lengthProp)
	{
		iterator=Function.getArg(iterator, astonlib.Data.each);
		getQuery=Function.getArg(astonlib.Data.parseQuery(getQuery), function(){return this;});
		
		var result=[];
		iterator(obj, function(el, index, level){result.push(getQuery.call(el, el, index, level));}, filterQuery, recursion, lengthProp);
		return result.length>0 ? result : undefined;
	},


	// get one (filtered) indexed element from collection
	getOne: function(obj, filterQuery, index, getQuery, recursion, getter, lengthProp)
	{
		index=Function.getArg(index, 0);
		getter=Function.getArg(getter, astonlib.Data.get);
		var currentIndex=-1;
		
		return getter(obj, 
			function(el, index, level) {
				currentIndex++;
				if (currentIndex>index)
				{
					return null;
				}
				else
				{
					return filterQuery.call(el, el, index, level);
				}
			}, 
		
			getQuery, recursion, lengthProp
		);
	},
	
	
	// get unique elements from collection
	// TODO: !!! speed optimalization !!!
	getUnique: function(obj, recursion, iterator, lengthProp)
	{
		/*var uniques=[];
		iterator(obj, function() {
				uniques.push(this);
			},
			
			function(element)
			{
				var found=false;
				iterator(obj, function() {found=true; return false;}, function(otherElement, index, level) {return level>0 && element==otherElement;}, recursion, lengthProp);
				return !found;
			},
			
			false, lengthProp
		);
		
		return uniques;*/
		return obj;
	},


	// TODO: index for recursed elements
	indexOf: function(obj, element, recursion, iterator, lengthProp)
	{
		iterator=Function.getArg(iterator, astonlib.Data.each);
		var result=false;
		iterator(obj, function(el, index) {result=index; return false;}, function() {return this==element;}, recursion, lengthProp);
		return result;
	},


	isIn: function(obj, element, recursion, iterator, lengthProp)
	{
		return astonlib.Data.indexOf(obj, element, recursion, iterator, lengthProp)!==false;
	},
	
	
	tokenize: function(obj, valueGetter, elemGetter, filterQuery, iterator, lengthProp)
	{
		var valueGetter=Function.getArg(valueGetter, '=');
		var elemGetter=Function.getArg(elemGetter, ',');
		
		if (String.isInstance(valueGetter))
		{
			valueSeparator=valueGetter;
			valueGetter=function(){return valueSeparator+this;};
		}
		
		if (String.isInstance(elemGetter))
		{
			elemSeparator=elemGetter;
			elemGetter=function(){return elemSeparator+this;};
		}
					
		iterator=Function.getArg(iterator, astonlib.Data.each);
		
		var result='';
		var notFirst=false;
		iterator(obj, function(value, key) {
			result+=elemGetter.call(key+valueGetter.call(value))
		}, 
		
		filterQuery, false);
		
		return result;
	}
}



astonlib.DOM = {
		QUERY_METHOD_PREFIX: 'astonlib.DOM.',
		
		Filter: {
			__filter: true,
			
			id: function(ids) {
				var id=this.id;
				
				if (isEmpty(id))
				{
					return false;
				}
				
				var found=false;
				astonlib.Data.each(ids, function(filterId) {
					if (filterId.endsWith('^'))
					{
						filterId=filterId.substr(0,filterId.length-1);
						if (id.startsWith(filterId))
						{
							found=true;
							return false;
						}
					}
					else
					{
						if (id==filterId)
						{
							found=true;
							return false;
						}
					}
				});
				
				return found;
			},
			
			tag: function(tagNames) {
				if (!this.tagName)
				{
					return false;
				}
				
				var tagName=this.tagName.toLowerCase();
				return astonlib.Data.isIn(tagNames, tagName);
			},
		
			input: function() {
				if (!this.tagName)
				{
					return false;
				}
				var tagName=this.tagName.toLowerCase();
				return tagName=='select' || tagName=='button' || tagName=='input' || tagName=='textarea';
			},
			
			button: function(special) {
				// special - include radios & checkboxes
				if (this.tagName)
				{
					var tagName=this.tagName.toLowerCase();
				}
				
				if  (this.type)
				{
					var type=this.type.toLowerCase();
				}
				
				return  tagName=='button' || 
						tagName=='input' && (
							 type=='button' ||
							 type=='submit' ||
							 special && (type=='checkbox' || type=='radio'));
			},
			
			is: function(obj){return this==obj;},
			
			className: function(classNames) {return al.Data.isIn(classNames, this.className);},
			
			attr: function(name, value){return (!isSet(value) && !isEmpty(this.getAttribute(name))) || this.getAttribute(name)==value;}
		},
		
		
		Each: {
			__each: true,
			
			value: function(value){
				astonlib.DOM.Element.setValue(this, value);
			},
			
			attr: function(attr, value){this.setAttribute(attr, value);},
			className: function(className){this.className=className;},
			style: function(style) {astonlib.DOM.Element.setStyle(this, style);},
			
			remove: function(){astonlib.DOM.Element.remove(this)},
			
			event: function(type, func, args){astonlib.Events.add(this, type, func, args);},
			removeEvent: function(type, func, args){astonlib.Events.remove(this, type, func, args);},
			callEvent: function(type){astonlib.Events.execute(this, type);},
			
			show: function(show){astonlib.DOM.Element.show(this, show)},
			enable: function(enable){this.disabled = !enable;},
						
			// add (remove) prefix to (from) attribute
			attrPrefix: function(attr, add, prefix)
			{
				attr=Function.getArg(attr,'id');
				add=Function.getArg(add,true);
				prefix=Function.getArg(prefix,'__');
				var val=this.getAttribute(attr);
				if (String.isInstance(val))
				{
					var prefixed= val.startsWith(prefix);
					if (add)
					{
					 if (!prefixed)
						{
							this.setAttribute(attr, prefix+val);
						}
					}
					else if (prefixed) 
					{
						this.setAttribute(attr, val.substr(prefix.length));
					}
				}
			}
		},
		
		
		Get: {
			__get: true,
			
			// return "deepest" parent for element
			// for <body><div><img></div></body> - <body> is 2nd-parent of <img>
			parent: function(maxDeep, withChilds)
			{
				withChilds=Function.getArg(withChilds, false);
				domElem=this;
				for (var i=0;i<maxDeep;i++)
				{
					domParent=this.parentNode;
					if (domParent)
					{
						domElem=domParent;
					}
					else
					{
						break;					
					}
				}
				
				if (withChilds)
				{
					domElem=astonlib.DOM.getAll(domElem);
				}
				
				return domElem;
			}
		},
	
		each: function(domElem, eachQuery, filterQuery, recursion)
		{
			eachQuery=astonlib.Data.parseQuery(eachQuery, astonlib.DOM.QUERY_METHOD_PREFIX);
			filterQuery=astonlib.Data.parseQuery(filterQuery, astonlib.DOM.QUERY_METHOD_PREFIX);
			
			if (isEmpty(recursion))
			{
				recursion=(isEmpty(domElem.length));
			}
			
			if (isEmpty(domElem.length))
			{
				domElem=domElem.childNodes;
			}
		
			return astonlib.Data.each(domElem, eachQuery,
					function(el, index, level) {
				 		return astonlib.Data.isIn([1], this.nodeType) && (isEmpty(filterQuery) || filterQuery.call(el, el, index, level));
					},				
					
					recursion ? 'childNodes' : null);
		},
	
		get: function(domElem, filterQuery, getQuery, recursion)
		{
			filterQuery=astonlib.Data.parseQuery(filterQuery, astonlib.DOM.QUERY_METHOD_PREFIX);
			getQuery=astonlib.Data.parseQuery(getQuery, astonlib.DOM.QUERY_METHOD_PREFIX);
			
			return astonlib.Data.get(domElem, filterQuery, getQuery, recursion, astonlib.DOM.each);
		},
		
		getAll: function(domElem, filterQuery, getQuery)
		{
			// TODO: change along with optimalized getUnique
			return astonlib.DOM.getUnique(astonlib.DOM.get(domElem, filterQuery, getQuery, true), false);
		},
		
		getOne: function(domElem, filterQuery, index, getQuery)
		{
			filterQuery=astonlib.Data.parseQuery(filterQuery, astonlib.DOM.QUERY_METHOD_PREFIX);
			getQuery=astonlib.Data.parseQuery(getQuery, astonlib.DOM.QUERY_METHOD_PREFIX);
			
			return astonlib.Data.getOne(domElem, filterQuery, index, getQuery, astonlib.DOM.get);
		},
		
		getUnique: function(domElem, recursion)
		{
			return astonlib.Data.getUnique(domElem, recursion, astonlib.DOM.each);
		},
		
		isIn: function(domElem, elem, recursion)
		{
			return astonlib.Data.isIn(domElem, elem, recursion, astonlib.DOM.each);
		}
}


astonlib.DOM.Element = {
	getPosition: function(domElem, vertical /* default is horizontal */)
	{
		vertical=Function.getArg(vertical,false);
		
		var original = domElem;
		var returnValue = vertical ? domElem.offsetTop: domElem.offsetLeft;
		 while((domElem = domElem.offsetParent) != null)
		 {
		  	if(domElem.tagName.toUpperCase()!='HTML')
		  	{
		  		returnValue += vertical ? domElem.offsetTop : domElem.offsetLeft; 
		  		if(document.all) 
		  		{
		  			returnValue+= vertical ? domElem.clientTop : domElem.clientLeft;
		  		}
		  	}
		 }
		 
		return returnValue;
	},
	
	
	setClass: function(domElem, className, add)
	{
		add=Function.getArg(add, true);
					
		if (domElem.className.charAt(0)!=' ')
		{
			domElem.className=' '+domElem.className;
		}

		if (isEmpty(domElem.initClassName))
		{
			domElem.initClassName=domElem.className;
		}
		
		if (className)
		{
			var classPos=domElem.className.indexOf(' '+className);
			if (add)
			{
				if (classPos<0)
				{
					domElem.className+=' '+className;
				}
			}
			else
			{
				if (classPos>=0)
				{
					domElem.className=domElem.className.substr(0, classPos)+domElem.className.substr(classPos+className.length+1);
				}
			}
		}
		else
		{
			if (domElem.initClassName)
			{
				domElem.className=domElem.initClassName;
			}
			else
			{
				domElem.className='';
			}
		}
	},
	
	
	setStyle: function(domElem, style)
	{
		domElem.setAttribute('style', style);
		domElem.style.cssText=style;
	},
	
	
	setValue: function(domElem, value)
	{
		value=Function.getArg(value, '');
		
		if (isSet(domElem.value)) 
		{
			domElem.value=value;
		} 
		else 
		{
			domElem.innerHTML=value;
		}
	},
	
	show: function(domElem, show)
	{
		show=Function.getArg(show, true);
		if (show)
		{
			domElem.style.display='';
		}
		else
		{
			domElem.style.display='none';
		}
	},
	
	remove: function(domElem)
	{
		domElem.parentNode.removeChild(domElem);
	}
}
		

		
astonlib.DOM.Input = {
	// save element value into cookie
	saveValue: function(domElem)
	{
		var cook=new astonlib.Cookie(domElem.id, '/');
		cook.set(domElem.value);
	},
	
	// restore element value from cookie
	restoreValue: function(domElem)
	{
		var cook=new astonlib.Cookie(domElem.id, '/');
		var elemValue=cook.get();
		if (!isEmpty(elemValue))
		{
			if (domElem.tagName.toLowerCase()=='select')
			{
				astonlib.DOM.Combo.restoreValue(domElem, elemValue);
			}
			else
			{
				domElem.value=elemValue;
			}
		}
		
		// cook.set('', -1);
	}
}
		
		
astonlib.DOM.Combo = {
	// restore combo value
	restoreValue: function(domCombo, comboValue)
	{
		astonlib.Data.each(domCombo.options, function(option, key) {
			if (option.value==comboValue)
			{
				domCombo.selectedIndex=key;
				return false;
			}
		});
	},


	// add options to combo from options-array
	addOptions: function(domCombo, options, truncate)
	{
		truncate=Function.getArg(truncate,false);
		if (truncate)
		{
			domCombo.options.length=0;
		}

		astonlib.Data.each(options, function(text, value) {
			domCombo.options.add(new Option(text,value));
		});
	},


	// get combo options into options-array
	getOptions: function(domCombo)
	{
		var opts={};
		var options=domCombo.options;
		if (options)
		{
			astonlib.Data.each(options, function(option) {
				opts[option.value]=option.text;
			});
		}

		return opts;
	}
}




astonlib.Load = {
	METHOD_GET: 'GET ',
	METHOD_POST: 'POST ',
	
	// load XML from string or url
	xml: function(xmlString)
	{
		var XML_HEADER='<?xml';
		
		if (!xmlString.contains(XML_HEADER))
		{
			astonlib.Load.ajax(xmlString, function(){xmlString=this;}, false, true);
		}
		
		if (!xmlString.contains(XML_HEADER))
		{
			return null;
		}
	
		if (document.implementation && document.implementation.createDocument) 
		{
				parser=new DOMParser();
				var xmlDoc=parser.parseFromString(xmlString, "text/xml");
		}
	  else
	  {
	  	try 
	  	{
		   	var xmlDoc = new ActiveXObject("MSXML2.DOMDocument");
		  }
		  catch(e)
			{
				return null;
			}
			
			xmlDoc.async=false;
		 	xmlDoc.loadXML(xmlString);
		}
		
		return xmlDoc;
	},
	
	
	ajax: function(url, callback, json, synchro, xxxx)
	{ 
		json=Function.getArg(json, true);
		synchro=Function.getArg(synchro, false);
		
		var usePost=false;
		if (url.startsWith(astonlib.Load.METHOD_GET))
		{
			url=url.substr(astonlib.Load.METHOD_GET.length).trim();
		}
		else if (url.startsWith(astonlib.Load.METHOD_POST))
		{
			url=url.substr(astonlib.Load.METHOD_POST.length).trim();
			usePost=true;
		}
		
		var result;
		var execute=function(data)
		{
			if (!isEmpty(data)) 
			{
				if (json)
				{
					data=data.getJSON();
					if (data=='')
					{
						return false;
					}
				}
			}

			result=callback.call(data, data);
		}
			
		
		var stateChange=function()
		{
			if (req.readyState == 4) {
				if (req.status == 200) {
					execute(req.responseText);
				}
			}
		}
		
		if (window.XMLHttpRequest) 
		{
			var req= new XMLHttpRequest();
		}
		else
		{
			try 
			{
				var req = new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch(e)
			{
				return null;
			}
		}
				
		if (usePost)
		{
			var pos=url.indexOf('?');
			var params=url.substr(pos+1);
			url=url.substr(0,pos);
			req.open('POST', url, !synchro)
			req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
		}
		else
		{
			var params=null;
			req.open('GET', url, !synchro);
		}
			
		if (!synchro) 
		{
			req.onreadystatechange = stateChange;
		}
		
		req.send(params);
		
		if (synchro)
		{
			execute(req.responseText);
		}

		return result;
	}
}



// easy manipulation with events
// TODO: how to handle destroyed functions/objects?
astonlib.Events = {
	AllowDOMContentLoaded: true,

	__handlers: {},
	
	// if func is undefined -> take-over previous event handler into __handlers 
	add: function(obj, eventType, func, args)
	{
		if (!obj) return;

		var onEvent='on'+eventType;
		eventType=eventType.toLowerCase();
		if (!astonlib.Events.AllowDOMContentLoaded && eventType=='domcontentloaded')
		{
			eventType='load'; onEvent='onload';
		}
		
		if (astonlib.Events.__handlers[eventType])
		{
			if (func)
			{
				var found=false;
				astonlib.Data.each(astonlib.Events.__handlers[eventType], 
						function() 
						{
							found=true;
							return false;
						},
						
						function(handler) { 
							return handler.obj==obj && handler.func==func && handler.args==args;
				});
				
				if (found)
				{
					return;
				}
			}
		}
		else
		{
			astonlib.Events.__handlers[eventType]=[];
		}
			
		if (func)
		{
			astonlib.Events.__handlers[eventType].push({obj: obj, func: func, 
														args: args ? args : []});
		}
		
		if (obj[onEvent] && !obj[onEvent].hooked)
		{
			astonlib.Events.__handlers[eventType].push({obj: obj, func: obj[onEvent]});
		}
		
		if (!obj[onEvent] || !obj[onEvent].hooked)
		{
			/*if (obj.attachEvent)
			{
				// attachEvent passes event as function parameter in IE
				obj[onEvent]=function(){};
				obj.attachEvent(onEvent, astonlib.Events._execute);
			}
			else*/
			{
				obj[onEvent]=astonlib.Events._execute;
			}
			obj[onEvent].hooked=true;
		}
	},

	
	execute: function(obj, type)
	{
		return astonlib.Events._execute.call(obj, {type: type, target: obj});
	},
	
	_execute: function(e)
	{
		if (!e)
		{
			e=window.event;
		}
		
		if (!e.target)
		{
			e.target=e.srcElement;
		}
		
		e.propagate=true;
		
		var result=true;
		var obj=this;
		
		astonlib.Data.each(astonlib.Events.__handlers[e.type.toLowerCase()], 
			function(handler)
			{
				var subResult=undefined;
				if (handler.args)
				{
					subResult=handler.func.apply(obj, handler.args.splice2(0,0,e));
				}
				else
				{
					subResult=handler.func.apply(obj);
				}
																						
				if (!isEmpty(subResult))
				{
					result=result && subResult;
				}
			},
			
			function(handler) {
				return handler.obj==obj;
		});
		
		if (!e.propagate)
		{
			e.cancelBubble=true;
			if (e.stopPropagation)
			{
				e.stopPropagation();
			}
		}
		
		e.returnValue=result;
		return result;
	},

	
	remove: function(obj, eventType, func, args)
	{
		if (!obj)
		{
			return;
		}

		eventType=eventType.toLowerCase();
		if (!astonlib.Events.AllowDOMContentLoaded && eventType=='domcontentloaded')
		{
			eventType='load';
		}
		
		var deletedItems=[];
		astonlib.Data.each(astonlib.Events.__handlers, 
			function(handlers, handlersEvent) 
			{
				astonlib.Data.each(handlers,
					function(handler, i)
					{
						deletedItems.push({type: handlersEvent, index: i});
					},
					function(handler)
					{
						return (handler.obj==obj) && (isEmpty(func) || handler.func==func) && (isEmpty(args) || handler.args==args);
					});
			},
			function(handlers, handlersEvent)
			{
				return (isEmpty(eventType) || handlersEvent==eventType);
		});
		
		astonlib.Data.each(deletedItems, function(item) {astonlib.Events.__handlers[item.type].splice(item.index,1);});
	}
}




astonlib.Cookie=function(c_name, path)
{
	path=Function.getArg(path,'');
	this.set=function(value, expiredays)
	{
		var exdate=new Date();
		var hasDate = !isEmpty(expiredays);
		
		if (hasDate)
		{
			exdate.setDate(exdate.getDate()+expiredays);
		}
	
		document.cookie=c_name+ "=" +escape(value)+
		((hasDate) ? ";expires="+exdate.toGMTString() : "" )+ (path=='' ? '' : ';path='+path);
	}

	this.get=function()
	{
		if (document.cookie.length>0)
		  {
		  c_start=document.cookie.indexOf(c_name + "=");
		  if (c_start!=-1)
		    { 
		    c_start=c_start + c_name.length+1; 
		    c_end=document.cookie.indexOf(";",c_start);
		    if (c_end==-1) c_end=document.cookie.length;
		    return unescape(document.cookie.substring(c_start,c_end));
		    } 
		  }
		return null;
	}
}



astonlib.Hacks = {
	// remove outline from buttons using "this.blur() hack"
	// aggresive -> includes other elements such as radio-buttons, check-boxes...
	removeOutline: function(rootElem, aggresive)
	{
		rootElem=Function.getArg(rootElem, document.body);
		
		astonlib.DOM.each(rootElem, {'each.event':['focus', function(){this.blur()}]},
									{'filter.button': [aggresive]});
	},

	// handles IE resize-window bug (elements have bad position after window resize)
	// TODO: we lost input values
	ieWindowResize: function()
	{
		if (document.all)
		{
			var body=document.body;
			var clientWidth=body.clientWidth;
			var clientHeight=body.clientHeight;
			
			body.onresize= 
				function() {
					if (body.clientWidth==clientWidth && body.clientHeight==clientHeight)
					{
						location.reload();
					}
					else
					{
						clientWidth=body.clientWidth;
						clientHeight=body.clientHeight;
					}
				};
		}
	},
	
	// workaround for IE6/7 div over select problem
	ieOverlay: function(domElem, show)
	{
		if (!document.all)
		{
			return;
		}
		
		show=Function.getArg(show, true);
		if (show)
		{
			iframe = document.createElement('iframe');
			iframe.src='javascript: "<html></html>"';
			iframe.allowtransparency=true;
			iframe.scrolling='no';
			iframe.frameborder=0;
			iframe.style.position='absolute';
			iframe.style.border='none';
			iframe.style.zIndex = (domElem.style.zIndex) ? domElem.style.zIndex-1 : 1;
			iframe.style.left = astonlib.DOM.Element.getPosition(domElem) + 'px';
			iframe.style.top = astonlib.DOM.Element.getPosition(domElem, true) + 'px';
			iframe.style.width = domElem.offsetWidth;
			iframe.style.height = domElem.offsetHeight;
			//iframe.style.filter='alpha(opacity=0)';
			//iframe.style.opacity='0';
			astonlib.DOM.Element.show(iframe);
			document.body.appendChild(iframe);
			domElem.ieOverlayFrame=iframe;
		}
		else
		{
			if (domElem.ieOverlayFrame && domElem.ieOverlayFrame.parentNode)
			{
				document.body.removeChild(domElem.ieOverlayFrame);
			}
		}
	}
}
	


// InfoWindow provides non-Ajax and Ajax version (if 'contents' is string [not JSON], it is assumed to be ajaxUrl)
astonlib.InfoWindow=function(elemObj, contents, viewerObj, idPrefix)
{
	var __this=this;
	
	var ajax = String.isInstance(contents) && !contents.isJSON();
	if (!ajax)
	{
		contents=String.getJSON(contents);
	}
	
	idPrefix=Function.getArg(idPrefix,'info');
	
	var divId=idPrefix+'Window';
	var iframeId=idPrefix+'IFrame';
	var anchId=idPrefix+'WindowClose';
	var titleId=idPrefix+'Title';
	
	var infoDiv;
		
	var createWindow=function() 
	{
		infoDiv = document.createElement('div');
	    infoDiv.setAttribute('id', divId);
		infoDiv.style.position='absolute';
		infoDiv.style.left = astonlib.DOM.Element.getPosition(elemObj) + 'px';
	  	infoDiv.style.top = astonlib.DOM.Element.getPosition(elemObj, true) + 'px';
	  	astonlib.DOM.Element.show(infoDiv, false);
	  	infoDiv.style.zIndex=100;

	  	infoDiv.innerHTML+='<table border="0" cellspacing="0" cellpadding="0" class="infoHeader"><tr><td id="'+titleId+'" style="width: 95%"></td><td style="text-align: left; padding-right: 2px; padding-top: 2px;"><a style="outline: none" id="'+anchId+'">&nbsp;</a></td></tr></table>';
	  	astonlib.DOM.Element.show(infoDiv, false);
	  	
	  astonlib.Events.add(infoDiv, 'click', function(e) {e.propagate=false;});
		document.body.appendChild(infoDiv);
	}
	
	var showWindow=function()
	{
		astonlib.Hacks.ieOverlay(infoDiv);
		astonlib.DOM.Element.show(infoDiv);
	}
	
	var removeWindow=function(e)
	{
		e.propagate=false;
		var remove=true;
		astonlib.DOM.each(elemObj, function() {remove=false; return false;}, {'filter.is':[e.target]});
		
		if (remove)
		{
			astonlib.Events.remove(document.body, 'click', __this.removeWindow);
			astonlib.DOM.Element.remove(infoDiv);
			astonlib.Hacks.ieOverlay(infoDiv, false)
		}
	}
		
	var showContents=function(data) {
		if (data.title)
		{
			document.getElementById(titleId).innerHTML = !(viewerObj && viewerObj.getTitle) ? data.title : viewerObj.getTitle(data);
		}
		infoDiv.innerHTML+= (viewerObj ? viewerObj.getBody(data) : data.data);
		
		showWindow();
		astonlib.Events.add(document.body, 'click', removeWindow);
		astonlib.Events.add(document.getElementById(anchId), 'click', removeWindow);
	};
	
	createWindow();
	
	if (ajax)
	{
		astonlib.Load.ajax(contents, showContents, true, true);
	}
	else
	{
		showContents(contents);
	}
}


astonlib.Renderers = {
	ValueList: function()
	{
		this.getBody=function(data) {
			var body='<table border="0" cellpadding="0" cellspacing="0" class="valueList">';		
			astonlib.Data.each(data.data, function(value, key) {
				body+='<tr><td class="valueListKey">'+key+':'+'</td><td class="valueListValue">'+value+'</td></tr>';
			});
			
			body+='</table>';
			return body; 
		}
	}
}
astonlib.ValueListRenderer=astonlib.Renderers.ValueList;



// TODO: better (optimized) caching
// !!! NOTE: default "deep" for parent finding is 1 (for simpler use with AWeb)
astonlib.PageStateChanger=function(notifier, states, rootIds, callback, implicitOps, opsPrefix)
{
	var PREFIX_ID='__';
	var SEPAR_OBJ='.';
	var SEPAR_MASK='.';
	var SEPAR_DEEP='!';
	var SEPAR_ASSIGN='=';
	
	var METHOD_FILL='fill';
	var METHOD_NONE='none';
	
	var DEFAULT_DEEP=1;
	var DEFAULT_OPS_PREFIX='astonlib.PageStateChanger.';
	
	var ajax = String.isInstance(states) && !states.isJSON();
	if (!ajax)
	{
		states=String.getJSON(states);
	}
	
	var root=document;
	if (rootIds)
	{
		root=astonlib.DOM.get(document, {'filter.id':[rootIds]});
	}
	
	implicitOps=Function.getArg(implicitOps, astonlib.PageStateChanger.BasicOps);
	opsPrefix=Function.getArg(opsPrefix, DEFAULT_OPS_PREFIX);
		
	var currentStateId;
	var statesCache={};
	var statesStack={};

	var setState=function(stateId, stateParam, state)
	{
		var result=undefined;
		
		if (isEmpty(state))
		{
			return result;
		}
		
		if (ajax && state['__cached']) 
		{
			statesCache[stateId][stateParam]=state;
		}
		
		// process every element
		astonlib.Data.each(state, function(elemOps, id) {
			// split id!deep
			var idSplitted=id.split2(SEPAR_DEEP);
			var domElem=null;
			id=idSplitted[0];
			var deep=idSplitted[1];
			
			if (isEmpty(deep))
			{
				deep=DEFAULT_DEEP;
			}			
			
			if (id=='__all')
			{
				// notifiers are removed from __all pseudo-id
				var notifierIds=notifier.getId();
				domElem=astonlib.DOM.getAll(root, {'!filter.tag':[['script']], '!filter.id':[notifierIds]});
			}
			else
			{
				// split id.mask
				var idSplitted=id.split2(SEPAR_MASK);
				id=idSplitted[0];

				// find both prefixed/non-prefixed ids
				domElem=astonlib.DOM.getAll(root, {'filter.id':[[id, PREFIX_ID+id]]});
						
				if (idSplitted[1])
				{
					domElem=astonlib.DOM.get(domElem, null, {'get.parent':[deep]});
					var mask=idSplitted[1];
					astonlib.PageStateChanger.BasicOps.opHide.call(domElem);
					domElem=astonlib.DOM.getAll(root, {'filter.id':[[id, PREFIX_ID+id]], 'filter.attr':['mask', mask]});
				}
			}

			domElem=astonlib.DOM.get(domElem, null, {'get.parent':[deep]});
		
			// process every operation
			astonlib.Data.each(elemOps, function (elemOp, key) {
				
				// split elemOp=value 
				var elemOpSplitted=elemOp.split2(SEPAR_ASSIGN);
				elemOp=elemOpSplitted[0];
				
				var value=elemOpSplitted[1];
				if (!isEmpty(value))
				{
					value=value.getJSON();
				}
				
				// split opsObject.opMethod
				elemOpSplitted=elemOp.split2(SEPAR_OBJ, true);
				opsObject=elemOpSplitted[0];
				opMethod=elemOpSplitted[1];
				
				if (isEmpty(opMethod))
				{
					opMethod=opsObject;
					opsObject=implicitOps;
				}
				else if (opsObject.length==0)
				{
					opsObject=implicitOps;
				}
				else
				{
					try
					{
						eval('opsObject='+opsObject+';');
					}
					catch (e)
					{
						try {
							eval('opsObject='+opsPrefix+opsObject+';');
						}
						catch(e)
						{
						}
					}
				}
	
				if (opsObject && opMethod.length>0)
				{
					if (opMethod!=METHOD_NONE)
					{
						if (!statesStack[id])
						{
							statesStack[id]={};
						}
						
						if (isEmpty(statesStack[id][elemOp]))
						{
							statesStack[id][elemOp]={};
						}
	
						var method=Object.getMethod(opsObject,opMethod, 'op');
						if (method)
						{
							result=method.call(domElem, value, stateId, stateParam, statesStack[id][elemOp]);
						}
						
						if (opMethod==METHOD_FILL && mask)
						{
							astonlib.PageStateChanger.BasicOps.opShow.call(domElem);
						}
					}
				}
			});
		});
		
		return result;
	}
	
	
	this.changeState=function(stateId, stateParam)
	{
		if (!isSet(stateId))
		{
			if (!isSet(currentStateId))
			{
				return false;
			}
			stateId=currentStateId;
		}
		
		if (!isSet(stateParam))
		{
			stateParam='';
		}
		
		stateParam={stateParam: stateParam};
		if (callback)
		{
			astonlib.Data.each(callback.call(this, stateId, stateParam),
				function(value, name)
				{
					stateParam[name]=value;
				}
			);
		}
		
		if (stateParam.__noop)
		{
			return false;
		}
		
		if (/*currentStateId!=stateId*/ true)
		{
			currentStateId=stateId;
			if (ajax)
			{
				if (!statesCache[stateId])
				{
					statesCache[stateId]={};
				}
				
				var state=statesCache[stateId][stateParam];
					
				if (!isSet(state))
				{
					stateParamStr=astonlib.Data.tokenize(stateParam, '=', '&');
					var ajaxUrl=states+'&stateId='+stateId.escape()+stateParamStr.escape(true);
					return astonlib.Load.ajax(ajaxUrl, function(state){return setState(stateId, stateParam, state)}, true, true, states);
				}
				else
				{
					return setState(stateId, stateParam, state);
				}
			}
			else
			{
				state=states[stateId];
				if (!isSet(state))
				{
					state=states['__default'];
				}
				
				return setState(stateId, stateParam, state);
			}
		}
	}
	
	notifier.addHandler(this.changeState);
	notifier.init();
}


// *** filler ***
astonlib.PageStateChanger.ElementFiller = {
	saveState: function()
	{
		astonlib.DOM.Input.saveValue(this);
	},
	
	fillDefault: function(value)
	{
		astonlib.DOM.Element.setValue(this, value);
	},
	
	fillSelect: function(value, stateId, stateParam, stack)
	{
		var comboOptions=stack[this.id];
		
		if (!comboOptions)
		{
			stack[this.id]=astonlib.DOM.Combo.getOptions(this);
		}
		else 
		{
			this.options.length=0;
		}
		
		if (this.options.length==0)
		{
			astonlib.DOM.Combo.addOptions(this, comboOptions);
		}
	
		astonlib.DOM.Combo.addOptions(this, value);
		astonlib.DOM.Input.restoreValue(this);
		
		// save combo state
		astonlib.Events.add(this, 'change', astonlib.PageStateChanger.ElementFiller.saveState);
	}
}


// *** ops ***	
astonlib.PageStateChanger.BasicOps = {
	opFill: function(value, stateId, stateParam, stack)
	{
		domElem=astonlib.DOM.getAll(this, {'filter.input':[]});
		astonlib.DOM.each(domElem, function(elem, index) {
			var tagName=this.tagName.toLowerCase();
			var method=Object.getMethod(astonlib.PageStateChanger.ElementFiller, tagName, 'fill');
			if (!method)
			{
				method=astonlib.PageStateChanger.ElementFiller.fillDefault;
			}
			
			method.call(elem, value, stateId, stateParam, stack);
		});
		
		astonlib.DOM.each(domElem, {'each.callEvent':['change']});
	},
	
	opShow: function()
	{
		astonlib.DOM.each(this, {'each.attrPrefix':['id', false]});
		astonlib.DOM.each(this, {'each.show':[true]});
	},
		
	opHide: function()
	{
		astonlib.DOM.each(this, {'each.show':[false]});
		astonlib.DOM.each(this, {'each.attrPrefix':['id', true]});
	},
		
	opEnable: function()
	{
		domElem=astonlib.DOM.getAll(this, {'filter.input':[]});
		astonlib.DOM.each(domElem, {'each.enable':[true]});
		astonlib.DOM.each(domElem, {'each.attrPrefix':['id', false]});
	},
		
	opDisable: function()
	{
		domElem=astonlib.DOM.getAll(this, {'filter.input':[]});
		astonlib.DOM.each(domElem, {'each.enable':[false]});
		astonlib.DOM.each(domElem, {'each.attrPrefix':['id']});
	},
	
	opStyle: function(value)
	{
		astonlib.DOM.each(this, {'each.style':[value]});
	},
	
	opClass: function(value)
	{
		astonlib.DOM.each(this, {'each.className': [value]});
	},
	
	opValue: function(value)
	{
		astonlib.DOM.each(this, {'each.value':[value]});
	}
}
astonlib.BasicOps=astonlib.PageStateChanger.BasicOps;


// validator operations - beta version (subject to change)
astonlib.PageStateChanger.ValidOps = {
	dateFromStr: function(string)
	{
		var dateArr=string.split('.');
		return new Date(dateArr[2],dateArr[1]-1,dateArr[0]);
	},
	
	// check, if date in element (this) is less than or equal to date in element with ID=value.id 
	// (if not, display value.msg)
	// TODO: add iteration for 'this'
	opDateLE: function(value)
	{
		domElem=astonlib.DOM.getAll(this, {'filter.input':[]});
		var domDate1=domElem[0];
		var date1=astonlib.PageStateChanger.ValidOps.dateFromStr(domDate1.value);
		
		var domDate2=document.getElementById(id);
		var date2=astonlib.PageStateChanger.ValidOpsHelper.dateFromStr(domDate2.value);
		if (date2.getTime()<date1.getTime())
		{
			alert(value.msg);
			return false;
		}
	}
}
astonlib.ValidOps=astonlib.PageStateChanger.ValidOps;


// extended operations
astonlib.PageStateChanger.ExtOps = { 
	// calculate (evaluate) value and set it to element
	// $<id>$ is placeholder for getElementId(id).value
	// TODO: alpha version
	opEval: function(value)
	{
		var SEPAR_PLACEHOLDER='$';
		
		domElem=astonlib.DOM.getAll(this, {'filter.input':[]});
		
		var evalArr=value.split(SEPAR_PLACEHOLDER);
		var evalValue='';
		astonlib.Data.each(evalArr, function(val, key) {
			if (key%2!=0)
			{
				var elemValue=document.getElementById(val).value;
				if (elemValue=='')
				{
					evalValue='""';
					return false;
				}
				evalValue+=elemValue;
			}
			else 
			{
				evalValue+=val;
			}
		});
	
		try 
		{
			astonlib.DOM.each(domElem, {'each.value':[eval(evalValue)]});
		}
		catch (e)
		{
			astonlib.DOM.each(domElem, {'each.value':[]});
		}
	},
	
	// get length of element value
	opValLength: function(value)
	{
		var elemVal=document.getElementById(value).value;
		if (!isEmpty(elemVal))
		{
			astonlib.DOM.each(this, {'each.value':[elemVal.length]});
		}
	},
	
	// set cookie
	opCookie: function(value)
	{
		var cook=new astonlib.Cookie(value.name, value.path);
		cook.set(value.value, value.expireDays);
	},
	
	// call js-method (with arguments)
	opCall: function(value, stateId, stateParam, stack)
	{
		var __this=this;
		astonlib.Data.each(value, function(args, name) {
			var func=eval(name);	
			if (func)
			{
				func.apply(__this, args.splice2(args.length, 0, stateId, stateParam, stack));
			}
		});
	}
}
astonlib.ExtOps=astonlib.PageStateChanger.ExtOps;



//*** notifiers ***
astonlib.Notifiers = {
	Abstract: function()
	{
		var __this=this;
		var handlers=[];
		
		this.getId=function()
		{
			return undefined;
		}
				
		this.addHandler=function(callback)
		{
			if (typeof(callback)=='function' && !astonlib.Data.isIn(handlers, callback))
			{
				handlers.push(callback);
			}
		}
		
		this.removeHandler=function(callback)
		{
			var pos=astonlib.Data.indexOf(handlers, callback);
			if (pos!==false)
			{
				handlers=handlers.splice(pos,1);
			}
		}
		
		this.notifyAll=function(stateId, stateParam)
		{
			var result=true;
		
			astonlib.Data.each(handlers, function(handler, key) {
				var res=handler(stateId, stateParam);
				if (!isEmpty(res))
				{
					result=result && res;
				}
			});
			
			return result;
		}
		
		this.init=function()
		{
			if (this.notifyOnInit)
			{
				notifyOnInit();
			}
		}
	},
			
	
	Element: function(id)
	{
		astonlib.Notifiers.Element.prototype=astonlib.Notifiers.Abstract;
		astonlib.Notifiers.Abstract.call(this);

		var __this=this;
		
		this.elem=astonlib.DOM.get(document, {'filter.id':[id]});
		
		this.getId=function()
		{
			return id;
		}
		
		this.init=function()
		{
			if (this.notifyOnInit)
			{
				astonlib.DOM.each(this.elem, function(){__this.notifyOnInit.call(this)});
			}
		}
	},
	
	
	OneShot: function(id, eventType)
	{
		if (isEmpty(id))
		{
			astonlib.Notifiers.OneShot.prototype=astonlib.Notifiers.Abstract;
			astonlib.Notifiers.Abstract.call(this);
			this.notifyOnInit=function()
			{
				this.notifyAll('');
			}
		}
		else
		{
			eventType=Function.getArg(eventType, 'click');
			astonlib.Notifiers.OneShot.prototype=astonlib.Notifiers.Element;
			astonlib.Notifiers.Element.call(this, id);
			
			var __this=this;
			astonlib.DOM.each(this.elem, {'each.event':[eventType, function(){__this.notifyAll(this.value);}]});
		}
	},

		
	Combo: function(id)
	{
		astonlib.Notifiers.Combo.prototype=astonlib.Notifiers.Element;
		astonlib.Notifiers.Element.call(this, id);
		
		var __this=this;
		
		this.notify=function()
		{
			return __this.notifyAll(this.value, this.id);
		}
		
		this.notifyOnInit=this.notify;
			
		astonlib.DOM.each(this.elem, {'each.event':['change', this.notify]});
	},
	
	
	Edit: function(id)
	{
		astonlib.Notifiers.Edit.prototype=astonlib.Notifiers.Element;
		astonlib.Notifiers.Element.call(this, id);
			
		var __this=this;
		
		this.notify=function()
		{
			return __this.notifyAll(this.value, this.id);
		}
		
		this.notifyOnInit=this.notify;
	
		astonlib.DOM.each(this.elem, {'each.event':['keyup', this.notify]});
	},
	
	
	Checkbox: function(id)
	{
		astonlib.Notifiers.Checkbox.prototype=astonlib.Notifiers.Element;
		astonlib.Notifiers.Element.call(this, id);
		
		var __this=this;
		
		this.notify=function()
		{
			return __this.notifyAll(this.checked ? "1" : "0", this.id);
		}
		this.notifyOnInit=this.notify;
			
		astonlib.DOM.each(this.elem, {'each.event':['click', this.notify]});
	},
	
	
	// toggle -> toggle between true/false state
	Button: function(id, toggleState, removeOldHandler)
	{
		removeOldHandler=Function.getArg(removeOldHandler, false);
		astonlib.Notifiers.Button.prototype=astonlib.Notifiers.Element;
		astonlib.Notifiers.Element.call(this, id);
	
		var __this=this;
		
		if (!isEmpty(toggleState))
		{
			var cookie=new astonlib.Cookie('toggle_'+id);
			var cook=cookie.get();
			var state= (isEmpty(cook)) ? !toggleState : (cook==0);
		}
		
		this.notify=function()
		{
			if (!isEmpty(toggleState))
			{
				state=!state;
				var result=__this.notifyAll(state ? 1 : 0, this.id);
				cookie.set(state ? 1 : 0);
			}
			else
			{
				var result=__this.notifyAll(this.value, this.id);
			}
					
			return result;
		}
		
		if (!isEmpty(toggleState))
		{
			this.notifyOnInit=this.notify;
		}
		
		if (removeOldHandler)
		{
			astonlib.DOM.each(this.elem, function(){this.onclick=null;});
		}
		astonlib.DOM.each(this.elem, {'each.event':['click', this.notify]});
	}
}
astonlib.OneShotNotifier=astonlib.Notifiers.OneShot;
astonlib.ComboNotifier=astonlib.Notifiers.Combo;
astonlib.ButtonNotifier=astonlib.Notifiers.Button;
astonlib.EditNotifier=astonlib.Notifiers.Edit;
astonlib.CheckboxNotifier=astonlib.Notifiers.Checkbox;



astonlib.showInfoWindow=function(elemObj, contents, viewerObj, idPrefix)
{
	new astonlib.InfoWindow(elemObj, contents, viewerObj, idPrefix);
}



astonlib.HidablePanel=function(id, headerText, hidden, prefix)
{
	prefix=Function.getArg(prefix, 'hid');
	
	var imgId=prefix+'Image_'+id;
	var hdrId=prefix+'Header_'+id;
	var body=document.getElementById(id);
	
	// problems occurred using innerHTML '<tr>..</tr>' in IE6, so I had to use this code
	var table=document.createElement('table');	table.cellspacing=0; table.cellpadding=0;
	table.className=prefix+'Panel';
	
	var tbody=document.createElement('tbody');
	table.appendChild(tbody);
	
	var tr=document.createElement('tr');
	tbody.appendChild(tr);
	
	var img=document.createElement('td'); img.className=prefix+'PanelImage'; img.id=imgId;
	tr.appendChild(img);
	
	var header=document.createElement('td'); header.className=prefix+'PanelHeader';	header.id=hdrId;
	header.innerHTML=headerText;
	tr.appendChild(header);
		
	var body=document.getElementById(id);
	body.parentNode.insertBefore(table, body);

	var changer=new astonlib.PageStateChanger(new astonlib.Notifiers.Button(imgId, true, !hidden), 
			'{"1": {"'+imgId+'!0": ["class=\''+prefix+'PanelImage '+prefix+'PanelImageActive\'"], "'+hdrId+'!0": ["class=\''+prefix+'PanelHeader '+prefix+'PanelHeaderActive\'"], "'+id+'!0": ["show", "ExtOps.cookie={\'name\': \'toggle_'+id+'\', \'value\':1}"]},'+
			' "0":{"'+imgId+'!0": ["class=\''+prefix+'PanelImage\'"], "'+hdrId+'!0": ["class=\''+prefix+'PanelHeader\'"], "'+id+'!0": ["hide", "ExtOps.cookie={\'name\': \'toggle_'+id+'\', \'value\':0}"]}}');
}



astonlib.PageStateSetter=function(state, rootIds, implicitOps)
{
	var changer=new astonlib.PageStateChanger(new astonlib.Notifiers.OneShot(), '{"__default":'+state+'}', rootIds, implicitOps);
}



//pre-filled input -> e.g. for search-box with default text "Search", which disappears on click
//idButton - onclick action on this button will be allowed, only if input is edited (focused) by user
astonlib.PrefilledInput=function(id, idButton, initialValue, styleClass)
{
	var ops='';
	var elem=document.getElementById(id);
	
	if (idButton)
	{
		ops+=', "ExtOps.call={\'astonlib.PrefilledInput.focused\':[\''+idButton+'\']}"';
		var button=document.getElementById(idButton);
		
		astonlib.Events.add(button, 'click');
		button.onclick=function(){return false;};
	}
	
	if (styleClass)
	{
		ops+=', "class=\''+elem.className+' '+styleClass+'\'"';
	}
	
	if (initialValue)
	{
		elem.value=initialValue;
	}
	
	return new astonlib.PageStateChanger(new astonlib.Notifiers.OneShot(id, 'focus'),
		'{"__default": {"'+id+'!0": ["value=\'\'"'+ops+']}}');
}

astonlib.PrefilledInput.focused=function(idButton)
{
	var button=document.getElementById(idButton);
	button.onclick=astonlib.Events._execute;
}



// simple (and dirty) filler for combo-boxes (don't use in new projects, included only for compatibility reasons)
// NOTE: previous version didn't use PageStateChanger
astonlib.SimpleFiller=function(id, fillId, data)
{
	var fillElem=document.getElementById(fillId);
	fillElem.data=data;
	fillElem.savedOptions=astonlib.DOM.Combo.getOptions(fillElem);

	var changer=new astonlib.PageStateChanger(new astonlib.Notifiers.Combo(id),
			'{"__default":{"'+fillId+'!0":["ExtOps.call={\'astonlib.SimpleFiller.fill\':[]}"]}}');

	astonlib.DOM.Input.restoreValue(fillElem);
	astonlib.Events.add(fillElem, 'change', function(){astonlib.DOM.Input.saveValue(this)});
}

astonlib.SimpleFiller.fill=function(currentKey)
{
	var domElem=this[0];
	astonlib.DOM.Combo.addOptions(domElem, domElem.savedOptions, true);
	astonlib.Data.each(domElem.data, function(value) {
		if (value.key==currentKey)
		{
			var currentValue=value.value;
			domElem.options.add(new Option(currentValue[1], currentValue[0]));
		}
	});
}



// set button as default
astonlib.DefaultButton=function(buttonId, formName)
{
	var button=document.getElementById(buttonId);
	var form=Function.getArg(formName, button.form, document[formName]);
	
	var redirectToDefault=function(e)
	{
		if (e.keyCode==13)
		{
			e.propagate=false;
			button.click();
		}
	}
	
	astonlib.DOM.each(form, {'each.event':['keypress', redirectToDefault]},
							{'filter.input':[], '!filter.is':[button]});
}



// simple & stupid JS menu highlighter (for server-side generated menus)
astonlib.MenuHighlighter=function(menuIds, defaultClass, hoverClass, highlightClass, menuName)
{
	menuIds=String.getJSON(menuIds);
	menuName=Function.getArg(menuName, 'mainMenu');
	defaultClass=Function.getArg(defaultClass, 'item');
	hoverClass=Function.getArg(hoverClass, 'hover');
	highlightClass=Function.getArg(highlightClass, 'highlight');
	var cook=new astonlib.Cookie(menuName);
	
	var saveItem=function()
	{
		cook.set(this.id);
	}
	
	var currentItem=cook.get();
	if (!isEmpty(currentItem))
	{
		var elem=document.getElementById(currentItem);
		if (elem)
		{
			elem.className=defaultClass+' '+highlightClass;
			elem.onclick=null;
			elem.style.cursor='default';
		}
	}
	
	astonlib.Data.each(menuIds, function() {
			var elem=document.getElementById(this);
			if (elem)
			{
				astonlib.Events.add(elem, 'click', saveItem);
				astonlib.Events.add(elem, 'mouseover', function(){this.className=defaultClass+' '+hoverClass;});
				astonlib.Events.add(elem, 'mouseout', function(){this.className=defaultClass;});
				elem.className=defaultClass;
			}
		},
			
		function() {
			return this!=currentItem;
		}
	);
}



// Multi-level CSS-styleable menu
// TODO: currently only 2 levels are supported - modify to support more (infinite) levels
// TODO: dynamically resizeable menu
// TODO: integrate with MenuHighlighter (save menu 'selected' state)
astonlib.Menu=function(containerId, items, vertical, prefix)
{
	var HIDE_TIMEOUT=20;

	items=String.getJSON(items);
	vertical=Function.getArg(vertical, false);
	prefix=Function.getArg(prefix, 'main');
	
	var container=document.getElementById(containerId);
	
	var itemMouseOut=function()
	{
		var thisObj=this; // why IE, whyyy??? -> passing 'this' through setTimeout doesn't work
		
		var out=function(/*thisObj*/) {
			if (!thisObj.subMenu || !thisObj.subMenu.hovered)
			{
				astonlib.DOM.Element.setClass(thisObj);
				if (thisObj.subMenu)
				{
					astonlib.Hacks.ieOverlay(thisObj.subMenu, false);
					astonlib.DOM.Element.show(thisObj.subMenu, false);
				}
			}
		}
		
		this.outTimeoutId=setTimeout(out, HIDE_TIMEOUT /*, this*/);
	}
	
	
	var itemMouseOver=function()
	{
		if (this.outTimeoutId)
		{
			clearTimeout(this.outTimeoutId);
			this.timeoutId=null;
		}
		
		astonlib.DOM.Element.setClass(this, 'hover');
		
		if (this.subMenu)
		{
			var left=astonlib.DOM.Element.getPosition(this);
			var top=astonlib.DOM.Element.getPosition(this, true);
			if (vertical)
			{
				left+=this.offsetWidth;
				this.subMenu.style.height=this.offsetHeight+'px';
			}
			else
			{
				top+=this.offsetHeight;
				this.subMenu.style.width=this.offsetWidth+'px';
			}
			
			this.subMenu.style.left=left+'px';
			this.subMenu.style.top=top+'px';
			this.subMenu.style.zIndex=100;
			astonlib.Hacks.ieOverlay(this.subMenu);
			astonlib.DOM.Element.show(this.subMenu);
		}
	}
	
	
	var menuMouseOver=function()
	{
		this.hovered=true;
		astonlib.DOM.Element.setClass(this, 'hover');
	}
	
	
	var menuMouseOut=function()
	{
		this.hovered=false;
		itemMouseOut.call(this.parentItem);
		astonlib.DOM.Element.setClass(this);
	}
	
	
	var createItem=function(item, level)
	{
		var menuItem=document.createElement('li');
		astonlib.Events.add(menuItem, 'click', function(){window.location=item.link;});
		var caption=document.createElement('span'); caption.innerHTML=item.caption; caption.className='caption';
		menuItem.appendChild(caption);
		astonlib.Events.add(menuItem, 'mouseover', itemMouseOver);
		astonlib.Events.add(menuItem, 'mouseout', itemMouseOut);
		return menuItem;
	}
	
	var createSubMenu=function(items, level, parentItem)
	{
		level=Function.getArg(level,0);
		var subMenu=document.createElement('ul');
		var subDiv=document.createElement('div');
		
		if (parentItem)
		{
			subMenu.style.position='absolute';
			astonlib.DOM.Element.show(subMenu, false);
			subMenu.parentItem=parentItem;
			
			astonlib.Events.add(subMenu, 'mouseover', menuMouseOver);
			astonlib.Events.add(subMenu, 'mouseout', menuMouseOut);
		}
		else
		{
			subMenu.id=prefix+'Menu';
			astonlib.DOM.Element.show(subMenu);
		}
		
		subMenu.className='level'+level;
		
		astonlib.Data.each(items, function() {
			var menuItem=createItem(this, level);
			if (this.items)
			{
				menuItem.subMenu=createSubMenu(this.items, level+1, menuItem);
				menuItem.appendChild(menuItem.subMenu);
			}
			subDiv.appendChild(menuItem);
		});
	
		subMenu.appendChild(subDiv);
		return subMenu;
	}
	
	container.appendChild(createSubMenu(items));
}



//fill elements from XML
astonlib.XMLFiller=function(mapping, xml)
{
	var SEPAR_TAG=',';
	
	mapping=String.getJSON(mapping);
	
	this.fill=function(xml)
	{
		var xmlDoc=astonlib.Load.xml(xml);

		if (xmlDoc)
		{	
			astonlib.Data.each(mapping, function(mapping, id) {
				
				var value='';
				if (mapping.tags)
				{
					var tags=mapping.tags.split(SEPAR_TAG);
					astonlib.Data.each(tags, function(tag, key) {
						var xmlElem=xmlDoc.getElementsByTagName(this.trim());
						if (xmlElem.length>0)
						{
							value+=mapping.escaped ? xmlElem[0].childNodes[0].nodeValue.unescape() : xmlElem[0].childNodes[0].nodeValue;
							if (String.isInstance(mapping.separator) && key<tags.length-1)
							{
								value+=mapping.separator;
							}
						}
					});
				}
			
				var domElem=document.getElementById(id);
				if (domElem)
				{
					astonlib.DOM.Element.setValue(domElem, value);
				}
			});
		}
	}
	
	if (xml)
	{
		this.fill(xml);
	}
}




// form, with POST submitting and error-handling
// TODO: file-posting
astonlib.Form=function(name, defaultButtonId, errorIdPrefix)
{
	errorIdPrefix=Function.getArg(errorIdPrefix, 'error_');
	
	var form=document[name];
	if (defaultButtonId)
	{
		this.defaultButton=new astonlib.DefaultButton(defaultButtonId, name);
	}
	
	var __this=this;
	
	var getSubmitUrl=function()
	{
		var data={};
		astonlib.Data.each(form.elements, function() {
			if (this.type && astonlib.Data.isIn(['checkbox', 'radio'], this.type.toLowerCase()) && !this.checked)
			{
				return;
			}
			
			data[this.name]=this.value.escape();
		});
		
		return form.action+'?'+astonlib.Data.tokenize(data, '=', '&').substr(1); // TODO: modify after tokenize() correction
	}
	
		
	this.setErrors=function(errors)
	{
		astonlib.Data.each(form.elements, function() {
			var elem=document.getElementById(errorIdPrefix+this.name);
			if (elem)
			{
				astonlib.DOM.Element.setValue(elem);
				astonlib.DOM.Element.show(elem, false);
			}
		});
			
		astonlib.Data.each(errors, function(error, name) {
			var elem=document.getElementById(errorIdPrefix+name);
			if (elem || !error.optional)
			{
				astonlib.DOM.Element.setValue(elem, error.message);
				astonlib.DOM.Element.show(elem);
			}
			
			if (error.focus)
			{
				document.getElementsByName(name)[0].focus();
			}
		});
	}
		
	
	this.submit=function()
	{
		astonlib.Load.ajax('POST '+getSubmitUrl(), function()
				{
					if (this.errors)
					{
						var errors=this.errors;
					}
					else
					{
						var errors={};
					}
					__this.setErrors(errors);
					
					if (!this.errors && this.redirectUrl)
					{
						window.location=this.redirectUrl;
					}
		});
		return false;
	}
	
	astonlib.Events.add(form, 'submit', this.submit);
	this.setErrors({});
}	


// exchange calculator 
astonlib.ExchangeCalc=function(homeCurrency, exRates, typeSelectId, buyInputId, sellInputId, buySelectId, sellSelectId, buyButtonId, sellButtonId, messages)
{
	var CURRENCY_DECIMAL_COUNT=2;
	
	exRates=String.getJSON(exRates);
	
	var selType=document.getElementById(typeSelectId);
	var inpBuy=document.getElementById(buyInputId);
	var inpSell=document.getElementById(sellInputId);
	var selBuy=document.getElementById(buySelectId);
	var selSell=document.getElementById(sellSelectId);
	var btnBuy=document.getElementById(buyButtonId);
	var btnSell=document.getElementById(sellButtonId);
	
	selBuy.options.length=0;
	selSell.options.length=0;
	selBuy.options.add(new Option(homeCurrency, homeCurrency));
	selSell.options.add(new Option(homeCurrency, homeCurrency));
	
	astonlib.Data.each(exRates, function (values, rate){
		selBuy.options.add(new Option(rate,rate));
		selSell.options.add(new Option(rate,rate));
	});
		
	var calculate=function()
	{
		var sell=(this==btnSell);
		var strValue = (sell) ? inpBuy.value : inpSell.value;
		
		var inValue=strValue.toDecimal();
		if (isEmpty(inValue))
		{
			alert(strValue+messages.invalidNumber);
			return;
		}
	
		var type=selType.value;
		var buyRates=exRates[selBuy.value];
		var sellRates=exRates[selSell.value];
				
		var isChange=type.indexOf('chg');
		if (isChange==0)
		{
			var changeType=type.substr(isChange+3);
		}
		
		if (!buyRates)
		{
			if (selBuy.value==homeCurrency)
			{
				buyRate=1;
			}
			/*else
			{
				alert(messages.noRate);
				return;
			}*/
		}
		else
		{
				buyRate= changeType ? buyRates['buy'+changeType] : buyRates[type];
		}
		
		if (!sellRates)
		{
			if (selSell.value==homeCurrency)
			{
				sellRate=1;
			}
			/*else
			{
				alert(messages.noRate);
				return;
			}*/
		}
		else
		{
			sellRate= changeType ? sellRates['sell'+changeType] : sellRates[type];
		}
		
		if (!(buyRate && sellRate))
		{
			alert(messages.noRate);
			return;
		}
				
		var outValue={};
		var inRate = (sell) ? buyRate : sellRate;
		var outRate = (sell) ? sellRate : buyRate;
		
		outValue.value=(inValue.value*inRate/outRate).toFixed(CURRENCY_DECIMAL_COUNT);
		outValue.decimal=inValue.decimal;
		outValue=String.fromDecimal(outValue);
		
		if (sell)
		{
			inpSell.value=outValue;
		}
		else
		{
			inpBuy.value=outValue;
		}
	}
			
			
	var changeType=function()
	{
		var buyHome = (selBuy.value==homeCurrency);
		var sellHome = (selSell.value==homeCurrency);
		
		var types=[];
		
		// customer BUY means bank SELL
		// customer SELL means bank BUY
		if (buyHome)
		{
				types=['sellCash', 'sell'];
		}
		else {
			if (sellHome)
			{
				types=['buyCash', 'buy'];
			}
			else
			{
				types=['chgCash', 'chg'];
			}
		}
			
		types.push('midCash');
		types.push('mid');
		
		selType.options.length=0;
		astonlib.Data.each(types, function(name) {
			selType.options.add(new Option(messages[name],name));
		});
	}
		
	btnBuy.onclick=calculate;
	btnSell.onclick=calculate;
	
	selBuy.onchange=changeType;
	selSell.onchange=changeType;
	
	changeType();
}


/******** AWeb/jQuery stuff *******/
if (window.jQuery)
{
	// highlight table row on click
	astonlib.TableRowHighlighter=function(tableClass, rowSelectedClass, parent)
	{
		tableClass=Function.getArg(tableClass, 'list');
		rowSelectedClass=Function.getArg(rowSelectedClass, 'selectedRow');
		parent=Function.getArg(parent, document.body);
		
		var tables=$('table.'+tableClass, parent);
	
		function rowClicked()
		{	
			if (this.table.selectedRow)
			{
				$(this.table.selectedRow).removeClass(rowSelectedClass);
			}
			
			if (this.table.selectedRow!=this)
			{
				$(this).addClass(rowSelectedClass);
				this.table.selectedRow=this;
			}
		}
		
		tables.each(function() {
			var table=this;
			var row=$('tr', this);
			row.click(rowClicked);
			row.each(function() {
				this.table=table;
			});
		});
	}
	
	
	astonlib.Log = function(text)
	{
		$("<div class='log'>" + text + "</div>").appendTo("body");
	}
	
	astonlib.ajaxLoad = function(parent)
	{
		$(parent).find("a.ajaxLoad").each(function()
		{
			var a = this;
			$.ajax({ url: a.href, success: function(html){$(a).replaceWith(html);} });
		});
	}
	
	
	astonlib.SlidePanel = function(name)
	{
		name=(name==undefined)?'.slide_panel':'#'+name;
				
		var header = $(name+'>.panel_header');
		var body = $(name+'>.panel_body');
	
				
		this.show=function()
		{
			header.addClass('panel_header_active');
			body.slideSell('fast'); 
		}
			
		this.hide = function()
		{
			header.attr('class', 'panel_header');
			body.slideUp('fast'); 
		}
		
		this.show();	
	}
	
	
	astonlib.AccordionPanel = function(name, fixHeight) 
	{	
		var key = (name==undefined) ? ".accordion_panel" : "#"+name;
		var linkClick = function()
		{
			if($(this).attr("class")!="panel_header_active")
			{
				$(key+">.panel_header_active").attr("class", "panel_header");
				$(this).addClass("panel_header_active");
			    var hide_el = $(key+">.panel_body:visible");
			    $(this).next(".panel_body").slideSell("fast");
			    hide_el.slideUp("fast");
				$(key+">[error=1]").addClass("error");
			}
		};
		var fixLinkClick = function()
		{
			if($(this).attr("class")!="panel_header_active")
			{
				$(key+">.panel_header_active").attr("class", "panel_header");
				$(this).addClass("panel_header_active");
			    var hide_el = $(key+">.panel_body:visible");
			    var show_el = $(this).next(".panel_body");
			    var body_height = hide_el.height();
				show_el.css({ height: 0, overflow: 'hidden' }).show();
			    hide_el.animate({height:"hide"},{ step: function(now) { show_el.height(Math.ceil(body_height - now)); }});
				$(key+">[error=1]").addClass("error");
			}
		};
		
	    var headers = $(key+">.panel_header").click(fixHeight>0 ? fixLinkClick : linkClick);
	    if(fixHeight>0)
	    {
	    	$(key).height(fixHeight);
	    	var body_height = fixHeight;
	
	    	headers.each(function() { body_height -= $(this).height(); });
	    	$(key+">.panel_body").height(body_height);
	    }
	    $(key+">.panel_body:gt(0)").hide();
	    $(key+">.panel_header:eq(0)").addClass("panel_header_active");
	    
	    this.show = function(pos)
	    {
			headers.eq(pos).click();
	    };
	
	    this.setErrorPanel = function(pos, err)
	    {
			if(err) headers.eq(pos).attr("error", "1").addClass("error");
			else headers.eq(pos).removeAttr("error").removeClass("error");
	    };
	};
	
	astonlib.TabPanel = function(name)
	{
		var key = (name==undefined) ? ".tab_panel" : "#"+name;
		var tab_body = $(key).after('<div class="tab_body"></div>').next();
		var tabClick = function()
		{
			if($(this).attr("class")!="panel_header_active")
			{
				$(key+">.panel_header_active").attr("class", "panel_header");
				$(this).addClass("panel_header_active");
				tab_body.html($(this).next(".panel_body").html());
			}
			$(key+">[error=1]").addClass("error");
		};
	    $(key+">.panel_body").hide();
	    var headers = $(key+">.panel_header").click(tabClick);
	
	    this.show = function(pos)
	    {
			headers.eq(pos).click();
	    };
	
	    this.setErrorTab = function(pos, err)
	    {
			if(err) headers.eq(pos).attr("error", "1").addClass("error");
			else headers.eq(pos).removeAttr("error").removeClass("error");
	    };
		this.show(0);
	};
	
	astonlib.Combo = function(name, items)
	{
		var el = $("#"+name);
		var modal = $('<div class="combo_modal"></div>');
		modal.hide().css({position: 'absolute', 'z-index': 1000}).appendTo("body");
		for(var i in items)
		{
			var elitem = $("<div>"+items[i]+"</div>");
			elitem.click(function() { el.val($(this).text()); modal.hide(); });
			modal.append(elitem);
		}
		this.show = function()
		{
			var pos = el.offset();
			var width = Math.max(el.width(), modal.width());
			modal.css({top: pos.top+el.height()+6, left: pos.left, width: width});
			modal.show();
		};
		this.hide = function()
		{
			modal.hide();
		};
		this.filter = function()
		{
			var text = el.val();
			modal.children().each(function(){ if($(this).text().indexOf(text)==0) $(this).show(); else $(this).hide(); });
		};
	
		modal.mousedown(function(e)
		{
			var x = e.pageX - this.offsetLeft;
			var y = e.pageY - this.offsetTop;
			astonlib.log("x=y: "+x+"="+y);
			e.stopPropagation();
		});
	
		modal.mouseup(function(e)
		{
			e.stopPropagation();
		});
	
		modal.mouseover(function(e)
		{
			e.stopPropagation();
		});
	
		el.after("<span>xx</span>").next().toggle(this.show, this.hide);
		el.bind("keyup", this.filter);	
		el.bind("keyup", this.show);	
	};
	
	astonlib.ContentMenu = function(clname)
	{
		$('ul.content_menu').each(function()
		{
			var ul_el = $(this);
			var btn_el = $('<span class="button_content_menu"></span>').append(ul_el.find('>li:first').html()).insertBefore(ul_el);
			
			var modal = $('<div class="content_menu_panel"></div>');
			modal.hide().css({position: 'absolute', 'z-index': 1000}).appendTo('body');
			modal.append(ul_el);
			modal.find('a').each(function(){ this.isModalLink = true; });
	
			var clickBtn = function()
			{	
				if(modal.is(':hidden'))
				{
					$('div.content_menu_panel').hide();
					var pos = btn_el.offset();
					modal.css({top: pos.top+btn_el.height(), left: pos.left});
					modal.show();
				}
				else modal.hide();
				return false;
			};
	
			$(btn_el).click(clickBtn);
		});
		$(document).click(function(e) { if(e.target.isMenuItem!=true) $('div.content_menu_panel').hide(); });
	}
}