/**
 * jatX
 * @author CHX
 * @namespace jatX
 */


var jatX = function() {
	var _version = "0.1";//kk
	var _ui = {};
	var _widgets = {};
	var _utilities = {};
	var _cache_elements = [];
	
	/**
	 * getElementById 的别名和扩展
	 * @param {Object} v
	 * @param {[Object]} w
	 * 
	 * v的格式: "id", "<tagName>", "<input-type>", "<input-type-name>", "<textarea-name>", "<select-name>"
	 */
	function _$(v, w) {
		w = w || window;
		var _el;
		if (typeof v == "string") {
			if (/^<([\w-]+)>$/.test(v)) {
				var _tagName = RegExp.$1;
				if (/input\-(text|button|radio|checkbox|hidden|image|reset|submit|file|password)(\-\w+)?/i.test(_tagName)) {
					if (window.ActiveXObject) {
						var _sName = RegExp.$2 ? " name=\"" + RegExp.$2.substring(1) + "\"" : " name=\"_jx_" + RegExp.$1 + "\"";
						_el = w.document.createElement("<input type=\"" + RegExp.$1 + "\"" + _sName + ">");
					} else {
						_el = w.document.createElement("input");
						_el.type = RegExp.$1;
						_el.name = RegExp.$2 ? RegExp.$2.substring(1) : "_jx_" + RegExp.$1;
					}
				} else if (/(textarea|select)(\-\w+)?/i.test(_tagName)) {
					if (window.ActiveXObject) {
						var _sName = RegExp.$2 ? " name=\"" + RegExp.$2.substring(1) + "\"" : " name=\"_jx_" + RegExp.$1 + "\"";
						_el = w.document.createElement("<" + RegExp.$1 + _sName + ">");
					} else {
						_el = w.document.createElement(RegExp.$1);
						_el.name = RegExp.$2 ? RegExp.$2.substring(1) : "_jx_" + RegExp.$1;
					}
				} else {
					_el = w.document.createElement(_tagName);
				}
			} else {
				//IE中会把name为v的作为结果，在些处理以得到正确的对象
				_el = w.document.getElementById(v);
				if(!_el) return null;
				if (_el.id != v) {
					_el = null;
					var _allID = document.all[v];
					for (var i = 0; i < _allID.length; i++) {
						if (_allID[i].id == v) {
							_el = _allID[i];
							break;
						}
					}
				}
			}
		} else {
			_el = v;
		}
		return _el;
	}

	/**
	 * 把对象oExt中的属性值或引用复制到o中(浅复制)
	 * @param {Object} o
	 * @param {Object} oExt
	 * @param {Object} bOverride
	 */
	function _augment(o, oExt, bOverride, fFilter) {
		if(!oExt) return;
		for (var p in oExt) {
			if (bOverride || !(p in o)) {
				if (typeof fFilter == "function") {
					if (fFilter.call(oExt, p)) {
						o[p] = oExt[p];
					}
				} else {
					o[p] = oExt[p];
				}
			}
		}
		//get toString in IE
		if (bOverride && typeof oExt.toString == "function" && oExt.toString != o.toString) {
			o.toString = oExt.toString;
		}
		return this;
	}
	
	/**
	 * 迭代一个对象
	 * @param {Object} target
	 * @param {Function} fn
	 * @param {Object} thisObj
	 */
	function _each(target, fn, thisObj) {
		thisObj = thisObj || target;
		for(var p in target) {
			fn.call(thisObj, target[p], p, target);
		}
	}
	
	/**
	 * 复制o到oContent（深复制）
	 * @param {Object} o
	 * @param {Object} oContent
	 * @param {Number} depth
	 * @param {Function} fFilter
	 * @return oContent
	 */
	function _clone(o, oRet, depth) {
		depth = depth || -1;
		oRet = (oRet && typeof oRet == "object") ? oRet : makeObj(o);
		var arrFlat = [];//用来检查循环引用的数组
/*
		function _cln() {
			var objClone;
			if (this.constructor == Object) {
				objClone = new this.constructor();
			} else {
				objClone = new this.constructor(this.valueOf());
			}
			for (var key in this) {
				if (objClone[key] != this[key]) {
					if (typeof(this[key]) == 'object') {
						objClone[key] = _cln.call(this[key]);
					} else {
						objClone[key] = this[key];
					}
				}
			}
			objClone.toString = this.toString;
			objClone.valueOf = this.valueOf;
			return objClone;
		}
*/
		//递归
		(function(_con, _o, _depth) {
			if(_depth == 0) return;//到达限定级数时停止
			var tmp = null;
			for(var p in _o) {
				if (_o.hasOwnProperty(p)) {
					tmp = _o[p];
					//如果对象tmp是循环引用，只设置一次
					if (isRing(tmp)) {
						_con[p] = tmp;
						continue;
					}
					//存入池中以便检查
					arrFlat.push(tmp);
					//如果对象可遍历
					if (tmp && typeof tmp == "object") {
						//根据类型生成一个空的对象副本
						_con[p] = makeObj(tmp);
						//进入子对象
						arguments.callee(_con[p], tmp, _depth - 1);
					} else {
						//基本类型直接赋值
						_con[p] = tmp;
					}
				}
			}
		})(oRet, o, depth);

		function makeObj(oRes) {
			if(oRes instanceof Array) {
				return new Array();
			}
			if(oRes instanceof String) {
				return new String(oRes.valueOf());
			}
			if(oRes instanceof Boolean) {
				return new Boolean(oRes.valueOf());
			}
			if(oRes instanceof Number) {
				return new Number(oRes.valueOf());
			}
			if(oRes instanceof RegExp) {
				return new RegExp(oRes.valueOf());
			}
			return new Object();
		}
		function isRing(val) {
			if(typeof val != "object") return false;
			return arrFlat.some(function(v) {
				return v === val;
			});
		}
		
		return oRet;
	}
	
	function _interface(oProto) {
		return oProto;
	}
	function _BaseClass() {
	}
	_BaseClass.prototype = {
		extend: function(oClass) {
			_each(oClass.prototype, function(v, p, o) {
				if(!/^__/.test(p)) this[p] = v;
			}, this);
			this.$super = oClass;
		},
		use: function(oPropList) {
			_each(oPropList, function(v, p, o) {
				if(typeof this[p] === "undefined") this[p] = v;
			}, this);
		},
		implement: function(oInterface) {
			if (oInterface) {
				for (var p in oInterface) {
					if (!this[p] || typeof oInterface[p] !== typeof this[p]) {
						throw new Error("Not implemented: \"" + p + "\" [" + typeof oInterface[p] + "]");
						break;
					}
				}
			}
		}
	};
	
	/**
	 * 创建一个JS类
	 * @param {Object} oClass
	 * @param {Object} fSuper
	 * @param {Object} bOverride
	 */
	function _class(oClass) {
		var _construct = oClass.__init || new Function();

		_augment(_construct.prototype, oClass, true);//设置类成员
		_augment(_construct.prototype, new _BaseClass, true);//设置默认成员
		
		_construct.prototype.constructor = _construct;
		if(oClass.toString) _construct.prototype.toString = oClass.toString;
		return _construct;
	}

	/**
	 * Element factory
	 * @param {Mix} v
	 * @param {ObjectWindow} w
	 */
	function _element(v, w) {
		var _el = _$(v, w);
//		if(_el.tagName == "TABLE") return _el;
		if(_el instanceof jatX.Element || _el instanceof jatX.Table) return _el;
		//查找缓存
		var _isCached = _cache_elements.some(function(v) {
			if(v.getValue() === _el) {
				_el = v;
				return true;
			}
		});

		if(_isCached) return _el;
		if(_el) {
			if(_el.tagName == "TABLE") {
				_el = new  jatX.Table(_el);
			} else {
				_el = new jatX.Element(_el);
			}
			
			_cache_elements.push(_el);
		}
		return _el;
	}

	return {
		getVersion: function() {
			return _version;
		},
		$E: _element,
		$: _$,
		augment: _augment,
		each: _each,
		clone: _clone,
		Class: _class,
		Interface: _interface,
		UI: _ui,
		widg: _widgets,
		util: _utilities,
		window: {}
	};
}();


/**
 * 通用文件，包括基本对象扩展.
 * @namespace : jatX.core
 * @author : CHX
 */

/////////////////////[Function]
jatX.augment(Function.prototype, {
	/**
	 * 延时执行一个函数
	 * @param {Int} n 毫秒
	 * @param {Object} thisObj 执行上下文对象
	 * @param {Array} args 参数列表
	 * @return {Int} timerID
	 */
	delay: function(n, thisObj, args) {
		var me = this;
		args = args instanceof Array ? args : Array.prototype.slice.call(arguments, 2);
		var f = function() {
			me.apply(thisObj || window, args);
		};
		return window.setTimeout(f, n);
	},
	
	/**
	 * 在足够长的间隔时间后执行
	 * @param {Object} n 毫秒
	 * @param {Object} thisObj 执行上下文对象
	 * @param {Object} args 参数列表
	 * @return {Object} this
	 */
	lazy: function() {
		if(this.__delayTimer > 0) window.clearTimeout(this.__delayTimer);
		this.__delayTimer = this.delay.apply(this, Array.prototype.slice.call(arguments, 0));
		
		return this;
	},
	/**
	 * 用闭包将参数“绑定”到函数本身
	 * @return {Function} 绑定了参数的新函数
	 */
	bind: function() {
		var t = this;
		var arg, context;
		if(typeof arguments[0] == "object") {
			context = arguments[0];
			arg = Array.prototype.slice.call(arguments, 1);
		} else {
			context = null;
			arg = Array.prototype.slice.call(arguments, 0);
		}
		
		return function() {
			var arg1 = Array.prototype.slice.call(arguments, 0);
			t.apply(context, arg1.concat(arg));
		};
	},
	/**
	 * 
	 */
	curry: function() {
		var originFunc = this;
		var args = [];
		for (var i = 0; i < arguments.length; i++) {
			args[i] = arguments[i];
		}
		if (args.length == 0) args = null;
		var newFunc = function() {
			var args = [];
			for (var i = 0; i < arguments.length; i++) {
				args[i] = arguments[i];
			}
			args = arguments.callee.curryArgs.concat(args);
			if (args.length == 0) args = null;
			return arguments.callee.originFunc.apply(this, args);
		};
		newFunc.curryArgs = args;
		newFunc.originFunc = originFunc;
		return newFunc;
	}
});

/////////////////////[String]
jatX.augment(String.prototype, {
	/**
	 * 过滤开始和结尾处的空白字符
	 * @return {String} 
	 */
	trim: function() {
		
		return this.replace(/^\s+|\s+$/, "");
	},
	/**
	 * 返回URL编码后的字符串
	 * @return {String} s
	 */
	encodeURL: function() {
		var s = "";
		for (var i = 0; i < this.length; i++) {
			s += "%" + this.charCodeAt(i).toString(16);
		}
		return s;
	},
	/**
	 * 返回URL解码后的字符串
	 */
	decodeURL: function() {
		return decodeURIComponent(this.toString());
	},
	repeat: function(n) {
		var s = this.valueOf();
		var r = "";
		while(n-- > 0) {
			r += s;
		}
		return r;
	}
});

//////////////////////[Array]
jatX.augment(Array.prototype, {
	forEach: function(fCallback, thisObj) {
		thisObj = typeof thisObj == "object" ? thisObj : this;
		for(var i=0;i < this.length;i ++) {
			fCallback.call(thisObj, this[i], i, this);
		}
		return this;
	},
	filter: function(fCallback, thisObj) {
		var _a = [];
		thisObj = typeof thisObj == "object" ? thisObj : this;
		for(var i=0;i < this.length;i ++) {
			if(fCallback.call(thisObj, this[i], i, this)) _a.push(this[i]); ;
		}
		return _a;
	},
	every: function(fCallback, thisObj) {
		for(var i=0;i<this.length;i++) {
			if(fCallback.call(thisObj||this, this[i], i, this) === false) return false;
		}
		return true;
	},
	some: function(fCallback, thisObj) {
		for(var i=0;i<this.length;i++) {
			if(fCallback.call(thisObj||this, this[i], i, this) === true) return true;
		}
		return false;
	},
	/**
	 * MDC : https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/Map
	 * @param {Object} fCallback
	 * @param {Object} thisObj
	 */
	map: function(fCallback, thisObj) {
		var len = this.length >>> 0;
		if (typeof fCallback != "function") throw new TypeError();
		
		var res = new Array(len);
		var thisp = thisObj;
		for (var i = 0; i < len; i++) {
			if (i in this) res[i] = fCallback.call(thisp, this[i], i, this);
		}
		
		return res;
		
	},
	shuffle: function() {
		this.sort(function(a,b){ return Math.random()>Math.random()?1:-1; });
		return this;
	}
});

/**
 * @author cheney
 */

jatX.Agent = jatX.Class({
	__init: function() {
		var _class = arguments.callee;
		
		_class.opera = this.isOpera();
		_class.ie = this.isIE();
		_class.ie6 = this.isIE6();
		_class.firefox = this.isFireFox();
		_class.safari = this.isSafari();
		_class.chrome = this.isChrome();
	},
	isOpera: function() {
		return /opera/i.test(navigator.userAgent);
	},
	isIE: function() {
		return /MSIE/.test(navigator.userAgent);
	},
	isFireFox: function() {
		return /firefox/i.test(navigator.userAgent);
	},
	isSafari: function() {
		
	},
	isChrome: function() {
		
	},
	isIE6: function() {
		return /MSIE 6/.test(navigator.userAgent);
	}
});

new jatX.Agent();
/**
 * EventDispatcher
 * @author Cheney
 */

jatX.EventDispatcher = function() {
	this.__listeners = {};
};
jatX.EventDispatcher.prototype = {
	dispatchEvent: function(name, e) {
		
		if (this.__listeners[name]) {
			this.__listeners[name].forEach(function(v) {
				var args = v.args.slice(0);
				args.unshift(e);
				v.fn.apply(v.owner, args);
			}, this);
			return true;
		}
		return false;
	},
	/**
	 * 批量注册事件
	 * @param {Object} oHandler
	 * @param {Object} thisObj
	 */
	addEventListeners: function(oHandler, thisObj) {

		if (typeof oHandler == "object") {
			for(var p in oHandler) {
				if(typeof oHandler[p] == "function") {
					this.addEventListener(p, oHandler[p], thisObj);
				}
			}
		}
		
		return this;
	},
	addEventListener: function(sEventName, fListener, thisObj, args) {
		thisObj = thisObj || this;
		args = args||[];
		if(!(this.__listeners[sEventName] instanceof Array)) this.__listeners[sEventName] = [];
					
		this.__listeners[sEventName].push({
			fn: fListener,
			owner: thisObj,
			args: args
		});
		
		return this;
	},
	removeEventListener: function(sEventName, fListener) {
		var _ea = this.__listeners[sEventName];
		for(var i=0; i<_ea.length; i++) {
			if(_ea[i].fn === fListener) {
				_ea.splice(i--, 1);
			}
		}
		return this;
	},
	removeEventListeners: function() {
		this.__listeners = {};
	}
};
/**
 * @author jat
 */

jatX.EventRegister = function() {
	jatX.augment(this, new jatX.EventDispatcher);//继承
};

jatX.EventRegister.prototype = {
	registerEvents: function() {
		for (var i=0, l=arguments.length; i<l; i++) {
			this.registerEvent(arguments[i]);
		}
	},
	registerEvent: function(sEventName, options) {
		if (!this.__listeners[sEventName]) this.__listeners[sEventName] = [];
		if (!this.__listeners[sEventName].binder) {
			var binder = jatX.event.createBinder(this._element, sEventName, options);
			binder.bind();
			binder.__listeners = this.__listeners;//对接
			if(binder) this.__listeners[sEventName].binder = binder;
			
			return true;
		}
		return false;
	},
	unregisterEvent: function(sEventName) {
		if(!sEventName) {
			for(var p in this.__listeners) {
				arguments.callee.call(this, p);
				
			}
			return false;
		}
		if (!this.__listeners[sEventName]) return false;
		if (this.__listeners[sEventName].binder) {
			this.__listeners[sEventName].binder.unbind();
			delete this.__listeners[sEventName].binder;
			
			return true;
		}
	}
};
/**
 * jatX.Window
 * @author Cheney
 */

(function() {
	var _cache = [];
	function _Window(win) {
		this._element = win || window;
	}
	
	var _prototype = {
		
	};
	
	jatX.augment(_Window.prototype, _prototype);
	jatX.augment(_Window.prototype, new jatX.EventRegister);
	
	jatX.Window = _Window;
	jatX.window = new _Window();
})();/**
 * 
 * @author Cheney
 */

(function() {
	var _cache = [];
	function _Document(doc) {
		this._document = doc || document;
		this.element = this._document.documentElement;
		this.body = this._document.body;
		this.head = this._document.getElementsByTagName("head")[0];
	}
	
	var _prototype = {
		getViewSize: function() {
			var _width = this.element.clientWidth;
			var _height = this.element.clientHeight;
			
			return {
				width: _width,
				height: _height
			};
		},
		getContentSize: function() {
			
		},
		getViewPosition: function() {
			var _top = this.element.scrollTop;
			var _left = this.element.scrollLeft;
			
			return {
				top: _top,
				left: _left
			};
		},
		setViewPosition: function(p) {
			
		}
	};
	
	jatX.augment(_Document.prototype, _prototype);
	jatX.augment(_Document.prototype, new jatX.EventDispatcher);
	
	jatX.Document = _Document;
	jatX.document = new _Document();
})();
/*!
 * Sizzle CSS Selector Engine - v1.0
 *  Copyright 2009, The Dojo Foundation
 *  Released under the MIT, BSD, and GPL Licenses.
 *  More information: http://sizzlejs.com/
 */
(function(){

var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
	done = 0,
	toString = Object.prototype.toString,
	hasDuplicate = false,
	baseHasDuplicate = true;

// Here we check if the JavaScript engine is using some sort of
// optimization where it does not always call our comparision
// function. If that is the case, discard the hasDuplicate value.
//   Thus far that includes Google Chrome.
[0, 0].sort(function(){
	baseHasDuplicate = false;
	return 0;
});

var Sizzle = function(selector, context, results, seed) {
	results = results || [];
	context = context || document;

	var origContext = context;

	if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
		return [];
	}
	
	if ( !selector || typeof selector !== "string" ) {
		return results;
	}

	var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context),
		soFar = selector, ret, cur, pop, i;
	
	// Reset the position of the chunker regexp (start from head)
	do {
		chunker.exec("");
		m = chunker.exec(soFar);

		if ( m ) {
			soFar = m[3];
		
			parts.push( m[1] );
		
			if ( m[2] ) {
				extra = m[3];
				break;
			}
		}
	} while ( m );

	if ( parts.length > 1 && origPOS.exec( selector ) ) {
		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
			set = posProcess( parts[0] + parts[1], context );
		} else {
			set = Expr.relative[ parts[0] ] ?
				[ context ] :
				Sizzle( parts.shift(), context );

			while ( parts.length ) {
				selector = parts.shift();

				if ( Expr.relative[ selector ] ) {
					selector += parts.shift();
				}
				
				set = posProcess( selector, set );
			}
		}
	} else {
		// Take a shortcut and set the context if the root selector is an ID
		// (but not if it'll be faster if the inner selector is an ID)
		if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
				Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
			ret = Sizzle.find( parts.shift(), context, contextXML );
			context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
		}

		if ( context ) {
			ret = seed ?
				{ expr: parts.pop(), set: makeArray(seed) } :
				Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
			set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;

			if ( parts.length > 0 ) {
				checkSet = makeArray(set);
			} else {
				prune = false;
			}

			while ( parts.length ) {
				cur = parts.pop();
				pop = cur;

				if ( !Expr.relative[ cur ] ) {
					cur = "";
				} else {
					pop = parts.pop();
				}

				if ( pop == null ) {
					pop = context;
				}

				Expr.relative[ cur ]( checkSet, pop, contextXML );
			}
		} else {
			checkSet = parts = [];
		}
	}

	if ( !checkSet ) {
		checkSet = set;
	}

	if ( !checkSet ) {
		Sizzle.error( cur || selector );
	}

	if ( toString.call(checkSet) === "[object Array]" ) {
		if ( !prune ) {
			results.push.apply( results, checkSet );
		} else if ( context && context.nodeType === 1 ) {
			for ( i = 0; checkSet[i] != null; i++ ) {
				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
					results.push( set[i] );
				}
			}
		} else {
			for ( i = 0; checkSet[i] != null; i++ ) {
				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
					results.push( set[i] );
				}
			}
		}
	} else {
		makeArray( checkSet, results );
	}

	if ( extra ) {
		Sizzle( extra, origContext, results, seed );
		Sizzle.uniqueSort( results );
	}

	return results;
};

Sizzle.uniqueSort = function(results){
	if ( sortOrder ) {
		hasDuplicate = baseHasDuplicate;
		results.sort(sortOrder);

		if ( hasDuplicate ) {
			for ( var i = 1; i < results.length; i++ ) {
				if ( results[i] === results[i-1] ) {
					results.splice(i--, 1);
				}
			}
		}
	}

	return results;
};

Sizzle.matches = function(expr, set){
	return Sizzle(expr, null, null, set);
};

Sizzle.find = function(expr, context, isXML){
	var set;

	if ( !expr ) {
		return [];
	}

	for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
		var type = Expr.order[i], match;
		
		if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
			var left = match[1];
			match.splice(1,1);

			if ( left.substr( left.length - 1 ) !== "\\" ) {
				match[1] = (match[1] || "").replace(/\\/g, "");
				set = Expr.find[ type ]( match, context, isXML );
				if ( set != null ) {
					expr = expr.replace( Expr.match[ type ], "" );
					break;
				}
			}
		}
	}

	if ( !set ) {
		set = context.getElementsByTagName("*");
	}

	return {set: set, expr: expr};
};

Sizzle.filter = function(expr, set, inplace, not){
	var old = expr, result = [], curLoop = set, match, anyFound,
		isXMLFilter = set && set[0] && isXML(set[0]);

	while ( expr && set.length ) {
		for ( var type in Expr.filter ) {
			if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
				var filter = Expr.filter[ type ], found, item, left = match[1];
				anyFound = false;

				match.splice(1,1);

				if ( left.substr( left.length - 1 ) === "\\" ) {
					continue;
				}

				if ( curLoop === result ) {
					result = [];
				}

				if ( Expr.preFilter[ type ] ) {
					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );

					if ( !match ) {
						anyFound = found = true;
					} else if ( match === true ) {
						continue;
					}
				}

				if ( match ) {
					for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
						if ( item ) {
							found = filter( item, match, i, curLoop );
							var pass = not ^ !!found;

							if ( inplace && found != null ) {
								if ( pass ) {
									anyFound = true;
								} else {
									curLoop[i] = false;
								}
							} else if ( pass ) {
								result.push( item );
								anyFound = true;
							}
						}
					}
				}

				if ( found !== undefined ) {
					if ( !inplace ) {
						curLoop = result;
					}

					expr = expr.replace( Expr.match[ type ], "" );

					if ( !anyFound ) {
						return [];
					}

					break;
				}
			}
		}

		// Improper expression
		if ( expr === old ) {
			if ( anyFound == null ) {
				Sizzle.error( expr );
			} else {
				break;
			}
		}

		old = expr;
	}

	return curLoop;
};

Sizzle.error = function( msg ) {
	throw "Syntax error, unrecognized expression: " + msg;
};

var Expr = Sizzle.selectors = {
	order: [ "ID", "NAME", "TAG" ],
	match: {
		ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
		CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
		TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
		CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
		PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
	},
	leftMatch: {},
	attrMap: {
		"class": "className",
		"for": "htmlFor"
	},
	attrHandle: {
		href: function(elem){
			return elem.getAttribute("href");
		}
	},
	relative: {
		"+": function(checkSet, part){
			var isPartStr = typeof part === "string",
				isTag = isPartStr && !/\W/.test(part),
				isPartStrNotTag = isPartStr && !isTag;

			if ( isTag ) {
				part = part.toLowerCase();
			}

			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
				if ( (elem = checkSet[i]) ) {
					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}

					checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
						elem || false :
						elem === part;
				}
			}

			if ( isPartStrNotTag ) {
				Sizzle.filter( part, checkSet, true );
			}
		},
		">": function(checkSet, part){
			var isPartStr = typeof part === "string",
				elem, i = 0, l = checkSet.length;

			if ( isPartStr && !/\W/.test(part) ) {
				part = part.toLowerCase();

				for ( ; i < l; i++ ) {
					elem = checkSet[i];
					if ( elem ) {
						var parent = elem.parentNode;
						checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
					}
				}
			} else {
				for ( ; i < l; i++ ) {
					elem = checkSet[i];
					if ( elem ) {
						checkSet[i] = isPartStr ?
							elem.parentNode :
							elem.parentNode === part;
					}
				}

				if ( isPartStr ) {
					Sizzle.filter( part, checkSet, true );
				}
			}
		},
		"": function(checkSet, part, isXML){
			var doneName = done++, checkFn = dirCheck, nodeCheck;

			if ( typeof part === "string" && !/\W/.test(part) ) {
				part = part.toLowerCase();
				nodeCheck = part;
				checkFn = dirNodeCheck;
			}

			checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
		},
		"~": function(checkSet, part, isXML){
			var doneName = done++, checkFn = dirCheck, nodeCheck;

			if ( typeof part === "string" && !/\W/.test(part) ) {
				part = part.toLowerCase();
				nodeCheck = part;
				checkFn = dirNodeCheck;
			}

			checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
		}
	},
	find: {
		ID: function(match, context, isXML){
			if ( typeof context.getElementById !== "undefined" && !isXML ) {
				var m = context.getElementById(match[1]);
				return m ? [m] : [];
			}
		},
		NAME: function(match, context){
			if ( typeof context.getElementsByName !== "undefined" ) {
				var ret = [], results = context.getElementsByName(match[1]);

				for ( var i = 0, l = results.length; i < l; i++ ) {
					if ( results[i].getAttribute("name") === match[1] ) {
						ret.push( results[i] );
					}
				}

				return ret.length === 0 ? null : ret;
			}
		},
		TAG: function(match, context){
			return context.getElementsByTagName(match[1]);
		}
	},
	preFilter: {
		CLASS: function(match, curLoop, inplace, result, not, isXML){
			match = " " + match[1].replace(/\\/g, "") + " ";

			if ( isXML ) {
				return match;
			}

			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
				if ( elem ) {
					if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
						if ( !inplace ) {
							result.push( elem );
						}
					} else if ( inplace ) {
						curLoop[i] = false;
					}
				}
			}

			return false;
		},
		ID: function(match){
			return match[1].replace(/\\/g, "");
		},
		TAG: function(match, curLoop){
			return match[1].toLowerCase();
		},
		CHILD: function(match){
			if ( match[1] === "nth" ) {
				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
				var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
					match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);

				// calculate the numbers (first)n+(last) including if they are negative
				match[2] = (test[1] + (test[2] || 1)) - 0;
				match[3] = test[3] - 0;
			}

			// TODO: Move to normal caching system
			match[0] = done++;

			return match;
		},
		ATTR: function(match, curLoop, inplace, result, not, isXML){
			var name = match[1].replace(/\\/g, "");
			
			if ( !isXML && Expr.attrMap[name] ) {
				match[1] = Expr.attrMap[name];
			}

			if ( match[2] === "~=" ) {
				match[4] = " " + match[4] + " ";
			}

			return match;
		},
		PSEUDO: function(match, curLoop, inplace, result, not){
			if ( match[1] === "not" ) {
				// If we're dealing with a complex expression, or a simple one
				if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
					match[3] = Sizzle(match[3], null, null, curLoop);
				} else {
					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
					if ( !inplace ) {
						result.push.apply( result, ret );
					}
					return false;
				}
			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
				return true;
			}
			
			return match;
		},
		POS: function(match){
			match.unshift( true );
			return match;
		}
	},
	filters: {
		enabled: function(elem){
			return elem.disabled === false && elem.type !== "hidden";
		},
		disabled: function(elem){
			return elem.disabled === true;
		},
		checked: function(elem){
			return elem.checked === true;
		},
		selected: function(elem){
			// Accessing this property makes selected-by-default
			// options in Safari work properly
			elem.parentNode.selectedIndex;
			return elem.selected === true;
		},
		parent: function(elem){
			return !!elem.firstChild;
		},
		empty: function(elem){
			return !elem.firstChild;
		},
		has: function(elem, i, match){
			return !!Sizzle( match[3], elem ).length;
		},
		header: function(elem){
			return (/h\d/i).test( elem.nodeName );
		},
		text: function(elem){
			return "text" === elem.type;
		},
		radio: function(elem){
			return "radio" === elem.type;
		},
		checkbox: function(elem){
			return "checkbox" === elem.type;
		},
		file: function(elem){
			return "file" === elem.type;
		},
		password: function(elem){
			return "password" === elem.type;
		},
		submit: function(elem){
			return "submit" === elem.type;
		},
		image: function(elem){
			return "image" === elem.type;
		},
		reset: function(elem){
			return "reset" === elem.type;
		},
		button: function(elem){
			return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
		},
		input: function(elem){
			return (/input|select|textarea|button/i).test(elem.nodeName);
		}
	},
	setFilters: {
		first: function(elem, i){
			return i === 0;
		},
		last: function(elem, i, match, array){
			return i === array.length - 1;
		},
		even: function(elem, i){
			return i % 2 === 0;
		},
		odd: function(elem, i){
			return i % 2 === 1;
		},
		lt: function(elem, i, match){
			return i < match[3] - 0;
		},
		gt: function(elem, i, match){
			return i > match[3] - 0;
		},
		nth: function(elem, i, match){
			return match[3] - 0 === i;
		},
		eq: function(elem, i, match){
			return match[3] - 0 === i;
		}
	},
	filter: {
		PSEUDO: function(elem, match, i, array){
			var name = match[1], filter = Expr.filters[ name ];

			if ( filter ) {
				return filter( elem, i, match, array );
			} else if ( name === "contains" ) {
				return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
			} else if ( name === "not" ) {
				var not = match[3];

				for ( var j = 0, l = not.length; j < l; j++ ) {
					if ( not[j] === elem ) {
						return false;
					}
				}

				return true;
			} else {
				Sizzle.error( "Syntax error, unrecognized expression: " + name );
			}
		},
		CHILD: function(elem, match){
			var type = match[1], node = elem;
			switch (type) {
				case 'only':
				case 'first':
					while ( (node = node.previousSibling) )	 {
						if ( node.nodeType === 1 ) { 
							return false; 
						}
					}
					if ( type === "first" ) { 
						return true; 
					}
					node = elem;
				case 'last':
					while ( (node = node.nextSibling) )	 {
						if ( node.nodeType === 1 ) { 
							return false; 
						}
					}
					return true;
				case 'nth':
					var first = match[2], last = match[3];

					if ( first === 1 && last === 0 ) {
						return true;
					}
					
					var doneName = match[0],
						parent = elem.parentNode;
	
					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
						var count = 0;
						for ( node = parent.firstChild; node; node = node.nextSibling ) {
							if ( node.nodeType === 1 ) {
								node.nodeIndex = ++count;
							}
						} 
						parent.sizcache = doneName;
					}
					
					var diff = elem.nodeIndex - last;
					if ( first === 0 ) {
						return diff === 0;
					} else {
						return ( diff % first === 0 && diff / first >= 0 );
					}
			}
		},
		ID: function(elem, match){
			return elem.nodeType === 1 && elem.getAttribute("id") === match;
		},
		TAG: function(elem, match){
			return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
		},
		CLASS: function(elem, match){
			return (" " + (elem.className || elem.getAttribute("class")) + " ")
				.indexOf( match ) > -1;
		},
		ATTR: function(elem, match){
			var name = match[1],
				result = Expr.attrHandle[ name ] ?
					Expr.attrHandle[ name ]( elem ) :
					elem[ name ] != null ?
						elem[ name ] :
						elem.getAttribute( name ),
				value = result + "",
				type = match[2],
				check = match[4];

			return result == null ?
				type === "!=" :
				type === "=" ?
				value === check :
				type === "*=" ?
				value.indexOf(check) >= 0 :
				type === "~=" ?
				(" " + value + " ").indexOf(check) >= 0 :
				!check ?
				value && result !== false :
				type === "!=" ?
				value !== check :
				type === "^=" ?
				value.indexOf(check) === 0 :
				type === "$=" ?
				value.substr(value.length - check.length) === check :
				type === "|=" ?
				value === check || value.substr(0, check.length + 1) === check + "-" :
				false;
		},
		POS: function(elem, match, i, array){
			var name = match[2], filter = Expr.setFilters[ name ];

			if ( filter ) {
				return filter( elem, i, match, array );
			}
		}
	}
};

var origPOS = Expr.match.POS,
	fescape = function(all, num){
		return "\\" + (num - 0 + 1);
	};

for ( var type in Expr.match ) {
	Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
	Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
}

var makeArray = function(array, results) {
	array = Array.prototype.slice.call( array, 0 );

	if ( results ) {
		results.push.apply( results, array );
		return results;
	}
	
	return array;
};

// Perform a simple check to determine if the browser is capable of
// converting a NodeList to an array using builtin methods.
// Also verifies that the returned array holds DOM nodes
// (which is not the case in the Blackberry browser)
try {
	Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;

// Provide a fallback method if it does not work
} catch(e){
	makeArray = function(array, results) {
		var ret = results || [], i = 0;

		if ( toString.call(array) === "[object Array]" ) {
			Array.prototype.push.apply( ret, array );
		} else {
			if ( typeof array.length === "number" ) {
				for ( var l = array.length; i < l; i++ ) {
					ret.push( array[i] );
				}
			} else {
				for ( ; array[i]; i++ ) {
					ret.push( array[i] );
				}
			}
		}

		return ret;
	};
};

var sortOrder;

if ( document.documentElement.compareDocumentPosition ) {
	sortOrder = function( a, b ) {
		if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
			if ( a == b ) {
				hasDuplicate = true;
			}
			return a.compareDocumentPosition ? -1 : 1;
		}

		var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
		if ( ret === 0 ) {
			hasDuplicate = true;
		}
		return ret;
	};
} else if ( "sourceIndex" in document.documentElement ) {
	sortOrder = function( a, b ) {
		if ( !a.sourceIndex || !b.sourceIndex ) {
			if ( a == b ) {
				hasDuplicate = true;
			}
			return a.sourceIndex ? -1 : 1;
		}

		var ret = a.sourceIndex - b.sourceIndex;
		if ( ret === 0 ) {
			hasDuplicate = true;
		}
		return ret;
	};
} else if ( document.createRange ) {
	sortOrder = function( a, b ) {
		if ( !a.ownerDocument || !b.ownerDocument ) {
			if ( a == b ) {
				hasDuplicate = true;
			}
			return a.ownerDocument ? -1 : 1;
		}

		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
		aRange.setStart(a, 0);
		aRange.setEnd(a, 0);
		bRange.setStart(b, 0);
		bRange.setEnd(b, 0);
		var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
		if ( ret === 0 ) {
			hasDuplicate = true;
		}
		return ret;
	};
}

// Utility function for retreiving the text value of an array of DOM nodes
function getText( elems ) {
	var ret = "", elem;

	for ( var i = 0; elems[i]; i++ ) {
		elem = elems[i];

		// Get the text from text nodes and CDATA nodes
		if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
			ret += elem.nodeValue;

		// Traverse everything else, except comment nodes
		} else if ( elem.nodeType !== 8 ) {
			ret += getText( elem.childNodes );
		}
	}

	return ret;
}

// Check to see if the browser returns elements by name when
// querying by getElementById (and provide a workaround)
(function(){
	// We're going to inject a fake input element with a specified name
	var form = document.createElement("div"),
		id = "script" + (new Date()).getTime();
	form.innerHTML = "<a name='" + id + "'/>";

	// Inject it into the root element, check its status, and remove it quickly
	var root = document.documentElement;
	root.insertBefore( form, root.firstChild );

	// The workaround has to do additional checks after a getElementById
	// Which slows things down for other browsers (hence the branching)
	if ( document.getElementById( id ) ) {
		Expr.find.ID = function(match, context, isXML){
			if ( typeof context.getElementById !== "undefined" && !isXML ) {
				var m = context.getElementById(match[1]);
				return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
			}
		};

		Expr.filter.ID = function(elem, match){
			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
			return elem.nodeType === 1 && node && node.nodeValue === match;
		};
	}

	root.removeChild( form );
	root = form = null; // release memory in IE
})();

(function(){
	// Check to see if the browser returns only elements
	// when doing getElementsByTagName("*")

	// Create a fake element
	var div = document.createElement("div");
	div.appendChild( document.createComment("") );

	// Make sure no comments are found
	if ( div.getElementsByTagName("*").length > 0 ) {
		Expr.find.TAG = function(match, context){
			var results = context.getElementsByTagName(match[1]);

			// Filter out possible comments
			if ( match[1] === "*" ) {
				var tmp = [];

				for ( var i = 0; results[i]; i++ ) {
					if ( results[i].nodeType === 1 ) {
						tmp.push( results[i] );
					}
				}

				results = tmp;
			}

			return results;
		};
	}

	// Check to see if an attribute returns normalized href attributes
	div.innerHTML = "<a href='#'></a>";
	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
			div.firstChild.getAttribute("href") !== "#" ) {
		Expr.attrHandle.href = function(elem){
			return elem.getAttribute("href", 2);
		};
	}

	div = null; // release memory in IE
})();

if ( document.querySelectorAll ) {
	(function(){
		var oldSizzle = Sizzle, div = document.createElement("div");
		div.innerHTML = "<p class='TEST'></p>";

		// Safari can't handle uppercase or unicode characters when
		// in quirks mode.
		if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
			return;
		}
	
		Sizzle = function(query, context, extra, seed){
			context = context || document;

			// Only use querySelectorAll on non-XML documents
			// (ID selectors don't work in non-HTML documents)
			if ( !seed && context.nodeType === 9 && !isXML(context) ) {
				try {
					return makeArray( context.querySelectorAll(query), extra );
				} catch(e){}
			}
		
			return oldSizzle(query, context, extra, seed);
		};

		for ( var prop in oldSizzle ) {
			Sizzle[ prop ] = oldSizzle[ prop ];
		}

		div = null; // release memory in IE
	})();
}

(function(){
	var div = document.createElement("div");

	div.innerHTML = "<div class='test e'></div><div class='test'></div>";

	// Opera can't find a second classname (in 9.6)
	// Also, make sure that getElementsByClassName actually exists
	if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
		return;
	}

	// Safari caches class attributes, doesn't catch changes (in 3.2)
	div.lastChild.className = "e";

	if ( div.getElementsByClassName("e").length === 1 ) {
		return;
	}
	
	Expr.order.splice(1, 0, "CLASS");
	Expr.find.CLASS = function(match, context, isXML) {
		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
			return context.getElementsByClassName(match[1]);
		}
	};

	div = null; // release memory in IE
})();

function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];
		if ( elem ) {
			elem = elem[dir];
			var match = false;

			while ( elem ) {
				if ( elem.sizcache === doneName ) {
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 && !isXML ){
					elem.sizcache = doneName;
					elem.sizset = i;
				}

				if ( elem.nodeName.toLowerCase() === cur ) {
					match = elem;
					break;
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}

function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
		var elem = checkSet[i];
		if ( elem ) {
			elem = elem[dir];
			var match = false;

			while ( elem ) {
				if ( elem.sizcache === doneName ) {
					match = checkSet[elem.sizset];
					break;
				}

				if ( elem.nodeType === 1 ) {
					if ( !isXML ) {
						elem.sizcache = doneName;
						elem.sizset = i;
					}
					if ( typeof cur !== "string" ) {
						if ( elem === cur ) {
							match = true;
							break;
						}

					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
						match = elem;
						break;
					}
				}

				elem = elem[dir];
			}

			checkSet[i] = match;
		}
	}
}

var contains = document.compareDocumentPosition ? function(a, b){
	return !!(a.compareDocumentPosition(b) & 16);
} : function(a, b){
	return a !== b && (a.contains ? a.contains(b) : true);
};

var isXML = function(elem){
	// documentElement is verified for cases where it doesn't yet exist
	// (such as loading iframes in IE - #4833) 
	var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
	return documentElement ? documentElement.nodeName !== "HTML" : false;
};

var posProcess = function(selector, context){
	var tmpSet = [], later = "", match,
		root = context.nodeType ? [context] : context;

	// Position selectors must be done after the filter
	// And so must :not(positional) so we move all PSEUDOs to the end
	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
		later += match[0];
		selector = selector.replace( Expr.match.PSEUDO, "" );
	}

	selector = Expr.relative[selector] ? selector + "*" : selector;

	for ( var i = 0, l = root.length; i < l; i++ ) {
		Sizzle( selector, root[i], tmpSet );
	}

	return Sizzle.filter( later, tmpSet );
};

// EXPOSE

window.Sizzle = Sizzle;

})();
/**
 * @author CHX
 */
jatX.effect = {
	easeInQuad: function(pos) {
		return Math.pow(pos, 2);
	},
	
	easeOutQuad: function(pos) {
		return -(Math.pow((pos - 1), 2) - 1);
	},
	
	easeInOutQuad: function(pos) {
		if ((pos /= 0.5) < 1) return 0.5 * Math.pow(pos, 2);
		return -0.5 * ((pos -= 2) * pos - 2);
	},
	
	easeInCubic: function(pos) {
		return Math.pow(pos, 3);
	},
	
	easeOutCubic: function(pos) {
		return (Math.pow((pos - 1), 3) + 1);
	},
	
	easeInOutCubic: function(pos) {
		if ((pos /= 0.5) < 1) return 0.5 * Math.pow(pos, 3);
		return 0.5 * (Math.pow((pos - 2), 3) + 2);
	},
	
	easeInQuart: function(pos) {
		return Math.pow(pos, 4);
	},
	
	easeOutQuart: function(pos) {
		return -(Math.pow((pos - 1), 4) - 1);
	},
	
	easeInOutQuart: function(pos) {
		if ((pos /= 0.5) < 1) return 0.5 * Math.pow(pos, 4);
		return -0.5 * ((pos -= 2) * Math.pow(pos, 3) - 2);
	},
	
	easeInQuint: function(pos) {
		return Math.pow(pos, 5);
	},
	
	easeOutQuint: function(pos) {
		return (Math.pow((pos - 1), 5) + 1);
	},
	
	easeInOutQuint: function(pos) {
		if ((pos /= 0.5) < 1) return 0.5 * Math.pow(pos, 5);
		return 0.5 * (Math.pow((pos - 2), 5) + 2);
	},
	
	easeInSine: function(pos) {
		return -Math.cos(pos * (Math.PI / 2)) + 1;
	},
	
	easeOutSine: function(pos) {
		return Math.sin(pos * (Math.PI / 2));
	},
	
	easeInOutSine: function(pos) {
		return (-.5 * (Math.cos(Math.PI * pos) - 1));
	},
	
	easeInExpo: function(pos) {
		return (pos == 0) ? 0 : Math.pow(2, 10 * (pos - 1));
	},
	
	easeOutExpo: function(pos) {
		return (pos == 1) ? 1 : -Math.pow(2, -10 * pos) + 1;
	},
	
	easeInOutExpo: function(pos) {
		if (pos == 0) return 0;
		if (pos == 1) return 1;
		if ((pos /= 0.5) < 1) return 0.5 * Math.pow(2, 10 * (pos - 1));
		return 0.5 * (-Math.pow(2, -10 * --pos) + 2);
	},
	
	easeInCirc: function(pos) {
		return -(Math.sqrt(1 - (pos * pos)) - 1);
	},
	
	easeOutCirc: function(pos) {
		return Math.sqrt(1 - Math.pow((pos - 1), 2));
	},
	
	easeInOutCirc: function(pos) {
		if ((pos /= 0.5) < 1) return -0.5 * (Math.sqrt(1 - pos * pos) - 1);
		return 0.5 * (Math.sqrt(1 - (pos -= 2) * pos) + 1);
	},
	
	easeOutBounce: function(pos) {
		if ((pos) < (1 / 2.75)) {
			return (7.5625 * pos * pos);
		} else if (pos < (2 / 2.75)) {
			return (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);
		} else if (pos < (2.5 / 2.75)) {
			return (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);
		} else {
			return (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);
		}
	},
	
	easeInBack: function(pos) {
		var s = 1.70158;
		return (pos) * pos * ((s + 1) * pos - s);
	},
	
	easeOutBack: function(pos) {
		var s = 1.70158;
		return (pos = pos - 1) * pos * ((s + 1) * pos + s) + 1;
	},
	
	easeInOutBack: function(pos) {
		var s = 1.70158;
		if ((pos /= 0.5) < 1) return 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s));
		return 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2);
	},
	
	elastic: function(pos) {
		return -1 * Math.pow(4, -8 * pos) * Math.sin((pos * 6 - 1) * (2 * Math.PI) / 2) + 1;
	},
	
	swingFromTo: function(pos) {
		var s = 1.70158;
		return ((pos /= 0.5) < 1) ? 0.5 * (pos * pos * (((s *= (1.525)) + 1) * pos - s)) : 0.5 * ((pos -= 2) * pos * (((s *= (1.525)) + 1) * pos + s) + 2);
	},
	
	swingFrom: function(pos) {
		var s = 1.70158;
		return pos * pos * ((s + 1) * pos - s);
	},
	
	swingTo: function(pos) {
		var s = 1.70158;
		return (pos -= 1) * pos * ((s + 1) * pos + s) + 1;
	},
	
	bounce: function(pos) {
		if (pos < (1 / 2.75)) {
			return (7.5625 * pos * pos);
		} else if (pos < (2 / 2.75)) {
			return (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);
		} else if (pos < (2.5 / 2.75)) {
			return (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);
		} else {
			return (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);
		}
	},
	
	bouncePast: function(pos) {
		if (pos < (1 / 2.75)) {
			return (7.5625 * pos * pos);
		} else if (pos < (2 / 2.75)) {
			return 2 - (7.5625 * (pos -= (1.5 / 2.75)) * pos + .75);
		} else if (pos < (2.5 / 2.75)) {
			return 2 - (7.5625 * (pos -= (2.25 / 2.75)) * pos + .9375);
		} else {
			return 2 - (7.5625 * (pos -= (2.625 / 2.75)) * pos + .984375);
		}
	},
	
	easeFromTo: function(pos) {
		if ((pos /= 0.5) < 1) return 0.5 * Math.pow(pos, 4);
		return -0.5 * ((pos -= 2) * Math.pow(pos, 3) - 2);
	},
	
	easeFrom: function(pos) {
		return Math.pow(pos, 4);
	},
	
	easeTo: function(pos) {
		return Math.pow(pos, 0.25);
	},
	
	linear: function(pos) {
		return pos;
	},
	
	sinusoidal: function(pos) {
		return (-Math.cos(pos * Math.PI) / 2) + 0.5;
	},
	
	reverse: function(pos) {
		return 1 - pos;
	},
	
	mirror: function(pos, transition) {
		transition = transition || tween.sinusoidal;
		if (pos < 0.5) 
			return transition(pos * 2);
		else return transition(1 - (pos - 0.5) * 2);
	},
	
	flicker: function(pos) {
		var pos = pos + (Math.random() - 0.5) / 5;
		return tween.sinusoidal(pos < 0 ? 0 : pos > 1 ? 1 : pos);
	},
	
	wobble: function(pos) {
		return (-Math.cos(pos * Math.PI * (9 * pos)) / 2) + 0.5;
	},
	
	pulse: function(pos, pulses) {
		return (-Math.cos((pos * ((pulses || 5) - .5) * 2) * Math.PI) / 2) + .5;
	},
	
	blink: function(pos, blinks) {
		return Math.round(pos * (blinks || 5)) % 2;
	},
	
	spring: function(pos) {
		return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6));
	},
	
	none: function(pos) {
		return 0;
	},
	
	full: function(pos) {
		return 1;
	}
};
/**
 * @author CHX
 * @namespace jatX.event
 */

jatX.event = function() {
	var _isReady = false;
	var _pool_domready = [];
	var _table_alias = {};
	var _event_define = {};


	////////////////////////[domready]
	function _domready(fCallback) {
		if (_isReady) {
			fCallback();
			return;
		}
		_pool_domready.push(fCallback);
	}
	function _checkDOMReady() {
		return (document && document.getElementsByTagName && document.getElementById && document.body);
	}
	function _fireDOMReady() {
		_isReady = true;
		while(_pool_domready.length > 0) {
			_pool_domready.shift()();
		}
	}
	//递归直到DOM加载
	(function() {
		(_checkDOMReady())?_fireDOMReady():setTimeout(arguments.callee, 100);
	})();
	
	/**
	 * 生成一个事件绑定器
	 * @param {Object} target 目标元素
	 * @param {String} type 事件名称
	 * @return {Object} 返回一个事件绑定器
	 */
	function _createBinder(target, type, options) {
		var binder = _table_alias[type] || jatX.event.Binder;
		return new binder(target, type, options);
	}
	/**
	 * 注册一个事件类型
	 * @param {String} sName 事件名称
	 * @param {Function} oClass 事件绑定器，缺省为Binder
	 */
	function _reg(sName, oClass) {
		_table_alias[sName] = oClass||jatX.event.Binder;
		ret[sName.toUpperCase()] = sName;
	}
	
	var ret = {
		define: {},
		domready: _domready,
		createBinder: _createBinder,
		reg: _reg
	};
	return ret;
}();
//jatX.event.bind(window, "unload", jatX.event.unbind);
jatX.ready = jatX.event.domready;
/**
 * @author jat
 */

jatX.event.BEFORE_DRAG = "before_drag";
jatX.event.DRAG        = "drag";
jatX.event.AFTER_DRAG  = "after_drag";
jatX.event.PLAYING     = "playing";
jatX.event.MOUSEOVER   = "mouseover";
jatX.event.MOUSEOUT    = "mouseout";
jatX.event.MOUSEDOWN   = "mousedown";
jatX.event.MOUSEUP     = "mouseup";
jatX.event.CLICK       = "click";
jatX.event.DBLCLICK    = "dblclick";

jatX.event.KEYDOWN     = "keydown";
jatX.event.KEYUP       = "keyup";
jatX.event.KEYPRESS    = "keypress";

jatX.event.HTTP_LOADING     = "loading";
jatX.event.HTTP_LOADED      = "loaded";
jatX.event.HTTP_INTERACTIVE = "interactive";
jatX.event.HTTP_COMPLETED   = "completed";
jatX.event.HTTP_ERROR       = "error";
jatX.event.HTTP_QUEUE       = "queue";
/**
 * DOM事件绑定器
 * @author Cheney
 */

jatX.event.Binder = jatX.Class({
	__init: function(target, type, opt) {
		this.use(new jatX.EventDispatcher);
		this.target  = target;
		this.type    = type;
		this.options = opt||{};
	},
	
	bind: function() {
		this.bindDOM();
	},
	unbind: function() {
		this.unbindDOM();
	},
	
	fire: function(e){
		
		this.dispatchEvent(jatX.event[this.type.toUpperCase()]||this.type, e);
	},
	
	bindDOM: function(target, type, fCallBack) {
		target = target || this.target;
		type = type || this.type;
		fCallBack = fCallBack || this.wrap(this.fire, this);
//		this.callBack = this.wrap(fCallBack || this.handler.handleEvent, context);
		
//		console.log("bind dom", target, type, fCallBack)
		if(target.addEventListener) {
			target.addEventListener(type, fCallBack, false);
		} else if(target.attachEvent) {
			target.attachEvent("on" + type, fCallBack);
		} else {
			this.bindDOM0(target, type, fCallBack);
		}
	},
	
	//包装，修正上下文对象，Event等。
	wrap: function(f, c){
		var owner = this;
		if (typeof f != "function") return null;
		return function(e){
			e = new jatX.Event(e);
			e.currentTarget = owner.target;//fix currentTarget
			e.type = owner.type;
			f.call(c || owner.target, e);
		};
	},
	unbindDOM: function(target, type, fCallBack) {
		target = target || this.target;
		type = type || this.type;
		fCallBack = fCallBack || this.fire;
		
//		console.log("unbind dom", target, type, fCallBack)
		if(target.removeEventListener) {
			target.removeEventListener(type, fCallBack, false);
		} else if(target.detachEvent) {
			target.detachEvent("on" + type, fCallBack);
		} else {
			this.unbindDOM0(target, type, fCallBack);
		}
	}
});
/**
 * @author Cheney
 */
/**
 * 双击按键
 * @author Cheney
 */

jatX.event.define.DoubleKeyPress = jatX.Class({
	__init: function() {
		this.step = 0;//表示击键次数
		this.keyCode = null;//存储上一次的keyCode
		
		this.extend(jatX.event.Binder);
		this._wrapMouseDown = this.wrap(this._onMouseDown, this);
		this.$super(arguments[0]);
	},
	bind: function() {
		this.bindDOM(null, "keydown", this._wrapMouseDown);
	},
	unbind: function() {
		this.unbindDOM(null, "keydown", this._wrapMouseDown);
	},
	fire0: function(e) {
		if (typeof this.handler.first === "function") {
			this.handler.first.apply(this.owner, this.arg);
		}
	},
	_onMouseDown: function(e) {
		this.step++;
		this.fire0(e);
		if (this.step === 2 && this.keyCode === e.key.code) {
			this.fire(e);
		}
		this.keyCode = e.key.code;
		this.coolDown.delay(200, this);
	},
	coolDown: function() {
		this.step = 0;
	}
});


jatX.event.reg("doublekeypress", jatX.event.define.DoubleKeyPress);/**
 * 自定义事件，拖动
 * @author Cheney
 */

jatX.event.define.Drag = jatX.Class({
	__init: function() {
		this.extend(jatX.event.Binder);
		
		//初始化包装器
		this._wrapDrag = this.wrap(this._drag, this);
		this._wrapMouseDown = this.wrap(this._startDrag, this);
		this._wrapMouseUp = this.wrap(this._endDrag, this);
		
		//必须在初始化包装器完成后再初始化父对象
		this.$super.apply(this, arguments);
		
		this._offset = {x:0, y:0};
	},
	bind: function() {
		this.bindDOM(null, "mousedown", this._wrapMouseDown);
	},
	_startDrag: function(e) {
		e.stop()
		this._startx = e.position.left;
		this._starty = e.position.top;
		
		e.rectx = e.position.left;
		e.recty = e.position.top;
		
		this.bindDOM(document, "mousemove", this._wrapDrag);
		this.bindDOM(document, "mouseup", this._wrapMouseUp);
		
		this.dispatchEvent(jatX.event.BEFORE_DRAG, e);
	},
	_drag: function(e) {
		e = new jatX.Event(e);
		e.offsetx = e.position.left - this._startx;
		e.offsety = e.position.top - this._starty;
		
		e.rectx = e.position.left;
		e.recty = e.position.top;
		
		if(typeof this.options.edge === "function") {
			var p = this.options.edge(e.position);
			if (p) {
				e.rectx = p.left;
				e.recty = p.top;
			}
		}
		this.dispatchEvent(jatX.event.DRAG, e);
	},
	_endDrag: function(e) {
		this.unbindDOM(document, "mousemove", this._wrapDrag);
		this.unbindDOM(document, "mouseup", this._wrapMouseUp);
		
		this.dispatchEvent(jatX.event.AFTER_DRAG, e);
	},
	unbind: function() {
		this.unbindDOM(null, "mousedown", this._wrapMouseDown);
	}
});

jatX.event.reg("drag", jatX.event.define.Drag);
/**
 * 识别按键和按键组合。
 * @author cheney
 */

jatX.event.define.Keymap = jatX.Class({
	__init: function() {
		this.extend(jatX.event.Binder);
//		console.log(this, 111)
		this._wrapKeypress = this.wrap(this._onKeypress, this);
		this._wrapKeydown = this.wrap(this._onKeydown, this);
		this._wrapKeyup = this.wrap(this._onKeyup, this);
		
		this.$super.apply(this, arguments);
		
		this._reset();
	},
	
	bind: function() {
		this.bindDOM(null, "keypress", this._wrapKeypress);
		this.bindDOM(null, "keydown", this._wrapKeydown);
		this.bindDOM(null, "keyup", this._wrapKeyup);
	},
	unbind: function() {
		this.unbindDOM(null, "keypress", this._wrapKeypress);
		this.unbindDOM(null, "keydown", this._wrapKeydown);
		this.unbindDOM(null, "keyup", this._wrapKeyup);
	},
	
	_onKeypress: function(e) {
		var code = e.key.charCode || e.key.keyCode;
		var letter = String.fromCharCode(code);
//		if(this.letter) {
//			if(letter !== this.letter) this.letter = letter;
//		}
//		console.log(code, this.letter, ":", letter)
		if (this.isPrintableChar) {
			e.letter = letter;
		}
		e.currentType = "keypress";
		e.keyname = this.keyname;
		
		this.dispatchEvent("keymap", e);
	},
	_onKeydown: function(e){
		var code = e.key.keyCode;
		
		var keyname = jatX.event.define.Keymap.table_function_key[code];
		
		if (!keyname) {
			keyname = jatX.event.define.Keymap.table_char_key[code];
			this.letter = keyname;
			this.isPrintableChar = true;
		} else {
			this.isPrintableChar = false;
		}
		this.keyname = keyname;
		
		this.keys.push(keyname);
		
		e.currentType = "keydown";
		e.keymap = this.keys.join("_");
		e.keyname = keyname;
		e.letter = null;
		this.dispatchEvent("keymap", e);
	},
	
	_onKeyup: function(e) {
		this._reset();
	},
	
	_reset: function() {
		this.keys = [];
		this.letter = "";
		this.keyname = "";
	}
});

jatX.event.define.Keymap.table_function_key = {
	8:"backspace", 9:"tab", 13:"enter", 19:"pause", 27:"escape", 32: "space",
	33:"pageup", 34:"pagedown", 35:"end", 36:"home", 37:"left", 38:"up",
	39:"right", 40:"down", 44:"printscreen", 45:"insert", 46:"delete",
	112:"f1", 113:"f2", 114:"f3", 115:"f4", 116:"f5", 117:"f6", 118:"f7",
	119:"f8", 120:"f9", 121:"f10", 122:"f11", 123:"f12", 144:"numlock", 145:"scrolllock",
	16:"shift", 17:"ctrl", 18:"alt"
};
jatX.event.define.Keymap.table_char_key = {
	48:"0", 49:"1", 50:"2", 51:"3", 52:"4", 53:"5", 54:"6", 55:"7", 56:"8", 57:"9",
	59:";", 61:"=", 65:"a", 66:"b", 67:"c", 68:"d", 69:"e", 70:"f", 71:"g", 72:"h",
	73:"i", 74:"j", 75:"k", 76:"l", 77:"m", 78:"n", 79:"o", 80:"p", 81:"q", 82:"r",
	83:"s", 84:"t", 85:"u", 86:"v", 87:"w", 88:"x", 89:"y", 90:"z", 107:"+", 109:"-",
	110:".", 188:",", 190:".", 191:"/", 192:"`", 219:"[", 220:"\\", 221:"]", 222:"\"",
	32: " "
};
jatX.event.reg("keymap", jatX.event.define.Keymap);
/**
 * 鼠标进入目标区域
 * @author Cheney
 */

jatX.event.reg("mouseenter", jatX.Class({
	__init: function() {
		this.extend(jatX.event.Binder);
		this._wrapMouseOver = this.wrap(this._onMouseOver, this);
		this._wrapMouseOut = this.wrap(this._onMouseOut, this);
		this.$super(arguments[0]);
		
		this._locked = false;
	},
	bind: function() {
		this.bindDOM(null, "mouseover", this._wrapMouseOver);
		this.bindDOM(null, "mouseout", this._wrapMouseOut);
	},
	unbind: function() {
		this.unbindDOM(null, "mouseover", this._wrapMouseOver);
		this.unbindDOM(null, "mouseout", this._wrapMouseOut);
	},
	_onMouseOver: function(e) {
		if(!this._locked) this.fire(e);
	},
	_onMouseOut: function(e) {
		this._lock();
		this._unlock.delay(0, this);
	},
	_lock: function() {
		this._locked = true;
	},
	_unlock: function() {
		this._locked = false;
	}
}));
/**
 * 鼠标离开目标区域
 * @author Cheney
 */

jatX.event.reg("mouseleave", jatX.Class({
	__init: function() {
		this.extend(jatX.event.Binder);
		this._wrapMouseOver = this.wrap(this._onMouseOver, this);
		this._wrapMouseOut = this.wrap(this._onMouseOut, this);
		this.$super(arguments[0]);
		
		this._locked = false;
		
	},
	bind: function() {
		this.bindDOM(null, "mouseover", this._wrapMouseOver);
		this.bindDOM(null, "mouseout", this._wrapMouseOut);
	},
	unbind: function() {
		this.unbindDOM(null, "mouseover", this._wrapMouseOver);
		this.unbindDOM(null, "mouseout", this._wrapMouseOut);
	},
	_onMouseOver: function(e) {
		this._cancel();
	},
	_onMouseOut: function(e) {
		this._tid = this.fire.delay(0, this, e);
	},
	_cancel: function() {
		clearTimeout(this._tid);
	}
}));
/**
 * @author Cheney
 */

jatX.event.reg("mousewheel", jatX.Class({
	__init: function() {
		this.extend(jatX.event.Binder);
		this._wrapWheel = this.wrap(this._onWheel, this);
		this.$super(arguments[0]);
	},
	
	bind: function() {
		//IE,Chrome,Safari,Opera
		this.bindDOM(null, "mousewheel", this._wrapWheel);
		//FireFox
		this.bindDOM(null, "DOMMouseScroll", this._wrapWheel);
	},
	
	unbind: function() {
			this.unbindDOM(null, "mousewheel", this._wrapWheel);
			this.unbindDOM(null, "DOMMouseScroll", this._wrapWheel);
	},
	
	_onWheel: function(e) {
		this.fire(e);
	}
}));
/**
 * @author Cheney
 */
/**
 * class Event
 * @constructor
 * @param {Object} e
 * @method {Object} $value
 */

jatX.Event = jatX.Class({
	__init: function(e) {
		if(typeof e === "object" && e instanceof arguments.callee) return e;
		
		this._event = e = e || window.event;
		this.target = e.target || e.srcElement;
		
		this.position = this.getPosition();
		this.key = this.getKey();
		this.button = this.getButton();
		this.type = this._event.type;

	},
	
	$value: function() {
		return this._event;
	},
	getPosition: function() {
		var _this = this;
		return {
			left: _this._event.clientX,
			top: _this._event.clientY,
			offsetLeft: _this._event.offsetX||_this._event.layerX,
			offsetTop: _this._event.offsetY||_this._event.layerY
		};
	},
	getButton: function() {
		var _this = this;
		var eW = this._event.which;
		var eB = this._event.button;
		function _getMouseWheel(){
			return _this._event.wheelDelta == 0 || _this._event.detail == 1 ? 0 : _this._event.wheelDelta < 0 || _this._event.detail > 0 ? 1 : -1;
		}
		
		return {
			delta: _getMouseWheel(),
			left: eW ? eB == 0 : !!(eB & 1),
			middle: eW ? eB == 1 : !!(eB & 4),
			right: eW ? eB == 2 : !!(eB & 2)
		};
	},
	getKey: function(){
		var e = this._event;
		var k = e.keyCode;
		var c = e.charCode||0;
	
		return {
			keyCode: k,
			charCode: c,
			alt: e.altKey,
			ctrl: e.ctrlKey,
			meta: e.metaKey,
			shift: e.shiftKey,
			up: (k == 38),
			down: (k == 40),
			left: (k == 37),
			right: (k == 39),
			enter: (k == 13),
			esc: (k == 27)
		};
	},
	stop: function(sType) {
		var _event = this._event;
		if (typeof sType == "undefined" || !sType) sType = "";
		sType = sType.toString().toLowerCase();
		switch (sType) {
			case "default", "1":
				_event.preventDefault ? _event.preventDefault() : _event.returnValue = false;
				break;
			case "bubble", "propagation", "2":
				_event.stopPropagation ? _event.stopPropagation() : _event.cancelBubble = true;
				break;
			default:
				_event.preventDefault ? _event.preventDefault() : _event.returnValue = false;
				_event.stopPropagation ? _event.stopPropagation() : _event.cancelBubble = true;
		}
		return this;
	}
});/**
 * @author Cheney
 */

jatX.Rectangle = jatX.Class({
	__init: function(left, top, width, height) {
		this.left = left>>0;
		this.top = top>>0;
		this.width = width>>0;
		this.height = height >> 0;
	},
	limit: function(p) {
		var _left = Math.max(p.left, this.left);
		_left = Math.min(_left, this.left + this.width);
		
		var _top = Math.max(p.top, this.top);
		_top = Math.min(_top, this.top + this.height);
		
		return {
			top: _top,
			left: _left
		};
	},
	isIn: function(p) {
		return ((p.left > this.left) && (p.left < this.left + this.width)) && ((p.top > this.top) && (p.top < this.top + this.height));
	},
	offset: function(offset) {
		this.top += offset.top||0;
		this.left += offset.left||0;
		this.width += offset.right||0;
		this.height += offset.bottom||0;
	}
});
/**
 * class Element 扩展DOM对象的方法
 * @author CHX
 */

jatX.Element = jatX.Class({
	__init: function(el) {
		this._element = el;
		
		this.use(new jatX.EventRegister);
//		alert(el)
		if (!this.valid()) {
			console.log(this._element, " is not an HTML element.");
			throw new Error("Invalid HTML element!");
		}

		this.tagName = this._element.tagName;
	},
	/**
	 * 判断一个对象是否是Element对象
	 * 调用方式  1. jatX.Element.prototype.valid(o);
	 * 			2. jatX.Element.prototype.valid.call(o);
	 * @param {Object} v
	 */
	valid: function(v) {
		var v = v || this._element || this;

		if(!v) return false;
		return v.nodeType && v.nodeType == 1;

		if(typeof v == "object") {
			if(/object|function/i.test(typeof HTMLElement) && v instanceof HTMLElement) {
				return true;
			} else {
				if(!(v instanceof Object) && v.nodeType && v.nodeType == 1) return true;
				return false;
			}
		}
		return false;
	},
	equals: function(obj) {
		return obj && (this._element === obj || this._element === obj._element);
	},
	getValue: function() {
		return this._element;
	},
	hasClass: function(sClass) {
		if(typeof sClass != "string" || !sClass) return false;
		return new RegExp("(?:^|\\s+)" + sClass + "(?:\\s+|$)").test(this._element.className);
	},
	delClass: function(sClass) {
		if (!sClass) {
			this._element.className = "";
			return this;
		}
		var a = this._element.className.split(/\s+/ig);
		a = a.filter(function(v) {
			return sClass != v;
		});
		this._element.className = a.join(" ");
		return this;
	},
	addClass: function(sClass) {
		if (!this.hasClass(sClass)) {
			this._element.className = this._element.className ? this._element.className + " " + sClass : sClass;
		}
		return this;
	},
	className: function(sClass) {
		if(typeof sClass == "string" && sClass) this._element.className = sClass;
		return this;
	},
	
	setStyle: function(name, value){
		var styleName;
		
		//过滤，只要字符串。
		if (typeof value != "string" && typeof value != "number") return this;
		if (name == "float") {
			styleName = this._element.currentStyle ? "styleFloat" : "cssFloat";
		} else {
			styleName = name;
		}
		this._element.style[styleName] = value.toString();
		return this;
	},
	setStyles: function(oStyle) {
		for (var stl in oStyle) {
			this.setStyle(stl, oStyle[stl]);
		}
	},
	
	getStyle: function(sName){
		var val = this._element.style[sName];
		if (!val) {
			if (document.defaultView && document.defaultView.getComputedStyle) {
				val = document.defaultView.getComputedStyle(this._element, null).getPropertyValue(sName);
			} else if (this._element.currentStyle) {
				sName = sName.replace(/\-([a-z])/ig, function($$, $1){
					return $1.toUpperCase();
				});
				val = this._element.currentStyle[sName];
			} else {
				val = "";
			}
		}
		return val;
	},

	getInnerSize: function() {
		return {
			width: this._element.clientWidth,
			height: this._element.clientHeight
		};
	},
	
	getOffsetSize: function() {
		return {
			width: this._element.offsetWidth,
			height: this._element.offsetHeight
		};
	},
	
	getSize: function(){
		var _width = /^(\d+)(?:px)?$/i.test(this.getStyle("width"))?parseInt(RegExp.$1):0;
		var _height = /^(\d+)(?:px)?$/i.test(this.getStyle("height"))?parseInt(RegExp.$1):0;
		return {
			width: _width,
			height: _height
		};
	},
	
	setSize: function(oSize) {
//		alert(oSize.width)
		if (typeof oSize.width == "number") this._element.style.width = Math.max(oSize.width, 0) + "px";
		if (typeof oSize.height == "number") this._element.style.height = Math.max(oSize.height, 0) + "px";
		return this;
	},
	
	top: function(top) {
		if(typeof top == "number") {
			this._element.style.top = top + "px";
			this.y = top;
			return this;
		} else {
			top = top || "offset";
			var _top = this._element.offsetTop;
			
			if(top != "offset") {
				var el = this._element;
				var _scrollOffset = document.documentElement.scrollTop + document.body.scrollTop;
				var _fixed = (top == "fixed");
			
				if (el.getBoundingClientRect) {
					//getBoundingClientRect 返回的值可能不是整数
					_top = Math.floor(el.getBoundingClientRect().top + (!_fixed ? _scrollOffset : 0));
				} else {
					while (el = el.offsetParent) {
						_top += el.offsetTop;
					}
					_top = _top - (_fixed ? _scrollOffset : 0);
				}
			}
			this.y = Math.floor(_top);
			return this.y;
		}
	},
	left: function(left) {
		if(typeof left == "number") {
			this._element.style.left = left + "px";
			this.x = left;
			return this;
		} else {
			left = left || "offset";
			var _left = this._element.offsetLeft;
			
			if(left != "offset") {
				var el = this._element;
				var _scrollOffset = document.documentElement.scrollLeft + document.body.scrollLeft;
				var _fixed = (left == "fixed");
			
				if (el.getBoundingClientRect) {
					//getBoundingClientRect 返回的值可能不是整数
					_left = Math.floor(el.getBoundingClientRect().left + (!_fixed ? _scrollOffset : 0));
				} else {
					while (el = el.offsetParent) {
						_left += el.offsetLeft;
					}
					_left = _left - (_fixed ? _scrollOffset : 0);
				}
			}
			this.x = Math.floor(_left);
			return this.x;
		}
		
	},
	width: function(width) {
		if(typeof width == "number") {
			this._element.style.width = width + "px";
			this.w = width;
			return this;
		} else {
			var _styleWidth = /^(\d+)(?:px)?$/i.test(this.getStyle("width"))?parseInt(RegExp.$1):NaN;
			this.w = isNaN(_styleWidth)?this._element.offsetWidth:_styleWidth;
			return this.w;
		}
	},
	height: function(height) {
		if(typeof height == "number") {
			this._element.style.height = height + "px";
			this.h = height;
			return this;
		} else {
			var _styleHeight = /^(\d+)(?:px)?$/i.test(this.getStyle("height"))?parseInt(RegExp.$1):NaN;
			
			this.h = isNaN(_styleHeight)?this._element.clientHeight:_styleHeight;
			return this.h;
		}
	},
	
	zIndex: function(z) {
		if(typeof z == "number") {
			this._element.style.zIndex = z;
			this.z = z;
			return this;
		}
		this.z = parseInt(this.getStyle("z-index"));
		return this.z;
	},
	
	/**
	 * 将本元素追加为elParent的子元素的最后
	 * @param {Object} elParent
	 */
	appendTo: function(elParent) {
		if (elParent instanceof this.constructor) elParent._element.appendChild(this._element);
		else elParent.appendChild(this._element);
		return this;
	},
	appendChild: function() {
		for (var i = 0; i < arguments.length; i++) {
			this._element.appendChild(!this.valid(arguments[i])?arguments[i]._element:arguments[i]);
		}
		return this;
	},
	/**
	 * 显示元素，可以设置参数 display 来强制元素的display级别（默认会自动判断原始级别）。
	 * @param {String} display
	 */
	show: function(display){
		if(typeof display == "string") {
			this._element.style.display = display;
			return this;
		}
		var s = this._element.style;
		var b = "block";
		var c = {
			P: b,
			DIV: b,
			FORM: b,
			H1: b,
			H2: b,
			H3: b,
			H4: b,
			OL: b,
			UL: b,
			FIELDSET: b,
			TD: "table-cell",
			TH: "table-cell",
			LI: "list-item",
			TABLE: "table",
			THEAD: "table-header-group",
			TBODY: "table-row-group",
			TFOOT: "table-footer-group",
			TR: "table-row",
			COL: "table-column",
			COLGROUP: "table-column-group",
			CAPTION: "table-caption",
			DL: b,
			DT: b,
			DD: b
		};
		
		try {
			if (typeof c[this.tagName] == "string") {
				s.display = c[this.tagName];
			} else {
				s.display = "inline";
			}
		} catch (e) {
			s.display = "block";
		}
		
		return this;
	},
	
	hide: function(){
		this._element.style.display = "none";
		return this;
	},
	
	setVisible: function(bVisi){
		sVisi = bVisi ? "visible" : "hidden";
		this.setStyle("visibility", sVisi);
		return this;
	},
	
	parent: function() {
		var ct = this.constructor;
		return new ct(this._element.parentNode);
	},
	
	attribute: function(name, value) {
		if(!value) return this._element.getAttribute(name);
		
		this._element.setAttribute(name, value);
		
		return this;
	},
	attributes: function(attr) {
		for(var a in attr) {
			this.attribute(a, attr[a]);
		}
		return this;
	},
	property: function(name, value) {
		if(!value) return this._element[name];
		
		this._element[name] = value;
		
		return this;
	},
	properties: function(prop) {
		for(var p in prop) {
			this.property(p, prop[p]);
		}
	},
	
	text: function(s){
		if (typeof s == "string") {
			if (typeof this._element.innerText != "undefined") {
				this._element.innerText = s;
			} else {
				this._element.textContent = s;
			}
			return this;
		}
		var t = this._element.innerText || this._element.textContent;
		if (typeof t != "string") t = "";
		return t;
	},
	html: function(s) {
		if(typeof s == "string") {
			this._element.innerHTML = s;
			return this;
		} else {
			return this._element.innerHTML;
		}
	},
	replaceWith: function(el) {
		if(!this.valid(el)) throw new Error('invalid node');
		if(this._element.parentNode.replaceChild(el, this._element)) {
			this._element = el;
		};
		return this;
	},
	clone: function(bIncludeChild) {
		var Cons = this.constructor;
		return new Cons(this._element.cloneNode(bIncludeChild));
	},
	die: function() {
		try {
			this.delEvent();
		} catch(e) {}
		this._element.parentNode.removeChild(this._element);
		delete this._element;
	},
	scrollIntoView: function(top) {
		try{
			this._element.scrollIntoView(top);
		} catch(e){};
		return this;
	},
	scrollTo: function(pos, dir) {
		
		var ss = 0;
		switch (pos) {
			case "top": ss = 0;break;
			case "middle": ss = (this._element.scrollHeight - this._element.clientHeight) / 2; break;
			case "bottom": ss = this._element.scrollHeight - this._element.clientHeight; break;
			
			case "left": ss = 0;break;
			case "center": ss = (this._element.scrollWidth - this._element.clientWidth) / 2;break;
			case "right": ss = this._element.scrollWidth - this._element.clientWidth;break;
			
			default: return this;
		}
		
		if (dir == "h") {
			this._element.scrollLeft = ss;
		} else {
			this._element.scrollTop = ss;
		}
		
		return this;
	},
	getElementsByClassName: function(sName) {
		if(this._element.getElementsByClassName) return this._element.getElementsByClassName(sName);
		
		var els = jatX.util.toArray(this._element.getElementsByTagName("*"));
		
		return els.filter(function(v) {
			return new RegExp("(?:^|\\s+)" + sName + "(?:\\s+|$)").test(v.className);
		});
	},
	/**
	 * Sizzle 引擎的CSS选择器
	 * @param {Object} str
	 */
	find: function(str) {
		var aEl = Sizzle(str, this._element);
		
		return aEl.map(function(v) {
			return new jatX.Element(v);
		}, this);
	},
	getSibling: function(dir) {
		if(!dir || dir !== "prev") dir = "next";
		var key = dir + "Sibling";
		var $ = this._element[key];
		
		while($ && $.nodeType !== 1) {
			$ = $[key];
		}
		
		return $;
	},
	insertSibling: function(el, dir) {
		var _el = this._element;
		if(dir && dir == "after") {
			var _next = this.getSibling("next");
			if (_next) {
				_el.parentNode.insertBefore(el, _next);
			} else {
				_el.parentNode.appendChild(el);
			}
		} else {
			_el.parentNode.insertBefore(el, _el);
		}
		return this;
	},
	/**
	 * 返回元素的坐标
	 * @param {String} refer 可能的值: document, offset(default), fixed
	 */
	getPosition: function(refer) {
		
		var _top = this.top(refer);
		var _left = this.left(refer);
		return {
			top: _top,
			left: _left
		};
	},
	/**
	 * 设置层的坐标(相对于整个文档)，z是可选的。
	 * @param {Object} oPos
	 */
	setPosition: function(oPos){
		if (!oPos) return;
		var x = oPos.left;
		var y = oPos.top;
		var z = oPos.z;
		var right = oPos.right;
		var bottom = oPos.bottom;
		
		if (typeof y == "number") this._element.style.top = y + "px";
		if (typeof x == "number") this._element.style.left = x + "px";
		if (typeof bottom == "number") this._element.style.bottom = bottom + "px";
		if (typeof right == "number") this._element.style.right = right + "px";
		if (typeof z == "number") this._element.style.zIndex = z;
		
		return this;
	}
});

/**
 * @author Cheney
 */

jatX.ElementRect = jatX.Class({
	__init: function($el) {
		this.extend(jatX.Rectangle);
		
		if ($el === document) {
			var size = jatX.document.getViewSize();
			var pos = jatX.document.getViewPosition();
			this.width = size.width;
			this.height = size.height;
			this.top = pos.top;
			this.left = pos.left;
		} else {
			var _element = jatX.$E($el);
			if (!_element) throw new Error("Require element for ElementRect.");
			
			this.width = _element.width();
			this.height = _element.height();
			
			this.top = _element.top();
			this.left = _element.left();
		}
	}
	
});
/**
 * @author CHX
 */

jatX.Table = jatX.Class({
	__init: function(el) {
		this.extend(jatX.Element);
		this.$super(el);
	},
	$value: function() {
		return this._element;
	},
	insertRow: function(idx) {
		return this._element.insertRow(idx);
	},
	addRow: function(iPos, iCells, sValue) {
		iCells = (typeof iCells == "number" && iCells) > 0 ? Math.round(iCells) : 1;
		
		var _a = [];
		
		var r = this._element.insertRow(iPos);
		for(var i = 0;i<iCells;i++) {
			var c = r.insertCell(i);
			_a.push(c);
			if(sValue) c.innerHTML = sValue.replace(/%i/, i);
		}
		
		return _a;
	},
	removeRow: function(iPos) {
		this._element.deleteRow(iPos);
	}
});
/**
 * @author Cheney
 */

jatX.Layer = jatX.Class({
	__init: function(v, p) {
		this._element = jatX.$(v||"<div>");
		p = p||document.body;
		this.extend(jatX.Element);
		this.$super(this._element);
		this.hide();
		p.appendChild(this._element);

		
	}
});
/**
 * @author cheney
 */

jatX.Request = jatX.Class({
	__init: function(method, url, data, opt) {
		this.use(new jatX.EventDispatcher);
		this.url = url;
		this.method = method;
		this.data = data;
		
		this.preventCache = true;
		this.async = true;
		this.time = 5000;
		
		this.xhr = this._createXhr();
		var owner = this;
		this.xhr.onreadystatechange = function() {
			owner._runner();
		};
	},
	_createXhr: function() {
		var xmlHttp;
		if (typeof XMLHttpRequest != "undefined") {
			xmlHttp = new XMLHttpRequest();
		} else if (window.ActiveXObject) {
			var aVersions = ["Msxml2.XMLHttp.5.0", "Msxml2.XMLHttp.4.0", "Msxml2.XMLHttp.3.0", "Msxml2.XMLHttp", "Microsoft.XMLHttp"];
			for (var i = 0; i < aVersions.length; i++) {
				try {
					xmlHttp = new ActiveXObject(aVersions[i]);
					break;
				} catch (e) {
				}
			}
		}
		return xmlHttp;
	},
	_buildUrl: function(withData) {
		var url = this.url;
		var sData = jatX.Request.serialize(this.data);
		if(withData) {
			var sep = url.indexOf("?") == -1 ? "?" : "&";
			url += sep + sData;
		}
		//用一个随机数来阻止缓存
		if(this.preventCache) {
			var sep = url.indexOf("?") == -1 ? "?" : "&";
			url += sep + new Date().getTime().toString(16);
		}
		return url;
	},
	_runner: function() {
//		console.log(this.xhr.readyState)
		switch(this.xhr.readyState) {
			case 1: this.dispatchEvent(jatX.event.HTTP_LOADING, null);break;
			case 2: this.dispatchEvent(jatX.event.HTTP_LOADED, null);break;
//			case 3: this.dispatchEvent(jatX.event.HTTP_INTERACTIVE, this.response());break;
			case 4: {
				if(this.timer) clearTimeout(this.timer);
				if(this.xhr.status == 200) {
					this.dispatchEvent(jatX.event.HTTP_COMPLETED, this.getResponse());
				} else {
					this.dispatchEvent(jatX.event.HTTP_ERROR, {
						type: "HTTP_ERROR",
						status: this.xhr.status,
						target: this
					});
				}
			};break;
		}
	},
	send: function() {
		switch(this.method) {
			case "GET": this.get(this._buildUrl(true));break;
			case "POST": this.post(this._buildUrl());break;
			case "HEAD": this.head(this._buildUrl(true));break;
			default: this.get(this._buildUrl(true));
		}
		this.timer = this.timeout.delay(this.time, this);
		return this;
		//runner
		var owner = this;
		(function() {
			if(!owner._runner()) setTimeout(arguments.callee, 80);
		})();
	},
	head: function(url) {
		this.xhr.open("HEAD", url, this.async);
		this.xhr.setRequestHeader("charset", "utf-8");
		this.xhr.send();
	},
	get: function(url) {
		
		this.xhr.open("GET", url, this.async);
		this.xhr.setRequestHeader("charset", "utf-8");
//		console.log("send:" + url)
		this.xhr.send();
	},
	post: function(url) {
		var sData = jatX.Request.serialize(this.data);
		this.xhr.open("POST", url, this.async);
		this.xhr.setRequestHeader("charset", "utf-8");
		this.xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
		this.xhr.send(sData);
	},
	abort: function() {
		this.xhr.onreadystatechange = null;
		this.xhr.abort();
		if(this.timer) clearTimeout(this.timer);
		this.dispatchEvent(jatX.event.HTTP_ERROR, {
			target: this
		});
	},
	getResponse: function(oRes) {
		var _text = "";
		var _xml = "";
		var _json;
		if (typeof oRes == "object") {
			_json = oRes;
			_text = this.serialize(_json);
		} else {
			_text = this.xhr.responseText;
			_xml = this.xhr.responseXML;
			try {
				var _code = "return " + _text.trim() + ";";
				_json = new Function(_code)();
				
			} catch (e) {
				_json = null;
			}
		}
		return {
			type: "completed",
			target: this,
			text: _text,
			xml: _xml,
			json: _json
		};
	},
	timeout: function() {
		this.abort();
		
		this.dispatchEvent(jatX.event.HTTP_ERROR, {
			type: "TIMEOUT",
			target: this
		});
		
		this.removeEventListeners();
	}
});

/**
 * 序列化一个对象
 * @param {Object} o
 */
jatX.Request.serialize = function(o){
	if (!o) return "";
	var a = [];
	for (var p in o) {
		a.push(p + "=" + encodeURIComponent(o[p]));
	}
	return a.join("&");
};
/**
 * @require jatX.Request
 * @author cheney
 */

jatX.JsonP = jatX.Class({
	__init: function(url, data, opt) {
		opt = opt || {};
		this.use(new jatX.EventDispatcher);
		this.url = url;
		this.data = data;
		
		this.callbackname = "callback";
		
		this.preventCache = true;
		this.time = opt.time || 5000;
		
		var owner = this;
		this.keeper = function() {
			owner.clear(true);
		};
	},
	send: function() {
		this.element = jatX.$E("<script>");
		this.element.attribute({
			"type": "text/javascript",
			"src": this._buildUrl()
		});
		this.element.appendTo(jatX.document.head);
		
		this.timer = this.timeout.delay(this.time, this);
	},
	_buildUrl: function() {
		var url = this.url;
		this.id = (this.generateCallbackId());
		
		var owner = this;
		jatX.JsonP[this.callbackname + this.id] = function(json){
			owner._callback(json);
		};
		this.data[this.callbackname] = "jatX.JsonP."+ this.callbackname + this.id;
		var sData = jatX.Request.serialize(this.data);
		var sep = url.indexOf("&") == -1 ? "?" : "&";
		url += sep + sData;
		//用一个随机数来阻止缓存
		if(this.preventCache) {
			sep = url.indexOf("&") == -1 ? "?" : "&";
			url += sep + new Date().getTime().toString(16);
		}
		return url;
	},
	generateCallbackId: function() {
		return new Date().getTime().toString(16);
	},
	_callback: function(json) {
		this.clear(true);
		this.dispatchEvent(jatX.event.HTTP_COMPLETED, {
			target: this,
			json: json
		});
	},
	timeout: function() {
		this.clear(false);
		this.dispatchEvent(jatX.event.HTTP_ERROR, {
			target: this
		});
	},
	clear: function(b) {
		if (b) {
			if(!jatX.JsonP[this.callbackname + this.id]) return;
			delete jatX.JsonP[this.callbackname + this.id];
			this.element.die();
		} else {
			jatX.JsonP[this.callbackname + this.id] = this.keeper;
			this.keeper.delay(30000, this);
		}
		if(this.timer) clearTimeout(this.timer);
		this.timer = null;
	},
	abort: function() {
		this.clear(false);
		this.dispatchEvent(jatX.event.HTTP_ERROR, {
			target: this
		});
	}
});

/**
 * 发送异步请求，实现请求队列queueMode, 类型有:
 * none(默认): 不排队。 wait:顺序排队。 cancel:只请求最后的，前面的取消。
 * 方法 get, post, head
 * @author Cheney
 */

jatX.Ajax = jatX.Class({
	__init: function(opt) {
		this.use(new jatX.EventDispatcher);
		opt = opt||{};
		this.url = opt.url;
		this.timeout = opt.timeout||12000;
		this.queueMode = opt.queueMode||"none";//wait, cancel
		
		this.currentProcess = null;

		this._queue = [];
	},
	request: function(method, data) {
		if(method == "JSONP") {
			var req = new jatX.JsonP(this.url, data);
		} else {
			var req = new jatX.Request(method, this.url, data);
		}
		req.addEventListeners(this._handlers, this);
		if(this.currentProcess) {
			switch(this.queueMode) {
				case "wait": this._queue.push(req);return;
				case "cancel": this.currentProcess.abort();break;
				default: ;
			}
		}
		req.send();
//		console.log("new: ---" + req.id)
		if (!this.currentProcess) {
//			console.log("set cur----" + req.url, this.currentProcess)
			this.currentProcess = req;
		};
	},
	head: function(data) {
		this.request("HEAD", data);
	},
	get: function(data) {
		this.request("GET", data);
	},
	post: function(data) {
		this.request("POST", data);
	},
	jsonp: function(data) {
		this.request("JSONP", data);
	},
	
	_handlers: {
		"completed": function(e) {
			var a = 1;
			this.dispatchEvent(jatX.event.HTTP_COMPLETED, e);
//			console.log("comp: "+e.text+"----"+(++a))
			if(this._queue.length > 0) {
				this.currentProcess = this._queue.shift();
//				console.log("shift:" + this.currentProcess.data.time +"----"+ (++a))
				this.currentProcess.send();
				this.dispatchEvent(jatX.event.HTTP_QUEUE, {
					currentProcess: this.currentProcess,
					target: this
				});
				return;
			}
			if (this.currentProcess) {
				this.currentProcess = null;
			}
			e.target.removeEventListeners();
		},
		"error": function(e) {
			this.dispatchEvent(jatX.event.HTTP_ERROR, e);
			if(this._queue.length > 0) {
				this.currentProcess = this._queue.shift().send();
				this.dispatchEvent(jatX.event.HTTP_QUEUE, {
					currentProcess: this.currentProcess,
					target: this
				});
				return;
			}
			if (this.currentProcess) {
				this.currentProcess = null;
			}
			e.target.removeEventListeners();
		},
		"loading": function(e) {
			this.dispatchEvent(jatX.event.HTTP_LOADING, e);
		},
		"loaded": function(e) {
			this.dispatchEvent(jatX.event.HTTP_LOADED, e);
		},
		"interactive": function(e) {
			this.dispatchEvent(jatX.event.HTTP_INTERACTIVE, e);
		}
	}
});

/**
 * 缓动的核心
 * @author CHX
 * @namespace jatX.Timer
 */

jatX.Timer = jatX.Class({
	__init: function(opt) {
		this.use(new jatX.EventDispatcher);
		this.options = opt;
		this.duration = opt.duration||0;
		this.step = opt.step||13;
		
		this.position = 0;
		this._timer = null;
		this.paused = false;
		this.stopped = true;
	},
	
	_runner: function(){
		if(this.duration) this.position = (new Date().getTime() - this._startTime) / this.duration;
		if (this.position > 1) this.position = 1;
		
		var event = {};
		event.n = (typeof this.options.adjust == "function") ? this.options.adjust(this.position) : this.position;
		this.dispatchEvent(jatX.event.EVENT_TWEEN, event);
		if (this.position >= 1) {
			this.stop();
		}
		if (this._paused) {
			clearInterval(this._timer);
		}
	},
	
	_startInterval: function() {
		var owner = this;
		this._timer = setInterval(function(){
			owner._runner();
		}, this.step);
	},

	start: function() {
		if(!this.stopped) return false;
		this.stopped = false;
		this._startTime = new Date().getTime();
		var event = {};
		this.dispatchEvent(jatX.event.EVENT_BEFORE, event);
		this._paused = false;
		this._startInterval();
	},
	stop: function() {
		if(this._timer) clearInterval(this._timer);
		this.position = 0;
		this._paused = false;
		this.stopped = true;
		var event = {};
		this.dispatchEvent(jatX.event.EVENT_AFTER, event);
		
	},
	pause: function() {
		if(this.stopped) return false;
		if(this._timer) clearInterval(this._timer);
		this._paused = true;
	},
	resume: function() {
		if(this.stopped) return false;
		this._startTime = new Date().getTime() - this.position*this.duration;
		this._paused = false;
		var owner = this;
		this._startInterval();
	}
});
/**
 * @author Cheney
 */
jatX.json = {
	decode: function(str) {
		var _text = str;
		try {
			var _code = "return " + _text.trim() + ";";
			return new Function(_code)();
			
		} catch (e) {
			return null;
		}
	},
	encode: function(obj) {
		//convert an object to json string.
	}
};
/**
 * @author CHX
 */

jatX.augment(jatX.util, {
	toArray: function(obj) {
		var a = [];
		for(var p in obj) {
			if(/^\d+$/.test(p)) a.push(obj[p]);
		}
		return a;
	},
	/**
	 * dispatchEvent
	 * @param {Object} element
	 * @param {String} event
	 */
	//from Prototype.js
	dispatchEvent: function(element, event) {
		if (document.createEventObject) {
			// dispatch for IE
			var evt = document.createEventObject();
			return element.dispatchEvent('on' + event, evt);
		} else {
			// dispatch for firefox + others
			var evt = document.createEvent("HTMLEvents");
			evt.initEvent(event, true, true); // event type,bubbling,cancelable
			return !element.dispatchEvent(evt);
		}
	}
});
/**
 * @author cheney
 */

jatX.Url = jatX.Class({
	__init: function(url) {
		this.url = url;
		
		this.host = "";
		this.protocol = "";
		this.filename = "";
		this.fileext = "";
		this.path = "";
		this.querystring = "";
		this.fragment = "";
		
		this.query = null;
	},
	
	_parse: function() {
		
	},
	
	addQuery: function(key, value) {
		
	},
	
	addQueryString: function(str) {
		
	}
});
/**
 * 存取document.cookie
 * @author Cheney
 */

jatX.util.cookie = function() {
	function _get(sName) {
		var a = document.cookie.split(/\s*;\s*/);
		var x = "";
		for(var i=0;i<a.length;i++) {
			x = a[i].split("=");
			if(x[0] === sName) return unescape(x[1]);
		}
		return null;
	}
	
	function _set(sName, sValue, nDays, sDomain, sPath) {
		var sExpire = "";
		if (typeof nDays == "number") {
			sExpire = ";expires=" + (new Date((new Date()).getTime() + nDays * 1000 * 60 * 60 * 24)).toGMTString();
		}
		if (typeof sDomain == "undefined") sDomain = "";
		if (typeof sPath == "undefined") sPath = "/";
		document.cookie = sName + "=" + escape(sValue) + sExpire + "; path=" + sPath + (sDomain ? "; domain=" + sDomain : "");
		return this;
	}
	
	return {
		"get" : _get,
		"set" : _set
	};
}();
/**
 * 拖动一个对象，参数target为产生拖动的对象，参数dragBox为被拖动的对象
 * @author CHX
 * @version 090730
 */
jatX.util.Drag = jatX.Class({
	__init: function(dragObj, moveObj, opt) {
		this.use(new jatX.EventDispatcher);
		
		this.options = opt||{};
		this.container_offset = this.options.container_offset||{};

		this.dragObj = jatX.$E(dragObj);
		if(!dragObj) throw new Error("No dragObj element specified");
		this.moveObj = jatX.$E(moveObj)||this.dragObj;
		
		var owner = this;
		this.dragObj.registerEvent(jatX.event.DRAG, {
			edge: function(p){
				return owner.fRect(p);
			}
		});
		this.dragObj.addEventListeners(this._handlers, this);
		
		
		this.position_refer = this.moveObj.getStyle("position");
//		console.log(this, 1)
	},
	_offset: {
		top: 0,
		left: 0
	},
	_getXY: function() {
		
	},

	fRect: function(p) {
		if(!this.rect) return null;
		return this.rect.limit(p);
		
	},
	
	_handlers: {
		drag: function(e){
			e.stop();
			var _top = e.recty - this._offset.top;
			var _left = e.rectx - this._offset.left;
			var p = (typeof this.options.adjust == "function") ? this.options.adjust.call(this, _left, _top) : {
				left: _left,
				top: _top
			};
			if (p) {
				this.moveObj.setPosition(p);
				e.top = p.top;
				e.left = p.left;
				this.dispatchEvent(jatX.event.EVENT_DRAG, e);
			}
			
		//		this._position_last = oPosition;
		},
		before_drag: function(e){
		
			this.innerRect = new jatX.ElementRect(this.moveObj);
			if (this.options.rect || this.options.container) {
				this.outerRect = this.options.rect || new jatX.ElementRect(this.options.container);
				this.outerRect.offset(this.container_offset);
			}
			//		console.log(this.innerRect, this.outerRect)
			if (this.outerRect) {
				if (this.position_refer == "fixed") {
					outer_left = 0;
					outer_top = 0;
				} else {
					outer_left = this.outerRect.left;
					outer_top = this.outerRect.top;
				}
				var left = e.position.left - this.innerRect.left + outer_left;
				var top = e.position.top - this.innerRect.top + outer_top;
				var width = this.outerRect.width - this.innerRect.width;
				var height = this.outerRect.height - this.innerRect.height;
				
				
				//			console.log(height)
				this.rect = new jatX.Rectangle(left, top, width, height);
			} else {
				this.rect = null;
			}
			var _p = this.moveObj.getPosition(this.position_refer);
			this._offset.left = e.rectx - _p.left;
			this._offset.top = e.recty - _p.top;
			e.left = _p.left;
			e.top = _p.top;
			this.dispatchEvent("onStart", e);
		},
		after_drag: function(e){
			var _p = this.moveObj.getPosition(this.position_refer);
			e.left = _p.left;
			e.top = _p.top;
			this.dispatchEvent("onEnd", e);
		}
	},
	
	disable: function() {
		this.disabled = true;
	},
	enable: function() {
		this.disabled = false;
	}
});
/**
 * @author CHX
 */

jatX.LayerManager = jatX.Class({
	__init: function(opt) {
		opt = opt||{};
		this.use(new jatX.EventDispatcher);
		this.$area = opt.area || document.body;
		this._arr_layers = [];
		
		this.currentTarget = null;
		this.bottom_z = opt.bottom_z||0;
		this.top_z = this.bottom_z;
		
	},
	
	_findLayers: function() {
		var tags = this.$area.getElementsByTagName("*");
		for(var i=0; i<tags.length; i++) {
			
		}
	},
	
	getTopZ: function() {
		
	},
	add: function(layer) {
		var z = layer.zIndex("z-index");
		var owner = this;
		
		layer.z = z;
		this.top_z = Math.max(this.top_z, z);
		layer.registerEvent(jatX.event.MOUSEDOWN);
		layer.addEventListener(jatX.event.MOUSEDOWN, function(e) {
			owner.focus(this);
		});
		this._arr_layers.push(layer);
	},
	focus: function(layer) {
		if (this.currentTarget) {
			this.currentTarget.dispatchEvent("blur", null);
		}
		var z = layer.z;
		layer.zIndex(this.top_z + 1);
		
		this._z_collapse(z);
		this.currentTarget = layer;
		
		this.currentTarget.dispatchEvent("focus", null);
		
	},
	_z_collapse: function(n) {
		console.log(n)
		for (var i = 0, l = this._arr_layers.length; i < l; i++) {
			if (this._arr_layers[i].z > n) this._arr_layers[i].zIndex(this._arr_layers[i].z - 1 + this.bottom_z);
		}
	},
	createLayer: function() {
		
	}
});
/**
 * @author CHX
 */

jatX.util.NodePath = jatX.Class({
	__init: function(oNode, oTop) {
		
		this.topNode = oTop || document.documentElement;
		this.arr = [];
		
		if(oNode) this.parse(oNode);
	},
	
	parse: function(oNode) {
		this.arr.length = 0;
		
		if(oNode === document) return this;
		
		if(oNode === document.documentElement) {
			this.arr.push(this.topNode);
			return this;
		}
		
		do {
			this.arr.push(oNode);
			oNode = oNode.parentNode;
		} while (oNode&&oNode!==this.topNode);
		
		this.arr.push(this.topNode);
		
		return this;
	},
	

	
	isLeaf: function(oNode) {
		if(oNode.childNodes.length == 0) return true;
		return oNode.childNodes.length == 1 && oNode.childNodes[0].nodeType == 3;
	},
	
	toString: function() {
		var a = [];
		this.arr.forEach(function(v) {
			a.push(v.tagName);
		});
		return a.join(" >> ");
	}
});

