var log = function(l) {
	asynx('log').appendHtml(l+"<br>");
};

var asynx = function(query) {
	return asynx.$(query, arguments[1]);
};

asynx.namespace = function(sNameSpace) {
	var levels = sNameSpace.split(".");
	var curLevel = asynx;
	for (var i = (levels[0] == "asynx") ? 1 : 0; i < levels.length; i++) {
 		curLevel[levels[i]] = curLevel[levels[i]] || {};
		curLevel = curLevel[levels[i]];
	};
	return curLevel;
};
	
asynx.extend = function() {
	var obj = arguments[0];
	var target = arguments[1];
	
	for (i in target) {
		obj[i] = target[i];
	}
	
	return obj;
};

asynx.path = function() {
	var r = /[\/]asynx[^\/js]*\.js$/g, p = "./";
	asynx('//script').each(function(s){
		if (r.test(s.src)) p=s.src.replace(r,"");
	});
	return p;
}

asynx.load = function(p) {

	var onComplete = function(r, a) {
		
		var f = asynx("//plugin", r);
		
		f.each(function(pl,x) {
			
			var s = pl.childNodes[x];
			
			var el = asynx('//name', pl)
			//var el = asynx.dom.getByTagName([pl], 'name');
			
			alert(el)
		});
	},
	
	ifNotMod = function(r,a) {
		log(r + ':' + a)
	};

	asynx.$ifUpdated(asynx.path()+'/plugins/config.xml',{},
		onComplete, null, ifNotMod, null, 'xml');
};

asynx.namespace("impl.core");

asynx.impl.core = {
	
	userAgent: navigator.userAgent.toLowerCase(),
	isSafari: false,
	isOpera: false,
	isIE: false,
	isFirefox: false,
	
	init: function() {
		window.asynx$ = asynx.$;  		
	},
	
	$: function() {
		var expression = arguments[0], s = arguments[1];
		var nodes = new asynx.selector(expression, s);
		return nodes;
	},
	
	browser: function() {
		this.isSafari = !!(/webkit/.test(this.userAgent));
		this.isOpera = !!(/opera/.test(this.userAgent));
		this.isIE = !!(/msie/.test(this.userAgent) && !/opera/.test(this.userAgent));
		this.isFirefox = !!(/mozilla/.test(this.userAgent) && /firefox/.test(this.userAgent));
	}
	
};

asynx.extend(asynx, asynx.impl.core);
asynx.init();
asynx.browser();
delete asynx.impl.core;

asynx.namespace("globals");
asynx.namespace("globals.ajax.threads");
asynx.namespace("globals.ajax.config");
asynx.namespace("globals.ajax.urlModifiedDates");
asynx.namespace("globals.cookies.cookiesCached");
asynx.namespace("globals.drag.lastzIndex");
asynx.globals.ajax.threads = [];
asynx.globals.ajax.config = {};
asynx.globals.ajax.urlModifiedDates = {};
asynx.globals.drag.lastzIndex = 0;


asynx.namespace("dom");

asynx.dom = {
	
	walk: function(node, func) {
        func(node);
        node = node.firstChild; 
        while (node) { 
            this.walk(node, func); 
            node = node.nextSibling; 
        } 
    },
	
	walkParents: function(node, func) {
        while (node) { 
	        func(node);
            node = node.parentNode; 
        } 
    },
	
	getChildNodes: function(rNode) {
		var element = typeof rNode == "object" ? rNode : document.getElementById(rNode);
		var results = []; 
		this.walk(element, function (node) { 
			results.push(node);
	    }); 
	    return results; 
	},
	
	getByClassName: function(className) { 
	    var results = []; 
		var context = arguments[1];
	    this.walk(context?context:document.body, function (node) { 
	        var a, c = node.className, i; 
	        if (c) { 
	            a = c.split(' '); 
	            for (i = 0; i < a.length; i += 1) { 
	                if (a[i] === className) { 
	                    results.push(node); 
	                    break; 
	                } 
	            } 
	        } 
	    }); 
	    return results; 
	},

	getByAttribute: function(attribute) { 
	    var results = []; 
		var sValue = arguments[1];
		
		if (!attribute) return [];
		var xQuery = "[@a='v']".replace("a", attribute);
		
		if (sValue) 
			xQuery=xQuery.replace("v", sValue);
		else
			xQuery=xQuery.replace("='v'", "");
		
		return asynx.xpath.getNodes(xQuery);
	},
	
	getByTagName: function(scopes, sTagName) {
		var nodeStore = [];
		try{
			for (var i=0; i<scopes.length;i++) {
				var scope = scopes[i];
				if (!scope) continue;
				var nodes = scope.getElementsByTagName(sTagName);
				asynx.merge(nodeStore, nodes);
			}
		}catch(e){}
		
		return nodeStore;
	},
	
	getFormByName: function(rForm, sName) {
		var elements = rForm.elements;
		for (var i = 0; i < elements.length; i++) {
			var element = elements[i];
			if (element.name == sName) return element;
		}
		return null;
	},
	
	append: function(f, c) {
		f.appendChild(c);
	},
	
	prepend: function(f, c) {
		f.insertBefore(c, f.firstChild);
	},
	
	before: function(f, c) {
		f.parentNode.insertBefore(c, f);
	},
	
	after: function(f, c) {
		f.parentNode.insertBefore(c, f.nextSibling);
	},
	
	remove: function(f, c) {
		if (c.zIndexFixer)
			f.removeChild(asynx(c.zIndexFixer));
		
		f.removeChild(c);
	}
	
};


asynx.namespace("event");

asynx.event = {
	
	BACKSPACE: 8,
	TAB: 9,
	RETURN: 13,
	ENTER: 13,
	SHIFT: 16,
	CONTROL: 17,
	ESC: 27,
	SPACE: 32,
	PAGEUP: 33,
	PAGEDOWN: 34,
	END: 35,
	HOME: 36,
	LEFT: 37,
	UP: 38,
	RIGHT: 39,
	DOWN: 40,
	DELETE: 46,
	F5: 116,
	
	cache: [],
	
	isCached: function(element, fn, type, args) {
		var cached = false;
		asynx.each(asynx.event.cache, function(evtCached) {
			if (evtCached && asynx.isInArray(element, evtCached) && asynx.isInArray(fn, evtCached) && asynx.isInArray(type, evtCached) && asynx.isInArray(args, evtCached)) cached = true;
		});
		return cached;
	},
	
	unloadCache: function() {
		asynx.each(asynx.event.cache, function(evtCached, x) {
			if (evtCached) {
				var cachedElement = evtCached[0];
				var cachedType = evtCached[1];
				var cachedFn = evtCached[2];
				var cachedHandle = evtCached[4];
				this.removeListener(cachedType, cachedElement, cachedFn);
				delete asynx.event.cache[x];
			}
		}, this);
	},
	
	add: function(type, el) {
		var fn = arguments[2];
		var args = arguments[3];
		var nodes = asynx$(el);
		
		asynx.each(nodes, function(node) {
			this.addListener(type, node, fn, args);
		}, this);
	},
	
	addListener: function(type, el) {
		var nodes = asynx$(el);
		var fn = arguments[2];
		var args = arguments[3];
		var element = nodes;
		
		if (!fn || !type) return;
		
		var handle = function(e) {
			e = asynx.event.fix(e?e:event);
			fn.apply(element, [e, args]);
			if (asynx.isIE)
				event.target = event.preventDefault = event.stopPropagation = null;
		};
		
		if (!this.isCached(element, fn, type, args)) {
			if (element.addEventListener)
				element.addEventListener(type, handle, false);
	
			else if (element.attachEvent && !this.isCached(element, fn, type, args)) { 
				element.attachEvent('on'+type, handle);
			}
		}
		// cache
		if (!this.isCached(element, fn, type, args)) 
			asynx.event.cache.push([ element, type, fn, args, handle ]);
		
		return element;
	},
	
	remove: function(type, el) {
		var fn = arguments[2];
		var nodes = asynx$(el);

		asynx.each(nodes, function(node) {
			this.removeListener(type, node, fn);
		}, this);
	},
	
	removeListener: function(type, el) {
		var nodes = asynx$(el);
		var fn = arguments[2];
		var element = nodes;
		if (!type) return;
		
		asynx.each(asynx.event.cache, function(evtCached, x) {
			
			if (evtCached) {
				var cachedElement = evtCached[0];
				var cachedType = evtCached[1];
				var cachedFn = evtCached[2];
				var cachedHandle = evtCached[4];
	
				var hasListener = !!(cachedFn == fn);
				var hasType =  !!(cachedType == type);
				var hasElement = !!(cachedElement == element);
				
				var removeEvent = function() {
					if (element.removeEventListener)
						element.removeEventListener(type, cachedHandle, false);
					else
						element.detachEvent("on"+type, cachedHandle);
				};
				
				if (!fn && hasElement && hasType) {
					removeEvent();
					delete asynx.event.cache[x];
				}
			
				if (fn && hasElement && hasType && hasListener) {
					removeEvent();
					delete asynx.event.cache[x];
				}
			}
		});
			
	},
	
	click: function(el, fn) {
		var args = arguments[2];
		this.add('click', el, fn, args);
	},
	
	dblclick: function(el, fn) {
		var args = arguments[2];
		this.add('dblclick', el, fn, args);
	},
	
	blur: function(el, fn) {
		var args = arguments[2];
		this.add('blur', el, fn, args);
	},
	
	change: function(el, fn) {
		var args = arguments[2];
		this.add('change', el, fn, args);
	},
	
	focus: function(el, fn) {
		var args = arguments[2];
		this.add('focus', el, fn, args);
	},
	
	load: function(el, fn) {
		var args = arguments[2];
		this.add('load', el, fn, args);
	},
	
	keypress: function(el, fn) {
		var args = arguments[2];
		this.add('keypress', el, fn, args);
	},
	
	keyup: function(el, fn) {
		var args = arguments[2];
		this.add('keyup', el, fn, args);
	},
	
	keydown: function(el, fn) {
		var args = arguments[2];
		this.add('keydown', el, fn, args);
	},
	
	mouseover: function(el, fn) {
		var args = arguments[2];
		this.add('mouseover', el, fn, args);
	},
	
	mouseout: function(el, fn) {
		var args = arguments[2];
		this.add('mouseout', el, fn, args);
	},
	
	mousedown: function(el, fn) {
		var args = arguments[2];
		this.add('mousedown', el, fn, args);
	},
	
	mouseup: function(el, fn) {
		var args = arguments[2];
		this.add('mouseup', el, fn, args);
	},
	
	mousemove: function(el, fn) {
		var args = arguments[2];
		this.add('mousemove', el, fn, args);
	},
	
	onLoad: function(fn) {
		var args = arguments[1];
		this.add('load', window, fn, args);
	},
	
	onStopTyping: function(el, fn) {
		var uargs = arguments[2];
		var delay = arguments[3];
		var interval = null;
		
		this.keydown(el, function(e, args) {
			clearInterval(interval);
		});
		
		this.keyup(el, function(e, args) {
			clearInterval(interval);			
			interval = asynx.executeOn(function() {
				fn.apply(el, [e, uargs])
			}, delay?delay:1000);
		});
	},
	
	// opera doesnt call multiple times
	whileKeyPressed: function(el, keys) {
		el=asynx(el);
		var fn = arguments[2];
		var fargs = arguments[3];
		var fnEnd = arguments[4];
		var fargsEnd = arguments[5];
		asynx.event.key(el,{keys:keys,type:'keydown'},function(e, a) {
			if(fn)fn.apply(this,[e,fargs]);
		});
		asynx.event.key(el,{keys:keys,type:'keyup'},function(e, a) {
			if(fnEnd)fnEnd.apply(this,[e,fargsEnd]);
		});
	},

	wait: function(sObjName, fn) {
		var scope = arguments[2];
		var interval = asynx.executeOn(function() {
			if (asynx$(sObjName)) {
				asynx.executeOn(function() { fn.apply(scope); }, 50);
				clearInterval(interval);
			}
		}, 20, true, scope);
	},
	
	
	key: function(el, attrs, fn) {
		var element = asynx$(el);
		var type = attrs.type?attrs.type:"keyup";
		attrs.fn = arguments[2];
		attrs.args = arguments[3];

		this.addListener(type, element, function(e, args) {
			
			var shiftPressed = args.shift?true:false;
			var altPressed = args.alt ?true:false;
			var ctrlPressed = args.ctrl?true:false;
			var pressed = e.which;
			var validKey = false;
			
			asynx.each(args.keys, function(key) {
				if (!/\d+/.test(key))
					key = key.toString().charCodeAt(0);
				if (pressed == key)	validKey = true;
			});
			
			var meta = !!(e.ctrlKey == ctrlPressed &&
				 e.altKey == altPressed && e.shiftKey == shiftPressed);
			
			if (meta && validKey)
				args.fn.apply(element, [e, args.args]);	
						
		}, attrs);
	},
	
	
	getMouseXY: function(e) {
		var posx = 0;
		var posy = 0;
		if (!e) var e = window.event;
		if (e.pageX || e.pageY) 	{
			posx = e.pageX;
			posy = e.pageY;
		}
		else if (e.clientX || e.clientY) 	{
			posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
			posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
		}
		//return { x: posx, y:posy }; 
		return [posx, posy]; 
	},
	
	
	fix: function(event) {
		var original = event;
		event = asynx.extend({}, original);
		
		event.preventDefault = function() {
			if (original.preventDefault)
				return original.preventDefault();
			original.returnValue = false;
		};
		event.stopPropagation = function() {
			if (original.stopPropagation)
				return original.stopPropagation();
			original.cancelBubble = true;
		};
		
		if ( !event.target && event.srcElement )
			event.target = event.srcElement;
				
		if (asynx.isSafari && event.target.nodeType == 3)
			event.target = original.target.parentNode;

		if ( !event.relatedTarget && event.fromElement )
			event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;

		if ( event.pageX == null && event.clientX != null ) {
			var e = document.documentElement, b = document.body;
			event.pageX = event.clientX + (e && e.scrollLeft || b.scrollLeft);
			event.pageY = event.clientY + (e && e.scrollTop || b.scrollTop);
		}
			
		if ( !event.which && (event.charCode || event.keyCode) )
			event.which = event.charCode || event.keyCode;
		
		if ( !event.metaKey && event.ctrlKey )
			event.metaKey = event.ctrlKey;

		if ( !event.which && event.button )
			event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
			
		return event;
	}
	
};



asynx.namespace("ajax");

asynx.ajax = function(attr) {
	this.init(attr);
}

asynx.ajax.prototype = {
	
	init: function(attr) {
		this.url = attr.url;
		this.method = attr.method?attr.method:'post';
		this.format = attr.format?attr.format:'text';
		this.charset = attr.charset?attr.charset:'utf-8';
		this.ifModified = attr.ifModified===true?true:false;
		this.ifNotModified = attr.ifNotModified;
		this.ifNotModifiedArgs = attr.ifNotModifiedArgs;
		this.onComplete = attr.onComplete;
		this.onCompleteArgs = attr.onCompleteArgs;
		this.loading = attr.loading;
		this.loadingArgs = attr.loadingArgs;
		this.onError = attr.onError;
		this.onErrorArgs = attr.onErrorArgs;
		this.json = attr.json===true?true:false;
		this.async = attr.async===false?false:true;
		this.script = attr.script===true?true:false;
		this.requestValues = {};
		this.requestObjects = [];
		this.xmlhttp = asynx.ajax.thread.getXMLHttpRequest();
		this.submiting = false;
		this.linkedForm = null;
		this.resetForm = true;
	},
	
	load: function() {
		asynx.ajax.thread.run(this);				
	},
	
	addValue: function(sKey, sValue) {
		this.requestValues[sKey] = sValue;
	},
	
	addObject: function(el) {
		var element = asynx$(el);
		try{
			this.requestObjects.push({name: element.name, value: element.value});
		}
		catch(e){ /*TODO*/ }
	},
	
	submit: function(form) {
		this.submiting = true;
		this.linkedForm = form;
		this.resetForm = arguments[1]==false?false:true;
	},
	
	buildRequestString: function() {
		var string = "";
		for (key in this.requestValues) {
			if (typeof this.requestValues[key] !== 'function') {
				value = this.requestValues[key];
				string += key+'='+encodeURIComponent(value)+"&";
			}
		}
		for (x in this.requestObjects) {
			object = this.requestObjects[x];
			if (object.name) string += object.name+'='+encodeURIComponent(object.value)+"&";
		}
		return string;
	}
	
}

asynx.ajax.thread = {
	
	states: ['uninitialized', 'open', 'sent', 'receiving', 'loaded'],
	locked: false,
	thread: 0,
	
	run: function(connector) {
		asynx.globals.ajax.threads.push(connector);
		
		if (!this.locked)
			this.dispatch();
	},
	
	dispatch: function() {
		
		this.locked = true;
		var connector = asynx.globals.ajax.threads[asynx.ajax.thread.thread];
		
		if (!connector) {
			this.locked = false;
			return;
		};
		
		if (connector.submiting) {
			this.ajaxSubmit(connector);			
			return;	
		};
		
		try {

			var xmlhttp = connector.xmlhttp;
			var sinceModified = asynx.globals.ajax.urlModifiedDates[connector.url] || new Date(0);
			
			var headers = [
				["If-Modified-Since", sinceModified],
				["X-Requested-With", 'XMLHttpRequest'],
				["Content-Type", 'application/x-www-form-urlencoded; charset='+connector.charset+';'],
				["Content-Length", connector.buildRequestString().length]
			];
			
			this.callLoading(connector);
			
			var isGet = !!(connector.method.toLowerCase() == 'get');
			var url = isGet ? connector.url+"?"+connector.buildRequestString() : connector.url;
			var sendData = isGet?null:connector.buildRequestString();
			
			xmlhttp.open(connector.method, url, connector.async);
			
			//log(xmlhttp.method);
			
			if (!asynx.isIE && connector.format == "xml")
				xmlhttp.overrideMimeType('text/xml');
			
			/*
			 * headers
			 */
			asynx.each(headers, function(header) {
				xmlhttp.setRequestHeader(header[0], header[1]);
			});
						
			xmlhttp.send(sendData);
			
			this.callLoading(connector);
			
			xmlhttp.onreadystatechange = function() {
				asynx.ajax.thread.processReadyState(connector);
			}
			
		}catch(e) {
			asynx.ajax.thread.finalize(connector);
		}
		
	},
	
	processReadyState: function(connector) {
		try {
			
			var xml = connector.xmlhttp;
			this.callLoading(connector);
			
			if (xml.readyState == 4) {
				
				var status = xml.status;
				var translated = this.translate(status);
				
	            if (translated == 'OK') {
					
					try {
						
						var type = xml.getResponseHeader("Content-Type");
						
						var urlModDates = asynx.globals.ajax.urlModifiedDates;
						var lastMod = xml.getResponseHeader("Last-Modified");
						
						// cache url x lastDate
						if (connector.ifModified && lastMod)
							urlModDates[connector.url] = lastMod;
							
					}
					catch(e){};
	
					this.callComplete(connector);
					this.done();
	            }
				
				else if (translated == 'Not-Modified') {
					this.callNotModified(connector);
					this.done();
				}
				
				else {
					this.callError(connector);
					this.done();
	            }
				
	        }
		
		}catch(e){
			alert(e.message);
			asynx.ajax.thread.finalize(connector);
		}
	},
	
	translate: function(status) {
		var index = {
			200:"OK", 304:"Not-Modified",
			400:"Bad Request", 401:"Unauthorized",
			403:"Forbidden", 404:"Not-Found",
			500:"Internal Server Error"
		};
		return index[status];
	},
	
	ajaxSubmit: function(connector) {
		var uid = "asynx_ajax_submit_" + asynx.uid();
		var iframe = asynx.createIframe(uid);
		var lForm = connector.linkedForm;
		var originalForm = asynx.extend({}, lForm);
		var extra = connector.buildRequestString();
		
		asynx.each(extra.split("&"), function(part) {
			if (part && part.constructor == String) {
				var key = part.split("=")[0];
				var value = part.split("=")[1];
				
				if (key && value && !lForm.elements[key]) {
					var hidden = document.createElement("input");
					hidden.type = 'hidden';
					hidden.name = key;
					hidden.value = value;
					hidden.setAttribute("asynxId", "__asynx_hidden_"+asynx.uid());
					lForm.appendChild(hidden);			
				}
			}
		});
		
		lForm.enctype = 'multipart/form-data';
		lForm.target = uid;
		lForm.method = connector.method;
		lForm.action = connector.url;
		lForm.submit();
		
		// reset form
		lForm.target = originalForm.action;
		lForm.action = originalForm.target;
		
		asynx$("//input[@asynxId^='__asynx_hidden_']").each(function(hidden) {
			if (hidden.constructor!=Array)
				lForm.removeChild(hidden);
		});
		
		if (connector.resetForm)
			lForm.reset();
		
		// callback
		var fn = function() {
			var r = asynx.iframeDoc(iframe).body.innerHTML;
			connector.onComplete.apply(this, [r, connector.onCompleteArgs]);
			
			asynx.executeOn(function() {
				asynx$("/body").removeChild(iframe);
			}, 100);
		};
		
		// mozilla and opera
		iframe.onload = function() {
			fn.apply(this);
		}
		 // ie
		if (asynx.isIE) {
			iframe.onreadystatechange = function() {
				var readyState = iframe.readyState;
				if (readyState == "complete") fn.apply(this);
			}
		}
		
		this.locked = false;
	},
	
	next: function() {
		asynx.ajax.thread.thread++;
		this.locked = false;
		this.dispatch();
	},
	
	done: function() {
		asynx.ajax.thread.next();
	},
	
	callLoading: function(connector) {
		if (connector.loading)
			connector.loading.apply(this, 
				[asynx.ajax.thread.states[connector.xmlhttp.readyState], connector.loadingArgs]);
	},
	
	callComplete: function(connector) {
		
		if (!connector.onComplete)
			return false;
		
		var xml = connector.xmlhttp;
		
		//log(xml);
		
		var isTextData = !!(connector.format == 'text');
		var response = isTextData?xml.responseText:xml.responseXML;
		
		
		if (isTextData && connector.script) {
			try { eval(response); }
			catch(e){};
		};
			
		if (isTextData && connector.json && !connector.script)
			response = asynx.evalJSON(xml.responseText);
		
		connector.onComplete.apply(this, [response, connector.onCompleteArgs]);
	},
	
	callError: function(connector) {
		var status = connector.xmlhttp.status;
		var translated = this.translate(status);
		if (connector.onError)
			connector.onError.apply(this, 
				[translated?translated:status, connector.xmlhttp.responseText, connector.onErrorArgs]);
	},
	
	callNotModified: function(connector) {
		if (!connector.ifNotModified) return false;
		connector.ifNotModified.apply(this, [connector.ifNotModifiedArgs]);
	},
	
	getXMLHttpRequest: function() {
		if (window.ActiveXObject) 
			return new ActiveXObject("Microsoft.XMLHTTP");
		else
			return new XMLHttpRequest();
	},
	
	finalize: function(connector) {
		try { connector.xmltttp.abort(); }
		catch(e) { /* TODO	*/ }
		asynx.ajax.thread.next();
	}
	
};

asynx.ajax.impl = {
	
	$open: function(url) {
		var data = arguments[1], fn = arguments[2], 
			fnargs = arguments[3], method = arguments[4],
			json = arguments[5], script = arguments[6], f = arguments[7];
		
		var ajax = new asynx.ajax({
			url:url,
			method:method?method:'post',
			format:f?f:'text',
			json:json==true?true:false,			
			script:script==true?true:false,			
			onComplete: function(r, args) {
				if (fn)	fn.apply(this, [script?args:r, args]);
			},
			onCompleteArgs: fnargs
		});
		
		asynx.forEach(data, function(k, v) {
			ajax.addValue(k,v);
		});
		ajax.load();
	},
	
	$get: function(url) {
		var data = arguments[1];
		var fn = arguments[2];
		var fnargs = arguments[3];
		this.$open(url, data, fn, fnargs, "get");
	},
	
	$post: function(url) {
		var data = arguments[1];
		var fn = arguments[2];
		var fnargs = arguments[3];
		this.$open(url, data, fn, fnargs, "post");
	},
	
	$submit: function(el, url) {
		el = asynx(el);
		var data = arguments[2];
		var fn = arguments[3];
		var fnargs = arguments[4];
		var method = arguments[5];
		
		var ajax = new asynx.ajax({
			url: url,
			method: method?method:'post',
			onComplete: function(r, args) {
				if (fn)	fn.apply(this, [r, args]);
			},
			onCompleteArgs: fnargs
		});
		
		asynx.forEach(data, function(k, v) {
			ajax.addValue(k,v);
		});
		
		ajax.submit(el, false);
		ajax.load();
	},
	
	$getJSON: function(url) {
		var data = arguments[1];
		var fn = arguments[2];
		var fnargs = arguments[3];
		this.$open(url, data, fn, fnargs, "post", true);
	},
	
	$getXML: function(url) {
		var data = arguments[1];
		var fn = arguments[2];
		var fnargs = arguments[3];
		this.$open(url, data, fn, fnargs, "post", false, false, 'xml');
	},
	
	$getScript: function(url) {
		var data = arguments[1];
		var fn = arguments[2];
		var fnargs = arguments[3];
		this.$open(url, data, fn, fnargs, "post", false, true);
	},
	
	$ifUpdated: function(url) {
		var data = arguments[1], fn = arguments[2],
			fnargs = arguments[3], fMod = arguments[4],
			fnModargs = arguments[5], f = arguments[6];
		
		var ajax = new asynx.ajax({
			ifModified:true,
			url:url,
			method:'get',
			format:f?f:'text',
			onComplete: function(r, args) {
				if (fn)	fn.apply(this, [r, args]);
			},
			onCompleteArgs: fnargs,
			
			ifNotModified: function(args) {
				if (fn)	fMod.apply(this, [args]);
			},
			ifNotModifiedArgs: fnModargs
		});
		
		asynx.forEach(data, function(k, v) {
			ajax.addValue(k,v);
		});
		ajax.load();
	}
	
};

asynx.extend(asynx, asynx.ajax.impl);
delete asynx.ajax.impl;

asynx.impl.array = {
	A: function(obj) {
		var arr = [];
		for(var i = 0; i < obj.length; i++) arr.push(obj[i]);
		return arr;
	},
	
	merge: function(first, second) {
		for (var i = 0; second[i]; i++) {
			first.push(second[i]);
		}
		return first;
	},
	
	diff: function(a1, a2) {
		var ret = [];
		for(var i = 0; i < a1.length; i++) {
			if(!this.canInclude(a2, a1[i])) {
				ret.push(a1[i]);
			}
		}
		return ret;
	},
	
	canInclude: function(array, value) {
		for(var i = 0; i < array.length; i++) {
			if(array[i] == value)
				return true;
		}
		return false;
	},
	
	unique: function(array) {
		for(var i = 0; i < array.length; i++) {
			for(var x = i + 1; x < array.length; x++) {
				if(array[i] == array[x]) {
					for(var z = x; z < array.length - 1; z++)
						array[z] = array[z + 1];
	
					array.length--;
					x--;
				}
			}
		}
		return array;
	},
	
	each: function(array, fn) {
		var scope = arguments[2];
		if (!array[0]) array = [array];
		for (var x=0; x < array.length; x++)
			fn.call(scope?scope:array[x], array[x], x);
	},
	
	forEach: function(obj, fn) {
		var scope = arguments[2];
		for (i in obj) {
			if (typeof obj[i] !== "function") {
				fn.call(scope?scope:obj, i, obj[i]);
			}
		}
	},
	
	isInArray: function(el, array) {
		for (var i = 0; i < array.length; i++) {
			if (el == array[i]) return true;			
		}
		return false;
	}
};

asynx.extend(asynx, asynx.impl.array);
delete asynx.impl.array;


asynx.impl.cookie = {
	
	initCookies: function () {
		var allCookies = document.cookie.split('; ');
		for (var i=0;i<allCookies.length;i++) {
			var cookiePair = allCookies[i].split('=');
			asynx.globals.cookies.cookiesCached[cookiePair[0]] = cookiePair[1];
		}
	},
	
	/**
	 * create a cookie
	 * 
	 * @author ppk book
	 * @param {Object} name
	 * @param {Object} value
	 * @param {Object} days
	 */
	createCookie: function(name,value,days) {
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			var expires = "; expires="+date.toGMTString();
		}
		else var expires = "";
		document.cookie = name+"="+value+expires+"; path=/";
		asynx.globals.cookies.cookiesCached[name] = value;
		this.initCookies();
	},
	
	/**
	 * read a cookie
	 * 
	 * @author ppk book
	 * @param {Object} name
	 */
	readCookie: function(name) {
		return asynx.globals.cookies.cookiesCached[name];
	},
	
	/**
	 * erase a cookie
	 * 
	 * @author ppk book
	 * @param {Object} name
	 */
	eraseCookie: function(name) {
		this.createCookie(name,"",-1);
		asynx.globals.cookies.cookiesCached[name] = undefined;
	},
	
	/**
	 * split the cookie value in a lot of pieces and stores all
	 * useful when the cookie you need is bigger than 266 bytes
	 * @param {Object} name
	 * @param {Object} value
	 * @param {Object} days
	 */
	createSplitedCookie: function(name,value,days) {
		var valueEncoded = encodeURIComponent(value);
		var bufferSize = 200;
		var piece = 0;
		var numberOfPieces = Math.ceil(valueEncoded.length / bufferSize);
		
		for(var x = 0; x < valueEncoded.length; x++) {
			if (x%bufferSize == 0) {
				var pieceValue = valueEncoded.substring(piece*bufferSize, (piece+1)*bufferSize);
				var nameOfPiece = name + "_" + piece;
				this.createCookie(nameOfPiece,pieceValue,days);
				piece++;
			}
		}
	},
	
	/**
	 * read all pices and return the full string
	 * @param {Object} name
	 */
	readSplitedCookie: function(name) {
		var piece = 0;
		var cookieValue = "";
		
		while(true) {
			var pieceValue = this.readCookie(name + '_' + piece);
			if (pieceValue == null) break;
			
			if (pieceValue != 'undefined')
				cookieValue += pieceValue;
				
			piece++;
		}
		
		return decodeURIComponent(cookieValue);
	},
	
	/**
	 * erase all cookie pices
	 * @param {Object} name
	 */
	eraseSplitedCookie: function(name) {
		var piece = 0;
		var cookieValue;
		
		while(true) {
			var namePiece = name + '_' + piece;
			var pieceValue = this.readCookie(namePiece);
			if (typeof pieceValue != 'string') break;
			this.eraseCookie(namePiece);
			piece++;
		}
	}
}
asynx.extend(asynx, asynx.impl.cookie);
delete asynx.impl.cookie;


asynx.impl.util = {
	
	curry: function(fn, scope) {
	    var scope = scope || window;
	    var args = [];

	    for (var i=2, len = arguments.length; i < len; ++i) {
	        args.push(arguments[i]);
	    };
	    return function() {
		    fn.apply(scope, args);
	    };
	},
	
	executeOn: function(rFunc, delay) {
		var scope = arguments[3];
		var cyclic = arguments[2];
		var timeOut = setInterval(
		function() {
			rFunc.apply(scope);
			if (!cyclic) clearInterval(timeOut);
		}
		, delay ? delay : 0);
		
		return timeOut;
	},
		
	evalJSON: function(json) {
		return json?eval("(" + json + ")"):false;
	},
	
	createIframe : function(frameId){
		var body = asynx$("/body");
		var iframe = null;
		var append = arguments[1]==false?false:true;
		
		if (asynx.isIE) {
			iframe = document.createElement('<iframe onload="" id="' + frameId + '" name="' + frameId + '" />');
		}else{
			iframe = document.createElement('iframe');
			iframe.name = frameId;
			iframe.id = frameId;
		}
		asynx.fling(iframe);
		
		if (append)
			body.appendChild(iframe);
			
		return iframe;
	},
	
	//throws out screen
	fling: function(rNode) {
		var element = asynx$(rNode);
		element.style.position = 'absolute';
		element.style.top = '-1000px';
		element.style.left = '-1000px';
	},
	
	// fix zindex IE problem
	fixzIndex: function(el) {
		var uid = 'asynx_fixzIndex_'+asynx.uid();
		var iframe = asynx(asynx.createIframe(uid, false));
		el = asynx(el);
		el.zIndexFixer = uid;
		
		asynx.dom.before(el, iframe);
		
		iframe.css({
			zIndex: 0,
			top: el.css('top'),
			left: el.css('left'),
			width: el.css('width'),
			height: el.css('height'),
			border: '0px none',
			filter: 'mask()',
			position: 'absolute'
		});
		
		return iframe;
	},
	
	iframeDoc: function(iframe) {
		var iDoc;
		
		// for NS6
		if (iframe.contentDocument)
			iDoc = iframe.contentDocument;
		// for ie5.5 and ie6
		else if (iframe.contentWindow)
			iDoc = iframe.contentWindow.document;
		// for ie5
		else if (iframe.document)
			iDoc = iframe.document;
			
		return iDoc;
	},
	
	createScript: function(rScript) {
		var body = asynx$('/body');
		var script = document.createElement('script');
		 
		script.type = 'text/javascript';
		
		if (rScript.src)
			script.src = rScript.src;
		else
			script.text = rScript.text;
			
		body.appendChild(script);
	},
	
	reviveScriptTags: function(rObj) {
		var scriptTags = rObj.getElementsByTagName('script');
		for (var x = 0; x < scriptTags.length; x++) {
			var script = scriptTags[x];
			asynx.createScript(script);
		}
	},
	
	evalScriptTags: function(html) {
		var body = asynx$("/body");
		var jsdiv = document.createElement("div");
		
		// prevent IE bug
		var hidden = "<span style='position:absolute;left:-1000px;top:-1000px;'>&nbsp;</span>";
		
		body.appendChild(jsdiv);
		asynx.fling(jsdiv);
		jsdiv.innerHTML = hidden+html;
		asynx.reviveScriptTags(jsdiv);
		body.removeChild(jsdiv);
	},
	
	uid: function() {
		return [Math.random()].
			join("").match(/^\d\.(\d+)/)[1];
	},
	
	css: function(el, s) {
		var nodes = asynx(el);
		var shortCuts = {
			'c':'color',
			'bg':'backgroundColor',
			'bgColor':'backgroundColor',
			'bgAttach':'backgroundAttachment',
			'bgImage':'backgroundImage',
			'bgPosition':'backgroundPosition',
			'bgRepeat':'backgroundRepeat',
			'radius':'MozBorderRadius',
			'opacity':asynx.isIE?'filter':'opacity',
			'alpha':asynx.isIE?'filter':'opacity',
			'pad':'padding',
			'w':'width',
			'h':'height'
		};
		
		if (nodes.constructor == Array &&
		nodes.length==0) return false;
		
		if (s.constructor==String) {
			nodes = nodes.constructor==Array?nodes[0]:nodes;
			
			if (s.match("opacity|alpha")) {
				if (asynx.isIE)	s = "filter";
				else s = "opacity"
			};
			
			var css = asynx.getCss(nodes, s);
			
			if (!s.match("top|left|height|width")) {
				var m = css.match(/alpha\(opacity=(\d+)\)/);
				if (asynx.isIE && m) css = m[1];
			}
			
			return css;
		}
		
		nodes.each(function(node, x) {
			asynx.forEach(s, function(k, v) {
				var link = shortCuts[k]?shortCuts[k]:k;
				
				if (/opacity|alpha/.test(k) && link.match("filter|opacity")) {
					if (!asynx.isIE) v = v/100; 
					
					if (link == "filter" &&
						 !/alpha\(opacity=/.test(v))	
							v = "alpha(opacity="+v+");";
				}
				
				if (asynx.isIE&&!node.currentStyle.hasLayout) {
					node.style.zoom = 1;
				}
				
				if (link.match("box|square")) {
					node.style['width'] = v;
					node.style['height'] = v;
					return;
				}
				else {
					//log(link+"-"+v)
					node.style[link] = v;
					
				}
				
			});
		});
	},
	
	getCss: function(el, s) {
		var element = asynx(el);
		
		if (element.constructor == Array &&
			element.length==0) return false;

		if (element.currentStyle)
			var v = element.currentStyle[s];
			
		else if (window.getComputedStyle)
			var v = document.defaultView.getComputedStyle(element,null).getPropertyValue(s);
		
		if (s.match("top|left"))
			return asynx.getXY(element)[s=="left"?0:1];	
		
		if (s.match("width"))
			return el.offsetWidth;
		
		if (s.match("height"))
			return el.offsetHeight;
		
		return v;
	},
	
	getXY: function(element) {
		var obj = element;
	    var curleft = 0;
	    var curtop = 0;
	   
	    if (obj.offsetParent) {
	        while (obj.offsetParent) {
	            curleft += obj.offsetLeft;
	            obj = obj.offsetParent;
	        }
	    }
	    else if (obj.x)
	        curleft += obj.x;
	       
	    obj = element;
	    if (obj.offsetParent) {
	        while (obj.offsetParent ) {
	            curtop += obj.offsetTop;
	            obj = obj.offsetParent;
	        }
	    }
	    else if (obj.y)
	        curtop += obj.y;

	    return [curleft,curtop];  
	},
	
	setXY: function(el,x,y) {
		el.css({ top: y, left: x });
	},
	
	trim: function(s){
		return s.replace(/^\s+|\s+$/g, "");
	},
	
	stripUnit: function(s) {
		return [s].join("").replace(/in|cm|mm|pt|pc|px|em|ex|%/, "");
	},
	
	isUndef: function(v) {
		return v === undefined;
	},
	
	isEmpty: function(v) {
		return v === "";
	}
};

asynx.extend(asynx, asynx.impl.util);
delete asynx.impl.util;

asynx.namespace("anim");
asynx.namespace("anim.easing");
asynx.namespace("anim.tween");

asynx.anim.tween = function() {
	this.init(arguments);
}

asynx.anim.tween.prototype = {
	
	init: function(arguments) {
		this.el = asynx(arguments[0]);
		this.begin = arguments[1];
		this.finish = arguments[2];
		this.duration = arguments[3];
		this.eq = arguments[4]||asynx.anim.easing.linear;
		this.s = arguments[5];
		this.p = arguments[6];
		this.change = this.finish-this.begin;
		this.time = 0;
		this.frame = null;
		this.animate();
	},
	
	animate: function() {
		var scope = this;

		var render = function() {
			var pos = this.eq.apply(this, [this.time++, this.begin, this.change, this.duration, this.s, this.p]);
			
			if (this.onTweenUpdate)
				this.onTweenUpdate.apply(this, [this.el, pos]);
				
			if (this.time > this.duration) {
				clearInterval(this.frame);
				if (this.onTweenEnd)
					this.onTweenEnd.apply(this, [this.el, pos]);
			};
		};
		
		this.frame = setInterval(function(){
			render.apply(scope);
		}, this.duration);
		
	}
	
}

asynx.anim.stop = function(tws) {
	if (!tws) return false;
	asynx.each(tws, function(tw) {
		if (tw) {
			clearInterval(tw.frame);
			delete tw;
		};
	});
};

asynx.anim.fade = function(el, a) {
	el = asynx(el);
	
	if (el.constructor == Array &&
		el.length==0) return false;
	
	var fn = arguments[2];
	var args = arguments[3];
	var duration = !asynx.isUndef(a.duration)?a.duration:20;
	var fac = asynx.anim.easing.factory;
	var equation = fac(a.equation)||fac('linear');
	var tweens = [];
	
	asynx.each(el, function(element) {
		var op = asynx(el).css("opacity");
		op = asynx.isEmpty(op) ? 100 : (!asynx.isIE?parseFloat(op)*100:op);
		var from = !asynx.isUndef(a.from)?a.from:op; 
		var to = !asynx.isUndef(a.to)?a.to:op;
		var tw = new asynx.anim.tween(element, from, to, duration, equation);
		tweens.push(tw);
		
		tw.onTweenUpdate = function(target, pos) {
			target.css({ "alpha": pos });
		};
		tw.onTweenEnd = function(target, pos) {
			if (fn) fn.apply(this, [target, args]);
		};
	}, this);
	
	return tweens;
};

asynx.anim.move = function(el) {
	el = asynx(el);
	
	if (el.constructor == Array &&
		el.length==0) return false;
	
	var a = arguments[1]||{};
	var axis = arguments[2]||"x";
	var fn = arguments[3];
	var args = arguments[4];
	var fac = asynx.anim.easing.factory;
	var duration = a.duration||20;
	var equation = fac(a.equation)||fac('linear');
	var tweens = [];
	
	asynx.each(el, function(element) {
		var co = asynx.getXY(element);
		var def = co[axis=="x"?0:1];
		var from = !asynx.isUndef(a.from)?a.from:def; 
		var to = !asynx.isUndef(a.to)?a.to:def;
		element.css({position:'absolute'});
		
		var tw = new asynx.anim.tween(element, from, to, duration, equation);
		tweens.push(tw);
		
		tw.onTweenUpdate = function(target, pos) {
			if (axis=="x") target.css({ "left": pos });
			if (axis=="y") target.css({ "top": pos });
		};
		tw.onTweenEnd = function(target, pos) {
			if (fn) fn.apply(this, [target, args]);
		};
	}, this);
	
	return tweens;
};

asynx.anim.show = function(el) {
	el = asynx(el);
	
	if (el.constructor == Array &&
		el.length==0) return false;
	
	var a = arguments[1]||{};
	var axis = arguments[2]||"y";
	var fn = arguments[3];
	var args = arguments[4];
	var duration = a.duration||20;
	var fac = asynx.anim.easing.factory;
	var equation = fac(a.equation)||fac('bounceOut');
	var tweens = [];
	
	asynx.each(el, function(element) {
		var w = element.css("width");
		var h = element.css("height");
		var to = asynx.stripUnit(axis == "x" ? w : h);
		el.css({visibility:'visible', display:'block'});	
		var tw = new asynx.anim.tween(element, 0, to, duration, equation);
		tweens.push(tw);
		
		tw.onTweenUpdate = function(ele, pos) {
			pos = asynx.stripUnit(pos) + 'px';
			if (axis=="x") ele.css({ "width": pos } );
			if (axis=="y") ele.css({ "height": pos } );
			
		};
		tw.onTweenEnd = function(ele, pos) {
			if (fn) fn.apply(this, [ele, args]);
		};
		
	}, this);

	return tweens;
};

asynx.anim.splash = function(el) {
	el = asynx(el);
	var a = arguments[1]||{};
	var fn = arguments[2];
	var args = arguments[3];
	var d = a.duration;
	el.css({opacity:0});
	return [ asynx.anim.show(el, { duration: d, equation:'strongInOut' }, "x"),
			  asynx.anim.show(el, { duration: d, equation:'strongInOut' }, "y"),
			  asynx.anim.fade(el, {from:0, to:100}, function(el, pos) {
			 	if (fn) fn.apply(this, [el, args]);
			  }) ];
}

asynx.anim.splashElastic = function(el) {
	el = asynx(el);
	var a = arguments[1]||{};
	var fn = arguments[2];
	var args = arguments[3];
	var d = a.duration;
	var tws = [];
	
	el.css({opacity:0});
	asynx.each(el, function(ele) {
		var from = ele.css("top")+50;
		tws.push(asynx.anim.splash(ele, { duration: d, equation:'linear' }));
		tws.push(asynx.anim.move(ele, { from: from , duration:d, equation: 'bounceOut' }, "y", function(el, pos) {
			 	if (fn) fn.apply(this, [el, args]);
			  }));
	}, this);
	
	return tws;
}

asynx.anim.easing = {
	
	factory: function(name) {
		var linear = asynx.anim.easing.linear;
		if (!name) return linear;
		var m = name.match(/^(linear|normal|strong|expo|back|bounce|elastic)(InOut|In|Out)$/);
		if (!m) return false;
		var eq = asynx.anim.easing[m[1]][m[2]];
		return eq;
	},
	
	linear: function(t, b, c, d) {
		return c*t/d + b;
	},
	
	normal: {
		In: function(t, b, c, d) {
			return c*(t/=d)*t + b;
		},
		
		Out: function(t, b, c, d) {
			return -c *(t/=d)*(t-2) + b;
		},
		
		InOut: function(t, b, c, d) {
			if ((t/=d/2) < 1) return c/2*t*t + b;
			return -c/2 * ((--t)*(t-2) - 1) + b;
		}
	},
	
	strong/*quint*/: {
		In: function(t, b, c, d) {
			return c*(t/=d)*t*t*t*t + b;
		},
		
		Out: function(t, b, c, d) {
			return c*((t=t/d-1)*t*t*t*t + 1) + b;
		},
		
		InOut: function(t, b, c, d) {
			if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
			return c/2*((t-=2)*t*t*t*t + 2) + b;
		}
	},
	
	expo: {
		In: function(t, b, c, d) {
			return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
		},
		
		Out: function(t, b, c, d) {
			return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
		},
		
		InOut: function(t, b, c, d) {
			if (t==0) return b;
			if (t==d) return b+c;
			if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
			return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
		}
	},
	
	back: {
		In: function(t, b, c, d, s) {
			s = s?s:1.70158;
			return c*(t/=d)*t*((s+1)*t - s) + b;
		},
		
		Out: function(t, b, c, d, s) {
			s = s?s:1.70158;
			return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
		},
		
		InOut: function(t, b, c, d, s) {
			s = s?s:1.70158;
			if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
			return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
		}
	},
	
	bounce: {
		In: function(t, b, c, d, s) {
			return c - asynx.anim.easing.bounce.Out (d-t, 0, c, d) + b;
		},
		
		Out: function(t, b, c, d, s) {
			if ((t/=d) < (1/2.75)) {
				return c*(7.5625*t*t) + b;
			} else if (t < (2/2.75)) {
				return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
			} else if (t < (2.5/2.75)) {
				return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
			} else {
				return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
			}
		},
		
		InOut: function(t, b, c, d, s) {
			if (t < d/2) return asynx.anim.easing.bounce.In (t*2, 0, c, d) * .5 + b;
			else return asynx.anim.easing.bounce.Out (t*2-d, 0, c, d) * .5 + c*.5 + b;
		}
	},
	
	elastic: {
		In: function(t, b, c, d, a, p) {
			if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
			if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
			else var s = p/(2*Math.PI) * Math.asin (c/a);
			return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		},
		
		Out: function(t, b, c, d, a, p) {
			if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
			if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
			else var s = p/(2*Math.PI) * Math.asin (c/a);
			return (a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b);
		},
		
		InOut: function(t, b, c, d, a, p) {
			if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
			if (!a || a < Math.abs(c)) { a=c; var s=p/4; }
			else var s = p/(2*Math.PI) * Math.asin (c/a);
			if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
			return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
		}
	}
	
};



asynx.namespace("drag");

asynx.drag = function() {
	this.init(arguments);
}

asynx.drag.prototype = {
	
	init: function(arguments) {
		this.el = asynx(arguments[0]);
		this.dX = 0;
		this.dY = 0;
		this.ntop = 0;
		this.nleft = 0;
		this.mouse = [];
		this.zIframe = null,
		this.zIndex = asynx.globals.drag.lastzIndex++,
		this.draggable = true;
		this.resizable = true;
		this.dragging = false;
		this.dragArea = null;
		this.clickTarget = null;
		this.initDrag();
	},
	
	initDrag: function() {
		var el = this.el;
		var t = el.css("top"), l = el.css("left"),
			w = el.css("width"), h = el.css("height");
		
		el.css({
			position:'absolute',
			zIndex:this.zIndex,
			top:t,
			left:l,
			width:w,
			height:h
		});
		
		el.mousedown(this._onStartDrag, [this]);
		el.mouseup(this._onEndDrag, [this]);
	},
	
	_onStartDrag: function(e, args) {
		
		var scope = args[0], ta = scope.clickTarget = e.target,
			dH = scope.dragArea, moveScope = asynx.isIE?asynx('/html'):document;
			
		dH = scope.dragArea = dH?dH:ta;
		scope.dragging = true;
		scope.findDelta(e);
		
		// drag by dragArea child
		asynx.dom.walkParents(ta,function(p){if(p==dH)ta=scope.clickTarget=dH;});
		
		// prevent scroll bug
		var w = asynx.stripUnit(scope.el.css('width'));
		var h = asynx.stripUnit(scope.el.css('height'));
		
		if (scope.el.scrollWidth>w||scope.el.scrollHeight>h) {
			var clickPosX = w-scope.dX;
			var clickPosY = h-scope.dY;
			var scrolls = {ie:23,ff:13,safari:3};
			var b = asynx.isIE||asynx.isOpera?'ie':(asynx.isFirefox?'ff':(asynx.isSafari?'safari':20));
			var scrollsize = scrolls[b];
			if (clickPosX<scrollsize||clickPosY<scrollsize) return false;
		}
		
		// onmove
		asynx.event.mousemove(moveScope, scope._onDrag, [scope]);
		
		// user
		if (scope.onStartDrag && ta==dH)
			scope.onStartDrag.apply(scope, [scope.el, e]);
	},
	
	_onDrag: function(e, args) {
		var scope = args[0];
		var el = scope.el, dH = scope.dragArea, ta = scope.clickTarget;
		var m = scope.mouse = asynx.event.getMouseXY(e);
		var l = scope.nleft = scope.mouse[0]-scope.dX;
		var t = scope.ntop = scope.mouse[1]-scope.dY;
		
		// drag area condition
		if (ta!=dH) return;
		
		if (scope.dragging && scope.draggable) {
			asynx.setXY(el, l, t);
			if (scope.zIframe) scope.setXY(scope.zIframe, l, t);
		};
		
		// user
		if (scope.onDrag)
			scope.onDrag.apply(scope, [el, e]);
	},
	
	_onEndDrag: function(e, args) {
		var scope = args[0], dH = scope.dragArea, ta = scope.clickTarget;
		scope.dragging = false;
		
		var moveScope = asynx.isIE?asynx('/html'):document;
		asynx.event.remove('mousemove', moveScope, scope._onDrag, [scope]);
		
		// user
		if (scope.onEndDrag && (ta==dH||!dH))
			scope.onEndDrag.apply(scope, [scope.el, e]);
	},
	
	setDraggable: function(b) {
		this.draggable = b;
	},
	
	setDragHandle: function(el) {
		this.dragArea = asynx(el);
	},
	
	setOnTop: function(b) {
		var el = this.el;
		var z = this.zIndex;
		if (b) z = asynx.globals.drag.lastzIndex++;
		el.css({zIndex:z});
	},
	
	fixzIndex: function() {
		// fix zIndex ie 
		if (asynx.isIE && !this.zIframe)
			this.zIframe = asynx.fixzIndex(this.el);
	},
	
	findDelta: function(e) {
		this.mouse = asynx.event.getMouseXY(e);
		this.dX = this.mouse[0] - (this.el.css("left")||0.0);
		this.dY = this.mouse[1] - (this.el.css("top")||0.0);
	}
}





asynx.namespace("xpath");

asynx.xpath = {
	
	query: null,
	scope: document,

	getNodes: function(query) {
		this.query = query;
		var sc = arguments[1];
		this.scope = [sc?sc:document];
		
		var schemas = this.schema(query);
		var validNodes = [];
		
		for (var i=0; i < schemas.length; i++) {
			var schema = schemas[i];
			var info = this.getExpInfo(schema);
			
			if (!info) break;
			
			var sAttr = info.sAttr;
			var sValue = info.sValue;
			var sTagName = info.sTagName == "all" ? "*" : info.sTagName;
			var nodeNum = info.nodeNum;
			var comparator = info.comparator;
			var customSelector = info.customSelector;
			var nodeContain = info.nodeContain;
			var solitaryNode = !!(/\d+/.test(nodeNum));
			
			var filterCriteria = {comparator:comparator, customSelector:customSelector};
		
			var byTag = !!(!sAttr && !sValue && sTagName);		
			var byTagAttr = !!(sAttr && !sValue);		
			var byTagAttrValue = !!(sAttr && sValue);		
			var canStoreValidNodes = !!(i+1 == schemas.length);
			
			var found = [];
			
			if (schema.nextQuery.substring(0,1) == "#") {
				var id = schema.nextQuery.substring(1, schema.nextQuery.length);
				found = [document.getElementById(id)];
			}
			else if (sAttr == "id" && sValue) {
				found = [document.getElementById(sValue)];
			}
			else{
				found = asynx.dom.getByTagName(this.scope, sTagName ? sTagName : "*");
			}
			
			if (byTagAttr)
				found = this.filter(found, sAttr, undefined, filterCriteria);
			
			else if (byTagAttrValue)
				found = this.filter(found, sAttr, sValue, filterCriteria);
			
			if (nodeContain)
				found = this.filterIfContainsNode(found, nodeContain);
				
			if (canStoreValidNodes) {
				if (solitaryNode)
				 	validNodes.push(found[nodeNum]);
				else 
				 	asynx.merge(validNodes, schema.getAll ? found : [found[0]]);
			};
			
			if (solitaryNode)
				this.scope = [found[nodeNum]];
			else
				this.scope = schema.getAll ? found : [found[0]];
				
		}
		
		if (customSelector)
			validNodes = this.applyCustomSelector(validNodes, customSelector);
		
		return validNodes;
	},
	
	filterIfContainsNode: function(nodes, nodeName) {
		
		var filtered = [];
		
		for (var x=0; nodes[x]; x++) {
			var node = nodes[x];
			var contains = node.getElementsByTagName(nodeName);
			if (contains.length > 0) filtered.push(node);
			else continue;
		};
		
		return filtered;
	},
	
	applyCustomSelector: function(nodes, customSelector) {
		
		var filtered = [];

		var cssFilters = {
			hidden:true,
			visible:true
		};
		
		// performance...
		if (cssFilters[customSelector]) {
			for (var x = 0; nodes[x]; x++) {
				var node = nodes[x];
				var style = node.style;
				var cssDisplay = style.display;
				var cssVisibility = style.visibility;
				
				var conditions = {
					visible: !!(cssDisplay!="none"&&cssVisibility!="hidden"),
					hidden: !!(cssDisplay=="none"||cssVisibility=="hidden")
				};
				
				if (conditions[customSelector])
					filtered.push(node);
				else continue;
			};
		}else{
			// other filters
			for (var x = 0; nodes[x]; x++) {
				var node = nodes[x];
	
				var conditions = {
					even: !!(x%2==0),
					odd: !!(x%2!=0),
					first: !!(x==0),
					last: !!(x==nodes.length-1),
					parent: !!(node.hasChildNodes())
				};
				
				if (conditions[customSelector])
					filtered.push(node);
				else continue;
			};
		}
		
		return filtered;
	},
	
	filter: function() {
		var nodes = arguments[0];
		var sAttr = arguments[1];
		var sValue = arguments[2];
		var criteria = arguments[3];
		var comparator = criteria.comparator;
		var customSelector = criteria.customSelector;
		var store = [];
		
		var byAttrValue = !!(sAttr && sValue);
		var byAttr = !!(sAttr && !sValue);
		var sType = /^[0-9.,]+$/.test(sValue) ? "digit" : "string";
		
		for (var x = 0; x < nodes.length; x++) {
			var node = nodes[x];
			
			if (!node) continue;
			
			var attrNode = node.getAttribute(sAttr);
			
			if (byAttr && node) {
				if (attrNode || attrNode == '') {
					store.push(node);
				}
				else continue;
			};
			
			if (byAttrValue && node && attrNode && sType == "digit") {
				var comparators = {
					digit: {
						"=": !!(parseFloat(attrNode) == parseFloat(sValue)),
						"!=": !!(parseFloat(attrNode) != parseFloat(sValue)),
						">": !!(parseFloat(attrNode) > parseFloat(sValue)),
						"<": !!(parseFloat(attrNode) < parseFloat(sValue)),
						">=": !!(parseFloat(attrNode) >= parseFloat(sValue)),
						"<=": !!(parseFloat(attrNode) <= parseFloat(sValue)),
						"^=": !!(attrNode.substring(0, sValue.length) == sValue),
						"$=": !!(attrNode.substring(attrNode.length-sValue.length, attrNode.length) == sValue),
						"all=": !!(attrNode.indexOf(sValue) != -1)
					}
				};
				if (comparators[sType][comparator]) store.push(node);
				else continue;
			}
			
			if (byAttrValue && node && attrNode && sType == "string") {
				var comparators = {
					string: {
						"=": !!(attrNode == sValue),
						"!=": !!(attrNode != sValue),
						"^=": !!(attrNode.substring(0, sValue.length) == sValue),
						"$=": !!(attrNode.substring(attrNode.length-sValue.length, attrNode.length) == sValue),
						"all=": !!(attrNode.indexOf(sValue) != -1)
					}
				};
				if (comparators[sType][comparator])	store.push(node);
				else continue;
			}
			
		}
		
		return store;
	},
	
	schema: function(query) {
		
		if (query.substring(0,1) != "/" && 
				query.substring(0,2) != "//") query += "//" + query;
		
		var siblings = query.split("/");
		siblings.shift();
		
		var getAllFromNext = false;
		var schema = [];
		
		for (var x = 0; x < siblings.length; x++) {
			var sibling = siblings[x];
			
			if (sibling == "") {
				getAllFromNext = true;
				continue;	
			};
			
			var sibling = sibling.replace("*", "all");
			var customSelector;
			var regexCustomSelector = /:([\w-]+)$/; //:even, :odd, ...
			var regexId = /^([\w-]+)?(#[\w-]+)/; //#id
			
			var mCustom = sibling.match(regexCustomSelector);
			if (mCustom) {
				customSelector = mCustom[1];
				sibling = sibling.replace(regexCustomSelector, "");
			};
			
			var mId = sibling.match(regexId);
			if (mId) {
				sibling = mId[2];
			};
			
			schema.push ({ nextQuery:sibling, getAll:getAllFromNext, query:query, customSelector:customSelector });
			getAllFromNext = false;
		}
		return schema;
	},
	
	getExpInfo: function(schema) {
		
		var matchers = [
			/ *([\w-]+)?\[ *@([\w-]+) *(=|<|>|>=|<=|!=|\^=|\$=|all=) *['"]?([\w.-]+|)?['"]? *\]( *\[ *([a-zA-Z-]+) *\])?( *\[ *([\d]+) *\])?$/,
			/ *([\w-]+)?\[ *@([\w-]+) *\]( *\[ *([a-zA-Z-]+) *\])?( *\[ *([\d]+) *\])?$/,
			/ *([\w-]+)( *\[ *([a-zA-Z-]+) *\])?( *\[ *([\d]+) *\])?$/
		];
		
		var rules = [
			{ tag:1, attr:2, comparator:3, _value:4, nodeNum:8, contains:6 },
			{ tag:1, attr:2, nodeNum:6, contains:4 },
			{ tag:1, contains:3, nodeNum:5}
		];
		
		var values = false;
		var nextQuery = schema.nextQuery;
		
		asynx.each(matchers, function(e, x) {
			var m = nextQuery.replace("*=", " all=").match(e);
			if (m) {
				var rule = rules[x];
				
				var sTagName = m[rule.tag];
				var sAttr = m[rule.attr];
				var sValue = m[rule._value];
				var nodeNum = m[rule.nodeNum];
				var comparator = m[rule.comparator];
				var nodeContain = m[rule.contains];
				
				//alert(nextQuery + " : " + sTagName + "-" + sAttr + "-" + sValue + "-" + nodeNum + "-" + nodeContain + "-" + x)
				values = {};
				values = { sAttr:sAttr, sValue:sValue, nodeNum:nodeNum, sTagName:sTagName, 
							comparator:comparator, customSelector:schema.customSelector, nodeContain:nodeContain };
			};
		});
		
		return values;
	}
		
};



asynx.namespace("selector");

asynx.selector = function() {
	
	var xQuery = arguments[0], s = arguments[1];
	
	if (typeof xQuery == "object") {
		xQuery = this.increaseObj(xQuery);
		return xQuery;
	}
		
	this.init(xQuery, s);
	return this.nodes;
};

asynx.selector.prototype = {
	
	nodes: [],
	query: null,
	xQuery: null,
	
	init: function() {
		
		
		this.query = new String(arguments[0]).replace("*=", " all=");
		//alert(this.query)
		var matchers = [
			/^([\w-]+)\.([\w-]+)$/, //div.className
			/^([\w-]+)\.([\w-]+)\[([\w-]+)\]$/, //div.className[a]
			/^#(.*)$/, //#id
			/^([\w-]+)$/, //id
			/^([\w-]+) *[\/>] *([\w-]+)$/, //ul/li or ul>li
			/\]\[ *@([\w-]+) *(=|<|>|>=|<=|!=|\^=|\$=|all=)? *(['"]?([\w.-]+|)?['"]?)? *\]$/ //input[@type=radio][@checked='3']
		];
		
		var rules = [
			{ tag:1, css:2 },
			{ tag:1, css:2, contains:3 },
			{ id: 1 },
			{ id: 1 },
			{ tag1: 1, tag2:2 },
			{ attr2:1, comparator:2, value2:4 }
		];
		
		var xAttr = "//{tag}[@{attr}='{value}']";
		
		var attrFilter, valueFilter, comparatorFilter;
		
		asynx.each(matchers, function(regex, x) {
			var m = this.query.match(regex);
			if (m) { 

				var tag = m[rules[x].tag];
				var tag1 = m[rules[x].tag1];
				var tag2 = m[rules[x].tag2];
				var css = m[rules[x].css];
				var id = m[rules[x].id];
				var contains = m[rules[x].contains];
				var attr2 = attrFilter = m[rules[x].attr2];
				var value2 = valueFilter = m[rules[x].value2];
				var comparator = comparatorFilter =  m[rules[x].comparator];
				
				var byId = !!(id);
				var byTagCss = !!(tag && css);
				var byTagCssContains = !!(tag && css && contains);
				var byChildren = !!(tag1 && tag2);
				var bySecondAttr = !!(attr2 && !value2);
				var bySecondAttrValue = !!(attr2 && value2);
				
				if (byId) 
					this.xQuery = xAttr.replace("{attr}", "id").
						replace("{value}", id).replace("{tag}", "");
				
				if (byTagCss) 
					this.xQuery = xAttr.replace("{attr}", "class").
						replace("{value}", css).replace("{tag}", tag);
				
				if (byTagCssContains)
					this.xQuery = xAttr.replace("{attr}", "class").
						replace("{value}", css).replace("{tag}", tag)+"["+contains+"]";
				
				if (byChildren)
					this.xQuery = "//"+tag1+"//"+tag2;
					
				if (bySecondAttr || bySecondAttrValue)
					this.xQuery = this.query.replace(regex, "]");
				
			//	alert(tag + "-" + css + "-" + id + "-" +  attr2 +"-" +  value2 + "=" + this.xQuery)
			}
		}, this);
		
		if (!this.xQuery) 
			this.xQuery = this.query;
		
		this.nodes = this.getNodes(arguments[1]);

		if (attrFilter && comparatorFilter)
			this.nodes = asynx.xpath.filter(this.nodes, attrFilter, valueFilter, {comparator:comparatorFilter, customSelector:undefined});
		
		var totalNodes = this.nodes.length;
		
		if (this.nodes.length == 1) 
			this.nodes = this.nodes[0];
		
		this.nodes = this.increaseObj(this.nodes);
		
	},
	
	getNodes: function() {
		return asynx.xpath.getNodes(this.xQuery, arguments[0]);
	},
	
	increaseObj: function(element) {
		
		element.each = function(fn) {
			asynx.each(this, function(e,x) {
				if (this) fn.apply(this, [e, x]);
			})
		}
		
		element.click = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.click(node, fn, args[1]);	
			}, this);
		}
		
		element.dblclick = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.dblclick(node, fn, args[1]);	
			}, this);
		}
		
		element.blur = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.blur(node, fn, args[1]);	
			}, this);
		}
		
		element.change = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.change(node, fn, args[1]);	
			}, this);
		}
		
		element.focus = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.focus(node, fn, args[1]);	
			}, this);
		}
		
		element.load = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.load(node, fn, args[1]);	
			}, this);
		}
		
		element.keypress = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.keypress(node, fn, args[1]);	
			}, this);
		}
		
		element.keyup = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.keyup(node, fn, args[1]);	
			}, this);
		}
		
		element.keydown = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.keydown(node, fn, args[1]);	
			}, this);
		}
		
		element.mouseover = function(fn) {
			var args = asynx.A(arguments);
			//element.each(function(node){
				asynx.event.mouseover(element, fn, args[1]);	
			//}, this);
		}
		
		element.mouseout = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.mouseout(node, fn, args[1]);	
			}, this);
		}
		
		element.mousedown = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.mousedown(node, fn, args[1]);	
			}, this);
		}
		
		element.mouseup = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.mouseup(node, fn, args[1]);	
			}, this);
		}
		
		element.mousemove = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.mousemove(node, fn, args[1]);	
			}, this);
		}
		
		element.onStopTyping = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.onStopTyping(node, fn, args[1]);	
			}, this);
		}
		
		element.onStopTyping = function(fn) {
			var args = asynx.A(arguments);
			element.each(function(node){
				asynx.event.onStopTyping(node, fn, args[1]);	
			}, this);
		}
		
		element.html = function(html) {
			var args = asynx.A(arguments);
			var evals = args[1];
			element.each(function(node){
				node.innerHTML = html;
				if (evals || evals == undefined)
					asynx.evalScriptTags(html);	
			}, this);
		}
		
		element.appendHtml = function(h) {
			element.html(element.innerHTML+h, arguments[1]);
		}
		
		element.load = function(url) {
			var args = asynx.A(arguments);
			var url = args[0];
			var data = args[1];

			asynx.$open(url, data, function(r,a) {
				element.each(function(node){
					element.html(r);
				}, this);
			});

		}
		
		element.css = function(s) {
			var args = asynx.A(arguments);
			var values = [];
			
			element.each(function(node){
				var v = asynx.css(node, s);
				if (v) values.push(v);
			}, this);
			
			return values.length==1?values[0]:values;
		}
		
		return element;
	}
	
};

