/*	====================================================================
		This code is created by Alessio D'Adamo Jacopo
		and it is intend of property of Alessio D'Adamo Jacopo
		Copyright© 2010 -2010
	====================================================================   */
	

// CORE

function log(){
	console.log.apply(this,arguments);
}

// Excpetions

function Exception(exc,name){
	this.name=(!$exists(name))?"Generic Exception":name;
	this.message=exc;
	return new Error(this.toString());
}
Exception.prototype=new Error;
Exception.prototype.constructor=Exception;
Exception.prototype.toString=function(){
	return this.name+": "+this.message;
}
Exception.prototype.getMessage=function(){
	return this.message;
}

function RuntimeException(exc){
	return Exception.call(this,"Uncompilable source code - "+exc,"Exception RuntimeException");
}
RuntimeException.prototype=new Exception;
RuntimeException.prototype.constructor=RuntimeException;

function CallToSuperException(classname){
	return RuntimeException.call(this,"call to super must be first statement in constructor of class <"+classname+">.");
}
CallToSuperException.prototype=new RuntimeException;
CallToSuperException.prototype.constructor=CallToSuperException;

function AbstractMethodException(classname,method){
	return RuntimeException.call(this,"class <"+classname+"> is not abstract and does not override abstract method "+method+"()");
}
AbstractMethodException.prototype=new RuntimeException;
AbstractMethodException.prototype.constructor=AbstractMethodException;

function InstantiationException(classname){
	return RuntimeException.call(this,"class <"+classname+"> is abstract; cannot be instantiated.");
}
InstantiationException.prototype=new RuntimeException;
InstantiationException.prototype.constructor=InstantiationException;

function IllegalArgumentException(func_name,error){
	return RuntimeException.call(this,"Function "+func_name+"() has illegal arguments: "+error);
}
IllegalArgumentException.prototype=new RuntimeException;
IllegalArgumentException.prototype.constructor=IllegalArgumentException;

function ClassFormatException(exc){
	return Exception.call(this,exc,"Exception ClassFormatException");
}
ClassFormatException.prototype=new Exception;
ClassFormatException.prototype.constructor=ClassFormatException;

function NotFunctionBodyException(method,value){
	return ClassFormatException.call(this,"Body of method "+method+"() is not a function: "+typeof(value));
}
NotFunctionBodyException.prototype=new ClassFormatException;
NotFunctionBodyException.prototype.constructor=NotFunctionBodyException;

function IllegalModifierException(classname,method,modifier){
	return ClassFormatException.call(this,"Method "+method+"() in class <"+classname+"> has illegals modifiers"+((modifier)?": "+modifier:"."));
}
IllegalModifierException.prototype=new ClassFormatException;
IllegalModifierException.prototype.constructor=IllegalModifierException;

// CORE

function $(_this_){
	var _class_=$.getOwnerClass($.caller);
	if(!_this_||!_class_||!_class_.__classid__) return null;
	var classid=_class_.__classid__;
	if(_this_==_class_) return _this_.__static_space__;
	var priv=_this_[classid];
	if(priv) return priv;
	priv=new _class_.__priv_builder__(_this_);
	return _this_[classid]=priv;
}
$.getOwnerClass=function(caller){
	while(caller){
		if(caller.__class__) return caller.__class__;
		caller=caller.caller;
	}
	return null;
}
	
function Class(_classname,_class,abstract,interface){
	_class=_class||{public:{}};
	if(typeof(_classname)!="string"){
		_class=_classname;
		_classname=null;
	}
	var constructor;
	var static_pattern=/^static__|^static /;
	var abstract_pattern=/^abstract__|^abstract /;
	var override_pattern=/^override__|^override /;
	var all_patterns=/^static__|^static |^override__|^override|^abstract__|^abstract /;
	var illegalmodifier_pattern=/(^static__|^static )(abstract__|abstract )|(^abstract__|^abstract )(static__|static )/;
	var clear_pattern=/"|'|\\|^\s+|\s+$/g;
	var illegal_pattern=/[^\w$]|^\d+/;
	var super_pattern=/^\$\(this\)\.Super\(/;
	var public_pattern="public";
	var private_pattern="private";
	var constructor_pattern="__constructor";
	var natives=["prototype","__constructor__","__class__","__abstract__","__interface__","__classname__","__classid__","__parentclass__","__priv_builder__"];
	var definedmethods=[];
	var public=_class.public;
	if(!public&&!_classname) throw(new ClassFormatException("Class <unknown> must have a public constructor."));
	var private=_class.private;
	var parent=_class.Extends;
	var interfaces=_class.Implements;
	delete _class.Extends;
	delete _class.Implements;
	var privbuilder;
	var _extends_=function(){};
	var _implements_=function(){};
	function missingSuperCall(constructor){
		return !super_pattern.test(constructor.getInnerCode());
	}
	function addMethod(obj,method,code,force){
		if(!force&&$find(method,definedmethods)) throw(new RuntimeException(method+"() is already defined in <"+classname+">"));
		obj[method]=code;
		if(code) definedmethods.push(method);
		if(!obj[method]) return;
		obj[method].__class__=constructor;
	}
	if(parent){
		_extends_=function(){
			if(!interface&&parent.__interface__) throw(new RuntimeException("no interface expected in class <"+classname+">"));
			var _void_=function(){};
			_void_.prototype=parent.prototype;
			constructor.prototype=new _void_;
			constructor.prototype.constructor=constructor;
			constructor.__parentclass__=parent;
			constructor.prototype.__class__=constructor;
			var parentid=parent.__classid__;
			for(var key in parent){
				if(parent.hasOwnProperty(key)&&!$find(key,natives)&&key!=parentid) addMethod(constructor,key,parent[key]);
			}
		}
	}
	if(interfaces){
		_implements_=function(){
			if(interface) throw(new RuntimeException("interface have no implementation <"+classname+">"));
			var list=(interfaces instanceof Array)?interfaces:[interfaces];
			var length=list.length;
			for(var i=length;i;){
				var _interface=list[--i];
				if(!_interface.__interface__) throw(new RuntimeException("interface expected in class <"+classname+">"));
				for(var key in _interface.prototype){
					if(_interface.prototype.hasOwnProperty(key)&&!$find(key,natives)) addMethod(constructor.prototype,key,_interface.prototype[key]);
				}
				for(var key in _interface){
					if(_interface.hasOwnProperty(key)&&!$find(key,natives)) addMethod(constructor,key,_interface[key]);
				}
			}	
		}
	}
	if(!_classname){
		for(_classname in public){
			if(public.hasOwnProperty(_classname)) break;
		}
	}
	var classname=_classname.replace(illegalmodifier_pattern,"").replace(all_patterns,"").replace(clear_pattern,"");
	var _constructor=public[_classname];
	delete public[classname];
	if(_constructor&&interface) throw(new ClassFormatException("Interface <"+classname+"> cannot have a constructor."));
	if(illegalmodifier_pattern.test(_classname)) throw(new IllegalModifierException(classname,_classname));
	if(illegal_pattern.test(_classname)) throw(new ClassFormatException("Property <"+_classname+"> in class <"+classname+"> has illegal name."));
	if(static_pattern.test(_classname)) throw(new ClassFormatException("Constructor of class <"+classname+"> has illegals modifiers: static"));
	_constructor=_constructor||function(){};
	if(typeof(_constructor)!="function") throw(new NotFunctionBodyException(_classname,public[classname]));
	if(parent&&missingSuperCall(_constructor)) throw(new CallToSuperException(classname));
	if(abstract||interface){
		constructor=function(){throw(new InstantiationException(classname));}
		constructor.__constructor__=_constructor;
		constructor.__constructor__.__class__=constructor;
	}
	else constructor=_constructor;
	if(!interface){
		privbuilder=constructor.__priv_builder__=function(_this_){
			this._this_=_this_;
		}
	}
	_extends_();
	constructor.__classname__=classname;
	constructor.__class__=constructor;
	constructor.__classid__=$uniqueId();
	constructor.__abstract__=(abstract)?1:0;
	constructor.__interface__=(interface)?1:0;
	constructor.prototype.__class__=constructor;
	_implements_();
	if(public){
		for(var key in public){
			if(!public.hasOwnProperty(key)) continue;
			var value=public[key];
			var p=key.replace(illegalmodifier_pattern,"").replace(all_patterns,"").replace(clear_pattern,"");
			if(illegalmodifier_pattern.test(key)) throw(new IllegalModifierException(classname,p));
			if(illegal_pattern.test(p)) throw(new ClassFormatException("Property <"+p+"> has illegal name."));
			if(static_pattern.test(key)){
				if(typeof(value)=="function"&&interface) throw(new IllegalModifierException(classname,p,"static"));
				addMethod(constructor,p,value);
				//addMethod(constructor.prototype,p,function(value){return function(){ return value.apply(constructor,arguments);}}(value),true);
			}
			else if(!(abstract||interface)){
				if(!value) throw(new AbstractMethodException(classname,p));
				if(typeof(value)!="function") throw(new NotFunctionBodyException(p,value));
				addMethod(constructor.prototype,p,value);
			}
			else{
				if(abstract_pattern.test(key)||interface){
					if(value) throw(new ClassFormatException("Abstract method "+p+"() of class <"+classname+"> cannot have a body."));
				}
				else if(abstract){
					if(!value) throw(new ClassFormatException("Missing method body "+p+"() in class <"+classname+">, or declare it abstract."));
					if(typeof(value)!="function") throw(new NotFunctionBodyException(p,value));
				}
				addMethod(constructor.prototype,p,value);
			}
		}
	}
	if(private){
		for(var key in private){
			if(!private.hasOwnProperty(key)) continue;
			var value=private[key];
			var p=key.replace(illegalmodifier_pattern,"").replace(all_patterns,"").replace(clear_pattern,"");
			if(illegalmodifier_pattern.test(key)) throw(new IllegalModifierException(classname,p));
			if(illegal_pattern.test(p)) throw(new ClassFormatException("Property <"+p+"> has illegal name."));
			if(interface) throw(new IllegalModifierException(classname,p,"private"));
			if(static_pattern.test(key)){
				if(!statics) var statics=constructor.__static_space__={};
				if(typeof(value)=="function") addMethod(statics,p,function(value){return function(){ return value.apply(constructor,arguments);}}(value));
				else addMethod(statics,p,value);
			}
			else{
				if(!value&&!abstract) throw(new AbstractMethodException(classname,p));
				if(typeof(value)!="function") throw(new NotFunctionBodyException(p,value));
				addMethod(privbuilder.prototype,p,function(value){return function(){return value.apply(this._this_,arguments);}}(value));
			}
		}
	}
	if(!abstract&&!interface){
		for(var key in constructor.prototype){
			if(!constructor.prototype[key]) throw(new AbstractMethodException(classname,key));
		}
	}
	if(parent&&!interface){
		privbuilder.prototype.Super=function(){
			this.Super=new this.__super__();
			this.Super._this_=this._this_;
			if(parent.__constructor__) parent.__constructor__.apply(this._this_,arguments);
			else parent.apply(this._this_,arguments);
		}
		privbuilder.prototype.__super__=function(){};
		var _super_=privbuilder.prototype.__super__.prototype;
		for(key in parent.prototype){
			if(parent.prototype.hasOwnProperty(key)&&typeof(parent.prototype[key])=="function"&&key!="__class__"){
				_super_[key]=function(m){
					return function(){
						return m.apply(this._this_,arguments);
					}
				}(parent.prototype[key])
			}
		}
	}
	window[classname]=constructor;
	return window[classname];
}

function AbstractClass(_classname,_class){
	Class(_classname,_class,true);
}

function Interface(_classname,_class){
	Class(_classname,_class,false,true);
}

// ===================================================================================================================

// Global Vars

var undefined;

// =============================== Native function ====================================

function $uniqueId(){
	return (++$uniqueId.counter+new Date().getTime()).toString(16);
}
$uniqueId.counter=0;

function $f(){
	return function(){};
}

function $isNull(obj){
	return obj===null;
}

function $isUndefined(obj){
	return obj===undefined;
}

function $exists(obj){
	return obj!=null;
}

function $isFunction(obj){
	return typeof(obj)=="function";
}

function $isString(obj){
	return typeof(obj)=="string";
}

function $isNumber(obj){
	return typeof(obj)=="number";
}

function $isObject(obj){
	return obj&&typeof(obj)=="object"&&obj.constructor===Object;
}

function $isArray(obj){
	return obj instanceof Array;
}

function $isRegExp(obj){
	return obj instanceof RegExp;
}

function $argumentsToArray(args,deletefirst){
	return [].slice.call(args,deletefirst||0);
}

function $objectToArray(obj){
	if(!$isObject(obj)) return null;
	var array=[];
	var i=0;
	for(var key in obj){
		if(obj.hasOwnProperty(key)) array[i++]={property:key,value:obj[key]};
	}
	return array;
}

function $firstValid(){
	var length=arguments.length;
	for(var i=0;i<length;i++){
		if(arguments[i]!=null) return arguments[i];
	}
	return null;
}

function $fillObject(obj){
	var args=$argumentsToArray(arguments,1);
	var length=args.length;
	for(var key in obj){
		if(obj.hasOwnProperty(key)){
			if(obj[key]==null){
				for(var i=0;i<length;i++){
					if(args[i]==null){
						args.splice(i--,1);
						length--;
						continue;
					}
					if((obj[key]=args[i][key])!=null) break;
				}
			}
		}
	}
	return obj;
}

function $mergeObjects(){
	var args=$argumentsToArray(arguments);
	var length=args.length;
	var o={};
	for(var i=0;i<length;i++){
		var obj=args[i];
		for(var key in obj){
			if(obj.hasOwnProperty(key)&&obj[key]!=null){
				o[key]=obj[key];
			}
		}
	}
	return o;
}

function $find(value){
	var args=(arguments[1] instanceof Array)?arguments[1]:$argumentsToArray(arguments,1);
	var length=args.length;
	var bool=false;
	for(var i=length;i--;){
		if(args[i]==value) return true;
	}
	return false;
}

function $clone(obj){
	var f=function(){};
	f.prototype=obj;
	var o=new f;
	return o;
}

function $classname(obj){
	if(!obj) return null;
	if(obj.__classname__) return obj.__classname__;
	var _class=obj.__class__;
	if(_class) return _class.__classname__;
	return null;
}

function $alert(){
	var length=arguments.length;
	var s="";
	for(var i=0;i<length;i++){
		s+=(arguments[i])?arguments[i].toString():($isUndefined(arguments[i]))?"undefined":"null";
		if(i<length) s+=", ";
	}
	alert(s);
}

function $main(func){
	var id=setInterval(function(){
		if(document.body){
			clearInterval(id);
			func();
		}
	},0);
}

function $onLoad(func){
	if(window.addEventListener) window.addEventListener("load",func,false);
	else window.attachEvent("onload",func);
}

function $onUnload(func){
	if(window.addEventListener) window.addEventListener("unload",func,false);
	else window.attachEvent("onunload",func);
}

function $html(tagName,imprint){
	if(!tagName) return document;
	if(tagName.match(/^\s*</)) return $$($html("div",{innerHTML:tagName.replace(/\s+?(?=<)/,"")}).childNodes[0]);
	var elm=$$(document.createElement(tagName));
	elm.set(imprint);
	return elm;
}

function $id(id){
	return $$(document.getElementById(id));
}

function $tag(tagName,filter){
	return (new HtmlList(document.getElementsByTagName(tagName))).sift(filter);
}

function $name(name,filter){
	return (new HtmlList(document.getElementsByName(name))).sift(filter);
}

function $class(className,filter){
	var elms=new HtmlList(document.getElementsByTagName("*"));
	filter=filter||{};
	filter.className=className;
	return elms.sift(filter);
}

function $implements(obj,methods_obj,_class_){
	for(var key in methods_obj){
		if(methods_obj.hasOwnProperty(key)) {
			obj[key]=methods_obj[key];
			if(obj[key]&&_class_) obj[key].__class__=_class_;
		}
	}
	if(methods_obj.hasOwnProperty("toString")){
		obj["toString"]=methods_obj["toString"];
		if(obj["toString"]&&_class_) obj["toString"].__class__=_class_;
	}
	return obj;
}

function $implementsPrivate(obj,methods_obj,_class_){
	obj.__priv_builder__=obj.__priv_builder__||function(_this_){
		this._this_=_this_;
	}
	var privbuilder=obj.__priv_builder__.prototype;
	for(var key in methods_obj){
		var value=methods_obj[key];
		if(methods_obj.hasOwnProperty(key)) {
			privbuilder[key]=function(value){return function(){return value.apply(this._this_,arguments);}}(value);
			if(privbuilder[key]&&_class_) privbuilder[key].__class__=_class_;
		}
	}
	return obj;
}

function $$(element){
	if(element&&!element.onClick) $implements(element,Element,Element);
	return element;
}

// ================================ Native implementations =====================================

$implements(Function.prototype, {
	when:function(event_type,delay){
		switch(event_type){
			case Event.DOCUMENT_LOAD:
				$onLoad(this);
				break;
			case Event.DOCUMENT_READY:
				$onReady(this);
				break;
			case Event.TIMEOUT:
				var delay=(delay)?delay:100;
				return setTimeout(this,delay);
			case Event.INTERVAL:
				var delay=(delay)?delay:100;
				return setInterval(this,delay);
		}
		return -1;
	},
	self:function(scope,argsArray){
		var self=this;
		this.__class__=$.getOwnerClass(arguments.callee.caller);
		if(!scope) return this;
		this.__class__=scope.__class__;
		if(argsArray){
			return function(){
				return self.apply(scope,argsArray);
			}
		}
		return function(){
			return self.apply(scope,arguments);
		}
	},
	setTimeout:function(delay,scope){
		var func=(scope||arguments.length>2)?this.self(scope||this,$argumentsToArray(arguments,2)):this;
		return new EventHandler("timeout",{id:setTimeout(func,delay),delya:delay},func);
	},
	setInterval:function(delay,scope){
		var func=(scope||arguments.length>2)?this.self(scope||this,$argumentsToArray(arguments,2)):this;
		return new EventHandler("interval",{id:setInterval(func,delay),delay:delay},func);
	},
	onTimeElapsed:function(func,scope){
		var scope=scope||this;
		var _func=function(evt){
			return func.call(scope,new Event(evt,this,_func));
		}
		this.onElapsed=_func;
		return new EventHandler("timeElapsed",id,this,delay);
	},
	repeatFor:function(n,delay){
		var self=this;
		var n=(n)?n:0;
		if(n>0){
			var id=(function(){
				if(--n==0) id.clear();
				self();
			}).setInterval(delay);
			return id;
		}
		else return this.setInterval(delay);
	},
	append:function(functionCode){
		if(typeof(functionCode)!="function") return this;
		var self=this;
		return function(){
			self.apply(self,arguments);
			return functionCode();
		}
	},
	getCode:function(name){
		return "var "+name+"="+this.toString()+";";
	},
	getInnerCode:function(){
		return this.toString().replace(/^function\s*\(.+?{\s*|}$/g,"");
	}
});
		
if(![].foreach){
	$implements(Array.prototype, {
		foreach:function(func){
			if(typeof(func)!="function") return;
			var length=this.length;
			for(var i=0;i<length;i++){
				func(this[i],i,this);
			}
		}
	});
}

if(![].indexOf){
	$implements(Array.prototype, {
		indexOf:function(targetElement,startIndex){
			var length=this.length;
			startIndex=(startIndex<0)?0:(startIndex>=length)?length-1:startIndex;
			for(var i=0;i<length;i++){
				if(this[i]==targetElement) return i;
			}
			return -1;
		}
	});
}

if(![].lastIndexOf){
	$implements(Array.prototype, {
		lastIndexOf:function(targetElement,startIndex){
			if([].lastIndexOf) return [].lastIndexOf.apply(this,arguments);
			var length=this.length;
			startIndex=(startIndex<0)?0:(startIndex>=length)?length-1:startIndex;
			for(var i=startIndex;i>0;i--){
				if(this[i]==targetElement) return i;
			}
			return -1;
		}
	});
}

if(![].map){
	$implements(Array.prototype, {
		map:function(func){
			if(typeof(func)!="function") return;
			var length=this.length;
			start=(!start||start<0)?0:(start>=length)?length-1:start;
			end=(!end)?length:(end<0)?0:(end>=length)?length-1:(end<=start)?start+1:end;
			var array=[];
			for(var i=start;i<end;i++){
				array[i]=func(this[i]);
			}
			return array;
		}		
	});			
}

if(![].some){
	$implements(Array.prototype, {
		some:function(func){
			var length=this.length;
			for(var i=0;i<length;i++){
				if(func(this[i])) return true;
			}
			return false;
		}
	});			
}
		
$implements(Array.prototype, {
	remove:function(targetElement,startIndex){
		var length=this.length;
		startIndex=(startIndex<0)?0:(startIndex>=length)?length:startIndex||0;
		if(typeof(targetElement)=="number") return this.splice(targetElement,1);
		for(var i=startIndex;i<length;i++){
			if(this[i]==targetElement){
				this.splice(i,1);
				return i;
			}
		}
		return -1;
	},
	selfmap:function(func,start,end){
		if(typeof(func)!="function") return;
		var length=this.length;
		start=(!start||start<0)?0:(start>=length)?length-1:start;
		end=(!end)?length:(end<0)?0:(end>=length)?length-1:(end<=start)?start+1:end;
		for(var i=start;i<end;i++){
			this[i]=func(this[i]);
		}
	},
	someIndex:function(func){
		var length=this.length;
		for(var i=0;i<length;i++){
			if(func(this[i])) return i;
		}
		return -1;
	},
	someObject:function(func){
		var length=this.length;
		for(var i=0;i<length;i++){
			if(func(this[i])) return this[i];
		}
		return null;
	},
	insert:function(obj,pos){
		var post=this.splice(pos,this.length);
		this.push(obj);
		[].push.apply(this,post);
		return this.length;
	},
	fill:function(obj,from,length){
		if(length){
			from=from||0;
			length=from+length;
		}
		else{
			length=from;
			from=0;
		}
		for(var i=from;i<length;i++){
			this[i]=obj;
		}
		return this;
	},
	getLast:function(){
		return this[this.length-1];
	},
	fromLast:function(index){
		return this[this.length-1-index];
	},
	contain:function(obj){
		var length=this.length;
		for(var i=0;i<length;i++){
			if(this[i]==obj) return true;
		}
		return false;
	}
});

$implements(Math, {
	roundUp:function(number){
		var r=Math.round(number);
		return (r-number>=0)?r:r+1;
	},
	sign:function(number){
		return (Math.abs(number)-number==0)?1:-1;
	}
});

$implements(Number.prototype, {
	between:function(min,max){
		return this>=min&&this<=max;
	},
	numToHex:function(digits){
		var s=this.toString(16);
		digits=digits||0;
		digits-=s.length;
		digits=(digits<0)?0:digits;
		while(digits--){
			s="0"+s;
		}
		return s;
	},
	carry:function(n){
		return (this&n)==n;
	}
});

$implements(String.prototype, {
	escape:function(){
		return this.replace(/(")|(')|(\\)/g,"\\$1$2$3");
	},
	unescape:function(){
		return this.replace(/\\(.)/g,/$1/);
	},
	isEmpty:function(){
		return this.length==0;
	},
	isNumber:function(start,length){
		if(this.length==0) return false;
		start=start||0;
		length=length||this.length;
		return this.substr(start,length).replace(/\d*\.*\d+/,"").length==0;
	},
	isWord:function(start,length){
		if(this.length==0) return false;
		start=start||0;
		length=length||this.length;
		return this.substr(start,length).replace(/[A-z]+/,"").length==0;
	},
	hexToNum:function(){
		var length=this.length;
		var hex=0;
		for(var i=length;i;){
			var char=this.charAt(length-i);
			hex+=((char.isNumber())?parseInt(char,10):(char.charCodeAt(0).between(65,70))?char.charCodeAt(0)-55:(char.charCodeAt(0).between(97,102))?char.charCodeAt(0)-87:Number.NaN)*Math.pow(16,--i);
		}
		return hex;
	},
	toDecimal:function(decimals,start,length){
		if(this.length==0) return Number.NaN;
		if(!this.isNumber(start,length)) return Number.NaN;
		start=start||0;
		length=length||this.length;
		var n=this.substr(start,length).split(".");
		var int=n[0]||0;
		var dec=n[1]||"";
		decimals=(decimals==null)?dec.length:decimals;
		while(decimals>=dec.length) dec+="0";
		if(decimals<dec.length) dec=dec.substring(0,decimals);
		int=parseInt(int+dec,10);
		return int/Math.pow(10,parseInt(dec.length));
		return int+((dec)?"."+dec:"");
	},
	test:function(string){
		return this==string;
	},
	testRegExp:function(regexp){
		return this.search(regexp)==-1;
	}
});

// ========================================== Events Structure ========================================
Class({
	public:{
		Event:function(event,target,firedFunc,handler){
			this.timeStamp=new Date();
			this.htmlEvent=event;
			this.target=target;
			this.firedFunction=firedFunc;
			this.eventHandler=handler;
			this.type=event.type;
			this.altKey=event.altKey;
			this.ctrlKey=event.ctrlKey;
			this.shiftKey=event.shiftKey;
			this.x=this.clientX=event.clientX;
			this.y=this.clientY=event.clientY;
			if(Browser.IE){
				this.pageX=window.document.body.scrollLeft+window.document.documentElement.scrollLeft+event.clientX;
				this.pageY=window.document.body.scrollTop+window.document.documentElement.scrollTop+event.clientY;
				this.screenX=window.screenLeft+event.clientX;
				this.screenY=window.screenTop+event.clientY;
				if(event.srcElement){
					this.offsetX=event.offsetX+target.offsetLeft-event.srcElement.offsetLeft;
					this.offsetY=event.offsetY+target.offsetTop-event.srcElement.offsetTop;
					this.resolved=event.srcElement.uniqueID==target.uniqueID;
				}
				this.button=(event.button==4)?3:event.button;
				this.leftButton=event.button==1;
				this.middleButton=event.button==4;
				this.fromElement=(event.fromElement)?event.fromElement:window;
				this.toElement=event.toElement;
				this.srcElement=event.srcElement;
				this.targetElement=target;
			}
			else{
				this.pageX=event.pageX;
				this.pageY=event.pageY;
				this.screenX=event.screenX;
				this.screenY=event.screenY;
				this.offsetX=event.pageX-((target.getX)?target.getX():0);
				this.offsetY=event.pageY-((target.getY)?target.getY():0);
				this.button=(event.button==0)?1:(event.button==1)?3:event.button;
				this.leftButton=event.button==0;
				this.middleButton=event.button==1;
				this.fromElement=(event.type=="mouseover")?event.relatedTarget:(event.type=="mouseout")?event.target:null;
				this.toElement=(event.type=="mouseover")?event.target:(event.type=="mouseout")?event.relatedTarget:null;
				this.srcElement=event.target;
				this.targetElement=event.currentTarget
				this.resolved=event.target===event.currentTarget;
			}
			this.rightButton=event.button==2;
			this.mouseX=this.pageX;
			this.mouseY=this.pageY;
			this.cancelBubble=false;
			this.bubbles=false;
			if(!(this.which=event.keyCode||event.charCode)) return;
			this.charValue=String.fromCharCode(this.which);
			this.isChar=this.which.between(65,90)||this.which.between(97,122);
			this.isNumber=this.which.between(48,57);
		},
		static__DOCUMENT_LOAD:1,
		static__DOCUMENT_READY:2,
		static__TIMEOUT:3,
		static__INTERVAL:4,
		clear:function(){
			if(this.eventHandler) this.eventHandler.clear();
		},
		stopPropagation:(document.addEventListener)?function(){
			this.htmlEvent.stopPropagation();
			this.cancelBubble=true;
		}:function(){
			this.htmlEvent.cancelBubble=true;
			this.cancelBubble=true;			
		},
		preventDefault:(document.addEventListener)?function(){
			this.htmlEvent.preventDefault();
			return false;
		}:function(){
			return false;
		}
	}
})

// Inherit from Event

Class({
	Extends:Event,
	public:{
		DragEvent:function(e,type,draggable,marker){
			$(this).Super(e,draggable);
			this.type=type;
			this.marker=marker;
		}
	}
})

Class({
	Extends:Event,
	public:{
		DropEvent:function(e,type,droppable,dragged,marker){
			$(this).Super(e,droppable);
			this.type=type;
			this.dragged=dragged;
			this.marker=marker;
			this.srcElement=droppable;
			this.bubbles=true;
		}
	}
})

Class({
	Extends:Event,
	public:{
		ShakeEvent:function(e,type,target){
			$(this).Super(e,target);
			this.type=type;
		}
	}
})

// Custom light event model

Class({
	public:{
		$Event:function(type,target){
			this.type=type;
			this.target=target;
		}
	}
})

Class({
	Extends:$Event,
	public:{
		MotionEvent:function(type,target,frame,value){
			$(this).Super(type,target);
			this.frame=frame;
			this.value=value;
		}
	}
})

Class({
	Extends:$Event,
	public:{
		TimerEvent:function(type,target,timestamp){
			$(this).Super(type,target);
			this.timestamp=timestamp;
		}
	}
})

Class({
	Extends:$Event,
	public:{
		HttpRequestEvent:function(type,httprequest,responseText,responseXML){
			$(this).Super(type,httprequest);
			this.responseText=responseText;
			this.responseXML=responseXML;
		}
	}
})

AbstractClass({
	public:{
		EventDispatcher:function(){
			$(this).events={};
		},
		hasEventListener:function(type){
			return $(this).events[type]!=null;
		},
		addEventListener:function(type,firedFunc,scope,bubbleDOM){
			var events=$(this).events;
			firedFunc=firedFunc.self(scope||this);
			events[type]=events[type]||[];
			events[type].push(firedFunc);
			return new EventHandler(type,this,firedFunc,null,bubbleDOM);
		},
		dispatchEvent:function(event){
			var type=event.type;
			var eventType=$(this).events[type];
			if(eventType){
				var length=eventType.length;
				for(var i=length;i--;){
					eventType[i](event);
					if(event.bubbles&&!event.cancelBubble){
						var parent=event.target.parentNode;
						while(!event.cancelBubble&&parent){
							var events=parent.bubblesEvents&&parent.bubblesEvents[type];
							if(events){
								event.target=parent;
								for(var j=events.length;j--;) events[j](event);
							}
							parent=parent.parentNode;
						}
					}
				}
			}
		},
		removeEventListener:function(type,func){
			var events=$(this).events;
			if(events[type]){
				var length=events[type].length;
				for(var i=length;i;){
					if(events[type][--i]==func) return events[type].splice(i--,1);
				}
			}
		}
	}
})

Class({
	Extends:EventDispatcher,
	public:{
		EventHandler:function(type,target,firedFunc,eventid,bubbleDOM){
			$(this).Super();
			this.eventType=type;
			if(type=="timeout"||type=="interval"){
				this.delay=target.delay;
				this.target=target.id;
			}
			else this.target=target;
			this.firedFunction=firedFunc;
			this.eventid=eventid||-1;
			this.state=1;
			if((this.bubbleDOM=bubbleDOM)) $(this).registerEvent();
		},
		static__CLEARED:0,
		static__RUNNING:1,
		static__IDLE:2,
		static__events:{currentId:0},
		static__handleEvent:function(target,firedFunc){
			var id=EventHandler.events.currentId;
			EventHandler.events[id]=target;
			EventHandler.events[id+1]=firedFunc;
			EventHandler.events.currentId+=2;
			target=firedFunc=null;
			return id;
		},
		clear:function(){
			if(!this.state) return false;
			this.state=0;
			$(this).detach(this.eventType);
			//console.log("CLEAR");
			$(this).unregisterEvent();
			if(this.eventid<0) return true;
			delete EventHandler.events[this.eventid];
			delete EventHandler.events[this.eventid+1];
			
			this.dispatchEvent(new $Event("onClear", this));
			return true;
		},
		idle:function(delay,time){
			if(this.state!=1) return false;
			delay=delay||0;
			time=time||0;
			if(delay) this.idle.setTimeout(delay,this);
			else{
				this.state=2;
				$(this).detach();
				//console.log("IDLE");
			}
			this.dispatchEvent(new $Event("onIdle", this));
			if(time) this.wakeup(time+delay);
			return true;
		},
		wakeup:function(delay){
			if(this.state!=2) return false;
			delay=delay||0;
			if(delay) this.wakeup.setTimeout(delay,this);
			else{
				this.state=1;
				$(this).attach();
				//console.log("WAKEUP");
			}
			this.dispatchEvent(new $Event("onWakeup", this));
			return true;
		},
		onIdle:function(func,scope){
			return this.addEventListener("onIdle",func,scope);
		},
		onWakeup:function(func,scope){
			return this.addEventListener("onWakeup",func,scope);
		},
		onClear:function(func,scope){
			return this.addEventListener("onClear",func,scope);
		}
	},
	private:{
		detach:function(eventType){
			eventType=eventType||this.eventType;
			//console.log("detach -> ",eventType);
			switch(eventType){
				case "update":
					$(this).detach("keyup");
					$(this).detach("change");
					return;
				case "timeout":
					clearTimeout(this.target);
					return;
				case "interval":
					clearInterval(this.target);
					return;
				default:
					if(this.target._removeEventListener) this.target._removeEventListener(eventType,this.firedFunction,false);
					if(this.target.removeEventListener) this.target.removeEventListener(eventType,this.firedFunction,false);
					if(this.target.detachEvent) this.target.detachEvent(eventType,this.firedFunction);
			}
		},
		attach:function(eventType){
			eventType=eventType||this.eventType;
			//console.log("attach -> ",eventType);
			switch(eventType){
				case "update":
					$(this).attach("keyup");
					$(this).attach("change");
					return;
				case "timeout":
					this.target=setTimeout(this.firedFunction,this.delay);
					return;
				case "interval":
					this.target=setInterval(this.firedFunction,this.delay);
					return;
				default:
					if(this.target._addEventListener) this.target._addEventListener(eventType,this.firedFunction,false);
					if(this.target.addEventListener) this.target.addEventListener(eventType,this.firedFunction,false);
					if(this.target.attachEvent) this.target.attachEvent(eventType,this.firedFunction);
			}
		},
		registerEvent:function(){
			this.bubbleDOM.bubblesEvents=this.bubbleDOM.bubblesEvents||{};
			this.bubbleDOM.bubblesEvents[this.eventType]=this.bubbleDOM.bubblesEvents[this.eventType]||[];
			this.bubbleDOM.bubblesEvents[this.eventType].push(this.firedFunction);
			//log("registered event ",this.eventType," for ",this.bubbleDOM);
		},
		unregisterEvent:function(){
			if(!this.bubbleDOM||!this.bubbleDOM.bubblesEvents||!this.bubbleDOM.bubblesEvents[this.eventType]) return;
			this.bubbleDOM.bubblesEvents[this.eventType].remove(this.firedFunction);
			if(this.bubbleDOM.bubblesEvents[this.eventType].length==0) delete this.bubbleDOM.bubblesEvents[this.eventType];
			//log("uregistered event ",this.eventType," for ",this.bubbleDOM);
		}
	}
})

$__GenericElementEvent=(window.addEventListener)?
	function(type){
		type=type.replace(/^on/i,"").toLowerCase();
		return function(func,scope){
			if(scope==this) scope=null;
			func.__class__=$.getOwnerClass(arguments.callee.caller);
			var id=EventHandler.handleEvent(this,func);
			var handler;
			var _func=function(evt){
				return EventHandler.events[id+1].call(scope||EventHandler.events[id],new Event(evt||window.event,EventHandler.events[id],func,handler));
			}
			if(type!="update"){
				this.addEventListener(type,_func,false);
				return handler=new EventHandler(type,this,_func,id);
			}
			this.addEventListener("keyup",_func,false);
			this.addEventListener("change",_func,false);
			return handler=new EventHandler("update",this,_func,id);
		}
	}:
	function(type){
		type="on"+type.replace(/^on/i,"").toLowerCase();
		return function(func,scope){
			if(scope==this) scope=null;
			func.__class__=$.getOwnerClass(arguments.callee.caller);
			var id=EventHandler.handleEvent(this,func);
			var handler;
			var _func=function(evt){
				return EventHandler.events[id+1].call(scope||EventHandler.events[id],new Event(evt||window.event,EventHandler.events[id],func,handler));
			}
			if(type!="onupdate"){
				this.attachEvent(type,_func);
				return handler=new EventHandler(type,this,_func,id);
			}
			this.attachEvent("onkeyup",_func);
			this.attachEvent("onchange",_func);
			return handler=new EventHandler("update",this,_func,id);
		}
	}


$GenericElementEvents={
	onClick:$__GenericElementEvent("click"),
	onDoubleClick:$__GenericElementEvent("dblclick"),
	onUpdate:$__GenericElementEvent("update"),
	onChange:$__GenericElementEvent("change"),
	onKeyDown:$__GenericElementEvent("keydown"),
	onKeyUp:$__GenericElementEvent("keyup"),
	onKeyPress:$__GenericElementEvent("keypress"),
	onMouseOver:$__GenericElementEvent("mouseover"),
	onMouseOut:$__GenericElementEvent("mouseout"),
	onMouseUp:$__GenericElementEvent("mouseup"),
	onMouseDown:$__GenericElementEvent("mousedown"),
	onMouseMove:$__GenericElementEvent("mousemove"),
	onSubmit:$__GenericElementEvent("submit"),
	onLoad:$__GenericElementEvent("load"),
	onMouseWheel:(window.addEventListener)?$__GenericElementEvent("DOMMouseScroll"):$__GenericElementEvent("mousewheel")
}

$WindowEvents={
	onScroll:$__GenericElementEvent("scroll"),
	onChange:$__GenericElementEvent("change"),
	onClose:$__GenericElementEvent("close"),
	onResize:$__GenericElementEvent("resize")
}

// ============================== Native DOM Implementations =============================

if(!window.getComputedStyle){
	$implements(window,{
		getComputedStyle:function(element,pseudoElt){
			return {
				getPropertyValue:function(name){
					name=CssRule.shorten(name);
					var style=element.style;
					var curStyle=element.currentStyle;
					if(!curStyle) return;
					var runStyle=element.runtimeStyle;
					var value=curStyle[name];
					if(!/\d+/.test(value)) return value;
					var storeLeft=style.left;
					var runtimeLeft=runStyle.left;
					runStyle.left=curStyle.left;
					style.left=value||0;
					var px=style.pixelLeft;
					style.left=storeLeft;
					runStyle.left=runtimeLeft;
					return px+"px";					
				}
			}
		}
	})
}
$implements(window,$WindowEvents);

$implements(document,{
	getElementsAt:function(x,y){
		var point=new Point(x,y);
		var elms=new HtmlList(this.getElementsByTagName("*"));
		var array=elms.toArray();
		for(var i=array.length;i--;){
			if(!array[i].getBounds().contain(point)) elms.remove(i);
		}
		return elms;
	}
});	

$_Element_={
	/* -------------------------------- Custom Events -------------------------------*/
	hasEventListener:function(type){
		type=type.replace(/^on/i,"");
		var events=this.bubblesEvents;
		if(!events) return false;
		return events.contain(type);
	},
	onDrag:function(func,scope){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive.addEventListener("onDrag",func,scope||this);
	},
	onDragStart:function(func,scope){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive.addEventListener("onDragStart",func,scope||this);
	},
	onDragStop:function(func,scope){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive.addEventListener("onDragStop",func,scope||this);
	},
	onDragOver:function(func,scope){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive.addEventListener("onDragOver",func,scope||this);
	},
	onDragMove:function(func,scope){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive.addEventListener("onDragMove",func,scope||this);
	},
	onDragOut:function(func,scope){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive.addEventListener("onDragOut",func,scope||this);
	},
	onDrop:function(func,scope){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive.addEventListener("onDrop",func,scope||this,this);
	},
	onStretch:function(func,scope){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive.addEventListener("onStretch",func,scope||this);
	},
	onStretchStart:function(func,scope){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive.addEventListener("onStretchStart",func,scope||this);
	},
	onStretchStop:function(func,scope){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive.addEventListener("onStretchStop",func,scope||this);
	},
	onShake:function(func,scope){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive.addEventListener("onShake",func,scope||this);
	},
	// -------------------------------  Tree walk -----------------------------------
	getFirstChild:function(textNode){
		if(!textNode){
			var childs=this.childNodes;
			var index=0;
			while(childs[index++].nodeType==3);
			return $$(childs[index-1]);
		}
		return $$(this.firstChild);
	},
	getMiddleChild:function(textNode){
		return $$(this.childNodes[Math.round(this.childNodes.length/2)]);
	},
	getLastChild:function(textNode){
		if(!textNode){
			var childs=this.childNodes;
			var index=childs.length-1;
			while(childs[index--].nodeType==3);
			return $$(childs[index+1]);
		}
		return $$(this.lastChild);
	},
	getChildNodes:function(deep,index){
		var childs=this.childNodes;
		var nl=new HtmlList(childs);
		if(deep){
			var length=childs.length;
			for(var i=0;i<length;i++){
				if(childs[i].hasChildNodes()){
					nl.merge(childs[i].getChildNodes(true));
				}
			}
		}
		return (index!=null)?nl.get(index):nl;
	},
	getParentNodes:function(index){
		var parent=this.parentNode;
		var list=new HtmlList();
		var d=document;
		var b=d.body;
		var i=index;
		var all=!i;
		while(parent&&parent!=d&&parent!=b&&(all||i--)){
			list.add(parent);
			parent=parent.parentNode;
		}
		return (index!=null)?list.get(index):list;
	},
	hasChild:function(targetChild,deep){
		var childs=this.getChildNodes().toArray();
		var length=childs.length;
		for(var i=length;i;){
			var child=childs[--i];
			if(child==targetChild) return i;
			else if(deep&&child.hasChildNodes()){
				return child.hasChild(targetChild,true);
			}
		}
		return -1;
	},
	hasParent:function(targetParent){
		var parent=this.parentNode;
		var i=0;
		while(parent){
			if(parent==targetParent) return i;
			parent=parent.parentNode;
			i++;
		}
		return -1;
	},
	getPreviousSibling:function(){
		var index=this.parentNode.hasChild(this);
		return $$(this.parentNode.childNodes[index-1]);
	},
	getNextSibling:function(){
		var nextSibling=this.nextSibling;
		while(nextSibling.nodeType==3){
			nextSibling=nextSibling.nextSibling;
		}
		return $$(nextSibling);
	},
	insertAfter:function(child,target){
		this.insertBefore(child,target.nextSibling);
		return this;
	},
	append:function(child){
		this.appendChild(child);
		return this;
	},
	insert:function(child,target,mode){
		if(!child) return;
		var mode=(target!=null)?(mode)?mode:"after":"first";
		switch(mode){
			case "after":
				this.insertAfter(child,target);
				break;
			case "before":
				this.insertBefore(child,target);
				break;
			case "first":
				this.insertBefore(child,this.firstChild);
				break;
			default:
				this.insertBefore(child,this.firstChild);
				break;
		}
		return this;
	},
	placeAfter:function(target){
		target.parentNode.insertAfter(this,target);
		return this;
	},
	placeBefore:function(target){
		target.parentNode.insertBefore(this,target);
		return this;
	},
	place:function(target,mode){
		var mode=(mode)?mode:"after";
		switch(mode){
			case "after":
				this.placeAfter(target);
				break;
			case "before":
				this.placeBefore(target);
				break;
			default:
				this.placeAfter(target);
				break;
		}
		return this;
	},
	apply:function(parent){
		this.storeNode();
		var parent=(parent)?parent:document.body;
		parent.appendChild(this);
		return this;
	},
	replaceWith:function(target){
		target.placeBefore(this);
		this.parentNode.removeChild(this);
		return target;
	},
	remove:function(targetChild){
		this.removeChild(targetChild);
		return targetChild;
	},
	removeAll:function(){
		while(this.childNodes[0]){
			this.removeChild(this.childNodes[0]);
		}
		return this;
	},
	release:function(){
		if(!this.parentNode) return;
		this.parentNode.removeChild(this);
		return this;
	},
	getParent:function(){
		return $$(this.parentNode);
	},
	storeNode:function(){
		this.storedSibling=this.nextSibling;
		this.storedParent=this.parentNode;
	},
	restoreNode:function(){
		if(this.storedSibling){
			this.placeBefore(this.storedSibling);
		}
		else if(this.storedParent){
			this.storedParent.appendChild(this);
		}
		return this;
	},
	clone:function(deep){
		return $$(this.cloneNode(deep||false));
	},
	//---------------------------- Position & Dimension  -------------------------------------
	left:function(){
		return this.getCurrentValue("left",true);
	},
	top:function(){
		return this.getCurrentValue("top",true);
	},
	getX:function(countBorder){
		var x=this.offsetLeft;
		var parent=this.offsetParent;
		if(!parent) return x;
		var sum=Browser.FF||Browser.IE&&Browser.versionID<=7;
		do x+=parent.offsetLeft+((sum)?parent.clientLeft:0);
		while(parent=parent.offsetParent);
		return x+((!countBorder)?this.getCurrentValue("border-left-width",true):0);
	},
	getY:function(countBorder){
		var y=this.offsetTop;
		var parent=this.offsetParent;
		if(!parent) return y;
		var sum=Browser.FF||Browser.IE&&Browser.versionID<=7;
		do y+=parent.offsetTop+((sum)?parent.clientTop:0);
		while(parent=parent.offsetParent);
		return y+((!countBorder)?this.getCurrentValue("border-top-width",true):0);
	},
	innerX:function(){
		return this.getX()+this.getCurrentValue("padding-left",true);
	},
	innerY:function(){
		return this.getY()+this.getCurrentValue("padding-top",true);
	},
	outerX:function(){
		return this.getX(true)-this.getCurrentValue("margin-left",true);
	},
	outerY:function(){
		return this.getY(true)-this.getCurrentValue("margin-top",true);
	},
	offsetX:function(fromParentNode){
		return this.outerX()-$$(((fromParentNode)?this.parentNode:this.offsetParent)).getX();
	},
	offsetY:function(fromParentNode){
		return this.outerY()-$$(((fromParentNode)?this.parentNode:this.offsetParent)).getY();
	},
	screenX:function(){
		return this.getX(true)+((window.screenLeft!=null)?window.screenLeft:window.screenX);
	},
	screenY:function(){
		return this.getY(true)+((window.screenTop!=null)?window.screenTop:window.screenY);
	},
	getLocation:function(){
		var x=this.offsetLeft;
		var y=this.offsetTop;
		var parent=this.offsetParent;
		var sum=Browser.FF||Browser.IE&&Browser.versionID<=7;
		while(parent){
			x+=parent.offsetLeft+((sum)?parent.clientLeft:0);
			y+=parent.offsetTop+((sum)?parent.clientTop:0);
			parent=parent.offsetParent;
		}
		return new Point(x,y);
	},
	getWidth:function(countBorder){
		if(!countBorder) return this.clientWidth;
		return this.offsetWidth;
	},
	getHeight:function(countBorder){
		if(!countBorder) return this.clientHeight;
		return this.offsetHeight;
	},
	innerWidth:function(){
		var cstyle=this.getComputedStyle();
		return this.getWidth()-parseInt(cstyle.getPropertyValue("padding-left"))+parseInt(cstyle.getPropertyValue("padding-right"));
	},
	innerHeight:function(){
		var cstyle=this.getComputedStyle();
		return this.getHeight()-parseInt(cstyle.getPropertyValue("padding-top"))+parseInt(cstyle.getPropertyValue("padding-bottom"));
	},
	outerWidth:function(){
		var cstyle=this.getComputedStyle();
		return this.getWidth(true)+parseInt(cstyle.getPropertyValue("margin-left"))+parseInt(cstyle.getPropertyValue("margin-right"));
	},
	outerHeight:function(countBorder){
		var cstyle=this.getComputedStyle();
		return this.getHeight(true)+parseInt(cstyle.getPropertyValue("margin-top"))+parseInt(cstyle.getPropertyValue("margin-bottom"));
	},
	getSize:function(countBorder){
		return new Dimension(this.width(countBorder),this.height(countBorder));
	},
	setX:function(x){
		this.style.left="0px";
		this.style.left=x-this.outerX()+"px";
		return this;
	},
	setY:function(y){
		this.style.top="0px";
		this.style.top=y-this.outerY()+"px";
		return this;
	},
	setLocation:function(x,y){
		if($isObject(x)||x instanceof Point){
			y=x.y;
			x=x.x;
		}
		this.setX(x);
		this.setY(y);
		return this;
	},
	setWidth:function(w){
		this.style.width=w+"px";
		return this;
	},
	setHeight:function(h){
		this.style.height=h+"px";
		return this;
	},
	setSize:function(w,h){
		if($isObject(w)||w instanceof Dimension){
			h=w.height;
			w=w.width;
		}
		this.setWidth(w);
		this.setHeight(h);
		return this;
	},
	getBounds:function(clienBool){
		var scrollX=0;
		var scrollY=0;
		if(clienBool){
			scrollX=document.documentElement.scrollLeft;
			scrollY=document.documentElement.scrollTop;
		}
		return new Rectangle(this.getX(true)-scrollX,this.getY(true)-scrollY,this.getWidth(true),this.getHeight(true));
	},
	//------------------------------------- Style ------------------------------------------
	getComputedStyle:function(){
		return window.getComputedStyle(this,null);
	},
	getCurrentValue:function(prop,number){
		return (number)?parseFloat(window.getComputedStyle(this,null).getPropertyValue(CssRule.lenghten(prop)))||0:window.getComputedStyle(this,null).getPropertyValue(CssRule.lenghten(prop));
	},
	setOpacity:(document.addEventListener)?function(alpha){
		this.style.opacity=alpha; 
	}:function(alpha){
		this.style.filter="alpha(opacity="+alpha*100+")"; 
	},
	getOpacity:(document.addEventListener)?function(){
		return parseFloat(this.style.opacity||1,10);
	}:function(){
		return parseFloat(((this.style.filter||"").match(/opacity=\d+/i)||["100"])[0].match(/\d+/)[0])/100;
	},
	setBackgroundColor:function(color){
		if($isString(color)) this.setStyle("background-color",color);
		else this.setStyle("background-color",color.getHTMLColor());
	},
	setBackgroundImage:function(image){
		if(image instanceof Image) this.setStyle("background-image","url(\""+image.src+"\")");
		else this.setStyle("background-image","url(\""+image+"\")");
	},
	setForegroundColor:function(color){
		if($isString(color)) this.setStyle("color",color);
		else this.setStyle("color",color.getHTMLColor());
	},
	setVisible:function(visible){
		this.style.display=(visible)?"":"none";
	},
	setDropTargets:function(){
		if(!this.interactive) this.interactive=new Interactive(this);
		this.interactive.setDropTargets.apply(this.interactive,arguments);
	},
	getCss:function(css){
		return this.style[CssRule.shorten(css)];
	},
	getStyle:function(boolObj){
		return (boolObj)?this.style:this.style.cssText||"";
	},
	setCss:function(css,value){
		if(css=="opacity") this.setOpacity(value);
		else this.style[CssRule.shorten(css)]=value;
	},
	removeCss:function(css){
		(this.style.removeProperty)?this.style.removeProperty(CssRule.shorten(css)):this.style.removeAttribute(CssRule.shorten(css));
	},
	setStyle:function(css,value){
		if($isString(css)){
			if(!value) this.style.cssText=css;
			else this.setCss(css,value);
		}
		else if(css instanceof Style) this.style.cssText=css.getCss();
		else{
			for(var key in css){
				if(css.hasOwnProperty(key)) this.setCss(key,css[key]);
			}
		}
		return this;
	},
	removeStyle:function(css){
		if($isString(css)){
			if(!value) this.style.cssText="";
			else this.removeCss(css);
		}
		else if(css instanceof Style) this.style.cssText="";
		else{
			for(var key in css){
				if(css.hasOwnProperty(key)) this.removeCss(key);
			}
		}
		return this;
	},
	//----------------------------------------- Interactions ----------------------------------------
	getInteractive:function(){
		if(!this.interactive) this.interactive=new Interactive(this);
		return this.interactive;
	},
	setDraggable:function(draggable,options){
		if(!this.interactive) this.interactive=new Interactive(this);
		this.interactive.setDraggable(draggable,options);
		return this;
	},
	setDroppable:function(droppable,options){
		if(!this.interactive) this.interactive=new Interactive(this);
		this.interactive.setDroppable(droppable,options);
		return this;
	},
	setStretchable:function(stretchable,options){
		if(!this.interactive) this.interactive=new Interactive(this);
		this.interactive.setStretchable(stretchable,options);
	},
	//-------------------------------------- Settings & Gettings ------------------------------------
	set:function(imprint){
		for(var key in imprint){
			if(imprint.hasOwnProperty(key)){
				if(key=="style") this.setStyle(imprint[key]);
				else if(key=="innerHTML") this.innerHTML=imprint[key];
				else if(key=="className") this.className=imprint[key];
				else if(key=="parentNode") this.apply(imprint[key]);
				else this.setAttribute(key,imprint[key]);
			}
		}
		return this;
	},
	unset:function(imprint){
		for(var key in imprint){
			if(imprint.hasOwnProperty(key)){
				if(key=="style") this.removeStyle(imprint[key]);
				else if(key=="innerHTML") this.innerHTML="";
				else if(key=="className") this.removeClass(imprint[key]);
				else if(key=="parentNode") this.release();
				else this.removeAttribute(key);
			}
		}
		return this;
	},
	setClass:function(className){
		this.className=(className||"");
	},
	addClass:function(className){
		if(!className||this.hasClass(className)) return;
		this.className+=" "+className;
	},
	removeClass:function(className){
		if(!className) return;
		this.className=this.className.replace(new RegExp("^"+className+"\\s+|\\s+"+className+"$|\\s+"+className+"(?=\\s)"),"");
	},
	getClass:function(asArray){
		var classes=this.className;
		return (asArray)?classes.split(" "):classes;
	},
	hasClass:function(className){
		if(!className) return;
		return new RegExp("^"+className+"|\\s"+className+"\\s|\\s"+className+"$").test(this.className);
	},
	setContent:function(content){
		content=(content!=null)?content:"";
		if(this.nodeName=="INPUT") this.value=content;
		else this.innerHTML=content;
		return this;
	},
	getContent:function(){
		if(this.nodeName=="INPUT"||this.nodeName=="TEXTAREA") return this.value;
		if(this.nodeName=="SELECT"){
			return this.options[this.selectedIndex].value;
		}
		return this.innerHTML;
	},
	appendContent:function(content){
		this.setContent(this.getContent()+content);
		return this;
	},
	copyContentTo:function(target){
		$$(target).setContent(this.getContent());
		return this.innerHTML;
	},
	sendContentTo:function(target){
		this.copyContentTo(target);
		this.setContent(null);
		return this;
	},
	empty:function(){
		this.setContent(null);
		this.removeAll();
		return this;
	},
	isEmpty:function(){
		return this.childNodes.length==0&&this.getContent().length==0;
	},
	toggle:function(imprint1,imprint2){
		var imprint=imprint1;
		if(this.toggleStatus){
			imprint=imprint2;
			delete this.toggleStatus;
		}
		else this.toggleStatus=1;
		this.set(imprint);
		return this;
	},
	toggleAttribute:function(prop,value1,value2){
		var value=value1;
		if(this["_toggle"+prop]){
			value=value2;
			delete this["_toggle"+prop];
		}
		else this["_toggle"+prop]=1;
		if(prop=="innerHTML") this.innerHTML=value;
		else this.setAttribute(prop,value);
		return this;
	},
	toggleStyle:function(prop,value1,value2){
		var value=value1;
		if(this["_toggle"+prop]){
			value=value2;
			delete this["_toggle"+prop];
		}
		else this["_toggle"+prop]=1;
		if(prop=="style") this.setStyle(value);
		else this.setStyle(prop,value);
		return this;
	},
	filter:function(filterObject){
		if($isFunction(filterObject)){
			return filterObject(this);
		}
		for(var filter_attr in filterObject){
			if(filterObject.hasOwnProperty(filter_attr)){
				var filter_value=filterObject[filter_attr];
				if(!filter_value.test(this[filter_attr])&&!filter_value.test(this.getAttribute(filter_attr))&&!filter_value.test(this.style[filter_attr])) return false;
			}
		}
		return true;
	},
	/* --------------------------------------- Interpolation -----------------------------------*/
	interpolate:function(propsObject,options){
		var interp=new Interpolation(this,propsObject,options);
		interp.start();
		return interp;
	},
	isInterpolated:function(){
		return this.currentInterpolation!=null;
	},
	getCurrentInterpolation:function(){
		return this.currentInterpolation
	},
	getTweenableValue:function(prop){
		prop=CssRule.shorten(prop);
		var value=this.getCurrentValue(prop);
		switch(prop){
			case "left": return (/\d+/.test(value))?value:this.getX();
			case "top": return (/\d+/.test(value))?value:this.getY();
			case "width": return (/\d+/.test(value))?value:this.getWidth();
			case "height": return (/\d+/.test(value))?value:this.getHeight();
			case "opacity": return this.getOpacity();
			default: return parseInt(value);
		}
	},
	/* --------------------------------------- Childs searching --------------------------------*/
	$tag:function(tagName,filter,deep){
		var elms=this.getChildNodes(deep);
		filter=filter||{};
		filter.tagName=tagName.toUpperCase();
		return elms.sift(filter);
	},
	$name:function(name,filter,deep){
		var elms=this.getChildNodes(deep);
		filter=filter||{};
		filter.name=name;
		return elms.sift(filter);
	},
	$class:function(className,filter,deep){
		var elms=this.getChildNodes(deep);
		filter=filter||{};
		filter.className=className;
		return elms.sift(filter);
	},
	$id:function(id,filter,deep){
		var elms=this.getChildNodes(deep);
		filter=filter||{};
		filter.id=id;
		return elms.sift(filter);
	}
}

$implements(window,$GenericElementEvents);
$implements(document,$GenericElementEvents);
$implements($_Element_,$GenericElementEvents);

if(!window.Element){
	Element={};
	Element.prototype={};
	$implements(Element,$_Element_,Element);
}
else $implements(Element.prototype,$_Element_,Element);


Element.__class__=Element;
Element.__classid__=$uniqueId();
Element.__abstract__=0;
Element.__interface__=0;
Element.prototype.__class__=Element;
Element.__classname__="Element";

delete $__Element;
delete $_Element_;
delete $__GenericElementEvent;

// ================================= Native Custom Class ======================================

Class({
	public:{
		HtmlFilter:function(filter){
			if(filter instanceof HtmlFilter) return filter;
			if($isFunction(filter)){
				this.filter=filter;
				this.isFunction=true;
			}
			else this.filter=$objectToArray(filter);
			if(!this.filter) this.filter=[];
		},
		applyTo:function(element){
			if(this.isFunction) return this.filter(element);
			var array=this.filter;
			var i=array.length;
			var filter, property, value;
			if(!i) return true;
			do{
				filter=array[--i];
				property=filter.property;
				value=filter.value;
				if(!value.test(element[property])&&!value.test(element.getAttribute(property))&&!value.test(element.style[property])) return false;
			}
			while(i);
			return true;
		}
	}
})

Class({
	public:{
		Html:function(tagName,imprint){
			if(!tagName) return document;
			if(tagName.match(/^</)) return $$($html("div",{innerHTML:tagName}).childNodes[0]);
			var elm=$$(document.createElement(tagName));
			elm.set(imprint);
			return elm;
		}
	}
})

Class({
	public:{
		Point:function(x,y){
			this.setLocation(x,y);
		},
		setLocation:function(x,y){
			if($isObject(x)||x instanceof Point){
				y=x.y;
				x=x.x;	
			}
			this.x=x;
			this.y=y;
		},
		translate:function(dx,dy){
			this.x+=dx;
			this.y+=dy;
		},
		distance:function(x,y){
			if($isObject(x)||x instanceof Point){
				y=x.y;
				x=x.x;	
			}
			var x=(this.x-x);
			var y=(this.y-y);
			return Math.sqrt(x*x+y*sy);
		}
	}
})

Class({
	public:{
		Dimension:function(width,height){
			this.setDimension(width,height);
		},
		setDimension:function(width,height){
			if($isObject(width)||width instanceof Dimension){
				height=width.height;
				width=width.width;
			}
			this.width=width;
			this.height=height;
		},
		scaleTo:function(width,height){
			if($isObject(width)||width instanceof Dimension){
				height=width.height;
				width=width.width;
			}
			var sw=width/this.width;
			var sh=height/this.height;
			this.scaleBy((sw<sh)?sw:sh);
			return this;
		},
		scaleBy:function(scale){
			this.width*=scale;
			this.height*=scale;
			return this;
		},
		getScaledBy:function(scale){
			return new Dimension(this.width*scale,this.height*scale);
		},
		getScaledTo:function(width,height){
			return new Dimension(this.width,this.height).scaleTo(width,height);
		},
		resizeOf:function(dw,dh){
			this.width+=dw;
			this.height+=dh;
			return this;
		},
		sum:function(width,height){
			if($isObject(width)||width instanceof Dimension){
				height=width.height;
				width=width.width;
			}
			return new Dimension(this.width+width,this.height+height);
		}
	}
})

Class({
	public:{
		Rectangle:function(x,y,width,height){
			this.setBounds(x,y,width,height);
		},
		contain:function(point){
			return point.x>=this.x&&point.x<=this.x+this.width&&point.y>=this.y&&point.y<=this.y+this.height;
		},
		setBounds:function(x,y,width,height){
			if($isObject(x)||x instanceof Rectangle){
				y=x.y;
				x=x.x;	
				height=width.height||0;
				width=width.width||0;
			}
			this.x=x;
			this.y=y;
			this.width=width;
			this.height=height;
		},
		setSize:function(width,height){
			this.width=width;
			this.height=height;
		},
		setLocation:function(x,y){
			this.x=x;
			this.y=y;
		},
		translate:function(dx,dy){
			this.x+=dx;
			this.y+=dy;
		},
		getCenter:function(){
			return new Point(this.x+this.width/2,this.y+this.height/2);
		}
	}
})

Class({
	Extends:EventDispatcher,
	public:{
		Interactive:function(element){
			$(this).Super();
			this.element=$$(element);
			this.canDrag=false;
			this.canStretch=false;
			var priv=$(this);
			priv.onmousedown=null;
			priv.onmouseup=null;
			priv.onmousemove=null;
			priv.dragOptions={type:"drag"};
			priv.stretchOptions={type:"stretch"};
			priv.init=false;
		},
		static__DELAY:20,
		static__NFRAMES:30,
		static__TRIGGERS:[],
		static__DROPPABLES:[],
		static__EVENTS_HANDLER:[],
		static__ACTIVE:false,
		static__TIMER:null,
		setDraggable1:function(draggable,options){
			var priv=$(this);
			if(!draggable) priv.restore1();
			else{
				if($isFunction(options)) options={easing:options};
				priv.dragOptions=$fillObject({
					activeArea:null,
					grid:null,
					easing:null,
					
					forceRefresh:null,
					delay:Interactive.DELAY,
					numFrames:Interactive.NFRAMES
				},options,{
					grid:[1,1]
				});
				if(priv.dragOptions.placeHolder&&!priv.dragOptions.placeHolder.parentNode) priv.dragOptions.placeHolder.parentNode=this.element.parentNode;
				priv.initEvents1();
			}
			this.draggable=draggable;
		},
		setDraggable:function(draggable,options){
			var priv=$(this);
			if(!draggable) priv.restore1();
			else{
				this.drag_options=$fillObject({
					activeClass:null,
					marker:null,
					group:null,
					activeAll:null,
					grid:null,
					parentNode:null
				},options,{
					activeClass:"interactive-draggable-active",
					marker:false,
					grid:[1,1]
				});
				priv.initEvents1();
			}
			this.draggable=draggable;
		},
		setDroppable:function(droppable,options){
			var priv=$(this);
			if(!droppable) priv.restore1();
			else{
				this.drop_options=$fillObject({
					activeClass:null,
					dragFilter:null
				},options,{
					activeClass:"interactive-droppable-active"
				});
				Interactive.DROPPABLES.push(this);
			}
			this.droppable=droppable;
		},
		setStretchable:function(stretchable,options){
			var priv=$(this);
			this.stretchable=stretchable;
			if(!stretchable) priv.restore();
			else{
				this.element.setCss("position",Interactive.POSITION);
				if($isFunction(options)) options={easing:options};
				priv.stretchOptions=$fillObject({
					activeArea:null,
					grid:null,
					easing:null,
					delay:null,
					numFrames:null
				},options,{
					activeArea:[
						{x:0,y:0,w:5,h:5,relative:"TOP_LEFT",affect:"ALL",cursor:"nw-resize"},
						{x:0,y:0,w:5,h:5,relative:"TOP_RIGHT",affect:"ALL",cursor:"ne-resize"},
						{x:0,y:0,w:5,h:5,relative:"BOTTOM_LEFT",affect:"ALL",cursor:"sw-resize"},
						{x:0,y:0,w:5,h:5,relative:"BOTTOM_RIGHT",affect:"ALL",cursor:"se-resize"},
						{x:0,y:5,w:5,bottom:5,relative:"V_LEFT",affect:"HORIZONTAL",cursor:"w-resize"},
						{x:0,y:5,w:5,bottom:5,relative:"V_RIGHT", affect:"HORIZONTAL",cursor:"e-resize"},
						{x:5,y:0,h:5,right:5,relative:"H_TOP",affect:"VERTICAL",cursor:"n-resize"},
						{x:5,y:0,h:5,right:5,relative:"H_BOTTOM",affect:"VERTICAL",cursor:"s-resize"}
					],
					grid:[1,1],
					easing:null,
					delay:Interactive.DELAY,
					numFrames:Interactive.NFRAMES
				});
				priv.initEvents();
			}
		},
		setStartValues:function(target,pos){
			switch(pos||target.getCurrentValue("position")){
			case "absolute":
				this.startX=target.offsetX();
				this.startY=target.offsetY();
				break;
			case "fixed":
				this.startX=target.outerX();
				this.startY=target.outerY();
				break;
			default:
				this.startX=target.left();
				this.startY=target.top();
				break;
			}
			this.startWidth=target.getWidth();
			this.startHeight=target.getHeight();
		},
		resetLocation:function(prevPos,pos){
			var target=this.element;
			log(prevPos,pos);
			if(prevPos==pos) return;
			switch(pos){
				case "static":
					target.removeCss("left");
					target.removeCss("top");
					return;
				case "relative":
					target.removeCss("left");
					target.removeCss("top");
					target.setX(target.left());
					target.setY(target.top());
					return;
				case "absolute":
					target.setX(target.offsetX());
					target.setY(target.offsetY());
					return;
				case "fixed":
					target.setX(target.outerX());
					target.setY(target.outerY());
					return;
				default: return;
			}
		},
		resetInitState:function(x,y,w,h){
			var priv=$(this);
			priv.startX=x||this.element.offsetLeft;
			priv.startY=y||this.element.offsetTop;
			priv.startW=w||this.element.getWidth();
			priv.startH=h||this.element.getHeight();
			priv.parentNode=this.element.parentNode
		},
		onDrag:function(func,scope){
			return this.addEventListener("onDrag",func,scope);
		},
		onDragStart:function(func,scope){
			return this.addEventListener("onDragStart",func,scope);
		},
		onDragStop:function(func,scope){
			return this.addEventListener("onDragStop",func,scope);
		},
		onDragOver:function(func,scope){
			return this.addEventListener("onDragOver",func,scope);
		},
		onDragOut:function(func,scope){
			return this.addEventListener("onDragOut",func,scope);
		},
		onDragMove:function(func,scope){
			return this.addEventListener("onDragMove",func,scope);
		},
		onDrop:function(func,scope){
			return this.addEventListener("onDrop",func,scope);
		},
		onStretch:function(func,scope){
			return this.addEventListener("onStretch",func,scope);
		},
		onStretchStart:function(func,scope){
			return this.addEventListener("onStretchStart",func,scope);
		},
		onStretchStop:function(func,scope){
			return this.addEventListener("onStretchStop",func,scope);
		},
		onShake:function(func,scope){
			return this.addEventListener("onShake",func,scope);
		}
	},
	private:{
		initEvents1:function(){
			var priv=$(this);
			if(priv.init) return;
			priv.init=true;
			var target=this.element;
			target.onselectstart=function(){return false;}
			target.onmousedown=function(){return false;}
			target.ondrag=function(){return false;}
			priv.triggerId=Interactive.TRIGGERS.length;
			Interactive.TRIGGERS.push(this);
			priv.onmousedown=target.onMouseDown(function(e){
				e.stopPropagation();
				this.active=this.canDrag||this.canStretch;
			},this);
			priv.checkarea=target.onMouseMove(function(e){
				if(this.actived) return;
				this.canStretch=this.canDrag=false;
				this.stretchable&&(this.canStretch=priv.checkArea(this,new Point(e.offsetX,e.offsetY),this.stretch_options))||this.draggable&&(this.canDrag=priv.checkArea(this,new Point(e.offsetX,e.offsetY),this.drag_options));
			},this);
			priv.initOuterEvents(target);
		},
		initOuterEvents:function(){
			var priv=$(this);
			var triggers=Interactive.TRIGGERS;
			var droppables=Interactive.DROPPABLES;
			if(Interactive.ACTIVE||triggers.length==0) return;
			var pageX,pageY,grid;
			var lastidrop;
			Interactive.EVENTS_HANDLER[0]=document.onMouseMove(function(e){
				e.stopPropagation();
				var x=e.pageX;
				var y=e.pageY;
				var i=triggers.length;
				if(Interactive.TIMER) return;
				Interactive.TIMER=(function(){
					Interactive.TIMER.clear();
					Interactive.TIMER=null;
				}).setTimeout(10);
				if(!i) return;
				do{
					var iObj=triggers[--i];
					var target=iObj.element;
					var drag_options=iObj.drag_options;
					if(iObj.active&&iObj.draggable&&iObj.canDrag&&!iObj.linked){
						//  set the starting values for current trigger
						if(!iObj.running){
							pageX=e.pageX;
							pageY=e.pageY;
							grid=drag_options.grid||[1,1];
							//  reset location indipendant from position
							var absolute=new Point(target.outerX(),target.outerY());
							if(drag_options.marker){
								if(!iObj.marker){
									log("clone");
									var subs=target.clone(true);
									//subs.addClass(drag_options.markerClass);
									log(drag_options.parentNode);
									if(drag_options.parentNode) subs.apply(drag_options.parentNode);
									else subs.placeBefore(target);
									subs.onselectstart=function(){return false;}
									subs.onmousedown=function(){return false;}
									subs.ondrag=function(){return false;}
									target=iObj.marker=subs;
								}
								else{
									if(drag_options.parentNode) iObj.marker.apply(drag_options.parentNode);
									else iObj.marker.placeBefore(target);
									target=iObj.marker;
								}
							}
							
							target.addClass(drag_options.activeClass);
							var pos=target.getCurrentValue("position")
							if(pos=="static") pos=target.style.position="relative";
							target.setLocation(absolute);
							iObj.setStartValues(target,pos);
							iObj.dispatchEvent(new DragEvent(e.htmlEvent,"onDragStart",iObj.element,iObj.marker));
						}
						if(iObj.marker) target=iObj.marker;
						var center=target.getBounds(true).getCenter();
						var mx=Math.round((x-pageX)/grid[0])*grid[0];
						var my=Math.round((y-pageY)/grid[1])*grid[1];
						if(grid[0]&&iObj.dragH) target.style.left=iObj.startX+mx+"px";
						if(grid[1]&&iObj.dragV) target.style.top=iObj.startY+my+"px";
						iObj.dispatchEvent(new DragEvent(e.htmlEvent,"onDrag",target));
						
						//  search for group
						if(drag_options.group){
							var group=drag_options.group;
							var activeAll=drag_options.activeAll;
							for(var j=triggers.length;j--;){
								var itrig=triggers[j];
								if(j!=i&&itrig.draggable&&itrig.drag_options.group==group){
									if(!itrig.running) itrig.setStartValues();
									var elm=itrig.element;
									if(activeAll){
										itrig.active=itrig.canDrag=true;
										elm.addClass(drag_options.activeClass);
									}
									elm.style.left=itrig.startX+mx+"px";
									elm.style.top=itrig.startY+my+"px";
									itrig.running=true;
									itrig.linked=true;
								}
							}
						}
						
						//  detect droppable items under the draggable item
						if(droppables.length){
							target.style.display="none";
							var droppable=document.elementFromPoint(center.x,center.y);
							target.style.display="";
							if(droppable&&droppable.noteType==3) droppable=droppable.parentNode;
							
							
/*							for(var j=droppables.length;j--;){
								var elm=droppables[j].element;
								var opt=droppables[j].drop_options;
								if(target!=elm&&target.filter(opt.dragFilter)) elm.addClass(opt.activeClass);
							}*/
							
							var idrop=droppable&&droppable.interactive;
							if(!idrop){
								lastidrop&&lastidrop.dispatchEvent(new DropEvent(e.htmlEvent,"onDragOut",droppable,iObj.element,iObj.marker));
								lastidrop=null;
							}
							else if(lastidrop!=idrop){
								lastidrop&&lastidrop.dispatchEvent(new DropEvent(e.htmlEvent,"onDragOut",droppable,iObj.element,iObj.marker));
								if(idrop.droppable){
									if(target.filter(idrop.drop_options.dragFilter)){
										idrop.dispatchEvent(new DropEvent(e.htmlEvent,"onDragOver",droppable,iObj.element,iObj.marker));
									}
									lastidrop=idrop;
								}
								else lastidrop=null;
							}
							else{
								if(idrop&&idrop.droppable){
									if(target.filter(idrop.drop_options.dragFilter)){
										idrop.dispatchEvent(new DropEvent(e.htmlEvent,"onDragMove",droppable,iObj.element,iObj.marker));
									}
								}
							}
						}
						iObj.running=true;
					}
				}
				while(i);
			});
			Interactive.EVENTS_HANDLER[1]=document.onMouseUp(function(e){
				e.stopPropagation();
				var i=triggers.length;
				if(!i) return;
				do{
					var iObj=triggers[--i];
					var target=iObj.element;
					var drag_options=iObj.drag_options;
					if(iObj.active&&iObj.canDrag&&iObj.running){
						if(iObj.clone){
							iObj.clone.release();
						}
						
						//  reset location indipendant from position
						if(iObj.marker) iObj.marker.release();
						else{
							var absolute=new Point(target.outerX(),target.outerY());
							target.removeClass(drag_options.activeClass);
							target.setLocation(absolute);
						}
						
						if(target.getCurrentValue("position")=="static"){
							target.removeCss("left");
							target.removeCss("top");
						}
						for(var j=droppables.length;j--;){
							droppables[j].element.removeClass(droppables[j].drop_options.activeClass);
						}
						
						if(lastidrop&&lastidrop.droppable){
							if(target.filter(lastidrop.drop_options.dragFilter)){
								lastidrop.dispatchEvent(new DropEvent(e.htmlEvent,"onDrop",lastidrop.element,target,iObj.marker));
							}
						}
						iObj.dispatchEvent(new DragEvent(e.htmlEvent,"onDragStop",target,iObj.marker));
					}
					iObj.running=iObj.active=iObj.linked=false;
				}
				while(i);
			});
			Interactive.ACTIVE=true;
		},
		
		initEvents:function(){
			var priv=$(this);
			if(priv.init) return;
			priv.init=true;
			var target=this.element;
			var startX,startY,startW,startH;
			var sx,sy,sw,sh,mx,my,shx,shy,ssx,ssy,pageX,pageY;
			var start,canDrag,canStretch;
			var backDrag,backStretch;
			var running=false;
			var timer;
			var shakedTime=0;
			target.onselectstart=function(){return false;}
			target.onmousedown=function(){return false;}
			target.ondrag=function(){return false;}
			priv.dragH=priv.dragV=priv.stretchH=priv.stretchV=true;
			priv.cursor=this.element.style.cursor||"default";
			if(priv.onmousedown) return;
			priv.onmousedown=target.onMouseDown(function(e){
				e.stopPropagation();
				start=canDrag||canStretch;
			},this);
			if(!document||priv.onmousemove) return;
			priv.onmousemove=document.onMouseMove(function(e){
				if(!start) return;
				var x=e.pageX;
				var y=e.pageY;
				var grid;
				if(this.stretchable&&canStretch){
					var ox=x-sx;
					var oy=y-sy;
					if(!running){
					}
					grid=priv.stretchOptions.grid||[1,1];
					if(priv.stretchH){
						mx=Math.round((ox-dx)/grid[0])*grid[0];
						if(dx<0.5*sw){
							if(ox<sw){
								target.style.left=sx+mx+"px";
								target.style.width=sw-mx+"px";
							}
						}
						else if(ox>0) target.style.width=sw+mx+"px";
					}
					if(priv.stretchV){
						my=Math.round((oy-dy)/grid[1])*grid[1];
						if(dy<0.5*sh){
							if(oy<sh){
								target.style.top=sy+my+"px";
								target.style.height=sh-my+"px";
							}
						}
						else if(oy>0) target.style.height=sh+my+"px";
					}
				}
				else if(this.draggable&&canDrag){
					if(priv.timer&&!priv.dragOptions.forceRefresh) return;
					priv.timer=(function(e){
						priv.timer.clear();
						priv.timer=null;
					}).setTimeout(10,this,e);
					
					if(!running){
						var options=priv.dragOptions;
						if(options.placeHolder){
							priv.placeHolder=target.clone(true);
							priv.placeHolder.addClass(options.placeHolder.className);
							priv.placeHolder.apply(options.placeHolder.parentNode);
						}
						var prevPos=target.getCurrentValue("position");
						if(options.target){
							target.addClass(options.target.className);
							if(options.target.parentNode) target.apply(options.target.parentNode);
						}
						if(target.getCurrentValue("position")=="static") target.style.position="relative";
						this.dispatchEvent(new DragEvent(e.htmlEvent,"onDragStart",target,mx-sx,my-sy));
						var pos=target.getCurrentValue("position");
						priv.resetLocation(prevPos,pos);
						if(pos=="relative"){
							sx=target.left();
							sy=target.top();
						}
						else if(pos=="absolute"){
							sx=target.offsetX();
							sy=target.offsetY();
						}
						else if(pos=="fixed"){
							sx=target.outerX();
							sy=target.outerY();
						}
						pageX=e.pageX;
						pageY=e.pageY;
						sw=target.getWidth();
						sh=target.getHeight();
					}					
					grid=priv.dragOptions.grid||[1,1];
					mx=Math.round((x-pageX)/grid[0])*grid[0];
					my=Math.round((y-pageY)/grid[1])*grid[1];
					var speed=(shx||x)-x;
					shx=x;
					if(Math.abs(speed)>=20){
						if(Math.abs(speed+(priv.speed||0))<=20){
							if(timer) timer.clear();
							timer=(function(){
								priv.speed=shakedTime=0;
							}).setTimeout(300);
							if(++shakedTime==3) this.dispatchEvent(new ShakeEvent(e.htmlEvent,"onShake",target));
						}
						priv.speed=speed;
					}
					if(grid[0]&&priv.dragH) target.style.left=sx+mx+"px";
					if(grid[1]&&priv.dragV) target.style.top=sy+my+"px";
					
					this.dispatchEvent(new DragEvent(e.htmlEvent,"onDrag",target,mx-sx,my-sy));
				}
				running=true;
			},this);
			if(priv.onmouseup) return;
			priv.onmouseup=document.onMouseUp(function(e){
				if(start&&running){
					var options=priv.dragOptions;
					this.dispatchEvent(new DragEvent(e.htmlEvent,"onDragStop",target,mx-sx,my-sy));
					if(priv.placeHolder){
						priv.placeHolder.release();
						priv.placeHolder=null;
					}
					var prevPos=target.getCurrentValue("position");
					if(options.target){
						target.removeClass(options.target.className);
						target.restoreNode();
					}
					var pos=target.getCurrentValue("position");
					$(this).resetLocation(prevPos,pos);
					if(priv.dropTargets){
						var dropList=document.getElementsAt(target.getBounds().getCenter()).sift({className:priv.dropTargets});
						this.dispatchEvent(new DropEvent(e.htmlEvent,"onDrop",target,mx-sx,my-sy,dropList));
					}
				}
				running=start=false;
			},this);
			if(priv.checkarea) return;
			priv.checkarea=target.onMouseMove(function(e){
				if(start) return;
				canStretch=canDrag=false;
				this.stretchable&&(canStretch=priv.checkArea(new Point(e.offsetX,e.offsetY),priv.stretchOptions))||this.draggable&&(canDrag=priv.checkArea(new Point(e.offsetX,e.offsetY),priv.dragOptions));
			},this);
		},
		checkArea:function(iObj,point,options){
			var priv=$(this);
			var area=options.activeArea;
			if(!area){
				iObj.dragH=iObj.dragV=iObj.stretchH=iObj.stretchV=true;
				return true;
			}
			var w=this.element.getWidth();
			var h=this.element.getHeight();
			var contain=false;
			for(var i=area.length;i--;){
				var b=area[i];
				switch((b.relative||"").toUpperCase()){
					case "TOP_LEFT":
						var rect=new Rectangle(b.x,b.y,b.w,b.h);
						break;
					case "TOP_RIGHT":
						var rect=new Rectangle(w-b.x-b.w,b.y,b.w,b.h);
						break;
					case "BOTTOM_LEFT":
						var rect=new Rectangle(b.x,h-b.y-b.h,b.w,b.h);
						break;
					case "BOTTOM_RIGHT":
						var rect=new Rectangle(w-b.x-b.w,h-b.y-b.h,b.w,b.h);
						break;
					case "V_LEFT":
						var rect=new Rectangle(b.x,b.y,b.w,h-b.y-(b.bottom||0));
						break;
					case "V_RIGHT":
						var rect=new Rectangle(w-b.x-b.w,b.y,b.w,h-b.y-(b.bottom||0));
						break;
					case "H_TOP":
						var rect=new Rectangle(b.x,b.y,w-b.x-(b.right||0),b.h);
						break;
					case "H_BOTTOM":
						var rect=new Rectangle(b.x,h-b.y-b.h,w-b.x-(b.right||0),b.h);
						break;
					default:
						var rect=new Rectangle(b.x,b.y,b.w,b.h);
						break;
				}
				if(rect.contain(point)){
					b.affect=b.affect||"ALL";
					iObj.dragH=priv.stretchH=b.affect.toUpperCase()=="HORIZONTAL"||b.affect.toUpperCase()=="ALL";
					iObj.dragV=priv.stretchV=b.affect.toUpperCase()=="VERTICAL"||b.affect.toUpperCase()=="ALL";
					this.element.style.cursor=b.cursor||priv.cursor;
					return true;
				}
			}
			this.element.style.cursor=priv.cursor;
			return false;
		},
		restore1:function(){
			var priv=$(this);
			var index=Interactive.TRIGGERS.remove(this);
			if(index==-1) return;
			this.onselectstart=document.body.onselectionstart;
			this.onmousedown=document.body.onmousedown;
			this.ondrag=null;
			if(priv.onmousedown) priv.onmousedown.clear();
			if(priv.checkarea) priv.checkarea.clear();
			if(Interactive.ACTIVE&&!Interactive.TRIGGERS.length){
				Interactive.EVENTS_HANDLER[0].clear();
				Interactive.EVENTS_HANDLER[1].clear();
				Interactive.ACTIVE=false;
			}
			//this.element.style.cursor=priv.cursor;
		},
		restore:function(){
			var priv=$(this);
			if(!this.draggable&&!this.stretchable){
				this.onselectstart=document.body.onselectionstart;
				this.onmousedown=document.body.onmousedown;
				this.ondrag=null;
				if(priv.onmousedown) priv.onmousedown.clear();
				if(priv.onmousemove) priv.onmousemove.clear();
				if(priv.onmouseup) priv.onmouseup.clear();
				if(priv.checkarea) priv.checkarea.clear();
			}
			this.element.style.cursor=priv.cursor;
		},
		resetLocation1:function(prevPos,pos){
			var target=this.element;
			if(prevPos==pos) return;
			switch(pos){
				case "static":
					target.removeCss("left");
					target.removeCss("top");
					return;
				case "relative":
					target.setX(target.left());
					target.setY(target.top());
					return;
				case "absolute":
					target.setX(target.offsetX());
					target.setY(target.offsetY());
					return;
				case "fixed":
					target.setX(target.outerX());
					target.setY(target.outerY());
					return;
				default: return;
			}
		}
	}
})

Class({
	public:{
		ArrayList:function(){
			$(this).array=Array.apply(this,arguments);
		},
		concat:function(array){
			[].push.apply($(this).array,array);
		},
		merge:function(arraylist){
			[].push.apply($(this).array,arraylist.toArray());
		},
		insert:function(index,obj){
			var arr=$(this).array;
			if(index>arr.length) return;
			var post=arr.splice(index,arr.length);
			arr.push(obj);
			$(this).array=arr.concat(post);
		},
		remove:function(index){
			return $(this).array.splice(index,1);
		},
		removeObject:function(obj){
			var arr=$(this).array;
			var index=arr.indexOf(obj);
			if(index!=-1){
				arr.splice(index,1);
				return true;
			}
			return false;
		},
		add:function(){
			[].push.apply($(this).array,arguments);
		},
		get:function(index){
			return $(this).array[index];
		},
		toArray:function(){
			return $(this).array;
		},
		size:function(){
			return $(this).array.length;
		},
		foreach:function(func){
			var arr=this.toArray();
			return arr.foreach(func);
		}
	}
})

Class({
	Extends: ArrayList,
	
	public:{
		HtmlList:function(html_enum){
			$(this).Super();
			if(arguments.length>1) [].push.apply(this.toArray(),arguments);
			else if(html_enum) this.fill(html_enum);
		},
		fill:function(html_enum){
			var length=html_enum.length;
			var nodeType;
			for(var i=0;i<length;i++){
				nodeType=html_enum[i].nodeType;
				if(nodeType!=3&&nodeType!=8) this.add($$(html_enum[i]));
			}
		},
		sift:function(filter){
			var filtered=new HtmlList();
			var arr=this.toArray();
			var length=arr.length;
			var element, i=0;
			if(!length) return filtered;
			filter=new HtmlFilter(filter);
			do if(filter.applyTo(element=arr[i])) filtered.add(element);
			while(++i<length);
			return filtered;
		},
		seep:function(filter){
			var removed=new HtmlList();
			var arr=this.toArray();
			var i=arr.length;
			var element;
			if(!i) return filtered;
			filter=new HtmlFilter(filter);
			do if(!filter.applyTo(element=arr[--i])){
				removed.add(element);
				this.remove(i);
			}
			while(i);
			return removed;
		},
		addClass:function(className){
			var arr=this.toArray();
			var i=arr.length;
			do{
				arr[--i].addClass(className);
			}
			while(i);
		},
		removeClass:function(className){
			var arr=this.toArray();
			var i=arr.length;
			do{
				arr[--i].removeClass(className);
			}
			while(i);
		}
	}
})

Class({
	public:{
		ValueToggle:function(value1,value2){
			this.values=[value1,value2];
			$(this).flag=false;
		},
		get:function(){
			return ($(this).flag)?this.values[0]:this.values[1];
		},
		set:function(flag){
			$(this).flag=flag;
		},
		toggle:function(){
			return ($(this).flag=!$(this).flag)?this.values[0]:this.values[1];
		},
		reset:function(){
			$(this).flag=false;
		},
		state:function(){
			return $(this).flag;
		}
	}
})

Class({
	Extends:ValueToggle,
	public:{
		BoolToogle:function(initValue){
			$(this).Super(initValue,!initValue);
		}
	}
})

Class({
	Extends:ValueToggle,
	public:{
		FunctionToogle:function(func1,func2){
			$(this).Super(func1,func2);
		},
		call:function(scope){
			var args=$argumentsToArray(arguments,1);
			return this.toggle().apply(scope,args);
		}
	}
})

// ====================================== NET =====================================

AbstractClass({
	public:{
		Browser:null,
		static__FF:false,
		static__SA:false,
		static__IE:false,
		static__OP:false,
		static__fullName:"",
		static__version:"",
		static__versionID:0,
		//static__screen:window.screen,
		static__init:function(){
			var name=navigator.appName;
			var vers=navigator.userAgent;
			switch(name){
				case "Microsoft Internet Explorer" :
					if((/MSIE.*Opera/).test(vers)){
						vers=vers.match(/Opera\s*\d+\.\d+/)[0].match(/\d+\.\d+/)[0];
						name="Opera";
						Browser.OP=true;
						Browser.IE=true;
						break;
					}
					vers=vers.match(/MSIE\s*\d+\.\d+/)[0].match(/\d+\.\d+/)[0];
					name="Internet Explorer";
					temp=null;
					Browser.IE=true;
					break;
				case "Netscape" :
					var temp=vers.match(/Firefox\/\d+\.*\d*\.*\d*|Safari\/\d+\.*\d*\.*\d*/)[0];
					vers=temp.split("/")[1];
					name=temp.split("/")[0];
					Browser.FF=name=="Firefox";
					Browser.SA=!Browser.FF;
					temp=null;
					break;
				case "Opera" :
					var temp=vers.match(/Opera+?\/\d+\.\d*/)[0];
					vers=temp.split("/")[1];
					name=temp.split("/")[0];
					Browser.OP=true;
					temp=null;
					break;
				default :
					vers="Not detect";
					name="Not detect";
					Browser.IE=Browser.OP=Browser.SA=Browser.FF=false;
					break;
			}
			Browser.fullName=name;
			Browser.version=vers;
			Browser.versionID=parseInt(vers,10);
		},
		static__getWidth:function(pixel){
			return document.documentElement.clientWidth+(pixel?"px" : 0);
		},
		static__getHeight:function(pixel){
			return document.documentElement.clientHeight+(pixel?"px" : 0);
		},
		static__getRenderedWidth:function(pixel){
			return ((Browser.IE&&Browser.versionID<8)?document.documentElement.offsetWidth:document.documentElement.scrollWidth)+(pixel?"px" : 0);
		},
		static__getRenderedHeight:function(pixel){
			return ((Browser.IE&&Browser.versionID<8)?document.documentElement.offsetHeight:document.documentElement.scrollHeight)+(pixel?"px" : 0);	
		},
		static__getScrollXPosition:function(pixel){
			return document.documentElement.scrollLeft+(pixel?"px" : 0);
		},
		static__getScrollYPosition:function(pixel){
			return document.documentElement.scrollTop+(pixel?"px" : 0);
		},
		static__getName:function(){
			return Browser.fullName+" "+Browser.version;
		}
	}
})
Browser.init();


Class({
	public:{
		QueryObject:function(data,name){
			$(this).map={};
			var queryString="";
			if(data){
				if($isString(data)){
					queryString=data;
					data=data.split(";");
					var length=data.length;
					for(var i=0;i<length;i++){
						var key=data[i].split("=")[0];
						var value=data[i].split("=")[1];
						$(this).map[key]=value;
					}
				}
				else if($isArray(data)){
					name=name||"array";
					var length=data.length;
					for(var i=0;i<length;i++){
						queryString+=name+"["+i+"]="+encodeURIComponent(data[i])+"&";
						$(this).map[i]=data[i];
					}
					queryString=queryString.replace(/&$/,"");
				}
				else{
					for(key in data){
						$(this).map=data;
						if(data.hasOwnProperty(key)){
							queryString+=key+"="+data[key]+"&";
						}
					}
					queryString=queryString.replace(/&$/,"");
				}
			}
			this.querystring=queryString;
		},
		getQuery:function(){
			return this.querystring;
		},
		getValue:function(key){
			return $(this).map[key];
		}
	}
})



Class({
	public:{
		URL:function(urlstring,_go){
			this.setUrl(urlstring,_go);
		},
		setUrl:function(urlstring,_go){
			this.url=urlstring||window.location.href;
			var temp=urlstring.split("?");
			this.hostname=temp[0];
			this.querystring=(temp[1])?temp[1]:"";
			if(_go) window.location.href=urlstring;
			return this.url;
		},
		addQuery:function(name,value){
			this.querystring=(this.querystring)?this.querystring+"&"+name+"="+value:name+"="+value;
			return this.url=this.hostname+"?"+this.querystring;
		},
		useQueryObject:function(queryObject){
			this.querystring=queryObject.querystring;
			return this.url=this.hostname+"?"+this.querystring;
		},
		useQueryString:function(queryString){
			this.querystring=queryString;
			return this.url=this.hostname+"?"+this.querystring;
		},
		getQueryValue:function(key){
			var queryObject=this.getQueryObject();
			return queryObject.getValue(key);
		},
		getQueryObject:function(){
			if(this.querystring){
				return new QueryObject(this.querystring);
			}
			return new QueryObject("");
		},
		locate:function(){
			window.location.href=this.url;
		},
		static__queryValue:function(key){
			return new URL(window.location.href).getQueryValue(key);
		},
		static__queryObject:function(toObject){
			return (new URL(window.location.href)).getQueryObject();
		},
		static__current:function(){
			return new URL(window.location.href);
		}
	}
})

Class({
	Extends:EventDispatcher,
	public:{
		HttpRequest:function(options){
			$(this).Super();
			this.http=null;
			try{
				this.http=new XMLHttpRequest();
			}
			catch(e){
				try{
					this.http=new ActiveXObject("Msxml2.XMLHTTP");
				}
				catch(e){
					this.http=new ActiveXObject("Microsoft.XMLHTTP");
				}
			}
			if(this.http){
				this.http.onreadystatechange=(function(){
					if(this.http.readyState==4&&this.http.status==200){
						this.dispatchEvent(new HttpRequestEvent("onResponse",this,this.http.responseText,this.http.responseXML));
						this.http.onreadystatechange=function(){};
						this.http.abort();
					}
				}).self(this);
			}
			this.open(options);
		},
		static__sendTo:function(queryObject,options){
			var http=new HttpRequest(options);
			if(http) http.send(queryObject);
			return http;
		},
		setRequestHeader:function(header,value){
			this.http.setRequestHeader(header,value);
		},
		open:function(options){
			var priv=$(this);
			if(!options) return;
			if($isString(options)) priv.url=options;
			priv.header=options.header||"content-type=application/x-www-form-urlencoded";
			priv.method=options.method||"POST";
			priv.url=(priv.url)?priv.url:(options.url instanceof URL)?options.url.hostname:options.url;
			priv.async=(options.async!=null)?options.async:true;
			priv.username=options.username;
			priv.password=options.password;
			if(!priv.url) return;
			this.http.open(priv.method,priv.url,priv.async,priv.username,priv.password);
			this.http.setRequestHeader(priv.header.split("=")[0],priv.header.split("=")[1]);
		},
		reOpen:function(){
			var priv=$(this);
			this.http.open(priv.method,priv.url,priv.async,priv.username,priv.password);
			this.http.setRequestHeader(priv.header.split("=")[0],priv.header.split("=")[1]);
		},
		post:function(url,async,username,password){
			this.http.open("POST",url,"content-type=application/x-www-form-urlencoded",async,username,password);
		},
		get:function(url,header,async,username,password){
			this.http.open("GET",url,header,async,username,password);
		},
		call:function(){
			this.reOpen();
			this.http.send(null);
		},
		send:function(data){
			data=(data instanceof QueryObject)?data.getQuery():data;
			this.reOpen();
			this.http.send(data);
		},
		sendByURL:function(url,method,header,async,username,password){
			this.open(method,url.hostname,header,async,username,password);
			this.send(url.getQueryObject());
		},
		onResponse:function(func,scope){
			this.addEventListener("onResponse",func,scope);
		}
	}
})


// =============================== Style & Motion ==================================
// Class

Class({
	public:{
		$Image:function(src,width,height){
			var img=$$((width&&height)?new Image(width,height):new Image());
			img.src=src;
			img.getImageSize=function(){
				return new Dimension(this.width,this.height);
			}
			return img;
		}
	}
})

Class({
	public:{
		Style:function(){
			$(this).rules={};
		},
		addCssRule:function(cssRule){
			if(!cssRule instanceof CssRule) throw(new IllegalArgumentException("addCssRule","cssRule"));
			this.addRule(cssRule.getRuleName(),cssRule.getRuleValue());
		},
		addRule:function(rule,value){
			if(!$isString(rule)||!$isString(value)) throw(new IllegalArgumentException("addRule","rule,value"));
			$(this).rules[rule]=value;
		},
		getCss:function(){
			var css="";
			var rules=$(this).rules;
			for(var rule in rules){
				if(rules.hasOwnProperty(rule)) css+=rule+":"+rules[rule]+";";
			}
			return css;
		},
		toString:function(){
			return "Style: "+this.getCss();
		}
	}
})

Class({
	public:{
		CssRule:function(rule,value){
			this.setCss(rule,value);
		},
		static__shorten:function(name){
			return (/-/.test(name))?name.replace(/-./g,function(w){return w.replace("-","").toUpperCase();}):name;
		},
		static__lenghten:function(name){
			return (/[A-Z]/.test(name))?name.replace(/[A-Z]/g,function(w){return "-"+w.toLowerCase();}):name;
		},
		getRuleName:function(){
			return $(this).ruleName;
		},
		getRuleValue:function(){
			return $(this).ruleValue;
		},
		getCss:function(){
			return $(this).css;
		},
		setCss:function(rule,value){
			$(this).ruleName=rule;
			$(this).ruleValue=value;
			$(this).css=rule+":"+value+";";
		}
	}
})

Class({
	Extends:CssRule,
	
	public:{
		Border:function(width,style,color,side){
			$(this).Super();
			this.width=parseInt(size,10)+"px";
			this.style=style;
			this.color=(color instanceof Color)?color:new Color(color);
			this.side=side;
			this.setCss("border"+(($notExists(side))?"":"-"+side),this.width+" "+this.style+" "+this.color.getHTMLColor);
		}
	}
})

Class({
	public:{
		Color:function(r,g,b){
			$(this).hexColor=0x000000;
			this.setRGB(r,g,b);
		},
		setRGB:function(){
			var priv=$(this);
			if($exists(arguments[0])){
				if($isArray(arguments[0])){
					priv.hexColor=(Math.round(arguments[0][0])*256+Math.round(arguments[0][1]))*256+Math.round(arguments[0][2]);
				}
				else if($exists(arguments[1])&&$exists(arguments[2])){
					priv.hexColor=(Math.round(arguments[0])*256+Math.round(arguments[1]))*256+Math.round(arguments[2]);
				}
				else if($isString(arguments[0])){
					var s=arguments[0];
					if(/rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)/.test(s)){
						var r=parseInt(s.match(/\d+/g)[0],10);
						var g=parseInt(s.match(/\d+/g)[1],10);
						var b=parseInt(s.match(/\d+/g)[2],10);
						priv.hexColor=(Math.round(r)*256+Math.round(g))*256+Math.round(b);
					}
					else{
						if(s.length<=4){
							var s=s.replace(/(\w)(\w)(\w)/,"$1$1$2$2$3$3");
						}
						priv.hexColor=s.replace("#","").hexToNum();
					}
				}
				else priv.hexColor=arguments[0];
			}
			else priv.hexColor=0;
			priv.red=priv.hexColor>>16;
			priv.green=(priv.hexColor>>8)&0xFF;
			priv.blue=(priv.hexColor)&0xFF;
			this.rgbColorComponents=[priv.red,priv.green,priv.blue];
		},
		getHexRGB:function(){
			return $(this).hexColor;
		},
		getHTMLColor:function(){
			return "#"+$(this).hexColor.numToHex(6);
		},
		getRed:function(){
			return $(this).red;
		},
		getGreen:function(){
			return $(this).green;
		},
		getBlue:function(){
			return $(this).blue;
		},
		mix:function(color,perc){
			var perc=perc||1;
			return this.blend(color,perc*0.5);
		},
		blend:function(color,perc){
			var perc=(!$isNull(perc))?(perc>1)?1:(perc<0)?0:perc:0.5;
			var invPerc=1-perc;
			var crgb=this.rgbColorComponents;
			var rgb=color.rgbColorComponents;
			return new Color(invPerc*crgb[0]+perc*rgb[0],invPerc*crgb[1]+perc*rgb[1],invPerc*crgb[2]+perc*rgb[2]);
		},
		static__htmlColor:function(colorString){
			if($isString(colorString)){
				if(/rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)/.test(colorString)){
					var r=parseInt(colorString.match(/\d+/g)[0],10);
					var g=parseInt(colorString.match(/\d+/g)[1],10);
					var b=parseInt(colorString.match(/\d+/g)[2],10);
					return "#"+((Math.round(r)*256+Math.round(g))*256+Math.round(b)).numToHegetX();
				}
				else return colorString;
			}
			return "#000000";
		}
	}
})

Class({
	public:{
		Linear:function(){
		},
		static__easeOut:function(start,end,frames,frame){
			return start+(end-start)/frames*frame;
		},
		static__easeIn:function(start,end,frames,frame){
			return start+(end-start)/frames*frame;
		},
		static__easeInOut:function(start,end,frames,frame){
			return start+(end-start)/frames*frame;
		},
		static__easeNone:function(start,end,frames,frame){
			return start+(end-start)/frames*frame;
		}
	}
})

Class({
	public:{
		Pow:function(n,bool){
			this.n=n;
			if(!bool) return new Pow(n,true);
		},
		easeOut:function(start,end,frames,frame){
			return end+(start-end)*Math.pow(1-frame/frames,this.n);
		},
		easeIn:function(start,end,frames,frame){
			return start+(end-start)*Math.pow(frame/frames,this.n);
		},
		easeInOut:function(start,end,frames,frame){
			if(frame<=(frames*=0.5)){
				return start+0.5*(end-start)*Math.pow(frame/frames,this.n);
			}
			return end+0.5*(start-end)*Math.pow(1-(frame-frames)/frames,this.n);
		}
	}
});

Class({
	public:{
		Exp:function(){},
		static__easeOut:function(start,end,frames,frame){
			return end+(start-end)*Math.exp(8*(-frame/frames));
		},
		static__easeIn:function(start,end,frames,frame){
			return start+(end-start)*Math.exp(8*(frame/frames-1));
		},
		static__easeInOut:function(start,end,frames,frame){
			if(frame<=(frames*=0.5)){
				return start+0.5*(end-start)*Math.exp(8*(frame/frames-1));
			}
			return end+0.5*(start-end)*Math.exp(8*((frames-frame)/frames));
		}
	}
})

Class({
	public:{
		Sin:function(){},
		static__easeOut:function(start,end,frames,frame){
			return start+(end-start)*Math.sin(0.5*Math.PI*frame/frames);
		},
		static__easeIn:function(start,end,frames,frame){
			return end+(start-end)*Math.sin(0.5*Math.PI*(frames-frame)/frames);
		},
		static__easeInOut:function(start,end,frames,frame){
			if(frame<=(frames*=0.5)){
				return 0.5*(end+start)+0.5*(start-end)*Math.sin(0.5*Math.PI*(frames-frame)/frames);
			}
			return 0.5*(end+start)+0.5*(end-start)*Math.sin(0.5*Math.PI*(frame-frames)/frames);
		}
	}
})

Class({
	public:{
		Elliptic:function(){},
		static__easeOut:function(start,end,frames,frame){
			return start+(end-start)/frames*Math.sqrt(2*frames*frame-frame*frame);
		},
		static__easeIn:function(start,end,frames,frame){
			return end+(start-end)/frames*Math.sqrt(frames*frames-frame*frame);
		},
		static__easeInOut:function(start,end,frames,frame){
			if(frame<=(frames*=0.5)){
				return 0.5*(end+start)+0.5*(start-end)/frames*Math.sqrt(frames*frames-frame*frame);
			}
			return 0.5*(end+start)+0.5*(end-start)/frames*Math.sqrt(frames*frames-(frame=2*frames-frame)*frame);
		}
	}
})

Class({
	public:{
		Back:function(){
		},
		static__easeOut:function(start,end,frames,frame){
			var M=end+0.3*(end-start);
			var m=0.5*(M+end);
			var F1=0.55*frames;
			var F2=0.5*(F1+frames);
			var d=frames-F2;
			if(frame<=F1) return M+(start-M)*(frame=1-frame/F1)*frame;
			else if(frame<=F2) return M+(m-M)*(frame=(frame-F1)/d)*frame;
			else return end+(m-end)*(frame=1-(frame-F2)/d)*frame;
		},
		static__easeIn:function(start,end,frames,frame){
			var M=start+0.3*(start-end);
			var m=0.5*(M+start);
			var F1=0.55*frames;
			var F2=0.5*(F1+frames);
			var d=frames-F2;
			if((frame=frames-frame)<=F1) return M+(end-M)*(frame=1-frame/F1)*frame;
			else if(frame<=F2) return M+(m-M)*(frame=(frame-F1)/d)*frame;
			else return start+(m-start)*(frame=1-(frame-F2)/d)*frame;
		},
		static__easeInOut:function(start,end,frames,frame){
			frames*=0.5;
			var M=start+0.15*(start-end);
			var m=0.5*(M+start);
			var F1=0.55*frames;
			var F2=0.5*(F1+frames);
			var d=frames-F2;
			if(frame<=frames){
				if((frame=frames-frame)<=F1) return M+(0.5*(end+start)-M)*(frame=1-frame/F1)*frame;
				else if(frame<=F2) return M+(m-M)*(frame=(frame-F1)/d)*frame;
				else return start+(m-start)*(frame=1-(frame-F2)/d)*frame;
			}
			M=end+0.15*(end-start);
			m=0.5*(M+end);
			frame-=frames;
			if(frame<=F1) return M+(0.5*(end+start)-M)*(frame=1-frame/F1)*frame;
			else if(frame<=F2) return M+(m-M)*(frame=(frame-F1)/d)*frame;
			else return end+(m-end)*(frame=1-(frame-F2)/d)*frame;
		}
	}
})

Class({
	public:{
		Bounce:function(q,bool){
			this.q=(q>=1)?0.9:(q<=0)?0:q||0.5;
			if(!bool) return new Bounce(q,true);
		},
		easeOut:function(start,end,frames,frame,n){
			var q=this.q;
			var q1=1-q;
			var q2=1+q;
			var to=frames*q1/q2;
			var n=(Math.log(0.5*(q2-frame*q1/to)+0.00001)/Math.log(q))|0;
			var qn=2*Math.pow(q,n);
			var a=(end-start)/(to*to);
			var x=frame+to*(qn-q2)/q1;
			return (end+a*x*(x-to*qn))|0;
		},
		easeIn:function(start,end,frames,frame){
			var q=this.q;
			var q1=1-q;
			var q2=1+q;
			var to=frames*q1/q2;
			var n=(Math.log(0.5*(q2-(frame=frames-frame)*q1/to)+0.00001)/Math.log(q))|0;
			var qn=2*Math.pow(q,n);
			var a=(start-end)/(to*to);
			var x=frame+to*(qn-q2)/q1;
			return (start+a*x*(x-to*qn))|0;
		},
		easeInOut:function(start,end,frames,frame){
			var q=this.q;
			var q1=1-q;
			var q2=1+q;
			var to=(frames*=0.5)*q1/q2;
			var st=start+(end-start)/2;
			if(frame<frames){
				end=start;
				frame=frames-frame;
			}
			else frame-=frames;
			var n=(Math.log(0.5*(q2-frame*q1/to)+0.00001)/Math.log(q))|0;
			var qn=2*Math.pow(q,n);
			var a=(end-st)/(to*to);
			var x=frame+to*(qn-q2)/q1;
			return (end+a*x*(x-to*qn))|0;
		}
	}
})
Class({
	public:{
		Elastic:function(){},
		static__easeOut:function(start,end,frames,frame){
			//3.18*9
			var y=(end-start)*(1-1.04*Math.exp(-6*(frame/=frames))*Math.sin(19*frame+1.27))+start;
			return (frame==1)?end:y;
		},
		static__easeIn:function(start,end,frames,frame){
			var y=(start-end)*(1-1.04*Math.exp(-6*(frame=1-frame/frames))*Math.sin(19*frame+1.27))+end;
			return (frame==0)?end:y;
		},
		static__easeInOut:function(start,end,frames,frame){
			if(frame<=(frames*=0.5)){
				var y=0.5*(start-end)*(1-1.04*Math.exp(-6*(frame=1-frame/frames))*Math.sin(19*frame+1.27))+0.5*(start+end);
				return (frame==0)?0.5*(start+end):y;
			}
			var y=0.5*(end-start)*(1-1.04*Math.exp(-6*(frame=frame/frames-1))*Math.sin(19*frame+1.27))+0.5*(start+end);
			return (frame==1)?end:y;
		}
	}
})

Class({
	Extends:EventDispatcher,
	public:{
		Timer:function(delay,taskPerformer,scope){
			$(this).Super();
			$(this).running=false;
			$(this).delay=delay||100;
			this.setTask(taskPerformer,scope);
		},
		cancel:function(){
			var priv=$(this);
			if(priv.timerHandler) priv.timerHandler.clear();
			priv.timerHandler=null;
			priv.running=false;
		},
		getDelay:function(){
			return $(this).delay;
		},
		getTask:function(){
			return $(this).task;
		},
		isRunning:function(){
			return $(this).running;
		},
		removeTask:function(){
			this.cancel();
			priv.task=null;
		},
		setDelay:function(delay){
			var running=this.isRunning();
			this.cancel();
			$(this).delay=delay||100;
			if(running) this.start();
		},
		setTask:function(taskPerformer,scope){
			if(!$isFunction(taskPerformer)) return null;
			$(this).task=taskPerformer.self(scope);
		},
		restart:function(){
			this.cancel();
			this.start();
			this.dispatchEvent(new TimerEvent("onTimerRestart",this,new Date().getTime()));
		},
		start:function(){
			if(!this.isRunning()){
				var priv=$(this);
				if(priv.timerHandler) priv.timerHandler.wakeup();
				else if($isFunction(priv.task)) priv.timerHandler=priv.task.setInterval(priv.delay);
				priv.running=true;
				this.dispatchEvent(new TimerEvent("onTimerStart",this,new Date().getTime()));
			}
		},
		stop:function(){
			if(this.isRunning()){
				$(this).timerHandler.idle();
				$(this).running=false;
				this.dispatchEvent(new TimerEvent("onTimerStop",this,new Date().getTime()));
			}
		},
		onTimerRestart:function(func,scope){
			return this.addEventListener("onTimerRestart",func,scope);
		},
		onTimerStart:function(func,scope){
			return this.addEventListener("onTimerStart",func,scope);
		},
		onTimerStop:function(func,scope){
			return this.addEventListener("onTimerStop",func,scope);
		}
	}
})

AbstractClass("Fx",{
	public:{
		static__NUMFRAMES:50,
		static__DELAY:25
	}
})

Class({
    Extends:EventDispatcher,
	public:{
		Interpolation:function(target,propsObject,options){
			$(this).Super();
			this.target=target;
			if(target.isInterpolated()) target.getCurrentInterpolation().stop();
			this.targetStyle=target.style;
			this.setOptions(options);
			this.easing=($isFunction(options))?options:this.easing;
			var priv=$(this);
			priv.timer=(this.timerless)?null:new Timer(this.delay,
				function(){
					this.setFrame(++this.currentFrame);
					this.dispatchEvent(new MotionEvent("onMotionUpdate",this,this.currentFrame,this.value));
					if(this.currentFrame>=this.numFrames) this.stop(true);
				},
			this);
			priv.running=false;
			priv.stopped=false;
			priv.suspended=false;
			priv.initInterpolation(propsObject);
		},
		addTweens:function(propsObj){
			if(!this.tweenedProps.contain(prop)){
				$(this).createTweensFrames(propObj.name,propObj.begin,propObj.finish,this.numFrames,this.easing);
			}
		},
		continueTo:function(propsObject,options){
			this.stop();
			$(this).initInterpolation(propsObject,$mergeObjects(this.getOptions(),options));
			this.start();
		},
		fforward:function(){
			this.setFrame(this.numFrames);
		},
		getBegin:function(prop){
			return $(this).beginValues[prop];
		},
		getFinish:function(prop){
			return $(this).finishValues[prop];
		},
		getOptions:function(){
			return {
				numFrames:this.numFrames,
				delay:this.delay,
				easing:this.easing,
				timerless:this.timerless
			};
		},
		isRunning:function(){
			return $(this).running;
		},
		loop:function(){
			this.start();
		},
		nextFrame:function(){
			this.setFrame(++this.currentFrame);
		},
		onMotionUpdate:function(func,scope){
			return this.addEventListener("onMotionUpdate",func,scope);
		},
		onMotionStart:function(func,scope){
			return this.addEventListener("onMotionStart",func,scope);
		},
		onMotionStop:function(func,scope){
			return this.addEventListener("onMotionStop",func,scope);
		},
		onMotionComplete:function(func,scope){
			return this.addEventListener("onMotionComplete",func,scope);
		},
		prevFrame:function(){
			this.setFrame(--this.currentFrame);
		},
		rewind:function(){
			this.setFrame(this.currentFrame=1);
		},
		resume:function(){
			var priv=$(this);
			if(priv.timer&&priv.stopped){
				priv.timer.start();
				priv.running=true;
				priv.stopped=false;
				this.dispatchEvent(new MotionEvent("onMotionResume",this,this.currentFrame,this.value));
			}
		},
		resumeTweens:function(){
			for(var i=arguments.length;i--;){
				var prop=arguments[i];
				if(!this.tweenedProps.contain(prop)){
					this.tweenedProps.push(prop);
					this.tweensFrames.push($(this).tweens[prop]);
				}
			}
		},
		reverse:function(){
			this.tweensFrames.foreach(function(frames){
				frames.reverse();
			});
			this.start();
		},
		setFrame:function(frame){
			var props=this.tweenedProps;
			var rendering=this.targetStyle;
			var frames=this.tweensFrames;
			//rendering.display="none";
			var i=props.length;
			if(!i) return;
			do rendering[props[--i]]=frames[i][frame];
			while(i);
			//rendering.display="";
		},
		setOptions:function(options){
			options=$fillObject({
				numFrames:null,
				delay:null,
				easing:null,
				timerless:null
			},options,{
				numFrames:Fx.NUMFRAMES,
				delay:Fx.DELAY,
				easing:Linear.easeNone,
				timerless:false
			});
			for(var option in options){
				if(options.hasOwnProperty(option)){
					this[option]=options[option];
				}
			}
		},
		start:function(){
			var priv=$(this);
			if(priv.timer){
				this.setFrame(this.currentFrame=1);
				priv.timer.start();
				this.dispatchEvent(new MotionEvent("onMotionStart",this,this.currentFrame,this.value));
				priv.running=true;
				priv.stopped=false;
			}
		},
		stop:function(complete){
			var priv=$(this);
			if(priv.timer&&priv.running){
				this.target.currentInterpolation=null;
				priv.timer.stop();
				priv.running=false;
				priv.stopped=true;
				priv.complete=complete;
				if(complete) this.dispatchEvent(new MotionEvent("onMotionComplete",this.target,this.currentFrame,this.value));
				else this.dispatchEvent(new MotionEvent("onMotionStop",this,this.currentFrame,this.value));
			}
		},
		stopTweens:function(){
			for(var i=arguments.length;i--;){
				var prop=arguments[i];
				var index=this.tweenedProps.remove(prop);
				if(index!=-1) this.tweensFrames.splice(index,1);
			}
			if(this.tweenedProps.length==0) this.stop();
		},
		yoyo:function(){
			this.continueTo($(this).beginValues);
		}
	},
	private:{
		initInterpolation:function(propsObject,options){
			this.target.currentInterpolation=this;
			if(options){
				this.setOptions(options);
				this.easing=($isFunction(options))?options:this.easing;
			}
			$(this).tweens={};
			$(this).beginValues={};
			$(this).finishValues={};
			this.tweenedProps=[];
			this.tweensFrames=[];
			for(var prop in propsObject){
				if(propsObject.hasOwnProperty(prop)){
					var value=propsObject[prop];
					prop=CssRule.shorten(prop);
					var begin=this.target.getTweenableValue(prop);
					var finish=value;
					var easing=this.easing;
					if($isArray(value)){
						begin=$firstValid(((!$isFunction(value[1]))?value[0]:begin),begin);
						finish=$firstValid(((!$isFunction(value[1]))?value[1]:value[0]),null);
						easing=$firstValid((($isFunction(value[1]))?value[1]:value[2]),easing);
					}
					$(this).tweens[prop]=$(this).createTweenFrames(prop,begin,finish,this.numFrames,easing);
				}
			}
		},
		createTweenFrames:function(prop,begin,finish,numFrames,easing){
			isColor=/color/i.test(prop);
			isOpacity=/opacity/i.test(prop);
			prop=(isOpacity&&Browser.IE)?"filter":prop;
			var frames=[];
			var unit=(isColor)?"":((finish).toString().match(/px|%|ul|pc|pt|mm|cm|in|ex|em/)||[""])[0];
			var math=(finish+"").match(/^\+/);
			if(math){
				finish=(finish+"").replace(/^\+/,"");
				finish=parseFloat(begin)+parseFloat(finish)+unit;
			}
			$(this).beginValues[prop]=begin;
			$(this).finishValues[prop]=finish;
			for(var i=numFrames+1;--i;){
				if(isColor) frames[i]=new Color(begin).blend(new Color(finish),easing(0,100,numFrames-1,i-1)/100).getHTMLColor();
				else{
					if(isOpacity&&Browser.IE) frames[i]="alpha(opacity="+easing(parseFloat(begin),parseFloat(finish),numFrames-1,i-1)*100+")";
					else frames[i]=easing(parseFloat(begin),parseFloat(finish),numFrames-1,i-1)+unit;
				}
			}
			frames[0]=frames[1];
			this.tweenedProps.push(prop);
			this.tweensFrames.push(frames);
			return frames;
		}
	}
})

Class({
	public:{
		Motion:function(target,propsObject,easing,numFrames,owner){
			this.target=target;
			this.targetStyle=target.style;
			this.easing=easing||Linear.easeNone;
			this.numFrames=numFrames||Fx.NUMFRAMES;
			$(this).initInterpolation(propsObject);
		},
		setInitialFrame:function(frame){
			this.keyFrame=frame-1;
			this.lastFrame=this.keyFrame+this.numFrames;
		},
		reallocate:function(numFrames){
			this.numFrames=numFrames;
			this.lastFrame=this.keyFrame+this.numFrames;
			for(var tweens,i=0;tween=this.tweens[i++];) tween.allocateFrames(numFrames);
		},
		setLastFrame:function(frame){
			this.reallocate(frame-this.keyFrame);
		},
		addTweens:function(propsObj){
			if(!this.tweenedProps.contain(prop)){
				$(this).createTweensFrames(propObj.name,propObj.begin,propObj.finish,this.numFrames,this.easing);
			}
		},
		getBegin:function(prop){
			return $(this).beginValues[prop];
		},
		getFinish:function(prop){
			return $(this).finishValues[prop];
		},
		getOptions:function(){
			return {
				numFrames:this.numFrames,
				delay:this.delay,
				easing:this.easing,
				timerless:this.timerless
			};
		},
		loop:function(){
			this.start();
		},
		resumeTweens:function(){
			for(var i=arguments.length;i--;){
				var prop=arguments[i];
				if(!this.tweenedProps.contain(prop)){
					this.tweenedProps.push(prop);
					this.tweensFrames.push($(this).tweens[prop]);
				}
			}
		},
		reverse:function(){
			this.tweensFrames.foreach(function(frames){
				frames.reverse();
			});
			this.start();
		},
		setFrame:function(frame){
			frame-=this.keyFrame;
			var props=this.tweenedProps;
			var rendering=this.targetStyle;
			var frames=this.tweensFrames;
			//rendering.display="none";
			var i=props.length;
			if(!i) return;
			do rendering[props[--i]]=frames[i][frame];
			while(i);
			//rendering.display="";
		},
		stopTweens:function(){
			for(var i=arguments.length;i--;){
				var prop=arguments[i];
				var index=this.tweenedProps.remove(prop);
				if(index!=-1) this.tweensFrames.splice(index,1);
			}
		},
		yoyo:function(){
			this.continueTo($(this).beginValues);
		}	
	},
	private:{
		initInterpolation:function(propsObject){
			$(this).tweens={};
			$(this).beginValues={};
			$(this).finishValues={};
			this.tweenedProps=[];
			this.tweensFrames=[];
			for(var prop in propsObject){
				if(propsObject.hasOwnProperty(prop)){
					var value=propsObject[prop];
					prop=CssRule.shorten(prop);
					var begin=this.target.getCurrentValue(prop);
					var finish=value;
					var easing=this.easing;
					if($isArray(value)){
						begin=$firstValid(((!$isFunction(value[1]))?value[0]:begin),begin);
						finish=$firstValid(((!$isFunction(value[1]))?value[1]:value[0]),null);
						easing=$firstValid((($isFunction(value[1]))?value[1]:value[2]),easing);
					}
					$(this).beginValues[prop]=begin;
					$(this).finishValues[prop]=finish;
					$(this).tweens[prop]=$(this).createTweenFrames(prop,begin,finish,this.numFrames,easing);
				}
			}
		},
		createTweenFrames:function(prop,begin,finish,numFrames,easing){
			isColor=/color/i.test(prop);
			isOpacity=/opacity/i.test(prop);
			prop=(isOpacity&&Browser.IE)?"filter":prop;
			var frames=[];
			var unit=(isColor)?"":((begin).toString().match(/px|%|ul|pc|pt|mm|cm|in|ex|em/)||[""])[0];
			var math=(finish+"").match(/^\+/);
			if(math){
				finish=(finish+"").replace(/^\+/,"");
				finish=parseFloat(begin)+parseFloat(finish)+unit;
			}
			for(var i=numFrames+1;--i;){
				if(isColor) frames[i]=new Color(begin).blend(new Color(finish),easing(0,100,numFrames-1,i-1)/100).getHTMLColor();
				else{
					var value=easing(parseFloat(begin),parseFloat(finish),numFrames-1,i-1);
					if(isOpacity&&Browser.IE) frames[i]="alpha(opacity="+value*100+")";
					else if(prop=="width"||prop=="height") frames[i]=((value<0)?0:value)+unit;
					else frames[i]=value+unit;
				}
			}
			frames[0]=frames[1];
			this.tweenedProps.push(prop);
			this.tweensFrames.push(frames);
			return frames;
		}
	}
})

Class({
	public:{
		TweenLayer:function(timeline,obj){
			this.numFrames=0;
			this.lastMotion;
			this.frames=[];
			this.layerId=timeline.layers.length;
			this.layerOwner=obj;
			this.timeline=timeline;
		},
		setFrame:function(frame){
			var m=this.frames[frame];
			if(!m){
				if(this.lastMotion) this.lastMotion.setFrame(this.lastMotion.lastFrame);
			}
			else (this.lastMotion=m).setFrame(frame);
			//this.layerOwner.setFrame(frame);
			//log(this.layerOwner.getX());
		},
		addMotion:function(motion,pos){
			switch(pos){
				case "continue": pos=this.numFrames; break;
				default:
					pos=(pos==null||pos=="after")?this.numFrames+1:(pos<1)?1:pos;
					if(this.frames[pos]) this.frames[pos].setLastFrame(pos-1);
					break;
			}
			motion.setInitialFrame(pos);
			var length=pos+motion.numFrames;
			this.frames.splice(length,this.numFrames);
			//log("layer["+this.layerId+"] ADD  ",motion.numFrames+" frames start at "+pos);
			for(var i=pos;i<length;i++){
				//log("layer["+this.layerId+"]   ",i);
				this.frames[i]=motion;
			}
			this.frames[0]=this.frames[1];
			this.numFrames=this.frames.length-1;
			//log("NEW LENGTH:"+this.numFrames);
		},
		fill:function(length){
			log("fill",this.numFrames,length);
			this.frames.fill(this.lastMotion,this.numFrames,length);
		},
		resizeMotion:function(motion,length){
			
		}
	}
})



Class({
	Extends:EventDispatcher,
	public:{
		TimeLine:function(name,delay){
			$(this).Super();
			this.name=name;
			this.numFrames=0;
			this.delay=delay||Fx.DELAY;
			this.objects=[];
			this.layers=[];
			this.currentFrame=1;
			this.tweens=[];
			this.looped=0;
			$(this).timer=new Timer(this.delay,function(e){
				this.setFrame(++this.currentFrame);
				if(this.currentFrame>=this.numFrames) this.stop(true);
			},this);
		},
		start:function(){
			var priv=$(this);
			if(priv.timer){
				this.setFrame(this.currentFrame=1);
				priv.timer.start();
				this.dispatchEvent(new MotionEvent("onMotionStart",this,this.frame,this.value));
				priv.running=true;
				priv.stopped=false;
			}
		},
		stop:function(complete){
			var priv=$(this);
			if(priv.timer&&priv.running){
				priv.timer.stop();
				priv.running=false;
				priv.stopped=true;
				if(complete) this.dispatchEvent(new MotionEvent("onMotionComplete",this,this.frame,this.value));
				else this.dispatchEvent(new MotionEvent("onMotionStop",this,this.frame,this.value));
			}
		},
		addLayer:function(obj){
			if(!obj) return;
			if(this.objects.indexOf(obj)!=-1){
				var placeHolderd=obj.placeHolderNode(true);
				placeHolderd.apply(obj.parentNode);
				obj=placeHolderd;
			}
			this.layers.push(new TweenLayer(this,obj));
			this.objects.push(obj);
			return obj;
		},
		onMotionUpdate:function(func,scope){
			return this.addEventListener("onMotionUpdate",func,scope);
		},
		onMotionComplete:function(func,scope){
			return this.addEventListener("onMotionComplete",func,scope);
		},
		addMotion:function(pos,target,propsObject,easing,numFrames){
			var behaviour=target.behaviour||{};
			for(var prop in behaviour){
				if(behaviour.hasOwnProperty(prop)){
					var currentValue=behaviour[prop];
					var tweenValue=propsObject[prop];
					if(tweenValue==null) propsObject[prop]=currentValue;
				}
			}
			for(var prop in propsObject){
				if(propsObject.hasOwnProperty(prop)){
					var propValue=propsObject[prop];
					var begin=($isArray(propValue))?($isFunction(propValue[1])||propValue[1]==null)?behaviour[prop]||target.getCurrentValue(prop):propValue[0]:behaviour[prop]||target.getCurrentValue(prop);
					var finish=($isArray(propValue))?($isFunction(propValue[1])||propValue[1]==null)?propValue[0]||Number.NaN:propValue[1]:propValue;
					behaviour[prop]=finish;
					propsObject[prop]=[begin,finish,($isFunction(propValue[1]))?propValue[1]:($isFunction(propValue[2]))?propValue[2]:easing];
				}
			}
			target.behaviour=behaviour;
			$(this).fitSize(target);
			var tween=new Motion(target,propsObject,easing,numFrames,this);
			//[].push.apply(this.tweens,tween.tweens);
			var layer;
			var index=0;
			if((index=this.objects.indexOf(target))==-1){
				layer=new TweenLayer(this,target);
				layer.addMotion(tween,pos);
				this.layers.push(layer);
				this.objects.push(target);
			}
			else{
				layer=this.layers[index];
				layer.addMotion(tween,pos);
			}
			this.numFrames=0;
			for(var layer,i=0;layer=this.layers[i++];) this.numFrames=(layer.numFrames>this.numFrames)?layer.numFrames:this.numFrames;
			//log("NEW SIZE:", this.numFrames);
		},
		getX:function(){
			return this.left;
		},
		getY:function(){
			return this.top;
		},
		getWidth:function(){
			return this.width;
		},
		getHeight:function(){
			return this.height;
		},
		getCurrentValue:function(css){
			css=CssRule.shorten(css);
			return this[css];
		},
		motionTo:function(target,propsObject,easing,numFrames){
			this.addMotion("continue",target,propsObject,easing,numFrames);
		},
		setFrame:function(frame){
			if(frame%(this.numFrames+1)==0) this.looped++;
			this.currentFrame=frame=frame-(this.numFrames)*this.looped;
			for(var layer,i=0;layer=this.layers[i++];) layer.setFrame(frame);
			this.dispatchEvent(new MotionEvent("onMotionUpdate"));
		}
	},
	private:{
		fitSize:function(target){
			var x1=target.getX();
			var y1=target.getY();
			var w=target.getWidth();
			var h=target.getHeight();
			var x2=x1+w;
			var y2=y1+h;
			if(this.left==null||x1<this.left) this.left=x1;
			if(this.right==null||x2>this.right) this.right=x2;
			if(this.top==null||y1<this.top) this.top=y1;
			if(this.bottom==null||y2>this.bottom) this.bottom=y2;
			this.width=this.right-this.left;
			this.height=this.bottom-this.top;
			this.scaleX=this.scaleY=1;
		}
	}
});


// ================================== Displayable Components ==============================

Class({
	public:{
		ValueConstraint:function(func,errorId){
			if(func instanceof ValueConstraint) return func;
			this.constraints=[];
			if(func){
				if(typeof(func)=="function"){
					this.addRule(func,errorId);
				}
				else if(typeof(func)=="number") $(this).setMask(func);
			}
		},
		static__DATE_EU:1,
		static__DATE_USA:2,
		static__DATE_ISO:3,
		static__DATETIME_EU:4,
		static__DATETIME_USA:5,
		static__DATETIME_ISO:6,
		static__TIME:7,
		static__INT:8,
		static__DECIMAL:9,
		static__STRING:10,
		static__EMAIL:11,
		static__NAME:12,
		static__FORM_CHECK:13,
		static__TEL_NUMBER:14,
		addRule:function(func,errorId){
			this.constraints.push({
				rule:func,
				errorId:errorId
			});
		},
		notpass:function(value){
			var length=this.constraints.length;
			for(var i=0;i<length;i++){
				var constraint=this.constraints[i];
				if(!constraint.rule(value)) return constraint;
			}
			return false;
		}
	},
	private:{
		setMask:function(type){
			switch(type){
				case ValueConstraint.DATE_EU:
					this.addRule(function(value){
						return /\d{2}[\/-]\d{2}[\/-]\d{4}/.test(value);
					},1);
					this.addRule(function(value){
						return /^(0[1-9]|[12][0-9]|3[01])/.test(value);
					},2);
					this.addRule(function(value){
						return /[\/-](0[1-9]|1[0-2])[\/-]/.test(value);
					},3);
					break;
				case ValueConstraint.DATE_USA:
					this.addRule(function(value){
						return /\d{2}[\/-]\d{2}[\/-]\d{4}/.test(value);
					},1);
					this.addRule(function(value){
						return /[\/-](0[1-9]|[12][0-9]|3[01])[\/-]/.test(value);
					},3);
					this.addRule(function(value){
						return /^(0[1-9]|1[0-2])/.test(value);
					},2);
					break;
				case ValueConstraint.DATE_ISO:
					this.addRule(function(value){
						return /\d{4}[\/-]\d{2}[\/-]\d{2}/.test(value);
					},1);
					this.addRule(function(value){
						return /(0[1-9]|[12][0-9]|3[01])$/.test(value);
					},2);
					this.addRule(function(value){
						return /[\/-](0[1-9]|1[0-2])[\/-]/.test(value);
					},3);
					break;
				case ValueConstraint.DATETIME_EU:
					this.addRule(function(value){
						return /\d{2}[\/-]\d{2}[\/-]\d{4}\s\d{2}:\d{2}(:\d{2})*(Z|\+\d{2})*/.test(value);
					},1);
					this.addRule(function(value){
						return /^(0[1-9]|[12][0-9]|3[01])/.test(value);
					},2);
					this.addRule(function(value){
						return /[\/-](0[1-9]|1[0-2])[\/-]/.test(value);
					},3);
					this.addRule(function(value){
						return /\s[0-5][0-9]:/.test(value);
					},4);
					this.addRule(function(value){
						return /:[0-5][0-9]:*/.test(value);
					},5);
					this.addRule(function(value){
						return /:[0-5][0-9](Z|\+\d{2})*$/.test(value);
					},6);
					break;
				case ValueConstraint.DATETIME_USA:
					this.addRule(function(value){
						return /\d{2}[\/-]\d{2}[\/-]\d{4}\s\d{2}:\d{2}(:\d{2})*(Z|\+\d{2})*/.test(value);
					},1);
					this.addRule(function(value){
						return /[\/-](0[1-9]|[12][0-9]|3[01])[\/-]/.test(value);
					},3);
					this.addRule(function(value){
						return /^(0[1-9]|1[0-2])/.test(value);
					},2);
					this.addRule(function(value){
						return /\s[0-5][0-9]:/.test(value);
					},4);
					this.addRule(function(value){
						return /:[0-5][0-9]:*/.test(value);
					},5);
					this.addRule(function(value){
						return /:[0-5][0-9](Z|\+\d{2})*$/.test(value);
					},6);
					break;
				case ValueConstraint.DATETIME_ISO:
					this.addRule(function(value){
						return /\d{4}[\/-]\d{2}[\/-]\d{2}\s\d{2}:\d{2}(:\d{2})*(Z|\+\d{2})*/.test(value);
					},1);
					this.addRule(function(value){
						return /[\/-](0[1-9]|[12][0-9]|3[01])\s/.test(value);
					},2);
					this.addRule(function(value){
						return /[\/-](0[1-9]|1[0-2])[\/-]/.test(value);
					},3);
					this.addRule(function(value){
						return /\s[0-5][0-9]:/.test(value);
					},4);
					this.addRule(function(value){
						return /:[0-5][0-9]:*/.test(value);
					},5);
					this.addRule(function(value){
						return /:[0-5][0-9](Z|\+\d{2})*$/.test(value);
					},6);
					break;
				case ValueConstraint.TIME:
					this.addRule(function(value){
						return /\d{2}:\d{2}(:\d{2})*(Z|\+\d{2})*/.test(value);
					},1);
					this.addRule(function(value){
						return /\s[0-5][0-9]:/.test(value);
					},4);
					this.addRule(function(value){
						return /:[0-5][0-9]:*/.test(value);
					},5);
					this.addRule(function(value){
						return /:[0-5][0-9](\+\d{2})*$/.test(value);
					},6);
					break
				case ValueConstraint.INT:
					this.addRule(function(value){
						return value.replace(/\d+/,"").length==0&&/\d+/.test(value);
					},1);
					break
				case ValueConstraint.DECIMAL:
					this.addRule(function(value){
						return value.replace(/\d*(\.\d+){0,1}/,"").length==0&&/\d*(\.\d+){0,1}/.test(value);
					},1);
					break
				case ValueConstraint.STRING:
					this.addRule(function(value){
						return value.replace(/[A-z]+/,"").length==0&&/[A-z]+/.test(value);
					},1);
					break
				case ValueConstraint.EMAIL:
					this.addRule(function(value){
						return value.replace(/[\w\.\+-]+@\w+(\.[a-zA-Z0-9]{2,})+/,"").length==0&&/[\w\.\+-]+@\w+(\.[a-zA-Z0-9]{2,})+/.test(value);
					},1);
					break;
				case ValueConstraint.NAME:
					this.addRule(function(value){
						return value.replace(/[A-z'\s]+/,"").length==0&&/[A-z'\s]+/.test(value);
					},1);
					break;
				case ValueConstraint.FORM_CHECK:
					this.addRule(function(form){
						var length=form.components.length;
						for(var i=0;i<length;i++){
							if(!form.components[i].isReady()) return true;
						}
						return false;
					},1);
					break;
				case ValueConstraint.TEL_NUMBER:
					this.addRule(function(value){
						return value.replace(/[\d+-:_\s\.\\\/\|]+/,"").length==0&&/[\d+-:_\s\.\\\/\|]+/.test(value);
					},1);
					break;
				default: break;
			}
		}
	}

})

Interface("LayoutManager",{
	public:{
		addComponent:null,
		removeComponent:null,
		layoutContainer:null
	}
});

Class({
	Implements: [LayoutManager],
	public:{
		GridLayout:function(rows,cols,hgap,vgap){
			$(this).rows=rows;
			$(this).cols=cols;
			$(this).hgap=hgap||0;
			$(this).vgap=vgap||0;
			$(this).numComponents=0;
		},
		addComponent:function(component){
			if(!component||!$(this).container) return;
			$(this).container.html.appendChild(component.html);
			$(this).numComponents++;
		},
		removeComponent:function(component){
			if(!component||!$(this).container) return;
			$(this).container.html.removeChild(component.html);
			$(this).numComponents--;
		},
		layoutContainer:function(container){
			if(!container) return;
			$(this).container=container;
			var cnt=container.html;
			if($(this).rows){
				var w=100/$(this).rows;
				for(var i=$(this).rows;i--;) cnt.appendChild($html("<div style=\"flow:left; width:"+w+"% \"></div>"));
				return;
			}
			if($(this).cols){
				var h=100/$(this).rows;
				for(var i=$(this).rows;i--;) cnt.appendChild($html("<div style=\"flow:left; height:"+h+"% \"></div>"));
				return;
			}
		}
	},
	private:{
		addColumns:function(){
			var w=100/$(this).cols||1;
			var h=100/$(this).rows||1
			for(var i=$(this).rows;i--;) cnt.appendChild($html("<div style=\"flow:left; width:"+w+"%; height:"+h+"%; \"></div>"));
		},
		addRow:function(){
			var h=100/$(this).cols;
			for(var i=$(this).cols;i--;) cnt.appendChild($html("<div style=\"flow:left; height:"+h+"% \"></div>"));
		}
	}
})

AbstractClass({
	public:{
		Component:function(tagName,attributes){
			this.components=[];
			var attributes=attributes||{};
			if($classname(attributes)=="Element") this.html=attributes;
			else{
				var id=($isObject(attributes))?attributes.id:attributes;
				if(id) this.html=$id(id);
				this.html=this.html||$html(tagName,attributes);	
			}
			if(!this.html) return null;
			$(this).ready=true;
		},
		addComponent:function(component,append){
			if(append) this.html.appendChild(component.html);
			this.components.push(component);
		},
		append:function(component){
			this.html.appendChild(component.html);
		},
		removeComponent:function(component){
			this.html.remove(component.html,true);
			return this.component.remove(component);
		},
		removeAll:function(){
			var length=this.components.length;
			var dom=this.html;
			for(var i=length;i;){
				var child=this.components[--i].html;
				dom.remove(child,true);
			}
			this.components=[];
		},
		isReady:function(){
			var priv=$(this);
			return priv.optional||priv.ready&&!this.isEmpty();
		},
		setReady:function(ready){
			$(this).ready=ready;
		},
		isOptional:function(){
			return $(this).optional;
		},
		setOptional:function(optional){
			$(this).optional=optional;
		},
		onReady:function(func,scope){
			if(typeof(func)=="function"){
				var target=this;
				scope=scope||this;
				$(this).readyFunction=function(evt){
					evt.type="ready";
					return func.call(scope,new Event(evt,target,func));
				}
			}
		},
		onUnready:function(func,scope){
			if(typeof(func)=="function"){
				var target=this;
				scope=scope||this;
				$(this).unreadyFunction=function(evt){
					evt.type="unready";
					return func.call(scope,new Event(evt,target,func));
				}
			}
		},
		setReadyStyle:function(style){
			$(this).readyStyle=style;
			this.setDefaultStyle(this.html.getCss());
			if(this.isReady()) this.html.setStyle(style);
		},
		setUnreadyStyle:function(style){
			$(this).unreadyStyle=style;
			if(!this.isReady()) this.html.setStyle(style);
		},
		setDefaultStyle:function(style){
			$(this).defaultStyle=style;
		},
		getReadyStyle:function(style){
			return $(this).readyStyle;
		},
		getUnreadyStyle:function(style){
			return $(this).unreadyStyle;
		},
		getDefaultStyle:function(){
			return $(this).defaultStyle;
		},
		applyConstraint:function(evt,model){
			var priv=$(this);
			var rule=model.notpass(this.getContent());
			if(!rule){
				evt.errorId="no errors";
				priv.ready=true;
				this.html.setStyle(priv.readyStyle);
				priv.readyFunction(evt);
				return true;
			}
			else{
				evt.errorId=rule.errorId;
				priv.ready=false;
				this.html.setStyle(priv.unreadyStyle);
				priv.unreadyFunction(evt);
				return false;
			}
		},
		abstract__getContent:null,
		abstract__isEmpty:null,
		abstract__addConstraint:null,
		abstract__removeConstraint:null
	},
	private:{
		readyFunction:function(){},
		unreadyFunction:function(){}
	}
})



Class({
	Extends:Component,
	public:{
		TextField:function(attributes,model,optional){
			$(this).Super("input",attributes);
			this.html.type="text";
			this.setOptional(optional);
			if(model) this.addConstraint(model);
		},
		addConstraint:function(model){
			model=new ValueConstraint(model);
			$(this).handler=this.html.onUpdate(function(evt){
				this.applyConstraint(evt,model);
			},this);
			this.applyConstraint({},model);
		},
		removeConstraint:function(){
			//log($(this).handler);
			if($(this).handler) $(this).handler.clear();
			this.setReadgetY(true);
			//log(this.getDefaultStyle());
			this.html.setStyle(this.getDefaultStyle());
		},
		reset:function(){
			this.html.setContent();
		},
		getContent:function(){
			return this.html.value;
		},
		setColor:function(color){
			this.html.setColor(color);
		},
		isEmpty:function(){
			return this.html.value.length==0;
		}
	}
})

Class({
	Extends:Component,
	public:{
		ImageButton:function(normal,pressed,overed){
			$(this).Super("input",{
				type:"image",
				value:"",
				src:normal||"",
				onmouseover:"this.src="+(overed||""),
				onmousedown:"this.src="+(pressed||""),
				onmouseup:"this.src="+(normal||"")
			});
			//log(this.html);
		},
		getContent:function(){},
		isEmpty:function(){},
		addConstraint:function(){},
		removeConstraint:function(){}
	}
})

Class({
	Extends:Component,
	
	public:{
		Form:function(attributes){
			$(this).Super("form",attributes);
			model=ValueConstraint.FORM_CHECK;
			this.addConstraint(model);
		},
		populate:function(optional){
			this.removeAll();
			this.allComponents=new HtmlList(this.html.elements);
			var elms=this.allComponents.sift({type:"text"});
			var length=elms.size();
			for(var i=0;i<length;i++){
				var elm=elms.get(i);
				this.attach(new TextField($$(elm),optional));
			}
		},
		attach:function(component,optional){
			optional=optional||true;
			component.setOptional(optional);
			this.addComponent(component);
		},
		add:function(component,optional){
			this.attach(component,optional);
			this.append(component);
		},
		resetUnreadyField:function(){
			this.components.foreach(function(elm,i,array){
				if(!elm.isReady()) elm.reset();
			});
		},
		setField:function(index,optional,model,readyStyle,unreadyStyle){
			this.components[index].addConstraint(model);
			this.components[index].setOptional(optional);
			this.components[index].setReadyStyle(readyStyle);
			this.components[index].setUnreadyStyle(unreadyStyle);
		},
		setFields:function(optional,model,readyStyle,unreadyStyle){
			this.components.foreach(function(elm,i,array){
				elm.addConstraint(model);
				elm.setOptional(optional);
				elm.setReadyStyle(readyStyle);
				elm.setUnreadyStyle(unreadyStyle);
			});
		},
		setReadyStyle:function(style){
			this.components.foreach(function(elm,i,array){
				elm.setReadyStyle(style);
			});
		},
		setUnreadyStyle:function(style){
			this.components.foreach(function(elm,i,array){
				elm.setUnreadyStyle(style);
			});
		},
		getQueryObject:function(){
			var o={};
			this.allComponents.foreach(function(elm,i,array){
				o[elm.getAttribute("name")]=$$(elm).getContent();
			});
			return new QueryObject(o);
		},
		setHttpRequest:function(httpReq){
			$(this).httpRequest=httpReq;
		},
		submit:function(resetUnready, async){
			if(resetUnready) this.resetUnreadyField();
			if(!this.applyConstraint({},$(this).currentModel)){
				if(!async) this.html.submit();
				else{
					if($(this).httpRequest){
						$(this).httpRequest.send(this.getQueryObject());
						return true;
					}
				}
				return true;
			}
			return false;
		},
		addConstraint:function(model){
			$(this).currentModel=new ValueConstraint(model);
			$(this).handler=this.html.onSubmit(function(evt){
				if(!this.applyConstraint(evt,model)) return evt.preventDefault();
			},this);
		},
		removeConstraint:function(){
			if($(this).handler) $(this).handler.clear();
			this.setReadgetY(true);
		},
		isEmpty:function(){
			return this.components.length==0;
		},
		getContent:function(){
			return this;	
		}
	}
})

Class({
	Extends: Form,
	public:{
		AJAXForm:function(attributes, httpreq){
			$(this).Super(attributes);
			
		}
	}
});

Class({

	public:{
		Menu:function(){
		},
		addItem:function(menuItem){
		},
		removeItem:function(menuItem){
		}
	}

})


Class({
	
	public:{
		MenuItem:function(){
		}
	}
	
})

