/*Display 0.9a3 
© 2010, Josh Strike. 
If you like this code, please donate $1 per domain you use it on! Paypal to josh@joshstrike.com. And send me a note! 
I'd also like to see any mods you come up with for the source. Enjoy =)
*This software is provided as-is with no warranty express or implied. This software may be freely copied so long as this header is included. 
Copying of the software implies no transfer of ownership. 
This software may not be re-sold commercially, in whole or in part, without the express written permission from the author.*/

//useful for testing... create a div with the id 'tracer' to use it.

var Strike = function(){
	function trace(str) {
		document.getElementById('tracer').innerHTML+=str+"<br />";
	}
	function traceOnce(str) {
		document.getElementById('tracer').innerHTML=str+"<br />";
	}
	
	Function.prototype.bind = function(obj) {
		var method = this, temp = function() {
			return method.apply(obj, arguments);
		};
		return temp;
	}
	
	var _MainEventList = [];
	
	function Mouse(display) {
		this.x = 0;
		this.y = 0;
		this.display = display;
		this.clicked = false;
		this.down = false;
		this.downDispatched = false;
		this.up = false;
		this.moved = false;
	}
	Mouse.prototype.registerPosition = function(e) {
		var toX = e.clientX-this.display.canvas.offsetLeft;
		var toY = e.clientY-this.display.canvas.offsetLeft;
		this.moved = (toX != this.x || toY != this.y);
		this.x = toX;
		this.y = toY;
	}
	Mouse.prototype.registerDown = function(e) {
		this.down = true;
	}
	Mouse.prototype.registerUp = function(e) {
		this.up = true;
	}	
	Mouse.prototype.registerClick = function(e) {
		this.clicked = true;
	}
	
	function StrikeDisplay(canvasID,backgroundColor,framerate,debug) {
		this.canvas = document.getElementById(canvasID);
		this.context = this.canvas.getContext('2d');
		
		this.hiddenCanvas = document.createElement('CANVAS');
		this.hiddenCanvas.setAttribute('width',this.canvas.width);
		this.hiddenCanvas.setAttribute('height',this.canvas.height);
		this.hiddenContext = this.hiddenCanvas.getContext('2d');
		
		this._mouse = new Mouse(this);
		this.canvas.onmousemove = this._mouse.registerPosition.bind(this._mouse);
		this.canvas.onclick = this._mouse.registerClick.bind(this._mouse);
		this.canvas.onmousedown = this._mouse.registerDown.bind(this._mouse);
		this.canvas.onmouseup = this._mouse.registerUp.bind(this._mouse);
		
		this.stage = new Sprite(this);
		this.stage.name = "stage";
		this.stage.display = this;
		this.framerate = framerate;
		this.backgroundColor = backgroundColor;
		this.showRedrawBounds = debug;
		this._uniqueChildBoundaries = true;
		this._redrawWithTraverser = false;
		this._boundFlicker = false;
		this.context.fillStyle = this.backgroundColor;
		this.context.fillRect(0,0,this.canvas.width,this.canvas.height);
		this._lastwr = new Array();
		setInterval("root.render()",1000/this.framerate);
	}
	StrikeDisplay.prototype.translateToSprite = function(s,cont) {
		if (!cont) {
			cont = this.context;
		} else {
			cont = this.hiddenContext;
		}
		var q = s;	
		var c = s.concatMatrix();
		try {
			cont.setTransform(c.a,c.b,c.c,c.d,c.tx,c.ty);
		} catch (err) {
			//alert (c.a+','+c.b+','+c.c+','+c.d+','+c.tx+',',c.ty);
		}
	}
	StrikeDisplay.prototype.translateWithinSprite = function(x,y,r,sx,sy,cont) {
		if (!cont) {
			cont = this.context;
		} else {
			cont = this.hiddenContext;
		}
		cont.translate(Number(x),Number(y));
		cont.rotate(r*(Math.PI/180));
		cont.scale(sx,sy);
	}
	StrikeDisplay.prototype.unTranslate = function(cont) {
		if (!cont) {
			cont = this.context;
		} else {
			cont = this.hiddenContext;
		}
		cont.setTransform(1,0,0,1,0,0);
	}
	StrikeDisplay.prototype.render = function(s,wr,redraw,childrenBounded) {
		//proceed through the entire display chain and create a _bb based on the invalid sprites.
		if (s==null) {
			var origin = true;
			var s = this.stage;
			var redraw = new Array();
			var wr = new Array();
			var childrenBounded = false;
		}
		s.dispatchEvent(new Event("enterFrame",cr,cr));
		var holdpush = new Array();
		for (var i=0;i<s.children.length;i++) {
			var cr = s.children[i];
			if (cr.blockRedraw) {
				childrenBounded = true;
				continue;
			}
			if (cr.invalid) {
				if (!childrenBounded) {
					//only drill down once for any invalid sprite... 
					wr.push(deriveBounds(cr,false,0,0,!this._uniqueChildBoundaries));
					childrenBounded = !this._uniqueChildBoundaries;
				}
				
				redraw.push(cr);
				
				//By default, this code block (and the associated _redrawWithTraverser flag) is off. There are problems with it. 
				//In essence, it tries to merge all overlapping bounding boxes so that only moving sprites or those they overlap need to be redrawn. 
				//Traversing the display chain for bounding box collisions, not surprisingly, turns out to be slower than just redrawing each sprite on 
				//each frame; this was basically abandoned early-on and there are still probably issues with miscalculation in some circumstances that could 
				//lead to graphics errors. Not recommended for use. 
				if (this._redrawWithTraverser && this.stage && this._lastwr && this._lastwr.length>0) {
					cr.invalid = false;
					var addl = this.BoundCollisionTraverse(cr);
					for (var j=0;j<addl.length;j++) {
						var lastwrbox = this._lastwr[this._lastwr.length-1];
						lastwrbox = deriveBounds(addl[j],lastwrbox,0,0);
						addl[j].invalid = false;
						if (redraw.indexOf(addl[j])==-1 && holdpush.indexOf(addl[j])==-1) {
							this.zCompare(cr,addl[j])>0?redraw.unshift(addl[j]):holdpush.push(addl[j]);
						}
					}
				}
				
			}		
		
			this.render(cr,wr,redraw,childrenBounded);	
			if (holdpush.length>0) {
				redraw.push(holdpush[0]);
			}
			childrenBounded = false;
		}
		if (origin) {
			this.context.fillStyle = this.backgroundColor;
			var usewr = this._lastwr;
			for (var ik = 0;ik<usewr.length;ik++) {
				this.context.fillRect(usewr[ik].left,usewr[ik].top,usewr[ik].width(),usewr[ik].height());
				if (this.showRedrawBounds) {
					this.context.strokeStyle = !this._boundFlicker?"#FF0000":Math.random()>.5?("#FF0000"):"#FFFFFF";
					this.context.lineWidth = 1;
					this.context.strokeRect(usewr[ik].left,usewr[ik].top,usewr[ik].width(),usewr[ik].height());
				}
			}
			
			//render draw each item on the list. 
			for (var k=0;k<redraw.length;k++) {
				redraw[k].graphics.draw();
			}
			
			this._lastwr = wr.slice();
			wr = [];
			
			this.checkMouse();
		}
		
		return (wr);
	}
	
	StrikeDisplay.prototype.checkMouse = function() {
		var mpoint = new Point(this._mouse.x,this._mouse.y);
		if (mpoint.x>this.stage.stageWidth || mpoint.y>this.stage.stageHeight || 
				mpoint.x<0 || mpoint.y<0) {
				//To do: mouse off-stage behavior... presently 
		}
		var viable = new Array();
		var b = this.SpritesUnderPoint(mpoint);
		for (var k in b) {
			if (b[k].hasParentMouseListeners) {
				if (b[k] == this.stage || b[k]._pointInGraphics(mpoint)) {
					//we don't re-render the whole stage on the hidden canvas each time, to save speed. 
					//so here we take a shortcut and always push the stage into the viable objects under the mouse. 
					viable.push(b[k]);
				}
			}
		}
		if (viable.length>0) {
			viable.sort(this.zCompare);
			if (this._mouse.clicked) {
				this.chainDispatchAsNeeded(viable[0],"click");
			}
			if (this._mouse.down && !this._mouse.downDispatched) {
				this.chainDispatchAsNeeded(viable[0],"mouseDown");
				this._mouse.downDispatched = true;
			}
			if (this._mouse.up) {
				this.chainDispatchAsNeeded(viable[0],"mouseUp");
				this._mouse.downDispatched = false;
			}
			this.chainDispatchAsNeeded(viable[0],"mouseOver");
			this.canvas.style.cursor = 'pointer';
		} else {
			this.canvas.style.cursor = '';
		}
	
		if (_MainEventList["mouseOut"]) {
			var viableChain = [];
			if (viable.length>0) {
				viableChain.push(viable[0]);
				var v = viable[0];
				while (v = v.parent) {
					viableChain.push(v);
				}
			}
			var mo = _MainEventList["mouseOut"]
			for (var m in mo) {
				if (mo[m].sprite.mouseWithin && viableChain.indexOf(mo[m].sprite)==-1) {
					mo[m].sprite.dispatchEvent(new Event("mouseOut",mo[m].sprite,mo[m].sprite));
					mo[m].sprite.mouseWithin = false;
				}
			}
		}
	
		this._mouse.clicked = false;
		this._mouse.down = false;
		this._mouse.up = false;
	}
	StrikeDisplay.prototype.chainDispatchAsNeeded = function(a,type,orig) {
		if (orig == null) {
			orig = a;
		}
		if (a._listeners[type]) {
			for (var k in a._listeners[type]) {
				var evt = new Event(type,a,orig);
				a.dispatchEvent(evt);
				if (type == "mouseOver" || type == "click" || type == "mouseDown" || type == "mouseUp") {
					a.mouseWithin = true;
				}
			}
		}
		if (a.parent != null) {
			this.chainDispatchAsNeeded(a.parent,type,orig);
		}
	}
	
	StrikeDisplay.prototype.SpritesUnderPoint = function(point,s,out) {
		if (s == null) {
			var out = [];
			var s = this.stage;
		}
		if (s._pointInBounds(point)) {
			out.push(s);
		}
		for (var k in s.children) {	
			this.SpritesUnderPoint(point,s.children[k],out);
		}
		return (out);
	}
	
	StrikeDisplay.prototype.zCompare = function(a,b) {
		var ar = [];
		var j = a;
		var k = b;
		ar.push(j);
		while (j = j.parent) {
			ar.push(j);
		}
		var lastk = k;
		while (k = k.parent) {
			var ark = ar.indexOf(k);
			if (ark>-1) {
				return (k.children.indexOf(ar[ark-1])>k.children.indexOf(lastk)?-1:1);
			}
			lastk = k;
		}
		return (-1);
	}
	
	StrikeDisplay.prototype.BoundCollisionTraverse = function(child,s,out) {
		if (s == null) {
			var out = [];
			var s = this.stage;
		}
		if (s != child && !s.invalid) {
			if (child._intersectsBounds(s)) {
				out.push(s);
			}
		}
		for (var k in s.children) {
			this.BoundCollisionTraverse(child,s.children[k],out);
		}
		return (out);
	}
	
	function Point(x,y) {
		this.x = x;
		this.y = y;
	}
	
	function Matrix(_a,_b,_c,_d,_tx,_ty,_u,_v,_w) {
		this.a = _a || 1;
		this.b = _b || 0;
		this.c = _c || 0;
		this.d = _d || 1;
		this.tx = _tx || 0;
		this.ty = _ty || 0;
		this.u = _u || 0;
		this.v = _v || 0;
		this.w = _w || 1;
	}
	Matrix.prototype.translate = function(x,y) {
		this.tx+=x;
		this.ty+=y;
	}
	Matrix.prototype.scale = function(sx,sy) {
		this.a *= sx;
		this.d *= sy;
		this.tx *= sx;
		this.ty *= sy;
	}
	Matrix.prototype.innerScale = function(sx,sy) {
		var m = new Matrix();
		m.scale(sx,sy);
		m = m.multiply(this);
		this.a = m.a;
		this.b = m.b;
		this.c = m.c;
		this.d = m.d;
		this.tx = m.tx;
		this.ty = m.ty;
	}
	Matrix.prototype.rotate = function(deg) {
		var sine = Math.sin(deg*(Math.PI/180));
		var cosine = Math.cos(deg*(Math.PI/180));
		var k = [this.a,this.b,this.c,this.d,this.tx,this.ty];
		this.a = k[0]*cosine - k[1]*sine;
		this.b = k[0]*sine + k[1]*cosine;
		this.c = k[2]*cosine - k[3]*sine;
		this.d = k[2]*sine + k[3]*cosine;
		//this.tx = k[4]*cosine - k[5]*sine;
		//this.ty = k[4]*sine + k[5]*cosine;
	}
	Matrix.prototype.transformPoint = function(point) {
		var prime = new Point(point.x*this.a+point.y*this.c+this.tx,point.x*this.b+point.y*this.d+this.ty);
		return (prime);
	}
	Matrix.prototype.deltaTransformPoint = function(point) {
		var prime = new Point(point.x*this.a+point.y*this.c,point.x*this.b+point.y*this.d);
		return (prime);
	}
	Matrix.prototype.multiply = function(m) {
		var mult = new Matrix(this.a*m.a+this.b*m.c+this.u*m.tx,
							  this.a*m.b+this.b*m.d+this.u*m.ty,
							  this.c*m.a+this.d*m.c+this.v*m.tx,
							  this.c*m.b+this.d*m.d+this.v*m.ty,
							  this.tx*m.a+this.ty*m.c+this.w*m.tx,
							  this.tx*m.b+this.ty*m.d+this.w*m.ty,
							  this.a*m.u+this.b*m.v+this.u*m.w,
							  this.c*m.u+this.d*m.v+this.v*m.w,
							  this.tx*m.u+this.ty*m.u+this.w*m.w);
		return (mult);
	}
	Matrix.prototype.inverse = function() {
		var n = this.a*this.d-this.b*this.c;
		var inv = new Matrix(this.d/n,
							 -this.b/n,
							 -this.c/n,
							 this.a/n,
							 (this.c*this.ty-this.d*this.tx)/n,
							 -(this.a*this.ty-this.b*this.tx)/n,
							 0,0,1);
		return (inv);
	}
	Matrix.prototype.getScaleX = function() {
		return (Math.sqrt(this.a * this.a + this.b * this.b));
	}
	Matrix.prototype.getScaleY = function() {
		return (Math.sqrt(this.c * this.c + this.d * this.d));
	}
	Matrix.prototype.getRotation = function() {
		var px = this.deltaTransformPoint(new Point(0,1));
		return ((180/Math.PI) * Math.atan2(px.y, px.x) - 90);	
	}
	
	function BoundingBox() {
		this.left = null;
		this.right = null;
		this.top = null;
		this.bottom = null;
	}
	BoundingBox.prototype.set = function(l,r,t,b,strokeOn,mult,xtra) {
		//additive set function
		if (!xtra) {
			xtra = 0;
		}
		if (!strokeOn) {
			sw = 1+xtra;
		} else {
			sw = (strokeOn.lineWidth+xtra)*mult;
		}
		if (this.left == null || l-sw<this.left) {
			this.left = l-sw;
		}
		if (this.right == null || r+sw>this.right) {
			this.right = r+sw;
		}
		if (this.top == null || t-sw<this.top) {
			this.top = t-sw;
		}
		if (this.bottom == null || b+sw>this.bottom) {
			this.bottom = b+sw;
		}
	}
	BoundingBox.prototype.unset = function() {
		this.left = null;
		this.right = null;
		this.top = null;
		this.bottom = null;
	}
	BoundingBox.prototype.width = function() {
		return (this.right-this.left);
	}
	BoundingBox.prototype.height = function() {
		return (this.bottom-this.top);
	}
	BoundingBox.prototype.debug = function() {
		return (this.left+","+this.right+","+this.top+","+this.bottom);
	}
	
	function Graphics(s) {
		this.sprite = s;
		this.list = new Array();
		this.corners = [];
		this.images = {};
		this.divs = [];
		this.fillOn = false;
		this.strokeOn = null;
		this.pathOn = false;
	}
	Graphics.prototype.clear = function() {
		this.list = new Array();
		this.corners = [];
		this.images = {};
		this.divs = [];
		this.sprite._bb.unset();
		this.sprite.invalid = true;
	}
	Graphics.prototype._setContextFill = function(context) {
		var fo = this.fillOn;
		if (fo.type == "basic") {
			context.fillStyle = fo.color;
		} else if (fo.type == "linearGradient") {
			var g = context.createLinearGradient(fo.xa,fo.ya,fo.xb,fo.yb);
			g.addColorStop(0,fo.c1);
			g.addColorStop(1,fo.c2);
			context.fillStyle = g;
		}
	}
	Graphics.prototype._beginFill = function(c,a,context) {
		if (!context) {
			if (c!="none") {
				this.fillOn = {type:"basic",color:_colorToStyle(c,a)};
			} else {
				this.fillOn = false;
			}
		} else {
			this.fillOn = {type:"basic",color:"#000000"};
		}
	}
	Graphics.prototype.beginFill = function(color,alpha) {
		if (!alpha) {
			alpha = 1;
		}
		this.list.push({f:'_beginFill',v:[color,alpha]});
		this.sprite.invalid = true;
		this._beginFill(color,alpha);
	}
	Graphics.prototype._beginSimpleGradient = function(ca,aa,cb,ab,xa,ya,xb,yb,cont) {
		if (!cont) {
			var c1 = _colorToStyle(ca,aa);
			var c2 = _colorToStyle(cb,ab);
			this.fillOn = {type:"linearGradient",c1:c1,c2:c2,xa:xa,ya:ya,xb:xb,yb:yb};
		} else {
			this.fillOn = {type:"basic",color:"#000000"};
		}
	}
	Graphics.prototype.beginSimpleGradient = function(colorA,alphaA,colorB,alphaB,xa,ya,xb,yb) {
		this.list.push({f:'_beginSimpleGradient',v:[colorA,alphaA,colorB,alphaB,xa,ya,xb,yb]});
		this.sprite.invalid = true;
		this._beginSimpleGradient(colorA,alphaA,colorB,alphaB,xa,ya,xb,yb);
	}
	Graphics.prototype._endFill = function(context) {
		this.fillOn = false;
	}
	Graphics.prototype.endFill = function() {
		this.list.push({f:'_endFill',v:[]});
		this.sprite.invalid = true;
		this._beginFill("none",1);
	}
	Graphics.prototype._lineStyle = function(w,c,a,context) {
		if (w>0) {
			this.strokeOn = {lineWidth:w,strokeStyle:_colorToStyle(c,a)};
		} else {
			this.strokeOn = null;
		}
	}
	Graphics.prototype.lineStyle = function(width,color,alpha) {
		if (!alpha) {
			alpha = 1;
		}
		this.list.push({f:'_lineStyle',v:[width,color,alpha]});
		this.sprite.invalid = true;
		this._lineStyle(width,color,alpha);
	}
	Graphics.prototype._moveTo = function(x,y,cont) {
		if (this.sprite.stage) {
			var context;
			if (!cont) {
				context = this.sprite.stage.display.context;
			} else {
				context = this.sprite.stage.display.hiddenContext;
			}
			if (!this.pathOn) {
				this.pathOn = true;
				context.beginPath();
			}
			var display = this.sprite.stage.display;
			display.translateToSprite(this.sprite,cont);
	
			context.moveTo(x,y);
			display.unTranslate(cont);
	
		}
	}
	Graphics.prototype.moveTo = function(x,y) {
		x = Number(x);
		y = Number(y);
		this.list.push({f:'_moveTo',v:[x,y]});
		this.corners.push(new Point(x,y));
		this.sprite.invalid = true;
		this.sprite.setBoundingBox();
	}
	Graphics.prototype._lineTo = function(x,y,cont) {
		if (this.sprite.stage) {
			var context;
			if (!cont) {
				context = this.sprite.stage.display.context;
			} else {
				context = this.sprite.stage.display.hiddenContext;
			}
			if (!this.pathOn) {
				this.pathOn = true;
				context.beginPath();
			}
			var display = this.sprite.stage.display;
			display.translateToSprite(this.sprite,cont);
			if (this.strokeOn != null) {
				context.lineWidth = this.strokeOn.lineWidth;
				context.strokeStyle = this.strokeOn.strokeStyle;
				context.lineTo(x,y);
				context.stroke();
				
			}
			display.unTranslate(cont);
		}
	}
	Graphics.prototype.lineTo = function(x,y) {
		x = Number(x);
		y = Number(y);
		this.list.push({f:'_lineTo',v:[x,y]});
		this.corners.push(new Point(x,y));
		this.sprite.invalid = true;
		this.sprite.setBoundingBox();
	}
	Graphics.prototype._curveTo = function(xa,ya,xb,yb,cont) {
		if (this.sprite.stage) {
			var context;
			if (!cont) {
				context = this.sprite.stage.display.context;
			} else {
				context = this.sprite.stage.display.hiddenContext;
			}
			if (!this.pathOn) {
				this.pathOn = true;
				context.beginPath();
			}
			var display = this.sprite.stage.display;
			display.translateToSprite(this.sprite,cont);
			if (this.strokeOn != null) {
				context.lineWidth = this.strokeOn.lineWidth;
				context.strokeStyle = this.strokeOn.strokeStyle;
				context.quadraticCurveTo(xa,ya,xb,yb);
				context.stroke();
				
			}
			display.unTranslate(cont);
		}
	}
	Graphics.prototype.curveTo = function(xa,ya,xb,yb) {
		xa = Number(xa);
		ya = Number(ya);
		xb = Number(xb);
		yb = Number(yb);
		this.list.push({f:'_curveTo',v:[xa,ya,xb,yb]});
		this.corners.push(new Point(xa,ya),new Point(xb,yb));
		this.sprite.invalid = true;
		this.sprite.setBoundingBox();
	}
	Graphics.prototype._endPath = function(cont) {
		if (!this.pathOn) return (false);
		var context;
		if (!cont) {
			context = this.sprite.stage.display.context;
		} else {
			context = this.sprite.stage.display.hiddenContext;
		}
		this.pathOn = false;
		if (this.fillOn) {
			this._setContextFill(context);
			context.fill();
			context.closePath();
		}
	}
	Graphics.prototype.endPath = function() {
		this.list.push({f:'_endPath',v:[]});
		this.sprite.invalid = true;
		this._endPath();
	}
		
	Graphics.prototype._drawRect = function(x,y,w,h,cont) {
		if (this.sprite.stage) {
			var context;
			if (!cont) {
				context = this.sprite.stage.display.context;
			} else {
				context = this.sprite.stage.display.hiddenContext;
			}
			var display = this.sprite.stage.display; 
			display.translateToSprite(this.sprite,cont); //transform the context to the sprite's collective transformation. 
			
			if (this.fillOn) {
				this._setContextFill(context);
				context.fillRect(x,y,w,h);
			}
			if (this.strokeOn != null) {
				context.lineWidth = this.strokeOn.lineWidth;
				context.strokeStyle = this.strokeOn.strokeStyle;
				context.strokeRect(x,y,w,h);
			}
			display.unTranslate(cont);
		}
	}
	Graphics.prototype.drawRect = function(x,y,w,h) {
		x = Number(x);
		y = Number(y);
		w = Number(w);
		h = Number(h);
		this.list.push({f:'_drawRect',v:[x,y,w,h]});
		this.corners.push(new Point(x,y),new Point(x+w,y),new Point(x,y+h),new Point(x+w,y+h));
		this.sprite.invalid = true;
		this.sprite.setBoundingBox();
	}
	Graphics.prototype._drawRoundRect = function(x,y,w,h,p,cont) {
		if (this.sprite.stage) {
			var context;
			if (!cont) {
				context = this.sprite.stage.display.context;
			} else {
				context = this.sprite.stage.display.hiddenContext;
			}
			var display = this.sprite.stage.display; 
			display.translateToSprite(this.sprite,cont); //transform the context to the sprite's collective transformation. 
			display.translateWithinSprite(x,y,0,1,1,cont);
			x = 0;
			y = 0;
			context.beginPath();
			context.moveTo(x+p,y);
			context.lineTo((x+w)-p,y);
			context.quadraticCurveTo(x+w,y,x+w,y+p);
			context.lineTo(x+w,(y+h)-p);
			context.quadraticCurveTo(x+w,y+h,(x+w)-p,y+h);
			context.lineTo(x+p,y+h);
			context.quadraticCurveTo(x,y+h,x,(y+h)-p);
			context.lineTo(x,y+p);
			context.quadraticCurveTo(x,y,x+p,y);
			
			if (this.fillOn) {
				this._setContextFill(context);
				context.fill();
			}
			if (this.strokeOn != null) {
				context.lineWidth = this.strokeOn.lineWidth;
				context.strokeStyle = this.strokeOn.strokeStyle;
				context.stroke();
			}
			context.closePath();
			display.unTranslate(cont);
		}
	}
	Graphics.prototype.drawRoundRect = function(x,y,w,h,p) {
		x = Number(x);
		y = Number(y);
		w = Number(w);
		h = Number(h);
		this.list.push({f:'_drawRoundRect',v:[x,y,w,h,p]});
		this.corners.push(new Point(x,y),new Point(x+w,y),new Point(x,y+h),new Point(x+w,y+h));
		this.sprite.invalid = true;
		this.sprite.setBoundingBox();
	}
	Graphics.prototype._drawCircle = function(x,y,r,cont) {
		if (this.sprite.stage) {
			var context;
			if (!cont) {
				context = this.sprite.stage.display.context;
			} else {
				context = this.sprite.stage.display.hiddenContext;
			}
			var display = this.sprite.stage.display; 
			display.translateToSprite(this.sprite,cont); //transform the context to the sprite's collective transformation. 
			
			context.beginPath();
			context.arc(x,y,r,0,Math.PI*2,false);
			if (this.fillOn) {
				this._setContextFill(context);
				context.fill();
			}
			if (this.strokeOn != null) {
				context.lineWidth = this.strokeOn.lineWidth;
				context.strokeStyle = this.strokeOn.strokeStyle;
				context.stroke();
			}
			context.closePath();
			display.unTranslate(cont);
		}
	}
	Graphics.prototype.drawCircle = function(x,y,radius) {
		x = Number(x);
		y = Number(y);
		radius = Number(radius);
		this.list.push({f:'_drawCircle',v:[x,y,radius]});
		this.corners.push(new Point(x-radius,y-radius),new Point(x-radius,y+radius),new Point(x+radius,y-radius),new Point(x+radius,y+radius));
		this.sprite.invalid = true;
		this.sprite.setBoundingBox();
	}
	Graphics.prototype._drawImage = function(name,x,y,dw,dh,sx,sy,sw,sh,cont) {
		if (this.sprite.stage && this.images[name].img) {
			var context;
			if (!cont) {
				context = this.sprite.stage.display.context;
			} else {
				context = this.sprite.stage.display.hiddenContext;
			}
			var display = this.sprite.stage.display;
			display.translateToSprite(this.sprite,cont);
			if (!cont) {
				if (sx == "none") {
					context.drawImage(this.images[name].img,x,y,dw,dh);
				} else {
					context.drawImage(this.images[name].img,x,y,dw,dh,sx,sy,sw,sh);
				}
			} else {
				context.fillStyle = '#000000';
				context.fillRect(x,y,dw,dh);
			}
			display.unTranslate(cont);
		}
	}
	Graphics.prototype.drawImage = function(name,src,x,y,dw,dh,sx,sy,sw,sh) {
		x = x ? Number(x) : 0;
		y = y ? Number(y) : 0;
		dw = dw ? Number(dw) : 0;
		dh = dh ? Number(dh) : 0;
		if (!sx && !sy && !sw && !sh) {
			sx = sx ? Number(sx) : "none";
		} else {
			sx = sx ? Number(sx) : 0;
			sy = sy ? Number(sy) : 0;
			sw = sw ? Number(sw) : 0;
			sh = sh ? Number(sh) : 0;
		}
		if (dw || dh) {
			this.list.push({f:'_drawImage',v:[name,x,y,dw,dh,sx,sy,sw,sh]});
			this.corners.push(new Point(x,y),new Point(x+dw,y),new Point(x,y+dh),new Point(x+dw,y+dh));
		}
		var img = new Image();
		img.name = name;
		img.onload = this._imageLoaded.bind(this);
		this.images[name] = {img:null,x:x,y:y,dw:dw,dh:dh};
		img.src = src;
		this.sprite.invalid = true;
		this.sprite.setBoundingBox();
	}
	Graphics.prototype._imageLoaded = function(e) {
		this.images[e.target.name].img = e.target;
		var imgObj = this.images[e.target.name];
		if (imgObj.dw==0) {
			var dw = this.images[e.target.name].img.width;
			var dh = this.images[e.target.name].img.height;
			this.list.push({f:'_drawImage',v:[e.target.name,imgObj.x,imgObj.y,dw,dh,"none",0,0,0]});
			this.corners.push(new Point(imgObj.x,imgObj.y),new Point(imgObj.x+dw,imgObj.y),new Point(imgObj.x,imgObj.y+dh),new Point(imgObj.x+dw,imgObj.y+dh));
		}
	}
	Graphics.prototype.attachDiv = function(id,x,y) {
		for (var i in this.divs) {
			if (this.divs[i].id == id) return (false);
		}
		if (!x) x = 0;
		if (!y) y = 0;
		this.divs.push({id:id,x:x,y:y});
	}
	Graphics.prototype.removeDiv = function(id) {
		for (var i in this.divs) {
			if (this.divs[i].id == id) {
				this.divs.splice(i,1);
				return (true);
			}
		}
		return (false);
	}
	Graphics.prototype.setDivProperties = function(id,props) {
		for (var i in this.divs) {
			if (this.divs[i].id == id) {
				for (var k in props) {
					this.divs[i][k] = props[k];
				}
				return (true);
			}
		}
		return (false);
	}
	Graphics.prototype.deriveAlpha = function() {
		var s = this.sprite;
		var a = s.alpha;
		while (s = s.parent) {
			a *= s.alpha;
		}
		return (a)
	}
	Graphics.prototype.draw = function() {
		//go through the list and draw. 
	
		var rc = this.sprite.stage.display.context;
		rc.save();
	
		rc.globalAlpha = this.deriveAlpha();
		if (this.sprite.shadow) {
			rc.shadowOffsetX = this.sprite.shadow.ox;
			rc.shadowOffsetY = this.sprite.shadow.oy;
			rc.shadowBlur = this.sprite.shadow.bluramt;
			rc.shadowColor = this.sprite.shadow.color;
		}
	
		for (var i=0;i<this.list.length;i++) {
			var com = this.list[i];
			var iter = "";
			for (var k=0;k<com.v.length;k++) {
				if (k>0) {
					iter += ",";
				}
				iter += '"'+com.v[k]+'"';
			}
			try {eval('this.'+com.f+'('+iter+');')} catch (err) {
				//alert('this.'+com.f+'('+iter+')');
			}
		}
		var m = this.sprite.concatMatrix();
		for (var k in this.divs) {
			var div = document.getElementById(this.divs[k].id);
			div.style.position = 'absolute';
			div.style.left = (m.tx+this.sprite.stage.display.canvas.offsetLeft+this.divs[k].x)+'px';
			div.style.top = (m.ty+this.sprite.stage.display.canvas.offsetTop+this.divs[k].y)+'px';
		}
		this.sprite.stage.display.context.restore();
	}
	Graphics.prototype._drawToHidden = function() {
		this.sprite.stage.display.hiddenContext.save();
		for (var i=0;i<this.list.length;i++) {
			var com = this.list[i];
			var iter = "";
			//if (com.f == '_beginFill') {
			//	iter = '"#000000","1"';
			//} else {
				for (var k=0;k<com.v.length;k++) {
					if (k>0) {
						iter += ",";
					}
					iter += '"'+com.v[k]+'"';
				}
			//}
			try {
				var cstr = '';
				if (iter != "") {
					cstr = 'this.'+com.f+'('+iter+',1);';
					eval('this.'+com.f+'('+iter+',1);');
				} else {
					cstr = 'this.'+com.f+'('+iter+',1);';
					eval('this.'+com.f+'(1);');
				}
			} catch (err) {
				//alert(cstr);
			}
		}
		this.sprite.stage.display.hiddenContext.save();
	}
	
	function Sprite(display) {
		this._listeners = {};
		this.graphics = new Graphics(this);
		this.children = new Array();
		this._bb = new BoundingBox();
		this.blockRedraw = false;
		if (display) {
			this.stage = this;
			this.stageWidth = display.canvas.width;
			this.stageHeight = display.canvas.height;
			this._bb.set(0,this.stageWidth,0,this.stageHeight);
		}
		this.transform = new Matrix();
		this.alpha = 1;
		this.shadow = null;
		this.mouseWithin = false;
	}
	Sprite.prototype.name = "";
	Sprite.prototype.parent = null;
	Sprite.prototype.invalid = true;
	Sprite.prototype._rotation = 0; //arbitrary usage... 
	Sprite.prototype.assignStage = function(s,st) {
		s.stage = st;
		for (var k=0;k<s.children.length;k++) {
			s.assignStage(s.children[k],st);
		}
	}
	
	///EVENTS///
	function Event(type,currentTarget,target) {
		this.type = type;
		this.currentTarget = currentTarget;
		this.target = target;
	}
	
	Sprite.prototype.dispatchEvent = function(evt) {
		for (var i in _MainEventList) {
			for (var k in _MainEventList[i]) {
				if (i == evt.type && _MainEventList[i][k].sprite == this) {
					evt.currentTarget = this; //switch this to currentTarget...?
					_MainEventList[i][k].fun(evt);
					return (true);
				}
			}
		}
	}
	Sprite.prototype._addMainListener = function(type,fun) {
		if (_MainEventList[type]) {
			_MainEventList[type].push({sprite:this,fun:fun});
		} else {
			_MainEventList[type] = [{sprite:this,fun:fun}];
		}
	}
	Sprite.prototype._removeMainListener = function(type,fun) {
		for (var k in _MainEventList[type]) {
			if (_MainEventList[type][k].sprite == this && _MainEventList[type][k].fun == fun) {
				delete (_MainEventList[type][k].sprite);
				delete (_MainEventList[type][k].fun);
				_MainEventList[type].splice(k,1);
				if (_MainEventList[type].length<1) {
					delete _MainEventList[type];
				}
			}
		}
	}
	Sprite.prototype._detachFromMain = function() {
		//remove all listeners associated with this sprite from the main event list... 
		for (var j in _MainEventList) {
			for (var k in _MainEventList[j]) {
				if (_MainEventList[j][k].sprite == this) {
					var mlist = _MainEventList[type].splice(k,1);
					mlist = null;
					delete mlist;
				}
			}
		}
		for (var c=0;c<this.children.length;c++) {
			this.children[c]._detachFromMain();
		}
	}
	Sprite.prototype.addEventListener = function(type,fun) {
		if (this._listeners[type]) {
			if (this.hasEventListener(type,fun)) {
				return (false);
			}
			this._listeners[type].push(fun);
		} else {
			this._listeners[type] = [fun];
		}
		this._addMainListener(type,fun);
	}
	Sprite.prototype.hasEventListener = function(type,fun,pos) {
		//pos flag returns the index of the listener on success (used for removal). 
		if (!this._listeners[type]) return (false);
		var len = this._listeners[type].length;
		for (var i=0;i<len;i++) {
			if (this._listeners[type][i] == fun) return (pos?i:true);
		}
		return (false);
	}
	Sprite.prototype.removeEventListener = function(type,fun) {
		var i = this.hasEventListener(type,fun,true);
		if (i !== false) {
			this._listeners[type].splice(i,1);
			this._removeMainListener(type,fun);
			if (this._listeners[type].length<1) {
				this._listeners[type] = null;
				delete this._listeners[type];
			}
		}
	}
	Sprite.prototype.destroyEventListeners = function() {
		//remove your listeners before calling this. Helps to free up memory. 
		this._listeners = {};
		this._detachFromMain();
	}
	
	///DRAWING///
	Sprite.prototype.setBBChildren = function() {
		for (var i=0;i<this.children.length;i++) {
			this.children[i].setBoundingBox();
			this.children[i].setBBChildren();
		}
	}
	Sprite.prototype.setBoundingBox = function() {
		var minmax=[null,null,null,null];
		var matrix = this.concatMatrix();
		matrix.translate(-this.x,-this.y);
		for (var i=0;i<this.graphics.corners.length;i++) {
			//0 0 is not necessary here... 
			var g = matrix.transformPoint(i==-1?new Point(0,0):this.graphics.corners[i]);
			
			if (minmax[0]==null || g.x<minmax[0]) {
				minmax[0] = g.x;
			}
			if (minmax[1]==null || g.x>minmax[1]) {
				minmax[1] = g.x;
			}
			if (minmax[2]==null || g.y<minmax[2]) {
				minmax[2] = g.y;
			}
			if (minmax[3]==null || g.y>minmax[3]) {
				minmax[3] = g.y;
			}
		}
		this._bb.unset();
		var sx = this.scaleX;
		var sy = this.scaleY;
		var larger = sx>sy?sx:sy;
		var xtra = this.shadow?(this.shadow.ox>this.shadow.oy?this.shadow.ox:this.shadow.oy)+this.shadow.bluramt:0;
		this._bb.set(minmax[0],minmax[1],minmax[2],minmax[3],this.graphics.strokeOn,larger,xtra);
		this.setBBChildren();
	}
	Sprite.prototype.getNativeSize = function(wr,matrix) {
		if (wr == null) {
			wr = new BoundingBox();
			var first = this.transform.getRotation();
			this.transform.rotate(-first);
			var matrix = this.transform;
		} else {
			var matrix = this.transform.multiply(matrix);
			//var matrix = this.concatMatrix();
		}
		
		var minmax=[null,null,null,null];
		for (var i=-1;i<this.graphics.corners.length;i++) {
			var g = matrix.transformPoint(i==-1?new Point(0,0):this.graphics.corners[i]);
			if (minmax[0]==null || g.x<minmax[0]) {
				minmax[0] = g.x;
			}
			if (minmax[1]==null || g.x>minmax[1]) {
				minmax[1] = g.x;
			}
			if (minmax[2]==null || g.y<minmax[2]) {
				minmax[2] = g.y;
			}
			if (minmax[3]==null || g.y>minmax[3]) {
				minmax[3] = g.y;
			}
		}
		wr.set(minmax[0],minmax[1],minmax[2],minmax[3]);
		for (var k=0;k<this.children.length;k++) {
			this.children[k].getNativeSize(wr,matrix);
		}
		if (first) {
			this.transform.rotate(first);
		}
		return ({width:wr.width(),height:wr.height()});
	}
	Sprite.prototype.addChild = function(s) {
		if (s.parent) {
			s.parent.removeChild(s,false);
		}
		s.parent = this;
		//recursively assign the stage to all children. 
		this.assignStage(s,this.stage);
		this.children.push(s);
	}
	Sprite.prototype.addChildAt = function(s,k) {
		s.parent = this;
		this.assignStage(s,this.stage);
		this.children.splice(k,0,s);
	}
	Sprite.prototype.getChildAt = function(k) {
		return (this.children[k]);
	}
	Sprite.prototype.removeChild = function(s) {
		var idx = this.children.indexOf(s);
		if (idx==-1) {
			return (false);
		}
		s.parent = null;
		this.assignStage(s,null);
		this.children.splice(this.children.indexOf(s),1);
		s._detachFromMain();
		delete (s);
	}
	Sprite.prototype.removeChildAt = function(k) {
		this.removeChild(this.children[k]);
	}
	Sprite.prototype.setChildIndex = function(c,i) {
		var ix = this.children.indexOf(c);
		if (ix>-1) {
			this.children.splice(ix,1);
			this.children.splice(i,0,c);
		}
	}
	
	var spritePrototype = Sprite.prototype;
	spritePrototype.__defineGetter__("numChildren", function() {
		return (this.children.length);
	});
	
	spritePrototype.__defineGetter__("x", function() {
		return (this.transform.tx);
	});
	spritePrototype.__defineSetter__("x", function(k) {
		if (isNaN(k)) {
			return (false);
		}
		this.transform.tx = Number(k);
		this.setBoundingBox();
		this.invalid = true;
	});
	
	spritePrototype.__defineGetter__("y", function() {
		return (this.transform.ty);
	});
	spritePrototype.__defineSetter__("y", function(k) {
		if (isNaN(k)) {
			return (false);
		}
		this.transform.ty = Number(k);
		this.setBoundingBox();
		this.invalid = true;
	});
	
	spritePrototype.__defineGetter__("rotation", function() {
		return (this._rotation);
	});
	spritePrototype.__defineSetter__("rotation", function(k) {
		this.transform.rotate(k-this.transform.getRotation());
		this._rotation = k;
		this.setBoundingBox();
		this.invalid = true;
	});
	
	spritePrototype.__defineGetter__("scaleX", function() {
		return (this.transform.getScaleX());
	});
	spritePrototype.__defineSetter__("scaleX", function(sx) {
		this.transform.innerScale(sx,1);
		this.setBoundingBox();
		this.invalid = true;
	});
	
	spritePrototype.__defineGetter__("scaleY", function() {
		return (this.transform.getScaleY());
	});
	spritePrototype.__defineSetter__("scaleY", function(sy) {
		this.transform.innerScale(1,sy);
		this.setBoundingBox();
		this.invalid = true;
	});
	
	spritePrototype.__defineGetter__("width", function() {
		return (this.getNativeSize().width);
	});
	spritePrototype.__defineSetter__("width", function(w) {
		if (this.width>1) {
			this.scaleX = w/this.width;
		}
	});
	
	spritePrototype.__defineGetter__("height", function() {
		return (this.getNativeSize().height);//return (deriveBounds(this,false,false,false).height());
	});
	spritePrototype.__defineSetter__("height", function(h) {
		if (this.height>1) {
			this.scaleY = h/this.height;
		}
	});
	
	Sprite.prototype.localToGlobal = function(point) {
		return (this.concatMatrix().transformPoint(point));
	}
	Sprite.prototype.globalToLocal = function(point) {
		return (this.concatMatrix().inverse().transformPoint(point));
	}
	
	Sprite.prototype.concatMatrix = function(s,m) {
		if (s == null) {
			s = this;
			var m = new Matrix(this.transform.a,this.transform.b,this.transform.c,this.transform.d,this.transform.tx,this.transform.ty);
		}
		while (s = s.parent) {
			m = m.multiply(s.transform);
			this.concatMatrix(s,m); //was m=...but that changes the result... 
		}	
		return (m);
	}
	Sprite.prototype._intersectsBounds = function(s) {
		var ab = deriveBounds(this,false,0,0,false);
		var sb = deriveBounds(s,false,0,0,false);
		if (ab.bottom<sb.top) return (false);
		if (ab.top>sb.bottom) return (false);
		if (ab.right<sb.left) return (false);
		if (ab.left>sb.right) return (false);
		return (true);
	}
	Sprite.prototype._pointInBounds = function(point) {
		//takes a GLOBAL point and checks it against the bounds here. 
		var ab = deriveBounds(this,false,0,0,false);
		if (ab.bottom<point.y) return (false);
		if (ab.top>point.y) return (false);
		if (ab.right<point.x) return (false);
		if (ab.left>point.x) return (false);
		return (true);
	}
	Sprite.prototype._pointInGraphics = function(point) {
		//check the hidden canvas against a global point to see whether the sprite has drawn into that area.
		if (!this.stage) return (false);
		var hc = this.stage.display.hiddenContext;
		hc.fillStyle = "#FFFFFF";
		hc.fillRect(0,0,this.stage.stageWidth,this.stage.stageHeight);
		this.graphics._drawToHidden();
		var hdat = hc.getImageData(point.x,point.y,1,1);
		var red = hdat.data[0];
		return (red != 255);
	}
	spritePrototype.__defineGetter__("hasParentMouseListeners", function() {
		if (this._listeners["mouseUp"] || this._listeners["mouseDown"] || this._listeners["click"] || this._listeners["mouseOver"] || this._listeners["mouseMoved"]) return (true);
		var e = this;
		while (e = e.parent) {
			if (e._listeners["mouseUp"] || e._listeners["mouseDown"] || e._listeners["click"] || e._listeners["mouseOver"] || e._listeners["mouseMoved"]) return (true);
		}
	});
	
	function _colorToStyle(c,a) {
		if (a==1) {
			return (c);
		} else {
			var r = parseInt(c.substring(1,3),16);
			var g = parseInt(c.substring(3,5),16);
			var b = parseInt(c.substring(5,7),16);
	
			return ('rgba('+r+','+g+','+b+','+a+')');
		}
	}
	
	function DropShadow(ox,oy,bluramt,color,alpha) {
		this.ox = ox;
		this.oy = oy;
		this.bluramt = bluramt;
		this.color = _colorToStyle(color,alpha);
	}
	
	
	function deriveBounds(s,wr,xhold,yhold,drill) {
		//Traverses display nodes downward from an arbitrary Sprite, 
		//Returns a the smalles possible bounding box holding the sprite and all its children, in the global coordinate space.
		//This function assumes the _bb's for every object are already set by their various drawing commands. 
		if (wr===false) {
			wr = new BoundingBox();
			xhold = s.x;
			yhold = s.y;
		} else {
			xhold = s.x;
			yhold = s.y;
		}
		var mat = s.concatMatrix();
		wr.set(s._bb.left+xhold,s._bb.right+xhold,s._bb.top+yhold,s._bb.bottom+yhold);
		
		if (drill) {
			for (var i=0;i<s.children.length;i++) {
				var cr = s.children[i];
				deriveBounds(cr,wr,xhold,yhold,drill);
			}
		}
		return (wr);
	}
	
	function Tween(sprite,prop,easing,from,to,seconds,display) {
		if (!sprite.stage && !display) {
			//you must pass a display parameter unless it's a visual sprite on the stage. 
			return (false);
		} else if (sprite.stage) {
			this.framerate = sprite.stage.display.framerate;
		} else {
			this.framerate = display.framerate;
		}
		this.sprite = sprite;
		this._listeners = {};
		this.prop = prop;
		this.easing = easing;
		this.from = from;
		this.to = to;
		this.seconds = seconds;
		this.ticks = (1000/this.framerate)*seconds;
		this.iterator = 0;
		this.running = true;
		this.pos = from;
		this.doFunction = this.doTween.bind(this);
		this.interval = setInterval(this.doFunction,1000/this.framerate);
	}
	Tween.prototype.doTween = function() {
		this.iterator++;
		if (this.iterator >= this.ticks) {
			this.dispatchEvent(new Event("motionFinished",this,this));
			this.stop();
		}
		this.pos = this.easing(this.from,this.to,this.iterator,this.ticks,this.pos);
		this.sprite[this.prop] = this.pos;
	}
	Tween.prototype.stop = function() {
		if (this.running) {
			clearInterval(this.interval);
		}
		this.running = false;
		delete (this.doFunction);
	}
	function EaseNone(f,t,i,tot,p) {
		return (f-((f-t)*(i/tot)));
	}
	function ei(r,p) {
		return Math.pow(r,p);
	}
	function eo(r,p) {
		return 1-ei(1-r,p);
	}
	function eio(r,p) {
		if (r<=.5) return (ei(2*r,p)/2);
		return (eo(2*(r-.5),p)/2+.5);
	}
	function EaseIn(f,t,i,tot,p) {
		return (f-ei(i/tot,2)*(f-t));
		//return (f-(Math.pow(i/tot,3))*(f-t));
	}
	function EaseOut(f,t,i,tot,p) {
		return (f-eo(i/tot,2)*(f-t));
	}
	function EaseInOut(f,t,i,tot,p) {
		return (f-eio(i/tot,2)*(f-t));
	}
	Tween.prototype.dispatchEvent = function(evt) {
		for (var i in _MainEventList) {
			for (var k in _MainEventList[i]) {
				if (i == evt.type && _MainEventList[i][k].sprite == this) {
					evt.currentTarget = this;
					_MainEventList[i][k].fun(evt);
					return (true);
				}
			}
		}
	}
	Tween.prototype._addMainListener = function(type,fun) {
		if (_MainEventList[type]) {
			_MainEventList[type].push({sprite:this,fun:fun});
		} else {
			_MainEventList[type] = [{sprite:this,fun:fun}];
		}
	}
	Tween.prototype._removeMainListener = function(type,fun) {
		for (var k in _MainEventList[type]) {
			if (_MainEventList[type][k].sprite == this && _MainEventList[type][k].fun == fun) {
				var mlist = _MainEventList[type].splice(k,1);
				mlist = null;
				delete (mlist);
				if (_MainEventList[type].length<1) {
					delete _MainEventList[type];
				}
			}
		}
	}
	Tween.prototype._detachFromMain = function() {
		//remove all listeners associated with this sprite from the main event list... 
		for (var j in _MainEventList) {
			for (var k in _MainEventList[j]) {
				if (_MainEventList[j][k].sprite == this) {
					var mlist = _MainEventList[j].splice(k,1);
					mlist = null;
					delete mlist;
				}
			}
		}
		/*for (var c=0;c<this.children.length;c++) {
			this.children[c]._detachFromMain();
		}*/
	}
	Tween.prototype.addEventListener = function(type,fun) {
		if (this._listeners[type]) {
			if (this.hasEventListener(type,fun)) return (false);
			this._listeners[type].push(fun);
		} else {
			this._listeners[type] = [fun];
		}
		this._addMainListener(type,fun);
	}
	Tween.prototype.hasEventListener = function(type,fun,pos) {
		//pos flag returns the index of the listener on success (used for removal). 
		if (!this._listeners[type]) return (false);
		var len = this._listeners[type].length;
		for (var i=0;i<len;i++) {
			if (this._listeners[type][i] == fun) return (pos?i:true);
		}
		return (false);
	}
	Tween.prototype.removeEventListener = function(type,fun) {
		var i = this.hasEventListener(type,fun,true);
		if (i !== false) {
			var list = this._listeners[type].splice(i,1);
			list = null;
			delete list;
			this._removeMainListener(type,fun);
			if (this._listeners[type].length<1) {
				this._listeners[type] = null;
				delete this._listeners[type];
			}
		}
	}
	Tween.prototype.destroyEventListeners = function() {
		this._listeners = {};
		this._detachFromMain();
	}

	return {
		//public methods//
		trace: trace, 
		traceOnce: traceOnce, 
		StrikeDisplay: StrikeDisplay, 
		Point: Point, 
		Matrix: Matrix, 
		Sprite: Sprite, 
		Graphics: Graphics, 
		Tween: Tween, 
		EaseIn: EaseIn, 
		EaseOut: EaseOut, 
		EaseNone: EaseNone, 
		DropShadow: DropShadow,
		Event: Event
	} //end wrap Strike object
}() //end and invoke anon function

//top-level commands; you can disable these and preface everything with Strike. if you prefer.
var trace = Strike.trace;
var traceOnce = Strike.traceOnce;
var StrikeDisplay = Strike.StrikeDisplay;
var Point = Strike.Point;
var Matrix = Strike.Matrix;
var Sprite = Strike.Sprite;
var Graphics = Strike.Graphics;
var Tween = Strike.Tween;
var EaseIn = Strike.EaseIn;
var EaseOut = Strike.EaseOut;
var EaseNone = Strike.EaseNone;
var DropShadow = Strike.DropShadow;
var Event = Strike.Event;
