/* elementary.js 
 * cross browser api for easing javascript development
 * see http://benipsen.com/elementary/
*/


/*  
	WriteForm is an object that writes forms to the page. 
	This is an effective method for spam protection since robots don't see the input objects on the page untill the link is clicked. 
*/
var WriteForm = {
				up:false,
				fields:false,
				submitValue:"Send",
				write:function(layer){
					if(WriteForm.up) return;
					if(!WriteForm.fields) return;
					var wrap = new Element(layer);		
					for(var f = 0; f < WriteForm.fields.length; f++){						
						var notempty = WriteForm.fields[f].notempty ? 'notempty="'+WriteForm.fields[f].notempty + '" ' : "";
						if(WriteForm.fields[f].type == "text")
							var fw = wrap.append('p', '<label>' + WriteForm.fields[f].label + '</label><input type="text" '+notempty+' name="'+WriteForm.fields[f].name+'" />', 'class="fieldwrap"');
						else
							var fw = wrap.append('p', '<label>' + WriteForm.fields[f].label + '</label><textarea '+notempty+' name="' + WriteForm.fields[f].name + '" rows="5"></textarea>', 'class="fieldwrap"');
					}	
					var fw = wrap.append('p', '<input type="submit" value="'+WriteForm.submitValue+'">', 'class="submit"');
					wrap.show("block");									
					wrap.getChildren("input")[0].focus();
					WriteForm.up = true;

				}				
			}


var Signup = {
		onData:function(data){
			var a = new Animation("signupmsg", {alpha:99.9});
			if(document.getElementById("signup")) document.getElementById("signup").style.display = 'none';
			document.getElementById("signupmsg").style.display = 'block';
			document.getElementById("signupmsg").innerHTML = "<p><strong>Thanks for signing up!</strong></p>";
			window.setTimeout(Signup.fadeout, 4000);
		},
		validate:function(_form){	
			
			var valid_email = /^.+\@.+\..+$/
			var btn = document.getElementById("signupbtn");
			if(_form.email.value.toString().match(valid_email)) {
				btn.disabled = false;
				btn.style.color = "#000";
			}else{
				btn.disabled = true;
				btn.style.color = "#CCC";
			}
		},
		send:function(_form){
			
			var obj = '{"mail":"'+_form.email.value+'"}';
			RemoteCall.handlers = Signup;
			RemoteCall.make("contacts","subscribe", obj);
			return false;
		},
		fadeout:function(){
			var a = new Animation("signupmsg", {alpha:99.9});				
				a.effect({alpha:0.01, duration:0.3, fps:1/50, trans:physics.easeOut}, function(){
																							a.element.hide('none');	   																				   	
																					   });
		}
}

function addWindowEventListener(eventName, callback, bubble){
	if(window.addEventListener){          
		window.addEventListener(eventName, callback, bubble);
	} else {
		document.attachEvent('on' + eventName, callback);
	}                                                  
}

function addPageLoadListener(listener){
	if (window.addEventListener) {
		window.addEventListener('load',listener,false);	
	} else if (document.addEventListener) {
		document.addEventListener('load',listener,false);
	} else if (window.attachEvent) {
		window.attachEvent('onload',listener);
	} else {
		if (typeof window.onload=='function') {
				var previously = window.onload;
				window.onload=function(){
					previously.call();
					listener.call();
				}
		} else { 
			window.onload = listener;
		}
	}	
}
/** effects wrapper. makes calls like Effect.FadeOut(element) possible using powerful animation engine */
var Effect = {
	fadeOut:function(element, options, after, args){
		
	}	
}



function dollar(num) {
		num = num.toString().replace(/\$|\,/g,'');
		if(isNaN(num))
		num = "0";
		sign = (num == (num = Math.abs(num)));
		num = Math.floor(num*100+0.50000000001);
		cents = num%100;
		num = Math.floor(num/100).toString();
		if(cents<10)
		cents = "0" + cents;
		for (var i = 0; i < Math.floor((num.length-(1+i))/3); i++)
		num = num.substring(0,num.length-(4*i+3))+','+
		num.substring(num.length-(4*i+3));
		return (((sign)?'':'-') + num + '.' + cents);
	}
	

var Toggled = null;
function ToggleLayer(layer){
	Toggled = new Element(layer);
	if(Toggled.element.style.display == "block"){
		var lay = new Animation(Toggled.element.id, {alpha:100});			
		lay.effect({alpha:0.01, duration:0.2, fps:1/50, trans:physics.easeOut}, function(){
				Toggled.hide('none');
		});
	}else{		
		var lay = new Animation(Toggled.element.id, {alpha:0.01});
		Toggled.show('block');				
		lay.effect({alpha:99.9, duration:0.2, fps:1/50, trans:physics.easeOut});
	}
}

var Valid = function(frm){
	var match = "";
	var password = "";	
	for(var e = 0; e < frm.elements.length; e++){
		if(frm.elements[e].getAttribute("notempty") && frm.elements[e].value == ""){
			var name = frm.elements[e].getAttribute("name");
				name = name.replace(/_/g,' ');
				name = name.replace(/\[|\]/g,' ');
			var notify = frm.elements[e].getAttribute("notempty") == "true" ? name + " is required." :  frm.elements[e].getAttribute("notempty") + " is required.";
			var id = "error_" + frm.elements[e].getAttribute("name"); 
			var msg = document.createElement("p");
				 msg.className = "error";
				 msg.innerHTML = notify;
				 msg.setAttribute('id', id)
			
			if(!document.getElementById(id))	
				frm.elements[e].parentNode.insertBefore(msg, frm.elements[e].previousSibling);
			frm.elements[e].focus();
			return false;
		}else if(frm.elements[e].getAttribute("valid-email")){
			
			var valid = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
			if (!frm.elements[e].value.match(valid)) {				
				var name = frm.elements[e].getAttribute("name");
					name = name.replace(/_/g,' ');
					name = name.replace(/\[|\]/g,' ');
				var notify = frm.elements[e].getAttribute("valid-email") == "true" ? name + " must be a vaild email address." :  frm.elements[e].getAttribute("valid-email") + " must be a vaild email address.";
				var id = "error_" + frm.elements[e].getAttribute("name"); 
				var msg = document.createElement("p");
					 msg.className = "error";
					 msg.innerHTML = notify;
					 msg.setAttribute('id', id)

				if(!document.getElementById(id))	
					frm.elements[e].parentNode.insertBefore(msg, frm.elements[e].previousSibling);
				frm.elements[e].focus();
				return false;
			}
			
		}else if(frm.elements[e].getAttribute("type") == "password"){
			if(!match){
				match = frm.elements[e].value;
				password = frm.elements[e];
			}else{
				if(frm.elements[e].value != match){
					var id = "matching_error";
					var msg = document.createElement("p");
						msg.className = "error";
						msg.innerHTML = "Your passwords do not match. Please re-enter";
						msg.setAttribute('id',id);
					
					if(!document.getElementById(id))	
						password.parentNode.appendChild(msg, frm.elements[e]);		
					password.focus();
					password.select();
					return false;
				}
			}
		} else {
			var id = "error_" + frm.elements[e].getAttribute("name"); 
			if(document.getElementById(id)) document.getElementById(id).parentNode.removeChild(document.getElementById(id)); 
		}
	}
	return true;
}


/** remote call wraper a call to the controler method or "action", and returns the resulting object **/
var RemoteCall = {
	handlers:null,
	make:function(controller, action, object, string){
		if(!string) string = true;
		var req = new Request(RemoteCall.handlers, string);
			req.send(WEB_HOME + "/remotecall/?name="+controller+"&action="+action+"&obj=" + object);
	}
}

/** allows for editable block elements, id attribute must be present to work correctly. **/
var TextEditor = {
	elements:false,
	control:false,
	action:false,
	active:false,
	appended:false,
	original_value:false,
	make:function(element, control, action, field, appended){
		if(!TextEditor.elements){
			TextEditor.elements = new Array();
			TextEditor.field = field;
			TextEditor.appended = appended;
			//addWindowEventListener('mouseup',TextEditor.cancel)
		} 
		var obj = new Element(element, { onclick:TextEditor.click, onrollover:TextEditor.over, onrollout:TextEditor.out});
		TextEditor.elements.push(obj); 
		this.control = control;
		this.action = action;
		
	},
	click:function(e){
		TextEditor.cancel();
		var inst = TextEditor.getinstance(this);
		var cont = inst.getContent();
			inst.setContent("");
			var field = inst.append("input",false,'type="text" value="'+cont+'"');
			inst.append("input",false,'type="button" class="button" value="save" onclick="TextEditor.save(this)"');
			inst.append("input",false,'type="button" class="button" value="cancel" onclick="TextEditor.cancel(this)"');
			inst.append("br",false,'style="clear:both;"');		
		TextEditor.active = inst;
		TextEditor.original_value = field.value;
		field.focus(); field.select();			
	},
	over:function(e){
		this.style.backgroundColor = "#EEEEEE";
		this.style.cursor = "pointer";
	},
	out:function(e){
		this.style.backgroundColor = "#FFF";
	},
	getinstance:function(source){
		for(var e = 0; e < TextEditor.elements.length; e++){
			if(TextEditor.elements[e].id == source.getAttribute("id"))
				return TextEditor.elements[e];
		}
	},
	cancel:function(){
		if(TextEditor.active){
			var value = TextEditor.active.element.firstChild.value;
			TextEditor.active.setStyleProperty('backgroundColor','#FFF');			
			TextEditor.active.setContent(TextEditor.original_value);
			TextEditor.active = null;
		}
	},
	onData:function(result){
		if(result.okay){
			TextEditor.active.setStyleProperty('backgroundColor','#FFF');			
			TextEditor.active.setContent(result.saved.name);
			TextEditor.active = null;
		}
	},
	save:function(){
		if(TextEditor.active){
			var id = TextEditor.active.element.id;
			if(TextEditor.appended){
				id = id.substring(0, id.indexOf(TextEditor.appended));
			}
			
			var value = TextEditor.active.element.firstChild.value;
			var save = '{"id":"'+id+'","'+TextEditor.field+'":"'+value+'"}';
			
			RemoteCall.handlers = TextEditor;
			RemoteCall.make(TextEditor.control, TextEditor.action, save);
			
			TextEditor.active.setContent("Saving...");
			
		}
	},
	revert:function(){
		
	}	
}


/** assign observer objects to keypress events.. **/
var KeyEventObservers = {
	list:null,
	add:function(key, handler){ 
		if(KeyEventObservers.list == null){
			 KeyEventObservers.list = new Object();
			 addWindowEventListener('keydown',KeyEventObservers.onkeydown, false);
			 addWindowEventListener('keyup',KeyEventObservers.onkeyup, false);
		}
		if(!KeyEventObservers.list[key]) KeyEventObservers.list[key] = new Array();
		KeyEventObservers.list[key].push(handler);			
	},
	onkeydown:function(e){
		if( ! KeyEventObservers.list[KeyMap.lookup(e.keyCode)]) return true;
		var observers = KeyEventObservers.list[KeyMap.lookup(e.keyCode)];
	    for(var o = 0; o < observers.length; o++){
			if(observers[o].down) observers[o].down(e);
		}
		return true;
	},
   	onkeyup:function(e){ 
		if( ! KeyEventObservers.list[KeyMap.lookup(e.keyCode)]) return true;
		var observers = KeyEventObservers.list[KeyMap.lookup(e.keyCode)];
	    for(var o = 0; o < observers.length; o++){
			if(observers[o].up) observers[o].up(e);
		}
		return true;
	}
}

var KeyMap = {
	names:['shift','ctl','up','down','left','right','enter'],
	//note: safari shift, ctl, and alt don't fire events!
	safari:[16,17,38,40,37,39,13],
	moz:[16,17,38,40,37,39,13],
	ie:[16,17,38,40,37,39,13],
	mac:[16,224,38,40,37,39,13],
	lookup:function(test){	
		var code = internet_explorer ? KeyMap.ie : KeyMap.moz;
		if(macintosh) code = KeyMap.mac;
		if(safari) code = KeyMap.safari;
		for(var i = 0; i < code.length; i++){
			if(code[i] == test)
				return KeyMap.names[i];
		}
		return "all";
	}
}

var Window = {
	construct:function(){
		
  	   //without scrolling...
	  if( typeof( window.innerWidth ) == 'number' ) {
		//moz, opera
		this.width = window.innerWidth;
		this.height = window.innerHeight;
	  } else if( document.documentElement &&
		( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
		//ie
		this.width = document.documentElement.clientWidth;
		this.height = document.documentElement.clientHeight;
	  }
	
	  //with scrolling..
	  if( document.body ) {
		//dom
			this.scrollheight = document.body.scrollHeight;
			this.scrollwidth = document.body.scrollWidth;
	   } else if(document.documentElement && document.documentElement.scrollHeight){
	    //ie
	   		this.scrollheight =  document.documentElement.scrollHeight;
			this.scrollwidth =  document.documentElement.scrollWidth;
		
	  } 
	  
	  //srolling offset
	  if (window.innerHeight){
	 	  	this.scrolledy = window.pageYOffset;
			this.scrolledx = window.pageXOffset;
	  } else if (document.documentElement && document.documentElement.scrollTop) {
			this.scrolledy = document.documentElement.scrollTop;
			this.scrolledx = document.documentElement.scrollLeft;
	  }else if (document.body){
		  this.scrolledy = document.body.scrollTop;
		  this.scrolledy = document.body.scrollLeft;
	  }	
	}
}
Window.construct();
addWindowEventListener("resize",Window.construct);
//dependencies - "not so clean" code, this is old and should all be replaced but it works- well.  

var internet_explorer = navigator.appName.indexOf("xplorer") > 0;
var macintosh = navigator.platform.indexOf("Mac") >= 0;
var safari = navigator.appVersion.indexOf("fari") > 0;


function Request(handlers, evaluate){
  this.onData = handlers.onData;
  this.onError = handlers.onError ? handlers.onError : false;
  this.onLoading = handlers.onLoading ? handlers.onLoading : false;
  this.evaluate = evaluate;
  this.lastRequest = ""; 
  var xmlhttp=false;
  var This = this;
  try { 
  	xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
 	} catch (e) {
 		 try {
  	 		xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  		  } catch (E) {
   			xmlhttp = false;
  		 }
 	}
   if (!xmlhttp && typeof XMLHttpRequest!='undefined') {
  		xmlhttp = new XMLHttpRequest();
    }
   this.stateChange = function( ){
		if ( xmlhttp.readyState == 4) {
        	if (xmlhttp.status == 200) {
		    	var response = (xmlhttp.responseText) ? xmlhttp.responseText : ""; 
				if(This.evaluate){
					var result;
					var str = 'result = ' + response + ';';
					try{
						eval(str);
					}catch(e){
						alert("Request Runtime error: " + e+ "\nReturned Response:\n\n" + response);
					}
					response = result;					
				}
				This.onData(response, This);
       		} else {
            	var e = xmlhttp.statusText + "status: " + xmlhttp.status;
				if(This.onError) This.onError(e, This);
        	}
	   }
   } 
   this.send = function( url, requestHeaders ) {
	  if(xmlhttp){		
	    	if(This.onLoading) This.onLoading();
  			xmlhttp.open("POST", url , true);
			xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
 			xmlhttp.onreadystatechange = This.stateChange;
			This.lastRequest = url;
			xmlhttp.send(null);
	   }else{
		   if(This.onError) This.onError("Sorry, your browser does not support remote requests.");
	   }
   }
}
function Element(id, io){	
	var This = this;
	if(typeof(id) == 'string'){
		if(!document.getElementById(id)){
			//alert("Can't find element with id: " + id);
			This.element = false;
		}
		This.element = document.getElementById(id);
		This.id = id;	
	}else{
		This.element = id;
		try{		
			This.id = This.element.getAttribute('id');
		}catch(e){
			This.id = null;
		}
	}
	if(!io) io = {};
	var units = io.units ? io.units : 'px';
	this.x = io.x ? io.x : false;
	this.y = io.y ? io.y : false; 
	this.width = io.width ? io.width : false; 
	this.height = io.height ? io.height : false; 
	this.alpha = (io.alpha != undefined) ? io.alpha : false;
	this.center = (io.center) ? io.center : false;
	this.contentElement = false;
	if(io.contentElement)  
		this.contentElement = document.getElementById(io.contentElement); 	
	this.setDimensions = function(w,h){
		if(isNum(w)) { this.element.style.width = (w + units); this.width = w;   }
		if(isNum(h)) { this.element.style.height = (h + units); this.height = h; }
		if(This.center){
			var cx = (This.width-w) * This.center.x;
			var cy = (This.height-h) * This.center.y;
			This.setPosition( This.x + cx, This.y + cy);
		}
	}
	this.setPosition = function(x,y){
	  if(isNum(y)) { this.element.style.top = y + units;  this.y = y;   }
	  if(isNum(x)) { this.element.style.left = x + units; this.x = x;  }
	  //if(this.center) this.setDimenions(this.width, this.height);
	}
	this.setOpacity = function(a){ 
		if(isNum(a)){
			this.element.style.opacity = (a/100);		
			this.element.style.filter = "Alpha(Opacity=" + a + ")";  
			this.alpha = a;
		}
	}	
	this.setStyleProperty = function(property, value){
		eval("this.element.style." + property + "=\"" + value + "\"");
	}
	this.setClass = function(name){
		this.element.className = name;	
	}
	this.addClass = function(name){
		if(this.element.className.toString().indexOf(name) < 0)
			this.element.className = this.element.className + " " + name;
	}
	this.removeClass = function(name){
		var cc = this.element.className.toString();
		var e = cc.substring(0,cc.indexOf(name));
		var b = cc.substring(cc.indexOf(name) + name.length, cc.length);
		this.element.className = b + " " + e;
	}	
	this.hide = function(disp){
		this.element.style.visibility = 'hidden';
		if(disp) this.element.style.display = disp;
	}	
	this.show = function(disp){
		this.element.style.visibility = 'visible';
		if(disp) this.element.style.display = disp;
	}	
	this.getRealHeight = function(){
		return this.element.offsetHeight;
	}
	this.getRealWidth = function(){
		return this.element.offsetWidth;
	}
	this.getRealTop = function(){
		if(internet_explorer){
			var top = 0;
	   	 	var obj = This.element;
				if (obj.offsetParent)
				{
					while (obj.offsetParent)
					{
						if(obj.offsetParent.getAttribute("id")) top += obj.offsetTop
						obj = obj.offsetParent;
					}
				}
				else if (obj.y)
					top += obj.y;
			return top;
		}else{
			return this.element.offsetTop;
		}  
	}
	this.getRealLeft = function(){
		if(this.ie){
			var left = 0;
			var obj = this.element;
				if (obj.parentNode)
				{
					while (obj.parentNode)
					{
						if(obj.offsetParent.getAttribute("id")) left += obj.parentNode.offsetLeft
						obj = obj.parentNode;
					}
				}
				else if (obj.x)
					left += obj.x;
			return left; 
		} else {
			return this.element.offsetLeft;
		}     
	}
	this.getRelativeTop = function(){
		var top = 0;
   	 	var obj = This.element;
			if (obj.offsetParent)
			{
				while (obj.offsetParent)
				{
					top += obj.offsetTop
					obj = obj.offsetParent;
				}
			}
			else if (obj.y)
				top += obj.y;
		return top;
	}
	this.getRelativeLeft = function(){	
		var left = 0;
		var obj = this.element;
			if (obj.offsetParent)
			{
				while (obj.offsetParent)
				{
					left += obj.offsetLeft
					obj = obj.offsetParent;
				}
			}
			else if (obj.x)
				left += obj.x;
		return left; 	  
	}
	this.getTop = function(){
		return this.element.offsetTop;
	}
	this.getLeft = function(){
		return this.element.offsetLeft;
	}
	this.getContent = function(cont){
		if(this.contentElement) return this.contentElement.innerHTML;
		return this.element.innerHTML;	
	}
	this.setContent = function(cont){
		if(this.contentElement) this.contentElement.innerHTML = cont;
		else this.element.innerHTML = cont;	
	}
	this.insertContent = function(cont, pos){
		var bCont = this.getContent();
		if(pos=='before') this.setContent(cont + bCont);
		else this.setContent(bCont + cont);
	}
	this.getChildren = function(tag){
		if(this.element)
			return this.element.getElementsByTagName(tag);
		else
			return new Array();
	}
	this.append = function(type, content, attributes){
		var ne;	
		if(!internet_explorer){ 
			ne = document.createElement(type);
			if(attributes){
				var atts = attributes.split('" ');
				for(var a=0; a < atts.length; a++){
					var data = atts[a].split('="');
					var value = data[1].indexOf('"') > 0 ? data[1].substring(0,data[1].length-1) : data[1];
					ne.setAttribute(data[0], value);
				}
			}
		}else{
			var make = '<' + type + ' ' + attributes + '>';
			ne = document.createElement(make);
		}
		if(content) ne.innerHTML = content;	
		this.element.appendChild(ne);
		return ne;
	}
	this.prepend = function(type, content){
			var ne = document.createElement(type);   
		    this.element.insertBefore(ne, This.element.firstChild); 
			if(content) ne.innerHTML = content; 
			return ne;
	}
	this.remove = function(node){
		this.element.removeChild(node);
	}
	this.insert = function(node, before){
		this.element.insertBefore(node, before);
	}
	this.setHandlers = function(io){   
		if(io.onclick) this.element.onclick = io.onclick;
		if(io.onrollover) this.element.onmouseover = io.onrollover;
		if(io.onrollout) this.element.onmouseout = io.onrollout;
		if(io.onpress) this.element.onmousedown = io.onpress;
		if(io.onrelease) this.element.onmouseup = io.onrelease;
		if(io.ondouble) this.element.ondblclick = io.ondouble;
		if(io.onmove) this.element.onmousemove = io.onmove;
	}	
	if(this.width || this.height)
		this.setDimensions(this.width, this.height);
	if(this.x || this.y)
		this.setPosition(this.x, this.y);
	if(this.alpha)
		this.setOpacity(this.alpha);
	if(io)
		this.setHandlers(io);
	function isNum(num){ if(num==0) return true; if(!num) return false; else return typeof(num) == 'number' };	
}
function Animation(el, io){
	var This = this;
	this.element = new Element(el, io);
	var next = function(){ };
	var args = false;  
	this.cancel = function(){ this.time.reset(); this.time.stop(); } 
	this.update = function() { 
		var t = This.trans( This.time.getTime() / This.dur );
		if(isNum(da)){
			var na  = oa + (t * da);
			This.element.setOpacity(na);
		}
		if(isNum(dx) || isNum(dy)){
			var nx  = ox + t * dx;  	     
			var ny  = oy + t * dy;
			This.element.setPosition(nx, ny);
		}
		if(isNum(dw) || isNum(dh)){
			var nw  =  ow + (t * dw);  	     
			var nh  =  oh + (t * dh);
			if(This.element.center){
				var cx = (This.element.width - nw) * This.element.center.x;
				var cy = (This.element.height - nh) * This.element.center.y;
				This.element.setPosition( This.element.x + cx, This.element.y + cy);
			}
			This.element.setDimensions(nw, nh);
		}
		if(observer) observer();
		if(t == 1){
			if(_effect.y && isNum(_effect.y)) This.element.element.style.top = _effect.y + 'px';
			if(_effect.x && isNum(_effect.x)) This.element.element.style.left = _effect.x + 'px';
			This.complete = true;
			try{ 
				 next(args);
				 next = new function(){};
			}catch(e){ }
		}
	}
	var _effect;
	var oa; var ox; var oy; var ow; var oh; 
	var da; var dx; var dy; var dw; var dh;
	this.effect = function(fect, after, afterArgs){
		if(This.complete){
			_effect = fect;
			if(fect.duration) This.dur = fect.duration;
			if(fect.fps) This.fps = fect.fps;
			if(fect.trans) This.trans = fect.trans;
			if(after) next = after;
			if(afterArgs) args = afterArgs;
			if(isNum(fect.alpha)){   oa = This.element.alpha;     da = fect.alpha - oa; }
			if(isNum(fect.width)){  ow = This.element.width;   dw = fect.width - ow;  }
			if(isNum(fect.height)){  oh = This.element.height;  dh = fect.height - oh; }
			if(isNum(fect.x)){	 ox = This.element.x;       dx = fect.x - ox;  }
			if(isNum(fect.y)){	  oy = This.element.y;	    dy = fect.y - oy; }
			This.complete = false;
			this.time.reset();
			this.time.start(This.dur, This.fps);  
		}
	}	
	var observer = false
	this.setUpdateObserver= function(obj){ observer = obj; }
	this.linear = function(x){ return x; }
	if(!io) io = { };
	this.time = new Timer(this.dur, this.fps, this.update);
	this.trans = (!io.trans) ? this.linear : io.trans;
	this.fps = (io.fps) ? io.fps : (1/24);
	this.dur = (io.duration) ? io.duration : 1;
	this.complete = true;
	function isNum(val) { 
		if(val==0) 
			return true; 
		else if(typeof(val) == 'number');
		 	return true;
		return false; }
}  
function Timer(duration, updateInterval, listener){
  	this.update = (updateInterval) ? updateInterval : (1/24);
	this.duration = (duration) ? duration : 1;
	this.listeners = new Array();
	if(listener) this.listeners.push(listener);
	var time = 0;  var timer = null;
	var self = this; var check;
	this.addListener = function(listenerObj){
		this.listeners.push(listenerObj);
	}	
	this.start = function(duration, interval){
		if(duration) this.duration = duration;
		if(interval) this.update = interval;
		check = this.update;
		run();
	}	
	this.stop = function(nocall){ 
		window.clearTimeout(timer);
		time = this.duration; 
		for(var l=0; l < self.listeners.length; l++)
			self.listeners[l].call(this, self); 		
	}							 
	this.getTime = function(){ return time; }
	this.reset = function() {  
		window.clearTimeout(timer); 
		time = 0; 
		check = 0; 
		timer = null; 
	}
    function run(){
		if(time <= self.duration){
			if(time >= check){
				for(var l=0; l < self.listeners.length; l++)
						self.listeners[l].call(this, self);
				check += self.update;	
			}
			time+= 0.01;			
			loop();
			return;	
		}
	  self.stop();
	}	
	function loop(){
		timer = window.setTimeout(run, 10);
	}
};
function Physics(){
	this.linear = function(x){ return x; }
	this.easeIn = function(x){ return Math.pow(x,2); }
	this.easeOut = function(x){ return 1 - Math.pow((x-1), 2); }
	this.sineWave = function(x){ return Math.sin(x*Math.PI/2); }
	this.spring = function(x){
		if(x < 0.65)
			return 1.1 * Math.sin(x * (Math.PI/1.5666) ); 
		else if(x < 1)
			return 1 + 0.1 * Math.sin(3.3 * (x +0.21) * Math.PI);	
		else
			return 1;		
	}	
	this.snap = function(x){ 
		if(x < 1)
			return 1.1 * Math.sin(x * (Math.PI/1.5666) );  
		else
			return 1;
	}
}
var physics = new Physics();

function EventInfo(e, cancel){
		if (!e) var e = window.event;			
		if (e.target) this.source = e.target;
		else if (e.srcElement) this.source = e.srcElement;
		if (this.source.nodeType == 3)
			this.source = this.source.parentNode;			
		if (e.pageX || e.pageY) {
			this.xmouse = e.pageX;
			this.ymouse = e.pageY;
		}
		else if (e.clientX || e.clientY) {
			this.xmouse = e.clientX + document.body.scrollLeft;
			this.ymouse = e.clientY + document.body.scrollTop;
		}		
		if(cancel){
			e.cancelBubble = true;
			if (e.stopPropagation) e.stopPropagation();
		}	
}