void function(){var mapping={},cache={};window.define=function(id,func){mapping[id]=func};window.require=function(id){if(!/\.js$/.test(id))id+='.js';if(cache[id])return cache[id];else return cache[id]=mapping[id]()}}();define("scripts/core/main.js",function(exports){exports={};var currentAlbumId;
var loading = require("scripts/modules/loading/main");
var Ucren = require("scripts/libs/ucren");
var page = require("scripts/modules/page/main");
var tree = require("scripts/modules/tree/main");
var list = require("scripts/modules/list/main");
var detail = require("scripts/modules/detail/main");

// 加载页面元素
var loadPage = function(){
	loading.show("正在加载页面");
	loading.hide();
	Ucren.Element("page").display(true);
	list.render("content");
	loadFolders();
	detail.render();
	defineEvents();
	page.startIn.defer(page, 500);
};

// 加载目录
var loadFolders = function(){
	loading.show("正在加载目录数据");
	var folder = Ucren.Element("folder");
	void function(data){
		data = require("store/folders");
		folder.html("");
		var folderTree = new tree({
			container: "folder",
			data: data,
			enableCheckBox: false,
			clickHandler: function(clickItem){
				if(clickItem.album){
				    loadAlbum("store/" + clickItem.album);
				}
			}
		});
		folderTree.render.defer(folderTree, 500);
		loading.hide();
	}();
};

// 加载专辑照片专列表
var loadAlbum = function(){
	var cache = {};
    return function(id){
		if(currentAlbumId == id)return ;
		currentAlbumId = id;
	    cache[id] || loading.show("正在加载专辑数据");

	    if(/albums\/(\w+)\//.test(id))
	        detail.setAlbumName(RegExp.$1);
	    
	    void function(data){
	    	data = require(id);
	    	cache[id] = true;
	        list.setData(id, data);
	        detail.setAlbumData(data);
	        loading.hide();
	    }();
	}
}();

// 定义事件
var defineEvents = function(){
	var starthere = Ucren.Element("starthere");
	list.dblclick(function(index){
		page.go("detail-page");
		detail.isCached(index) || loading.show("正在打开照片");
		detail.showIndex(index, function(){
		    loading.hide();
		});
	});
	detail.onClose(function(currentIndex){
	    page.go("list-page");
	    list.focusIndex(currentIndex);
	});

	document.onkeydown = function(){ return false; }
	
	var folder = Ucren.Element("folder");
	var startHiden = folder.addEvents({
		mousemove: function(){
		    if(starthere.display()){
		    	page.startOut();
		    	folder.removeEvents(startHiden);
		    }
		}
	});
};

exports.start = function(){
	loadPage();
};;return exports});define("scripts/libs/ucren.js",function(exports){exports={};/**
 * ucren-lite
 * filename: boot.js
 * author: dron
 * date: 2009-03-15
 * contact: ucren.com
 */

	var Ucren;
	//
	// [基本数据类型扩展]
	//

	// String.prototype.trim
	String.prototype.trim = function(){
		return this.replace(/^\s+|\s+$/, "");
	};

	// String.prototype.format
	String.prototype.format = function(conf){
		var rtn = this, blank = {};
		Ucren.each(conf, function(item, key){
			item = item.toString().replace(/\$/g, "$$$$");
			rtn = rtn.replace(RegExp("@{" + key + "}", "g"), item);
		});
		return rtn.toString();
	};

	// String.prototype.htmlEncode
	String.prototype.htmlEncode = function(){
		var div = document.createElement("div");
		return function(){
			var text;
			div.appendChild(document.createTextNode(this));
			text = div.innerHTML;
			div.innerHTML = "";
			return text;
		};
	}();

	// String.prototype.byteLength
	String.prototype.byteLength = function(){
		return this.replace(/[^\x00-\xff]/g, "--").length;
	};

	// String.prototype.subByte
	String.prototype.subByte = function(len, tail){
		var s = this;
		if(s.byteLength() <= len)
			return s;
		tail = tail || "";
		len -= tail.byteLength();
		return s = s.slice(0, len).replace(/([^\x00-\xff])/g, "$1 ")
			.slice(0, len)
			.replace(/[^\x00-\xff]$/, "")
			.replace(/([^\x00-\xff]) /g, "$1") + tail;
	}

	// Function.prototype.defer
	Function.prototype.defer = function(scope, timeout){
		var me = this;
		var fn = function(){
			me.apply(scope, arguments);
		};
		return setTimeout(fn, timeout);
	};


	// Function.prototype.bind
	Function.prototype.bind = function(scope){
		var me = this;
		return function(){
			return me.apply(scope, arguments);
		}
	};

	// Function.prototype.improve
	Function.prototype.improve = function(fn){
		var origin = this;
		return function(){
			var args = [].slice.call(arguments);
				args.unshift(origin);
			return fn.apply(this, args);
		};
	};

	// Function.prototype.saturate
	Function.prototype.saturate = function(scope/*, args */){
		var fn = this;
		var args = Array.prototype.slice.call(arguments, 1);
		return function(){
			return fn.apply(scope, args);
		}
	};

	// Function.prototype.when
	Function.prototype.when = function(cond){
		var f = function(x){
			if(x = cond()){
				clearInterval(f.timer);
				return this.call(this, x);
			}
		}.bind(this);
		f.timer = setInterval(f, 100);
	};

	// Function.prototype.condition
	Function.prototype.condition = function(cond){
		var fn = this;
		return function(){
			if(cond.apply(this, arguments)){
				return fn.apply(this, arguments);
			}
		};
	};

	// Function.prototype.infrequently
	Function.prototype.infrequently = function(interval){
		interval = interval || 100;
		var fn = this;
		var callbacks = {};
		var count = 0;
		var nul = function(){};
		var stoped = false;
		var returnFunc = function(){
			var self = this, args = Array.prototype.slice.call(arguments, 0);
			callbacks[count] = function(count){
				return function(){
					if(stoped)
						return ;
					fn.apply(self, args);
					delete callbacks[count];
					setTimeout(callbacks[count + 1] || nul, interval);
				};
			}(count);
			if(count == 0){
				setTimeout(callbacks[count] || nul, interval);
			}
			count ++;
		};
		returnFunc.stop = function(){
			stoped = true;
		};
		return returnFunc;
	};

	// Function.prototype.concatArguments
	Function.prototype.concatArguments = function(scope/*, args */){
		var me = this;
		var outerArg = Array.prototype.slice.call(arguments, 1);
		return function(){
			var innerArg = Array.prototype.slice.call(arguments, 0);
			return me.apply(scope, innerArg.concat(outerArg));
		};
	};

	// Array.prototype.indexOf
	Array.prototype.indexOf = function(item, i){
		i || (i = 0);
		var length = this.length;
		if(i < 0)
			i = length + i;
		for(; i < length; i++)
			if(this[i] === item)
				return i;
		return -1;
	};

	// Array.prototype.lastIndexOf
	Array.prototype.lastIndexOf = function(item, i) {
		i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
		var n = this.slice(0, i).reverse().indexOf(item);
		return (n < 0) ? n : i - n - 1;
	};

	// Array.prototype.every
	Array.prototype.every = function(fn, context) {
		for (var i = 0, len = this.length >>> 0; i < len; i++) {
			if (i in this && !fn.call(context, this[i], i, this)) {
				return false;
			}
		}
		return true;
	};

	// Array.prototype.filter
	Array.prototype.filter = function(fn, context) {
		var result = [ ], val;
		for (var i = 0, len = this.length >>> 0; i < len; i++) {
			if (i in this) {
				val = this[i]; // in case fn mutates this
				if (fn.call(context, val, i, this)) {
					result.push(val);
				}
			}
		}
		return result;
	};

	// Array.prototype.forEach
	Array.prototype.forEach = function(fn, context) {
		for (var i = 0, len = this.length >>> 0; i < len; i++) {
			if (i in this) {
				fn.call(context, this[i], i, this);
			}
		}
	};

	// Array.prototype.map
	Array.prototype.map = function(fn, context) {
		var result = [ ];
		for (var i = 0, len = this.length >>> 0; i < len; i++) {
			if (i in this) {
				result[i] = fn.call(context, this[i], i, this);
			}
		}
		return result;
	};

	// Array.prototype.some
	Array.prototype.some = function(fn, context) {
		for (var i = 0, len = this.length >>> 0; i < len; i++) {
			if (i in this && fn.call(context, this[i], i, this)) {
				return true;
			}
		}
		return false;
	};

	// Array.prototype.remove
	Array.prototype.remove = function(value){
		var idx = this.indexOf(value);
		if (idx !== -1) {
			this.splice(idx, 1);
		}
		return this;
	};

	// Array.prototype.reduce
	Array.prototype.reduce = function(fn /*, initial*/) {
		var len = this.length >>> 0, i = 0, rv;

		if (arguments.length > 1) {
			rv = arguments[1];
		} else {
			do {
				if (i in this) {
					rv = this[i++];
					break;
				}
				if (++i >= len) {
					throw new TypeError();
				}
			}
			while (true);
		}

		for (; i < len; i++) {
			if (i in this) {
				rv = fn.call(null, rv, this[i], i, this);
			}
		}

		return rv;
	};

	// Array.prototype.scramble
	Array.prototype.scramble = function(){
		var len = this.length, idx = 0, ary = this.slice(0), result = [];
		while(len --)
			result[idx ++] = ary.splice(Ucren.randomNumber(len), 1);
		return result;
	};

	// Number.prototype.pad (disable)
//	Number.prototype.pad = function(length){
//		var num = this.toString().split(".")[0];
//		if(length - num.length > -1){
//			return Array(length - num.length + 1).join("0") + num;
//		}else{
//			return num;
//		}
//	};

	Ucren = {

		//
		// [全局属性]
		//

		// Ucren.isIe
		isIe: /msie/i.test(navigator.userAgent),

		// Ucren.isIe6
		isIe6: /msie 6/i.test(navigator.userAgent),

		// Ucren.isFirefox
		isFirefox: /firefox/i.test(navigator.userAgent),

		// Ucren.isSafari
		isSafari: /safari/i.test(navigator.userAgent),

		// Ucren.isOpera
		isOpera: /opera/i.test(navigator.userAgent),

		// Ucren.isChrome
		isChrome: /chrome/i.test(navigator.userAgent), //todo isChrome = true, isSafari = true

		// Ucren.isStrict
		isStrict: document.compatMode == "CSS1Compat",

		// Ucren.tempDom
		tempDom: document.createElement("div"),

		//
		// [全局方法]
		//

		// Ucren.apply
		apply: function(form, to, except){
			if(!to)to = {};
			if(except){
				Ucren.each(form, function(item, key){
					if(key in except)
						return ;
					to[key] = item;
				});
			}else{
				Ucren.each(form, function(item, key){
					to[key] = item;
				});
			}
			return to;
		},

		// Ucren.appendStyle
		appendStyle: function(text){
			var style;

			if(arguments.length > 1)
				text = Array.prototype.join.call(arguments, "");

			if(document.createStyleSheet){
				style = document.createStyleSheet();
				style.cssText = text;
			}else{
				style = document.createElement("style");
				style.type = "text/css";
				//style.innerHTML = text; fix Chrome bug
				style.appendChild(document.createTextNode(text));
				document.getElementsByTagName("head")[0].appendChild(style);
			}
		},

		// Ucren.addEvent
		addEvent: function(target, name, fn){
			var call = function(){
				fn.apply(target, arguments);
			};
			if(target.dom){
				target = target.dom;
			}
			if(window.attachEvent){
				target.attachEvent("on" + name, call);
			}else if(window.addEventListener){
				target.addEventListener(name, call, false);
			}else{
				target["on" + name] = call;
			}
			return call;
		},

		// Ucren.delEvent
		delEvent: function(target, name, fn){
			if(window.detachEvent){
				target.detachEvent("on" + name, fn);
			}else if(window.removeEventListener){
				target.removeEventListener(name, fn, false);
			}else if(target["on" + name] == fn){
				target["on" + name] = null;
			}
		},

		// Ucren.Class
		Class: function(initialize, methods, befores, afters){
			var fn, prototype, blank;
			initialize = initialize || function(){};
			methods = methods || {};
			blank = {};
			fn = function(){
				this.instanceId = Ucren.id();
				initialize.apply(this, arguments);
			};
			prototype = fn.prototype;
			Ucren.registerClassEvent.call(prototype);
			Ucren.each(methods, function(item, key){
				prototype[key] = function(method, name){
					if(typeof(method) == "function"){
						return function(){
							var args, rtn;
							args = Array.prototype.slice.call(arguments, 0);
							if(befores &&
								befores.apply(this, [name].concat(args)) === false){
								return ;
							}
							this.fireEvent("before" + name, args);
							rtn = method.apply(this, args);
							if(afters)
								afters.apply(this, [name].concat(args));
							this.fireEvent(name, args);
							return rtn;
						};
					}else{
						return method;
					}
				}(item, key);
			});
			prototype.getOriginMethod = function(name){
				return methods[name];
			};
			return fn;
		},

		//private
		registerClassEvent: function(){
			this.on = function(name, fn){
				var instanceId = this.instanceId;
				Ucren.dispatch(instanceId + name, fn.bind(this));
			};
			this.onbefore = function(name, fn){
				var instanceId = this.instanceId;
				Ucren.dispatch(instanceId + "before" + name, fn.bind(this));
			};
			this.un = function(name, fn){
				//todo
			};
			this.fireEvent = function(name, args){
				var instanceId = this.instanceId;
				Ucren.dispatch(instanceId + name, args);
			};
		},

		// Ucren.createFuze
		createFuze: function(){
			var queue, fn, infire;
			queue = [];
			fn = function(process){
				if(infire){
					process();
				}else{
					queue.push(process);
				}
			};
			fn.fire = function(){
				while(queue.length){
					queue.shift()();
				}
				infire = true;
			};
			fn.extinguish = function(){
				infire = false;
			};
			fn.wettish = function(){
				if(queue.length){
					queue.shift()();
				}
			};
			return fn;
		},

		// Ucren.createIf
		createIf: function(expressionFunction){
			return function(callback){
				var expression = expressionFunction();
				var returnValue = {
					Else: function(callback){
						callback = callback || nul;
						expression || callback();
					}
				};
				callback = callback || nul;
				expression && callback();
				return returnValue;
			};
		},

		// Ucren.dispatch
		dispatch: function(arg1, arg2, arg3){
			var fn, send, incept;

			if(typeof(arg2) == "undefined"){
				arg2 = [];
			}

			fn = arguments.callee;
			if(!fn.map){
				fn.map = {};
			}

			send = function(processId, args, scope){
				var map, processItems;
				map = fn.map;
				if(processItems = map[processId]){
					Ucren.each(processItems, function(item){
						item.apply(scope, args);
					});
				}
			};

			incept = function(processId, fun){
				var map;
				map = fn.map;
				if(!map[processId]){
					map[processId] = [];
				}
				map[processId].push(fun);
			};

			if(typeof(arg2) == "function"){
				incept.apply(this, arguments);
			}else if(arg2 instanceof Array){
				send.apply(this, arguments);
			}
		},

		// Ucren.each (not recommended)
		each: function(unknown, fn){
			/// unknown 是 array 的，会慢慢退化，建议用 Array.prototype.forEach 替代
			/// unknown 为其它类似的，短期内将暂时支持
			if(unknown instanceof Array || (typeof unknown == "object" &&
				typeof unknown[0] != "undefined" && unknown.length)){
				if(typeof unknown == "object" && Ucren.isSafari)
					unknown = Array.prototype.slice.call(unknown);
//				for(var i = 0, l = unknown.length; i < l; i ++){
//					if(fn(unknown[i], i) === false){
//						break;
//					}
//				}
				unknown.forEach(fn);
			}else if(typeof(unknown) == "object"){
				var blank = {};
				for(var i in unknown){
					if(blank[i]){
						continue;
					}
					if(fn(unknown[i], i) === false){
						break;
					}
				}
			}else if(typeof(unknown) == "number"){
				for(var i = 0; i < unknown; i ++){
					if(fn(i, i) === false){
						break;
					}
				}
			}else if(typeof(unknown) == "string"){
				for(var i = 0, l = unknown.length; i < l; i ++){
					if(fn(unknown.charAt(i), i) === false){
						break;
					}
				}
			}
		},

		// Ucren.Element
		Element: function(el, returnDom){
			var rtn, handleId;
			if(el && el.isUcrenElement){
				return returnDom ? el.dom : el;
			}
			el = typeof(el) == "string" ? document.getElementById(el) : el;

			if(!el)
				return null;

			if(returnDom)
				return el;

			handleId = el.getAttribute("handleId");
			if(typeof handleId == "string"){
				return Ucren.handle(handleId - 0);
			}else{
				rtn = new Ucren.BasicElement(el);
				handleId = Ucren.handle(rtn);
				el.setAttribute("handleId", handleId + "");
				return rtn;
			}
		},

		// Ucren.Event
		Event: function(e){
			e = e || window.event;

			if(!e){
				var c = arguments.callee.caller;
				while(c){
					e = c.arguments[0];
					if(e && typeof(e.altKey) == "boolean"){ // duck typing
						break;
					}
					c = c.caller;
					e = null;
				}
			}

			return e;
		},

		// Ucren.fixNumber
		fixNumber: function(unknown, defaultValue){
			return typeof(unknown) == "number" ? unknown : defaultValue;
		},

		// Ucren.fixString
		fixString: function(unknown, defaultValue){
			return typeof(unknown) == "string" ? unknown : defaultValue;
		},

		// Ucren.fixConfig
		fixConfig: function(conf){
			var defaultConf;
			defaultConf = {};
			if(typeof conf == "undefined"){
				return defaultConf;
			}else if(typeof conf == "function"){
				return new conf;
			}else{
				return conf;
			}
		},

		// Ucren.handle
		handle: function(unknown){
			var fn, type, number;
			fn = arguments.callee;
			if(!fn.cache){
				fn.cache = {};
			}
			if(typeof(fn.number) == "undefined"){
				fn.number = 0;
			}
			type = typeof(unknown);
			if(type == "number"){
				return fn.cache[unknown.toString()];
			}else if(type == "object" || type == "function"){
				number = fn.number ++;
				fn.cache[number.toString()] = unknown;
				return number;
			}
		},

		// Ucren.id
		id: function(){
			var id = arguments.callee;
			id.number = ++ id.number || 0;
			return "_" + id.number;
		},

		// Ucren.loadImage
		loadImage: function(urls, onLoadComplete){
			var length = urls.length;
			var loaded = 0;
			var check = function(){
				if(loaded == length)
					onLoadComplete && onLoadComplete();
			};
			Ucren.each(urls, function(url){
				var img = document.createElement("img");
				img.onload = img.onerror = function(){
					this.onload = this.onerror = null;
					loaded ++;
					check();
				};
				Ucren.tempDom.appendChild(img);
				img.src = url;
			});
		},

		// Ucren.loadScript
		loadScript: function(src, callback){
			Ucren.request(src, function(text){
				eval(text);
				callback && callback(text);
			});
		},

		// Ucren.makeElement
		makeElement: function(tagName, attributes){
			var el = document.createElement(tagName);
			var setStyle = function(unknown){
				if(typeof unknown == "string")
					el.style.cssText = unknown;
				else
					Ucren.apply(unknown, el.style);
			};

			for (var prop in attributes) {
				if (prop === "class")
					el.className = attributes[prop];
				else if (prop === "for")
					el.htmlFor = attributes[prop];
				else if(prop === "style")
					setStyle(attributes[prop]);
				else
					el.setAttribute(prop, attributes[prop]);
			}

			return el;
		},

		// Ucren.nameSpace
		nameSpace: function(path){
			if(typeof(path) == "string"){
				var parts, part, rtn;
				parts = path.split(".");
				rtn = window;
				while(parts.length){
					part = parts.shift();
					if(typeof(rtn[part]) != "object" &&
						typeof(rtn[part]) != "function"){
						rtn[part] = {};
					}
					rtn = rtn[part];
				}
				return rtn;
			}
		},

		// Ucren.nul
		nul: function(){
			return false;
		},

		// Ucren.queryString
		queryString: function(name, sourceString){
			var source, pattern, result;
			source = sourceString || location.href;
			pattern = new RegExp("(\\?|&)" + name + "=([^&#]*)(#|&|$)", "i");
			result = source.match(pattern);
			return result ? result[2] : "";
		},

		// Ucren.randomNumber
		randomNumber: function(num){
			return Math.floor(Math.random() * num);
		},

		// Ucren.randomWord
		randomWord: function(){
			var cw = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
			return function(length, sourceString){
				var words, re = [];
				words = sourceString || cw;
				Ucren.each(length, function(index){
					re[index] = words.charAt(this.randomNumber(words.length));
				}.bind(this));
				return re.join("");
			}
		}(),

		// Ucren.request
		request: function(url, callback){
			request = Ucren.request;
			var xhr = request.xhr;
			if(!request.xhr){
				if(window.XMLHttpRequest){
					xhr = request.xhr = new XMLHttpRequest();
				}else{
					xhr = request.xhr = new ActiveXObject("Microsoft.XMLHTTP");
				}
			}
			xhr.open("GET", url, true);
			xhr.onreadystatechange = function(){
				if(xhr.readyState == 4 && xhr.status == 200){
					callback(xhr.responseText);
				}
			};
			xhr.send(null);
		},

		// Ucren.decodeColor
		decodeColor: function(){
			var r = /^\#?(\w{2})(\w{2})(\w{2})$/;
			var x = function(x){
				return parseInt(x, 16);
			};
			return function(color){
				r.test(color);
				return {
					red: x(RegExp.$1),
					green: x(RegExp.$2),
					blue: x(RegExp.$3)
				};
			}
		}(),

		// Ucren.encodeColor
		encodeColor: function(){
			var x = function(x){
				return x.toString(16).split(".")[0];
			};
			x = x.improve(function(origin, x){
				x = origin(x);
				return x.length == 1 ? "0" + x : x;
			});
			return function(data){
				return ["#", x(data.red), x(data.green), x(data.blue)].join("");
			}
		}()
	};

	//
	// [底层操作类]
	//

	// Ucren.BasicDrag
	Ucren.BasicDrag = Ucren.Class(
		/* constructor */ function(conf){
			conf = Ucren.fixConfig(conf);
			this.type = Ucren.fixString(conf.type, "normal");

			var isTouch = this.isTouch = "ontouchstart" in window;

			this.TOUCH_START = isTouch ? "touchstart" : "mousedown",
			this.TOUCH_MOVE = isTouch ? "touchmove" : "mousemove",
			this.TOUCH_END = isTouch ? "touchend" : "mouseup";
		},

		/* methods */ {
			bind: function(el, handle){
				el = Ucren.Element(el);
				handle = Ucren.Element(handle) || el;

				var evt = {};

				evt[this.TOUCH_START] = function(e){
					e = Ucren.Event(e);
					this.startDrag();
					e.cancelBubble = true;
					e.stopPropagation && e.stopPropagation();
					return e.returnValue = false;
				}.bind(this);

				handle.addEvents(evt);
				this.target = el;
			},

			//private
			getCoors: function(e){
				var coors = [];
				if (e.targetTouches && e.targetTouches.length) { 	// iPhone
					var thisTouch = e.targetTouches[0];
					coors[0] = thisTouch.clientX;
					coors[1] = thisTouch.clientY;
				}else{ 								// all others
					coors[0] = e.clientX;
					coors[1] = e.clientY;
				}
				return coors;
			},

			//private
			startDrag: function(){
				var target, draging, e;
				target = this.target;
				draging = target.draging = {};

				this.isDraging = true;

				draging.x = parseInt(target.style("left"), 10) || 0;
				draging.y = parseInt(target.style("top"), 10) || 0;

				e = Ucren.Event();
				var coors = this.getCoors(e);
				draging.mouseX = coors[0];
				draging.mouseY = coors[1];

				this.registerDocumentEvent();
			},

			//private
			endDrag: function(){
				this.isDraging = false;
				this.unRegisterDocumentEvent();
			},

			//private
			registerDocumentEvent: function(){
				var target, draging;
				target = this.target;
				draging = target.draging;

				draging.documentSelectStart =
					Ucren.addEvent(document, "selectstart", function(e){
						e = e || event;
						e.stopPropagation && e.stopPropagation();
						e.cancelBubble = true;
						return e.returnValue = false;
					});

				draging.documentMouseMove =
					Ucren.addEvent(document, this.TOUCH_MOVE, function(e){
						var ie, nie;
						e = e || event;
						ie = Ucren.isIe && e.button != 1;
						nie = !Ucren.isIe && e.button != 0;
						if((ie || nie) && !this.isTouch)
							this.endDrag();
						var coors = this.getCoors(e);
						draging.newMouseX = coors[0];
						draging.newMouseY = coors[1];
						e.stopPropagation && e.stopPropagation();
						return e.returnValue = false;
					}.bind(this));

				draging.documentMouseUp =
					Ucren.addEvent(document, this.TOUCH_END, function(){
						this.endDrag();
					}.bind(this));

				clearInterval(draging.timer);
				draging.timer = setInterval(function(){
					var x, y, dx, dy;
					if(draging.newMouseX){
						dx = draging.newMouseX - draging.mouseX;
						dy = draging.newMouseY - draging.mouseY;
						x = draging.x + dx;
						y = draging.y + dy;
						if(this.type == "calc"){
							this.returnValue(dx, dy, x, y);
						}else{
							target.left(x).top(y);
						}
					}
				}.bind(this), 10);
			},

			//private
			unRegisterDocumentEvent: function(){
				var draging = this.target.draging;
				Ucren.delEvent(document, this.TOUCH_MOVE, draging.documentMouseMove);
				Ucren.delEvent(document, this.TOUCH_END, draging.documentMouseUp);
				Ucren.delEvent(document, "selectstart", draging.documentSelectStart);
				clearInterval(draging.timer);
			},

			//private
			returnValue: function(dx, dy){
				//todo something
			}
		}
	);

	// Ucren.Template
	Ucren.Template = Ucren.Class(
		/* constructor */ function(){
			this.string = Array.prototype.join.call(arguments, "");
		},

		/* methods */ {
			apply: function(conf){
				return this.string.format(conf);
			}
		}
	);

	// Ucren.BasicElement
	Ucren.BasicElement = Ucren.Class(
		/* constructor */ function(el){
			this.dom = el;
		this.countMapping = {};
		},

		/* methods */ {
			isUcrenElement: true,

			attr: function(name, value){
				if(typeof value == "string"){
					this.dom.setAttribute(name, value);
				}else{
					return this.dom.getAttribute(name);
				}
				return this;
			},

			style: function(/* unknown1, unknown2 */){
				var getStyle = Ucren.isIe ?
					function(name){
						return this.dom.currentStyle[name];
					} :

					function(name){
						var style;
						style = document.defaultView.getComputedStyle(this.dom, null);
						return style.getPropertyValue(name);
					};

				return function(unknown1, unknown2){
					if(typeof unknown1 == "object"){
						Ucren.each(unknown1, function(value, key){
							this[key] = value;
						}.bind(this.dom.style));
					}else if(typeof unknown1 == "string" && typeof unknown2 == "undefined"){
						return getStyle.call(this, unknown1);
					}else if(typeof unknown1 == "string" && typeof unknown2 != "undefined"){
						this.dom.style[unknown1] = unknown2;
					}
					return this;
				};
			}(),

			hasClass: function(name){
				var className = " " + this.dom.className + " ";
				return className.indexOf(" " + name + " ") > -1;
			},

			setClass: function(name){
				if(typeof(name) == "string")
					this.dom.className = name.trim();
				return this;
			},

			addClass: function(name){
				var el, className;
				el = this.dom;
				className = " " + el.className + " ";
				if(className.indexOf(" " + name + " ") == -1){
					className += name;
					className = className.trim();
					className = className.replace(/ +/g, " ");
					el.className = className;
				}
				return this;
			},

			delClass: function(name){
				var el, className;
				el = this.dom;
				className = " " + el.className + " ";
				if(className.indexOf(" " + name + " ") > -1){
					className = className.replace(" " + name + " ", " ");
					className = className.trim();
					className = className.replace(/ +/g, " ");
					el.className = className;
				}
				return this;
			},

			html: function(html){
				var el = this.dom;

				if(typeof html == "string"){
					el.innerHTML = html;
				}else if(html instanceof Array){
					el.innerHTML = html.join("");
				}else{
					return el.innerHTML;
				}
				return this;
			},

			left: function(number){
				var el = this.dom;
				if(typeof(number) == "number"){
					el.style.left = number + "px";
					this.fireEvent("infect", [{ left: number }]);
				}else{
					return this.getPos().x;
				}
				return this;
			},

			top: function(number){
				var el = this.dom;
				if(typeof(number) == "number"){
					el.style.top = number + "px";
					this.fireEvent("infect", [{ top: number }]);
				}else{
					return this.getPos().y;
				}
				return this;
			},

			width: function(unknown){
				var el = this.dom;
				if(typeof unknown == "number"){
					el.style.width = unknown + "px";
					this.fireEvent("infect", [{ width: unknown }]);
				}else if(typeof unknown == "string"){
					el.style.width = unknown;
					this.fireEvent("infect", [{ width: unknown }]);
					}else{
					return this.getSize().width;
					}
					return this;
				},

			height: function(unknown){
					var el = this.dom;
				if(typeof unknown == "number"){
					el.style.height = unknown + "px";
					this.fireEvent("infect", [{ height: unknown }]);
				}else if(typeof unknown == "string"){
					el.style.height = unknown;
					this.fireEvent("infect", [{ height: unknown }]);
					}else{
					return this.getSize().height;
					}
					return this;
				},

			count: function(name){
				return this.countMapping[name] = ++ this.countMapping[name] || 1;
			},

			display: function(bool){
				var dom = this.dom;
				if(typeof(bool) == "boolean"){
					dom.style.display = bool ? "block" : "none";
					this.fireEvent("infect", [{ display: bool }]);
				}else{
					return this.style("display") != "none";
				}
				return this;
			},

			first: function(){
				var c = this.dom.firstChild;
				while(c && !c.tagName && c.nextSibling){
					c = c.nextSibling;
				}
				return c;
			},

			add: function(dom){
				var el;
				el = Ucren.Element(dom);
				this.dom.appendChild(el.dom);
				return this;
			},

			remove: function(dom){
				var el;
				if(dom){
					el = Ucren.Element(dom);
					el.html("");
					this.dom.removeChild(el.dom);
				}else{
					el = Ucren.Element(this.dom.parentNode);
					el.remove(this);
				}
				return this;
			},

			insert: function(dom){
				var tdom;
				tdom = this.dom;
				if(tdom.firstChild){
					tdom.insertBefore(dom, tdom.firstChild);
				}else{
					this.add(dom);
				}
				return this;
			},

			addEvents: function(conf){
				var blank, el, rtn;
				blank = {};
				rtn = {};
				el = this.dom;
				Ucren.each(conf, function(item, key){
					rtn[key] = Ucren.addEvent(el, key, item);
				});
				return rtn;
			},

			removeEvents: function(conf){
				var blank, el;
				blank = {};
				el = this.dom;
				Ucren.each(conf, function(item, key){
					Ucren.delEvent(el, key, item);
				});
				return this;
			},

			getPos: function(){
				var el, parentNode, pos, box, offset;
				el = this.dom;
				pos = {};

				if(el.getBoundingClientRect){
					box = el.getBoundingClientRect();
					offset = Ucren.isIe ? 2 : 0;
					var doc = document;
					var scrollTop = Math.max(doc.documentElement.scrollTop,
						doc.body.scrollTop);
					var scrollLeft = Math.max(doc.documentElement.scrollLeft,
						doc.body.scrollLeft);
					return {
						x: box.left + scrollLeft - offset,
						y: box.top + scrollTop - offset
					};
				}else{
					pos = {
						x: el.offsetLeft,
						y: el.offsetTop
					};
					parentNode = el.offsetParent;
					if(parentNode != el){
						while(parentNode){
							pos.x += parentNode.offsetLeft;
							pos.y += parentNode.offsetTop;
							parentNode = parentNode.offsetParent;
						}
					}
					if(Ucren.isSafari && this.style("position") == "absolute"){ // safari doubles in some cases
						pos.x -= document.body.offsetLeft;
						pos.y -= document.body.offsetTop;
					}
				}

				if(el.parentNode){
					parentNode = el.parentNode;
				}else{
					parentNode = null;
				}

				while(parentNode && parentNode.tagName.toUpperCase() != "BODY" &&
					parentNode.tagName.toUpperCase() != "HTML"){ // account for any scrolled ancestors
					pos.x -= parentNode.scrollLeft;
					pos.y -= parentNode.scrollTop;
					if(parentNode.parentNode){
						parentNode = parentNode.parentNode;
					}else{
						parentNode = null;
					}
				}

				return pos;
			},

			getSize: function(){
				var dom = this.dom;
				var display = this.style("display");

				if (display && display !== "none") {
					return { width: dom.offsetWidth, height: dom.offsetHeight };
					}

				var style = dom.style;
				var originalStyles = {
					visibility: style.visibility,
					position:   style.position,
					display:    style.display
				};

				var newStyles = {
					visibility: "hidden",
					display:    "block"
				};

				if (originalStyles.position !== "fixed")
				  newStyles.position = "absolute";

				this.style(newStyles);

				var dimensions = {
					width:  dom.offsetWidth,
					height: dom.offsetHeight
				};

				this.style(originalStyles);

				return dimensions;
			},

			observe: function(el, fn){
				el = Ucren.Element(el);
				el.on("infect", fn.bind(this));
				return this;
			},

			usePNGbackground: function(image){
				var dom;
				dom = this.dom;
				if(/\.png$/i.test(image) && Ucren.isIe6){
					dom.style.filter =
						"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" +
						image + "',sizingMethod='scale');";
					/// 	_background: none;
					///  _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='images/pic.png',sizingMethod='scale');
				}else{
					dom.style.backgroundImage = "url(" + image + ")";
				}
				return this;
			},

			setAlpha: function(){
				var reOpacity = /alpha\s*\(\s*opacity\s*=\s*([^\)]+)\)/;
				return function(value){
					var element = this.dom, es = element.style;
					if(!Ucren.isIe){
						es.opacity = value / 100;
					/* }else if(es.filter === "string"){ */
					}else{
						if (element.currentStyle && !element.currentStyle.hasLayout)
							es.zoom = 1;

						if (reOpacity.test(es.filter)) {
							value = value >= 99.99 ? "" : ("alpha(opacity=" + value + ")");
							es.filter = es.filter.replace(reOpacity, value);
						} else {
							es.filter += " alpha(opacity=" + value + ")";
						}
					}
					return this;
				};
			}(),

			fadeIn: function(callback){
				if(typeof this.fadingNumber == "undefined")
					this.fadingNumber = 0;
				this.setAlpha(this.fadingNumber);

				var fading = function(){
					this.setAlpha(this.fadingNumber);
					if(this.fadingNumber == 100){
						clearInterval(this.fadingInterval);
						callback && callback();
					}else
						this.fadingNumber += 10;
				}.bind(this);

				this.display(true);
				clearInterval(this.fadingInterval);
				this.fadingInterval = setInterval(fading, Ucren.isIe ? 20 : 30);

				return this;
			},

			fadeOut: function(callback){
				if(typeof this.fadingNumber == "undefined")
					this.fadingNumber = 100;
				this.setAlpha(this.fadingNumber);

				var fading = function(){
					this.setAlpha(this.fadingNumber);
					if(this.fadingNumber == 0){
						clearInterval(this.fadingInterval);
						this.display(false);
						callback && callback();
					}else
						this.fadingNumber -= 10;
				}.bind(this);

				clearInterval(this.fadingInterval);
				this.fadingInterval = setInterval(fading, Ucren.isIe ? 20 : 30);

				return this;
			},

			useMouseAction: function(className, actions){
				/**
				 *  调用示例:  el.useMouseAction("xbutton", "over,out,down,up");
				 *  使用效果:  el 会在 "xbutton xbutton-over","xbutton xbutton-out","xbutton xbutton-down","xbutton xbutton-up"
				 *             等四个 className 中根据相应的鼠标事件来进行切换。
				 *  特别提示:  useMouseAction 可使用不同参数多次调用。
				 */
				if(!this.MouseAction)
					this.MouseAction = new Ucren.MouseAction({ element: this });
				this.MouseAction.use(className, actions);
				return this;
			}
		}
	);

	// Ucren.DataStack
	Ucren.DataStack = Ucren.Class(
		/* constructor */ function(conf){
			conf = Ucren.fixConfig(conf);
			this.fields = conf.fields || [];
			this.records = conf.records || [];
			this.go(0);
		},

		/* methods */ {
			go: function(number){
				this.pointer = Ucren.fixNumber(number, 0);
				this.currentRecord = this.records[this.pointer];
			},

			pos: function(name, value){
				Ucren.each(this.records, function(item, key){
					if(item[name] === value){
						this.go(i);
						return false;
					}
				}.bind(this));
			},

			load: function(records){
				this.records = records || [];
				this.go(0);
			},

			loadFromXml: function(file){
				//todo
			},

			read: function(unknown){
				var type = typeof(unknown);
				switch(type){
					case "number":
						return this.records[unknown];
						break;
					case "string":
						return this.currentRecord[unknown];
						break;
					default:
						return this.currentRecord;
						break;
				}
			},

			append: function(record){
				this.records.push(record);
			},

			insertBefore: function(index, record){
				this.records.splice(index, 0, record);
			},

			del: function(n){
				this.records.splice(n, 1);
				this.go(0);
			},

			edit: function(name, value){
				this.currentRecord[name] = value;
			},

			sortBy: function(name, type){
				type = Ucren.fixString(type, "asc");
				switch(type){
					case "asc":
						this.records.sort(function(a, b){
							return a[name] < b[name] ? -1 : 1;
						});
						break;
					case "desc":
						this.records.sort(function(a, b){
							return a[name] > b[name] ? -1 : 1;
						});
						break;
				}
			},

			count: function(){
				return this.records.length;
			},

			each: function(fn){
				Ucren.each(this.records, fn);
			}
		}
	);

	// Ucren.Timer
	Ucren.Timer = Ucren.Class(
		/* constructor */ function(conf){
			this.time = Ucren.isIe ? conf.time : conf.time * 1.5;
			this.mapping = {};
			this.count = 0;
		},

		/* methods */ {
			add: function(id, fn){
				if(!this.mapping[id])
					this.mapping[id] = fn,
					++ this.count == 1 && this.start();
			},
			remove: function(id){
				if(this.mapping[id])
					delete this.mapping[id],
					-- this.count || this.stop();
			},
			start: function(){
				var callF = function(fn){ fn.call(); };
				var intervalF = function(){ Ucren.each(this.mapping, callF); };
				return function(){
					clearInterval(this.interval);
					this.interval = setInterval(intervalF.bind(this), this.time);
				};
			}(),
			stop: function(){
				clearInterval(this.interval);
			}
		}
	);

	//
	// [基础控件]
	//

	// Ucren.Color
	Ucren.Color = Ucren.Class(
		/* constructor */ function(){},

		/* methods */ {
			setHex: function(value){
				value = Ucren.decodeColor(value);
				this.setRGB(value.red, value.green, value.blue);
				return this;
			},

			getHex: function(){
				return Ucren.encodeColor(this.getRGB());
			},

			setRGB: function(red, green, blue){
				red = Math.min(255, Math.max(0, red));
				green = Math.min(255, Math.max(0, green));
				blue = Math.min(255, Math.max(0, blue));
				this.update((red << 16) | (green << 8 ) | blue);
				return this;
			},

			getRGB: function(){
				return {
					red: this.value >> 16 & 0xFF,
					green: this.value >> 8 & 0xFF,
					blue: this.value & 0xFF
				}
			},

			setHSB: function(hue, sat, bri){
				var rgbInfo = Ucren.Color.HSB2RGB(hue, sat, bri);
				this.setRGB(rgbInfo.red, rgbInfo.green, rgbInfo.blue);
				return this;
			},

			getHSB: function(){
				var rgbInfo = this.getRGB();
				return Ucren.Color.RGB2HSB(rgbInfo.red, rgbInfo.green, rgbInfo.blue);
			},

			transTo: function(targetColor, percent){
				targetColor = (new Ucren.Color).setHex(targetColor);
				var thiz, that, dr, rg, rb;
				thiz = this.getRGB();
				that = targetColor.getRGB();
				return Ucren.encodeColor({
					red: thiz.red + (that.red - thiz.red) * percent,
					green: thiz.green + (that.green - thiz.green) * percent,
					blue: thiz.blue + (that.blue - thiz.blue) * percent
				});
			},

			//privates
			update: function(value){
				this.value = value;
			}
		}
	);

	//private Ucren.Color.HSB2RGB
	Ucren.Color.HSB2RGB = function(hue, sat, bri) {
		hue = hue < 0 ? hue % 360 + 360 : hue >= 360 ? hue % 360 : hue;
		sat = sat < 0 ? 0 : sat > 100 ? 100 : sat;
		bri = bri < 0 ? 0 : bri > 100 ? 100 : bri;

		sat *= 0.01;
		bri *= 0.01;

		if(sat == 0){
			var val = bri * 255;
			return {
				red: val,
				green: val,
				blue: val
			};
		}

		var max = bri * 255;
		var min = max * (1 - sat);
		return this._hMinMax2RGB(hue, min, max);
    };

	//private Ucren.Color.RGB2HSB
	Ucren.Color.RGB2HSB = function(red, green, blue) {
        red = (red < 0)? 0 : (red > 255) ? 255 : Math.round(red);
        green = (green < 0) ? 0 : (green > 255) ? 255 : Math.round(green);
        blue = (blue < 0) ? 0 : (b > 255) ? 255 : Math.round(blue);

        var min = Math.min(red, green, blue);
        var max = Math.max(red, green, blue);
        var sat;

        if(max == 0){
            return {
				hue: 0,
				sat: 0,
				bri: 0
			}
        }else{
            sat = (max - min) / max * 100;
        }

        var bri = max / 255 * 100;

        var hue = this._getHue(red, green, blue, max, min);
        return {
			hue: hue,
			sat: sat,
			bri: bri
		}
    },

	//private Ucren.Color._hMinMax2RGB
	Ucren.Color._hMinMax2RGB = function(h, min, max) {
		var r,g,b;
		var area = Math.floor(h / 60);

		switch (area) {
			case 0:
				r = max;
				//0 - 0, 60-255
				g = min+h * (max-min)/ 60;
				b = min;
				break;
			case 1:
				r = max - (h - 60) * (max - min) / 60;
				g = max;
				b = min;
				break;
			case 2:
				r = min;
				g = max;
				b = min + (h - 120) * (max - min) / 60;
				break;
			case 3:
				r = min;
				g = max - (h - 180) * (max - min) / 60;
				b = max;
				break;
			case 4:
				r = min + (h - 240) * (max - min) / 60;
				g = min;
				b = max;
				break;
			case 5:
				r = max;
				g = min;
				b = max - (h - 300) * (max - min) / 60;
				break;
			case 6:
				r = max;
				//0 - 0, 60-255
				g = min + h  * (max - min) / 60;
				b = min;
				break;
		}

		r = Math.min(255, Math.max(0, Math.round(r)));
		g = Math.min(255, Math.max(0, Math.round(g)));
		b = Math.min(255, Math.max(0, Math.round(b)));

		return {
			red: r,
			green: g,
			blue: b
		};
    };

	//private Ucren.Color._getHue
	Ucren.Color._getHue = function(red, green, blue, max, min) {
		var range = max - min;
		if(range == 0)
			return 0;

		var rr = (max - red);
		var gg = (max - green);
		var bb = (max - blue);

		var h;
		switch(max){
			case red:
				h = bb - gg;
				break;
			case green:
				h = 2 * range + rr - bb;
				break;
			case blue:
				h = 4 * range + gg - rr;
				break;
		}

		h *= -60;
		h /= range;
		h = h < 0 ? h + 360 : h;

		return h;
    };

	// Ucren.ColorTheme (颜色组)
	Ucren.ColorTheme = Ucren.Class(
		/* constructor */ function(conf){
			/// colors mapping:
			/// e.g. { bg1: "#xxx", bg2: "#xxx", ft1: "#xxx", text: "#xxx" }
			this.reference = conf.reference || {};
			this.colors = Ucren.apply(this.reference, {});
		},

		/* methods */ {
			adjustColor: function(colorKey, colorValue){
				/// e.g. adjustColor("bg2", "#xxx")
				var thizColorHSBInfo = (new Ucren.Color).setHex(this.reference[colorKey]).getHSB();
				var targetColorHSBInfo = (new Ucren.Color).setHex(colorValue).getHSB();
				var diffH = targetColorHSBInfo.hue - thizColorHSBInfo.hue;
				var diffS = targetColorHSBInfo.sat - thizColorHSBInfo.sat;
				var diffB = targetColorHSBInfo.bri - thizColorHSBInfo.bri;
				this.update(diffH, diffS, diffB);
			},

			getColor: function(colorKey){
				return this.colors;
			},

			//privates
			update: function(diffH, diffS, diffB){
				Ucren.each(this.colors, function(color, key){
					var c = (new Ucren.Color).setHex(colorValue);
					var ohsb = c.getHSB();
					c.setHSB(ohsb.hue + diffH, ohsb.sat + diffS, ohsb.bri + diffB);
					this[key] = c.getHex();
				}.bind(this.colors));
			}
		}
	);

	/*
	.ucrenlite-basicslippage-layer{
		overflow: hidden;
		line-height: 0;
	}
	.ucrenlite-basicslippage-inner{
		text-decoration: none;
		text-align: center;
		font-size: 14px;
		display: block;
	}
	*/

	// Ucren.BasicSlippage
	Ucren.BasicSlippage = Ucren.Class(
		/* constructor */ function(conf){
			conf = Ucren.fixConfig(conf);
			this.container = Ucren.Element(conf.container);
			this.width = Ucren.fixNumber(conf.width, 16);
			this.height = Ucren.fixNumber(conf.height, 16);
			this.image = conf.image;
			this.length = Ucren.fixNumber(conf.length, 1);
			this.direction = Ucren.fixString(conf.direction, "vertical");
			this.position =
			this.defaultPosition = Ucren.fixNumber(conf.defaultPosition, 0);
			this.reviseOffset = Ucren.fixNumber(conf.reviseOffset, 0);

			this.loadingBackgroundColor = Ucren.fixString(conf.loadingBackgroundColor, "");
			this.loadingColor = Ucren.fixString(conf.loadingColor, "");
			this.loadingText = Ucren.fixString(conf.loadingText, "");

			this.enableAnimation = !! conf.enableAnimation;
			this.animationInterval = Ucren.fixNumber(conf.animationInterval, 100);

			this.isVertical = this.direction == "vertical";
			this.isHorizontal = this.direction == "horizontal";
		},

		/* methods */ {
			render: function(){
				var html, innerWidth, innerHeight;
				this.layerId = Ucren.id();
				this.innerId = Ucren.id();
				if(this.isVertical){
					innerWidth = this.width;
					innerHeight = this.height * this.length;
				}else if(this.isHorizontal){
					innerWidth = this.width * this.length;
					innerHeight = this.height;
				}
				html = Ucren.BasicSlippage.template.apply({
					layerId: this.layerId,
					innerId: this.innerId,
					width: this.width,
					height: this.height,
					innerWidth: innerWidth,
					innerHeight: innerHeight,
					loadingText: this.loadingText
				});
				this.container.html(html);
				this.layer = Ucren.Element(this.layerId);
				this.inner = Ucren.Element(this.innerId);
				this.change(this.defaultPosition);
				this.offset();

				var innerStyle = this.inner.dom.style;
					innerStyle.backgroundColor = this.loadingBackgroundColor;
					innerStyle.color = this.loadingColor;
					innerStyle.lineHeight = this.height + "px";

				this.inner.html(this.loadingText);

				Ucren.loadImage([this.image], function(){
					this.inner.dom.style.backgroundColor = "";
					this.inner.html("");
					this.inner.usePNGbackground(this.image);
				}.bind(this));

				if(this.enableAnimation){
					this.disposeAnimation();
				}
			},

			change: function(number){
				var style;
				style = this.inner.dom.style;
				number = Ucren.fixNumber(number, 0);
				this.position = number;
				if(this.isVertical){
					style.marginTop = - this.height * number + "px";
				}else if(this.isHorizontal){
					style.marginLeft = - this.width * number + "px";
				}
			},

			animationTo: function(number){
				var timer;
				number = Ucren.fixNumber(number, 0);
				timer = this.timer;
				timer.stop();
				this.targetPosition = number;
				timer.start();
			},

			//private
			offset: function(){
				if(!this.reviseOffset){
					return false;
				}
				if(this.isVertical){
					this.inner.width(this.width * (this.reviseOffset + 1));
				}else if(this.isHorizontal){
					this.inner.height(this.height * (this.reviseOffset + 1));
				}
				this.reverseDirection();
				this.change(this.reviseOffset);
				this.reverseDirection();
			},

			//private
			reverseDirection: function(){
				this.isVertical = !this.isVertical;
				this.isHorizontal = !this.isHorizontal;
			},

			//private
			disposeAnimation: function(){
				var timer =
				this.timer = new Ucren.Timer({
					time: this.animationInterval });
				this.targetPosition = 0;
				timer.add(Ucren.id(), function(){
					var position;
					if(this.position < this.targetPosition){
						position = this.position + 1;
					}else if(this.position > this.targetPosition){
						position = this.position - 1;
					}else{
						return this.timer.stop();
					}
					this.change(position);
				}.bind(this));
			}
		}
	);

	Ucren.BasicSlippage.template = new Ucren.Template(
		"<div id='@{layerId}' class='ucrenlite-basicslippage-layer' ",
		"style='width: @{width}px; height: @{height}px;'>",
			"<a id='@{innerId}' class='ucrenlite-basicslippage-inner' href='ucren:' onclick='return false;' hidefocus='hidefocus' onfocus='this.blur();' ",
			"style='width: @{innerWidth}px; height: @{innerHeight}px;'>",
				"@{loadingText}",
			"</a>",
		"</div>");

	// Ucren.MouseAction (for Ucren.BasicElement)
	Ucren.MouseAction = Ucren.Class(
		/* constructor */ function(conf){
			conf = Ucren.fixConfig(conf);
			this.element = Ucren.Element(conf.element);
			this.setup();
		},

		/* methods */ {
			use: function(className, actions){
				this.className = className;

				this.actions = {};
				if(actions){
					Ucren.each(actions.split(","), function(value){
						this[value] = true;
					}.bind(this.actions));
				}

				this.element.setClass(this.className);
				if(this.lastActionName)
					this.actionEvents["mouse" + this.lastActionName]();
			},

			//private
			setup: function(){
				var actionEvent = function(actionName){
					return function(){
						if(this.actions[actionName]){
							if(actionName == "out"){
								this.element.setClass(this.className);
							}else{
								if(actionName == "up")
									actionName = "over";
								this.element.setClass(this.className + " " +
									this.className + "-" + actionName);
							}
						}
						this.lastActionName = actionName;
					};
				};

				this.actionEvents = {
					mouseover: actionEvent("over").bind(this),
					mouseout: actionEvent("out").bind(this),
					mousedown: actionEvent("down").bind(this),
					mouseup: actionEvent("up").bind(this)
				};
				this.element.addEvents(this.actionEvents);
			}
		}
	);

	// Ucren.queryElement
	Ucren.queryElement = function(){

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

		[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 = Sizzle.isXML(context),
				soFar = selector, ret, cur, pop, i;

			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 {
				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 && Sizzle.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] && Sizzle.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;
						}
					}
				}

				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"){
						var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
							match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
							!/\D/.test(match[2]) && "0n+" + match[2] || match[2]);
						match[2] = (test[1] + (test[2] || 1)) - 0;
						match[3] = test[3] - 0;
					}

					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((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){
					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 || Sizzle.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;
		};

		try {
			Array.prototype.slice.call(document.documentElement.childNodes, 0)[0].nodeType;
		} 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;
			};
		}

		Sizzle.getText = function(elems){
			var ret = "", elem;

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

				if(elem.nodeType === 3 || elem.nodeType === 4){
					ret += elem.nodeValue;

				} else if(elem.nodeType !== 8){
					ret += Sizzle.getText(elem.childNodes);
				}
			}

			return ret;
		};

		(function(){
			var form = document.createElement("div"),
				id = "script" + (new Date()).getTime();
			form.innerHTML = "<a name='" + id + "'/>";

			var root = document.documentElement;
			root.insertBefore(form, root.firstChild);

			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(){
			var div = document.createElement("div");
			div.appendChild(document.createComment(""));

			if(div.getElementsByTagName("*").length > 0){
				Expr.find.TAG = function(match, context){
					var results = context.getElementsByTagName(match[1]);

					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;
				};
			}

			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>";

				if(div.querySelectorAll && div.querySelectorAll(".TEST").length === 0){
					return;
				}

				Sizzle = function(query, context, extra, seed){
					context = context || document;

					if(!seed && context.nodeType === 9 && !Sizzle.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>";

			if(!div.getElementsByClassName || div.getElementsByClassName("e").length === 0){
				return;
			}

			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;
				}
			}
		}

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

		Sizzle.isXML = function(elem){
			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;

			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);
		};

		return Sizzle;
	}();


	// Ucren.initialize
	//Ucren.initialize = function(){
	//	var encode = function(str){W
	//		var re = "", c, lc = 0;
	//		Ucren.each(str, function(value){
	//			c = value.charCodeAt(0);
	//			re += Math.abs(lc - c);
	//			lc = c;
	//		});
	//		return re;
	//	};
	//
	//	var nul = function(){
	//		// todo
	//	};
	//
	//	var obj = {};
	//
	//	if(encode(location.href).indexOf("18151396453122") == -1){
	//		Ucren.each(Ucren, function(value, key){
	//			switch(typeof(value)){
	//				case "function":
	//					Ucren[key] = nul;
	//					break;
	//				case "object":
	//					Ucren[key] = obj;
	//					break;
	//				case "number":
	//					Ucren[key] = 0;
	//					break;
	//				case "string":
	//					Ucren[key] = "";
	//					break;
	//			}
	//		});
	//	}
	//}();

	//
	// [数据操作相关]
	//

	// Ucren.JSON
	Ucren.JSON = new function(){
		var useHasOwn = {}.hasOwnProperty ? true : false;

		var pad = function(n) {
			return n < 10 ? "0" + n : n;
		};

		var m = {
			"\b": '\\b',
			"\t": '\\t',
			"\n": '\\n',
			"\f": '\\f',
			"\r": '\\r',
			'"' : '\\"',
			"\\": '\\\\'
		};

		var encodeString = function(s){
			if(/[\"\\\x00-\x1f]/.test(s)) {
				return '"' + s.replace(/([\x00-\x1f\\\"])/g, function(a, b) {
					var c = m[b];
					if(c){
						return c;
					}
					c = b.charCodeAt();
					return "\\u00" +
						Math.floor(c / 16).toString(16) +
						(c % 16).toString(16);
				}) + '"';
			}
			return '"' + s + '"';
		};

		var encodeArray = function(o){
			var a = ["["], b, i, l = o.length, v;
				for(i = 0; i < l; i += 1) {
					v = o[i];
					switch (typeof v) {
						case "undefined":
						case "function":
						case "unknown":
							break;
						default:
							if(b) {
								a.push(',');
							}
							a.push(v === null ? "null" : Ucren.JSON.encode(v));
							b = true;
					}
				}
				a.push("]");
				return a.join("");
		};

		var encodeDate = function(o){
			return '"' + o.getFullYear() + "-" +
					pad(o.getMonth() + 1) + "-" +
					pad(o.getDate()) + "T" +
					pad(o.getHours()) + ":" +
					pad(o.getMinutes()) + ":" +
					pad(o.getSeconds()) + '"';
		};

		this.encode = function(o){
			if(typeof o == "undefined" || o === null){
				return "null";
			}else if(o instanceof Array){
				return encodeArray(o);
			}else if(o instanceof Date){
				return encodeDate(o);
			}else if(typeof o == "string"){
				return encodeString(o);
			}else if(typeof o == "number"){
				return isFinite(o) ? String(o) : "null";
			}else if(typeof o == "boolean"){
				return String(o);
			}else {
				var a = ["{"], b, i, v;
				for(i in o) {
					if(!useHasOwn || o.hasOwnProperty(i)) {
						v = o[i];
						switch (typeof v) {
						case "undefined":
						case "function":
						case "unknown":
							break;
						default:
							if(b){
								a.push(',');
							}
							a.push(this.encode(i), ":",
									v === null ? "null" : this.encode(v));
							b = true;
						}
					}
				}
				a.push("}");
				return a.join("");
			}
		};

		this.decode = function(json){
			return eval("(" + json + ')');
		};
	};

	if(Ucren.isIe)
		document.execCommand("BackgroundImageCache", false, true);

	window.Ucren = Ucren;

	for(var i in Ucren){
	    exports[i] = Ucren[i];
	};return exports});define("scripts/modules/detail/main.js",function(exports){exports={};var loading = require("scripts/modules/loading/main");
var page = require("scripts/modules/page/main");
var Ucren = require("scripts/libs/ucren"), E = Ucren.Element, Q = Ucren.queryElement;
var data, albumName, showAnimTimer, movePhotoTimer;
var closeBtn, onClose, currentIndex;
var animing = false;
var imageCache = {};

var imgViewer = E("imgviewer");
var photoDetailCont = E("photo-detail-cont"), photoDetailContClone;
var photoDetailContParent = photoDetailCont.dom.parentNode;
var closeBtnCont = E("detail-close-btn");

var prevTrigger = E("prev-trigger");
var nextTrigger = E("next-trigger");
var prevArrow = E("prev-arrow");
var nextArrow = E("next-arrow");
var prevPhoto = E("prev-photo");
var prevPhotoImage = E(Q("div", prevPhoto.dom)[0]);
var nextPhoto = E("next-photo");
var nextPhotoImage = E(Q("div", nextPhoto.dom)[0]);
var detailHk = E("detail-hk");

var exponential = function(index, offset, target, framesNum){
	if(index == 0)
		return offset;
	else if(index == framesNum)
		return offset + target;
	else if((index /= framesNum / 2) < 1)
		return target / 2 * Math.pow(2, 10 * (index - 1)) + offset;
	else
		return target / 2 * (-Math.pow(2, -10 * -- index) + 2) + offset;
};

var yPercent = .5, hPercentPerPx = 0, screenWidth = 10000, screenHeight = 10000;
var lastXPercent =.5;

var imgViewerResetMousePos = function(){
	var lastX = 0, lastY = 0;
	return function(x, y){
		if(lastX == x && lastY == y)return ;
		if(imageScroller.curPX)imageScroller.curPX = 0;
		lastX = x;
		lastY = y;
		var sh = screenHeight - 90;
		y -= 45;
		y = y < 0 ? 0 : y > sh ? sh : y;
	    yPercent = y / sh;
	}  
}();

var cloneViewer = function(){
   	photoDetailContClone = photoDetailCont.dom.cloneNode(true);
	photoDetailContClone.id = "";
	photoDetailContClone.className = "photo-detail-cont-clone";
	photoDetailContClone.removeAttribute("handleId");
	photoDetailContParent.insertBefore(photoDetailContClone, photoDetailCont.dom);
	photoDetailContClone.scrollTop = photoDetailCont.dom.scrollTop;
	photoDetailContClone = E(photoDetailContClone);
}

var initViewer = function(w, h){
    imgViewer.setAlpha(0);
    // imgViewer.display(false);
    imgViewer.width(w || 0).height(h || 0);
	yPercent = .5;

    if(h < screenHeight){
    	imgViewer.style("marginTop", (screenHeight - h - 10) / 2 + "px");    
    	clearInterval(movePhotoTimer);
    	hPercentPerPx = 0;
    	photoDetailCont.dom.scrollTop = 0;
    }else{
        imgViewer.style("marginTop", "40px");
        startMoveEvent(h);
        hPercentPerPx = 1 / (h + 10);
        photoDetailCont.dom.scrollTop = Math.round((h + 90 - screenHeight) * yPercent);
    }
};

var showSrc = function(src){
	animing = true;
	// imgViewer.display(true);
    imgViewer.style("backgroundImage", "url(" + src + ")");
    var alpha = 0;
    clearInterval(showAnimTimer);
    showAnimTimer = setInterval(function(){
    	photoDetailContClone && photoDetailContClone.setAlpha(100 - alpha);
        imgViewer.setAlpha(alpha);
        if(alpha < 100){
        	alpha += 4;
        }else{
        	animing = false;
        	clearInterval(showAnimTimer);
        	photoDetailContClone && photoDetailContParent.removeChild(photoDetailContClone.dom);
        	photoDetailContClone = null;
        }
    }, Ucren.isIe ? 16 : 24);
};

var close = function(){
	if(close.locked)return ;
	close.locked = true;
	hideOut(function(){
		clearInterval(movePhotoTimer);
		clearInterval(showAnimTimer);
		close.locked = false;
	    onClose && onClose(currentIndex);
	});
};

var hideOut = function(callback){
	var alpha = 100;
	var timer = setInterval(function(){
	    imgViewer.setAlpha(alpha);
	    if(alpha > 0){
	        alpha -= 10;
	    }else{
	    	animing = false;
	        clearInterval(timer);
	        callback && callback();
	    }
	}, Ucren.isIe ? 20 : 30);
};

var startMoveEvent = function(imgHeight){
	clearInterval(movePhotoTimer);
	movePhotoTimer = setInterval(function(){
		if(imageScroller.curPX){
			yPercent += imageScroller.curPX * hPercentPerPx;
			yPercent = yPercent > 1 ? 1 : yPercent < 0 ? 0 : yPercent;
			if(yPercent == 0 || yPercent == 1)
				imageScroller.curPX = 0;
		}

		var oldScrollTop = photoDetailCont.dom.scrollTop;
	    var scrollTop = Math.round((imgHeight + 90 - screenHeight) * yPercent);
	    if(Math.abs(scrollTop - oldScrollTop) < 2)
	    	scrollTop = oldScrollTop;
	    if(scrollTop != oldScrollTop)
	    	photoDetailCont.dom.scrollTop += Math.ceil((scrollTop -  oldScrollTop) / 7.5);
	}, Ucren.isIe ? 16 : 24);
};

// 上一张、下一张动画工具函数
var nearbyMover = {
	prevPhotoShow: function(){
	    clearInterval(this.prevTimer);
	    this.prevTimer = setInterval(function(){
	    	if(this.prevPhotoIndex < this.framesNum)
	    	    this.prevPhotoIndex ++;
	    	else
	    	    clearInterval(this.prevTimer);
	    	this.updatePrevPhotoX();
	    }.bind(this), Ucren.isIe ? 20 : 30);
	},

	prevPhotoHide: function(){
	    clearInterval(this.prevTimer);
	    this.prevTimer = setInterval(function(){
	    	if(this.prevPhotoIndex > 0)
	    	    this.prevPhotoIndex --;
	    	else
	    	    clearInterval(this.prevTimer);
	        this.updatePrevPhotoX();
	    }.bind(this), Ucren.isIe ? 20 : 30);
	},

	nextPhotoShow: function(){
	    clearInterval(this.nextTimer);
	    this.nextTimer = setInterval(function(){
	    	if(this.nextPhotoIndex < this.framesNum)
	    	    this.nextPhotoIndex ++;
	    	else
	    	    clearInterval(this.nextTimer);
	    	this.updateNextPhotoX();
	    }.bind(this), Ucren.isIe ? 20 : 30);
	},

	nextPhotoHide: function(){
	    clearInterval(this.nextTimer);
	    this.nextTimer = setInterval(function(){
	    	if(this.nextPhotoIndex > 0)
	    	    this.nextPhotoIndex --;
	    	else
	    	    clearInterval(this.nextTimer);
	        this.updateNextPhotoX();
	    }.bind(this), Ucren.isIe ? 20 : 30);
	},

	// privates
	framesNum: 24,

	photoX: [-127, 20],
	arrowX: [40, 60],
			
	prevPhotoIndex: 0,
	nextPhotoIndex: 0,

	updatePrevPhotoX: function(){
        var photoX = this.getPhotoIndexByIndex(this.photoX, this.prevPhotoIndex);
        var arrowX = this.getPhotoIndexByIndex(this.arrowX, this.prevPhotoIndex);
        prevPhoto.left(photoX);
        prevArrow.left(arrowX);
	},

	updateNextPhotoX: function(){
        var photoX = this.getPhotoIndexByIndex(this.photoX, this.nextPhotoIndex);
        var arrowX = this.getPhotoIndexByIndex(this.arrowX, this.nextPhotoIndex);
        nextPhoto.style("right", photoX + "px");
        nextArrow.style("right", arrowX + "px");
	},

	getPhotoIndexByIndex: function(Xs, index){
	    return exponential(index, Xs[0], Xs[1] - Xs[0], this.framesNum);
	}
};

// 上下键滚动工具函数
var imageScroller = {
	// 按向上键
	upKeydown: function(){
		var me = this;
		if(me.curPX == 0)
			me.curPX = -me.firstStep;
        else if(me.curPX > -me.speedLimit)
            me.curPX -= me.stepPX;
	},

	// 按向下键
	downKeydown: function(){
		var me = this;
		if(me.curPX == 0)
		    me.curPX = me.firstStep;
        else if(me.curPX < me.speedLimit)
            me.curPX += me.stepPX;
	},

	// 松按键
	keyup: function(){
		var me = this;
		clearInterval(this.keyup.timer);
		this.keyup.timer = setInterval(function(){
		    if(me.curPX != 0)
		       	me.curPX -= me.curPX > 0 ? me.stepPX : -me.stepPX;
		    else
		        clearInterval(me.keyup.timer);
		}, 30);
	},

	// privates
	curPX: 0, /* px */
	stepPX: 10, /* px */
	firstStep: 50, /* px */
	speedLimit: 120 /* px */
};

exports.isCached = function(index){
	return !! imageCache["store/albums/" + albumName + "/images/" + data[index].src];
},

exports.setAlbumData = function(d){
	data = d;  
};

exports.setAlbumName = function(name){
	albumName = name;    
};

exports.showIndex = function(index, callback){
	var item = data[index];
	var src = "store/albums/" + albumName + "/images/" + item.src;
	currentIndex = index;
	initViewer(item.width, item.height);

	if(index == 0){
	    prevArrow.display(false);
	    nearbyMover.prevPhotoHide();
	}else{
	    prevArrow.display(true);
	    prevPhotoImage.style("backgroundImage", "url(store/albums/" + albumName + "/thumbnails/" + data[index - 1].src + ")");
	}

	if(index >= data.length - 1){
	    nextArrow.display(false);
	    nearbyMover.nextPhotoHide();
	}else{
	    nextArrow.display(true);
	    nextPhotoImage.style("backgroundImage", "url(store/albums/" + albumName + "/thumbnails/" + data[index + 1].src + ")");
	}

	Ucren.loadImage([src], function(){
		imageCache[src] = true;
		showSrc(src);
		callback && callback();
	});

	setTimeout(function(){
	    detailHk.dom.focus();
	}, 20);
};

exports.render = function(){
    closeBtn = new Ucren.BasicSlippage({
    	container: closeBtnCont,
    	width: 40, height: 40,
    	image: "images/close-btn.png",
    	length: 2
    });
    closeBtn.render();
    this.defineEvent();
};

exports.defineEvent = function(){
	var goPhoto = function(addIndex){
		if(loading.inworking || animing)return ;
		var index = currentIndex + addIndex;
		if(index < 0 || index > data.length - 1)return ;
		
		exports.isCached(index) || loading.show("正在打开照片");
    	
    	cloneViewer();
    	exports.showIndex(index, loading.hide.bind(loading));
	};

    closeBtnCont.addEvents({
    	click: close,
    	mouseover: function(){ closeBtn.change(1); },
    	mouseout: function(){ closeBtn.change(0); }
    });
    imgViewer.addEvents({
    	mousemove: function(e){
    	    e = Ucren.Event(e);
    	    imgViewerResetMousePos(e.clientX, e.clientY);
    	}
    });
    photoDetailCont.observe(photoDetailCont, function(conf){
    	if(conf.width)
    		screenWidth = conf.width;
        if(conf.height)
        	screenHeight = conf.height;
    });

    prevTrigger.addEvents({
    	mouseover: function(){
    		if(currentIndex > 0)
    	    	nearbyMover.prevPhotoShow();
    	},
    	mouseout: function(){
    		nearbyMover.prevPhotoHide();
    	},
    	mouseup: function(){
    	   	goPhoto(-1);
    	}
    });

    nextTrigger.addEvents({
    	mouseover: function(){
    		if(currentIndex < data.length - 1)
    	    	nearbyMover.nextPhotoShow();
    	},
    	mouseout: function(){
    		nearbyMover.nextPhotoHide();
    	},
    	mouseup: function(){
    	    goPhoto(1);
    	}
    });

    var lockedUpNDown = false;

    Ucren.addEvent(document, "keydown", function(e){
    	if(page.pageName != "detail-page")return ;
	    e = Ucren.Event(e);
	    switch(e.keyCode){
	        case 27: // ESC
	        case 8: // BackSpace
	        	close();
	        	break;
	        case 38: // up
        	    lockedUpNDown = true;
	        	imageScroller.upKeydown();
	        	break;
	        case 40: // down
        	    lockedUpNDown = true;
	        	imageScroller.downKeydown();
	            break;
	        case 37: // left
	        	goPhoto(-1);
	        	break;
	        case 39: // right
	    		goPhoto(1);
	    		break;
	    	case 33: // PgUp
	    		yPercent = 0;
	    		break;
	    	case 34: // PgDn
	    	    yPercent = 1;
	    	    break; 
	    }
		e.cancelBubble = true;
		e.stopPropagation && e.stopPropagation();
		return e.returnValue = false;
    });

    Ucren.addEvent(document, "keyup", function(e){
    	if(page.pageName != "detail-page")return ;
	    e = Ucren.Event(e);
	    switch(e.keyCode){
	        case 38:
	        case 40: // 在 opera 下，keycode=40 的 keyup 事件获取不到
	            lockedUpNDown = false;
	            imageScroller.keyup();
	            break;	    	        	
	    }
	});
};

exports.onClose = function(callback){
    onClose = callback;
};;return exports});define("scripts/modules/list/main.js",function(exports){exports={};var Ucren = require("scripts/libs/ucren");
var testUrl = "";

var page = Ucren.Element("page");

var mousedownId = null;
var currentItemId = null;
var cellSize = 1, rowSize = 1, rowSize2 = 1, dataLength = 0;
var handleId = Ucren.handle(exports);
var idPrefix = "";
var keydownLock = false;
var keydownLockTimeout = 40;
var dblclickCallback;
var iconSize = 124;

var template = new Ucren.Template(
	"<div id='@{id}' index='@{index}' aid='@{aId}' class='item' itemContainer='true'>",
		"<div class='icon'>",
			"<div id='@{bId}' class='border' handleEvent='true' thumbnail='@{thumbnail}'></div></div>",
		"<div class='name' handleEvent='true'><a id='@{aId}' href='' onclick='return false;' handleEvent='true' onblur='Ucren.handle(@{handleId}).onblur(\"@{id}\");' onkeydown='Ucren.handle(@{handleId}).onkeydown(\"@{id}\");return false;'>@{name}</a></div>",
	"</div>");

var showPartThumbnail = function(){
    var container = exports.container;
    var startIndex = Math.floor(container.dom.scrollTop / iconSize) * cellSize;
    var indexNumber = cellSize * rowSize2;
    for(var i = startIndex, thumbnail; i < startIndex + indexNumber; i ++){
    	var el = document.getElementById(idPrefix + "_b" + i);
    	if(!el)break;
    	if(thumbnail = el.getAttribute("thumbnail")){
    	    el.style.backgroundImage = "url(" + thumbnail + ")";
    	    el.setAttribute("thumbnail", "");
    	}
    }
};

var formatThumbnailUrl = function(id, name){
	return id.replace(/[^/]+\.js$/, "thumbnails/" + name);
};

var getItem = function(el){
	el = Ucren.Element(el, true);
	var node = el.parentNode;
	while(!node.getAttribute("itemContainer"))
		node = node.parentNode;
	return Ucren.Element(node);
};

var selectItem = function(dom, isMouseDown){
	var itemEl = Ucren.Element(dom);
	if(!itemEl)return ;

	var id = itemEl.dom.id;
	var aId = itemEl.attr("aId");

	itemEl.addClass("selected");

	var lastEl;
	if(currentItemId){
	    lastEl = Ucren.Element(currentItemId);
	    if(lastEl && lastEl != itemEl)
	        lastEl.delClass("selected");
	}

	setTimeout(function(){
	    Ucren.Element(aId, true).focus();
	    setTimeout(function(){
	        currentItemId = id;
	        mousedownId = null;
	    }, 10);
	}, 10);

	return itemEl;
};

var viewItem = function(dom){
	var itemEl = Ucren.Element(dom);
	if(!itemEl)return ;
	dblclickCallback && dblclickCallback(+ itemEl.attr("index"));
};

var unSelect = function(){
	var lastEl;
	if(currentItemId && (lastEl = Ucren.Element(currentItemId)))
	    lastEl.delClass("selected");
};

var defineEvent = function(el){
    el.addEvents({
    	mousedown: function(e){
    		e = Ucren.Event(e);
    	    var target = e.target || e.srcElement;
    	    mousedownId = null;
    	    if(!target.getAttribute("handleEvent"))
    	        return false;
			var itemEl = getItem(target);
			mousedownId = itemEl.dom.id;
			selectItem(itemEl, true);
			return false;
    	},
    	
    	dblclick: function(e){
    		e = Ucren.Event(e);
    	    var target = e.target || e.srcElement;
    	    if(!target.getAttribute("handleEvent"))
    	        return false;
			var itemEl = getItem(target);
			viewItem(itemEl, true);
			return false;
    	}
    });
};

var getPositionByIndex = function(index){
    return {
    	rowIndex: Math.floor(index / cellSize),
    	cellIndex: index % cellSize
    };
};

exports.render = function(el){
	this.container = el = Ucren.Element(el);
	el.addClass("clearfix");
	defineEvent(el);

	this.container.on("infect", function(conf){
	    if(conf.width){
	    	cellSize = Math.floor((conf.width - 20) / iconSize);
	    	rowSize = Math.ceil(dataLength / cellSize);
	    }
	    if(conf.height){
	        rowSize2 = Math.ceil(conf.height / iconSize);
	    }
	    showPartThumbnail();
	});

	this.container.addEvents({
		scroll: showPartThumbnail
	});
};

exports.setData = function(id, data){
	idPrefix = Ucren.id();
    var html = data.map(function(data, index){
    	return template.apply({
    		id: idPrefix + "_" + index,
    		aId: idPrefix + "_a" + index,
    		bId: idPrefix + "_b" + index,
    		index: index,
    		handleId: handleId,
    		name: data.fileName.subByte(14, ".."),
    		thumbnail: formatThumbnailUrl(id, data.src)
    	});
    });
    this.container.html(html);
    this.container.dom.scrollTop = 0;
    showPartThumbnail();
    dataLength = data.length;
    rowSize = Math.ceil(dataLength / cellSize);
};

exports.onblur = function(id){
	if(mousedownId == id)return ;
	unSelect();
};

exports.focusIndex = function(rowIndex, cellIndex){
	var index;
	if(typeof cellIndex == "undefined")
	    index = rowIndex;
	else
	    index = rowIndex * cellSize + cellIndex;
	var el = Ucren.Element(idPrefix + "_" + index);
	return selectItem(el);
};

exports.focusLeft = function(id){
	var index = Ucren.Element(id, true).getAttribute("index") - 0;
	var pos = getPositionByIndex(index), id;
	if(pos.cellIndex == 0)return ;
	this.focusIndex(pos.rowIndex, pos.cellIndex - 1);
};

exports.focusRight = function(id){
	var index = Ucren.Element(id, true).getAttribute("index") - 0;
	var pos = getPositionByIndex(index), id;
	if(pos.cellIndex == cellSize - 1)return ;
	this.focusIndex(pos.rowIndex, pos.cellIndex + 1);
};

exports.focusUp = function(id){
    var index = Ucren.Element(id, true).getAttribute("index") - 0;
	var pos = getPositionByIndex(index), id;
	if(pos.rowIndex == 0)return ;
	var el = this.focusIndex(pos.rowIndex - 1, pos.cellIndex);
	// 向上滚动时要处理聚焦问题，向其它方向由 a 标签的特性自动聚焦
	var scrollTop = (pos.rowIndex - 1) * 130;
	if(el && scrollTop < this.container.dom.scrollTop){
		this.container.dom.scrollTop = scrollTop;
		// el.dom.scrollIntoView(true);
		// if(page.dom.scrollLeft > 0)
		// 	page.dom.scrollLeft = 0; // ie 下 scrollIntoView 会造成 scrollLeft 变化
	}
};

exports.focusDown = function(id){
    var index = Ucren.Element(id, true).getAttribute("index") - 0;
	var pos = getPositionByIndex(index), id;
	if(pos.rowIndex == rowSize - 1)return ;
	if(index + cellSize > dataLength - 1){
	 	pos = getPositionByIndex(dataLength - 1);
	 	this.focusIndex(pos.rowIndex, pos.cellIndex);
	}else{
		this.focusIndex(pos.rowIndex + 1, pos.cellIndex);	
	}
};

exports.onkeydown = function(id){
	if(keydownLock)return ;
	keydownLock = true;
	setTimeout(function(){
	    keydownLock = false;
	}, keydownLockTimeout);

	var e = Ucren.Event();
	switch(e.keyCode){
	    case 37: // left
	    	this.focusLeft(id);
	    	break;
	    case 38: // top
	        this.focusUp(id);
	        break;
	    case 39: // right
	        this.focusRight(id);
	        break;
	    case 40: // bottom
	        this.focusDown(id);
	        break;
	    case 13: // enter
	    	var target = e.target || e.srcElement;
	    	var itemEl = getItem(target);
			viewItem(itemEl);
	    	break; 
	}
	// 这里明确不能阻止冒泡，在 detail 的逻辑里有对 document 的事件做侦听
	// e.cancelBubble = true;
	// e.stopPropagation && e.stopPropagation();
};

exports.dblclick = function(callback){
    dblclickCallback = callback;
};;return exports});define("scripts/modules/loading/main.js",function(exports){exports={};var Ucren = require("scripts/libs/ucren");
var loading = Ucren.Element("loading");
var loadingBg = Ucren.Element("loading-bg");
var loader = Ucren.Element("loading-loader");
var loadingText = Ucren.Element("loading-text");
var loadingState = Ucren.Element("loading-state");
var lastdecimal, tempdecimal, interv;
var close = function(){
	loading.display(false);
	loadingBg.display(false);
};

var exponential = function(index, offset, target, framesNum){
	if(index == 0)
		return offset;
	else if(index == framesNum)
		return offset + target;
	else if((index /= framesNum / 2) < 1)
		return target / 2 * Math.pow(2, 10 * (index - 1)) + offset;
	else
		return target / 2 * (-Math.pow(2, -10 * -- index) + 2) + offset;
};

exports.animTo = function(){
	var timer = 0, lastWidth = 0, frames = 15;
    return function(width, callback){
    	var last = lastWidth, index = 0, ctime;
    	// clearInterval(timer);
    	timer = ctime = setInterval(function(){
    		if(timer != ctime)return clearInterval(ctime);
    	    var w = lastWidth = exponential(index ++, last, width - last, frames);
    	    loader.style("width", Math.round(w) + "%");
	    	loadingState.html(w.toFixed(2) + "%");
	    	w === 100 && loadingText.html("完成.");
	    	if(index > frames){
	    	    clearInterval(ctime);
	    	    lastWidth = 0;
	    	    callback && setTimeout(callback, 100);
	    	}
    	}, Ucren.isIe ? 16 : 24);
    }
}();

	// 显示 loading
exports.show = function(text){
	if(this.inworking)return ;
	var proc = 0, me = this;
	var time = 150;
	var intervFun = function(){
		var n = Math.max(Math.floor((100 - proc) / 4), 0);

		if(n == 0)lastdecimal = lastdecimal + Ucren.randomNumber(10);
		else lastdecimal = Ucren.randomNumber(1000);

		proc = Math.min(proc + n, 100);
		me.animTo(proc);

		if(lastdecimal > 999){
			proc = Math.min(proc + 1, 99);
			lastdecimal -= 1000;
		}

		tempdecimal = lastdecimal / 1000;
		clearTimeout(interv);
		interv = setTimeout(intervFun, time);
	};

	loadingText.html(text + "...");
	loadingBg.display(true);
	loading.display(true);
	intervFun();
	this.inworking = true;
};

	// 隐藏 loading
exports.hide = function(){
	if(!this.inworking)return ;

	clearTimeout(interv);
	this.animTo(100, function(){
		close();
	    this.inworking = false;
	}.bind(this));
	loadingState.html("100%");
};;return exports});define("scripts/modules/page/main.js",function(exports){exports={};var Ucren = require("scripts/libs/ucren");

// list-page
var page = Ucren.Element("page");
var aside = Ucren.Element("aside");
var content = Ucren.Element("content");
var folder = Ucren.Element("folder");
var starthere = Ucren.Element("starthere");

// detail-page
var photoDetailCont = Ucren.Element("photo-detail-cont");
var detailCloseBtn = Ucren.Element("detail-close-btn");

var exponential = function(index, offset, target, framesNum){
	if(index == 0)
		return offset;
	else if(index == framesNum)
		return offset + target;
	else if((index /= framesNum / 2) < 1)
		return target / 2 * Math.pow(2, 10 * (index - 1)) + offset;
	else
		return target / 2 * (-Math.pow(2, -10 * -- index) + 2) + offset;
};

var doSetHeight = function(conf){
    if(conf.height)
        this.height(conf.height - 10);
};

var doResize = function(){
	clearTimeout(doResize.timer);
	doResize.timer = setTimeout(function(){
	    var w, h;
		w = document.documentElement.clientWidth;
		h = document.documentElement.clientHeight;
		page.width(w).height(h);
	}, 100);
};

// list-page
aside.observe(page, doSetHeight);
content.observe(page, function(conf){
    if(conf.width)
    	this.width(conf.width - 264);
    if(conf.height)
    	this.height(conf.height - 20);
});
folder.observe(aside, function(conf){
    if(conf.height)
    	this.height(conf.height - 27 - 10); // 5 * 2
});

// detail-page
photoDetailCont.observe(page, function(conf){
	if(conf.width)
	    this.width(conf.width);
	if(conf.height)
		this.height(conf.height);
});
detailCloseBtn.observe(page, function(conf){
    if(conf.width)
    	this.left(conf.width - 40);
});


doResize();
Ucren.addEvent(window, "resize", doResize);

exports.startNumber = 0;

var showStart = function(){
    starthere.setAlpha(exponential(exports.startNumber, 0, 100, 20));
	starthere.left(exponential(exports.startNumber, 20, -15, 20));
};

var createStartShown = function(dir, lastIndex){
	return function(){
		exports.startNumber += dir;
		showStart();
			
		if(exports.startNumber == 1)
			starthere.display(true);
		else if(exports.startNumber == 0)
			starthere.display(false);

		if(exports.startNumber == lastIndex)
			clearInterval(exports.startTimer);
	}
};

exports.startIn = function(){
	exports.startTimer = setInterval(createStartShown(+ 1, 20), 30);
};

exports.startOut = function(){
	clearInterval(exports.startTimer);
	exports.startTimer = setInterval(createStartShown(- 1, 0), 30);	
};

exports.go = function(pageName){
	var pages = [
		Ucren.Element("list-page"),
		Ucren.Element("detail-page")
	];
	this.pageName = pageName;
	pages.forEach(function(el){
	    el.display(false);
	    if(el.dom.id == pageName)
	        el.display(true);
	});
};;return exports});define("scripts/modules/tree/main.js",function(exports){exports={};var Ucren = require("scripts/libs/ucren");
var E = Ucren.Element, Q = Ucren.queryElement;

// 格式化数据，输入扁平数据，产生树状数据和 dataMapping
var formatData = function(data){
	var formatedData = [];
	var dataItemStates = {};
	var undefinedParentChilds = {};
	data.forEach(function(item, index){
		var p;
		item.childs = [];
		item.checked = 0;
		if(item.p){
			if(p = dataItemStates[item.p]){
				p.childs.push(item);
				dataItemStates[item.p].nodeType = "folder";
			}else if(p = undefinedParentChilds[item.p]){
				p.push(item);
			}else{
				undefinedParentChilds[item.p] = [item];
			}
		}else{
			formatedData.push(item);
		}

		item.nodeType = "normal";
		dataItemStates[item.n] = item;
		if(undefinedParentChilds[item.n]){
			item.childs = undefinedParentChilds[item.n].concat(item.childs);
			item.nodeType = "folder";
			delete undefinedParentChilds[item.n];
		}
	});

	Ucren.each(undefinedParentChilds, function(childs, name){
		var item = { n: name, p: "", childs: childs, checked: 0, nodeType: "folder"  };
		formatedData.push(item);
		dataItemStates[name] = item;
//			formatedData.push.apply(formatedData, childs);
	});

	return [formatedData, dataItemStates];
};

// 根据数据节点的状态，关联更新其它数据节点（与界面无关）
var updateCheckStates = function(dataMapping, dataItem, value, _dire){ // _dire: 1 向外 0 向里
	if(!dataItem)return ;

	dataItem.checked = value;

	// 向里
	var inwards = function(){
		if(value == .5)return ;
		dataItem.childs.forEach(function(dataItem){
			updateCheckStates(dataMapping, dataItem, value, 0);
		});
	};

	// 向外
	var forth = function(){
		var p, c, sum;
		if(p = dataItem.p){
			p = dataMapping[p];
			c = p.childs;
			sum = c.reduce(function(sum, dataItem){
				return sum + dataItem.checked;
			}, 0);
			if(sum === 0){
				p.checked = 0;
			}else if(sum === c.length){
				p.checked = 1;
			}else{
				p.checked = .5;
			}
			updateCheckStates(dataMapping, p, p.checked, 1);
		}
	};

	if(_dire === 0){
		inwards();
	}else if(_dire === 1){
		forth();
	}else{
		inwards();
		forth();
	}
};

var nodeTemplate = new Ucren.Template(
	"<div class='relation' id='@{relationId}'>",
		"<div class='expanded-viewer' id='@{expandedViewerId}'></div>",
	"</div>",
	"<div class='selection'>",
		"<div class='selection-inputer'>",
			"<input type='checkbox' id='@{checkinputId}' onfocus='this.blur()' onmousedown='return false' onclick='return false;' />",
		"</div>",
		"<div class='selection-clicker' id='@{checkClickerId}'></div>",
	"</div>",
	"<div class='icon' id='@{iconId}'></div>",
	"<div class='name'><a id='@{namelinkId}' href='' title='@{name}' onclick='return false;'>@{name} </a></div>");

var nodeTemplate2 = new Ucren.Template(
	"<div class='relation' id='@{relationId}'>",
		"<div class='expanded-viewer' id='@{expandedViewerId}'></div>",
	"</div>",
	"<div class='icon' id='@{iconId}'></div>",
	"<div class='name'><a id='@{namelinkId}' href='' onclick='return false;' onkeydown='Ucren.handle(@{handleId}).onkeydown(event); return false;'>@{name} </a></div>");

// class node
var node = new Ucren.Class(
	/* constructor */ function(conf){
		this.container = E(conf.container);
		this.name = conf.name || "";
		this.childsData = conf.childsData;
		this.tree = conf.tree;
		this.expanded = !! conf.expanded;
		this.checked = 0;
		this.tree.nodes.push(this);
		this.tree.nodeMapping[this.name] = this;
		this.clickHandler = conf.clickHandler || function(){};
		this.nameRenderer = conf.nameRenderer || function(text){ return text; };
		this.data = conf.data;
		this.handleId = Ucren.handle(this);

		if(conf.icon){
			this.icon = conf.icon;
		}else if(this.childsData.length){
			this.icon = "images/tree/etfolder.gif";
		}else{
			this.icon = "images/tree/etfile.gif";
		}
	},

	/* methods */ {
		render: function(){
			var enableCheckBox = this.tree.enableCheckBox;
			var template = enableCheckBox ? nodeTemplate : nodeTemplate2;

			this.container.html(template.apply({
				handleId: this.handleId,
				name: this.nameRenderer(this.name, this.parent ? this.parent.name : ""),
				iconId: this.iconId = Ucren.id(),
				namelinkId: this.namelinkId = Ucren.id(),
				expandedViewerId: this.expandedViewerId = Ucren.id(),
				relationId: this.relationId = Ucren.id(),
				checkinputId: this.checkinputId = Ucren.id(),
				checkClickerId: this.checkClickerId = Ucren.id()
			}));

			E(this.iconId).style("backgroundImage", "url(" + this.icon + ")");
			this.disposeEvent();

			if(this.childsData.length){
				E(this.expandedViewerId).display(true);
				var dropDownLayer = Ucren.makeElement("div", { "class": "dropdownlayer" });
				E(this.container).add(dropDownLayer);
				dropDownLayer = this.dropDownLayer = E(dropDownLayer);
			}

			if(this.dropDownLayer && !this.expanded)
				this.collapse();
			else
				this.expand();
		},

		expand: function(_callback){
			if(!this.hasExpanded && this.childsData.length){
				this.hasExpanded = true;
				this.renderChilds(this.childsData, function(){
					this.tree.updateListLastNodes();
					this.tree.updateNodeCheckStates(this);
					this.expand(_callback);
				}.bind(this));
				return ;
			}

			if(!this.dropDownLayer)return ;
			this.dropDownLayer.display(true);
			E(this.expandedViewerId).style("backgroundPosition", "0 -20px");
			E(this.iconId).style("backgroundPosition", "0 -20px");
			this.expanded = true;
			this.tree.fixRelativeEls();
			_callback && _callback();
		},

		collapse: function(){
			if(!this.dropDownLayer)return ;
			this.dropDownLayer.display(false);
			E(this.expandedViewerId).style("backgroundPosition", "0 0");
			E(this.iconId).style("backgroundPosition", "0 0");
			this.expanded = false;
			this.tree.fixRelativeEls();
		},

		setCheck: function(value){
			updateCheckStates(this.tree.dataMapping, this.tree.dataMapping[this.name], value);
			this.tree.updateNodeCheckStates(this);
			this.tree.fireEvent("nodeCheck", [this.name, value]);
		},

		setHidden: function(bool){
			this.isHidden = bool;
			this.container.display(bool);
			if(this.dropDownLayer)
				this.dropDownLayer.display(bool);
		},

		select: function(){
			var nameEl = E(this.namelinkId);
			if(this.tree.selectionNode){
				var lastNameEl = E(this.tree.selectionNode.namelinkId);
				lastNameEl.delClass("selected");
			}

			this.tree.selectionNode = this;
			nameEl.addClass("selected");
			
			setTimeout(function(){
			    nameEl.dom.focus();
			}, 100);

			return true;
		},

		focus: function(){
			var nameEl = E(this.namelinkId);
			if(this.tree.selectionNode){
				var lastNameEl = E(this.tree.selectionNode.namelinkId);
				lastNameEl.delClass("selected");
			}
			this.tree.selectionNode = this;
			nameEl.addClass("selected");
			this.clickHandler(this.data);

			var parent = this;
			while(parent = parent.parent)
				parent.expand && parent.expand();
		},

		setItsLast: function(bool){
			var relation = E(this.relationId);
			if(bool){
				this.dropDownLayer && this.dropDownLayer.addClass("dropdownlayer-last");
				relation.addClass("relation-last");
			}else{
				this.dropDownLayer && this.dropDownLayer.delClass("dropdownlayer-last");
				relation.delClass("relation-last");
			}
		},

		// privates
		renderChilds: function(childsData, callback){
			var dropDownLayer = this.dropDownLayer;
			dropDownLayer.html("loading..");
			dropDownLayer.display(true);
			void function(){
				dropDownLayer.html("");
				dropDownLayer.display(false);
				var subContainerIds = [];
				var subContainers = [];
				childsData.forEach(function(item, index){
					subContainerIds[index] = Ucren.id();
					subContainers[index] = "<div id='" + subContainerIds[index] + "' class='node clearfix'></div>";
				});
				dropDownLayer.html(subContainers.join(""));
				var list = [];
				childsData.forEach(function(item, index, array){
					var nodeItem = new node({
						data: item,
						container: subContainerIds[index],
						name: item.n,
						childsData: item.childs,
						tree: this.tree,
						expanded: item.expanded,
						clickHandler: this.clickHandler,
						nameRenderer: this.nameRenderer
					});
					nodeItem.parent = this;
					nodeItem.index = index;
					nodeItem.render();
					list.push(nodeItem);
					if(index == 0){
					    nodeItem.isFirst = true;
					}else if(index == array.length - 1){
						nodeItem.isLast = true;
					}
				}.bind(this));
				this.tree.lists.push(list);
				this.childs = list;
				callback && callback();
			}.defer(this, 0);
		},

		setViewChecked: function(){
			clearTimeout(this.setViewCheckedTimer);
			this.setViewCheckedTimer = setTimeout(function(){
				var checkinput = E(this.checkinputId, true);
				var checkedValue = this.tree.dataMapping[this.name].checked;
				if(checkedValue == this.checked)
					return ;
				this.checked = checkedValue;
				switch(checkedValue){
					case 0:
						checkinput.disabled = false;
						checkinput.checked = false;
						break;
					case .5:
						checkinput.disabled = true;
						checkinput.checked = true;
						break;
					case 1:
						checkinput.checked = true;
						checkinput.disabled = false;
						break;
				}
			}.bind(this), 10);
		},

		disposeEvent: function(){
			var nameEl = E(this.namelinkId);
			var expandedViewer = E(this.expandedViewerId);
			var checkinput = E(this.checkinputId);
			var checkClicker = E(this.checkClickerId);

			nameEl.addEvents({
				focus: function(){
					nameEl.addClass("focus");
					return true;
				}.bind(this),

				blur: function(){
					nameEl.delClass("focus");
					return true;
				}.bind(this),

				mousedown: this.select.bind(this),

				click: function(){
					if(!this.expanded)
						this.expand();
					this.clickHandler(this.data);
					return true;
				}.bind(this)
			});

			expandedViewer.addEvents({
				click: function(){
					if(this.expanded){
						this.collapse();
					}else{
						this.expand();
					}
				}.bind(this)
			});

			if(this.tree.enableCheckBox){
				checkClicker.addEvents({
					click: function(){
						var checkValue = this.tree.dataMapping[this.name].checked;
						switch(checkValue){
							case 0:
							case .5:
//									this.setCheck(1);
								this.tree.fireEvent("beforeCheckBoxClick", [this, 1]);
								break;
							case 1:
//									this.setCheck(0);
								this.tree.fireEvent("beforeCheckBoxClick", [this, 0]);
								break;
						}
					}.bind(this)
				});
			}
		},

		// 修正 checkClicker 位置偏差问题
		fixRelativeEls: function(step){
			if(!this.tree.enableCheckBox)return ;
			if(step == 1){
				E(this.checkClickerId).style("top", "0");
			}else if(step == 2){
				E(this.checkClickerId).style("top", "-20px");
			}
		},

		// 热键
		onkeydown: function(e){
		    e = Ucren.Event(e);
		    var node, newNode, parent;
		    switch(e.keyCode){
		        case 37: // left
		            if(this.expanded){
		            	this.collapse();
		            }else if(parent = this.parent){
		            	 parent.select && parent.select();
		            }
		        	break;
		        case 38: // top
		        	parent = this.parent;
		            if(this.isFirst){
		                parent.select && parent.select();
		            }else if(parent.childs && (newNode = parent.childs[this.index - 1])){
		            	newNode.select();
		            }
		            break;
		        case 39: // right
		            if(this.dropDownLayer && !this.expanded){
		                this.expand();
		            }else if(this.dropDownLayer && (node = this.childs[0])){
		            	node.select();
		            }
		            break;
		        case 40: // bottom
		        	if(this.dropDownLayer && this.expanded){
		        	    if(node = this.childs[0]){
		        	        node.select();
		        	    }
		        	}else{
		        	    node = this;
		        	    parent = node.parent;
		        	    while(parent){
		        	    	if(parent.childs && (newNode = parent.childs[node.index + 1])){
		        	    		newNode.select();
		        	    		break;
		        	    	}
		        	    	node = parent;
		        	    	parent = node.parent;
		        	    }
		        	}
		            break;
		    }
		}			
	}
);

// class tree
var tree = new Ucren.Class(
	/* constructor */ function(conf){
		this.container = E(conf.container);
		this.data = conf.data;
		this.enableCheckBox = typeof conf.enableCheckBox == "boolean" ?
			conf.enableCheckBox : true;
		this.clickHandler = conf.clickHandler;
		this.nameRenderer = conf.nameRenderer;
		this.nodes = [];
		this.nodeMapping = {};
		this.lists = [];

		var formatedData = formatData(conf.data);
		this.formatedData = formatedData[0];
		this.dataMapping = formatedData[1];

		this.setNodeCheckWithoutUpdateTimers = {};
		this.handleId = Ucren.handle(this);
	},

	/* methods */ {
		render: function(){
			var innerContainer = Ucren.makeElement("div", { "class": "simpletree" });
			this.container.add(innerContainer = E(innerContainer));

			var subContainerIds = [];
			var subContainers = [];
			this.formatedData.forEach(function(item, index){
				subContainerIds[index] = Ucren.id();
				subContainers[index] = "<div id='" + subContainerIds[index] + "' class='node clearfix'></div>";
			});
			innerContainer.html(subContainers.join(""));

			var list = [];
			this.formatedData.forEach(function(item, index, array){
				var nodeItem = new node({
					data: item,
					container: subContainerIds[index],
					name: item.n,
					childsData: item.childs,
					tree: this,
					expanded: item.expanded,
					clickHandler: this.clickHandler,
					nameRenderer: this.nameRenderer
				});
				nodeItem.parent = this;
				nodeItem.index = index;
				nodeItem.render();
				list.push(nodeItem);
				if(index == 0){
				    nodeItem.isFirst = true;
				}else if(index == array.length - 1){
					nodeItem.isLast = true;
				}
			}.bind(this));
			this.lists.push(list);
			this.childs = list;
			this.updateListLastNodes();
		},

		getCheckedData: function(){
			// TODO:
		},

		getRoot: function(){
			return this.nodes[0];
		},

		focusToKey: function(key){
			var dataMapping = this.dataMapping;
			var data = dataMapping[key];
			var nodeMapping = this.nodeMapping;
			var arr = [], pn;

			var tp = data;
			while(true){
				tp = dataMapping[tp.p];
				if(tp){
					arr.unshift(tp.n);
				}else{
					break;
				}
			}

			var expand = function(){
				var d, n;
				if(d = arr.shift()){
					n = nodeMapping[d];
					n.expand(expand);
				}else if(d = nodeMapping[key]){
					d.focus();
				}
			};
			expand();
		},

		// 只更新 dataMapping 中某个节点的选中状态（会自动关联更新其它节点的更新状态），但界面上不作更新
		setNodeCheckWithoutUpdate: function(name, value){
			clearTimeout(this.setNodeCheckWithoutUpdateTimers[name]);
			this.setNodeCheckWithoutUpdateTimers[name] = setTimeout(function(){
				var dataMapping = this.dataMapping;
				var dataItem = dataMapping[name];
				updateCheckStates(dataMapping, dataItem, value);
			}.bind(this), 10);
		},

		// 根据 dataMapping 中记录的选中状态，更新界面，obj 为参考的节点实例，会根据 obj 来自动找出需要更新的节点的界面
		// 如果没有 obj 参数，则更新所有已渲染的节点
		updateNodeCheckStates: function(obj){
			clearTimeout(this.updateNodeCheckStatesTimer);
			this.updateNodeCheckStatesTimer = setTimeout(function(){
				if(obj){
					var nodes = [obj], p = obj;
					var inwards = function(node){
						if(node.childs){
							nodes.push.apply(nodes, node.childs);
							node.childs.forEach(function(node){
								if(node.expanded)
									inwards(node);
							});
						}
					};
					inwards(p);
					while(p = p.parent)
						nodes.push(p);
				}else{
					nodes = this.nodes;
				}

				nodes.forEach(function(node, index){
					node.setViewChecked && node.setViewChecked();
				});
			}.bind(this), 10);
		},

		// privates
		updateListLastNodes: function(){
			var lists = this.lists;
			lists.forEach(function(list, index){
				var length = list.length;
				var found = false;
				for(var i = length - 1; i >= 0; i --){
					var node = list[i];
					if(!node.isHidden){
						if(found){
							node.setItsLast(false);
						}else{
							found = true;
							node.setItsLast(true);
						}
					}
				}
			});
		},

		// 修正 checkClicker 位置偏差问题
		fixRelativeEls: function(){
			var nodes = this.nodes;
			nodes.forEach(function(node){
				node.fixRelativeEls(1);
			});
			setTimeout(function(){
				nodes.forEach(function(node){
					node.fixRelativeEls(2);
				});
			}, 0);
		}
	}
);

tree.updateCheckStates = updateCheckStates;

exports = tree;;return exports});