
/*------------------------------------------------- public function -----------------------------------------------*/
function $OpenNewWindow(u, i, w, h, r, s, t) { var t = 20; var l = 120; if (window.screen.height) t = (window.screen.height - h) / 2; if (window.screen.width) l = (window.screen.width - w) / 2; var win = window.open(u, i, "width=" + w + ",height=" + h + ",resizable=" + (r ? "yes" : "no") + ",scrollbars=" + (s ? "yes" : "no") + ",status=" + (t ? "1" : "0") + ", top=" + t + ", left=" + l); if (win) win.focus(); return win; }

var $equals = function(obj1, obj2) {
	return (obj1 == obj2 || obj1.trim() == obj2.trim() || JSON.encode(obj1) == JSON.encode(obj2));
};

var $isMatch = function(ele, match, matchValue, eleAttr) {
	var value = eleAttr ? $(ele).get('value').trim().length : $(ele).get('value').trim();
	return eval(value + match + matchValue);
};
$isMatch.extend({
    IS:'==',
    NOT_IS:'!=',
    MORE:'>',
    MORE_IS:'>=',
    LESS:'<',
    LESS_IS:'<='
});

var $isRegex = function(ele, regex, params) {
	return $(ele).get('value').trim().test(regex, params || 'i');
};
$isRegex.extend({
    EMAIL:"^[a-z0-9._%-]+@[a-z0-9.-]+\\.[a-z]{2,4}$",
    URL:"^(http|https|ftp)\\:\\/\\/[a-z0-9\\-\\.]+\\.[a-z]{2,3}(:[a-z0-9]*)?\\/?([a-z0-9\\-\\._\\?\\,\\'\\/\\\\\\+&amp;%\\$#\\=~])*$",
    MOBILE:"^1\\d{10}$",
    ZIPCODE:"^\\d{6}$"
});

function $dialog(title, content, btn) {
    var eleTitle = new Element("div").addClass("DialogTitle");
    ($type(title) == 'array')?eleTitle.adopt(title):eleTitle.set("html", title);

    var eleContent = new Element("div").addClass("DialogContent");
    ($type(content) == 'array')? eleContent.adopt(content):eleContent.set("html", content);

    var eleBtn = new Element("div").addClass("DialogButtons");
    ($type(btn) == 'array')? eleBtn.adopt(btn):eleBtn.set("html", btn);

    return new Element("div").adopt([eleTitle, eleContent, eleBtn]);
 };

 function $isValidBtyes(s, n) {
 	var w = 0;
 	for (var i = 0; i < s.length; i++) {
 		var c = s.charCodeAt(i);
 		if ((c >= 0x0001 && c <= 0x007e) || (0xff60 <= c && c <= 0xff9f)) {
 			w++;
 		} else {
 			w += 2;
 		}
 	}
 	if (w > n) {
 		return false;
 	}
 	return true;
 }

function $uploadFlashVars(settings) {
	return ["movieName=", encodeURIComponent(settings.movieName),
			"&uploadURL=", encodeURIComponent(settings.upload_url),
			"&useQueryString=", encodeURIComponent(settings.use_query_string),
			"&httpSuccess=", encodeURIComponent(settings.httpSuccessString),
			"&params=", encodeURIComponent(settings.paramString),
			"&filePostName=", encodeURIComponent(settings.file_post_name),
			"&fileTypes=", encodeURIComponent(settings.file_types),
			"&fileTypesDescription=", encodeURIComponent(settings.file_types_description),
			"&fileSizeLimit=", encodeURIComponent(settings.file_size_limit),
			"&fileUploadLimit=", encodeURIComponent(settings.file_upload_limit),
			"&fileQueueLimit=", encodeURIComponent(settings.file_queue_limit),
			"&ifdebug=", encodeURIComponent(settings.ifdebug),
			"&successCall=", encodeURIComponent(settings.success_call),
			"&completeCall=", encodeURIComponent(settings.complete_call),
			"&buttonAction=", encodeURIComponent(settings.button_action)
		].join("");
}

function $getFlashHtml(movieName, flashUrl, width, height, mode, settings) {
    return ['<object id="', movieName, '" type="application/x-shockwave-flash" data="', flashUrl, '" width="', width, '" height="', height, '">',
					'<param name="wmode" value="', mode, '" />',
					'<param name="movie" value="', flashUrl, '" />',
					'<param name="quality" value="high" />',
					'<param name="menu" value="false" />',
					'<param name="allowScriptAccess" value="always" />',
					'<param name="flashvars" value="' + settings + '" />',
					'</object>'].join('');
}

 /*------------------------------------------------- implement -----------------------------------------------*/
 Array.implement({
	min: function(){
		return Math.min.apply(null, this);
	},
	max: function(){
		return Math.max.apply(null, this);
	},
	average: function(){
		return this.length ? this.sum() / this.length : 0;
	},
	sum: function(){
		var result = 0, l = this.length;
		if (l){
			do {
				result += this[--l];
			} while (l);
		}
		return result;
	}
});

Hash.implement({
	getFromPath: function(notation){
		var source = this.getClean();
		notation.replace(/\[([^\]]+)\]|\.([^.[]+)|[^[.]+/g, function(match){
			if (!source) return null;
			var prop = arguments[2] || arguments[1] || arguments[0];
			source = (prop in source) ? source[prop] : null;
			return match;
		});
		return source;
	},
	cleanValues: function(method){
		method = method || $defined;
		this.each(function(v, k){
			if (!method(v)) this.erase(k);
		}, this);
		return this;
	},
	run: function(){
		var args = arguments;
		this.each(function(v, k){
			if ($type(v) == 'function') v.run(args);
		});
	}
});

String.implement({
	cnEncode: function() {
		return encodeURIComponent(this);
	},
	cnDecode: function() {
		return decodeURIComponent(this);
	}
});

Element.implement({
	appendHTML: function(html, where) {
		if ($type(html) != 'string') return false;
		where = where || 'bottom';
		var temp = new Element('div');
		temp.set('html', html);
		var data = (where == 'bottom' || where == 'before') ? $A(temp.childNodes) : $A(temp.childNodes).reverse();
		data.each(function(node) {
			if ($type(node) == 'element') $(node).inject(this, where);
		}, this);
		return this;
	},
	css: function(key, value) {
		if ($type(key) == 'object') {
			for (var p in key) this.css(p, key[p]);
			return this;
		}
		this.setStyle(key, value);
		return this;
	},
	attr: function(key, value) {
		if ($type(key) == 'object') {
			for (var p in key) this.attr(p, key[p]);
			return this;
		}
		this.setProperty(key, value);
		return this;
	},
	isDisplayed: function() {
		return this.getStyle('display') != 'none';
	},
	toggle: function() {
		return this[this.isDisplayed() ? 'hide' : 'show']();
	},
	hide: function() {
		var d;
		try {
			//IE fails here if the element is not in the dom
			if ('none' != this.getStyle('display')) d = this.getStyle('display');
		} catch (e) { }

		return this.store('originalDisplay', d || 'block').setStyle('display', 'none');
	},
	show: function(display) {
		return this.setStyle('display', display || this.retrieve('originalDisplay') || 'block');
	},
	swapClass: function(remove, add) {
		return this.removeClass(remove).addClass(add);
	}
});

Element.alias('store', 'sdata');
Element.alias('retrieve', 'gdata');

// live
 (function() {
 	var guid = 1;
 	function liveHandler(e) {
 		var t = $(e.target), type = e.type, fns = document.retrieve('live', []), eles = [], stop = true;
 		if (!fns.length) return;
 		fns.each(function(item) {
 			if (item.type == type) {
 				var order = closest(item.exp, t);
 				//console.log(order);
 				if (order) eles.push({ ele: t, fn: item, order: order });
 			}
 		});

 		if (eles.length) {
 			eles.sort(function(a, b) {
 				return a.order - b.order;
 			});

 			eles.each(function(item) {
 				if (item.fn.call(item.ele, e) === false) return (stop = false);
 			});
 		}
 		return stop;
 	}

 	function closest(exp, t) {
 		var pos = $type(exp) == 'string' ? $$(exp) : null, cur = t, closer = 1;
 		if (!pos) return false;

 		while (cur && !isBody(cur)) {
 			//console.log(cur);
 			if (pos.contains(cur)) {
 				return closer;
 			}
 			cur = cur.getParent();
 			closer++;
 		}
 		return false;
 	}

 	function isBody(element) {
 		return (/^(?:body|html)$/i).test(element.tagName);
 	}

 	Window.implement({
 		$live: function(exp, type, fn) {
 			var fns = document.retrieve('live', []);
 			var wrap = function() { return fn.apply(this, arguments) };
 			wrap.guid = fn.guid = fn.guid || wrap.guid || guid++;
 			wrap.type = type;
 			wrap.exp = exp;
 			fns.length ? fns.each(function(item) {
 				if (item.guid != wrap.guid || item.type != wrap.type || item.exp != wrap.exp) fns.push(wrap);
 			}) : fns.push(wrap);
 			document.addEvent(type, liveHandler);
 		},
 		$die: function(exp, type, fn) {
 			var fns = document.retrieve('live');
 			if (!fns || !fns.length) return;
 			document.store('live',fns.filter(function(item) {
 				return !(item.exp == exp && item.type == type && (fn ? item.guid == fn.guid : true));
 			}));
 		}
 	});

 })();



 /*-------------------------------------------------App  module -----------------------------------------------*/
 //npage section
 var npage = new Hash({
 	ids: new Hash(),
 	data: new Hash(),
 	regEvents: function(events) {
 		events = events || { domready: $empty, load: $empty, unload: $empty };
 		for (var i in events) {
 			if (typeof events[i] == 'function') window.addEvent(i, events[i]);
 		}
 		return this;
 	},
 	setEles: function(eles, alias) {
 		if (!eles) return;
 		var result, F = arguments.callee;
 		F.extend({ v: true, d: [] });
 		eles = new Hash(eles);
 		if (alias) window[alias] = this.ids;
 		eles.each(function(value, key) {
 			if (result = value) this.ids.set(key, result);
 			else { F.v = false; F.d.push(key); }
 		}, this);
 		return F.v;
 	},
 	setData: function(data, alias) {
 		if (!data) return;
 		data = new Hash(data);
 		if (alias) window[alias] = this.data;
 		data.each(function(value, key) {
 			this.data.set(key, value);
 		}, this);
 		return this;
 	},
 	erase: function() {
 		for (var i = 0, l = arguments.length; i < l; i++) { try { this[arguments[i]].empty(); } catch (e) { alert('unexpected param'); } }
 	},
 	get: function(type) {
 		if (type && $type(this[type])=='hash') return this[type].getClean();
 	}
 });
 


 /*SWFObject v2.1 <http://code.google.com/p/swfobject/>*/

 var swfobject = function() {

 	var UNDEF = "undefined",
		OBJECT = "object",
		SHOCKWAVE_FLASH = "Shockwave Flash",
		SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
		FLASH_MIME_TYPE = "application/x-shockwave-flash",
		EXPRESS_INSTALL_ID = "SWFObjectExprInst",

		win = window,
		doc = document,
		nav = navigator,

		domLoadFnArr = [],
		regObjArr = [],
		objIdArr = [],
		listenersArr = [],
		script,
		timer = null,
		storedAltContent = null,
		storedAltContentId = null,
		isDomLoaded = false,
		isExpressInstallActive = false;

 	/* Centralized function for browser feature detection
 	- Proprietary feature detection (conditional compiling) is used to detect Internet Explorer's features
 	- User agent string detection is only used when no alternative is possible
 	- Is executed directly for optimal performance
 	*/
 	var ua = function() {
 		var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
			playerVersion = [0, 0, 0],
			d = null;
 		if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
 			d = nav.plugins[SHOCKWAVE_FLASH].description;
 			if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
 				d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
 				playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
 				playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
 				playerVersion[2] = /r/.test(d) ? parseInt(d.replace(/^.*r(.*)$/, "$1"), 10) : 0;
 			}
 		}
 		else if (typeof win.ActiveXObject != UNDEF) {
 			var a = null, fp6Crash = false;
 			try {
 				a = new ActiveXObject(SHOCKWAVE_FLASH_AX + ".10");
 			}
 			catch (e) {
 				try {
 					a = new ActiveXObject(SHOCKWAVE_FLASH_AX + ".7");
 				}
 				catch (e) {
 					try {
 						a = new ActiveXObject(SHOCKWAVE_FLASH_AX + ".6");
 						playerVersion = [6, 0, 21];
 						a.AllowScriptAccess = "always";     // Introduced in fp6.0.47
 					}
 					catch (e) {
 						if (playerVersion[0] == 6) {
 							fp6Crash = true;
 						}
 					}
 				}
 				if (!fp6Crash) {
 					try {
 						a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
 					}
 					catch (e) { }
 				}
 			}
 			if (!fp6Crash && a) { // a will return null when ActiveX is disabled
 				try {
 					d = a.GetVariable("$version"); // Will crash fp6.0.21/23/29
 					if (d) {
 						d = d.split(" ")[1].split(",");
 						playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
 					}
 				}
 				catch (e) { }
 			}
 		};
 		var u = nav.userAgent.toLowerCase(),
			p = nav.platform.toLowerCase(),
			webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
			ie = false,
			windows = p ? /win/.test(p) : /win/.test(u),
			mac = p ? /mac/.test(p) : /mac/.test(u);
 		/*@cc_on
 		ie = true;
 		@if (@_win32)
 		windows = true;
 		@elif (@_mac)
				mac = true;
			@end
 		@*/
 		return { w3cdom: w3cdom, pv: playerVersion, webkit: webkit, ie: ie, win: windows, mac: mac };
 	} ();

 	/* Cross-browser onDomLoad
 	- Based on Dean Edwards' solution: http://dean.edwards.name/weblog/2006/06/again/
 	- Will fire an event as soon as the DOM of a page is loaded (supported by Gecko based browsers - like Firefox -, IE, Opera9+, Safari)
 	*/
 	var onDomLoad = function() {
 		if (!ua.w3cdom) {
 			return;
 		}
 		addDomLoadEvent(main);
 		if (ua.ie && ua.win) {
 			try {	 // Avoid a possible Operation Aborted error
 				doc.write("<scr" + "ipt id=__ie_ondomload defer=true src=//:></scr" + "ipt>"); // String is split into pieces to avoid Norton AV to add code that can cause errors 
 				script = getElementById("__ie_ondomload");
 				if (script) {
 					addListener(script, "onreadystatechange", checkReadyState);
 				}
 			}
 			catch (e) { }
 		}
 		if (ua.webkit && typeof doc.readyState != UNDEF) {
 			timer = setInterval(function() { if (/loaded|complete/.test(doc.readyState)) { callDomLoadFunctions(); } }, 10);
 		}
 		if (typeof doc.addEventListener != UNDEF) {
 			doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, null);
 		}
 		addLoadEvent(callDomLoadFunctions);
 	} ();

 	function checkReadyState() {
 		if (script.readyState == "complete") {
 			script.parentNode.removeChild(script);
 			callDomLoadFunctions();
 		}
 	}

 	function callDomLoadFunctions() {
 		if (isDomLoaded) {
 			return;
 		}
 		if (ua.ie && ua.win) { // Test if we can really add elements to the DOM; we don't want to fire it too early
 			var s = createElement("span");
 			try { // Avoid a possible Operation Aborted error
 				var t = doc.getElementsByTagName("body")[0].appendChild(s);
 				t.parentNode.removeChild(t);
 			}
 			catch (e) {
 				return;
 			}
 		}
 		isDomLoaded = true;
 		if (timer) {
 			clearInterval(timer);
 			timer = null;
 		}
 		var dl = domLoadFnArr.length;
 		for (var i = 0; i < dl; i++) {
 			domLoadFnArr[i]();
 		}
 	}

 	function addDomLoadEvent(fn) {
 		if (isDomLoaded) {
 			fn();
 		}
 		else {
 			domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+
 		}
 	}

 	/* Cross-browser onload
 	- Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/
 	- Will fire an event as soon as a web page including all of its assets are loaded 
 	*/
 	function addLoadEvent(fn) {
 		if (typeof win.addEventListener != UNDEF) {
 			win.addEventListener("load", fn, false);
 		}
 		else if (typeof doc.addEventListener != UNDEF) {
 			doc.addEventListener("load", fn, false);
 		}
 		else if (typeof win.attachEvent != UNDEF) {
 			addListener(win, "onload", fn);
 		}
 		else if (typeof win.onload == "function") {
 			var fnOld = win.onload;
 			win.onload = function() {
 				fnOld();
 				fn();
 			};
 		}
 		else {
 			win.onload = fn;
 		}
 	}

 	/* Main function
 	- Will preferably execute onDomLoad, otherwise onload (as a fallback)
 	*/
 	function main() { // Static publishing only
 		var rl = regObjArr.length;
 		for (var i = 0; i < rl; i++) { // For each registered object element
 			var id = regObjArr[i].id;
 			if (ua.pv[0] > 0) {
 				var obj = getElementById(id);
 				if (obj) {
 					regObjArr[i].width = obj.getAttribute("width") ? obj.getAttribute("width") : "0";
 					regObjArr[i].height = obj.getAttribute("height") ? obj.getAttribute("height") : "0";
 					if (hasPlayerVersion(regObjArr[i].swfVersion)) { // Flash plug-in version >= Flash content version: Houston, we have a match!
 						if (ua.webkit && ua.webkit < 312) { // Older webkit engines ignore the object element's nested param elements
 							fixParams(obj);
 						}
 						setVisibility(id, true);
 					}
 					else if (regObjArr[i].expressInstall && !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac)) { // Show the Adobe Express Install dialog if set by the web page author and if supported (fp6.0.65+ on Win/Mac OS only)
 						showExpressInstall(regObjArr[i]);
 					}
 					else { // Flash plug-in and Flash content version mismatch: display alternative content instead of Flash content
 						displayAltContent(obj);
 					}
 				}
 			}
 			else {	// If no fp is installed, we let the object element do its job (show alternative content)
 				setVisibility(id, true);
 			}
 		}
 	}

 	/* Fix nested param elements, which are ignored by older webkit engines
 	- This includes Safari up to and including version 1.2.2 on Mac OS 10.3
 	- Fall back to the proprietary embed element
 	*/
 	function fixParams(obj) {
 		var nestedObj = obj.getElementsByTagName(OBJECT)[0];
 		if (nestedObj) {
 			var e = createElement("embed"), a = nestedObj.attributes;
 			if (a) {
 				var al = a.length;
 				for (var i = 0; i < al; i++) {
 					if (a[i].nodeName == "DATA") {
 						e.setAttribute("src", a[i].nodeValue);
 					}
 					else {
 						e.setAttribute(a[i].nodeName, a[i].nodeValue);
 					}
 				}
 			}
 			var c = nestedObj.childNodes;
 			if (c) {
 				var cl = c.length;
 				for (var j = 0; j < cl; j++) {
 					if (c[j].nodeType == 1 && c[j].nodeName == "PARAM") {
 						e.setAttribute(c[j].getAttribute("name"), c[j].getAttribute("value"));
 					}
 				}
 			}
 			obj.parentNode.replaceChild(e, obj);
 		}
 	}

 	/* Show the Adobe Express Install dialog
 	- Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
 	*/
 	function showExpressInstall(regObj) {
 		isExpressInstallActive = true;
 		var obj = getElementById(regObj.id);
 		if (obj) {
 			if (regObj.altContentId) {
 				var ac = getElementById(regObj.altContentId);
 				if (ac) {
 					storedAltContent = ac;
 					storedAltContentId = regObj.altContentId;
 				}
 			}
 			else {
 				storedAltContent = abstractAltContent(obj);
 			}
 			if (!(/%$/.test(regObj.width)) && parseInt(regObj.width, 10) < 310) {
 				regObj.width = "310";
 			}
 			if (!(/%$/.test(regObj.height)) && parseInt(regObj.height, 10) < 137) {
 				regObj.height = "137";
 			}
 			doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
 			var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn",
				dt = doc.title,
				fv = "MMredirectURL=" + win.location + "&MMplayerType=" + pt + "&MMdoctitle=" + dt,
				replaceId = regObj.id;
 			// For IE when a SWF is loading (AND: not available in cache) wait for the onload event to fire to remove the original object element
 			// In IE you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
 			if (ua.ie && ua.win && obj.readyState != 4) {
 				var newObj = createElement("div");
 				replaceId += "SWFObjectNew";
 				newObj.setAttribute("id", replaceId);
 				obj.parentNode.insertBefore(newObj, obj); // Insert placeholder div that will be replaced by the object element that loads expressinstall.swf
 				obj.style.display = "none";
 				var fn = function() {
 					obj.parentNode.removeChild(obj);
 				};
 				addListener(win, "onload", fn);
 			}
 			createSWF({ data: regObj.expressInstall, id: EXPRESS_INSTALL_ID, width: regObj.width, height: regObj.height }, { flashvars: fv }, replaceId);
 		}
 	}

 	/* Functions to abstract and display alternative content
 	*/
 	function displayAltContent(obj) {
 		if (ua.ie && ua.win && obj.readyState != 4) {
 			// For IE when a SWF is loading (AND: not available in cache) wait for the onload event to fire to remove the original object element
 			// In IE you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
 			var el = createElement("div");
 			obj.parentNode.insertBefore(el, obj); // Insert placeholder div that will be replaced by the alternative content
 			el.parentNode.replaceChild(abstractAltContent(obj), el);
 			obj.style.display = "none";
 			var fn = function() {
 				obj.parentNode.removeChild(obj);
 			};
 			addListener(win, "onload", fn);
 		}
 		else {
 			obj.parentNode.replaceChild(abstractAltContent(obj), obj);
 		}
 	}

 	function abstractAltContent(obj) {
 		var ac = createElement("div");
 		if (ua.win && ua.ie) {
 			ac.innerHTML = obj.innerHTML;
 		}
 		else {
 			var nestedObj = obj.getElementsByTagName(OBJECT)[0];
 			if (nestedObj) {
 				var c = nestedObj.childNodes;
 				if (c) {
 					var cl = c.length;
 					for (var i = 0; i < cl; i++) {
 						if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
 							ac.appendChild(c[i].cloneNode(true));
 						}
 					}
 				}
 			}
 		}
 		return ac;
 	}

 	/* Cross-browser dynamic SWF creation
 	*/
 	function createSWF(attObj, parObj, id) {
 		var r, el = getElementById(id);
 		if (el) {
 			if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
 				attObj.id = id;
 			}
 			if (ua.ie && ua.win) { // IE, the object element and W3C DOM methods do not combine: fall back to outerHTML
 				var att = "";
 				for (var i in attObj) {
 					if (attObj[i] != Object.prototype[i]) { // Filter out prototype additions from other potential libraries, like Object.prototype.toJSONString = function() {}
 						if (i.toLowerCase() == "data") {
 							parObj.movie = attObj[i];
 						}
 						else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
 							att += ' class="' + attObj[i] + '"';
 						}
 						else if (i.toLowerCase() != "classid") {
 							att += ' ' + i + '="' + attObj[i] + '"';
 						}
 					}
 				}
 				var par = "";
 				for (var j in parObj) {
 					if (parObj[j] != Object.prototype[j]) { // Filter out prototype additions from other potential libraries
 						par += '<param name="' + j + '" value="' + parObj[j] + '" />';
 					}
 				}
 				el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';
 				objIdArr[objIdArr.length] = attObj.id; // Stored to fix object 'leaks' on unload (dynamic publishing only)
 				r = getElementById(attObj.id);
 			}
 			else if (ua.webkit && ua.webkit < 312) { // Older webkit engines ignore the object element's nested param elements: fall back to the proprietary embed element
 				var e = createElement("embed");
 				e.setAttribute("type", FLASH_MIME_TYPE);
 				for (var k in attObj) {
 					if (attObj[k] != Object.prototype[k]) { // Filter out prototype additions from other potential libraries
 						if (k.toLowerCase() == "data") {
 							e.setAttribute("src", attObj[k]);
 						}
 						else if (k.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
 							e.setAttribute("class", attObj[k]);
 						}
 						else if (k.toLowerCase() != "classid") { // Filter out IE specific attribute
 							e.setAttribute(k, attObj[k]);
 						}
 					}
 				}
 				for (var l in parObj) {
 					if (parObj[l] != Object.prototype[l]) { // Filter out prototype additions from other potential libraries
 						if (l.toLowerCase() != "movie") { // Filter out IE specific param element
 							e.setAttribute(l, parObj[l]);
 						}
 					}
 				}
 				el.parentNode.replaceChild(e, el);
 				r = e;
 			}
 			else { // Well-behaving browsers
 				var o = createElement(OBJECT);
 				o.setAttribute("type", FLASH_MIME_TYPE);
 				for (var m in attObj) {
 					if (attObj[m] != Object.prototype[m]) { // Filter out prototype additions from other potential libraries
 						if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
 							o.setAttribute("class", attObj[m]);
 						}
 						else if (m.toLowerCase() != "classid") { // Filter out IE specific attribute
 							o.setAttribute(m, attObj[m]);
 						}
 					}
 				}
 				for (var n in parObj) {
 					if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // Filter out prototype additions from other potential libraries and IE specific param element
 						createObjParam(o, n, parObj[n]);
 					}
 				}
 				el.parentNode.replaceChild(o, el);
 				r = o;
 			}
 		}
 		return r;
 	}

 	function createObjParam(el, pName, pValue) {
 		var p = createElement("param");
 		p.setAttribute("name", pName);
 		p.setAttribute("value", pValue);
 		el.appendChild(p);
 	}

 	/* Cross-browser SWF removal
 	- Especially needed to safely and completely remove a SWF in Internet Explorer
 	*/
 	function removeSWF(id) {
 		var obj = getElementById(id);
 		if (obj && (obj.nodeName == "OBJECT" || obj.nodeName == "EMBED")) {
 			if (ua.ie && ua.win) {
 				if (obj.readyState == 4) {
 					removeObjectInIE(id);
 				}
 				else {
 					win.attachEvent("onload", function() {
 						removeObjectInIE(id);
 					});
 				}
 			}
 			else {
 				obj.parentNode.removeChild(obj);
 			}
 		}
 	}

 	function removeObjectInIE(id) {
 		var obj = getElementById(id);
 		if (obj) {
 			for (var i in obj) {
 				if (typeof obj[i] == "function") {
 					obj[i] = null;
 				}
 			}
 			obj.parentNode.removeChild(obj);
 		}
 	}

 	/* Functions to optimize JavaScript compression
 	*/
 	function getElementById(id) {
 		var el = null;
 		try {
 			el = doc.getElementById(id);
 		}
 		catch (e) { }
 		return el;
 	}

 	function createElement(el) {
 		return doc.createElement(el);
 	}

 	/* Updated attachEvent function for Internet Explorer
 	- Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
 	*/
 	function addListener(target, eventType, fn) {
 		target.attachEvent(eventType, fn);
 		listenersArr[listenersArr.length] = [target, eventType, fn];
 	}

 	/* Flash Player and SWF content version matching
 	*/
 	function hasPlayerVersion(rv) {
 		var pv = ua.pv, v = rv.split(".");
 		v[0] = parseInt(v[0], 10);
 		v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
 		v[2] = parseInt(v[2], 10) || 0;
 		return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
 	}

 	/* Cross-browser dynamic CSS creation
 	- Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
 	*/
 	function createCSS(sel, decl) {
 		if (ua.ie && ua.mac) {
 			return;
 		}
 		var h = doc.getElementsByTagName("head")[0], s = createElement("style");
 		s.setAttribute("type", "text/css");
 		s.setAttribute("media", "screen");
 		if (!(ua.ie && ua.win) && typeof doc.createTextNode != UNDEF) {
 			s.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
 		}
 		h.appendChild(s);
 		if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
 			var ls = doc.styleSheets[doc.styleSheets.length - 1];
 			if (typeof ls.addRule == OBJECT) {
 				ls.addRule(sel, decl);
 			}
 		}
 	}

 	function setVisibility(id, isVisible) {
 		var v = isVisible ? "visible" : "hidden";
 		if (isDomLoaded && getElementById(id)) {
 			getElementById(id).style.visibility = v;
 		}
 		else {
 			createCSS("#" + id, "visibility:" + v);
 		}
 	}

 	/* Filter to avoid XSS attacks 
 	*/
 	function urlEncodeIfNecessary(s) {
 		var regex = /[\\\"<>\.;]/;
 		var hasBadChars = regex.exec(s) != null;
 		return hasBadChars ? encodeURIComponent(s) : s;
 	}

 	/* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
 	*/
 	var cleanup = function() {
 		if (ua.ie && ua.win) {
 			window.attachEvent("onunload", function() {
 				// remove listeners to avoid memory leaks
 				var ll = listenersArr.length;
 				for (var i = 0; i < ll; i++) {
 					listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
 				}
 				// cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
 				var il = objIdArr.length;
 				for (var j = 0; j < il; j++) {
 					removeSWF(objIdArr[j]);
 				}
 				// cleanup library's main closures to avoid memory leaks
 				for (var k in ua) {
 					ua[k] = null;
 				}
 				ua = null;
 				for (var l in swfobject) {
 					swfobject[l] = null;
 				}
 				swfobject = null;
 			});
 		}
 	} ();


 	return {
 		/* Public API
 		- Reference: http://code.google.com/p/swfobject/wiki/SWFObject_2_0_documentation
 		*/
 		registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr) {
 			if (!ua.w3cdom || !objectIdStr || !swfVersionStr) {
 				return;
 			}
 			var regObj = {};
 			regObj.id = objectIdStr;
 			regObj.swfVersion = swfVersionStr;
 			regObj.expressInstall = xiSwfUrlStr ? xiSwfUrlStr : false;
 			regObjArr[regObjArr.length] = regObj;
 			setVisibility(objectIdStr, false);
 		},

 		getObjectById: function(objectIdStr) {
 			var r = null;
 			if (ua.w3cdom) {
 				var o = getElementById(objectIdStr);
 				if (o) {
 					var n = o.getElementsByTagName(OBJECT)[0];
 					if (!n || (n && typeof o.SetVariable != UNDEF)) {
 						r = o;
 					}
 					else if (typeof n.SetVariable != UNDEF) {
 						r = n;
 					}
 				}
 			}
 			return r;
 		},

 		embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj) {
 			if (!ua.w3cdom || !swfUrlStr || !replaceElemIdStr || !widthStr || !heightStr || !swfVersionStr) {
 				return;
 			}
 			widthStr += ""; // Auto-convert to string
 			heightStr += "";
 			if (hasPlayerVersion(swfVersionStr)) {
 				setVisibility(replaceElemIdStr, false);
 				var att = {};
 				if (attObj && typeof attObj === OBJECT) {
 					for (var i in attObj) {
 						if (attObj[i] != Object.prototype[i]) { // Filter out prototype additions from other potential libraries
 							att[i] = attObj[i];
 						}
 					}
 				}
 				att.data = swfUrlStr;
 				att.width = widthStr;
 				att.height = heightStr;
 				var par = {};
 				if (parObj && typeof parObj === OBJECT) {
 					for (var j in parObj) {
 						if (parObj[j] != Object.prototype[j]) { // Filter out prototype additions from other potential libraries
 							par[j] = parObj[j];
 						}
 					}
 				}
 				if (flashvarsObj && typeof flashvarsObj === OBJECT) {
 					for (var k in flashvarsObj) {
 						if (flashvarsObj[k] != Object.prototype[k]) { // Filter out prototype additions from other potential libraries
 							if (typeof par.flashvars != UNDEF) {
 								par.flashvars += "&" + k + "=" + flashvarsObj[k];
 							}
 							else {
 								par.flashvars = k + "=" + flashvarsObj[k];
 							}
 						}
 					}
 				}
 				addDomLoadEvent(function() {
 					createSWF(att, par, replaceElemIdStr);
 					if (att.id == replaceElemIdStr) {
 						setVisibility(replaceElemIdStr, true);
 					}
 				});
 			}
 			else if (xiSwfUrlStr && !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac)) {
 				isExpressInstallActive = true; // deferred execution
 				setVisibility(replaceElemIdStr, false);
 				addDomLoadEvent(function() {
 					var regObj = {};
 					regObj.id = regObj.altContentId = replaceElemIdStr;
 					regObj.width = widthStr;
 					regObj.height = heightStr;
 					regObj.expressInstall = xiSwfUrlStr;
 					showExpressInstall(regObj);
 				});
 			}
 		},

 		getFlashPlayerVersion: function() {
 			return { major: ua.pv[0], minor: ua.pv[1], release: ua.pv[2] };
 		},

 		hasFlashPlayerVersion: hasPlayerVersion,

 		createSWF: function(attObj, parObj, replaceElemIdStr) {
 			if (ua.w3cdom) {
 				return createSWF(attObj, parObj, replaceElemIdStr);
 			}
 			else {
 				return undefined;
 			}
 		},

 		removeSWF: function(objElemIdStr) {
 			if (ua.w3cdom) {
 				removeSWF(objElemIdStr);
 			}
 		},

 		createCSS: function(sel, decl) {
 			if (ua.w3cdom) {
 				createCSS(sel, decl);
 			}
 		},

 		addDomLoadEvent: addDomLoadEvent,

 		addLoadEvent: addLoadEvent,

 		getQueryParamValue: function(param) {
 			var q = doc.location.search || doc.location.hash;
 			if (param == null) {
 				return urlEncodeIfNecessary(q);
 			}
 			if (q) {
 				var pairs = q.substring(1).split("&");
 				for (var i = 0; i < pairs.length; i++) {
 					if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
 						return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
 					}
 				}
 			}
 			return "";
 		},

 		// For internal usage only
 		expressInstallCallback: function() {
 			if (isExpressInstallActive && storedAltContent) {
 				var obj = getElementById(EXPRESS_INSTALL_ID);
 				if (obj) {
 					obj.parentNode.replaceChild(storedAltContent, obj);
 					if (storedAltContentId) {
 						setVisibility(storedAltContentId, true);
 						if (ua.ie && ua.win) {
 							storedAltContent.style.display = "block";
 						}
 					}
 					storedAltContent = null;
 					storedAltContentId = null;
 					isExpressInstallActive = false;
 				}
 			}
 		}
 	};
 } ();

 
/**
* table content
* -----------------------------
* AjaxReq
* IframeShim
* Observer
* Overlay
* PopupPanel
* Tip
* Prompt
* Mbox
* Minput
* Mtab
* Calendar
* Datepicker
* Carousel
* Autocompleter

**/

/*
 * class AjaxReq
 *
    {
	   code:200,
	   msg:''
    }
 */

 var AjaxReq = new Class({
 	Implements: [Options, Events],
 	options: {
 		url: null,
 		method: 'get',
 		data: null,
 		headers: {},
 		async: true,
 		evalScripts: true,
 		secure: false,
 		update: false,
 		//custom options
 		callType: 'json',
 		timeOut: 30000,
 		onRequest: $empty,
 		onSuccess: $empty,
 		onError: $empty

 	},

 	initialize: function(options) {
 		this.setOptions(options);
 		var requestOptions = {
 			url: this.options.url,
 			method: this.options.method,
 			data: this.options.data,
 			headers: this.options.headers,
 			async: this.options.async,
 			evalScripts: this.options.evalScripts,
 			secure: this.options.secure,
 			update: this.options.update
 		};
 		requestOptions.onRequest = this.request.bind(this);
 		requestOptions.onSuccess = this.success.bind(this);
 		requestOptions.onFailure = requestOptions.onException = requestOptions.onCancel = this.error.bind(this);

 		switch (this.options.callType) {
 			case 'html': 
 				{
 					this.ajax = new Request.HTML(requestOptions); break;
 				}
 			case 'json': 
 				{
 					this.ajax = new Request.JSON(requestOptions);
 					this.ajax.headers.extend({ 'Accept': 'application/json, */*' });
 					break;
 				}
 		}
 		return this;
 	},
 	error: function() {
 		if (this.options.timeOut) $clear(this.options.timeOut);
 		this.fireEvent('error');
 		return this;
 	},
 	success: function(a, b, c, d) {
 		if (this.options.timeOut) $clear(this.options.timeOut);
 		if (this.options.callType == 'html') {
 			if (this.$events.success) {
 				this.fireEvent('success', [a, b, c, d]);
 			}
 		} else {
 			if (this.$events.success) {
 				this.fireEvent('success', [a, b]);
 			}
 		}
 		return this;
 	},
 	request: function() {
 		this.fireEvent('request');
 		return this;
 	},
 	send: function(options) {
 		this.options.timeOut = setTimeout(function() { this.ajax.cancel(); }.bind(this), this.options.timeOut);
 		this.ajax.send(options);
 	}
 });

 Request.Queue = new Class({

 	Implements: [Options, Events],

 	Binds: ['attach', 'request', 'complete', 'cancel', 'success', 'failure', 'exception'],

 	options: {/*
		onRequest: $empty(argsPassedToOnRequest),
		onSuccess: $empty(argsPassedToOnSuccess),
		onComplete: $empty(argsPassedToOnComplete),
		onCancel: $empty(argsPassedToOnCancel),
		onException: $empty(argsPassedToOnException),
		onFailure: $empty(argsPassedToOnFailure),*/
 		stopOnFailure: true,
 		autoAdvance: true,
 		concurrent: 1,
 		requests: {}
 	},

 	initialize: function(options) {
 		this.setOptions(options);
 		this.requests = new Hash;
 		this.addRequests(this.options.requests);
 		this.queue = [];
 		this.reqBinders = {};
 	},

 	addRequest: function(name, request) {
 		this.requests.set(name, request);
 		this.attach(name, request);
 		return this;
 	},

 	addRequests: function(obj) {
 		$each(obj, function(req, name) {
 			this.addRequest(name, req);
 		}, this);
 		return this;
 	},

 	getName: function(req) {
 		return this.requests.keyOf(req);
 	},

 	attach: function(name, req) {
 		if (req._groupSend) return this;
 		['request', 'complete', 'cancel', 'success', 'failure', 'exception'].each(function(evt) {
 			if (!this.reqBinders[name]) this.reqBinders[name] = {};
 			this.reqBinders[name][evt] = function() {
 				this['on' + evt.capitalize()].apply(this, [name, req].extend(arguments));
 			} .bind(this);
 			req.addEvent(evt, this.reqBinders[name][evt]);
 		}, this);
 		req._groupSend = req.send;
 		req.send = function(options) {
 			this.send(name, options);
 			return req;
 		} .bind(this);
 		return this;
 	},

 	removeRequest: function(req) {
 		var name = $type(req) == 'object' ? this.getName(req) : req;
 		if (!name && $type(name) != 'string') return this;
 		req = this.requests.get(name);
 		if (!req) return this;
 		['request', 'complete', 'cancel', 'success', 'failure', 'exception'].each(function(evt) {
 			req.removeEvent(evt, this.reqBinders[name][evt]);
 		}, this);
 		req.send = req._groupSend;
 		delete req._groupSend;
 		return this;
 	},

 	getRunning: function() {
 		return this.requests.filter(function(r) { return r.running; });
 	},

 	isRunning: function() {
 		return !!this.getRunning().getKeys().length;
 	},

 	send: function(name, options) {
 		var q = function() {
 			this.requests.get(name)._groupSend(options);
 			this.queue.erase(q);
 		} .bind(this);
 		q.name = name;
 		if (this.getRunning().getKeys().length >= this.options.concurrent || (this.error && this.options.stopOnFailure)) this.queue.push(q);
 		else q();
 		return this;
 	},

 	hasNext: function(name) {
 		return (!name) ? !!this.queue.length : !!this.queue.filter(function(q) { return q.name == name; }).length;
 	},

 	resume: function() {
 		this.error = false;
 		(this.options.concurrent - this.getRunning().getKeys().length).times(this.runNext, this);
 		return this;
 	},

 	runNext: function(name) {
 		if (!this.queue.length) return this;
 		if (!name) {
 			this.queue[0]();
 		} else {
 			var found;
 			this.queue.each(function(q) {
 				if (!found && q.name == name) {
 					found = true;
 					q();
 				}
 			});
 		}
 		return this;
 	},

 	runAll: function() {
 		this.queue.each(function(q) {
 			q();
 		});
 		return this;
 	},

 	clear: function(name) {
 		if (!name) {
 			this.queue.empty();
 		} else {
 			this.queue = this.queue.map(function(q) {
 				if (q.name != name) return q;
 				else return false;
 			}).filter(function(q) { return q; });
 		}
 		return this;
 	},

 	cancel: function(name) {
 		this.requests.get(name).cancel();
 		return this;
 	},

 	onRequest: function() {
 		this.fireEvent('request', arguments);
 	},

 	onComplete: function() {
 		this.fireEvent('complete', arguments);
 	},

 	onCancel: function() {
 		if (this.options.autoAdvance && !this.error) this.runNext();
 		this.fireEvent('cancel', arguments);
 	},

 	onSuccess: function() {
 		if (this.options.autoAdvance && !this.error) this.runNext();
 		this.fireEvent('success', arguments);
 	},

 	onFailure: function() {
 		this.error = true;
 		if (!this.options.stopOnFailure && this.options.autoAdvance) this.runNext();
 		this.fireEvent('failure', arguments);
 	},

 	onException: function() {
 		this.error = true;
 		if (!this.options.stopOnFailure && this.options.autoAdvance) this.runNext();
 		this.fireEvent('exception', arguments);
 	}

 });

 var IframeShim = new Class({
 	Implements: [Options, Events],
 	options: {
 		name: '',
 		className: 'iframeShim',
 		display: false,
 		zIndex: null,
 		margin: 0,
 		offset: {
 			x: 0,
 			y: 0
 		},
 		browsers: (Browser.Engine.trident4 || (Browser.Engine.gecko && !Browser.Engine.gecko19 && Browser.Platform.mac)),
 		onInject: $empty
 	},
 	initialize: function(element, options) {
 		this.setOptions(options);
 		//legacy
 		if (this.options.offset && this.options.offset.top) this.options.offset.y = this.options.offset.top;
 		if (this.options.offset && this.options.offset.left) this.options.offset.x = this.options.offset.left;
 		this.element = $(element);
 		this.makeShim();
 		return;
 	},
 	makeShim: function() {
 		this.shim = new Element('iframe');
 		this.id = this.options.name || new Date().getTime() + "_shim";
 		if (this.element.getStyle('z-Index').toInt() < 1 || isNaN(this.element.getStyle('z-Index').toInt()))
 			this.element.setStyle('z-Index', 999);
 		var z = this.element.getStyle('z-Index') - 1;

 		if ($chk(this.options.zIndex) && this.element.getStyle('z-Index').toInt() > this.options.zIndex)
 			z = this.options.zIndex;

 		this.shim.setStyles({
 			'position': 'absolute',
 			'zIndex': z,
 			'border': 'none',
 			'filter': 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'
 		}).setProperties({
 			'src': 'javascript:void(0);',
 			'frameborder': '0',
 			'scrolling': 'no',
 			'id': this.id
 		}).addClass(this.options.className);

 		this.element.store('shim', this);

 		var inject = function() {
 			this.shim.inject(document.body);
 			if (this.options.display) this.show();
 			else this.hide();
 			this.fireEvent('inject');
 		};
 		if (this.options.browsers) {
 			if (Browser.Engine.trident && !IframeShim.ready) {
 				window.addEvent('load', inject.bind(this));
 			} else {
 				inject.run(null, this);
 			}
 		}
 	},
 	position: function(obj) {
 		if (!this.options.browsers || !IframeShim.ready) return this;
 		if (obj) {
 			this.shim.setStyles({
 				width: obj.width,
 				height: obj.height,
 				top: obj.top,
 				left: obj.left
 			});
 		 }
 		else { 
 			var before = this.element.getStyles('display', 'visibility', 'position');
 			this.element.setStyles({
 				display: 'block',
 				position: 'absolute',
 				visibility: 'hidden'
 			});
 			var size = this.element.getSize();
 			var pos = this.element.getPosition();
 			this.element.setStyles(before);
 			if ($type(this.options.margin)) {
 				size.x = size.x - (this.options.margin * 2);
 				size.y = size.y - (this.options.margin * 2);
 				this.options.offset.x += this.options.margin;
 				this.options.offset.y += this.options.margin;
 			}

 			this.shim.setStyles({
 				width: size.x,
 				height: size.y,
 				top: pos.y,
 				left: pos.x
 			});
 		}
 		
 		return this;
 	},
 	hide: function() {
 		if (this.options.browsers) this.shim.setStyle('display', 'none');
 		return this;
 	},
 	show: function(obj) {
 		if (!this.options.browsers) return this;
 		this.shim.setStyle('display', 'block');
 		return this.position(obj);
 	},
 	dispose: function() {
 		if (this.options.browsers) this.shim.dispose();
 		return this;
 	}
 });
window.addEvent('load', function(){
	IframeShim.ready = true;
});



//overlay class
var Overlay = new Class({
	Implements: [Options, Events],
	getOptions: function() {
		return {
			useFx: false,
			name:'',
			duration: 200,
			colour: '#000',
			opacity: 0.2,
			zIndex: 99,
			hasShim: true,
			container: document.body,
			onClick: $empty
		};
	},

	initialize: function(options) {
		this.setOptions(this.getOptions(), options);
		this.options.container = $(this.options.container);

		this.container = new Element('div').setProperty('id', this.options.name+'_overlay').setStyles({
			position: 'absolute',
			left: '0',
			top: '0',
			width: '100%',
			height: '100%',
			backgroundColor: this.options.colour,
			zIndex: this.options.zIndex,
			opacity: this.options.opacity
		}).inject(this.options.container);


		if (this.options.hasShim) this.shim = new IframeShim(this.container);
		this.options.useFx ? this.fade = new Fx.Tween(this.container, { property: 'opacity', duration: this.options.duration }).set(0) : this.fade = null;
		this.container.setStyle('display', 'none');

		this.container.addEvent('click', function() {
			this.fireEvent('click');
		} .bind(this));

		window.addEvent('resize', this.position.bind(this));
		return this.position();
	},

	position: function() {
		if (this.options.container == document.body) {
			var h = window.getScrollHeight() + 'px';
			this.container.setStyles({ top: '0px', height: h });
		} else {
			var myCoords = this.options.container.getCoordinates();
			this.container.setStyles({
				top: myCoords.top + 'px',
				height: myCoords.height + 'px',
				left: myCoords.left + 'px',
				width: myCoords.width + 'px'
			});
		}
	},

	show: function() {
		this.container.setStyle('display', '');
		if (this.fade) this.fade.cancel().start(this.options.opacity);
		if (this.shim) this.shim.show();
		return this.position();
	},

	hide: function(dispose) {
		if (this.fade) this.fade.cancel().start(0);
		this.container.setStyle('display', 'none');
		if (this.shim) this.shim.hide();
		if (dispose) this.dispose();
		return this;
	},

	dispose: function() {
		this.container.dispose();
		if (this.shim) this.shim.dispose();
	}

});



/**
* Class PopupPanel 
* you should use this css to you panel
* { position:absolute; visibility:hidden}
*
**/

var PopupPanel = new Class({
	Implements: [Options, Events],
	options: {
		triger: 'mouseover',
		type: 'cling-left',
		adjust: { x: 20, y: 20 },
		useFx: false,
		effect: { property: 'opacity' },
		zIndex: 999,
		hasShim: true,
		onShow: $empty,
		onHide: $empty
	},
	initialize: function(trigger, panel, options) {
		this.setOptions(options);
		this.trigger = $(trigger);
		this.panel = $(panel).setStyles({ 'position': 'absolute', 'visibility': 'hidden' }).inject($(document.body));
		if (this.options.hasShim) this.shim = new IframeShim(this.panel);
		this.display = false;

		if (this.options.useFx) {
			this.fx = new Fx.Tween(this.panel, this.options.effect);
			this.fx.set(0);
		}

		if (this.options.triger == 'click') {
			this.trigger.addEvents({
				click: function() {
					this.display ? this.hide() : this.show();
				} .bind(this)
			});
			document.addEvent('mouseup', function(e) {
				if (e && this.display == true && this.panel != e.target && this.trigger != e.target) this.hide();
			} .bind(this));
		} else {
			this.trigger.addEvents({
				mouseenter: this.show.bind(this),
				mouseleave: this.hide.bind(this)
			});
			this.panel.addEvents({
				mouseenter: this.show.bind(this),
				mouseleave: this.hide.bind(this)
			});
		}

		window.addEvent('resize', this.position.bind(this));

		this.position();
		return this;
	},
	show: function() {
		this.display = true;
		if (this.fx) {
			this.fx.cancel().start(1);
		} else {
			this.panel.setStyle('visibility', 'visible');
		}

		if (this.shim) this.shim.show();
		this.fireEvent('onShow');
		return this.position();
	},
	hide: function() {
		this.display = false;
		if (this.fx) {
			this.fx.cancel().start(0);
		} else {
			this.panel.setStyle('visibility', 'hidden');
		}

		if (this.shim) this.shim.hide();
		this.fireEvent('onHide');
		return this;
	},
	position: function() {
		this.triggerCoo = this.trigger.getCoordinates();
		this.panelCoo = { 'z-index': this.options.zIndex, top: this.triggerCoo.bottom - 2 + 'px' };
		switch (this.options.type) {
			case 'side-right':
				$extend(this.panelCoo, { left: this.triggerCoo.right - 2 + 'px', top: this.triggerCoo.top + 'px' });
				break;
			case 'side-left':
				$extend(this.panelCoo, { right: window.getWidth().toInt() - this.triggerCoo.left - 2 + 'px', top: this.triggerCoo.top + 'px' });
				break;
			case 'cling-right':
				$extend(this.panelCoo, { right: window.getWidth().toInt() - this.triggerCoo.right + 'px' });
				break;
			case 'cling-left':
				$extend(this.panelCoo, { left: this.triggerCoo.left + 'px' });
				break;
			default:
				$extend(this.panelCoo, { left: this.triggerCoo.left + this.options.adjust.x + 'px', top: this.triggerCoo.top + this.options.adjust.y + 'px' });
		}
		this.panel.setStyles(this.panelCoo);
		if (this.shim) this.shim.position();
		return this;
	}
});

/**
* Class Tip 
* default----property:tip
* 
*
**/
var Tip=new Class({
    Implements: [Options, Events],
    options:{
        tipClass:null,
        adjust:{x:20,y:20},
		useFx: false,
		effect:{property:'opacity'},
		zIndex:999,
        fn:null,
        onShow:$empty,
        onHide:$empty
    },
    initialize:function(className,options){
        this.setOptions(options);
        this.build();
        if(this.options.useFx) {
			this.fx = new Fx.Tween(this.frame,this.options.effect);
			this.fx.set(0);
		}
        this.content=$$('.'+className);
        this.content.each(function(item){
            var self=item;
            item.addEvent('mouseover',function(e){
                this.show(e);
                if(this.options.fn){this.options.fn.call(this,self);}
                else{ this.getContent(self);}
            }.bind(this));
            
             item.addEvent('mouseout',function(e){
                this.hide(e);
            }.bind(this));
            
             item.addEvent('mousemove',function(e){
                this.locate(e);
            }.bind(this));
            
        }.bind(this));
    },
    build:function(){
        this.frame=new Element('div').setProperty('id','tipFrame').setStyles({visibility:'hidden',position:'absolute','z-index':this.options.zIndex});
        this.container=new Element('div').setProperty('id','tipContent').addClass(this.options.tipClass).inject(this.frame);
        this.frame.inject($(document.body));
    },
    getContent:function(ele){
        this.container.set('html','<p>'+ele.getProperty('tip')+'</p>');
    },
    locate:function(e){
        e=new Event(e);
        var pos= { x:e.page.x, y:e.page.y};
        this.frame.setStyles({top:pos.y+this.options.adjust.y,left:pos.x+this.options.adjust.x});
    },
    show: function(e) {
		(this.fx)?this.fx.cancel().start(1):this.frame.setStyle('visibility','visible');
	    this.locate(e);
		this.fireEvent('show');
	},
	hide: function() {
		(this.fx)?this.fx.cancel().start(0):this.frame.setStyle('visibility','hidden');
		this.fireEvent('hide');
	}
});



/*
* Prompt
*/
var Prompt = new Class({
	Implements: [Options, Events],
	getOptions: function() {
		return {
			name: 'dp',
			zIndex: 999,
			container: document.body,
			overlay: false,
			hasShim: true,
			closable: true,
			titleClass: 'DialogTitle',
			contClass: 'DialogContent',
			btnClass: 'DialogButtons',
			deftitle: '友情提示',
			initProperty: {
				'btnOk': '确定',
				'btnCancel': '取消',
				'boxStyle': null,
				'inputStyle': { 'display': 'block', 'margin': '0 auto 10px', 'width': '150px' },
				'btnStyle': { 'margin-right': '20px', 'width': '60px' },
				'promptValue': '',
				'overlay': true,
				'closable': true,
				'onClose': null,
				'onReturn': null
			},
			fn: $empty,
			onReturn: function(properties) {
				this.options.fn.call(this, this.value, properties);
			} .bind(this)

		};
	},

	initialize: function(options) {
		if (Prompt._instance) return Prompt._instance;
		Prompt._instance = this;
		this.setOptions(this.getOptions(), options);
		this.build();
		this.display = 0;
		//add esc key press event
		document.addEvent('keyup', function(e) { if (e.key == 'esc') { this.value = false; this.hide(); } } .bind(this));
		window.addEvents({
			resize: this.position.bind(this),
			scroll: this.position.bind(this)
		});
		return this;
	},

	build: function() {
		if (this.options.overlay && !this.overlay) this.overlay = new Overlay({ name: 'prompt', container: this.options.container, hasShim: this.options.hasShim });

		this.control = new Element('div', {
			'id': this.options.name + '-control',
			'class': this.options.btnClass
		});

		this.InBox = new Element('div', {
			'id': this.options.name + '-InBox',
			'class': this.options.contClass
		});

		this.title = new Element('p', {
			'id': this.options.name + '-title',
			'class': this.options.titleClass
		});


		this.closehandle = new Element('a', {
			'id': this.options.name + '-closehandle',
			'href': 'javascript:void(0)'
		}).addEvent('click', function() {
			this.value = false;
			this.hide();
		} .bind(this));


		this.Box = new Element('div', {
			'id': this.options.name + '-Box',
			'styles': {
				'width': '300px',
				'display': 'none',
				'z-index': this.options.zIndex,
				'position': 'absolute',
				'top': '0',
				'left': '0'
			}
		}).adopt([this.title, this.InBox, this.control, this.closehandle || null]);

		this.Box.inject(this.options.container);
	},

	alert: function(message, properties) {
		this.messageBox('alert', message, properties);
	},

	confirm: function(message, properties) {
		this.messageBox('confirm', message, properties);
	},

	prompt: function(message, properties) {
		this.messageBox('prompt', message, properties);
	},
	position: function() {
		if (this.display == 1) {
			var box = document.getSize(), scroll = document.getScroll();
			this.Box.setStyles({
				'left': (scroll.x + (box.x - this.Box.getStyle('width').toInt()) / 2).toInt(),
				'top': (scroll.y + (box.y - this.Box.offsetHeight) / 2).toInt()
			});
		}
		return this;
	},

	show: function(focus, properties) {
		if (this.display == 0) {
			this.display = 1;

			if (this.overlay && properties.overlay) this.overlay.show();

			(properties.closable && this.closehandle) ? this.closehandle.setStyle('display', '') : this.closehandle.setStyle('display', 'none');

			if (properties.boxStyle) this.Box.setStyles(properties.boxStyle);
			this.Box.setStyle('display', 'block');

			this.position();
			//this.fireEvent('onShow', [this.overlay || null]);
			//focus button
			focus.focus();
			return this;
		}

	},

	hide: function(properties) {
		var r = true;
		if (properties && properties.onClose) {
			r = properties.onClose.call(this);
			if (!r) return false;
		}
		if (this.display == 1) {
			this.display = 0;
			if (this.overlay) this.overlay.hide();
			this.Box.setStyles({
				'display': 'none',
				'top': 0
			});

			this.fireEvent('onReturn', [this.overlay || null]);
			return this;
		}

	},
	dispose: function() {
		this.Box.dispose();
		if (this.overlay) this.overlay.dispose();
		return this;
	},
	messageBox: function(type, message, properties) {
		properties = $merge(this.options.initProperty, properties || {});
		if (properties.overlay && !this.overlay) this.overlay = new Overlay({ name: 'prompt', container: this.options.container, hasShim: this.options.hasShim });
		properties.onReturn ? this.options.fn = properties.onReturn : this.options.fn = $empty;
		if ($type(message) != 'array') message = [this.options.deftitle, message];

		if (type == 'alert') {
			this.AlertBtnOk = new Element('input', {
				'id': 'alertOk',
				'type': 'submit',
				'value': properties.btnOk,
				'styles': properties.btnStyle
			});

			this.AlertBtnOk.addEvent('click', function() {
				this.value = true;
				this.hide(properties);
			} .bind(this));

			this.title.set('html', message[0]);
			this.InBox.set('html', message[1]);
			this.control.empty().grab(this.AlertBtnOk);

			this.show(this.AlertBtnOk, properties);
		}
		else if (type == 'confirm') {
			this.ConfirmBtnOk = new Element('input', {
				'id': 'confirmOk',
				'type': 'submit',
				'value': properties.btnOk,
				'styles': properties.btnStyle
			});

			this.ConfirmBtnCancel = new Element('input', {
				'id': 'confirmCancel',
				'type': 'submit',
				'value': properties.btnCancel,
				'styles': properties.btnStyle
			});

			this.ConfirmBtnOk.addEvent('click', function() {
				this.value = true;
				this.hide(properties);
			} .bind(this));

			this.ConfirmBtnCancel.addEvent('click', function() {
				this.value = false;
				this.hide();
			} .bind(this));
			this.title.set('html', message[0]);
			this.InBox.set('html', message[1]);
			this.control.empty().adopt([this.ConfirmBtnOk, this.ConfirmBtnCancel]);
			this.show(this.ConfirmBtnOk, properties);
		}
		else if (type == 'prompt') {
			this.PromptBtnOk = new Element('input', {
				'id': 'promptOk',
				'type': 'submit',
				'value': properties.btnOk,
				'styles': properties.btnStyle
			});

			this.PromptBtnCancel = new Element('input', {
				'id': 'promptCancel',
				'type': 'submit',
				'value': properties.btnCancel,
				'styles': properties.btnStyle
			});

			this.PromptInput = new Element('input', {
				'id': 'promptInput',
				'type': 'text',
				'value': properties.promptValue,
				'styles': properties.inputStyle
			});

			this.PromptBtnOk.addEvent('click', function() {
				this.value = this.PromptInput.value;
				this.hide(properties);
			} .bind(this));

			this.PromptBtnCancel.addEvent('click', function() {
				this.value = false;
				this.hide();
			} .bind(this));

			this.title.set('html', message[0]);
			this.InBox.set('html', message[1]);
			this.control.empty().adopt([this.PromptInput, this.PromptBtnOk, this.PromptBtnCancel]);

			this.show(this.PromptBtnOk, properties);
		}
		else {
			this.value = false;
			this.hide();
		}
	}
});



/**
* Class Mbox 
* 
* {type,url,size}
*
**/

var Mbox = {

	presets: {
		sizeLoading: { x: 180, y: 30 },
		sizeDefault: { x: 600, y: 450 },
		marginInner: { x: 20, y: 20 },
		marginImage: { x: 50, y: 75 },

		size: null,
		type: 'ele',
		url: false,

		winId: 'mbox-window',
		contId: 'mbox-content',
		closeId: 'mbox-btn-close',

		overlay: false,
		hasShim: true,
		overlayClosable: false,

		autoSize: false,
		reposition: true,
		closable: false,
		container: null,
		zIndex: 999,

		useFx: false,
		resizeFx: {},
		contentFx: {},

		parse: 'rel',
		parseSecure: false,
		ajaxOptions: {},

		onLoading: $empty,
		onOpen: $empty,
		onShow: $empty,
		onClosing: $empty,
		onClose: $empty
	},

	initialize: function(presets) {
		if (this.options) return this;

		this.options = {};
		this.setOptions(this.presets, presets || {}).build();

		this.bound = {
			window: this.reposition.bind(this, [null]),
			scroll: this.checkTarget.bind(this),
			close: this.close.bind(this),
			key: this.onKey.bind(this)
		};
		this.isOpen = this.isLoading = false;
		return this;
	},

	build: function() {
		this.overlay = new Overlay({ name: 'mbox', hasShim: this.options.hasShim, onClick: (this.options.overlayClosable) ? this.close.bind(this) : null });
		//please bulid three components:closeBtn,content,win
		this.closeBtn = new Element('a', { id: this.options.closeId, href: '#' });

		this.content = new Element('div', { id: this.options.contId, styles: { visibility: 'hidden'} });

		this.win = new Element('div', {
			id: this.options.winId,
			styles: { display: 'none', zIndex: this.options.zIndex + 2 }
		}).adopt(this.closeBtn, this.content);
		//if (Browser.Engine.trident4) this.win.addClass('mbox-window-ie6');

		if (this.options.useFx) {
			this.fx = {
				win: new Fx.Morph(this.win, $merge({

					unit: 'px',
					duration: 750,
					transition: Fx.Transitions.Quint.easeOut,
					link: 'cancel',
					unit: 'px'
				}, this.options.resizeFx)),
				content: new Fx.Tween(this.content, $merge({
					property: 'opacity',
					duration: 250,
					link: 'cancel'
				}, this.options.contentFx))
			};
		}

		$(document.body).adopt(this.win);
	},

	assign: function(to, options) {
		to.addEvent('click', function(e) {
			new Event(e).stop();
			Mbox.open(options, this);
		});
	},
	//1.支持事件
	//2.支持多种内容
	//3.支持tween
	open: function(options, from) {
		if (!options) return false;
		this.initialize(options);
		if (from) this.element = $(from); //for fix assign
		this.setOptions($merge({ overlay: true, closable: true, container: document }, options));
		if (this.element && this.options.parse) {
			var obj = this.element.getProperty(this.options.parse);
			if (obj && (obj = JSON.decode(obj, this.options.parseSecure))) this.setOptions(obj);
		}

		if (!this.isOpen) {
			this.isOpen = true;
			(this.options.closable) ? this.closeBtn.setStyle('display', '') : this.closeBtn.setStyle('display', 'none');
			if (this.overlay && this.options.overlay) this.overlay.show();
			this.toggleListeners(true);

			this.toggleLoading(true);
			this.fireEvent('onOpen', [this.content]);
			this.resize(true);
			this.load();
		}

		return this;
	},

	openLite: function(obj, width, height, options) {
		this.initialize(options);
		this.setOptions($merge({ overlay: true, closable: false, container: document }, options));

		if (obj) {
			width = width || 180;
			height = height || 30;
			(this.options.closable) ? this.closeBtn.setStyle('display', '') : this.closeBtn.setStyle('display', 'none');
			$type(obj) == 'string' ? this.content.set('html', obj) : this.content.empty().adopt(obj);
			this.win.setStyles({ 'width': (width + 'px'), 'height': (height == 'auto') ? height : (height + 'px') });
		}

		if (!this.isOpen) {
			this.isOpen = true;
			(this.options.closable) ? this.closeBtn.setStyle('display', '') : this.closeBtn.setStyle('display', 'none');
			if (this.overlay && this.options.overlay) this.overlay.show();
			this.toggleListeners(true);

			this.win.setStyle('display', '');
			(this.fx) ? this.fx.content.cancel().start(1) : this.content.setStyle('visibility', 'visible');
		}
		return this.reposition(true);
	},

	hide: function() {
		if (this.isOpen) {
			this.isOpen = false;
			if (this.overlay && this.options.overlay) this.overlay.hide();

			this.win.setStyle('display', 'none');
			(this.fx) ? this.fx.content.cancel().start(0) : this.content.setStyle('visibility', 'hidden');
			this.trash();
		}
		return this;
	},

	close: function(e) {
		if ($type(e) == 'event') new Event(e).stop();
		if (!this.isOpen) return this;
		this.fireEvent('onClosing', [this.content]);
		this.isOpen = false;
		if (this.overlay && this.options.overlay) this.overlay.hide();
		this.hideContent();
		this.win.setStyle('display', 'none');
		this.fireEvent('onClose', [this.content]);
		this.trash();
		return this;
	},

	trash: function() {
		if (this.element) this.element = null;
		this.asset = null;
		this.options = {};
		this.setOptions(this.presets);
		this.toggleListeners();
		this.removeEvents();
	},

	load: function() {
		this.getContent();
		if (this.options.autoSize) {
			switch (this.type) {
				case 'image':
					{
						new Asset.image(this.asset.url, { onload: function(ele) {

							var box = document.getSize(), size;
							box.x -= this.options.marginImage.x;
							box.y -= this.options.marginImage.y;
							size = { x: ele.width, y: ele.height };

							for (var i = 2; i--; ) {
								if (size.x > box.x) {
									size.y *= box.x / size.x;
									size.x = box.x;
								} else if (size.y > box.y) {
									size.x *= box.y / size.y;
									size.y = box.y;
								}
							}
							size.x = size.x.toInt();
							size.y = size.y.toInt();

							this.asset['url'] = ele.setProperties({ width: size.x, height: size.y });
							this.asset['size'] = size;
							this.resize();
						} .bind(this)
						});
						break;
					}
				case 'iframe':
					{
						var iframeOptions = { src: this.asset.url };
						iframeOptions.onload = function(d) {
							var scroll = d.getScrollSize();
							this.asset['size'] = { x: scroll.x, y: scroll.y };
							this.resize();
						} .bind(this);
						new IFrame(iframeOptions).inject(this.content);
						break;
					}
				case 'string': case 'ajax':
					{
						this.handlers[this.type].call(this);
						this.asset['size'] = this.content.getScrollSize();
						this.resize();
						break;
					}
				case 'swf': case 'ele':
					{
						this.resize();
						break;
					}
			}
		} else {
			this.resize();
		}
	},

	onError: function() {
		this.asset = null;
		this.content.set('text', 'Error during loading');
	},

	getContent: function() {
		this.asset = {};
		this.asset.size = this.options.size || this.options.sizeDefault;
		if (this.options.type) {
			this.type = this.options.type;
			this.asset.url = this.options.url;

		} else {

			this.asset.url = this.element.getProperty('href');
			this.parsers.some(function(parser, key) {
				var content = parser.call(this);

				if (content) {
					this.type = key;
					this.asset.url = content;
					return true;
				}
				return false;
			}, this);
		}
		this.content.className = this.options.contId + '-' + this.type;
		return this;

	},

	resize: function(init) {
		var box = document.getSize(), scroll = document.getScroll();
		this.size = init ? this.options.sizeLoading : this.asset.size;
		var left = (scroll.x + (box.x - this.size.x - this.options.marginInner.x) / 2).toInt(), top = (scroll.y + (box.y - this.size.y - this.options.marginInner.y) / 2).toInt();
		var to = {
			width: this.size.x,
			height: this.size.y,
			left: (left >= 0) ? left : 0,
			top: (top >= 0) ? top : 20
		};
		if (init) {
			this.content.empty().setStyle('visibility', 'hidden');
			this.win.setStyles(to).setStyle('display', '');
		} else {
			if (this.fx) {
				this.fx.win.cancel().start(to).chain(function() { this.applyContent() } .bind(this));
			} else {
				this.win.setStyles(to);
				this.applyContent();
			}

		}

		return this.reposition(true);
	},

	reposition: function(init) {
		if (!init && !this.options.reposition) return this;
		var size = this.options.container.getSize(), scroll = this.options.container.getScroll(), pos = this.options.container.getPosition(), c = this.win.offsetHeight < size.y;

		this.win.setStyles({
			left: ((this.options.container == document ? scroll.x : pos.x) + (size.x - this.win.offsetWidth) / 2).toInt() + 'px',
			top: (c) ? ((this.options.container == document ? scroll.y : pos.y) + (size.y - this.win.offsetHeight) / 2).toInt() + 'px' : (scroll.y + 100).toInt() + 'px'
		});
		window[c ? 'addEvent' : 'removeEvent']('scroll', this.bound.window);
		return this;
	},

	applyContent: function() {
		if (this.isLoading) this.toggleLoading(false);
		this.content.empty();
		this.handlers[this.type].call(this);
		this.showContent();
		return this;
	},

	toggleListeners: function(state) {
		var fn = (state) ? 'addEvent' : 'removeEvent';
		this.closeBtn[fn]('click', this.bound.close);
		document[fn]('keydown', this.bound.key);
		window[fn]('resize', this.bound.window)[fn]('scroll', this.bound.window);
	},

	toggleLoading: function(state) {
		this.isLoading = state;
		this.win[(state) ? 'addClass' : 'removeClass']('mbox-loading');
		if (state) this.fireEvent('onLoading', [this.win]);
	},

	showContent: function() {
		(this.fx) ? this.fx.content.cancel().start(1) : this.content.setStyle('visibility', 'visible');
		this.fireEvent('onShow', [this.win]);
	},

	hideContent: function() {
		if (this.fx) {
			this.fx.content.cancel().start(0).chain(function() { this.content.empty() } .bind(this));
		} else {
			this.content.setStyle('visibility', 'hidden');
			this.content.empty();
		}
	},

	onKey: function(e) {
		switch (e.key) {
			case 'esc': if (this.options.closable) this.close(e);
			case 'up': case 'down': return false;
		}
	},

	checkTarget: function(e) {
		return this.content.hasChild(e.target);
	},

	removeEvents: function(type) {
		if (!this.$events) return this;
		if (!type) this.$events = null;
		else if (this.$events[type]) this.$events[type] = null;
		return this;
	},

	extend: function(properties) {
		return $extend(this, properties);
	},

	handlers: new Hash(),

	parsers: new Hash()

};

Mbox.extend(new Events).extend(new Options);

Mbox.parsers.extend({

	image: function(preset) {
		return (preset || (/\.(?:jpg|png|gif|bmp)$/i).test(this.asset.url)) ? this.asset.url : false;
	},
	swf: function(preset) {
		return (preset || this.asset.url.test(/\.swf/) || true) ? this.asset.url : false;
	}
});

Mbox.handlers.extend({

	image: function() {
		this.content.adopt(typeof this.asset.url == 'string' ? new Element('img', { src: this.asset.url }) : this.asset.url );
	},
	swf: function() {
		var swf = new Swiff(this.asset.url, {
			id: 'mbox-swf',
			width: this.asset.size.x,
			height: this.asset.size.y
		});
		this.content.adopt(swf);
	},
	string: function() {
		this.content.set('html', this.asset.url);

	},
	ele: function() {
		this.content.grab($(this.asset.url));
	},

	ajax: function() {
		new Request.HTML($merge({
			method: 'get',
			update: this.content
		}, this.options.ajaxOptions)).addEvents({
			onFailure: this.onError.bind(this)
		}).send({ url: this.asset.url });
	},

	iframe: function() {
		var iframe = new Element('iframe', {
			src: this.asset.url,
			frameBorder: 0,
			width: this.asset.size.x,
			height: this.asset.size.y
		});
		this.content.adopt(iframe);
	}

});




/**
* Class Minput
* 
* 
*
**/

var Minput = {

	presets: {
		openwidth: 26,
		zIndex: 9,
		checkboxClass: 'minputCheckbox',
		radioboxClass: 'minputRadiobox',
		hiddenClass: 'minputHidden',
		checkedClass: 'minputChecked',
		selectwrapClass: 'minputWrapper',
		selectcontClass: 'minputContent',
		selectopenClass: 'minputOpen'
	},

	initialize: function(presets) {
		if (this.options) return this;
		this.options = {};
		this.setOptions($merge(this.presets, presets));
	},
	checkbox: function(ele, options) {
		this.options = $merge(this.options, options || {});
		if ($$(ele).length != 0) {
			ele.each(function(item, index) {
				var minput = item;
				var mlabel = (item.getParent().tagName.toLowerCase() == 'label') ? item.getParent() : null;

				var subs = new Element('a').addClass(this.options.checkboxClass).inject(minput, 'after');
				minput.addClass(this.options.hiddenClass);
				$$(subs, mlabel).addEvent('click', function() {
					if (minput.checked === true) {
						minput.checked = false;
						subs.removeClass(this.options.checkedClass);
					}
					else {
						minput.checked = true;
						subs.addClass(this.options.checkedClass);
					}
					return false;
				} .bind(this));
				if (minput.checked) { subs.addClass(this.options.checkedClass); }
			}, this);
		}
		return this;

	},
	radiobox: function(ele, options) {
		this.options = $merge(this.options, options || {});
		if ($$(ele).length != 0) {
			ele.each(function(item, index) {
				var minput = item;
				var mlabel = (item.getParent().tagName.toLowerCase() == 'label') ? item.getParent() : null;

				var subs = new Element('a').addClass(this.options.radioboxClass).setProperty('rel', minput.name).inject(minput, 'after');
				minput.addClass(this.options.hiddenClass);
				$$(subs, mlabel).addEvent('click', function() {
					minput.checked = true;
					subs.addClass(this.options.checkedClass);
					$$('a[rel="' + subs.getProperty("rel") + '"]').erase(subs).each(function(item) {
						item.removeClass(this.options.checkedClass);
						item.getPrevious().checked = false;
					}, this);
					return false;
				} .bind(this));
				if (minput.checked) { subs.addClass(this.options.checkedClass); }
			}, this);
		}
		return this;
	},

	selectbox: function(ele, options) {
		this.options = $merge(this.options, options || {});
		var self = this;
		if ($$(ele).length != 0) {
			ele.each(function(item, index) {

			var $select = item;
				var $width = $select.getSize().x+(options.adjustWidth||0);
				$select.addClass(this.options.hiddenClass);

				var $wrapper = new Element('div').addClass(this.options.selectwrapClass).setStyle('z-index', this.options.zIndex).set('html', '<div><span class="' + this.options.selectcontClass + '"></span><a href="javascript:void(0)" onfocus="this.blur()" class="' + this.options.selectopenClass + '"></a></div><ul></ul>');
				$wrapper.getElement('.' + this.options.selectcontClass).setStyle('width', $width - this.options.openwidth + 'px');

				var $ul = $wrapper.getElement('ul').setStyles({ 'width': $width + 'px', 'z-index': this.options.zIndex + 1, 'display': 'none' });

				$select.getElements('option').each(function(item, index) {
					new Element('li').set('html', '<a href="javascript:void(0)" index="' + index + '">' + item.get('text') + '</a>').inject($ul);
				});
				$wrapper.inject($select, 'after');

				$ul.getElements('a').addEvent('click', function(e) {
					$ul.getElements('a.selected').removeClass('selected');
					$(this).addClass('selected');
					$wrapper.getElement('.' + self.options.selectcontClass).set('html', $(this).get('html'));
					$ul.setStyle('display', 'none');
					$select.selectedIndex = $(this).getProperty('index');
					var evt;
					document.all ? $select.fireEvent('change') : (evt = document.createEvent('HTMLEvents'), evt.initEvent('change', true, true), $select.dispatchEvent(evt));
					return false;
				});

				$ul.getElements('a')[$select.selectedIndex].fireEvent('click');

			}, this);


			/*bind open event */
			$$('a.' + this.options.selectopenClass).addEvent('click', function(e) {
				var $ul = $(this).getParent().getNext();
				if ($ul.getStyle('display') == 'none') { hideSelect(); $ul.setStyle('display', 'block'); }
				else { $ul.setStyle('display', 'none'); }
				return false;
			});


			/* Hide all open selects */
			var hideSelect = function() {
				$$('.' + self.options.selectwrapClass + ' ul').setStyle('display', 'none');
			};

			/* Check for an external click */
			var checkExternalClick = function(e) {
				if ($(e.target).getParents('.' + self.options.selectwrapClass).length === 0) { hideSelect(); }
			};

			/* Apply document listener */
			document.addEvent('mousedown', checkExternalClick);
		}

		return this;
	},
	reset: function(form) {
		$(form).addEvent('reset', function() { var action = function() { this._reset(form); } .bind(this); setTimeout(action, 10); } .bind(this));
	},
	_reset: function(f) {
		var sel;
		$(f).getElements('select').each(function(item) {
			if (item.getNext().hasClass(this.options.selectwrapClass)) {
				sel = (item.selectedIndex < 0) ? 0 : item.selectedIndex;
				item.getNext().getElements('ul a').each(function(sitem, index) {
					if (index == sel) sitem.fireEvent('click');
				});
			}
		});
		$(f).getElements('a.' + this.options.checkboxClass + ',a.' + this.options.radioboxClass).removeClass(this.options.checkedClass);
		$(f).getElements('input[type="checkbox"],input[type="radio"]').each(function(item) { if (item.checked) { item.getNext().addClass(this.options.checkedClass); } }, this);
	},
	extend: function(properties) {
		return $extend(this, properties);
	}
};
Minput.extend(new Events).extend(new Options);


/**
* Class Mtab 
* use li(data) == panel(id)
* 
*
**/

var Mtab = new Class({
	
	initialize: function(element, options) {
		this.options = $merge({
			tabClass:{width:'500px',height:	'250px'},
			useFx:{transition:Fx.Transitions.Bounce.easeOut,property:'height'},
			//duration:1000,
			//mouseOverClass:'active',
			activeClass:'active',
			panelClass:'mtabPanel',
			show:0,//index
			useAjax: 	false,
			ajaxOptions: {method:'get',url:''},
			ajaxCache:{},
			ajaxLoadingText:'Loading...'
		}, options || {});
		
		this.el = $(element);
		this.elid = element;
		
		this.el.setStyles(this.options.tabClass);
		this.ajaxCache=new Hash(this.options.ajaxCache);
		//console.log(this.ajaxCache);
		this.titles = $$('#' + this.elid + ' ul li');
		//this.panelHeight = this.el.getSize().y - (this.titles[0].getSize().y + 4);
		this.panels = $$('#' + this.elid + ' .'+this.options.panelClass);

		//this.panels.setStyle('height', this.panelHeight);
		
		this.titles.each(function(item) {
			item.addEvent('click', function(e){
					//item.removeClass(this.options.mouseOverClass);
					
					if(item != this.activeTitle)this.activate(item);
					
				}.bind(this)
			);
		
		}.bind(this));
		
		
		if(this.options.show != 'none') this.activate(this.titles[this.options.show]);
		
	},
	
	activate: function(tab){
	
		if($type(tab) == 'string') 
		{
			myTab = $$('#' + this.elid + ' ul li').filter('[data='+tab+']')[0];
			tab = myTab;
		}
		
		if($type(tab) == 'element')
		{
			var newTab = tab.getProperty('data');
			this.panels.removeClass(this.options.activeClass);
			this.activePanel = this.panels.filter('#'+newTab)[0];
			this.activePanel.addClass(this.options.activeClass);
			
			if(this.options.useFx)
			{
				//this.panels.filter('#'+newTab).setStyle('height', 0);
				var changeEffect = new Fx.Tween(this.activePanel, $merge({duration:1000},this.options.useFx));
				changeEffect.start(20,this.activePanel.getSize().y);
			}
			
			this.titles.removeClass(this.options.activeClass);
			this.activeTitle = tab;
			tab.addClass(this.options.activeClass);
			
			if(this.options.useAjax)
			{
				this._getContent();
			}
		}
	},
	
	_getContent: function(){
	    var tab=this.activeTitle.getProperty('data');
	    var updateEle=this.activePanel;
		this.activePanel.set('html',this.options.ajaxLoadingText);
		// console.log(this.ajaxCache);
		if(this.ajaxCache.has(tab)){updateEle.set('html',this.ajaxCache.get(tab)); return false;}
		
		this.ajaxOptions = $merge(this.options.ajaxOptions,{
		    update: updateEle,
		    url:this.options.ajaxOptions.url+ '?tab='+tab,
		    onComplete:function(a,b,c,d){
		        this.ajaxCache.set(tab,c);
		       
		    }.bind(this)
		 });
		var tabRequest = new Request.HTML(this.ajaxOptions).send();
		
	},
	
	add: function(title, label, content){
		//the new title
		var newTitle = new Element('li', {
			'data': title
		});
		newTitle.appendText(label);
		this.titles.include(newTitle);
		$$('#' + this.elid + ' ul').adopt(newTitle);
		newTitle.addEvent('click', function() {
			if(newTitle != this.activeTitle)this.activate(newTitle);
		}.bind(this));
		
		
		//the new panel
		var newPanel = new Element('div', {
			//'style': {'height': this.options.panelHeight},
			'id': title,
			'class': this.options.panelClass
		});
		
		if(!this.options.useAjax)
		{
		    //this.ajaxCache.set(title,content);
			newPanel.set('html',content);
		}
		this.panels.include(newPanel);
		this.el.adopt(newPanel);
	},
	
	remove: function(title){
		if(this.activeTitle.title == title)
		{
			this.activate(this.titles[0]);
		}
		$$('#' + this.elid + ' ul li').filter('[data='+title+']')[0].dispose();
		
		$$('#' + this.elid + ' .'+this.options.panelClass).filter('#'+title)[0].dispose();
	},
	
	next: function(){
		var nextTab = this.activeTitle.getNext();
		if(!nextTab) {
			nextTab = this.titles[0];
		}
		this.activate(nextTab);
	},
	
	previous: function(){
		var previousTab = this.activeTitle.getPrevious();
		if(!previousTab) {
			previousTab = this.titles[this.titles.length - 1];
		}
		this.activate(previousTab);
	}
});


/**
* Class Calendar
*
* 
*
**/

var Calendar = new Class({
	Implements: [Options, Events],
	options: {
		initDate: new Date(),
		monthText: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
		weekText: ['日', '一', '二', '三', '四', '五', '六'],
		range: [new Date(1949, 0, 1), new Date(2015, 0, 1)],
		display: true,
		hasShim: false,
		onSelect: $empty
	},
	initialize: function(cal, options) {
		this.setOptions(options);
		this.container = $(cal);
		if (this.options.hasShim) this.shim = new IframeShim(this.container);
		this.initDate = this.options.initDate;
		this.init(this.container, this.initDate);
		this.display = this.options.display;
		(this.display) ? this.show() : this.hide();
	},
	init: function(cal, date) {

		cal.set('html', '');
		var month = this.MonthInfo(date.getFullYear(), date.getMonth());
		cal.addClass("mcalendar");

		var yearStr = [];
		yearStr.push("<li class='mcalendar_logo'></li>");
		yearStr.push("<li class='mcalendar_year'><a href='#' cal='year' year='" + date.getFullYear() + "'>" + date.getFullYear() + "年</a></li>");
		yearStr.push("<li class='mcalendar_month'><a href='#' cal='month' month='" + date.getMonth() + "'>" + this.options.monthText[date.getMonth()] + "</a></li>");
		var year = new Element('ul').set('html', yearStr.join(''));


		var todayStr = [];
		todayStr.push("<li><a href='#' cal='preyear' title='preyear'> << </a></li>");
		todayStr.push("<li><a href='#' cal='preweek' title='preweek'> < </a></li>");
		todayStr.push("<li class='mcalendar_today'><a href='#' cal='today'>今天</a></li>");
		todayStr.push("<li><a href='#' cal='nextweek' title='nextweek'> > </a></li>");
		todayStr.push("<li><a href='#' cal='nextyear' title='nextyear'> >> </a></li>");
		var today = new Element('ul').set('html', todayStr.join(''));


		var weekStr = []
		for (i = 0; i < 7; i++) {
			weekStr.push("<li class='mcalendar_week'>" + this.options.weekText[i] + "</li>");
		}
		var week = new Element('ul').set('html', weekStr.join(''));
		cal.adopt(year, today, week);

		for (i = 0; i < 6; i++) {
			var days = new Element('ul');

			for (var j = 0; j < 7; j++) {
				var d = 7 * i - month.firstDay + j + 1;
				var css = d == date.getDate() ? "class='mcalendar_selected'" : "";
				if (d > 0 && d <= month.days) {
					var curd = new Date(date.getFullYear(), date.getMonth(), d);
					if (curd >= this.options.range[0] && curd <= this.options.range[1]) {

						days.grab(new Element('li').set('html', "<a href='#' " + css + " year='" + date.getFullYear() + "' month='" + date.getMonth() + "' date='" + d + "'>" + d + "</a>"));
					} else {
						days.grab(new Element('li').addClass('mcalendar_outrange').set('html', d));
					}
				} else {

					days.grab(new Element('li').addClass('mcalendar_invalid').set('html', '&nbsp;'));
				}
			}

			cal.adopt(days);
		};


		cal.getElements("a").addEvent('focus', function() { this.blur() });



		cal.getElements("a").addEvent('click', function(e) {
			var self = new Event(e).target;
			if ($(self).getProperty("cal") == "today") {
				this.init(cal, new Date());
				this.fireEvent('select', [new Date()]);

			}
			else if ($(self).getProperty("cal") == "preyear") {
				date.setFullYear(date.getFullYear() - 1);
				this.init(cal, date);
			}
			else if ($(self).getProperty("cal") == "nextyear") {
				date.setFullYear(date.getFullYear() + 1);
				this.init(cal, date);
			}
			else if ($(self).getProperty("cal") == "preweek") {
				date.setMonth(date.getMonth() - 1);
				this.init(cal, date);
			}
			else if ($(self).getProperty("cal") == "nextweek") {
				date.setMonth(date.getMonth() + 1);
				this.init(cal, date);
			}
			else if ($(self).getProperty("cal") == "year") {
				var year = new Element('select').setStyle('width',  '60px');
				var selected = $(self).getProperty('year');
				for (var i = this.options.range[0].getFullYear(); i <= this.options.range[1].getFullYear(); i++) {

					year.grab(new Element('option').setProperty('value', i).set('html', i));
				}
				year.addEvent('change', function(e) {
					var self = new Event(e).target;
					date.setFullYear(self.value);
					this.init(cal, date);
				} .bind(this));
				year.setProperty('value', selected);
				year.replaces($(self));

			}
			else if ($(self).getProperty("cal") == "month") {
				var mon = new Element('select').setStyle('width', '60px');
				var selected = $(self).getProperty('month');
				for (i = 0; i < 12; i++) {
					mon.grab(new Element('option').setProperty('value', i).set('html', this.options.monthText[i]));
				}
				mon.addEvent('change', function(e) {
					var self = new Event(e).target;
					date.setMonth(self.value);
					this.init(cal, date);
				} .bind(this));

				mon.setProperty('value', selected);
				mon.replaces($(self));

			}
			else {
				cal.getElement(".mcalendar_selected").removeProperty("class");
				self.className = "mcalendar_selected";
				this.fireEvent('select', [new Date($(self).getProperty("year"), $(self).getProperty("month"), $(self).getProperty("date"))]);

			}
			return false;
		} .bind(this));
	},
	MonthInfo: function(y, m) {
		var monthDays = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		var d = (new Date(y, m, 1));
		d.setDate(1);
		if (d.getDate() == 2) d.setDate(0);
		y += 1900;
		return {
			days: m == 1 ? (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0) ? 29 : 28) : monthDays[m],
			firstDay: d.getDay()
		};
	},
	show: function() {
		this.display = true;
		this.container.setStyle('display', '');
		if (this.shim) this.shim.show();
	},
	hide: function() {
		this.display = false;
		this.container.setStyle('display', 'none');
		if (this.shim) this.shim.hide();
	},
	dispose: function() {
		this.container.empty();
		if (this.shim) this.shim.dispose();
	}


});


/**
* Class datepicker
*
* 
*
**/

var Datepicker = new Class({
	Implements: [Options],
	options: {
		initDate: "",
		hasShim: false,
		monthText: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
		weekText: ["日", "一", "二", "三", "四", "五", "六"],
		range: [new Date(1970, 0, 1), new Date(2015, 0, 1)],
		splitChar: "-"
	},
	initialize: function(ele, dateinput, options) {
		this.setOptions(options);
		this.calendar = null;
		this.container = null;
		this.ele = $(ele);
		this.ele.addEvent('click', function(e) {
			if (this.calendar) { this.calendar.display ? this.calendar.hide() : this.calendar.show(); return; }
			var self = new Event(e).target;
			if (!this.container) this.container = new Element('div').setProperty('id', $time() + '_date');

			var offset = $(self).getCoordinates();
			this.container.setStyles({
				position: "absolute",
				left: offset.left,
				top: offset.bottom
			});
			$(document.body).grab(this.container);

			var initdate = new Date();

			this.calendar = new Calendar(this.container, {
				initDate: initdate,
				range: this.options.range,
				monthText: this.options.monthText,
				weekText: this.options.weekText,
				hasShim: this.options.hasShim,
				onSelect: function(date) {
					dateinput.value = date.getFullYear() + this.options.splitChar + (date.getMonth() + 1) + this.options.splitChar + date.getDate();
					this.calendar.hide();
				} .bind(this)
			});


		} .bind(this));

		document.addEvent('mousedown', this.insideSelector.bind(this));

	},
	insideSelector: function(e) {
		if ($(e.target).getParents('.mcalendar').length === 0 && e.target !== this.ele && this.calendar) this.calendar.hide();
	},

	dispose: function() {
		if (this.calendar) this.calendar.dispose();
	}
});





/**
* Class Carousel
* <div class="carousel">
     <div class="previous" id="wp">
    </div>
    <div class="next" id="wn">
    </div>
    <div class="clip">
        <ul class="cont" id="wcont">
        <li class="item"><img src="/s/fimg/1.jpg" /></li>
        <li class="item"><img src="/s/fimg/2.jpg" /></li>
        <li class="item"><img src="/s/fimg/3.jpg" /></li>
        <li class="item"><img src="/s/fimg/4.jpg" /></li>
        <li class="item"><img src="/s/fimg/5.jpg" /></li>
        <li class="item"><img src="/s/fimg/6.jpg" /></li>
        </ul>
    </div>
</div>
* for imanual :data={currentPos:0,img:[{src:'/s/fimg/1.jpg',href:'/'},{src:'/s/fimg/2.jpg',href:'/'},{src:'/s/fimg/3.jpg',href:'/'},{src:'/s/fimg/4.jpg',href:'/'},{src:'/s/fimg/5.jpg',href:'/'},{src:'/s/fimg/6.jpg',href:'/'}]}
* for manual : data=1(currentPos)
**/
var Carousel = new Class({
	Implements: [Events, Options],
	options: {
		type: "auto", // auto || slide || manual ||imanual
		idContent: null,
		idPrevious: null,
		idNext: null,

		klass: "item",
		size: 100, //move size;imgSize:64,
		interval: 3000,
		direction: "left", // set: top || left
		slideCount: 1,

		//if type=auto suppose pause ,please set above
		idPause: null,
		playClass: 'play',

		//custom setting
		showCount: 3, //type=[manual,imanual]
		autoFx: {}, //type=[auto,slide,manual]
		itemFx: {}, //type=[imanual]
		unableClass: 'unable', //type=[manual,imanual]
		selectClass:'sitem',
		itemHTML: '<p><a href="{0}"><img src="{0}" style="width:100px; height:75px" /></a></p>',

		onPrevious: $empty,
		onNext: $empty,
		onGo: $empty
	},

	initialize: function(options, data) {
		this.setOptions(options);
		this.container = $(this.options.idContent);
		(arguments.length > 1) ? this.data = data : this.data = null;
		this.aItems = $A(this.container.getElements('.' + this.options.klass));
		this.fx = new Fx.Morph(this.container, $merge({ duration: 500, transition: Fx.Transitions.Cubic.easeInOut, wait: false }, this.options.autoFx));
		this.isMouseOver = false;

		if (this.options.idPrevious != null)
			$(this.options.idPrevious).addEvent("click", function(event) {
				var e = new Event(event).stop();
				if (!$(e.target).hasClass(this.options.unableClass)) {
					if (this.options.idPause != null) {
						$(this.options.idPause).removeClass(this.options.playClass).fireEvent('click');
					}
					this._previous();
				}

			} .bind(this));
		if (this.options.idNext != null)
			$(this.options.idNext).addEvent("click", function(event) {
				var e = new Event(event).stop();
				if (!$(e.target).hasClass(this.options.unableClass)) {
					if (this.options.idPause != null) {
						$(this.options.idPause).removeClass(this.options.playClass).fireEvent('click');
					}
					this._next();
				}

			} .bind(this));


		switch (this.options.type) {
			case 'auto':
				{
					(2).times(function() {
						this.aItems.each(function(item) {
							item.clone().inject(this.container);
						} .bind(this));
					} .bind(this));
					this.aItems = $A(this.container.getElements('.' + this.options.klass));

					if (this.options.idPause == null) {
						this.aItems.each(function(item) {
							item.addEvents({
								"mouseenter": function() {
									this.isMouseOver = true;
									this.timer = $clear(this.timer);
								} .bind(this),
								"mouseleave": function() {
									this.isMouseOver = false;
									this.timer = this._autoRotate.periodical(this.options.interval, this);
								} .bind(this)
							});
						} .bind(this));
					} else {
						$(this.options.idPause).addEvent("click", function(event) {
							$(this.options.idPause).toggleClass(this.options.playClass);
							if (this.options.type == "auto" && !$(this.options.idPause).hasClass(this.options.playClass)) {
								this.timer = this._autoRotate.periodical(this.options.interval, this);
							} else {
								if (this.options.type == "auto") this.timer = $clear(this.timer);
							}

						} .bind(this));
					}

					this.atScreen = this.aItems.length / 3;
					this.container.setStyle(this.options.direction, -this.atScreen * this.options.size);
					this.timer = this._autoRotate.periodical(this.options.interval, this);


					break;
				}
			case 'slide':
				{
					this.atScreen = 0;
					this.container.setStyle(this.options.direction, -this.atScreen * this.options.size);
					break;
				}
			case 'manual':
				{

					this.currentPos = this.data.toInt();
					this.imgArray = $A(this.container.getElements('.' + this.options.klass));
					this.dataLength = this.imgArray.slice(this.currentPos, this.currentPos + this.options.showCount + 1).length;
					this._animate(this.currentPos);
					this._check();
					break;
				}
			case 'imanual':
				{
					this.defaultPos = this.data.currentPos.toInt();
					this.currentPos = this.data.currentPos.toInt();
					this.imgArray = this.data.img;
					this._showImg(this.currentPos, this.options.showCount);
					break;
				}

		}


	},


	go: function(n) {

		this.atScreen = Math.abs(n % (this.aItems.length));
		this._animate(this.atScreen);

		this.fireEvent("onGo", this, 20);
		return this;
	},

	_previous: function() {
		switch (this.options.type) {
			case 'auto':
				{
					this.atScreen -= this.options.slideCount;
					if (this.atScreen < this.aItems.length / 3) {
						this.container.setStyle(this.options.direction, -this.options.size * this.aItems.length * 2 / 3);
						this.atScreen = this.aItems.length * 2 / 3 - this.options.slideCount;
					}
					this._animate(this.atScreen);
					this.fireEvent("onPrevious", this, 20);

					break;
				}
			case 'slide':
				{

					break;
				}
			case 'manual':
				{
					(this.currentPos -= this.options.slideCount, (this.currentPos < 0) ? this.currentPos = 0 : this.currentPos = this.currentPos);
					this.dataLength = this.imgArray.slice(this.currentPos, this.currentPos + this.options.showCount + 1).length;
					this._animate(this.currentPos);
					this._check();

					this.fireEvent("onPrevious", this, 20);
					break;
				}
			case 'imanual':
				{
					(this.currentPos -= this.options.slideCount, (this.currentPos < 0) ? this.currentPos = 0 : this.currentPos = this.currentPos);
					this._showImg(this.currentPos, this.options.showCount);

					this.fireEvent("onPrevious", this, 20);
					break;
				}

		}


	},

	_next: function() {
		switch (this.options.type) {
			case 'auto':
				{
					this.atScreen += this.options.slideCount;

					if (this.atScreen > this.aItems.length * 2 / 3) {
						this.container.setStyle(this.options.direction, -this.options.size * this.aItems.length / 3);
						this.atScreen = this.aItems.length / 3 + this.options.slideCount;
					}
					this._animate(this.atScreen);
					this.fireEvent("onNext", this, 20);

					break;
				}
			case 'slide':
				{

					break;
				}
			case 'manual':
				{
					this.currentPos += this.options.slideCount;
					this.dataLength = this.imgArray.slice(this.currentPos, this.currentPos + this.options.showCount + 1).length;
					this._animate(this.currentPos);
					this._check();

					this.fireEvent("onNext", this, 20);
					break;
				}
			case 'imanual':
				{
					this.currentPos += this.options.slideCount;
					this._showImg(this.currentPos, this.options.showCount);

					this.fireEvent("onNext", this, 20);
					break;
				}

		}

	},

	_showImg: function(pos, count) {
		var html = [], pos0, pos1, pos2;
		var dataArray = this.imgArray.slice(pos, pos + count + 1);
		this.dataLength = dataArray.length;
		var temp = this.options.itemHTML.split('{0}');
		pos0 = temp[0];
		pos1 = temp[1];
		pos2 = temp[2];
		dataArray.each(function(item, index) {
			html.push('<li class="' + this.options.klass + '">' + pos0 + item.href + pos1 + item.src + pos2 + '</li>');
		}, this);
		this.container.set('html', html.join(''));
		this._check();
		return this;

	},

	_check: function() {
		if ($(this.options.idPrevious).hasClass(this.options.unableClass)) $(this.options.idPrevious).removeClass(this.options.unableClass);
		if ($(this.options.idNext).hasClass(this.options.unableClass)) $(this.options.idNext).removeClass(this.options.unableClass);

		if (this.currentPos == 0) {
			$(this.options.idPrevious).addClass(this.options.unableClass);
		}
		if (this.dataLength <= this.options.showCount) {
			$(this.options.idNext).addClass(this.options.unableClass);
		}
		if ((this.currentPos <= this.defaultPos) && (this.defaultPos < this.currentPos + this.options.showCount)) {
			this.container.getElements('li')[this.defaultPos - this.currentPos].className = this.options.selectClass;
		}


	},

	_autoRotate: function() {
		if (!this.isMouseOver) this._next();
	},

	_animate: function(a) {
		var that = this;
		if (that.options.direction == "top") {
			that.fx.start({ "top": -a * that.options.size });
		} else {
			that.fx.start({ "left": -a * that.options.size });
		}

	},

	_animateImg: function(next, pos) {
		this.itemFx = new Fx.Tween(this.container.getFirst(), $merge({ duration: 100, transition: Fx.Transitions.Quad.easeOut, wait: false }, this.options.itemFx));
		(next) ? this.itemFx.start((this.options.direction == "left") ? 'width' : 'height', [this.options.size, 1]).chain(function() { this._showImg(pos, this.options.showCount) } .bind(this)) : this.itemFx.start((this.options.direction == "left") ? 'width' : 'height', [1, this.options.size]);

	}
});



/**
* Class Autocompleter
*
* required （Observer）
*
**/
Element.implement({

	getOffsetParent: function() {
		var body = this.getDocument().body;
		if (this == body) return null;
		if (!Browser.Engine.trident) return $(this.offsetParent);
		var el = this;
		while ((el = el.parentNode)){
			if (el == body || Element.getComputedStyle(el, 'position') != 'static') return $(el);
		}
		return null;
	},

	getCaretPosition: function() {
		if (!Browser.Engine.trident) return this.selectionStart;
		this.focus();
		var work = document.selection.createRange();
		var all = this.createTextRange();
		work.setEndPoint('StartToStart', all);
		return work.text.length;
	},

	selectRange: function(start, end) {
		if (Browser.Engine.trident) {
			var range = this.createTextRange();
			range.collapse(true);
			range.moveEnd('character', end);
			range.moveStart('character', start);
			range.select();
		} else {
			this.focus();
			this.setSelectionRange(start, end);
		}
		return this;
	}

});


var Autocompleter = new Class({

	Implements: [Options, Events],

	options: {
		enable: true,
		minLength: 1,
		width: 'inherit',
		height: 'auto',
		adjust: { x: 0, y: 0 },
		maxChoices: 10,
		className: 'autocompleter',
		selectClass: 'ac_select',
		closeClass: 'ac_close',
		zIndex: 999,
		delay: 200,
		observerOptions: {},
		fxOptions: {},
		extraParams: {},
		autoSubmit: true,
		autoTrim: true,
		autoClose: true,
		filter: null,
		parser: null,
		selectMode: true,
		wordSync: true,
		multiple: false,
		separatorSplit: ',',
		isfix: false,
		filterSubset: false,
		filterCase: false,
		listCloseBtn: true,
		onSelection: $empty,
		onShow: $empty,
		onHide: $empty,
		onBlur: $empty,
		onFocus: $empty
	},

	initialize: function(element, url, options) {
		this.element = $(element);
		this.setOptions(options);
		this.build();
		this.observer = new Observer(this.element, this.fetch.bind(this), $merge({
			'delay': this.options.delay
		}, this.options.observerOptions));
		this.queryValue = null;
		if (this.options.filter) this.filter = this.options.filter.bind(this);
		this.selectMode = this.options.selectMode;
		this.enable = this.options.enable;
		this.extraParams = this.options.extraParams;
		($type(url) === 'array') ? this.remote = false : this.remote = true;
		this.cached = false;
		this.cacheStatus = 'loading';
		this.url = url;

	},

	build: function() {

		this.choices = new Element('ul', {
			'class': this.options.className,
			'styles': {
				'zIndex': this.options.zIndex,
				'position': 'absolute'
			}
		}).inject(document.body);

		if (this.options.isfix) this.fix = new IframeShim(this.choices);

		this.fx = (!this.options.fxOptions) ? null : new Fx.Tween(this.choices, $merge({
			'property': 'opacity',
			'link': 'cancel',
			'duration': 200
		}, this.options.fxOptions)).addEvent('onStart', Chain.prototype.clearChain).set(0);

		this.element.setProperty('autocomplete', 'off')
			.addEvent('keyup', this.onCommand.bind(this))
			.addEvent('focus', this.toggleFocus.create({ bind: this, arguments: true, event: true }))
			.addEvent('blur', this.toggleFocus.create({ bind: this, arguments: false, event: true }));

		this.choices.onmousedown = function() {
			return false;
		};
	},

	destroy: function() {
		if (this.fix) this.fix.dispose();
		this.choices = this.selected = this.choices.destroy();
	},

	toggleFocus: function(e, state) {
		e.stop();
		this.focussed = state;
		if (!this.focussed) { if (this.options.autoClose) this.hideChoices(true); }
		else this.prefetch();
		this.fireEvent((state) ? 'onFocus' : 'onBlur', [this.element]);
	},

	onCommand: function(e) {
		if (e && e.key && !e.shift) {
			switch (e.key) {
				case 'enter':
					e.stop();
					//if (this.element.value != this.opted) return true;
					if (this.selected && this.visible) {
						this.choiceSelect(this.selected);
						return !!(this.options.autoSubmit);
					}
					break;
				case 'up': case 'down':
					if (this.visible && this.queryValue !== null) {
						var up = (e.key == 'up');
						//set close button
						if (this.selected && this.selected.getNext().hasClass(this.options.closeClass)) up ? this.choiceOver(this.selected.getPrevious(), true) : this.choiceOver(this.choices.getFirst(), true);
						//end
						else {
							this.choiceOver((this.selected || this.choices)[
							        (this.selected) ? ((up) ? 'getPrevious' : 'getNext') : ((up) ? 'getLast' : 'getFirst')
						        ](), true);
						}

					}
					return false;
				case 'esc': case 'tab':
					this.hideChoices(true);
					break;
			}
		}
		return true;
	},

	prefetch: function() {
		if (this.cacheStatus == 'loaded') return true;
		if (!this.remote) {

			this.cached = this.url;
			this.cacheStatus = 'loaded';
		} else {
			//		    this.ajaxReq= new AjaxReq({url:this.url,callType:'json',onSuccess:function(a,b){
			//		                this.cached= a;
			//		                this.update(this.cached.msg.shop);
			//		    }.bind(this)});

			this.cached = [];
			this.cacheStatus = 'loaded';
		}
	},

	fetch: function() {
		if (!this.enable) return false;
		if (this.cacheStatus != 'loaded') return false;
		var value = this.element.value, query = value, index = 0;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			var values = value.split(split);
			index = this.element.getCaretPosition();
			var toIndex = value.substr(0, index).split(split);
			var last = toIndex.length - 1;
			index -= toIndex[last].length;
			query = values[last];
		}

		if (query.length < this.options.minLength) {
			this.hideChoices();
		}
		else {
			this.queryIndex = index;
			if ((JSON.encode(this.extraParams) === this.queryExtraParams && query === this.queryValue) || (this.visible && query == this.selectedValue)) {
				if (this.visible) return false;
				this.showChoices();
			} else {
				this.queryExtraParams = JSON.encode(this.extraParams);
				this.queryValue = query;
				if (this.remote) {
					this.makeUrl();
					this.ajaxReq = new AjaxReq({ url: this.makeUrl(), callType: 'json', onSuccess: function(a, b) {
						this.cached = a;
						var parserData = this.options.parser(this.cached);
						if ($type(parserData) == "array") {
							this.update(parserData);
						}
						else if ($type(parserData.data) == "array" && parserData.more) {
							this.update(parserData.data, parserData.more);
						}
					} .bind(this)
					});
					//this.ajaxReq.send({url:this.url+'?q='+this.queryValue});
					this.ajaxReq.send();
				} else {
					this.update(this.filter(this.cached));
				}

			}
		}
		return true;

	},

	makeUrl: function() {
		var url = this.url + "?q=" + encodeURIComponent(this.queryValue);
		for (var i in this.extraParams) {
			url += "&" + i + "=" + encodeURIComponent(this.extraParams[i]);
		}
		return url;
	},

	filter: function(tokens) {
		var regex = new RegExp(((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp(), (this.options.filterCase) ? '' : 'i');
		var result = [];
		(tokens || this.tokens).each(function(item) {
			if (regex.test(item)) result.push(item);
		}, this);
		return result;
	},


	setSelection: function(finish) {
		var input = this.selectedValue, value = input;
		if (!input) return false;
		var start = this.queryValue.length, end = input.length;

		if (input.substr(0, start).toLowerCase() != this.queryValue.toLowerCase()) start = 0;
		if (this.options.multiple) {
			var split = this.options.separatorSplit;
			value = this.element.value;
			start += this.queryIndex;
			end += this.queryIndex;
			var old = value.substr(this.queryIndex).split(split, 1)[0];

			value = value.substr(0, this.queryIndex) + input + value.substr(this.queryIndex + old.length);
			if (finish) {
				var space = /[^\s,]+/;

				var tokens = [];
				value.split(this.options.separatorSplit).each(function(item) {
					if (space.test(item)) tokens.push(item);
				}, this);

				var sep = this.options.separatorSplit;
				value = tokens.join(sep) + sep;
				end = value.length;
			}
		}

		if (this.options.wordSync) this.observer.setValue(value);
		this.opted = value;

		if (finish) start = end;
		this.element.selectRange(start, end);
		//fix autoSubmit
		var selIndex = this.selected.getElement('span').get('html');
		var selText = value;
		if (this.options.autoSubmit && finish) this.fireEvent('onSelection', [this.element, this.selected, selIndex, selText]);
	},

	showChoices: function() {
		var first = this.choices.getFirst(), last = this.choices.getLast(), styles;
		if (!first || this.visible) return;
		var pos = this.element.getCoordinates(), width = this.options.width || 'auto';


		if ($type(this.options.height) === 'number') {
			(last.getCoordinates(this.choices).bottom > this.options.height) ? styles = { 'overflow-y': 'scroll', 'height': this.options.height} : styles = { 'overflow-y': 'hidden', 'height': this.options.height };
		} else {
			styles = { 'overflow-y': 'hidden', 'height': this.options.height };
		}
		styles = $merge(styles, {
			'left': pos.left + this.options.adjust.x,
			'top': pos.bottom + this.options.adjust.y,
			'width': (width === true || width == 'inherit') ? pos.width : width
		});

		if (!this.visible) {
			this.visible = true;
			this.choices.setStyles(styles);
			this.fx ? this.fx.start(1) : this.choices.setStyle('visibility', 'visible');
			if (this.fix) this.fix.show();
			this.fireEvent('onShow', [this.element, this.choices]);
		}

	},

	hideChoices: function(clear) {
		if (clear) {
			var value = this.element.value;
			if (this.options.autoTrim) {
				value = value.split(this.options.separatorSplit).filter($arguments(0)).join(this.options.separatorSplit);
			}
			this.observer.setValue(value);
		}
		if (!this.visible) return;
		this.visible = false;
		this.observer.clear();
		var hide = function() {
			this.choices.setStyle('visibility', 'hidden');
			if (this.fix) this.fix.hide();
		} .bind(this);
		this.fx ? this.fx.start(0).chain(hide) : hide();
		this.fireEvent('onHide', [this.element, this.choices]);
	},



	update: function(tokens, more) {
		this.choices.empty();
		if (this.selected) this.selected = this.selectedValue = null;

		if (!tokens || !tokens.length) {
			this.hideChoices();
		} else {
			if (this.options.maxChoices < tokens.length) tokens.length = this.options.maxChoices;
			tokens.each(function(token) {
				var item = token.split('|');
				var choice = new Element('li', { 'html': this.markQueryValue(item) });
				choice.inputValue = item[0];
				this.addChoiceEvents(choice).inject(this.choices);
			}, this);
			//set close button
			if (more && more.text && more.link) {
				var moreBtn = new Element('a').addClass("BL").setProperty('href', more.link).set('html', more.text);
				var moreLi = new Element('li');
				moreLi.grab(moreBtn);
				moreLi.inject(this.choices);
			}

			if (this.options.listCloseBtn) {
				var closeBtn = new Element('a').addClass("BL").setStyle('margin-left', '8px').setProperty('href', '#').set('html', '关闭').addEvent('click', function() { this.hideChoices(true); return false; } .bind(this));
				var closeLi = new Element('li').addClass(this.options.closeClass);
				closeLi.grab(closeBtn);
				closeLi.inject(this.choices);
			}
			//end
			this.showChoices();
		}
	},
	markQueryValue: function(item) {
		return (item.length == 1) ? item[0] : '<span style="float:right;display:none;">' + item[1] + '</span>' + item[0];
	},

	addChoiceEvents: function(el) {
		return el.addEvents({
			'mouseover': this.choiceOver.bind(this, [el]),
			'click': this.choiceSelect.bind(this, [el])
		});
	},
	choiceOver: function(choice, selection) {
		if (!choice || choice == this.selected) return;
		if (this.selected) this.selected.removeClass(this.options.selectClass);
		this.selected = choice.addClass(this.options.selectClass);
		this.fireEvent('onSelect', [this.element, this.selected, selection]);
		if (!selection) return;
		if (this.selectMode) {
			this.selectedValue = this.selected.inputValue;
			this.setSelection();
		}

	},

	choiceSelect: function(choice) {
		if (choice) this.choiceOver(choice);
		this.selectedValue = this.selected.inputValue;
		this.setSelection(true);
		this.queryValue = null;
		this.hideChoices();
	}

});


var Observer = new Class({

	Implements: [Options, Events],

	options: {
		periodical: false,
		delay: 1000
	},

	initialize: function(el, onFired, options){
		this.setOptions(options);
		this.addEvent('onFired', onFired);
		this.element = $(el) || $$(el);
		this.boundChange = this.changed.bind(this);
		this.resume();
	},

	changed: function() {
		var value = this.element.get('value');	
		if ((this.value == value || JSON.encode(this.value) == JSON.encode(value))) return;
		this.clear();
		this.value = value;
		this.timeout = this.onFired.delay(this.options.delay, this);
	},

	setValue: function(value) {
		this.value = value;
		this.element.set('value', value);
		return this.clear();
	},

	onFired: function() {
		this.fireEvent('onFired', [this.value, this.element]);
	},

	clear: function() {
		$clear(this.timeout || null);
		return this;
	},
	pause: function(){
		$clear(this.timeout);
		$clear(this.timer);
		this.element.removeEvent('keyup', this.boundChange);
		return this;
	},
	resume: function(){
		this.value = this.element.get('value');
		if (this.options.periodical) this.timer = this.changed.periodical(this.options.periodical, this);
		else this.element.addEvent('keyup', this.boundChange);
		return this;
	}

});
