function Request(handlers){
 	
  //event handler functions 
  this.onData = handlers.onData;
  this.onError = handlers.onError ? handlers.onError : false;
  this.onLoading = handlers.onLoading ? handlers.onLoading : false;
  this.lastRequest = "";
  
  var xmlhttp=false;
  var This = this;
  
  //create xmlhttp object.. http://jibbering.com/2002/4/httprequest.htm
  try { //ie
  	xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
 	} catch (e) {
 		 try {
  	 		xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
  		  } catch (E) {
   			xmlhttp = false;
  		 }
 	}

   if (!xmlhttp && typeof XMLHttpRequest!='undefined') { //moz
  		xmlhttp = new XMLHttpRequest();
    }

   this.stateChange = function( ){
		if ( xmlhttp.readyState == 4) {
        	if (xmlhttp.status == 200) {
		    	var response = (xmlhttp.responseText) ? xmlhttp.responseText : "";
				This.onData(response, This);
       		} else {
            	var e = xmlhttp.statusText;
				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.");
	   }
   }
}
/**
/*  element.js
/*  This wrapper creates a programmer friendly, cross-browser API for setting common 
/*  element properties.
/*
/*  Ben Ipsen  2006. No Copyright. No license. Just Love. 
/*  Use wisely and for the greater good.  
/*
/*  docs: http://benipsen.com/elementary/
**/

function Element(id, io){	
	var This = this;
	
	//create element holder
	if(typeof(id) == 'string'){
		try{
			This.element = document.getElementById(id);
			This.id = id;
		}catch(e){
			alert("Problem initializing Element object with id: " + id + ". \n" + e);
		}
	}else{
		This.element = id;
		try{		
			This.id = This.element.getAttribute('id');
		}catch(e){
			This.id = null;
		}
	}
	
	if(!io) io = {};
	
	//private units
	var units = io.units ? io.units : 'px';
	
	//public properties, width, height, x, y..  etc.
	this.x = io.x ? io.x : false; //this.element.offsetLeft;  
	this.y = io.y ? io.y : false; //this.element.offsetTop;
	this.width = io.width ? io.width : false; 
	this.height = io.height ? io.height : false; 
	this.alpha = (io.alpha != undefined) ? io.alpha : 100;
	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.setDimentions(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(this.ie){
			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;
		}else{
			return this.element.offsetTop;
		}  
	}
	this.getRealLeft = function(){
		if(this.ie){
			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; 
		} else {
			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){
		return this.element.getElementsByTagName(tag);
	}
	this.append = function(type, content, attributes){
		var ne = document.createElement(type);	
		this.element.appendChild(ne);
		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){   
		
		//initialize handler events
		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;
	}	
	this.forceAbsolute = function(){
		var x = This.x; var y = This.y;
		var w = This.width; var h = This.height;
		This.element.style.position = 'absolute';
		This.setPosition(x,y);
		This.setDimensions(w, h);
	}	
	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);
	
	//private
	function isNum(num){ 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();

/**
/*  events.js
/*  Gets properties of any event and cancel bubble upon construction with optional param.
/*  Keys handles events trigged by user keyboard input
/*  addDOMEvent registers events with the document 

/*  Ben Ipsen  2005. No Copyright. No license. Just Love. 
/*  Use wisely and for the greater good.  
/*
/*  docs: http://benipsen.com/elementary/
**/

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


//register listeners for window/document events cross-browser
//register listeners cross browser
function addWindowEventListener(eventName, callback, bubble){
	if(window.addEventListener){          
		window.addEventListener(eventName, callback, bubble);
	} else {
		//ie
		document.attachEvent('on' + eventName, callback);
	}                                                  
}
