/* 
	The basic OOP functions
*/
var start = (new Date()).getTime();
var virtual = function (){
	throw("Invoking abstract method");
};
var Interface = function (obj){
	var inter = function (){
		throw("Instantiating interface");
	};
	for (var x in obj){
		inter[x] = obj[x];
	}
	return inter;
};
Interface.extend = function (){
	var _sub = function (){
		throw("Instantiating interface");
	};
	for (var i = 0, l = arguments.length; i < l - 1; i++){
		var inter = arguments[i];
		for (var x in inter)
			_sub[x] = inter[x];
	}
	var obj = arguments[arguments.length - 1];
	for (var x in obj)
		_sub[x] = obj[x];
	return _sub;
};
var Class = function (obj){
	var _class = function (){
		for (var x in this){
			if (this[x] == virtual)
				throw("Instantiating abstract class, you need to implement " + x);
		}
		if (typeof this.__construct != "undefined")
			this.__construct.apply(this, arguments);
	};
	_class.implement = function (inter, obj){
		for (var x in inter){
			if (x != "prototype")
				_class.prototype[x] = inter[x];
		}
		for (var x in obj)
			_class.prototype[x] = obj[x];
	}
	_class.hasImplemented = function (){
		for (var i = 0, l = arguments.length; i < l; i++){
			for (var x in arguments[i]){
				if (x != "prototype" && ! _class.prototype[x] || _class.prototype[x] == virtual){
					return false;
				}
			}
		}
		return true;
	}
	if (typeof obj.statics != "undefined"){
		for (var x in obj.statics){
			_class[x] = obj.statics[x];
		}
		obj.statics = null;
		delete obj.statics;
	}
	_class.prototype = {
		__eventListeners: 0,

		addEventListener: function (evt, fn, scope, once){
			var event = {
				type: evt,
				fn: fn,
				scope: scope,
				once: once
			};
			if (type(this.__eventListeners) != "array")
				this.__eventListeners = new Array();
			this.__eventListeners.push(event);
			return this;
		},
		on: function (evt, fn, scope, once){
			var event = {
				type: evt,
				fn: fn,
				scope: scope,
				once: once
			};
			if (type(this.__eventListeners) != "array")
				this.__eventListeners = new Array();
			this.__eventListeners.push(event);
			return this;
		},
		fireEvent: function (evt, data){
			if (type(this.__eventListeners) != "array")
				return this;
			var ret;
			if (type(data) != "array")
				data = [data];
			this.__eventListeners.each(function (v){
				if (v.type == evt && ret !== false){
					ret = v.fn.apply(v.scope, data);
					if (v.once){
						this.__eventListeners = this.__eventListeners.remove(v);
					}
				}
			}, this);
			return ret;
		},
		removeEventListener: function (evt, fn){
			if (type(this.__eventListeners) != "array")
				this.__eventListeners = new Array();
			this.__eventListeners.each(function (v){
				if (v.type == evt && v.fn == fn){
					this.__eventListeners = this.__eventListeners.remove(v);
				}
			}, this);
			return this;
		},
		removeAllEventListeners: function (evt){
			if (type(this.__eventListeners) != "array")
				this.__eventListeners = new Array();
			this.__eventListeners.each(function (v){
				if (v.type == evt)
					this.__eventListeners = this.__eventListeners.remove(v);
			}, this);
			return this;
		}
	};
	for (var x in obj){
		_class.prototype[x] = obj[x];
	}
	return _class;
};
Class.extend = function (base, obj){
	var _sub = function (){
		if (typeof this.__construct != "undefined")
			this.__construct.apply(this, arguments);
		this.parent = base.prototype;
	};
	for (var x in base.prototype){
		_sub.prototype[x] = base.prototype[x];
	}
	for (var x in obj){
		_sub.prototype[x] = obj[x];
	}
	return _sub;
};
Class.mixin = function (base, obj){
	for (var x in obj){
		base[x] = obj[x];
	}
	return base;
};

/*
	extending the prototype of basic data type
*/
Class.mixin(Array.prototype, {
	each: function (fn, scope, ex){
		for (var i = 0, l = this.length; i < l; i++)
			fn.call(scope, this[i], i, ex);
		return this;
	},
	filter: function (fn, scope){
		var r = [];
		if (type(fn) == "string"){
			var q = fn;
			fn = function (item, idx){
				if (q == "odd") return (! (idx % 2));
				else if (q == "even") return (idx % 2);
				else return (q == idx);
			}
		}
		for (var i = 0, l = this.length; i < l; i++){
			if (fn.call(scope, this[i], i))
				r[r.length] = this[i];
		}
		return r;
	},
	map: function (fn, scope){
		var r = [];
		for (var i = 0, l = this.length; i < l; i++)
			r[r.length] = fn.call(scope, this[i], i);
		return r;
	},
	first: function (){
		if (this.length)
			return this[0];
	},
	last: function (){
		if (this.length)
			return this[this.length - 1];
	},
	find: function (item){
		for (var i = 0, l = this.length; i < l; i++){
			if (this[i] == item)
				return i;
		}
		return false;
	},
	exist: function (item){
		return (this.find(item) !== false);
	},
	unique: function (){
		var r = [];
		for (var i = 0, l = this.length; i < l; i++){
			if (! r.exist(this[i]))
				r[r.length] = this[i];
		}
		return r;
	},
	union: function (ar){
		return this.concat(ar).unique();
	},
	remove: function (){
		var r = [];
		if (type(arguments[0]) == "array")
			arguments = arguments[0];
		for (var i = 0, l = this.length; i < l; i++){
			var found = false;
			for (var j = 0, m = arguments.length; j < m; j++){
				if (arguments[j] == this[i]){
					found = true;
					break;
				}
			}
			if (! found)
				r[r.length] = this[i];
		}
		return r;
	}
});
Class.mixin(String.prototype, {
	trim: function (){
		return this.replace(/^\s+|\s+$/g, "");
	},
	upperFirstLetter: function (){
		return this.replace(/\b[a-z]/g, function(match){
			return match.toUpperCase();
		});
	},
	insert: function (idx, str){
		if (idx >= 0){
			while (idx > this.length)
				idx -= (this.length + 1);
		}else{
			do{
				idx += this.length;
			}while (idx < 0);
		}
		return this.substring(0, idx) + str + this.substring(idx);
	},
	toInteger: function (){
		return parseInt(this);
	},
	toFloat: function (){
		return parseFloat(this);
	},
	ljust: function (len, str){
		if (type(str) == "undefined" || str == "")
			str = " ";
		var sl = str.length;
		var r = this;
		var t = len - r.length;
		while (t > 0){
			r += (t > sl ? str : str.substr(0, t));
			t = len - r.length;
		}
		return r;
	},
	rjust: function (len, str){
		if (type(str) == "undefined" || str == "")
			str = " ";
		var sl = str.length;
		var r = this;
		var t = len - r.length;
		while (t > 0){
			r = (t > sl ? str : str.substr(0, t)) + r;
			t = len - r.length;
		}
		return r;
	},
	repeat: function (time){
		var r = "";
		for (var i = 0; i < time; i++)
			r += this;
		return r;
	},
	toCamel: function (){
		var a = this.split("-");
		var r = a[0];
		for (var i = 1, al = a.length; i < al; i++)
			r += a[i][0].toUpperCase() + a[i].substring(1);
		return r;
	},
	strToURI: function (){
		return encodeURIComponent(this);
	},
	uriToStr: function (){
		return decodeURIComponent(this);
	}
});
Class.mixin(Number.prototype, {
	toFloor: function (){
		return Math.floor(this);
	},
	toCeil: function (){
		return Math.ceil(this);
	},
	toRound: function (){
		return Math.round(this);
	},
	limit: function (min, max){
		if (this < min)
			return min;
		if (this > max)
			return max;
		return this;
	},
	toFormat: function ( decimals, dec_point, thousands_sep ) {
		var n = this, c = isNaN(decimals = Math.abs(decimals)) ? 0 : decimals;
		var d = type(dec_point) == "undefined" ? "." : dec_point;
		var t = type(thousands_sep) == "undefined" ? "," : thousands_sep, s = n < 0 ? "-" : "";
		var i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;

		return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
	},
	toInteger: function (){
		return parseInt(this);
	},
	toFloat: function (){
		return parseFloat(this);
	}
});
Class.mixin(Function.prototype, {
	startTimer: function (interval, duration){
		this._timer = setInterval(this, interval);
		var a = this._timer;
		if (type(duration) == "number"){
			setTimeout(function (){
				clearInterval(a);
			}, duration);
		}
		return this;
	},
	stopTimer: function (){
		if (type(this._timer) != "undefined")
			clearInterval(this._timer);
		return this;
	},
	once: function (timeout){
		setTimeout(this, timeout);
		return this;
	}
});
Class.mixin(Date.prototype, {
	getDayOfYear: function (){
		var onejan = new Date(this.getFullYear(),0,1);
		return Math.ceil((this - onejan) / 86400000);
	},
	getDayOfWeekLong: function (){
		var weekDayLong = {
			0: "Sunday",
			1: "Monday",
			2: "Tuesday",
			3: "Wednesday",
			4: "Thursday",
			5: "Friday",
			6: "Saturday"
		};
		return weekDayLong[this.getDay()];
	},
	getDayOfWeekShort: function (){
		return this.getDayOfWeekLong().substr(0, 3);
	},
	getSuffixOfDay: function (){
		var monthDay = this.getDate();
		var suffixOfDay = "th";
		if (monthDay / 10 != 1){
			if (monthDay % 10 == 1)
				suffixOfDay = "st";
			else if (monthDay % 10 == 2)
				suffixOfDay = "nd";
			else if (monthDay % 10 == 3)
				suffixOfDay = "rd";
		}
		return suffixOfDay;
	},
	getWeekOfYear: function (){
		var onejan = new Date(this.getFullYear(),0,1);
		return Math.ceil((((this - onejan) / 86400000) + onejan.getDay())/7);
	},
	getMonthLong: function (){
		var monthLong = {
			0: "January",
			1: "February",
			2: "March",
			3: "April",
			4: "May",
			5: "June",
			6: "July",
			7: "August",
			8: "September",
			9: "October",
			10: "November",
			11: "December"
		};
		return monthLong[this.getMonth()];
	},
	getWeekInMonth: function (){
		var t = new Date(this.getFullYear(), this.getMonth());
		return Math.ceil((this.getDate() + t.getDay()) / 7);
	},
	getMonthShort: function (){
		return this.getMonthLong().substr(0, 3);
	},
	getDaysInMonth: function (){
		var month = this.getMonth() + 1;
		var year = this.getFullYear();
		var m = [31,28,31,30,31,30,31,31,30,31,30,31];
		if (month != 2) return m[month - 1];
		if (year%4 != 0) return m[1];
		if (year%100 == 0 && year%400 != 0) return m[1];
		return m[1] + 1;
	},
	getMeridiem: function (){
		return (this.getHours() < 13 ? "am" : "pm");
	},
	getHourInTwelve: function (){
		var hour = this.getHours();
		return (hour > 12 ? hour - 12 : (hour == 0 ? 12 : hour));
	},
	getSwatch: function (){
		return (((this.getTime()/86400000)%1)+(1/24)).toString().substring(2,5);
	},
	isLeapYear: function (){
		return new Date(this.getFullYear(), 2-1, 29).getDate() == 29;
	},
	toFormat: function (format){
		//http://www.php.net/manual/en/function.date.php
		//timezone and full date/time not implemented yet
		var t = "";
		var skip = false;
		
		var weekDay = this.getDay();
		var monthDay = this.getDate();
		var month = this.getMonth();
		var hour = this.getHours();
		var minute = this.getMinutes();
		var second = this.getSeconds();
		
		for (var i = 0, l = format.length; i < l; i ++){
			if (! skip){
				if (format[i] == "%"){
					skip = true;
				}else{
					var a = format.charAt(i);
					switch (a){
						case "d":
							t += (""+monthDay).rjust(2, "0");
						break;
						case "D":
							t += this.getDayOfWeekShort();
						break;
						case "j":
							t += monthDay;
						break;
						case "l":
							t += this.getDayOfWeekLong();
						break;
						case "N":
							t += weekDay;
						break;
						case "S":
							t += this.getSuffixOfDay();
						break;
						case "w":
							t += weekDay;
						break;
						case "z":
							t += this.getDayOfYear();
						break;
						case "W":
							t += this.getWeekOfYear();
						break;
						case "F":
							t += this.getMonthLong();
						break;
						case "m":
							t += (""+ (month + 1)).rjust(2, "0");
						break;
						case "M":
							t += this.getMonthShort();
						break;
						case "n":
							t += (month + 1);
						break;
						case "t":
							t += this.getDaysInMonth();
						break;
						case "L":
							t += (this.isLeapYear() ? 1 : 0);
						break;
						case "o":
							t += this.getFullYear();
						break;
						case "Y":
							t += this.getFullYear();
						break;
						case "y":
							t += (""+this.getFullYear()).substr(2);
						break;
						case "a":
							t += this.getMeridiem();
						break;
						case "A":
							t += this.getMeridiem().toUpperCase();
						break;
						case "B":
							t += this.getSwatch();
						break;
						case "g":
							t += this.getHourInTwelve();
						break;
						case "G":
							t += hour;
						break;
						case "h":
							t += (""+this.getHourInTwelve()).rjust(2,"0");
						break;
						case "H":
							t += (""+hour).rjust(2,"0");
						break;
						case "i":
							t += (""+minute).rjust(2,"0");
						break;
						case "s":
							t += (""+second).rjust(2,"0");
						break;
						case "u":
							t += this.getMilliseconds();
						break;
						default:
							t += a;
						break;
					}
				}
			}else{
				t += format[i];
				skip = false;
			}
		}		
		return t;
	}
});

/*
	Defining the mix class
	the browser class (static)
*/
var mix = Class({});
Class.mixin(mix, {
	version: "0.1",

	browser: {
		IE: 1,
		Opera: 2,
		Webkit: 3,
		Gecko: 4,
		MobileSafari: 5,
	
		isIE: (!!(window.attachEvent && !window.opera)),
		isOpera: (!! window.opera),
		isWebkit: (navigator.userAgent.indexOf('AppleWebKit/') > -1),
		isGecko: (navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1),
		isMobileSafari: (!!navigator.userAgent.match(/Apple.*Mobile.*Safari/)),
	
		getCoreType: function (){
			if (!!(window.attachEvent && !window.opera)){
				return this.IE;
			}else if (!! window.opera){
				return this.Opera;
			}else if (navigator.userAgent.indexOf('AppleWebKit/') > -1){
				return this.WebKit;
			}else if (navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1){
				return this.Gecko;
			}else if (!!navigator.userAgent.match(/Apple.*Mobile.*Safari/)){
				return this.MobileSafari;
			}
		},
		getBaseUrl: function (){
			var url = location.pathname;
			url = url.split("/");
			var a = url.pop();
			if (a == "")
				a = "index.php";
			return a;
		}
	}
});

/*
	validation class (static)
*/
Class.mixin(mix, {
	validation: {
		getType: function (el){
			if (typeof el == "object"){
				if (el == null)
					return "null";
				if (el.slice && el.shift)
					return "array";
				else if (el.nodeName)
					return "element";
				else if (el._type == "mixelements")
					return "mixelements";
				else
					return "object";
			}else{
				return typeof el;
			}
		},
		isEmail: function (email){
			var regex = /^[a-z0-9][a-z0-9-_.]*@[a-z0-9][a-z0-9-_]*\.[a-z0-9-_.]*[a-z]$/i;
			return regex.test(String(email));
		},
		isUrl: function (url){
			var regex = /(https|http|ftp|rtsp|mms)?:\/\/([-\w\.]+)+(:\d+)?(\/([\w/_\.]*(\?\S+)?)?)?/;
			return regex.test(String(url));
		}
	}
})

Class.mixin(mix, {
	elements: Class({
		//methods to get and filter mixelements
		_elList: "",
		_type: "mixelements",
		
		__construct: function(el){
			if (type(this._elList) != "array")
				this._elList = [];
			if (type(el) == "string"){
				var t = el.charAt(0);
				if (t == ".")
					this.gClass(el.substr(1));
				else if (t == "$")
					this.gGroup(el.substr(1));
				else if (t== "#")
					this.gId(el.substr(1));
				else if (t == "@")
					this.gMix(el.substr(1));
				else
					this.gTagName(el);
			}else{
				this.gEl(el);
			}
			return this;
		},
		gLength: function (){
			if (type(this._elList) != "array")
				this._elList = [];
			return this._elList.length;
		},
		gEl: function (el){
			this._elList = [];
			if (type(el) != "undefined")
				this._elList[0] = el;
			return this;
		},
		gTagName: function (tag){
			var t = document.getElementsByTagName(tag);
			var tl = t.length;
			var a = [];
			for (var i = 0; i < tl; i++){
				if (! $(t[i]).hasAttr("mix"))
					a[a.length] = t[i];
			}
			if (a.length)
				this._elList = a;
			else
				this.gMix(tag);
			return this;
		},
		gId: function (id){
			var t = document.getElementById(id);
			this._elList = [];
			if (t)
				this._elList[0] = t;
			return this;
		},
		gMix: function (typ){
			var a = [];
			for (var x in mix.UIComponents){
				if (type(mix.UIComponents[x].type) != "undefined" && mix.UIComponents[x].type == typ)
					a[a.length] = mix.UIComponents[x].element;
			}
			this._elList = a;
			return this;
		},
		gAttr: function (k, v){
			var list = [];
			var has = (type(v) == "undefined");
			this.eachElement(function (el){
				if (el.nodeType != 1)
					return;
				if (has){
					if ($(el).hasAttr(k))
						list[list.length] = el;
				}else{
					if ((" " + $(el).attr(k) + " ").indexOf(" " + v + " ") > -1)
						list[list.length] = el;
				}
			}, this);
			this._elList = list;
			return this;
		},
		gGroup: function(grp){
			return this.gAttr("group", grp);
		},
		gClass: function (cls){
			var a = [];
			this.eachElement(function (el){
				var c = el.className;
				var cA = c.split(" ");
				if (cA.exist(cls))
					a[a.length] = el;
			}, this);
			this._elList = a;
			return this;
		},
		fId: function (id){
			var f = function (item){
				return (item.id == id);
			};
			var t = $();
			t._elList = this._elList.filter(f);
			return t;
		},
		fTagName: function (tag){
			var f = function (item){
				return (item.nodeName.toLowerCase() == tag);
			};
			var t = $();
			t._elList = this._elList.filter(f);
			return t;
		},
		fAttr: function (attr, val){
			var t = $();
			var f;
			var not = false;
			if (attr.charAt(0) == "!"){
				not = true;
				attr = attr.substr(1);
			}
			if (type(val) == "undefined"){
				f = function (item){
					return $(item).hasAttr(attr);
				};
			}else{
				f = function (item){
					return ($(item).attr(attr) == val);
				};
			}
			var g = function (item){
				return (not ? ! f(item) : f(item));
			};
			t._elList = this._elList.filter(g);
			return t;
		},
		fGroup: function (grp){
			return this.fAttr("group", grp);
		},
		fClass: function (cls){
			var n = false;
			if (cls.charAt(0) == "!"){
				n = true;
				cls = cls.substr(1);
			}
			var f = function (item){
				var c = item.className;
				var cA = c.split(" ");
				return (n ? ! cA.exist(cls) : cA.exist(cls));
			};
			var t = $();
			t._elList = this._elList.filter(f);
			return t;
		}
	})
});

Class.mixin(mix.elements.prototype, {
	//methods to manipulate mixelements
	
	addElement: function (el){
		if (type(el) != "undefined" && el.nodeType == 1)
			this._elList.push(el);
		return this;
	},
	eachChildren: function (fn, scope){
		if (! this.gLength()) return this;
		this.each(function (el){
			$(el)._accessElement(el, fn, scope);
		});
		return this;
	},
	eachElement: function (fn, scope){
		var doc = document.documentElement;
		this._accessElement(doc, fn, scope);
		return this;
	},
	_accessElement: function (el, fn, scope){
		if (el.nodeType == 1){
			fn.call(scope, el);
			for (var i = 0, a = el.childNodes.length; i < a; i++)
				this._accessElement(el.childNodes[i], fn, scope);
		}
	},
	each: function (fn, scope){
		for (var i = 0,  l = this.gLength(); i < l; i++)
			fn.call(scope, this._elList[i], i);
		return this;
	},
	filter: function (fn, scope){
		this._elList = this._elList.filter(fn, scope);
		return this;
	},		
	union: function (set){
		if (type(set) == "string")
			set = $(set);
		this._elList = this._elList.union(set._elList);
		return this;
	},
	exclude: function (set){
		this._elList = this._elList.remove.apply(this._elList, set._elList);
		return this;
	},
	
	//methods to transverse elements
	firstElement: function (){
		return this._elList.first();
	},
	lastElement:function (){
		return this._elList.last();
	},
	first: function (){
		return $(this.firstElement());
	},
	last: function (){
		return $(this.lastElement());
	},
	element: function (idx){
		return $(this._elList[idx]);
	},
	parent: function (){
		var r = $();
		this.each(function (v){
			r.addElement(v.parentNode);
		});
		return r;
	},
	firstChild: function (){
		var r = $();
		this.each(function (v){
			if (type(v.firstChild) != "undefined")
				r.addElement(v.firstChild);
		});
		return r;
	},
	lastChild: function (){
		var r = $();
		this.each(function (v){
			if (type(v.lastChild) != "undefined")
				r.addElement(v.lastChild);
		});
		return r;
	},
	children: function (){
		var r = $();
		this.each(function (el){
			if (el.nodeType == 1){
				for (var i = 0, l = el.childNodes.length; i < l; i++)
					r.addElement(el.childNodes[i]);
			}
		});
		return r;
	},
	removeChild: function (el){
		this.each(function (v){
			v.removeChild(el);
		});
		return this;
	},
	siblings: function (pre){
		var r = $();
		this.each(function (v){
			r.addElement((pre ? v.previousSibling: v.nextSibling));
		});
		return r;
	},
	prevSibling: function (){
		return this.siblings(true);
	},
	nextSibling: function (){
		return this.siblings();
	},
	childIdx: function (){
		var idx = 0;
		var a = this.firstElement();
		while (a = a.previousSibling)
			idx++;
		return idx;
	},
	
	//methods to change properties of mixelements
	attr: function (k, v){
		if (type(v) == "undefined"){
			if (! this._elList.length)
				return false;
			if (!! this.firstElement().getAttribute)
				return this.firstElement().getAttribute(k);
			else
				return this.firstElement()[k];
		}else{
			if (this._elList.length){
				this.each(function (item){
					if (!! item.setAttribute)
						item.setAttribute(k, v);
					else
						item[k] = v;
				});
			}
			return this;
		}
	},
	hasAttr: function (attr) {
		if (! this.gLength())
			return false;
		if (this.firstElement().hasAttribute)
			return this.firstElement().hasAttribute(attr);
		var t = this.firstElement().outerHTML.match(/^<[^>]*>/);
		return (! t ? false : (t[0].indexOf(" " + attr + "=") > -1));
	},
	removeAttr: function (){
		for (var i = 0, al = arguments.length; i < al; i++){
			this.each(function (item){
				item.removeAttribute(arguments[i]);
			});
		}
		return this;
	},
	html: function (txt){
		if (type(txt) != "undefined"){
			this.each(function (v){
				v.innerHTML = txt;
			});
			return this;
		}else{
			var str = "";
			this.each(function (v){
				str += v.innerHTML;
			});
			return str;
		}
	},
	val: function (value){
		if (type(value) == "undefined"){
			if (! this.gLength()) return this;
			var v = this.firstElement();
			if ($(v).hasAttr("mix")){
				var instance = $(v).getInstance();
				if (type(instance.val) == "function")
					return instance.val();
			}
			var t = v.nodeName.toLowerCase();
			switch (t){
				case "select":
					if (v.multiple){
						var vs = [];
						var o = v.options;
						for (var i = 0, l = o.length; i < l; i++){
							if (o[i].selected)
								vs[vs.length] = o[i].value;
						}
						return vs;
					}else{
						return (v.selectedIndex > -1 && v.selectedIndex <= v.length ? v.options[v.selectedIndex].value : "");
					}
				break;
				case "input":
				case "textarea":
					return v.value;
				break;
			}
			return this;
		}else{
			this.each(function (v){
				if ($(v).hasAttr("mix")){
					var instance = $(v).getInstance();
					if (type(instance.val) == "function")
						instance.val(value);
				}
				var t = v.nodeName.toLowerCase();
				switch (t){
					case "input":
					case "textarea":
						v.value = value;
					break;
					case "select":
						var opt = v.options;
						for (var i = 0, l = opt.length, m = type(value); i < l; i++){
							if (m == "array")
								opt[i].selected = value.exist(opt[i].value);
							else
								opt[i].selected = (value == opt[i].value);
						}
					break;
				}
			});
		}
		return this;
	},
	check: function (c){
		if (type(c) == "undefined")
			return this.firstElement().checked;
		this.each(function (v){
			v.checked = c;
		});
		return this;
	},
	focus: function(){
		this.firstElement().focus();
		return this;
	},
	blur: function (){
		this.each(function (el){
			el.blur();
		});
		return this;
	},
	addOption: function (text, value){
		this.each(function (el){
			if (el.nodeName.toLowerCase() == "select"){
				var nOption = document.createElement("option");
				nOption.text = text;
				nOption.value = value;
				el.add(nOption, null);
			}
		});
		return this;
	},
	removeOption: function (idx){
		this.each(function (el){
			if (el.nodeName.toLowerCase() == "select"){
				el.remove(idx);
			}
		});
		return this;
	},
	removeAllOptions: function (){
		this.each(function (el){
			if (el.nodeName.toLowerCase() == "select"){
				for (var i = 0, l = el.length; i < l; i++){
					el.remove(0);
				}
			}
		});
		return this;
	},
	reset: function (){
		this.each(function (el){
			if (el.nodeName.toLowerCase() == "form"){
				el.reset();
			}
		})
		return this;
	},
	submit: function (){
		this.each(function (el){
			if (el.nodeName.toLowerCase() == "form"){
				el.submit();
			}
		})
		return this;
	},
	ajaxSubmit: function(oncomplete, scope){
		this.each(function (el){
			if (el.nodeName.toLowerCase() == "form"){
				$(el).fireEvent("beforeAjaxSubmit");
				var r = new mix.Ajax({
					method: $(el).attr("method"),
					url: $(el).attr("action")
				});
				$(el).eachChildren(function (e){
					var tag = e.nodeName.toLowerCase();
					if (tag == "input" || tag == "textarea" || tag == "select"){
						if (e.name){
							if (e.type == "checkbox"){
								if ($(e).check()){
									r.addData(e.name, (e.value ? e.value : "on"));
								}
							}else if (e.type == "radio"){
								if ($(e).check())
									r.addData(e.name, e.value);
							}else{
								r.addData(e.name, $(e).val());
							}
						}
					}
				});
				if (type(oncomplete) == "function")
					r.on("complete", oncomplete, scope, true);
				r.send();
			}
		});
		return this;
	},
	hasClass: function (cls){
		if (! this._elList.length)
			return false;
		var p = new RegExp(" " + cls + " ");
		return (p.test(" " + this.firstElement().className + " "));
	},
	addClass: function (cls){
		this.each(function (v, k){
			var p = new RegExp(" " + cls + " ");
			if (! p.test(" " + v.className + " "))
				v.className = v.className + " " + cls;
		});
		
		return this;
	},
	removeClass: function (cls){
		this.each(function (v, k){
			var t = " " + v.className + " ";
			v.className = t.replace(" " + cls + " ", " ").trim();
		});
		
		return this;
	},
	usetip: function (tip){
		this.each(function (el){
			$("#"+tip).getInstance().attach(el);
		});
		return this;
	},
	createInstance: function (){
		this.eachChildren(function (el){
			var a = $(el).attr("mix");
			if (! a) return;
			var t = new mix[a](el.id, el);
			mix.UIComponents[el.id] = {
				type: a,
				element: el,
				object: t
			};
		});
		return this;
	},
	
	//methods to handle event for mixelements
	_attachEvent: function (el, evt){
		el["on" + evt] = function (e){
			var ret;
			var listenerToRemove = [];
			el.__eventListeners.each(function (listener){
				if (listener.event != evt || ret === false) return;
				var t = listener.fn.call(listener.scope, e, listener.element);
				if (type(t) == "boolean")
					ret = t;
				if (listener.once)
					listenerToRemove[listenerToRemove.length] = listener;
			});
			listenerToRemove.each(function (listener){
				$(el).removeEventListener(listener.event, listener.fn);
			}, this);
			
			if (type(ret) == "boolean")
				return ret;		
		};
	},
	addEventListener: function (evt, fn, scope, once){			
		this.each(function (v){
			if (type(v.__eventListeners) != "array")
				v.__eventListeners = [];
			var ev = {
				event: evt,
				fn: fn,
				scope: scope,
				once: once,
				element: v
			};
			v.__eventListeners.push(ev);
			this._attachEvent(v, evt);
		}, this);
		return this;
	},
	on: function (evt, fn, scope, once){			
		this.each(function (v){
			if (type(v.__eventListeners) != "array")
				v.__eventListeners = [];
			var ev = {
				event: evt,
				fn: fn,
				scope: scope,
				once: once,
				element: v
			};
			v.__eventListeners.push(ev);
			this._attachEvent(v, evt);
		}, this);
		return this;
	},
	fireEvent: function (evt, data){
		this.each(function (v){
			if (type(v["on" + evt]) == "function"){
				v["on"+evt](data);
			}
		});
		return this;
	},
	removeEventListener: function (evt, fn){
		this.each(function (v){
			if (type(v.__eventListeners) == "array"){
				v.__eventListeners.each(function (listener){
					if (listener.event == evt && listener.fn == fn)
						v.__eventListeners = v.__eventListeners.remove(listener);
				});
				this._attachEvent(v, evt);	
			}
		}, this);
		return this;
	},
	removeAllEventListeners: function (evt){
		this.each(function (v){
			if (type(evt) == "undefined"){
				v.__eventListeners = new Array();
				this._attachEvent(v, evt);
			}else{
				if (type(v.__eventListeners) == "array"){
					v.__eventListeners.each(function (listener){				
						if (listener.event == evt)
							v.__eventListeners = v.__eventListeners.remove(listener);
					});
					this._attachEvent(v, evt);
				}
			}
		}, this);
		return this;
	},
	
	//methods to get/set styles
	css: function (attr, value){
		if (type(value) == "undefined"){
			if (this.gLength())
				value = this.firstElement().style[attr.toCamel()];
			if (attr == "opacity"){
				if (mix.browser.isIE){
					value = this.firstElement().style["filter"].replace("alpha(opacity=","").replace(")","");
				}else{
					value = value * 100;
				}
			}
			if (attr == "scroll-y"){
				value = this.scroll().top;
			}
			if (attr == "scroll-x"){
				value = this.scroll().left;
			}
			return value;
		}else{
			if (attr == "scroll-y"){
				this.scroll(undefined, value);
			}else	if (attr == "scroll-x"){
				this.scroll(value);
			}else{
				this.each(function (v){
					if (attr == "opacity"){
						if (mix.browser.isIE){
							v.style["filter"] = "alpha(opacity=" + value + ")";
						}else{
							v.style[attr] = value / 100;
						}
					}else{
						v.style[attr.toCamel()] = value;
					}
				});
			}
			return this;
		}
	},
	
	//methods to retrieve dimension
	size: function (){
		if (! this.gLength())
			return {width: 0, height: 0};
		return {width: this.firstElement().offsetWidth, height: this.firstElement().offsetHeight};
	},
	position: function (absolute){
		if (! absolute){
			if (! this.gLength())
				return {left: 0, top: 0};
			return {left: this.firstElement().offsetLeft, top: this.firstElement().offsetTop};
		}else{
			var el = this.firstElement();
			var t = el.offsetTop;
			var l = el.offsetLeft;
			while (el = el.offsetParent){
				t += el.offsetTop;
				l += el.offsetLeft;
			}
			return {left: l, top: t};
		}
	},
	scroll: function (x, y){
		if ((type(x) != "undefined" && x !== true) || (type(y) != "undefined" && y !== true)){
			this.each(function (v){
				if (type(x) != "undefined")
					v.scrollLeft = x;
				if (type(y) != "undefined")
					v.scrollTop = y;
			});
			return this;
		}else{
			var el = this.firstElement();
			var t = el.scrollTop;
			var l = el.scrollLeft;
			if (x === true){
				while (el = el.offsetParent){
					t += el.scrollTop;
					l += el.scrollLeft;
				}
				t += document.documentElement.scrollTop;
				l += document.documentElement.scrollLeft;
			}
			return {
				left: l,
				top: t,
				width: this.firstElement().scrollWidth,
				height: this.firstElement().scrollHeight
			};
		}
	},
	
	//methods to make animation
	animate: function (css, dura, fps, func){
		var duration = (type(dura) == "undefined" ? 500 : dura);
		var fps = (type(fps) == "undefined" ? 10 : fps);
		var timesSpan = 0;
		var totalTimes = duration / 1000 * fps;
		var interval = Math.round(duration / totalTimes);
		var oEl = this;
		if (type(func) == "undefined")
			func = mix.animation.linear;
		var _animation = function (){
			if (timesSpan > totalTimes){
				oEl.each(function (element){
					for (var x in css){
						$(element).css(x, css[x][1] + css[x][2]);
					}
				});
				return;
			}
			oEl.each(function (element){
				for (var x in css){
					if (type(css[x]) != "array") return;
					var start, end;
					if (timesSpan == 0){
						var t = css[x][0].toInteger();
						var unit = css[x][0].replace(""+t, "");
						if (css[x].length == 1){
							css[x][1] = css[x][0].replace(unit, "").toInteger();
							css[x][0] = $(element).css(x).replace(unit, "").toInteger();
						}else{
							css[x][0] = css[x][0].toInteger();
							css[x][1] = css[x][1].toInteger();
						}
						css[x][2] = unit;
					}
					start = css[x][0];
					end = css[x][1];
					var delta = (end - start) / totalTimes;
					var ratio = func(timesSpan / totalTimes);
					$(element).css(x, Math.round(start + (end-start) * ratio) + css[x][2]);
				}
				element._animation = _animation;
			});
			timesSpan++;
		};
		_animation.startTimer(interval, duration + 1000);
		return this;
	},
	
	stopAnimation: function (){
		this.each(function (el){
			if (type(el._animation) != "undefined")
				el._animation.stopTimer();
		});
		return this;
	},
	
	//methods for providing interface for mixUI
	getInstance: function (){
		if (! this.gLength())
			return false;
		if (type(mix.UIComponents[this.firstElement().id]) != "undefined")
			return mix.UIComponents[this.firstElement().id].object;
		return false;
	}
});

Class.mixin(mix, {
	animation: {
		linear: function (i){
			return i;
		},
		sine: function (i){
			return (1 - Math.sin((1 - i) * Math.PI / 2));
		},
		circ: function (i){
			return (1 - Math.sin(Math.acos(i)));
		},
		expo: function (i){
			return (Math.pow(2, 8 * (i - 1)));
		},
		bounce: function (i){
			var value;
			for (var a = 0, b = 1; 1; a += b, b /= 2){
				if (i >= (7 - 4 * a) / 11){
					value = - Math.pow((11 - 6 * a - 11 * i) / 4, 2) + b * b;
					break;
				}
			}
			return value;
		},
		elastic: function(i){
			return Math.pow(2, 10 * --i) * Math.cos(20 * i * Math.PI / 3);
		},
		opposite: function (func){
			return (function (i){
				return (1 - func(1 - i));
			});
		}
	}
});

/*
	error class, for error handling
*/
Class.mixin(mix, {
	error: {
		report: function (e){
			if (! e)
				window.onerror = function (){return true;};
			else{
				window.onerror = function (m, u, l){
					return false;
				};
			}
		}
	}
});

/*
 	json class
 */
Class.mixin(mix, {
	JSON: {
		specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},
		
		encode: function (obj){
			switch (type(obj)){
				case "string":
					if (/["\\\x00-\x1f]/.test(obj)) {
						return '"' + obj.replace(/([\x00-\x1f\\"])/g, function(a, b) {
							var c = this.specialChars[b];
							if(c)
								return c;
							c = b.charCodeAt();
							return "\\u00" + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
					 	}) + '"';
					}
					return '"' + obj + '"';
				break;
				case "array":
					var a = [];
					obj.each(function (v){
						a.push(this.encode(v));
					}, this);
					return "[" + a.join(",") + "]";
				break;
				case "object":
					var a = [];
					for (var x in obj)
						a.push(this.encode(x) + ":" + this.encode(obj[x]));
					return "{" + a.join(",") + "}";
				break;
				case "number":
				case "boolean":
					return String(obj);
				break;
				default:
					return "null";
			}
			return null;
		},
		
		decode: function (str){
			return eval("(" + str + ")");
		}
	}
});

/*
	Ajax class
*/
Class.mixin(mix, {
	Ajax: Class({
		url: location.pathname.substr(1),
		method: "GET",
		data: "",
		async: true,
		encoding: "utf-8",
		headers: "",
		_running: false,
		_req: "",
		
		__construct: function (opt){
			if (type(opt.url) != "undefined")
				this.url = opt.url;
			if (type(opt.method) != "undefined")
				this.method = opt.method;
			this.setData(opt.data);
			if (type(opt.async) != "undefined")
				this.async = opt.async;
			if (type(opt.encoding) != "undefined")
				this.encoding = opt.encoding;
			if (type(opt.headers) != "undefined")
				this.headers = opt.headers;
		},
		getRequestObj: function(){
			if (mix.browser.isIE){
				try{
					this._req = new ActiveXObject("Msxml2.XMLHTTP");				
				}catch(e){
					this._req = new ActiveXObject("Microsoft.XMLHTTP");
				}
			}else{
				this._req = new XMLHttpRequest();
			}
			return this._req;
		},
		setUrl: function (url){
			this.url = url;
			return this;
		},
		setMethod: function (method){
			this.method = method;
			return this;
		},
		setData: function (data){
			this.data = new Array();
			this.data["key"] = new Array();
			this.data["value"] = new Array();
			if (type(data) == "undefined")
				return this;
			var i = 0;
			for (var x in data){
				this.data["key"][i] = x;
				this.data["value"][i] = data[x];
				i++;
			}
			return this;
		},
		addData: function (key, value){
			this.data["key"].push(key);
			this.data["value"].push(value);
			return this;
		},
		setAsync: function (async){
			this.async = async;
			return this;
		},
		setEncoding: function (encoding){
			this.encoding = encoding;
			return this;
		},
		setHeaders: function (headers){
			this.headers = headers;
			return this;
		},
		send: function (data){
			if (type(data) != "undefined")
				this.setData(data);
			this.fireEvent("send", this.data);
			this._req = this.getRequestObj();
			var r = this;
			this._req.onreadystatechange = function (){
				switch (r._req.readyState){
					case 1:
						r.fireEvent("loading", r._req);
					break;
					case 4:
						r.running = false;
						r.fireEvent("complete", {
							xml: r._req.responseXML,
							text: r._req.responseText
						});
					break;
				}
			};
			this.method = this.method.toUpperCase();
			var d = "";
			for (var i = 0, l = this.data["key"].length; i < l; i++){
				d += this.data["key"][i].strToURI() + "=" + this.data["value"][i].strToURI().replace(/\\\\/g,"\\") + "&";
			}
			d = d.substr(0, d.length - 1);
			var url = this.url;
			if (this.method == "POST")
				this._req.open("POST", url, this.async);
			else
				this._req.open(this.method, url + (url.indexOf("?") == -1 ? "?": "&") + d, this.async);
			this._req.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset="+this.encoding);
			if (type(this.headers) == "object"){
				for (var x in this.headers){
					this._req.setRequestHeader(x, this.headers[x]);
				}
			}
			if (this.method == "POST")
				this._req.send(d);
			else
				this._req.send(null);
			this._running = true;
			return this;
		},
		stop: function (){
			this.fireEvent("stop", this._req);
			if (this._running)
				this._req.abort();
			return this;
		}
	})
});

//tip class
Class.mixin(mix, {
	tip: Class({
		id: "",
		el: "",
		_attachedElement: "",
		
		__construct: function (id, el){
			this.id = id;
			this.el = el;
			this._attachedElement = [];
		},
		showTip: function (){
			if (this.fireEvent("beforeShow") === false) return this;
			$("#" + this.id).css("display", "block").css("zIndex", "10");
			this.fireEvent("show");
			return this;
		},
		moveTip: function (e){
			var s = $(document.documentElement).scroll();
			$("#" + this.id).css("left", (e.left + s.left + 2) + "px").css("top", (e.top + s.top + 2) + "px");
			return this;
		},
		hideTip: function (){
			if (this.fireEvent("beforeHide") === false) return this;
			$("#" + this.id).css("display", "none");
			this.fireEvent("hide");
			return this;
		},
		_mouseOver: function (){
			this.showTip();
		},
		_mouseMove: function (e){
			if (! e)
				e = window.event;
			this.moveTip({left: e.clientX + 2, top: e.clientY + 2});
		},
		_mouseOut: function (){
			this.hideTip();
		},
		attach: function (element){			
			if (this._attachedElement.exist(element))
				return this;			
			var a = this;
			$(element).on("mouseover", a._mouseOver, this)
					.on("mousemove", a._mouseMove, this)
					.on("mouseout", a._mouseOut, this);
			this._attachedElement.push(element);
			return this;
		},
		detach: function (element){
			if (! this._attachedElement.exist(element))
				return this;
			var a = this;
			$(element).removeEventListener("mouseover", a._mouseOver)
					.removeEventListener("mousemove", a._mouseMove)
					.removeEventListener("mouseout", a._mouseOut);
			this._attachedElement = this._attachedElement.remove(element);
			return this;
		}
	})
});

//usetemplate class
Class.mixin(mix, {
	useTemplate: Class({
		id: "",
		el: "",
		
		__construct: function (id, el){
			this.id = id;
			this.el = el;
			if ($(el).attr("delayRender") != "true")
				this.applyTemplate();
		},
		
		applyTemplate: function (replacer){
			var el = this.el;
			var id = this.id;
			
			var str = $("#" + $(el).attr("template")).html();
			if (type(replacer) != "undefined"){
				for (var x in replacer){
					var r = replacer[x];
					var reg = new RegExp('%'+x, "gi");
					str = str.replace(reg, r);
				}
			}else{
				var replacer = $(el).children();
				replacer.each(function (el){
					var reg = new RegExp('%'+$(el).attr("index"), "gi");
					str = str.replace(reg, $(el).html());
				});
			}
			
			if (str != ""){
				$(el).html(str);
			}
			this.fireEvent("applied");
			return this;
		}
	})
});

//template class
Class.mixin(mix, {
	template: Class({
		id: "",
		
		__construct: function (id){
			this.id = id;
		}
	})
});

//numberBox class
Class.mixin(mix, {
	numberBox: Class({
		id: "",
		el: "",
		_editable: "",
		_maxlength: "",
		_size: "",
		
		__construct: function (id, el){
			this.id = id;
			this.el = el;
			this._editable = ($("#"+id).attr("editable") != "false");
			this._maxlength = $("#"+id).firstElement().maxLength;
			this._size = $("#"+id).firstElement().size;
			var a = this;
			$("#" + id).on("mouseover", function (e, el){
				return a.fireEvent("mouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("mouseout", e);
			}).on("mousedown", function (e, el){
				return a.fireEvent("mousedown", e);
			}).on("mousemove", function (e, el){
				return a.fireEvent("mousemove", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("mouseup", e);
			}).on("click", function (e, el){
				return a.fireEvent("click", e);
			}).on("blur", function (e, el){
				return a.fireEvent("blur", e);
			}).on("change", function (e, el){
				return a.fireEvent("change", a.val());
			}).on("focus", function (e, el){
				return a.fireEvent("focus", e);
			}).on("keydown", function (e, el){
				return a.fireEvent("keydown", e);
			}).on("keypress", function (e, el){
				return a.fireEvent("keypress", e);
			}).on("keyup", function (e, el){
				return a.fireEvent("keyup", e);
			});
			
			
			a.on("keypress", function (e, el){
				var keynum = (window.event ? e.keyCode : e.which);
				if ((! ((keynum >= 48) && (keynum <= 57))) && keynum != 190 && keynum != 46 && keynum != 8 && keynum != 37 && keynum != 39)
					return false;
			});
			a.editable(a._editable);
		},
		_preventEdit: function (){
			return false;
		},
		enable: function (){
			$("#" + this.id).firstElement().disabled = false;
			this.fireEvent("enable");
			return this;
		},
		disable: function (){
			$("#" + this.id).firstElement().disabled = true;
			this.fireEvent("disable");
			return this;
		},
		size: function (size){
			if (type(size) == "undefined")
				return this._size;
			else{
				$("#"+ this.id).firstElement().size = size;
				this._size = size;
				return this;
			}
		},
		maxlength: function (l){
			if (type(l) == "undefined")
				return this._maxlength;
			else{
				$("#"+this.id).firstElement().maxLength = l;
				this._maxlength = l;
				return this;
			}
		},
		editable: function (editable){
			if (type(editable) == "undefined")
				return this._editable;
			else{
				if (editable){
					$("#" + this.id).removeEventListener("keydown", this._preventEdit)
				}else{
					$("#" + this.id).on("keydown", this._preventEdit)
				}
				this._editable = editable;
				return this;
			}
		},
		val: function (value){
			if (type(value) != "undefined"){
				$("#" + this.id).firstElement().value = parseFloat(value);
			}else{
				return $("#" + this.id).firstElement().value;
			}
		}
	})
});

//comboBox class
Class.mixin(mix, {
	comboBox: Class({
		id: "",
		el: "",
		_showingList: "",
		_editable: "",
		_maxlength: "",
		_size: "",
		_active: "",
		_highlightedIdx: "",
		_value: "",
		_isNewValue: "",
		_req: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			a._showingList = false;
			a._editable = ($(el).attr("editable") != "false");
			a._maxlength = el.maxLength;
			a._size = el.size;
			a._active = ($(el).attr("active") == "true");
			a._highlightedIdx = 0;
			a._value = $(el).attr("val");
			a._isNewValue = (a.searchValue(a._value) === false);
			
			a.editable(a._editable);
			a.val(a._value);
			if (el.disabled)
				a.disable();
			
			$(el).on("mouseover", function (e, el){
				return a.fireEvent("mouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("mouseout", e);
			}).on("mousedown", function (e, el){
				return a.fireEvent("mousedown", e);
			}).on("mousemove", function (e, el){
				return a.fireEvent("mousemove", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("mouseup", e);
			}).on("click", function (e, el){
				return a.fireEvent("click", e);
			}).on("blur", function (e, el){
				return a.fireEvent("blur", e);
			}).on("change", function (e, el){
				return a.fireEvent("textChange", e);
			}).on("focus", function (e, el){
				return a.fireEvent("focus", e);
			}).on("keydown", function (e, el){
				return a.fireEvent("keydown", e);
			}).on("keypress", function (e, el){
				return a.fireEvent("keypress", e);
			}).on("keyup", function (e, el){
				return a.fireEvent("keyup", e);
			});
			
			$("#" + id + "-img").on("mouseover", function (e, el){
				return a.fireEvent("btnMouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("btnMouseout", e);
			}).on("mousedown", function (e, el){
				return a.fireEvent("btnMousedown", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("btnMouseup", e);
			}).on("click", function (e, el){
				return a.fireEvent("btnClick", e);
			});
			
			a._attachItemEvent();
			
			a.on("btnMouseover", function (e){
				if (a.fireEvent("beforeBtnMouseover", e) === false) return false;
				$("#" + id + "-img").firstElement().src = "../mixFramework/image/arrow-down-mover.png";
				$("#" + id + "-img").addClass("mixComboBox-btnMOver");
			}).on("btnMouseout", function (e){
				if (a.fireEvent("beforeBtnMouseout", e) === false) return false;
				$("#" + id + "-img").firstElement().src = "../mixFramework/image/arrow-down.png";
				$("#" + id + "-img").removeClass("mixComboBox-btnMOver");
			}).on("btnMousedown", function (e){
				if (a.fireEvent("beforeBtnMousedown", e) === false) return false;
				a.toggleList();
				$("#" + id).firstElement().focus();
				a.on("beforeBlur", a._false, a, true);
			}).on("btnMouseup", function (e){
				if (a.fireEvent("beforeBtnMouseup", e) === false) return false;
				$("#" + id).firstElement().focus();
			}).on("keyup", function (e){
				if (a.fireEvent("beforeKeyup") === false) return false;
				var t = a.searchShowValue(el.value);			
				if (t === false)
					a.val(el.value);
				else
					a.val($(t).attr("value"));
				if (a._active && a._editable)
					a.updateList();
				a.showingList(true);
			}).on("blur", function (e){
				if (a.fireEvent("beforeBlur", e) === false) return false;
				a.showingList(false);
			}).on("itemMouseover", function (idx){
				if (a.fireEvent("beforeItemMouseover", idx) === false) return false;
				a.highlight(idx);
			}).on("itemMouseout", function (idx){
				if (a.fireEvent("beforeItemMouseout", idx) === false) return false;
				a.highlight(idx, false);
			}).on("itemMousedown", function (idx){
				if (a.fireEvent("beforeItemMousedown", idx) === false) return false;
				a.val($("$" + id).fAttr("index", idx).attr("value"));
				a.fireEvent("select", idx);
			}).on("showList", function (){
				if (a.fireEvent("beforeShowList") === false) return false;
				if (! a._isNewValue){
					var t = $("$" + id).fAttr("value", a._value).firstElement();
					if (t)
						a.highlight($(t).attr("index"));
				}else{
					a.highlight(0);
				}
			}).on("select", function (idx){
				if (a.fireEvent("beforeSelect", idx) === false) return false;
				a.showingList(false);
			});
		},
		
		_false: function (){
			return false;
		},
		_attachItemEvent: function (){
			var i = 0;
			var a = this;
			$("$" + this.id).each(function (el){
				$(el).attr("index", i);
				i++;
			}).on("mouseover", function (e, el){
				return a.fireEvent("itemMouseover", [$(el).attr("index"), el]);
			}).on("mouseout", function (e, el){
				return a.fireEvent("itemMouseout", $(el).attr("index"));
			}).on("mousedown", function (e, el){
				return a.fireEvent("itemMousedown", [$(el).attr("index"), el]);
			}).on("click", function (e, el){
				return a.fireEvent("itemClick", $(el).attr("index"));
			});
			
			return this;
		},
		getItem: function (idx){
			var t = $("$" + this.id).fAttr("index", ""+idx);
			return (t.gLength() ? t : false);
		},
		searchValue: function (value){
			var t = $("$" + this.id).fAttr("value", value);
			return (t.gLength() ? t : false);
		},
		searchShowValue: function (value){
			var t = $("$" + this.id).fAttr("showValue", value);
			return (t.gLength() ? t : false);
		},
		updateList: function (){
			var value = this.showVal();
			var id = this.id;
			var req = this._req;
			if (type(req) == "string"){
				req = new mix.Ajax({
					url: "../mixFramework/mix.php"
				});
				req.addEventListener("complete", function (response){
					$("#" + id + "-list").html(response.text).children().createInstance();
					this._attachItemEvent();
				}, this);
				this._req = req;
			}
			req.stop();
			req.send({
				"mix": "comboBox",
				"id": id,
				"input": value
			});
			return this;
		},
		
		highlight: function (idx, highlight){
			if (type(idx) == "undefined"){
				return parseInt(this._highlightedIdx);
			}else{
				if (type(highlight) == "undefined")
					highlight = true;
				if (highlight){
					this.highlight(this._highlightedIdx, false);
					$("$" + this.id).element(idx).addClass("mixComboBox-itemMOver");
					this._highlightedIdx = idx;
				}else{
					$("$" + this.id).element(idx).removeClass("mixComboBox-itemMOver");
					this._highlightedIdx = false;
				}
				return this;
			}
		},
		toggleList: function (){
			if (this._showingList){
				this.showingList(false);
			}else{
				this.showingList(true);
			}
			return this;
		},
		showingList: function (show){
			if (type(show) == "undefined"){
				return this._showingList;
			}else{
				if (show){
					if (this.fireEvent("showList") === false)
						return this;
					var size = $("#" + this.id + "-combo").size();
					var pos = $("#" + this.id).position(true);
					$("#" + this.id + "-list").css("width", size.width - 2 + "px").css("display", "block").css("left", pos.left + "px").css("top", (pos.top + size.height) + "px");
					this._showingList = true;
					return this;
				}else{
					if (this.fireEvent("hideList") === false) return this;
					$("#" + this.id + "-list").css("display", "none");
					this._showingList = false;
					return this;
				}
			}
		},
		enable: function (){
			$("#" + this.id).firstElement().disabled = false;
			this.removeEventListener("beforeBtnMousedown", this._false);
			this.fireEvent("enable");
			return this;
		},
		disable: function (){
			$("#" + this.id).firstElement().disabled = true;
			this.on("beforeBtnMousedown", this._false);
			this.fireEvent("disable");
			return this;
		},
		size: function (size){
			if (type(size) == "undefined")
				return this._size;
			else{
				$("#"+ this.id).firstElement().size = size;
				this._size = size;
				return this;
			}
		},
		maxlength: function (l){
			if (type(l) == "undefined")
				return this._maxlength;
			else{
				$("#"+this.id).firstElement().maxLength = l;
				this._maxlength = l;
				return this;
			}
		},
		editable: function (editable){
			if (type(editable) == "undefined")
				return this._editable;
			else{
				if (editable){
					$("#" + this.id).removeEventListener("keydown", this._false);
				}else{
					$("#" + this.id).on("keydown", this._false);
				}
				this._editable = editable;
				return this;
			}
		},
		val: function (value){
			if (type(value) == "undefined"){
				return this._value;
			}else{
				var t = this.searchValue(value);
				if (t === false){
					this._value = value;
					this._isNewValue = true;
					this.el.value = value;
					$("#" + this.id + "-new").firstElement().value = "true";
					$("#" + this.id + "-value").firstElement().value = value;
				}else{
					this._value = value;
					this._isNewValue = false;
					this.el.value = (t.attr("showValue") == "" ? (t.html() == "" ? "" : t.html()) : t.attr("showValue"));
					$("#" + this.id + "-new").firstElement().value = "false";
					$("#" + this.id + "-value").firstElement().value = value;
				}
				this.fireEvent("change", [this._value]);
				return this;
			}
		},
		showVal: function (){
			if (this._isNewValue){
				return this._value;
			}else{
				var t = this.searchValue(this._value);
				return t.attr("showValue");
			}
		}
	})
});

//datePicker class
Class.mixin(mix, {
	datePicker: Class({
		id: "",
		el: "",
		showing: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			a.showing = false;
			
			$("#" + id + "-monthLeft").on("mouseover", function (e, el){
				return a.fireEvent("monthLeftMouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("monthLeftMouseout", e);
			}).on("mousedown", function (e, el){
				return a.fireEvent("monthLeftMousedown", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("monthLeftMouseup", e);
			}).on("click", function (e, el){
				return a.fireEvent("monthLeftClick", e);
			});
			$("#" + id + "-monthRight").on("mouseover", function (e, el){
				return a.fireEvent("monthRightMouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("monthRightMouseout", e);
			}).on("mousedown", function (e, el){
				return a.fireEvent("monthRightMousedown", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("monthRightMouseup", e);
			}).on("click", function (e, el){
				return a.fireEvent("monthRightClick", e);
			});
			$("#" + id + "-yearLeft").on("mouseover", function (e, el){
				return a.fireEvent("yearLeftMouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("yearLeftMouseout", e);
			}).on("mousedown", function (e, el){
				return a.fireEvent("yearLeftMousedown", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("yearLeftMouseup", e);
			}).on("click", function (e, el){
				return a.fireEvent("yearLeftClick", e);
			});
			$("#" + id + "-yearRight").on("mouseover", function (e, el){
				return a.fireEvent("yearRightMouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("yearRightMouseout", e);
			}).on("mousedown", function (e, el){
				return a.fireEvent("yearRightMousedown", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("yearRightMouseup", e);
			}).on("click", function (e, el){
				return a.fireEvent("yearRightClick", e);
			});
			$("#" + id + "-close").on("click", function (e, el){
				return a.fireEvent("closeClick", e);
			});
			$("#" + id + "-today").on("click", function (e, el){
				return a.fireEvent("todayClick", e);
			});
			$("#" + id + "-day").children().fTagName("tbody").children().each(function (el){
				$(el).children().on("click", function (e, el){
					var t = $(el).attr("date").split("-");
					return a.fireEvent("dateSelect", new Date(t[0], t[1] - 1, t[2]));
				});
			});
			$("#" + id + "-month").on("change", function (){
				return a.fireEvent("monthChange");
			});
			$("#" + id + "-year").on("change", function (){
				return a.fireEvent("yearChange");
			});
			
			a.on("monthLeftMouseover", function (e){
				if (a.fireEvent("beforeMonthLeftMouseover", e) === false) return false;
				$("#" + id + "-monthLeft").addClass("mixDatePicker-ymBtnMOver");
			}).on("monthLeftMouseout", function (e){
				if (a.fireEvent("beforeMonthLeftMouseout", e) === false) return false;
				$("#" + id + "-monthLeft").removeClass("mixDatePicker-ymBtnMOver");
			}).on("monthLeftClick", function (e){
				if (a.fireEvent("beforeMonthLeftClick", e) === false) return false;
				a.prevMonth();
			}).on("monthRightMouseover", function (e){
				if (a.fireEvent("beforeRightMouseover", e) === false) return false;
				$("#" + id + "-monthRight").addClass("mixDatePicker-ymBtnMOver");
			}).on("monthRightMouseout", function (e){
				if (a.fireEvent("beforeRightMouseout", e) === false) return false;
				$("#" + id + "-monthRight").removeClass("mixDatePicker-ymBtnMOver");
			}).on("monthRightClick", function (e){
				if (a.fireEvent("beforeMonthRightClick", e) === false) return false;
				a.nextMonth();
			}).on("yearLeftMouseover", function (e){
				if (a.fireEvent("beforeYearLeftMouseover", e) === false) return false;
				$("#" + id + "-yearLeft").addClass("mixDatePicker-ymBtnMOver");
			}).on("yearLeftMouseout", function (e){
				if (a.fireEvent("beforeYearLeftMouseout", e) === false) return false;
				$("#" + id + "-yearLeft").removeClass("mixDatePicker-ymBtnMOver");
			}).on("yearLeftClick", function (e){
				if (a.fireEvent("beforeYearLeftClick", e) === false) return false;
				a.prevYear();
			}).on("yearRightMouseover", function (e){
				if (a.fireEvent("beforeYearRightMouseover", e) === false) return false;
				$("#" + id + "-yearRight").addClass("mixDatePicker-ymBtnMOver");
			}).on("yearRightMouseout", function (e){
				if (a.fireEvent("beforeYearRightMouseout", e) === false) return false;
				$("#" + id + "-yearRight").removeClass("mixDatePicker-ymBtnMOver");
			}).on("yearRightClick", function (e){
				if (a.fireEvent("beforeYearRightClick", e) === false) return false;
				a.nextYear();
			}).on("closeClick", function (e){
				if (a.fireEvent("beforeCloseClick", e) === false) return false;
				a.hide();
				a.removeAllEventListeners("dateSelect").on("dateSelect", function (date){
					if (a.fireEvent("beforeDateSelect", date) === false) return false;
					a.hide();
				});
			}).on("monthChange", function (){
				if (a.fireEvent("beforeMonthChange") === false) return false;
				a.generateDays();
			}).on("yearChange", function (){
				if (a.fireEvent("beforeYearChange") === false) return false;
				a.generateDays();
			}).on("todayClick", function (){
				if (a.fireEvent("beforeTodayClick") === false) return false;
				a.fireEvent("dateSelect", new Date());
			}).on("dateSelect", function (date){
				if (a.fireEvent("beforeDateSelect", date) === false) return false;
				a.hide();
			});
			
			a.generateDays();
		},
		
		generateDays: function (){
			var dayOne = new Date($("#" + this.id + "-year").val(), $("#" + this.id + "-month").val() - 1);
			var lastMonth = new Date($("#" + this.id + "-year").val(), $("#" + this.id + "-month").val() - 1);
			lastMonth.setTime(lastMonth.getTime() - 24 * 60 * 60 * 1000);
			var nextMonth = new Date($("#" + this.id + "-year").val(), $("#" + this.id + "-month").val() - 1);
			nextMonth.setTime(nextMonth.getTime() + nextMonth.getDaysInMonth() * 24 * 60 * 60 * 1000);
			var spaceLeft = 42;
			var week = $("#" + this.id + "-day").children().fTagName("tbody").children();
			if (lastMonth.getDay() != 6){
				var day = lastMonth.getDate();
				for (var i = lastMonth.getDay(); i > -1; i--){
					week.element(0).children().element(i).html(day).addClass("mixDatePicker-dayNotInMonth")
						.attr("date", lastMonth.getFullYear() + "-" + (lastMonth.getMonth() + 1) + "-" + day);
					spaceLeft--;
					day--;
				}
			}
			
			var day = dayOne.getDate();
			
			var days = dayOne.getDaysInMonth();
			var lastWeek;
			for (var i = 1; i <= days; i++){
				lastWeek =dayOne.getWeekInMonth();
				week.element(lastWeek - 1).children().element(dayOne.getDay()).html(day).removeClass("mixDatePicker-dayNotInMonth")
					.attr("date", dayOne.getFullYear() + "-" + (dayOne.getMonth() + 1) + "-" + day);
				dayOne.setTime(dayOne.getTime() + 24 * 60 * 60 * 1000);
				spaceLeft--;
				day++;
			}
			
			day = 1;
			if (dayOne.getDay() == 0)
				lastWeek++;
			for (var i = spaceLeft; i > 0; i--){
				week.element(lastWeek -1).children().element(dayOne.getDay()).html(day).addClass("mixDatePicker-dayNotInMonth")
					.attr("date", dayOne.getFullYear() + "-" + (dayOne.getMonth() + 1) + "-" + day);
				dayOne.setTime(dayOne.getTime() + 24 * 60 * 60 * 1000);
				day++;
				if (dayOne.getDay() == 0)
					lastWeek++;
			}
			
			return this;
		},
		
		prevMonth: function (){
			var currentYear = $("#" + this.id + "-year").val();
			var t = new Date(currentYear, $("#" + this.id + "-month").val() -2);
			$("#" + this.id + "-year").val(t.getFullYear());
			$("#" + this.id + "-month").val(t.getMonth() + 1);
			this.fireEvent("monthChange");
			if (currentYear != t.getFullYear())
				this.fireEvent("yearChange");
			return this;
		},
		nextMonth: function (){
			var currentYear = $("#" + this.id + "-year").val();
			var t = new Date(currentYear, $("#" + this.id + "-month").val());
			$("#" + this.id + "-year").val(t.getFullYear());
			$("#" + this.id + "-month").val(t.getMonth() + 1);
			this.fireEvent("monthChange");
			if (currentYear != t.getFullYear())
				this.fireEvent("yearChange");
			return this;
		},
		prevYear: function (){
			var currentYear = $("#" + this.id + "-year").val();
			var t = new Date(currentYear - 1, $("#" + this.id + "-month").val() - 1);
			$("#" + this.id + "-year").val(t.getFullYear());
			this.fireEvent("yearChange");
			return this;
		},
		nextYear: function (){
			var currentYear = $("#" + this.id + "-year").val();
			var t = new Date(parseInt(currentYear) + 1, $("#" + this.id + "-month").val() - 1);
			$("#" + this.id + "-year").val(t.getFullYear());
			this.fireEvent("yearChange");
			return this;
		},
		setDate: function (date){
			if (date == "")
				date = new Date();
			if (type(date) == "string"){
				var t = new Date();
				t.setTime(Date.parse(date));
				date = t;
			}
			$("#" + this.id + "-year").val(date.getFullYear());
			$("#" + this.id + "-month").val(date.getMonth() + 1);
			this.generateDays();
			this.highlightDate(date);
			return this;
		},
		highlightDate: function (date){
			if (type(date) == "undefined")
				date = new Date();
			if (type(date) == "string"){
				var t = new Date();
				t.setTime(Date.parse(date));
				date = t;
			}
			var fTr = $("#" + this.id + "-day").children().fTagName("tbody").children();
			var d = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
			fTr.each(function (el){
				$(el).children().each(function (td){
					var t = $(td);
					if (t.attr("date") == d)
						t.addClass("mixDatePicker-highlightDay");
					else
						t.removeClass("mixDatePicker-highlightDay");
				});
			});
			return this;
		},
		toggleShow: function (){
			if (this.showing)
				this.hide();
			else
				this.show();
		},
		show: function (){
			$("#" + this.id).css("display", "block").css("zIndex", "5");
			this.showing = true;
			this.fireEvent("show");
		},
		hide: function (){
			$("#" + this.id).css("display", "none").css("zIndex", "5");
			this.showing = false;
			this.fireEvent("hide");
		}
	})
});

//dateInput class
Class.mixin(mix, {
	dateInput: Class({
		id: "",
		el: "",
		datePicker: "",
		format: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			a.datePicker = $(el).attr("datePicker");
			a.format = ($(el).attr("format") ? $(el).attr("format") : "M j, Y");
			
			$("#" + id + "-img").on("mouseover", function (e, el){
				return a.fireEvent("btnMouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("btnMouseout", e);
			}).on("mousedown", function (e, el){
				return a.fireEvent("btnMousedown", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("btnMouseup", e);
			}).on("click", function (e, el){
				return a.fireEvent("btnClick", e);
			})
			$("#" + id).on("keyup", function (e, el){
				return a.fireEvent("keyup", e);
			}).on("mouseover", function (e, el){
				return a.fireEvent("mouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("mouseout", e);
			}).on("mousedown", function (e, el){
				return a.fireEvent("mousedown", e);
			}).on("mousemove", function (e, el){
				return a.fireEvent("mousemove", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("mouseup", e);
			}).on("blur", function (e, el){
				return a.fireEvent("blur", e);
			}).on("change", function (e, el){
				return a.fireEvent("change", e);
			}).on("focus", function (e, el){
				return a.fireEvent("focus", e);
			}).on("keydown", function (e, el){
				return a.fireEvent("keydown", e);
			}).on("keypress", function (e, el){
				return a.fireEvent("keypress", e);
			}).on("click", function (e){
				return a.fireEvent("click", e);
			});
			
			
			a.on("btnMouseover", function (e){
				if (a.fireEvent("beforeBtnMouseover", e) === false) return false;
				$("#" + id + "-img").firstElement().src = "../mixFramework/image/dateInput-mover.png";
			}).on("btnMouseout", function (e){
				if (a.fireEvent("beforeBtnMouseout", e) === false) return false;
				$("#" + id + "-img").firstElement().src = "../mixFramework/image/dateInput.png";
			}).on("btnClick", function (e){
				if (a.fireEvent("beforeBtnClick", e) === false) return false;
				a.toggleDatePicker();
				$("#" + a.datePicker).getInstance().on("dateSelect", function (date){
					$("#" + id).val(date.toFormat(a.format));
					a.fireEvent("change");
				}, this, true);
			}).on("click", function (e){
				if (a.fireEvent("beforeClick", e) === false) return false;
				a.toggleDatePicker();
				$("#" + a.datePicker).getInstance().on("dateSelect", function (date){
					$("#" + id).val(date.toFormat(a.format));
					a.fireEvent("change");
				}, this, true);
			}).on("keydown", a._false);
			if (el.disabled)
				this.disable();
		},
		
		_false: function (){
			return false;
		},
		toggleDatePicker: function (){
			var dP = $("#" + this.datePicker).getInstance();
			if (dP.showing)
				this.hideDatePicker();
			else
				this.showDatePicker();
			return this;
		},
		showDatePicker: function (){
			var pos = $("#" + this.id + "-date").position(true);
			var size = $("#" + this.id + "-date").size();
			var widthOffset = -2;
			var leftOffset = 0;
			var topOffset = 0;
			if (mix.browser.isIE){
				leftOffset = 1;
				topOffset = 1;
				widthOffset = -2;
			}
			var w = ((size.width + widthOffset) > 210 ? size.width + widthOffset : 210);
			$("#" + this.datePicker).css("left", (pos.left + leftOffset) + "px").css("top", (pos.top + size.height + topOffset) + "px").css("width", w + "px")
				.getInstance().setDate($("#" + this.id).val()).show();
			return this;
		},
		hideDatePicker: function(){
			$("#" + this.datePicker).getInstance().hide();
			return this;
		},
		enable: function (){
			$("#" + this.id).firstElement().disabled = false;
			this.removeEventListener("beforeBtnClick", this._false);
			this.fireEvent("enable");
			return this;
		},
		disable: function (){
			$("#" + this.id).firstElement().disabled = true;
			this.on("beforeBtnClick", this._false);
			this.fireEvent("disable");
			return this;
		}
	})
});

Class.mixin(mix, {
	ajaxPage: Class({
		id: "",
		el: "",
		_ajax: "",
		cache: "",
		loadedList: "",
		cacheList: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			a.cache = ($(el).attr("cache") == "true");
			a.loadedList = [];
			a.cacheList = [];
			if ($(el).attr("autoLoad") == "true")
				a.load();
			
			$("#" + id).on("keyup", function (e, el){
				return a.fireEvent("keyup", e);
			}).on("mouseover", function (e, el){
				return a.fireEvent("mouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("mouseout", e);
			}).on("mousedown", function (e, el){
				return a.fireEvent("mousedown", e);
			}).on("mousemove", function (e, el){
				return a.fireEvent("mousemove", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("mouseup", e);
			}).on("blur", function (e, el){
				return a.fireEvent("blur", e);
			}).on("focus", function (e, el){
				return a.fireEvent("focus", e);
			}).on("keydown", function (e, el){
				return a.fireEvent("keydown", e);
			}).on("keypress", function (e, el){
				return a.fireEvent("keypress", e);
			}).on("click", function (e){
				return a.fireEvent("click", e);
			});
		},
		load: function (src){
			if (this.fireEvent("beforeLoad") === false) return this;
			if (type(src) == "undefined")
				src = $(this.el).attr("src");
			if (this.cache && this.loadedList.exist(src)){
				if (this.fireEvent("ajaxLoad", this.cacheList[src]) === false) return this;
				$(this.el).html(this.cacheList[src].text).children().createInstance().eachChildren(function (el){
					var a = $(el).attr("usetip");
					if (type(a) == "string" && a != "")
						$(el).usetip(a);
				});
				this.fireEvent("load", this.cacheList[src]);
				return this;
			}
			this._ajax = new mix.Ajax({});
			this._ajax.on("complete", function (response){
				if (this.fireEvent("ajaxLoad", response) === false) return;
				$(this.el).html(response.text).children().createInstance().eachChildren(function (el){
					var a = $(el).attr("usetip");
					if (type(a) == "string" && a != "")
						$(el).usetip(a);
				});
				this.loadedList.push(src);
				this.cacheList[src] = response;
				this.fireEvent("load", response);
			}, this);
			this._ajax.setUrl(src);
			this._ajax.send();
			return this;
		}
	})
});

Class.mixin(mix, {
	tabPanel: Class({
		id: "",
		el: "",
		selectedTab: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			
			var tabs = $("#" + id + "-tabs").firstChild().firstChild().children();
			var s = tabs.fAttr("selected", "true");
			if (s.gLength())
				a.selectedTab = s.attr("content");
			else
				a.selectedTab = tabs.attr("content");
			
			a.selectTab(a.selectedTab);
			var s = tabs.fAttr("disabled", "true");
			if (s.gLength()){
				s.each(function (el){
					a.disable($(el).attr("content"));
				});
			}
			
			tabs.on("click", function (e, el){
				return a.fireEvent("tabClick", [e, el]);
			}).on("mouseover", function (e, el){
				return a.fireEvent("tabMouseover", [e, el]);
			}).on("mouseout", function (e, el){
				return a.fireEvent("tabMouseout", [e, el]);
			}).on("mousemove", function (e, el){
				return a.fireEvent("tabMousemove", [e, el]);
			});
			
			a.on("tabClick", function (e, el){
				if (a.fireEvent("beforeTabClick", [e, el]) === false) return false;
				a.selectTab($(el).attr("content"));			
			}).on("tabMouseover", function (e, el){
				if (a.fireEvent("beforeTabMouseover", [e, el]) === false) return false;
				$(el).addClass("mixTabPanel-tabMOver");
			}).on("tabMouseout", function (e, el){
				if (a.fireEvent("beforeTabMouseout", [e, el]) === false) return false;
				$(el).removeClass("mixTabPanel-tabMOver");
			});
		},
		
		_false: function (){
			return false;
		},
		
		selectTab: function (content){
			this.deselectAll();
			$("#" + this.id + "-tabs").firstChild().firstChild().children().fAttr("content", content).addClass("mixTabPanel-selectedTab");
			$("#" + content).css("display", "block");
			this.selectedTab = content;
			if (this.fireEvent(content+"Selected") === false) return this;
			this.fireEvent("tabSelected", content);
			return this;
		},
		deselectAll: function (){
			$("#" + this.id + "-tabs").firstChild().firstChild().children().removeClass("mixTabPanel-selectedTab").attr("selected", "false");
			$("#" + this.id + "-tabContents").children().css("display", "none");
			this.selectedTab = "";
			return this;
		},
		enable: function(content){
			$("#" + this.id + "-tabs").firstChild().firstChild().children().fAttr("content", content)
				.removeEventListener("click", this._false).removeEventListener("mouseover", this._false)
				.removeClass("mixTabPanel-tabDisabled");
			this.fireEvent("enable");
			return this;
		},
		disable: function (content){
			$("#" + this.id + "-tabs").firstChild().firstChild().children().fAttr("content", content)
				.on("click", this._false).on("mouseover", this._false)
				.addClass("mixTabPanel-tabDisabled");
			this.fireEvent("disable");
			return this;
		}
	})
});

Class.mixin(mix, {
	spinner: Class({
		id: "",
		el: "",
		min: "",
		max: "",
		step: "",
		dPlace: "",
		_cycle: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			a.min = $(el).attr("min");
			a.max = $(el).attr("max");
			a.step = $(el).attr("step");
			a.dPlace = $(el).attr("dPlace");
			a._cycle = ($(el).attr("cycle") == "true");
			
			$("#" + id + "-btnUp").on("mousedown", function (e, el){
				return a.fireEvent("btnUpMousedown", e);
			}).on("mouseover", function (e, el){
				return a.fireEvent("btnUpMouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("btnUpMouseout", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("btnUpMouseup", e);
			}).on("click", function (e, el){
				return a.fireEvent("btnUpClick", e);
			});
			$("#" + id + "-btnDown").on("mousedown", function (e, el){
				return a.fireEvent("btnDownMousedown", e);
			}).on("mouseover", function (e, el){
				return a.fireEvent("btnDownMouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("btnDownMouseout", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("btnDownMouseup", e);
			}).on("click", function (e, el){
				return a.fireEvent("btnDownClick", e);
			});
			$("#" + id + "-numBox").on("keyup", function (e, el){
				return a.fireEvent("keyup", e);
			}).on("mouseover", function (e, el){
				return a.fireEvent("mouseover", e);
			}).on("mouseout", function (e, el){
				return a.fireEvent("mouseout", e);
			}).on("mousedown", function (e, el){
				return a.fireEvent("mousedown", e);
			}).on("mousemove", function (e, el){
				return a.fireEvent("mousemove", e);
			}).on("mouseup", function (e, el){
				return a.fireEvent("mouseup", e);
			}).on("blur", function (e, el){
				return a.fireEvent("blur", e);
			}).on("focus", function (e, el){
				return a.fireEvent("focus", e);
			}).on("keydown", function (e, el){
				return a.fireEvent("keydown", e);
			}).on("keypress", function (e, el){
				return a.fireEvent("keypress", e);
			}).on("click", function (e){
				return a.fireEvent("click", e);
			}).on("change", function (e, el){
				return a.fireEvent("change", el.value);
			});
			
			a.on("btnUpMouseover", function (){
				if (a.fireEvent("beforeBtnUpMouseover") === false) return false;
				$("#" + id + "-btnUp").addClass("mixSpinner-spinnersMOver").firstChild().firstElement().src = "../mixFramework/image/spinner-up-mover.png";
			}).on("btnUpMouseout", function (){
				if (a.fireEvent("beforeBtnUpMouseout") === false) return false;
				$("#" + id + "-btnUp").removeClass("mixSpinner-spinnersMOver").firstChild().firstElement().src = "../mixFramework/image/spinner-up.png";
			}).on("btnDownMouseover", function (){
				if (a.fireEvent("beforeBtnDownMouseover") === false) return false;
				$("#" + id + "-btnDown").addClass("mixSpinner-spinnersMOver").firstChild().firstElement().src = "../mixFramework/image/spinner-down-mover.png";
			}).on("btnDownMouseout", function (){
				if (a.fireEvent("beforeBtnDownMouseout") === false) return false;
				$("#" + id + "-btnDown").removeClass("mixSpinner-spinnersMOver").firstChild().firstElement().src = "../mixFramework/image/spinner-down.png";
			}).on("btnUpMousedown", function (){
				if (a.fireEvent("beforeBtnUpMousedown") === false) return false;
				a.increaseByStep();
			}).on("btnDownMousedown", function (){
				if (a.fireEvent("beforeBtnDownMousedown") === false) return false;
				a.decreaseByStep();
			});
		},
		
		getNumBoxInstance: function (){
			return $("#" + this.id + "-numBox").getInstance();
		},
		increaseByStep: function (steps){
			if (type(steps) == "undefined")
				steps = 1;
			var newVal = parseFloat((parseFloat(this.val()) + parseFloat(this.step) * steps).toFixed(this.dPlace));
			if (newVal <= parseFloat(this.max)){
				this.val(newVal);
				this.fireEvent("change", $("#" + this.id + "-numBox").firstElement().value);
			}else{
				if (this.fireEvent("overMax") === false) return false;
				if (this._cycle){
					this.val(parseFloat(this.min));
					this.fireEvent("change", $("#" + this.id + "-numBox").firstElement().value);
				}
			}
			return this;
		},
		decreaseByStep: function (steps){
			if (type(steps) == "undefined")
				steps = 1;
			var newVal = parseFloat((parseFloat(this.val()) - parseFloat(this.step) * steps).toFixed(this.dPlace));
			if (newVal >= parseFloat(this.min)){
				this.val(newVal);
				this.fireEvent("change", $("#" + this.id + "-numBox").firstElement().value);
			}else{
				if (this.fireEvent("overMin") === false) return false;
				if (this._cycle){
					this.val(parseFloat(this.max));
					this.fireEvent("change", $("#" + this.id + "-numBox").firstElement().value);
				}
			}
			return this;
		},
		val: function (value){
			if (type(value) == "undefined"){
				return $("#" + this.id + "-numBox").firstElement().value;
			}else{
				$("#" + this.id + "-numBox").firstElement().value = value;
				return this;
			}
		}
	})
});

Class.mixin(mix, {
	timeInput: Class({
		id: "",
		el: "",
		_showSecond: "",
		_twelve: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			a._showSecond = ($("#" + id).attr("showSecond") == "true");
			a._twelve = ($("#" + id).attr("twelve") == "true");
			
			$("#" + id + "-hour").getInstance().on("change", function (val){
				if (a.fireEvent("hourChange") === false) return false;
				return a.fireEvent("change", $("#" + id + "-time").val());
			});
			$("#" + id + "-minute").getInstance().on("change", function (val){
				if (a.fireEvent("minuteChange") === false) return false;
				return a.fireEvent("change", $("#" + id + "-time").val());
			});
			if (a._showSecond){
				$("#" + id + "-second").getInstance().on("change", function (val){
					if (a.fireEvent("secondChange") === false) return false;
					return a.fireEvent("change", $("#" + id + "-time").val());
				});
			}
			if (a._twelve){
				$("#" + id + "-meridiem").on("change", function (val){
					if (a.fireEvent("meridiemChange") === false) return false;
					return a.fireEvent("change", $("#" + id + "-time").val());
				});
			}
			a.addEventListener("change", function (val){
				if (a.fireEvent("beforeChange", val) === false) return false;
				a.setValueByInput();
			});
			if ($("#" + this.id + "-time").val() != "")
				a.setInputByValue();
		},
		setInputByValue: function (){
			var time = this.val().split(":");
			var hour = parseInt(time[0]);
			if (this._twelve){
				if (hour > 12){
					$("#" + this.id + "-hour").val(hour - 12);
				}else{
					$("#" + this.id + "-hour").val(hour);
				}
			}else{
				$("#" + this.id + "-hour").val(hour);
			}
			var minute = parseInt(time[1]);
			$("#" + this.id + "-minute").val(minute);
			if (this._showSecond)
				$("#" + this.id + "-second").val(time[2]);
			return this;
		},
		setValueByInput: function (){
			var hour = $("#" + this.id + "-hour").val();
			var minute = $("#" + this.id + "-minute").val();
			if (this._showSecond)
				var second = $("#" + this.id + "-second").val();
			if (this._twelve){
				hour = parseInt(hour);
				if ($("#" + this.id + "-meridiem").val() == "pm"){
					if (hour != 12)
						hour += 12;
				}else{
					if (hour == 12)
						hour = 0;
				}
			}
			var time = hour + ":" + minute;
			if (this._showSecond)
				time = time + ":" + second;
			this.val(time);
			return this;
		},
		val: function (value){
			if (type(value) == "undefined")
				return $("#" + this.id + "-time").val();
			else{
				$("#" + this.id + "-time").val(value);
				return this;
			}
		}
	})
});

Class.mixin(mix, {
	drag: {
		
		prepareDragElement: function(mDownEl, moveEl, container, dragX, dragY, xBound, yBound){
			if (type(mDownEl) == "mixelements")
				mDownEl = mDownEl.firstElement();
				
			if (type(moveEl) == "mixelements")
				moveEl = moveEl.firstElement();
			else if (type(moveEl) == "undefined")
				moveEl = mDownEl;
				
			if (type(container) == "undefined")
				container = document.documentElement;
			else if (type(container) == "mixelements")
				container = container.firstElement();
			
			if (type(dragX) == "undefined")
				dragX = true;
			if (type(dragY) == "undefined")
				dragY = true;
			
			if (type(xBound) == "undefined"){
				xBound = {
					min: $(container).position().left,
					max: $(container).position().left + $(container).size().width
				};
			}
			if (type(yBound) == "undefined"){
				yBound = {
					min: $(container).position().top,
					max: $(container).position().top + $(container).size().height
				};
			}
			$(moveEl).removeAllEventListeners("dragStart").removeAllEventListeners("dragging").removeAllEventListeners("dragEnd");
			var f = function (e, el){
				if (window.event)
					e = window.event;
				if (! moveEl._dragging)
					$(moveEl).fireEvent("dragStart", e);
				moveEl._dragging = true;
				var pos = $(moveEl).position();
				moveEl._startPosX = pos.left;
				moveEl._startPosY = pos.top;
				moveEl._startMouseX = e.clientX;
				moveEl._startMouseY = e.clientY;
				return false;
			};
			$(mDownEl).on("mousedown", f);
			var g = function (e, el){
				if (window.event)
					e = window.event;
				if (moveEl._dragging){
					var mDeltaX = e.clientX - moveEl._startMouseX;
					var mDeltaY = e.clientY - moveEl._startMouseY;
					var newPosX = moveEl._startPosX + mDeltaX;
					var newPosY = moveEl._startPosY + mDeltaY;
					var mSize = $(moveEl).size();
					if (dragX){
						if (newPosX + mSize.width / 2 < xBound.max && newPosX + mSize.width / 2 > xBound.min)
							$(moveEl).css("left", newPosX + "px");
					}
					if (dragY){
						if (newPosY + mSize.height / 2 < yBound.max && newPosY + mSize.height / 2 > yBound.min)
							$(moveEl).css("top", newPosY + "px");
					}
					var left = $(moveEl).css("left").toInteger();
					var top = $(moveEl).css("top").toInteger();
					$(moveEl).fireEvent("dragging", {
						left: left, 
						top: top,
						leftPer: ((left + mSize.width / 2 - xBound.min) / (xBound.max - xBound.min)).toFixed(2),
						topPer: ((top + mSize.height / 2 - yBound.min) / (yBound.max - yBound.min)).toFixed(2)
					});
				}
			};
			
			var h = function (e, el){
				if (moveEl._dragging){
					$(moveEl).fireEvent("dragEnd", e);
				}
				moveEl._dragging = false;
			};
			$(container).on("mousemove", g).on("mouseup", h);
		}
	}
});

//slider class
Class.mixin(mix, {
	slider: Class({
		id: "",
		el: "",
		_smooth: "",
		_min: "",
		_max: "",
		_step: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			a._smooth = ($(el).attr("smooth") == "true");
			var range = $(el).attr("range").split("-");
			a._min = range[0].toFloat();
			a._max = range[1].toFloat();
			a._step = $(el).attr("step").toFloat();
			a.val(a.val());
			
			//initialize the position
			a.prepare();
		},
		prepare: function (){
			var a = this;
			var id = a.id;
			var pos = $("#" + id + "-outer").position();
			var min = pos.left;
			var max = pos.left + $("#" + id + "-outer").size().width;
			var l = min + a.val() * ((max-min) / ((a._max - a._min) / a._step)) - $("#" + id + "-btn").size().width / 2;
			$("#" + id + "-btn").css("left", l + "px");
			var xBound = {
				min: $("#" + id + "-outer").position().left,
				max: $("#" + id + "-outer").position().left + $("#" + id + "-outer").size().width
			};
			mix.drag.prepareDragElement($("#" + id + "-btn"), $("#" + id + "-btn"), document.documentElement, true, false, xBound);
			$("#" + id + "-btn").on("dragging", function (data){
				a.val(data.leftPer * (a._max - a._min));
			}).on("dragEnd", function (){
				a.fireEvent("change", a.val());
			});
			return this;
		},
		smooth: function (s){
			if (type(s) == "undefined")
				return this._smooth;
			else
				this._smooth = s;
			return this;
		},
		
		val: function (value){
			if (type(value) == "undefined"){
				return $("#" + this.id).firstElement().value;
			}else{
				value = parseFloat(value);
				var range = this._max - this._min;
				if (value > this._max || value < this._min)
					return this;
				var per = value / range;
				var numOfStep = Math.round(value / this._step);
				var v = this._min + this._step * numOfStep;
				$("#" + this.id).firstElement().value = v;
				if (! this._smooth){
					var pos = $("#" + this.id + "-outer").position();
					var min = pos.left;
					var max = pos.left + $("#" + this.id + "-outer").size().width;
					var l = min + numOfStep * ((max-min) / ((this._max - this._min) / this._step));
					$("#" + this.id + "-btn").css("left", l + "px");
				}
			}
		}
	})
});

//starRating class
Class.mixin(mix, {
	starRating: Class({
		id: "",
		el: "",
		_starNum: "",
		_editable: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			a._starNum = $(el).attr("starNum").toInteger();
			a._editable = ($(el).attr("editable") == "true");
			
			a.val(el.value);
			
			$("#" + id + "-outer").children().fTagName("img").on("mouseover", function (e, el){
				a.fireEvent("starMouseover", parseInt(el.id.replace(id+"-star", "")));
			}).on("mouseout", function (e, el){
				a.fireEvent("starMouseout", parseInt(el.id.replace(id+"-star", "")));
			}).on("click", function (e, el){
				a.fireEvent("starClick", parseInt(el.id.replace(id+"-star", "")));
			});
			
			a.on("starMouseover", function (star){
				if (! a._editable) return false;
				if (a.fireEvent("beforeStarMouseover", star) === false) return false;
				for (var i = 1; i <= star; i++)
					$("#" + id + "-star" + i).addClass("mixStarRating-starMOver");
				for (var i = star + 1; i <= a._starNum; i++)
					$("#" + id + "-star" + i).removeClass("mixStarRating-starMOver");
			}).on("starMouseout", function (star){
				if (! a._editable) return false;
				if (a.fireEvent("beforeStarMouseout", star) === false) return false;
				a.val(a.val());
			}).on("starClick", function (star){
				if (! a._editable) return false;
				if (a.fireEvent("beforeStarClick", star) === false) return false;
				a.val(parseInt(star));
			});
		},
		editable: function (editable){
			if (type(editable) == "undefined")
				return this._editable;
			else{
				this._editable = editable;
				return this;
			}
		},
		val: function (value){
			if (type(value) == "undefined")
				return this.el.value;
			else{
				if (this.el.value != value)
					this.fireEvent("change", parseInt(value));
				value = parseInt(value);
				this.el.value = value;
				for (var i = 1; i <= value; i++)
					$("#" + this.id + "-star" + i).addClass("mixStarRating-starMOver");
				for (var i = value + 1; i <= this._starNum; i++)
					$("#" + this.id + "-star" + i).removeClass("mixStarRating-starMOver");
				return this;
			}
		}
	})
});

//advertiser class
Class.mixin(mix, {
	advertiser: Class({
		id: "",
		el: "",
		_advNum: "",
		_showing: "",
		_rotate: "",
		_interval: "",
		_timer: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			a._advNum = $(el).attr("childNum").toInteger();
			a._showing = $(el).attr("showing");
			a._rotate = ($(el).attr("rotate") == "true");
			a._interval= $(el).attr("interval").toInteger();
			
			a.show(a._showing);
			a.rotate(a._rotate);
		},
		
		hideAll: function (){
			$(this.el).children().addClass("mixAdvertiser-hideAdv");
			return this;
		},
		show: function (adv){
			if (type(adv) == "undefined"){
				return parseInt(this._showing);
			}else{
				this._showing = adv;
				this.hideAll();
				$(this.el).children().fAttr("num", adv).removeClass("mixAdvertiser-hideAdv");
				return this;
			}
		},
		rotate: function (t){
			if (type(t) == "undefined"){
				return this._rotate;
			}else{
				if (t){
					var b = this;
					var _rotateFn = function (){
						var a = b.show();
						if (b.fireEvent("beforeRotate", a) === false) return false;
						a++;
						if (a > b._advNum){
							a = 1;
						}
						b.show(a);
						b.fireEvent("rotate", a);
					};
					_rotateFn.startTimer(this._interval);
					this._timer = _rotateFn._timer;
				}else{
					clearInterval(this._timer);
					this.fireEvent("stopRotate");
				}
				return this;
			}
		},
		interval: function (s){
			if (type(s) == "undefined")
				return this._interval;
			else{
				var r = this.rotate();
				s = parseInt(s);
				this.rotate(false);
				this._interval = s;
				this.rotate(r);
				return this;
			}
		}
	})
});

//validate class
Class.mixin(mix, {
	validate: Class({
		id: "",
		el: "",
		_type: "",
		_control: "",
		_valid: "",
		_range: "",
		_regex: "",
		_length: "",
		_showing: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			a._type = $(el).attr("type");
			a._control = $(el).attr("control");
			if (a._type == "range")
				a._range = $(el).attr("range");
			if (a._type == "regex")
				a._regex = $(el).attr("regex");
			if (a._type == "length")
				a._length = $(el).attr("length");
			a._valid = true;
			a._showing = false;
			if ($(el).attr("defaultShow") == "true")
				$(el).css("display", "inline");
			
			var t = $("#" + a._control);
			if (t.getInstance() !== false){
				t = t.getInstance();
			}
			t.on("change", function (){
				var val = t.val();
				if (a._type == "required"){
					a.setValid(val != "");
				}else if (a._type == "range"){
					var r = a._range.split("-");
					var min = r[0];
					var max = r[1];
					var val = t.val();
					
					if (parseFloat(val) == val){
						val = parseFloat(val);
						min = parseFloat(min);
						max = parseFloat(max);
					}
					a.setValid(val <= max && val >= min);
				}else if (a._type == "regex"){
					var val = t.val();
					var reg = new RegExp(a._regex);
					a.setValid(reg.test(val));
				}else if (a._type == "length"){
					var l = t.val().length;
					var r = a._length.split("-");
					var min;
					var max;
					if (r[0] == "u")
						min = l - 1;
					else
						min = r[0].toInteger();
					if (r[1] == "u")
						max = l + 1;
					else
						max = r[1].toInteger();
					a.setValid(l >= min && l <= max);
				}else if (a._type == "email"){
					a.setValid(mix.validation.isEmail(val));
				}
			});
		},
		
		valid: function (){
			return this._valid;
		},
		
		setValid: function (condition){
			if (condition){
				if (this.fireEvent("valid") === false) return false;
				this._valid = true;
				this.show(false);
			}else{
				if (this.fireEvent("invalid") === false) return false;
				this._valid = false;
				this.show(true);
			}
			return this;
		},
		
		show: function (showing){
			if (type(showing) == "undefined")
				return this._showing;
			else{
				this._showing = showing;
				if (this._showing){
					$(this.el).css("display", "inline");
				}else{
					$(this.el).css("display", "none");
				}
				return this;
			}
		}
	})
});

Class.mixin(mix, {
	accordion: Class({
		id: "",
		el: "",
		_showing: "",
		_showOne: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			a._showing = [];
			a._showOne = ($(el).attr("showOne") == "true");
			
			var title = $(el).children().fGroup("title");
			title.on("click", function (e, el){
				return a.fireEvent("titleClick", $(el).attr("index"));
			}).on("mouseover", function (e, el){
				return a.fireEvent("titleMouseover", $(el).attr("index"));
			});
			
			var content = $(el).children().fGroup("content");
			content.fAttr("expanded", "true").each(function (el){
				this._showing.push($(el).attr("index"));
				$(el).css("height", $(el).scroll().height + "px");
				title.fAttr("index", $(el).attr("index")).addClass("mixAccordion-selectedTtl");
			}, a);
			if ($(el).attr("mouseoverToggle") == "true"){
				a.on("titleMouseover", function (idx){
					if (a.fireEvent("beforeTitleMouseover", idx) === false) return false;
					if (! a._showing.exist(idx))
						a.hideAll().showSection(idx);
				});

			}else{
				a.on("titleClick", function (idx){
					if (a.fireEvent("beforeTitleClick", idx) === false) return false;
					a.toggleSection(idx);
				});
			}
		},
		
		toggleSection: function (idx){
			if (this._showing.exist(idx)){
				this.showSection(idx, false);
			}else{
				this.showSection(idx);
			}
			return this;
		},
		hideAll: function (){
			this._showing.each(function (idx){
				this.showSection(idx, false);
			}, this);
			return this;
		},
		togglable: function (idx, t){
			var a = $(this.el).children().fGroup("title").fAttr("index", idx);
			if (type(t) == "undefined")
				return (a.attr("togglable") != "false");
			else
				a.attr("togglable", (t ? "true" : "false"));
			return this;
		},
		showSection: function (idx, show, duration, fps){
			if (type(show) == "undefined")
				show = true;
			if (type(duration) == "undefined")
				duration = 500;
			if (type(fps) == "undefined")
				fps = 30;
			var title = $(this.el).children().fGroup("title").fAttr("index", idx);
			if (title.attr("togglable") == "false")
				return this;
			if (show){
				if (this._showOne)
					this.hideAll();
				var a = $(this.el).children().fGroup("content").fAttr("index", idx);
				var height = a.scroll().height;
				a.stopAnimation();
				a.animate({
					"height": [parseInt(a.css("height") ? a.css("height") : 0) + "px", height + "px"]
				}, duration, fps, mix.animation.opposite(mix.animation.expo));
				this._showing.push(idx);
				$(this.el).children().fGroup("title").fAttr("index", idx).addClass("mixAccordion-selectedTtl");
			}else{
				var a = $(this.el).children().fGroup("content").fAttr("index", idx);
				a.stopAnimation();
				a.animate({
					"height": [parseInt(a.css("height")) + "px", "0px"]
				}, duration, fps, mix.animation.opposite(mix.animation.expo));
				this._showing = this._showing.remove(idx);
				$(this.el).children().fGroup("title").fAttr("index", idx).removeClass("mixAccordion-selectedTtl");
			}
			return this;
		}
	})
});

Class.mixin(mix, {
	hSelect: Class({
		id: "",
		el: "",
		_selected: "",
		_options: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			if ($(el).attr("vertical") != "true")
				a._options = $(el).firstChild().firstChild().children().fTagName("td");
			else
				a._options = $(el).firstChild().children().children().fTagName("td");
			a.val($("#" + id + "-value").val());
			
			a._options.on("click", function (e, el){
				return a.fireEvent("optionClick", $(el).attr("value"));
			}).on("mouseover", function (e, el){
				return a.fireEvent("optionMouseover", $(el).attr("value"));
			}).on("mouseout", function (e, el){
				return a.fireEvent("optionMouseout", $(el).attr("value"));
			});
			
			a.on("optionClick", function (value){
				if (a.fireEvent("beforeOptionClick", value) === false) return false;
				a.val(value);
			}).on("optionMouseover", function (value){
				if (a.fireEvent("beforeOptionMouseover", value) === false) return false;
				a._options.fAttr("value", value).addClass("mixHSelect-mOver");
			}).on("optionMouseout", function (value){
				if (a.fireEvent("beforeOptionMouseout", value) === false) return false;
				a._options.fAttr("value", value).removeClass("mixHSelect-mOver");
			});
		},
		
		val: function (val){
			if (type(val) == "undefined")
				return $("#" + this.id + "-value").val();
			if (this._selected == val)
				return this;
			var option = this.getElementByValue(val);
			if (val == ""){
				this._selected = "";
				$("#" + this.id + "-select").css("display", "none");
				$("#" + this.id + "-value").val("");
				return this;
			}
			var pos;
			if ($(this.el).attr("pos") == "absolute")
				pos = option.position(true);
			else
				pos = option.position();
			
			var size = option.size();
			var offset = 0;
			var posOffset = 1;
			if (mix.browser.isIE){
				offset = 1;
				posOffset = 0;
			}
			if (this._selected == ""){
				$("#" + this.id + "-select").css("display", "block").css("zIndex", "5").css("left", (pos.left - posOffset) + "px").css("top", (pos.top - posOffset) + "px")
					.css("width", (size.width - offset)+"px").css("height", (size.height - offset)+"px");
			}else{
				$("#" + this.id + "-select").css("display", "block").stopAnimation().animate({
					"left": [(pos.left - posOffset) + "px"],
					"top": [(pos.top - posOffset) + "px"],
					"width": [(size.width - offset) + "px"],
					"height": [(size.height - offset) + "px"]
				}, 500, 30, mix.animation.opposite(mix.animation.expo));
			}
			this._selected = val;
			$("#" + this.id + "-value").val(val);
			this.fireEvent("change", val);
			return this;
		},
		getElementByValue: function (val){
			return this._options.fAttr("value", val);
		}
	})
});

Class.mixin(mix, {
	richEditor: Class({
		id: "",
		el: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			
			this.editable($(el).attr("editable") != "false");
			this.iframeVal($("#" + id + "-txt").val());
		},
		
		getIFrameDoc: function (){
			if (this.el.contentDocument)
				return this.el.contentDocument;
			else
				return document.frames[this.id].document;
		},
		
		editable: function (edit){
			if (type(edit) == "undefined"){
				return ($(this.el).attr("editable") == "false");
			}else{
				if (edit){
					$(this.el).attr("editable", "true").firstElement().contentDocument.designMode = "on";
				}else{
					$(this.el).attr("editable", "false").firstElement().contentDocument.designMode = "off";
				}
			}
		},
		
		iframeVal: function (value){
			if (type(value) == "undefined"){
				return this.el.contentWindow.document.body.innerHTML;
			}else{
				this.el.contentWindow.document.body.innerHTML = value;
			}
		},
		
		txtAreaVal: function (value){
			if (type(value) == "undefined"){
				return $("#" + id + "-txt").val();
			}else{
				$("#" + id + "-txt").val(value);
			}
		},
		
		execCmd: function (param, arg){
			this.getIFrameDoc().execCommand(param, false, arg);
			return this;
		},
		
		bold: function (){
			return this.execCmd("bold");
		},
		
		italic: function (){
			return this.execCmd("italic");
		},
		
		underline: function (){
			return this.execCmd("underline");
		},
		
		strikeThrough: function (){
			return this.execCmd("strikethrough");
		},
		
		foreColor: function (color){
			return this.execCmd("forecolor", (color.charAt(0) == "#" ? color.substr(1) : color));
		},
		
		hiliteColor: function (color){
			return this.execCmd("hilitecolor", (color.charAt(0) == "#" ? color.substr(1) : color));
		},
		
		justify: function (opt){
			return this.execCmd("justify" + opt);
		},
		
		ul: function (){
			return this.execCmd("insertunorderedlist");
		},
		
		ol: function (){
			return this.execCmd("insertorderedlist");
		},
		
		indent: function (){
			return this.execCmd("indent");
		},
		
		outdent: function (){
			return this.execCmd("outdent");
		},
		
		fontSize: function (size){
			return this.execCmd("fontsize", parseInt(size));
		},
		
		removeFormat: function(){
			return this.execCmd("removeformat");
		},
		
		superscript: function (){
			return this.execCmd("superscript");
		},
		
		subscript: function (){
			return this.execCmd("subscript");
		},
		
		hr: function (){
			return this.execCmd("inserthorizontalrule");
		},
		
		insertLink: function (text, url){
			return this.execCmd("inserthtml", "<a href=\"" + url + "\">" + text + "</a>");
		}
	})
});

Class.mixin(mix, {
	colorPicker: Class({
		id: "",
		el: "",
		hex: "0123456789ABCDEF",
		red: "",
		green: "",
		blue: "",
		bgR: "",
		bgG: "",
		bgB: "",
		
		__construct: function (id, el){
			var a = this;
			a.id = id;
			a.el = el;
			
			this.red = 0;
			this.green = 0;
			this.blue = 0;
			this.bgR = 0;
			this.bgG = 0;
			this.bgB = 0;
			
			this.init();
			
			this.val($("#"+id+"-value").val());
		},
		
		init: function (absPos){
			if (type(absPos) == "undefined")
				absPos = true;
			var id = this.id;
			$("#" + id + "-hueHandle").removeAllEventListeners("change");
			$("#" + id + "-bwHandle").removeAllEventListeners("change");
			var pos = $("#" + id + "-bw").position(absPos);
			var size = $("#" + id + "-bw").size();
			var xBound = {min:pos.left, max:pos.left + size.width};
			var yBound = {min:pos.top, max:pos.top + size.height};
			$("#" + id + "-bwHandle").css("left", (pos.left + size.width / 2) + "px").css("top", (pos.top + size.height / 2) + "px");
			mix.drag.prepareDragElement($("#" + id + "-bwHandle"), $("#" + id + "-bwHandle"), $("body"), true, true, xBound, yBound);
			
			pos = $("#" + id + "-hue").position(absPos);
			size = $("#" + id + "-hue").size();
			xBound = {min:pos.left, max:pos.left + size.width};
			yBound = {min:pos.top, max:pos.top + size.height};
			$("#" + id + "-hueHandle").css("left", (pos.left + size.width / 2) + "px").css("top", (pos.top + size.height / 2) + "px");
			mix.drag.prepareDragElement($("#" + id + "-hueHandle"), $("#" + id + "-hueHandle"), $("body"), true, true, xBound, yBound);
			
			$("#" + id + "-hueHandle").on("dragging", function (arg){
				var x = arg.topPer * 6;
				var r = (x >= 2 && x <= 4 ? 0 :1);
				r = (x > 1 && x <= 2 ? (-x + 2) : r);
				r = (x >= 4 && x <=5 ? (x-4) : r);
				var g = (x >= 4 ? 0 :1);
				g = (x >= 0 && x <= 1 ? x : g);
				g = (x >= 3 && x <= 4 ? (- x + 4) : g);
				var b = (x <= 2 ? 0 :1);
				b = (x > 2 && x <= 3 ? (x - 2) : b);
				b = (x >= 5 && x <= 6 ? (-x + 6) : b);
				this.setBg(parseInt(r * 255), parseInt(g * 255), parseInt(b*255));
				
				var pos = $("#" + id + "-bwHandle").position(true);
				var bPos = $("#" + id + "-bw").position(true);
				var bSize = $("#" + id + "-bw").size();
				var size = $("#" + id + "-bwHandle").size();
				$("#" + id + "-bwHandle").fireEvent("dragging", {leftPer: ((pos.left + size.width / 2 - bPos.left) / bSize.width).toFixed(2),topPer: ((pos.top + size.height / 2 - bPos.top) / bSize.height).toFixed(2)});
			}, this);
			
			$("#" + id + "-bwHandle").on("dragging", function (arg){
				var r = this.bgR;
				r = arg.leftPer * (r + (255 - r) * arg.topPer);
				var g = this.bgG;
				g = arg.leftPer * (g + (255 - g) * arg.topPer);
				var b = this.bgB;
				b = arg.leftPer * (b + (255 - b) * arg.topPer);
				this.red = parseInt(r);
				this.green = parseInt(g);
				this.blue = parseInt(b);
				this.fireEvent("change", [{r:this.red,g:this.green,b:this.blue}, (this.dec2hex(this.red) + this.dec2hex(this.green) + this.dec2hex(this.blue))]);
			}, this);
			return this;
		},
		
		hex2dec: function (hexNum){
			var a = 0;
			for (var i = hexNum.length - 1; i > -1; i--){
				a += parseInt(this.hex.indexOf(hexNum.charAt(i))) * Math.pow(16, i);
			}
			return a;
		},
		
		dec2hex: function (decNum){
			var hv = "";
			for (var i = 0; i < 2; i++){
				k = decNum & 15;
				hv = this.hex.charAt(k) + hv;
				decNum = decNum >> 4;
			}
			return hv;
		},
		
		setBg: function (r, g, b){
			$("#" + this.id + "-bw").css("background-color", "#" + this.dec2hex(r) + this.dec2hex(g) + this.dec2hex(b));
			this.bgR = r;
			this.bgG = g;
			this.bgB = b;
			return this;
		},
		
		val: function (r, g, b, hex){
			if (type(r) == "undefined"){
				return $("#"+this.id+"-value").val();
			}else{
				if (type(g) == "undefined"){
					this.red = this.hex2dec(r.substring(0, 2));
					this.green = this.hex2dec(r.substring(2, 4));
					this.blue = this.hex2dec(r.substring(4, 6));
					$("#"+this.id+"-value").val(r);
				}else{
					if (type(hex) == "undefined" || ! hex){
						var a = this.dec2hex(r) + this.dec2hex(g) + this.dec2hex(b);
						this.red = r;
						this.green = g;
						this.blue = b;
						$("#"+this.id+"-value").val(a);
					}else{
						this.red = this.hex2dec(r);
						this.green = this.hex2dec(g);
						this.blue = this.hex2dec(b);
						$("#"+this.id+"-value").val(r + g + b);
					}
				}
				this.setBg(this.red, this.green, this.blue);
				
				return this;
			}
		}
	})
});

Class.mixin(mix, {
	xml: {
		parseFromString: function (str){
			try{
				var x = new ActiveXObject("Microsoft.XMLDOM");
				x.async = "false";
				x.loadXML(str);
				return x;
			}catch(e){
				try{
					var x = new DOMParser();
					x = x.parseFromString(str, "text/xml");
					return x;
				}catch(e){
				}
			}
			return false;
		}
	}
});

Class.mixin(mix, {
	event: Class({
	})
});
mix.Events = new mix.event();

/*
	short hand for using objects
*/
var $ = function (el){
	return (new mix.elements(el));
};
var type = function (el){
	return mix.validation.getType(el);
};
var time = function (){
	return (new Date()).getTime();
};
var date = function (format, timeStamp){
	if (type(timeStamp) == "undefined")
		timeStamp = time();
	var d = new Date();
	d.setTime(timeStamp);
	return d.toFormat(format);
};

//preparing
window.onload = function (){
	mix.Events.fireEvent("load");
};
window.onunload = function(){};

mix.UIComponents = new Array();
var end;
mix.Events.on("load", function (){
	var t = $(document.documentElement);
	t.createInstance();
	
	$().gAttr("usetip").each(function (el){
		$(el).usetip($(el).attr("usetip"));
	});
	end = time();
});
