

/*! Array */
(function(obj,fns){
	var p = obj.prototype;
	for (var s in fns) if (!obj[s]) p[s] = fns[s];
})(Array,{
	forEach: function(fn,thisp){
		for (var i=0;i<this.length;i++) {
			fn.call(thisp||null,this[i],i,this);
		}
	}
	,largest: function(){
		return Math.max.apply(Math,this);
	}
	,smallest: function(){
		return Math.min.apply(Math,this);
	}
	,rnd: function(){
		return this[Math.round(Math.random()*this.length)-1];
	}
	,indexOf: function(n){
		for (var i=0;i<this.length;i++) if (this[i]===n) return i;
		return -1;
	}
	,lastIndexOf: function(n){
		var i = this.length;
		while (i--) if (this[i]===n) return i;
		return -1;
	}
/*	,forEach: function(f){
		var i=this.length, j, l=this.length;
		for(i=0;i<l;i++) if((j=this[i])) f(j);
	}*/
/*	,insert: function(i,v){ // todo: insert is similar to splice ... maybe rewrite, maybe not
		if (i>=0) {
			var a = this.slice(), b = a.splice(i);
			a[i] = v;
			return a.concat(b);
		}
	}*/
	,unique: function(){
		var a = [],i,j=this.length,k=j,o;
		for (i=0;i<j;i++) {
			o = this[i];
			if (a.indexOf(o)===-1) {
				a.push(o);
			} else {
				this.splice(i,1);
				i--;
				j--;
			}
		}
		return k-j;
	}
/*	,concat: function(a){
		for (var i = 0, b = this.copy(); i<a.length; i++) {
			b[b.length] = a[i];
		}
		return b;
	}*/
	,copy: function(){
		var a = [], i = this.length;
		while (i--) a[i] = (typeof this[i].copy!=='undefined')?this[i].copy():this[i];
		return a;
	}
	,shuffle: function(){
		var i = this.length,j,t;
		while (i--) {
			j = Math.floor((i+1)*Math.random());
			t = this[i];
			this[i] = this[j];
			this[j] = t;
		}
		return this;
	}
/*	,pop: function(){
		var b = this[this.length - 1];
		this.length--;
		return b;
	}
	,push: function(){
		for (var i = 0,b = this.length,a = arguments; i<a.length; i++) {
			this[b+i] = a[i];
		}
		return this.length;
	}
	,shift: function(){
		for (var i = 0,b = this[0]; i<this.length - 1; i++) {
			this[i] = this[i + 1];
		}
		this.length--;
		return b;
	}
	,slice: function(a,c) {
		var i = 0, b, d = [];
		if (!c) c = this.length;
		if (c<0) c = this.length + c;
		if (a<0) a = this.length - a;
		if (c<a) {
			b = a;
			a = c;
			c = b;
		}
		for (i; i<c - a; i++) d[i] = this[a + i];
		return d;
	}
	,splice: function(a,c) {
		var i = 0,e = arguments,d = this.copy(),f = a;
		if (!c) c = this.length - a;
		for (i; i<e.length - 2; i++) {
			this[a + i] = e[i + 2];
		}
		for (a; a<this.length - c; a++) {
			this[a + e.length - 2] = d[a - c];
		}
		this.length -= c - e.length + 2;
		return d.slice(f,f + c);
	}
	,unshift: function(a) {
		this.reverse();
		var b = this.push(a);
		this.reverse();
		return b;
	}*/

	// todo: rshift lshift
//	Array.prototype.rshift = function(n) {
//		for (var i=0; i < n; i++) {
//			this.unshift(this.pop());
//		};
//		return this;
//	}
//
//	Array.prototype.lshift = function(n) {
//		for (var i=0; i < n; i++) {
//			this.push(this.shift());
//		};
//		return this;
//	}

});


/*! color */
if (window.color===undefined) {
	window.color = function() {
		var o = {};
		var iClr = 0;
		var iLen = 6;
		var FF = Math.pow(2,8)-1;
		//var FFFFFF = Math.pow(2,24)-1;
		//
		var iR = arguments[0]||0;
		var iG = arguments[1]||0;
		var iB = arguments[2]||0;
		var iA = arguments[3]|1;
		switch (arguments.length) {
			case 0: o.integer = iClr = Math.floor(Math.random()*Math.pow(2,24)); break;
			case 1: 
				if (typeof(iR)=='string') {
					var s = iR.replace('#','');
					if (s.length===3) s = s.substr(0,1)+s.substr(0,1)+s.substr(1,1)+s.substr(1,1)+s.substr(2,1)+s.substr(2,1);
					o.integer = iClr = eval('0x'+s);
				} else o.integer = iClr = iR<255?iR<<16|iR<<8|iR:iR;
			break;
			case 2: o.integer = iClr = iR; break;
			case 3: o.integer = iClr = iR<<16|iG<<8|iB; break;
		}

		function makeRGB() {
			o.r = iR = (iClr>>16)&FF;
			o.g = iG = (iClr>>8)&FF;
			o.b = iB = iClr&FF;
		}

		function rgba(alpha) {
			if (alpha!==undefined) iA = alpha;
			o.rgba = 'rgba('+iR+','+iG+','+iB+','+iA+'))';
			return o.rgba;
		}

		function makeHex() {
			o.hex = '#'+iClr.toString(16).pad(iLen,'0',false);
		}

		function setColor(i) {
			o.integer = iClr = i;
			makeRGB();
			makeHex();
			return o;
		}

		function addColor(c) {
			if (!isColor(c)) c = color(c);
			o.r = iR = Math.min(iR+c.r,FF);
			o.g = iG = Math.min(iG+c.g,FF);
			o.b = iB = Math.min(iB+c.b,FF);
			o.integer = iClr = iR<<16|iG<<8|iB;
			makeHex();
			return o;
		}

		function subtract(c) {
			if (!isColor(c)) c = color(c);
			o.r = iR = Math.max(iR-c.r,0);
			o.g = iG = Math.max(iG-c.g,0);
			o.b = iB = Math.max(iB-c.b,0);
			o.integer = iClr = iR<<16|iG<<8|iB;
			makeHex();
			return o;
		}

		function average(c,p) {
			if (!isColor(c)) c = color(c);
			if (p===undefined) p = .5;
			var h = 1-p;
			o.r = iR = Math.round(h*iR+p*c.r);
			o.g = iG = Math.round(h*iG+p*c.g,FF);
			o.b = iB = Math.round(h*iB+p*c.b,FF);
			o.integer = iClr = iR<<16|iG<<8|iB;
			makeHex();
			return o;
		}

		function isColor(c) {
			if (!c) return false;
			for (var s in o) if (c.hasOwnProperty(s)!==o.hasOwnProperty(s)) return false;
			return true;
		}

		makeRGB();
		makeHex();
		o.toString = function(){return iA===1?o.hex:o.rgba};
		o.set = setColor;
		o.rgba = rgba;
		o.add = addColor;
		o.subtract = subtract;
		o.average = average;
		return o;
	}
}

/*! type */
if (type===undefined) {
	var type = function(o){
		type.UNDEFINED = 0;
		type.NULL = 1;

		type.OBJECT = 2;
		type.ARRAY = 21;
		type.NODE = 22;
		type.EVENT = 23;

		type.FUNCTION = 3;

		type.STRING = 4;
		type.BOOLEAN = 5;
		type.INT = 6;
		type.FLOAT = 7;

		type.s = function(o,check){
			if (check===undefined) check = true;
			var iType = check?type(o):o;
			var s;
			switch (iType) {
				case type.UNDEFINED: s = 'undefined'; break;
				case type.NULL: s = 'null'; break;

				case type.OBJECT: s = 'Object'; break;
				case type.ARRAY: s = 'Array'; break;
				case type.NODE: s = 'Node'; break;
				case type.EVENT: s = 'Event'; break;

				case type.FUNCTION: s = 'function'; break;
				case type.REGEXP: s = 'RegExp'; break;

				case type.STRING: s = 'String'; break;
				case type.BOOLEAN: s = 'boolean'; break;
				case type.INT: s = 'int'; break;
				case type.FLOAT: s = 'float'; break;
			}
			return s;
		};
		var i = 0;
		if (o===null) {
			i = type.NULL;
		} else {
			switch (typeof(o)){
			case 'object':
				var c = o.constructor;
				if (c===Array) i = type.ARRAY;
				else if (o.ownerDocument!==undefined) i = type.NODE;
				else if ((function(){
					var bE = true;
					var aE = [
						'eventPhase'
						,'currentTarget'
						,'cancelable'
						,'target'
						,'bubbles'
						,'type'
						,'cancelBubble'
						,'srcElement'
						,'defaultPrevented'
						,'timeStamp'
						,'returnValue'
					];
					for (var s in aE) {
						if (aE.hasOwnProperty(s)) {
							if (o[aE[s]]===undefined) {
								bE = false;
								break;
							}
						}
					}
					return bE;
				})()) i = type.EVENT;
				else i = type.OBJECT; 
			break;
			case 'function': i = type.FUNCTION; break;
			case 'string': i = type.STRING; break;
			case 'boolean': i = type.BOOLEAN; break;
			case 'number': i = o===Math.round(o)?type.INT:type.FLOAT; break;
			}
		}
		return i;
	};
}
(function(obj,fns){
	var p = obj.prototype;
	for (var s in fns) if (!obj[s]) p[s] = fns[s];
})(String,{
	pad: function(length,chr,left){
		if (left===undefined) left = false;
		var iFill = Math.max(0,length-this.length);
		var aFill = [];
		for (var i=0;i<iFill;i++) aFill.push(chr);
		return left?(aFill.join('')+this):(this+aFill.join(''));
	}
	,toType: function(){
		// integer
		var i = parseInt(this);
		if (i.toString()==this) return i;
		// floating point
		var f = parseFloat(this);
		if (f.toString()==this) return f;
		// boolean
		var b = this=='true'||(this=='false'?false:null);
		if (b!==null) return b;
		//
		return this;
	}
	,generate: function(iLen,bCut) {
		var isInt = function(n) {
			return (n%1)===0;
		}
		var rand = function(fStr,fEnd) {
			var fNum = fStr + Math.random()*(fEnd-fStr);
			return (isInt(fStr)&&isInt(fEnd))?Math.round(fNum):fNum;
		}
		if (iLen===undefined) iLen = 6;
		if (bCut===undefined) bCut = false;
		var aLtr = [
			['a','e','i','o','u','y']
			,['aa','ai','au','ea','ee','ei','eu','ia','ie','io','iu','oa','oe','oi','ua','ui']
			,['b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','z']
			,['bb','br','bs','cc','ch','cl','cr','db','dd','df','dg','dh','dj','dk','dl','dm','dn','dp','dq','dr','ds','dt','dv','dw','dz','fb','fd','ff','fg','fh','fj','fk','fl','fm','fn','fp','fq','fr','fs','ft','fv','fw','fz','gb','gd','gf','gg','gh','gj','gk','gl','gm','gn','gp','gq','gr','gs','gt','gv','gw','gz','kb','kd','kf','kg','kh','kj','kk','kl','km','kn','kp','kq','kr','ks','kt','kv','kw','kz','lb','ld','lf','lg','lh','lj','lk','ll','lm','ln','lp','lq','lr','ls','lt','lv','lw','lz','mb','md','mf','mg','mh','mj','mk','ml','mm','mn','mp','mq','mr','ms','mt','mv','mw','mz','nb','nd','nf','ng','nh','nj','nk','nl','nm','nn','np','nq','nr','ns','nt','nv','nw','nz','pb','pd','pf','pg','ph','pj','pk','pl','pm','pn','pp','pq','pr','ps','pt','pv','pw','pz','qb','qd','qf','qg','qh','qj','qk','ql','qm','qn','qp','qq','qr','qs','qt','qv','qw','qz','rb','rd','rf','rg','rh','rj','rk','rl','rm','rn','rp','rq','rr','rs','rt','rv','rw','rz','sb','sc','sd','sf','sg','sh','sj','sk','sl','sm','sn','sp','sq','sr','ss','st','sv','sw','sz','tb','td','tf','tg','th','tj','tk','tl','tm','tn','tp','tq','tr','ts','tt','tv','tw','tz','vb','vd','vf','vg','vh','vj','vk','vl','vm','vn','vp','vq','vr','vs','vt','vv','vw','vz','xb','xd','xf','xg','xh','xj','xk','xl','xm','xn','xp','xq','xr','xs','xt','xv','xw','xx','xz']
		];
		var iSnm = 6;
		var sPsw = "";
		var iNum = 0;
		for (var i=0;i<iSnm;i++) {
			if (i==0)			iNum = rand(0,2);
			else if (i==iSnm-1)	iNum = (iNum<2)?2:rand(0,1);
			else				iNum = (iNum<2)?rand(0,1)+2:rand(0,1);
			var aLst = aLtr[iNum];
			sPsw += aLst[ rand(0,aLst.length-1) ];
		}
		return bCut?sPsw.substr(0,iLen):sPsw;
	}
//	,upperCase: function(){} // todo: case fns
//	,lowerCase: function(){}
//	,switchCase: function(){}

// reverse case with array indexing
//	int main()
//{
//  int i;
//  char str[80] = "This Is A Test";
//
//  cout << "Original string: " << str << "\n";
//
//  for(i = 0; str[i]; i++) {
//    if(isupper(str[i]))
//      str[i] = tolower(str[i]);
//    else if(islower(str[i]))
//      str[i] = toupper(str[i]);
//  }
//
//  cout << "Inverted-case string: " << str;
//
//  return 0;
//}

//String.prototype.capitalize = function () {
//    return this.replace(RegExp("^\\p{L}"), function ($0) { return $0.toUpperCase(); })
//}
});

/*! ImageLoader */
Document.prototype.loadImage = function(uri,callBack,error){
	var mLd = document.createElement('img');
	mLd.setAttribute('src',uri);
	mLd.addEventListener('load',function(e){
		var w = mLd.width;
		var h = mLd.height;
		var mCv = document.createElement('canvas');
		mCv.setAttribute('width',w);
		mCv.setAttribute('height',h);
		var oCt = mCv.getContext('2d');
		oCt.drawImage(mLd,0,0);
		if (callBack!==undefined) callBack.call(this,{
			toString: function(){return 'object [ImageLoader]'}
			,loadEvent:e
			,width:w
			,height:h
			,w:w
			,h:h
			,uri:uri
			,name:uri.split('/').pop()
			,type:uri.split('.').pop()
			,img:mLd
			,canvas:mCv
			,context:oCt
		});
	});
	mLd.addEventListener('error',function(r){
		error(r);
	});
	return {
		toString: function(){return 'object [ImageLoader]'}
		,addEventListener: function(){}
	};
};
if (point===undefined) {
	var point = function(_x,_y) {
		var o = {
			 x:_x
			,y:_y
			,subtract: function(p) {
				o.x -= p.x;
				o.y -= p.y;
				return o;
			}
			,add: function(p) {
				o.x += p.x;
				o.y += p.y;
				return o;
			}
			,multiply: function(f) {
				o.x *= f;
				o.y *= f;
				return o;
			}
			,divide: function(f) {
				o.x /= f;
				o.y /= f;
				return o;
			}
			,size:			function() { return Math.sqrt(o.x*o.x+o.y*o.y); }
			,normalize:		function() { return o.divide(o.size()); }
			,normalized:	function() { return o.clone().normalize(); }
			,radians:		function() { return Math.atan2(o.y,o.x); }
			,angle:			function() { return o.radians()*180; }
			,clone:			function() { return point(o.x,o.y); }
			,toString:		function() { return '[object point '+o.x+', '+o.y+']'; }
		};
		return o;
	}
}
// todo: write unit tests
// see http://paulirish.com/2011/requestanimationframe-for-smart-animating/

// shim layer with setTimeout fallback

    window.requestAnimFrame = (function(){
      return  window.requestAnimationFrame       || 
              window.webkitRequestAnimationFrame || 
              window.mozRequestAnimationFrame    || 
              window.oRequestAnimationFrame      || 
              window.msRequestAnimationFrame     || 
              function(callback, element){
                window.setTimeout(function(){
                    callback(+new Date);
                }, 1000 / 60);
              };
    })();

/*
 * Pixastic Lib - Core Functions - v0.1.3
 * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
 * License: [http://www.pixastic.com/lib/license.txt]
 */

var Pixastic = (function() {


	function addEvent(el, event, handler) {
		if (el.addEventListener)
			el.addEventListener(event, handler, false); 
		else if (el.attachEvent)
			el.attachEvent("on" + event, handler); 
	}

	function onready(handler) {
		var handlerDone = false;
		var execHandler = function() {
			if (!handlerDone) {
				handlerDone = true;
				handler();
			}
		}
		document.write("<"+"script defer src=\"//:\" id=\"__onload_ie_pixastic__\"></"+"script>");
		var script = document.getElementById("__onload_ie_pixastic__");
		script.onreadystatechange = function() {
			if (script.readyState == "complete") {
				script.parentNode.removeChild(script);
				execHandler();
			}
		}
		if (document.addEventListener)
			document.addEventListener("DOMContentLoaded", execHandler, false); 
		addEvent(window, "load", execHandler);
	}

	function init() {
		var imgEls = getElementsByClass("pixastic", null, "img");
		var canvasEls = getElementsByClass("pixastic", null, "canvas");
		var elements = imgEls.concat(canvasEls);
		for (var i=0;i<elements.length;i++) {
			(function() {

			var el = elements[i];
			var actions = [];
			var classes = el.className.split(" ");
			for (var c=0;c<classes.length;c++) {
				var cls = classes[c];
				if (cls.substring(0,9) == "pixastic-") {
					var actionName = cls.substring(9);
					if (actionName != "")
						actions.push(actionName);
				}
			}
			if (actions.length) {
				if (el.tagName.toLowerCase() == "img") {
					var dataImg = new Image();
					dataImg.src = el.src;
					if (dataImg.complete) {
						for (var a=0;a<actions.length;a++) {
							var res = Pixastic.applyAction(el, el, actions[a], null);
							if (res) 
								el = res;
						}
					} else {
						dataImg.onload = function() {
							for (var a=0;a<actions.length;a++) {
								var res = Pixastic.applyAction(el, el, actions[a], null)
								if (res) 
									el = res;
							}
						}
					}
				} else {
					setTimeout(function() {
						for (var a=0;a<actions.length;a++) {
							var res = Pixastic.applyAction(
								el, el, actions[a], null
							);
							if (res) 
								el = res;
						}
					},1);
				}
			}

			})();
		}
	}

	if (typeof pixastic_parseonload != "undefined" && pixastic_parseonload)
		onready(init);

	// getElementsByClass by Dustin Diaz, http://www.dustindiaz.com/getelementsbyclass/
	function getElementsByClass(searchClass,node,tag) {
	        var classElements = new Array();
	        if ( node == null )
	                node = document;
	        if ( tag == null )
	                tag = '*';

	        var els = node.getElementsByTagName(tag);
	        var elsLen = els.length;
	        var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
	        for (i = 0, j = 0; i < elsLen; i++) {
	                if ( pattern.test(els[i].className) ) {
	                        classElements[j] = els[i];
	                        j++;
	                }
	        }
	        return classElements;
	}

	var debugElement;

	function writeDebug(text, level) {
		if (!Pixastic.debug) return;
		try {
			switch (level) {
				case "warn" : 
					console.warn("Pixastic:", text);
					break;
				case "error" :
					console.error("Pixastic:", text);
					break;
				default:
					console.log("Pixastic:", text);
			}
		} catch(e) {
		}
		if (!debugElement) {
			
		}
	}

	// canvas capability checks

	var hasCanvas = (function() {
		var c = document.createElement("canvas");
		var val = false;
		try {
			val = !!((typeof c.getContext == "function") && c.getContext("2d"));
		} catch(e) {}
		return function() {
			return val;
		}
	})();

	var hasCanvasImageData = (function() {
		var c = document.createElement("canvas");
		var val = false;
		var ctx;
		try {
			if (typeof c.getContext == "function" && (ctx = c.getContext("2d"))) {
				val = (typeof ctx.getImageData == "function");
			}
		} catch(e) {}
		return function() {
			return val;
		}
	})();

	var hasGlobalAlpha = (function() {
		var hasAlpha = false;
		var red = document.createElement("canvas");
		if (hasCanvas() && hasCanvasImageData()) {
			red.width = red.height = 1;
			var redctx = red.getContext("2d");
			redctx.fillStyle = "rgb(255,0,0)";
			redctx.fillRect(0,0,1,1);
	
			var blue = document.createElement("canvas");
			blue.width = blue.height = 1;
			var bluectx = blue.getContext("2d");
			bluectx.fillStyle = "rgb(0,0,255)";
			bluectx.fillRect(0,0,1,1);
	
			redctx.globalAlpha = 0.5;
			redctx.drawImage(blue, 0, 0);
			var reddata = redctx.getImageData(0,0,1,1).data;
	
			hasAlpha = (reddata[2] != 255);
		}
		return function() {
			return hasAlpha;
		}
	})();


	// return public interface

	return {

		parseOnLoad : false,

		debug : false,
		
		applyAction : function(img, dataImg, actionName, options) {

			options = options || {};

			var imageIsCanvas = (img.tagName.toLowerCase() == "canvas");
			if (imageIsCanvas && Pixastic.Client.isIE()) {
				if (Pixastic.debug) writeDebug("Tried to process a canvas element but browser is IE.");
				return false;
			}

			var canvas, ctx;
			var hasOutputCanvas = false;
			if (Pixastic.Client.hasCanvas()) {
				hasOutputCanvas = !!options.resultCanvas;
				canvas = options.resultCanvas || document.createElement("canvas");
				ctx = canvas.getContext("2d");
			}

			var w = img.offsetWidth;
			var h = img.offsetHeight;

			if (imageIsCanvas) {
				w = img.width;
				h = img.height;
			}

			// offsetWidth/Height might be 0 if the image is not in the document
			if (w == 0 || h == 0) {
				if (img.parentNode == null) {
					// add the image to the doc (way out left), read its dimensions and remove it again
					var oldpos = img.style.position;
					var oldleft = img.style.left;
					img.style.position = "absolute";
					img.style.left = "-9999px";
					document.body.appendChild(img);
					w = img.offsetWidth;
					h = img.offsetHeight;
					document.body.removeChild(img);
					img.style.position = oldpos;
					img.style.left = oldleft;
				} else {
					if (Pixastic.debug) writeDebug("Image has 0 width and/or height.");
					return;
				}
			}

			if (actionName.indexOf("(") > -1) {
				var tmp = actionName;
				actionName = tmp.substr(0, tmp.indexOf("("));
				var arg = tmp.match(/\((.*?)\)/);
				if (arg[1]) {
					arg = arg[1].split(";");
					for (var a=0;a<arg.length;a++) {
						thisArg = arg[a].split("=");
						if (thisArg.length == 2) {
							if (thisArg[0] == "rect") {
								var rectVal = thisArg[1].split(",");
								options[thisArg[0]] = {
									left : parseInt(rectVal[0],10)||0,
									top : parseInt(rectVal[1],10)||0,
									width : parseInt(rectVal[2],10)||0,
									height : parseInt(rectVal[3],10)||0
								}
							} else {
								options[thisArg[0]] = thisArg[1];
							}
						}
					}
				}
			}

			if (!options.rect) {
				options.rect = {
					left : 0, top : 0, width : w, height : h
				};
			} else {
				options.rect.left = Math.round(options.rect.left);
				options.rect.top = Math.round(options.rect.top);
				options.rect.width = Math.round(options.rect.width);
				options.rect.height = Math.round(options.rect.height);
			}

			var validAction = false;
			if (Pixastic.Actions[actionName] && typeof Pixastic.Actions[actionName].process == "function") {
				validAction = true;
			}
			if (!validAction) {
				if (Pixastic.debug) writeDebug("Invalid action \"" + actionName + "\". Maybe file not included?");
				return false;
			}
			if (!Pixastic.Actions[actionName].checkSupport()) {
				if (Pixastic.debug) writeDebug("Action \"" + actionName + "\" not supported by this browser.");
				return false;
			}

			if (Pixastic.Client.hasCanvas()) {
				if (canvas !== img) {
					canvas.width = w;
					canvas.height = h;
				}
				if (!hasOutputCanvas) {
					canvas.style.width = w+"px";
					canvas.style.height = h+"px";
				}
				ctx.drawImage(dataImg,0,0,w,h);

				if (!img.__pixastic_org_image) {
					canvas.__pixastic_org_image = img;
					canvas.__pixastic_org_width = w;
					canvas.__pixastic_org_height = h;
				} else {
					canvas.__pixastic_org_image = img.__pixastic_org_image;
					canvas.__pixastic_org_width = img.__pixastic_org_width;
					canvas.__pixastic_org_height = img.__pixastic_org_height;
				}

			} else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style == "undefined") {
				img.__pixastic_org_style = img.style.cssText;
			}

			var params = {
				image : img,
				canvas : canvas,
				width : w,
				height : h,
				useData : true,
				options : options
			}

			// Ok, let's do it!

			var res = Pixastic.Actions[actionName].process(params);

			if (!res) {
				return false;
			}

			if (Pixastic.Client.hasCanvas()) {
				if (params.useData) {
					if (Pixastic.Client.hasCanvasImageData()) {
						canvas.getContext("2d").putImageData(params.canvasData, options.rect.left, options.rect.top);

						// Opera doesn't seem to update the canvas until we draw something on it, lets draw a 0x0 rectangle.
						// Is this still so?
						canvas.getContext("2d").fillRect(0,0,0,0);
					}
				}

				if (!options.leaveDOM) {
					// copy properties and stuff from the source image
					canvas.title = img.title;
					canvas.imgsrc = img.imgsrc;
					if (!imageIsCanvas) canvas.alt  = img.alt;
					if (!imageIsCanvas) canvas.imgsrc = img.src;
					canvas.className = img.className;
					canvas.style.cssText = img.style.cssText;
					canvas.name = img.name;
					canvas.tabIndex = img.tabIndex;
					canvas.id = img.id;
					if (img.parentNode && img.parentNode.replaceChild) {
						img.parentNode.replaceChild(canvas, img);
					}
				}

				options.resultCanvas = canvas;

				return canvas;
			}

			return img;
		},

		prepareData : function(params, getCopy) {
			var ctx = params.canvas.getContext("2d");
			var rect = params.options.rect;
			var dataDesc = ctx.getImageData(rect.left, rect.top, rect.width, rect.height);
			var data = dataDesc.data;
			if (!getCopy) params.canvasData = dataDesc;
			return data;
		},

		// load the image file
		process : function(img, actionName, options, callback) {
			if (img.tagName.toLowerCase() == "img") {
				var dataImg = new Image();
				dataImg.src = img.src;
				if (dataImg.complete) {
					var res = Pixastic.applyAction(img, dataImg, actionName, options);
					if (callback) callback(res);
					return res;
				} else {
					dataImg.onload = function() {
						var res = Pixastic.applyAction(img, dataImg, actionName, options)
						if (callback) callback(res);
					}
				}
			}
			if (img.tagName.toLowerCase() == "canvas") {
				var res = Pixastic.applyAction(img, img, actionName, options);
				if (callback) callback(res);
				return res;
			}
		},

		revert : function(img) {
			if (Pixastic.Client.hasCanvas()) {
				if (img.tagName.toLowerCase() == "canvas" && img.__pixastic_org_image) {
					img.width = img.__pixastic_org_width;
					img.height = img.__pixastic_org_height;
					img.getContext("2d").drawImage(img.__pixastic_org_image, 0, 0);

					if (img.parentNode && img.parentNode.replaceChild) {
						img.parentNode.replaceChild(img.__pixastic_org_image, img);
					}

					return img;
				}
			} else if (Pixastic.Client.isIE()) {
 				if (typeof img.__pixastic_org_style != "undefined")
					img.style.cssText = img.__pixastic_org_style;
			}
		},

		Client : {
			hasCanvas : hasCanvas,
			hasCanvasImageData : hasCanvasImageData,
			hasGlobalAlpha : hasGlobalAlpha,
			isIE : function() {
				return !!document.all && !!window.attachEvent && !window.opera;
			}
		},

		Actions : {}
	}


})();

/*
 * Pixastic Lib - HSL Adjust  - v0.1.1
 * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
 * License: [http://www.pixastic.com/lib/license.txt]
 */

Pixastic.Actions.hsl = {
	process : function(params) {

		var hue = parseInt(params.options.hue,10)||0;
		var saturation = (parseInt(params.options.saturation,10)||0) / 100;
		var lightness = (parseInt(params.options.lightness,10)||0) / 100;


		// this seems to give the same result as Photoshop
		if (saturation < 0) {
			var satMul = 1+saturation;
		} else {
			var satMul = 1+saturation*2;
		}

		hue = (hue%360) / 360;
		var hue6 = hue * 6;

		var rgbDiv = 1 / 255;

		var light255 = lightness * 255;
		var lightp1 = 1 + lightness;
		var lightm1 = 1 - lightness;
		if (Pixastic.Client.hasCanvasImageData()) {
			var data = Pixastic.prepareData(params);

			var rect = params.options.rect;

			var p = rect.width * rect.height;

			var pix = p*4, pix1 = pix + 1, pix2 = pix + 2, pix3 = pix + 3;

			while (p--) {

				var r = data[pix-=4];
				var g = data[pix1=pix+1];
				var b = data[pix2=pix+2];

				if (hue != 0 || saturation != 0) {
					// ok, here comes rgb to hsl + adjust + hsl to rgb, all in one jumbled mess. 
					// It's not so pretty, but it's been optimized to get somewhat decent performance.
					// The transforms were originally adapted from the ones found in Graphics Gems, but have been heavily modified.
					var vs = r;
					if (g > vs) vs = g;
					if (b > vs) vs = b;
					var ms = r;
					if (g < ms) ms = g;
					if (b < ms) ms = b;
					var vm = (vs-ms);
					var l = (ms+vs)/510;
					if (l > 0) {
						if (vm > 0) {
							if (l <= 0.5) {
								var s = vm / (vs+ms) * satMul;
								if (s > 1) s = 1;
								var v = (l * (1+s));
							} else {
								var s = vm / (510-vs-ms) * satMul;
								if (s > 1) s = 1;
								var v = (l+s - l*s);
							}
							if (r == vs) {
								if (g == ms)
									var h = 5 + ((vs-b)/vm) + hue6;
								else
									var h = 1 - ((vs-g)/vm) + hue6;
							} else if (g == vs) {
								if (b == ms)
									var h = 1 + ((vs-r)/vm) + hue6;
								else
									var h = 3 - ((vs-b)/vm) + hue6;
							} else {
								if (r == ms)
									var h = 3 + ((vs-g)/vm) + hue6;
								else
									var h = 5 - ((vs-r)/vm) + hue6;
							}
							if (h < 0) h+=6;
							if (h >= 6) h-=6;
							var m = (l+l-v);
							var sextant = h>>0;
							if (sextant == 0) {
								r = v*255; g = (m+((v-m)*(h-sextant)))*255; b = m*255;
							} else if (sextant == 1) {
								r = (v-((v-m)*(h-sextant)))*255; g = v*255; b = m*255;
							} else if (sextant == 2) {
								r = m*255; g = v*255; b = (m+((v-m)*(h-sextant)))*255;
							} else if (sextant == 3) {
								r = m*255; g = (v-((v-m)*(h-sextant)))*255; b = v*255;
							} else if (sextant == 4) {
								r = (m+((v-m)*(h-sextant)))*255; g = m*255; b = v*255;
							} else if (sextant == 5) {
								r = v*255; g = m*255; b = (v-((v-m)*(h-sextant)))*255;
							}
						}
					}
				}

				if (lightness < 0) {
					r *= lightp1;
					g *= lightp1;
					b *= lightp1;
				} else if (lightness > 0) {
					r = r * lightm1 + light255;
					g = g * lightm1 + light255;
					b = b * lightm1 + light255;
				}

				if (r < 0) 
					data[pix] = 0
				else if (r > 255)
					data[pix] = 255
				else
					data[pix] = r;

				if (g < 0) 
					data[pix1] = 0
				else if (g > 255)
					data[pix1] = 255
				else
					data[pix1] = g;

				if (b < 0) 
					data[pix2] = 0
				else if (b > 255)
					data[pix2] = 255
				else
					data[pix2] = b;

			}

			return true;
		}
	},
	checkSupport : function() {
		return Pixastic.Client.hasCanvasImageData();
	}

}

// tween.js r3 - http://github.com/sole/tween.js
var TWEEN=TWEEN||function(){var a,e,c,b=[];return{start:function(g){c=setInterval(this.update,1E3/(g||60))},stop:function(){clearInterval(c)},add:function(g){b.push(g)},getAll:function(){return b},removeAll:function(){b=[]},remove:function(g){a=b.indexOf(g);a!==-1&&b.splice(a,1)},update:function(g){a=0;e=b.length;for(g=g||(new Date).getTime();a<e;)if(b[a].update(g))a++;else{b.splice(a,1);e--}}}}();
TWEEN.Tween=function(a){var e={},c={},b={},g=1E3,i=0,j=null,n=TWEEN.Easing.Linear.EaseNone,k=null,l=null,m=null;this.to=function(d,f){if(f!==null)g=f;for(var h in d)if(a[h]!==null)b[h]=d[h];return this};this.start=function(d){TWEEN.add(this);j=d?d+i:(new Date).getTime()+i;for(var f in b)if(a[f]!==null){e[f]=a[f];c[f]=b[f]-a[f]}return this};this.stop=function(){TWEEN.remove(this);return this};this.delay=function(d){i=d;return this};this.easing=function(d){n=d;return this};this.chain=function(d){k=
d};this.onUpdate=function(d){l=d;return this};this.onComplete=function(d){m=d;return this};this.update=function(d){var f,h;if(d<j)return true;d=(d-j)/g;d=d>1?1:d;h=n(d);for(f in c)a[f]=e[f]+c[f]*h;l!==null&&l.call(a,h);if(d==1){m!==null&&m.call(a);k!==null&&k.start();return false}return true}};TWEEN.Easing={Linear:{},Quadratic:{},Cubic:{},Quartic:{},Quintic:{},Sinusoidal:{},Exponential:{},Circular:{},Elastic:{},Back:{},Bounce:{}};TWEEN.Easing.Linear.EaseNone=function(a){return a};
TWEEN.Easing.Quadratic.EaseIn=function(a){return a*a};TWEEN.Easing.Quadratic.EaseOut=function(a){return-a*(a-2)};TWEEN.Easing.Quadratic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a;return-0.5*(--a*(a-2)-1)};TWEEN.Easing.Cubic.EaseIn=function(a){return a*a*a};TWEEN.Easing.Cubic.EaseOut=function(a){return--a*a*a+1};TWEEN.Easing.Cubic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a;return 0.5*((a-=2)*a*a+2)};TWEEN.Easing.Quartic.EaseIn=function(a){return a*a*a*a};
TWEEN.Easing.Quartic.EaseOut=function(a){return-(--a*a*a*a-1)};TWEEN.Easing.Quartic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a;return-0.5*((a-=2)*a*a*a-2)};TWEEN.Easing.Quintic.EaseIn=function(a){return a*a*a*a*a};TWEEN.Easing.Quintic.EaseOut=function(a){return(a-=1)*a*a*a*a+1};TWEEN.Easing.Quintic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a*a;return 0.5*((a-=2)*a*a*a*a+2)};TWEEN.Easing.Sinusoidal.EaseIn=function(a){return-Math.cos(a*Math.PI/2)+1};
TWEEN.Easing.Sinusoidal.EaseOut=function(a){return Math.sin(a*Math.PI/2)};TWEEN.Easing.Sinusoidal.EaseInOut=function(a){return-0.5*(Math.cos(Math.PI*a)-1)};TWEEN.Easing.Exponential.EaseIn=function(a){return a==0?0:Math.pow(2,10*(a-1))};TWEEN.Easing.Exponential.EaseOut=function(a){return a==1?1:-Math.pow(2,-10*a)+1};TWEEN.Easing.Exponential.EaseInOut=function(a){if(a==0)return 0;if(a==1)return 1;if((a*=2)<1)return 0.5*Math.pow(2,10*(a-1));return 0.5*(-Math.pow(2,-10*(a-1))+2)};
TWEEN.Easing.Circular.EaseIn=function(a){return-(Math.sqrt(1-a*a)-1)};TWEEN.Easing.Circular.EaseOut=function(a){return Math.sqrt(1- --a*a)};TWEEN.Easing.Circular.EaseInOut=function(a){if((a/=0.5)<1)return-0.5*(Math.sqrt(1-a*a)-1);return 0.5*(Math.sqrt(1-(a-=2)*a)+1)};TWEEN.Easing.Elastic.EaseIn=function(a){var e,c=0.1,b=0.4;if(a==0)return 0;if(a==1)return 1;b||(b=0.3);if(!c||c<1){c=1;e=b/4}else e=b/(2*Math.PI)*Math.asin(1/c);return-(c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/b))};
TWEEN.Easing.Elastic.EaseOut=function(a){var e,c=0.1,b=0.4;if(a==0)return 0;if(a==1)return 1;b||(b=0.3);if(!c||c<1){c=1;e=b/4}else e=b/(2*Math.PI)*Math.asin(1/c);return c*Math.pow(2,-10*a)*Math.sin((a-e)*2*Math.PI/b)+1};
TWEEN.Easing.Elastic.EaseInOut=function(a){var e,c=0.1,b=0.4;if(a==0)return 0;if(a==1)return 1;b||(b=0.3);if(!c||c<1){c=1;e=b/4}else e=b/(2*Math.PI)*Math.asin(1/c);if((a*=2)<1)return-0.5*c*Math.pow(2,10*(a-=1))*Math.sin((a-e)*2*Math.PI/b);return c*Math.pow(2,-10*(a-=1))*Math.sin((a-e)*2*Math.PI/b)*0.5+1};TWEEN.Easing.Back.EaseIn=function(a){return a*a*(2.70158*a-1.70158)};TWEEN.Easing.Back.EaseOut=function(a){return(a-=1)*a*(2.70158*a+1.70158)+1};
TWEEN.Easing.Back.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*(3.5949095*a-2.5949095);return 0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)};TWEEN.Easing.Bounce.EaseIn=function(a){return 1-TWEEN.Easing.Bounce.EaseOut(1-a)};TWEEN.Easing.Bounce.EaseOut=function(a){return(a/=1)<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375};
TWEEN.Easing.Bounce.EaseInOut=function(a){if(a<0.5)return TWEEN.Easing.Bounce.EaseIn(a*2)*0.5;return TWEEN.Easing.Bounce.EaseOut(a*2-1)*0.5+0.5};

/*!
* CANVASIMG 0.5.7
* Copyright (c) 2010 Ron Valstar http://www.sjeiti.com/
*
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*/
/*
*
* todo:
*	- maybe make toDataURL target string instead of boolean
*	- build in a scale for cpu intensive operations like Perlin Noise (alpha can easily be scaled down four times without being noticeably uglier)
*
* in this update:
*	- added transitions: fold and flip (working on pageflip)
*
* 0.5.6
*	- props overwrite defaults (so do not use defaults in calculations)
*
* 0.5.5
*	- new transition: zoom
*	- implemented toDataURL
*	- cleaned up target.constructor===default
*	- changed time calculation
*	- global default variables
*	- built in timeReset for time consuming initialisations
*	- major internal refactoring for transitions: init-from-to functions
*
* 0.5.4
*	- new transition: drip
*
* 0.5.3
*	- new transitions: square, wave, noise and simplexNoise
*	- added code to prevent double transitions onto a target
*	- added code so toImg can also be a String
*	- readjusted particles to calculate the height of the glyph in order to find the exact center
*	- if there's only one particle it will always center
*/
if (!CIMG) {
	var CIMG = function() {
		function trace() { try {console.log.apply(console, arguments);} catch (e) {} }
		try { TWEEN; } catch (err) { alert("You need to include Sole's tween.js"); return; }
		var bCanvas = !!document.createElement('canvas').getContext;
		if (!bCanvas) trace("The canvas element is not supported in this browser.");
		var o = {
			 transition:	{}
			,constructor:	null
			,id:			"CanvasImg"
			,version:		"0.5.7"
			,defaults: { // global variables
				 globalScale:	1 // todo: implement global
				,toDataURL:		false // todo: implement global, with "image/jpeg",.1  and   "image/png"
				,tweenType:		TWEEN.Easing.Linear.EaseNone
				,transition:	null
				,time:			1000
				,frameRate:		42 // 1000/24 = 41,67
				,exists:		"ignore" //  ignore / append / replace
			}
			,toString:		function() {
				return "[object CANVASIMG]";
			}
		};
		var oTransitions = {};
		//
		function newCanvasFor(img) {
			var oCanvas = document.createElement("canvas");
			oCanvas.width  = img.width;
			oCanvas.height = img.height;
			return oCanvas;
		}
		//
		function imageToCanvas(canvas,img) {
			if (img.constructor===String) {
				var mImg = document.createElement('img');
				mImg.setAttribute('src',img);
				mImg.onload = function(){
					 imageToCanvas(canvas,mImg);
				};
				return;
			}
			var oCtx = canvas.getContext("2d");
			var iW = oCtx.canvas.width;
			var iH = oCtx.canvas.height;
			oCtx.drawImage(img, 0,0,iW,iH);
			return oCtx;
		}
		//
		var iIdNrs = 0;
		function getIdFor(target) {
			iIdNrs++;
			var sId = "cimgid"+iIdNrs;
			target.setAttribute("id",sId);
			return sId;
		}
		//
		function toDataUrl(target,p) {
			switch (target.constructor) {
				case HTMLCanvasElement: case CanvasRenderingContext2D: break;
				case HTMLImageElement: target.setAttribute("src",p.canvas.toDataURL("image/jpeg")); break;// "image/jpeg" // "image/png"
				default: target.style.backgroundImage = "url("+p.canvas.toDataURL("image/jpeg")+")";
			}
		}
		//
		function removeTransition(target,end,callback) {
			var sId = target.getAttribute("id");
			var p = oTransitions[sId];
			if (p.timer) {
				clearInterval(p.timer);
				delete p.timer;
			}
			if (p.canvas!==undefined) {
				switch (target.constructor) {
					case HTMLImageElement:
						if (end) target.setAttribute('src',p.toImg.getAttribute('src'));
						else toDataUrl(target,p);
						if (!p.toDataURL) {
							target.style.display = p.canvas.style.display;
							p.canvas.parentNode.removeChild(p.canvas);
						}
					break;
					case HTMLCanvasElement: case CanvasRenderingContext2D:
						if (end) imageToCanvas(p.canvas,p.toImg);
					break;
					default:
						if (end) target.style.backgroundImage = "url("+p.toImg.getAttribute("src")+")";
						else toDataUrl(target,p);
						if (!p.toDataURL) p.canvas.parentNode.removeChild(p.canvas);
				}
			}
			if (callback&&p.callback!==undefined) p.callback();
			delete oTransitions[sId];
			return p;
		}
		//
		function tween(target,toImg,time,transition,tweenType,properties) {

			time = time===undefined?o.defaults.time:time;
			transition = transition||o.defaults.transition;
			tweenType = tweenType||o.defaults.tweenType;

			// if canvas is not supported just replace and inmediately do the callback
			if (!bCanvas) {
				var sTo = toImg.constructor===String?toImg:toImg.getAttribute("src");
				switch (target.constructor) {
					case HTMLImageElement: target.setAttribute("src",sTo); break;
					default: target.style.backgroundImage = "url("+sTo+")";
				}
				if (properties.callback!==undefined) properties.callback();
				return false;
			}

			// if target and toImg have the same src's do nothing and do the callback
			if (target.constructor!==HTMLCanvasElement&&target.constructor!==CanvasRenderingContext2D) {
				var sTargetSrc;
				if (target.constructor===HTMLImageElement) {
					sTargetSrc = target.getAttribute("src");
				} else {
					var sBgI = target.style.backgroundImage;
					if (sBgI.substr(4,1)==="\"")	sTargetSrc = sBgI.substring(5,sBgI.length-2);
					else							sTargetSrc = sBgI.substring(4,sBgI.length-1);
				}
				var sToimgSrc;
				if (toImg.constructor===String) {
					sToimgSrc = toImg;
				} else {
					sToimgSrc = toImg.getAttribute("src");
				}
				if (sTargetSrc==sToimgSrc) {
					if (properties.callback!==undefined) properties.callback();
					return false;
				}
			}

			// duplicate the properties (to make sure the object is unique) and append with defaults
			var oProps = {
				extend: function(o) {
					for (var s in o) if (!this.hasOwnProperty(s)) this[s] = o[s];
					return this;
				}
			}.extend(properties).extend(o.defaults);
			//
			// check if the target already has a transition running
			var sId = target.getAttribute("id")||getIdFor(target);
			if (oTransitions[sId]===undefined) {
				oTransitions[sId] = oProps;
			} else {
				switch (oProps.exists) {
					case "ignore": return false; break;
					case "append": return false; break; // todo: chain transitions
					case "replace":
						var oOldProps = removeTransition(target,false,true);
						// using toDataUrl takes some time, hence onload, and since onload does not work on css, we fake it
						var mFake = document.createElement("img");
						mFake.onload = function(){ tween(target,toImg,time,transition,tweenType,oProps); };
						toDataUrl(mFake,oOldProps);
						//setTimeout(function(e){ tween(target,toImg,time,transition,tweenType,props); },100);
						// toDataUrl causes the target height to plummet for a moment
						target.style.width = oOldProps.w+"px";
						target.style.height = oOldProps.h+"px";
						return false;
					break;
				}
			}
			//
			// check if toImg is a string or an img
			var mCnv;
			var oCtx;
			if (toImg.constructor===String) {
				removeTransition(target);
				var mImg = document.createElement('img');
				mImg.setAttribute('src',toImg);
				mImg.onload = function(){
					tween(target,mImg,time,transition,tweenType,oProps);
				}
				// todo: check why png files sometimes do not load
				return true;
			}
			// check the type of the target
			switch (target.constructor) {
				case HTMLImageElement:
					mCnv = newCanvasFor(target);
					oCtx = imageToCanvas(mCnv,target);
					if (!oProps.toDataURL) {
						target.parentNode.insertBefore(mCnv,target);
						// mimic and hide target
						for (var i=0;i<target.style.length;i++){
							var sStyle = target.style[i].replace('-value','');
							mCnv.style.setProperty(sStyle,target.style.getPropertyValue(sStyle),null);
						}
						target.style.display = 'none';
					}
				break;
				case HTMLCanvasElement:
					mCnv = target;
					oCtx = target.getContext("2d");
				break;
				case CanvasRenderingContext2D:
					mCnv = target.canvas;
					oCtx = target;
				break;
				default:
					if (oProps.backgroundImageContext) {
						mCnv = oProps.backgroundImageContext.canvas;
						oCtx = oProps.backgroundImageContext;
					} else {
						var mTempImg = document.createElement("img");
						var sUri;
						var sBgI = target.style.backgroundImage;
						if (sBgI==='') {
							trace("canvasImg warning: The targets background image should be set inline for it to work properly.");
							sUri = toImg.getAttribute("src");
						} else {
							//var aUri = sBgI.match(/[a-z0-9:\.\/\?=_#&%~-]+/gi); // regex doesnt work for data:image/png;base64....
							//sUri = aUri[1];
							// firefox does url("img") while chrome does url(img)
							if (sBgI.substr(4,1)==="\"")	sUri = sBgI.substring(5,sBgI.length-2);
							else							sUri = sBgI.substring(4,sBgI.length-1);
						}
						mTempImg.setAttribute("src",sUri);
						mTempImg.onload = function() {
							if (target.style.position!=="absolute") target.style.position = "relative";
							mCnv = newCanvasFor(mTempImg);
							if (!oProps.toDataURL) {
								mCnv.style.position = "absolute";
								mCnv.style.top = "0px";
								mCnv.style.left = "0px";
								mCnv.style.zIndex = 0;
								// the targets children should be above the canvas
								for (var i=0;i<target.children.length;i++) {
									var mChild = target.children[0];
									if (mChild.style.position!=="absolute") mChild.style.position = "relative";
									if (mChild.style.zIndex==='') mChild.style.zIndex = i+1;
								}
								if (target.children.length===0) target.appendChild(mCnv);
								else target.insertBefore(mCnv,target.children[0]);
							}
							oCtx = imageToCanvas(mCnv,mTempImg);
							oProps.backgroundImageContext = oCtx;
							tween(target,toImg,time,transition,tweenType,oProps);
						};
						removeTransition(target);
						return true;
					}
				break;
			}
			// we really start here
			var iW = mCnv.width;
			var iH = mCnv.height;
			//
			var mCnvFr = document.createElement("canvas");
			mCnvFr.width  = iW;
			mCnvFr.height = iH;
			var oCtxFr = mCnvFr.getContext("2d");
			oCtxFr.drawImage(mCnv, 0,0,iW,iH);
			//
			var mCnvTo = document.createElement("canvas");
			mCnvTo.width  = iW;
			mCnvTo.height = iH;
			var mCtxTo = mCnvTo.getContext("2d");
			toImg; // needed for Firefox buttonbashing (don't ask me why)
			mCtxTo.drawImage(toImg, 0,0,iW,iH);
			//
			var mCnvTmp = document.createElement("canvas");
			mCnvTmp.width  = iW;
			mCnvTmp.height = iH;
			var mCtxTmp = mCnvTmp.getContext("2d");
			//
			// assemble props that are parsed
			oProps.toImg = toImg;
			oProps.r = Math.ceil(.5*Math.sqrt(iW*iW+iH*iH));
			oProps.w = mCnv.width;
			oProps.h = mCnv.height;
			oProps.seed = Math.round(2147483647*Math.random());
			oProps.canvas = mCnv;
			oProps.context = oCtx;
			oProps.canvasFrom = mCnvFr;
			oProps.canvasTo = mCnvTo;
			oProps.contextTmp = mCtxTmp;
			oProps.apply = function(composite,isfrom) {
				if (isfrom) this.context.clearRect(0,0,this.w,this.h);
				this.contextTmp.globalCompositeOperation = composite||"source-in";
				this.contextTmp.fillStyle = this.contextTmp.createPattern(isfrom?this.canvasFrom:this.canvasTo, 'no-repeat');
				this.contextTmp.fillRect(0,0,this.w,this.h);
				this.contextTmp.globalCompositeOperation = "source-over";
				this.context.drawImage(this.contextTmp.canvas, 0,0,this.w,this.h);
				if (!isfrom) this.contextTmp.clearRect(0,0,this.w,this.h);
				return this;
			};
			//
			// the actual transition in time
			if (transition.init) transition.init(oProps);
			oProps.tstart = new Date().getTime();
			oProps.timer = setInterval(function(){
				var iTcurrent = new Date().getTime();
				var iTime = (iTcurrent-oProps.tstart)/time;
				oProps.t = tweenType(iTime);
				if (iTime<1) {
					// draw from
					if (transition.from) transition.from(oProps);
					else oCtx.drawImage(mCnvFr, 0,0,iW,iH);
					// draw to
					if (transition.to) transition.to(oProps);
					else oCtx.drawImage(mCnvTo, 0,0,iW,iH);
					// skip canvas
					if (oProps.toDataURL) toDataUrl(target,oProps);
				} else if (iTime>=1) { // the end
					removeTransition(target,true,true);
				}
			},oProps.frameRate);
			return true;
		}
		// disclose functions
		o.set = imageToCanvas;
		o.tween = tween;
		return o;
	}();
	////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////
	////////////////////////////////////////////////////////////////////////////////
	//
	// TRANSITIONS
	//
	// fade
	CIMG.defaults.transition = CIMG.transition.fade = function(){
		return {
			to: function(p){
				p.context.globalAlpha = p.t;
				p.context.drawImage(p.canvasTo, 0,0,p.w,p.h);
				p.context.globalAlpha = 1;
			}
		};
	}();
	// zoom
	CIMG.transition.zoom = function(){
		return {
			init:function(p){
				p.extend({
					scale: 5
				});
			},from: function(p){
				var s = 1+p.scale*p.t;
				p.context.drawImage(p.canvasFrom, -.5*(s-1)*p.w,-.5*(s-1)*p.h,s*p.w,s*p.h);
			},to: function(p){
				p.context.globalAlpha = p.t;
				var s = 1+p.scale*(1-p.t);
				p.context.drawImage(p.canvasTo, -.5*(s-1)*p.w,-.5*(s-1)*p.h,s*p.w,s*p.h);
				p.context.globalAlpha = 1;
			}
		}
	}();
	// wipe
	CIMG.transition.wipe = function(){
		return {
			init: function(p){
				p.extend({
					direction: "r" // t, r, b, l
				})
			},to: function(p){
				switch (p.direction) {
					case "t": p.context.drawImage(p.canvasTo, 0,-(1-p.t)*p.h,p.w,p.h); break;
					case "b": p.context.drawImage(p.canvasTo, 0,(1-p.t)*p.h,p.w,p.h); break;
					case "l": p.context.drawImage(p.canvasTo, -(1-p.t)*p.w,0,p.w,p.h); break;
					case "r": p.context.drawImage(p.canvasTo, (1-p.t)*p.w,0,p.w,p.h); break;
				}
			}
		}
	}();
	// fold
	CIMG.transition.fold = function(){
		return {
			init: function(p){
				p.extend({
					 direction: "r" // t, r, b, l
					,linear: false
					,shadow: .3
				})
			},from: function(p){
				var bTL = p.direction==="l"||p.direction==="t";
				p.context.drawImage(bTL?p.canvasTo:p.canvasFrom, 0,0,p.w,p.h, 0,0,p.w,p.h);
				switch (p.direction) {
					case "t": case "b":	p.context.drawImage(bTL?p.canvasFrom:p.canvasTo,	0,p.h/2,p.w,p.h/2, 0,p.h/2,p.w,p.h/2); break;
					case "l": case "r": p.context.drawImage(bTL?p.canvasFrom:p.canvasTo,	p.w/2,0,p.w/2,p.h, p.w/2,0,p.w/2,p.h); break;
				}
			},to: function(p){
				var bHr = p.direction==="l"||p.direction==="r";
				var bTL = p.direction==="l"||p.direction==="t";
				var t = bTL?1-p.t:p.t;
//				var t = Math.min(Math.max(bTL?1-p.t:p.t,.0000001,.999999999);
				var bSide = p.linear?t:t<.5;
				var fSinT = .5*(Math.sin((t-.5)*Math.PI)+1);
				var x;
				var y;
				var w;
				var h;
				switch (p.direction) {
					case "t": case "b":
						x = 0;
						y = (bSide?.5:1-fSinT)*p.h;
						w = p.w;
						h = Math.abs(.5-fSinT)*p.h;
					break;
					case "l": case "r":
						x = (bSide?.5:1-fSinT)*p.w;
						y = 0;
						w = Math.abs(.5-fSinT)*p.w;
						h = p.h;
					break;
				}
				p.context.drawImage(bSide!==bTL?p.canvasFrom:p.canvasTo,  (bHr?1:0)*(bSide?.5:0)*p.w,(bHr?0:1)*(bSide?.5:0)*p.h,(bHr?.5:1)*p.w,(bHr?1:.5)*p.h,  x,y,w,h);
				if (p.shadow!==0) {
					var fAlpha = Math.min(Math.max(p.shadow*(.5-Math.abs(.5-fSinT)),1),0);
					p.context.fillStyle = bSide===bHr?'rgba(0,0,0,'+fAlpha+')':'rgba(255,255,255,'+fAlpha+')';
					p.context.fillRect(x,y,w,h);
				}
			}
		}
	}();
	// flip
	CIMG.transition.flip = function(){
		return {
			init: function(p){
				p.extend({
					 vertical: false
					,linear: false
					,shadow: .3
				})
			},from: function(p){
				p.context.clearRect(0,0,p.w,p.h);
			},to: function(p){
				var bHalf = p.t<.5;
				var fSinT = .5*(Math.sin((p.t-.5)*Math.PI)+1);
				//var t = (p.linear?p.t:fSinT)*(bHalf?1:-1)+(bHalf?0:1);
				var x = (p.vertical?0:p.t)*p.w;
				var y = (p.vertical?p.t:0)*p.h;
				var w = (p.vertical?1:1-p.t*2)*p.w;
				var h = (p.vertical?1-p.t*2:1)*p.h;
				p.context.drawImage( bHalf?p.canvasFrom:p.canvasTo, x,y,w,h);
				if (p.shadow>0) { // todo: not right yet (probably use t)
					var fAlpha = p.shadow*(.5-Math.abs(.5-fSinT));
					p.context.fillStyle = bHalf===p.vertical?'rgba(0,0,0,'+fAlpha+')':'rgba(255,255,255,'+fAlpha+')';
					p.context.fillRect(x,y,w,h);
				}
			}
		}
	}();
	// pageflip
	CIMG.transition.pageflip = function(){
		return {
			init: function(p){
				p.extend({
					shadow: .3
				})
			},from: function(p){
//				oCtx.drawImage(mCnvFr, 0,0,iW,iH);
				p.context.clearRect(0,0,p.w,p.h);
			},to: function(p){
				var x = (1-p.t)*p.w
				var y = .5*Math.sin(p.t*Math.PI)*p.h;
				//
//  				p.context.save();
				//
//				p.context.restore();;
//				p.context.closePath();
				p.context.beginPath();
				p.context.lineTo(p.w,0);
//				p.context.beginPath()
				p.context.moveTo(x,y);
				//
				p.context.lineWidth = 1;
				p.context.strokeStyle = '#000';
				p.context.stroke();
				p.context.closePath();

				p.context.fillRect(x,y,2,2);
//				p.context.restore();
				//
//				p.apply();
			}
		}
	}();
	// circle
	CIMG.transition.circle = function(){
		return {
			init: function(p){
				p.extend({
					 grow: true
					,fade: 100
				});
			},to: function(p){
				var x = p.w/2;
				var y = p.h/2;
				var r = Math.max(0,(p.grow?p.t:1-p.t)*(p.r+p.fade));
				p.contextTmp.beginPath();
				//
				if (p.fade===0) {
					p.contextTmp.fillStyle = '#f00';
				} else {
					var oGrad = p.contextTmp.createRadialGradient(x,y,0,x,y,r);
					oGrad.addColorStop(p.r/(p.r+p.fade), '#000');
					oGrad.addColorStop(1, 'rgba(0,0,0,0)');
					p.contextTmp.fillStyle = oGrad;
				}
				p.contextTmp.arc(x,y,r,0,2*Math.PI, false);
				p.contextTmp.closePath();
				p.contextTmp.fill();
				p.apply(p.grow?"source-in":"source-out");
			}
		}
	}();
	// square
	CIMG.transition.square = function(){
		return {
			init:function(p){
				p.extend({
					grow: true
				});
			},to: function(p){
				var t = p.grow?p.t:1-p.t;
				var w = t*p.w;
				var h = t*p.h;
				var x = (p.w-w)/2;
				var y = (p.h-h)/2;
				p.contextTmp.beginPath();
				p.contextTmp.fillStyle = '#f00';
				// todo: if gradient: draw four triangles with linearGradient
				p.contextTmp.fillRect(x,y,w,h);
				p.contextTmp.closePath();
				p.contextTmp.fill();
				p.apply(p.grow?"source-in":"source-out");
			}
		}
	}();
	// clock
	CIMG.transition.clock = function(){
		return {
			init:function(p){
				p.extend({
					 clockwise: true
					,startAngle: 0
				});
			},to: function(p){
				var fRdnStart = (p.startAngle/180-.5)*Math.PI;
				p.contextTmp.beginPath();
				p.contextTmp.moveTo(Math.floor(p.w/2),Math.floor(p.h/2));
				p.contextTmp.arc(Math.floor(p.w/2),Math.floor(p.h/2),p.r,fRdnStart,fRdnStart+(p.clockwise?1:-1)*(p.t)*2*Math.PI, false);
				p.contextTmp.closePath();
				p.contextTmp.fill();
				p.apply(p.clockwise?"source-in":"source-out");
			}
		}
	}();
	// wave
	CIMG.transition.wave = function(){
		return {
			to:function(p){
				var x = (1-2*p.t)*p.w;
				p.contextTmp.beginPath();
				p.contextTmp.moveTo(x,p.h);
				p.contextTmp.bezierCurveTo(x+p.w*.5,p.h, x+p.w*.5,0, x+p.w,0);
				p.contextTmp.lineTo(x+p.w*2,0);
				p.contextTmp.lineTo(x+p.w*2,p.h);
				p.contextTmp.closePath();
				p.contextTmp.fill();
				p.apply();
			}
		}
	}();
	// blinds
	CIMG.transition.blinds = function(){
		return {
			init:function(p){
				p.extend({
					 number:	16
					,even:		.9
					,rotation:	.2*Math.PI
				});
			},to: function(p){
				//p.rotation += .01;
				var iRmxBlind = 2*p.r/p.number;
				p.contextTmp.translate(p.w/2, p.h/2);
				p.contextTmp.rotate(p.rotation);
				for (var i=0;i<p.number;i++) {
					var fTT = Math.min(Math.max(   p.even*(p.t) + (1-p.even)*((p.t)*p.number-i)   ,0),1);
					p.contextTmp.fillRect(-p.r,-p.r+Math.round(iRmxBlind/2+i*iRmxBlind-fTT*iRmxBlind/2),2*p.r,Math.ceil(fTT*(iRmxBlind+.1)));
				}
				p.contextTmp.rotate(-p.rotation);
				p.contextTmp.translate(-p.w/2, -p.h/2);
				//
				p.apply();
			}
//			},from: function(p){
//				//p.rotation += .01;
//				var iRmxBlind = 2*p.r/p.number;
//				p.contextTmp.translate(p.w/2, p.h/2);
//				p.contextTmp.rotate(p.rotation);
//				for (var i=0;i<p.number;i++) {
//					var fTT = Math.min(Math.max(   p.even*(p.t) + (1-p.even)*((p.t)*p.number-i)   ,0),1);
//					p.contextTmp.fillRect(-p.r,-p.r+Math.round(iRmxBlind/2+i*iRmxBlind-fTT*iRmxBlind/2),2*p.r,Math.ceil(fTT*(iRmxBlind+.1)));
//				}
//				p.contextTmp.rotate(-p.rotation);
//				p.contextTmp.translate(-p.w/2, -p.h/2);
//				////////////////////
//				p.apply("xor",true);
//			},to: function(p){
//				p.apply("xor");
//			}
		}
	}();
	// particles
	CIMG.transition.particles = function(){
		// todo: add property for parsing an image to use as particle
		return {
			init:function(p){
				p.extend({
					 number: 128
					,scale: 1
					,character: "*"
					,font: "Verdana"
				});
				// since fillText is rather slow we temporarily store the particle image
				var iShot = Math.floor(.6*p.h);
				p.contextTmp.font = iShot+'px '+p.font;
				p.contextTmp.textBaseline = "middle";
				//
				p.mTCnv = document.createElement("canvas");
				p.mTCnv.width = p.w;
				p.mTCnv.height = p.h;
				p.mTCtx = p.mTCnv.getContext("2d");
				p.mTCtx.font = p.contextTmp.font;
				p.mTCtx.textBaseline = "middle";
				p.mTCtx.fillText(p.character,p.w/4,p.h/3);
				//
				// find character constraints (since p.contextTmp.measureText(p.character) sucks)
				var iFindWH = 8;
				var aFindWH = [];
				var mFindCnv;
				for (var k=0;k<2;k++) {
					mFindCnv = p.mTCnv;
					var bW = k===0;
					for (var i=iFindWH;i>=1;i/=2) {
						var mFCnv = document.createElement("canvas");
						mFCnv.width =	bW?p.w:i;
						mFCnv.height =	bW?i:p.h;
						var mFCtx = mFCnv.getContext("2d");
						mFCtx.drawImage(mFindCnv, 0,0, bW?p.w:i,bW?i:p.h);
						if (i>1) {
							mFindCnv = mFCnv;
						} else {
							var mFDta = mFCtx.getImageData(0,0, bW?p.w:i,bW?i:p.h);
							var iStart = undefined;
							var iEnd = undefined;
							for (var j=0;j<mFDta.data.length/4;j++) {
								var iAlpha = mFDta.data[j*4+3];
								if (iAlpha!==0&&iStart===undefined)	iStart = Math.max(0,j-1);
								if (iAlpha===0&&iEnd===undefined)	iEnd = j;
								else if (iAlpha!==0)				iEnd = undefined;
							}
							aFindWH.push(iStart);
							aFindWH.push(iEnd);
						}
					}
				}
				var iMrg = 0;
				var iRsX = aFindWH[0]||0;
				var iRsY = aFindWH[2]||0;
				var iRsW = Math.max(1,(aFindWH[1]-aFindWH[0])||1);
				var iRsH = Math.max(1,(aFindWH[3]-aFindWH[2])||1);
				var mResult = document.createElement("canvas");
				mResult.width =  iRsW+2*iMrg;
				mResult.height = iRsH+2*iMrg;
				var mRsltCtx = mResult.getContext("2d");
				mRsltCtx.drawImage(p.mTCnv, iRsX,iRsY,iRsW,iRsH, iMrg,iMrg,iRsW,iRsH);
				p.mTCnv = mResult;
			},to: function(p){
				var iNumParticles = p.number;
				Prng.seed = p.seed;
				for (var i=0;i<iNumParticles;i++) {
					var iPx = p.w*(iNumParticles===1?.5:Prng.random());
					var iPy = p.h*(iNumParticles===1?.5:Prng.random());
					var iSze = Math.max(0,(p.t)*p.r/Math.sqrt(iNumParticles)*1.5);
					var iT1SzW = iSze * p.mTCnv.width * .02 * p.scale;
					var iT1SzH = iSze * p.mTCnv.height * .02 * p.scale;
					iPx -= iT1SzW/2;
					iPy -= iT1SzH/2;
					p.contextTmp.drawImage(p.mTCnv, iPx,iPy, iT1SzW,iT1SzH);
				}
				p.apply();
			}
		}
	}();
	// noise
	CIMG.transition.noise = function(){
		return {
			init:function(p){
				Prng.seed = p.seed;
				p.noise = [];
				for (var i=0;i<p.w*p.h;i++) p.noise.push(Prng.random());
				p.contextTmp.fillRect(0,0,p.w,p.h);
				p.imgdata = p.contextTmp.getImageData(0,0,p.w,p.h);
				p.pixels = p.imgdata.data;
			},to: function(p){ // todo: this should be possible to do without looping through pixels the whole time.... with some sort of composite stuff
				for (var i=0;i<p.pixels.length/4;i++) p.pixels[4*i+3] = p.noise[i]>p.t?0:255;
				p.contextTmp.putImageData(p.imgdata, 0,0);
				p.apply();
			}
		};
	}();
	// simplexNoise
	CIMG.transition.simplexNoise = function(){
		return {
			init:function(p){
				try { PerlinSimplex; } catch (err) { alert("You need to include PerlinSimplex.js"); return; }
				p.extend({
					 scaleX:	.02
					,scaleY:	.02
					,fade:		.3
				});
				Prng.seed = p.seed;
				p.noise = [];
				var x1 = Prng.rnd();
				var y1 = Prng.rnd();
				for (var i=0;i<p.w*p.h;i++) {
					var x = x1+p.scaleX*(i%p.w);
					var y = y1+p.scaleY*Math.floor(i/p.w);
					p.noise.push(PerlinSimplex.noise(x,y));
				}
				p.contextTmp.fillRect(0,0,p.w,p.h);
				p.imgdata = p.contextTmp.getImageData(0,0,p.w,p.h);
				p.pixels = p.imgdata.data;
			},to: function(p){ // todo: this should be possible to do without looping through pixels the whole time.... with some sort of composite stuff
				for (var i=0;i<p.pixels.length/4;i++) {
					var t = -.5*p.fade + p.t*(1+p.fade);
					p.pixels[4*i+3] = 255*Math.min(Math.max((t-(p.noise[i]-.5*p.fade))*(1/p.fade),0),1);
				}
				p.contextTmp.putImageData(p.imgdata, 0,0);
				p.apply();
			}
		}
	}();
	// drip
	CIMG.transition.drip = function(){
		return {
			init:function(p){
				try { PerlinSimplex; } catch (err) { alert("You need to include PerlinSimplex.js"); return; }
				p.extend({
					 scaleX:	.02
					,scaleY:	.0002
					,fade:		.3
				});
				p.contextTmp.fillRect(0,0,p.w,p.h);
				p.imgdata = p.contextTmp.getImageData(0,0,p.w,p.h);
				p.pixels = p.imgdata.data;
				//
				p.noise = [];
				Prng.seed = p.seed;
				var x1 = Prng.rnd();
				var y1 = Prng.rnd();
				for (var i=0;i<p.w*p.h;i++) {
					var x = i%p.w;
					var y = Math.floor(i/p.w);
					var xx = x1+p.scaleX*x;
					p.noise.push((y/p.h)*PerlinSimplex.noise(xx));
				}
			},to: function(p){ // todo: this should be possible to do without looping through pixels the whole time.... with some sort of composite stuff
				for (var i=0;i<p.pixels.length/4;i++) {
					var t = -.5*p.fade + p.t*(1+p.fade);
					p.pixels[4*i+3] = 255*Math.min(Math.max((t-(p.noise[i]-.5*p.fade))*(1/p.fade),0),1);
				}
				p.contextTmp.putImageData(p.imgdata, 0,0);
				p.apply();
			}
		}
	}();
	CANVASIMG = CIMG;
}
// a psuedo random number generator for the particle transition
if (!Prng) {
	var Prng = function() {
		var iMersenne = 2147483647;
		var iRnd = function(seed) {
			if (arguments.length) oReturn.seed = arguments[0];
			oReturn.seed = oReturn.seed*16807%iMersenne;
			return oReturn.seed;
		};
		var oReturn = {
			seed: 123,
			rnd: iRnd,
			random: function(seed) {
				if (arguments.length) oReturn.seed = arguments[0];
				return iRnd()/iMersenne;
			}
		};
		return oReturn;
	}();
}
// extra array fn
Array.prototype.indexOf=function(n){for(var i=0;i<this.length;i++){if(this[i]===n){return i;}}return -1;};


/*!
 * jQuery hashchange event - v1.3 - 7/21/2010
 * http://benalman.com/projects/jquery-hashchange-plugin/
 * 
 * Copyright (c) 2010 "Cowboy" Ben Alman
 * Dual licensed under the MIT and GPL licenses.
 * http://benalman.com/about/license/
 */

// Script: jQuery hashchange event
//
// *Version: 1.3, Last updated: 7/21/2010*
// 
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
// GitHub       - http://github.com/cowboy/jquery-hashchange/
// Source       - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
// (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
// 
// About: License
// 
// Copyright (c) 2010 "Cowboy" Ben Alman,
// Dual licensed under the MIT and GPL licenses.
// http://benalman.com/about/license/
// 
// About: Examples
// 
// These working examples, complete with fully commented code, illustrate a few
// ways in which this plugin can be used.
// 
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
// 
// About: Support and Testing
// 
// Information about what version or versions of jQuery this plugin has been
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
// 
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
// Unit Tests      - http://benalman.com/code/projects/jquery-hashchange/unit/
// 
// About: Known issues
// 
// While this jQuery hashchange event implementation is quite stable and
// robust, there are a few unfortunate browser bugs surrounding expected
// hashchange event-based behaviors, independent of any JavaScript
// window.onhashchange abstraction. See the following examples for more
// information:
// 
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
// 
// Also note that should a browser natively support the window.onhashchange 
// event, but not report that it does, the fallback polling loop will be used.
// 
// About: Release History
// 
// 1.3   - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
//         "removable" for mobile-only development. Added IE6/7 document.title
//         support. Attempted to make Iframe as hidden as possible by using
//         techniques from http://www.paciellogroup.com/blog/?p=604. Added 
//         support for the "shortcut" format $(window).hashchange( fn ) and
//         $(window).hashchange() like jQuery provides for built-in events.
//         Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
//         lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
//         and <jQuery.fn.hashchange.src> properties plus document-domain.html
//         file to address access denied issues when setting document.domain in
//         IE6/7.
// 1.2   - (2/11/2010) Fixed a bug where coming back to a page using this plugin
//         from a page on another domain would cause an error in Safari 4. Also,
//         IE6/7 Iframe is now inserted after the body (this actually works),
//         which prevents the page from scrolling when the event is first bound.
//         Event can also now be bound before DOM ready, but it won't be usable
//         before then in IE6/7.
// 1.1   - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
//         where browser version is incorrectly reported as 8.0, despite
//         inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
// 1.0   - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
//         window.onhashchange functionality into a separate plugin for users
//         who want just the basic event & back button support, without all the
//         extra awesomeness that BBQ provides. This plugin will be included as
//         part of jQuery BBQ, but also be available separately.

(function($,window,undefined){
  '$:nomunge'; // Used by YUI compressor.
  
  // Reused string.
  var str_hashchange = 'hashchange',
    
    // Method / object references.
    doc = document,
    fake_onhashchange,
    special = $.event.special,
    
    // Does the browser support window.onhashchange? Note that IE8 running in
    // IE7 compatibility mode reports true for 'onhashchange' in window, even
    // though the event isn't supported, so also test document.documentMode.
    doc_mode = doc.documentMode,
    supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
  
  // Get location.hash (or what you'd expect location.hash to be) sans any
  // leading #. Thanks for making this necessary, Firefox!
  function get_fragment( url ) {
    url = url || location.href;
    return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
  };
  
  // Method: jQuery.fn.hashchange
  // 
  // Bind a handler to the window.onhashchange event or trigger all bound
  // window.onhashchange event handlers. This behavior is consistent with
  // jQuery's built-in event handlers.
  // 
  // Usage:
  // 
  // > jQuery(window).hashchange( [ handler ] );
  // 
  // Arguments:
  // 
  //  handler - (Function) Optional handler to be bound to the hashchange
  //    event. This is a "shortcut" for the more verbose form:
  //    jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
  //    all bound window.onhashchange event handlers will be triggered. This
  //    is a shortcut for the more verbose
  //    jQuery(window).trigger( 'hashchange' ). These forms are described in
  //    the <hashchange event> section.
  // 
  // Returns:
  // 
  //  (jQuery) The initial jQuery collection of elements.
  
  // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
  // $(elem).hashchange() for triggering, like jQuery does for built-in events.
  $.fn[ str_hashchange ] = function( fn ) {
    return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
  };
  
  // Property: jQuery.fn.hashchange.delay
  // 
  // The numeric interval (in milliseconds) at which the <hashchange event>
  // polling loop executes. Defaults to 50.
  
  // Property: jQuery.fn.hashchange.domain
  // 
  // If you're setting document.domain in your JavaScript, and you want hash
  // history to work in IE6/7, not only must this property be set, but you must
  // also set document.domain BEFORE jQuery is loaded into the page. This
  // property is only applicable if you are supporting IE6/7 (or IE8 operating
  // in "IE7 compatibility" mode).
  // 
  // In addition, the <jQuery.fn.hashchange.src> property must be set to the
  // path of the included "document-domain.html" file, which can be renamed or
  // modified if necessary (note that the document.domain specified must be the
  // same in both your main JavaScript as well as in this file).
  // 
  // Usage:
  // 
  // jQuery.fn.hashchange.domain = document.domain;
  
  // Property: jQuery.fn.hashchange.src
  // 
  // If, for some reason, you need to specify an Iframe src file (for example,
  // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
  // do so using this property. Note that when using this property, history
  // won't be recorded in IE6/7 until the Iframe src file loads. This property
  // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
  // compatibility" mode).
  // 
  // Usage:
  // 
  // jQuery.fn.hashchange.src = 'path/to/file.html';
  
  $.fn[ str_hashchange ].delay = 50;
  /*
  $.fn[ str_hashchange ].domain = null;
  $.fn[ str_hashchange ].src = null;
  */
  
  // Event: hashchange event
  // 
  // Fired when location.hash changes. In browsers that support it, the native
  // HTML5 window.onhashchange event is used, otherwise a polling loop is
  // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
  // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
  // compatibility" mode), a hidden Iframe is created to allow the back button
  // and hash-based history to work.
  // 
  // Usage as described in <jQuery.fn.hashchange>:
  // 
  // > // Bind an event handler.
  // > jQuery(window).hashchange( function(e) {
  // >   var hash = location.hash;
  // >   ...
  // > });
  // > 
  // > // Manually trigger the event handler.
  // > jQuery(window).hashchange();
  // 
  // A more verbose usage that allows for event namespacing:
  // 
  // > // Bind an event handler.
  // > jQuery(window).bind( 'hashchange', function(e) {
  // >   var hash = location.hash;
  // >   ...
  // > });
  // > 
  // > // Manually trigger the event handler.
  // > jQuery(window).trigger( 'hashchange' );
  // 
  // Additional Notes:
  // 
  // * The polling loop and Iframe are not created until at least one handler
  //   is actually bound to the 'hashchange' event.
  // * If you need the bound handler(s) to execute immediately, in cases where
  //   a location.hash exists on page load, via bookmark or page refresh for
  //   example, use jQuery(window).hashchange() or the more verbose 
  //   jQuery(window).trigger( 'hashchange' ).
  // * The event can be bound before DOM ready, but since it won't be usable
  //   before then in IE6/7 (due to the necessary Iframe), recommended usage is
  //   to bind it inside a DOM ready handler.
  
  // Override existing $.event.special.hashchange methods (allowing this plugin
  // to be defined after jQuery BBQ in BBQ's source code).
  special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
    
    // Called only when the first 'hashchange' event is bound to window.
    setup: function() {
      // If window.onhashchange is supported natively, there's nothing to do..
      if ( supports_onhashchange ) { return false; }
      
      // Otherwise, we need to create our own. And we don't want to call this
      // until the user binds to the event, just in case they never do, since it
      // will create a polling loop and possibly even a hidden Iframe.
      $( fake_onhashchange.start );
    },
    
    // Called only when the last 'hashchange' event is unbound from window.
    teardown: function() {
      // If window.onhashchange is supported natively, there's nothing to do..
      if ( supports_onhashchange ) { return false; }
      
      // Otherwise, we need to stop ours (if possible).
      $( fake_onhashchange.stop );
    }
    
  });
  
  // fake_onhashchange does all the work of triggering the window.onhashchange
  // event for browsers that don't natively support it, including creating a
  // polling loop to watch for hash changes and in IE 6/7 creating a hidden
  // Iframe to enable back and forward.
  fake_onhashchange = (function(){
    var self = {},
      timeout_id,
      
      // Remember the initial hash so it doesn't get triggered immediately.
      last_hash = get_fragment(),
      
      fn_retval = function(val){ return val; },
      history_set = fn_retval,
      history_get = fn_retval;
    
    // Start the polling loop.
    self.start = function() {
      timeout_id || poll();
    };
    
    // Stop the polling loop.
    self.stop = function() {
      timeout_id && clearTimeout( timeout_id );
      timeout_id = undefined;
    };
    
    // This polling loop checks every $.fn.hashchange.delay milliseconds to see
    // if location.hash has changed, and triggers the 'hashchange' event on
    // window when necessary.
    function poll() {
      var hash = get_fragment(),
        history_hash = history_get( last_hash );
      
      if ( hash !== last_hash ) {
        history_set( last_hash = hash, history_hash );
        
        $(window).trigger( str_hashchange );
        
      } else if ( history_hash !== last_hash ) {
        location.href = location.href.replace( /#.*/, '' ) + history_hash;
      }
      
      timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
    };
    
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    $.browser.msie && !supports_onhashchange && (function(){
      // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
      // when running in "IE7 compatibility" mode.
      
      var iframe,
        iframe_src;
      
      // When the event is bound and polling starts in IE 6/7, create a hidden
      // Iframe for history handling.
      self.start = function(){
        if ( !iframe ) {
          iframe_src = $.fn[ str_hashchange ].src;
          iframe_src = iframe_src && iframe_src + get_fragment();
          
          // Create hidden Iframe. Attempt to make Iframe as hidden as possible
          // by using techniques from http://www.paciellogroup.com/blog/?p=604.
          iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
            
            // When Iframe has completely loaded, initialize the history and
            // start polling.
            .one( 'load', function(){
              iframe_src || history_set( get_fragment() );
              poll();
            })
            
            // Load Iframe src if specified, otherwise nothing.
            .attr( 'src', iframe_src || 'javascript:0' )
            
            // Append Iframe after the end of the body to prevent unnecessary
            // initial page scrolling (yes, this works).
            .insertAfter( 'body' )[0].contentWindow;
          
          // Whenever `document.title` changes, update the Iframe's title to
          // prettify the back/next history menu entries. Since IE sometimes
          // errors with "Unspecified error" the very first time this is set
          // (yes, very useful) wrap this with a try/catch block.
          doc.onpropertychange = function(){
            try {
              if ( event.propertyName === 'title' ) {
                iframe.document.title = doc.title;
              }
            } catch(e) {}
          };
          
        }
      };
      
      // Override the "stop" method since an IE6/7 Iframe was created. Even
      // if there are no longer any bound event handlers, the polling loop
      // is still necessary for back/next to work at all!
      self.stop = fn_retval;
      
      // Get history by looking at the hidden Iframe's location.hash.
      history_get = function() {
        return get_fragment( iframe.location.href );
      };
      
      // Set a new history item by opening and then closing the Iframe
      // document, *then* setting its location.hash. If document.domain has
      // been set, update that as well.
      history_set = function( hash, history_hash ) {
        var iframe_doc = iframe.document,
          domain = $.fn[ str_hashchange ].domain;
        
        if ( hash !== history_hash ) {
          // Update Iframe with any initial `document.title` that might be set.
          iframe_doc.title = doc.title;
          
          // Opening the Iframe's document after it has been closed is what
          // actually adds a history entry.
          iframe_doc.open();
          
          // Set document.domain for the Iframe document as well, if necessary.
          domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
          
          iframe_doc.close();
          
          // Update the Iframe's hash, for great justice.
          iframe.location.hash = hash;
        }
      };
      
    })();
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    
    return self;
  })();
  
})(jQuery,this);

/*
 * jQuery Color Animations
 * Copyright 2007 John Resig
 * Released under the MIT and GPL licenses.
 */

(function(jQuery){

	// We override the animation for all of these color styles
	jQuery.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'color', 'outlineColor'], function(i,attr){
		jQuery.fx.step[attr] = function(fx){
			if ( fx.state == 0 ) {
				fx.start = getColor( fx.elem, attr );
				fx.end = getRGB( fx.end );
			}

			fx.elem.style[attr] = "rgb(" + [
				Math.max(Math.min( parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1]), 255), 0),
				Math.max(Math.min( parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2]), 255), 0)
			].join(",") + ")";
		}
	});

	// Color Conversion functions from highlightFade
	// By Blair Mitchelmore
	// http://jquery.offput.ca/highlightFade/

	// Parse strings looking for color tuples [255,255,255]
	function getRGB(color) {
		var result;

		// Check if we're already dealing with an array of colors
		if ( color && color.constructor == Array && color.length == 3 )
			return color;

		// Look for rgb(num,num,num)
		if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
			return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])];

		// Look for rgb(num%,num%,num%)
		if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
			return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];

		// Look for #a0b1c2
		if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
			return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];

		// Look for #fff
		if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
			return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];

		// Otherwise, we're most likely dealing with a named color
		return colors[jQuery.trim(color).toLowerCase()];
	}
	
	function getColor(elem, attr) {
		var color;

		do {
			color = jQuery.curCSS(elem, attr);

			// Keep going until we find an element that has color, or we hit the body
			if ( color != '' && color != 'transparent' || jQuery.nodeName(elem, "body") )
				break; 

			attr = "backgroundColor";
		} while ( elem = elem.parentNode );

		return getRGB(color);
	};
	
	// Some named colors to work with
	// From Interface by Stefan Petre
	// http://interface.eyecon.ro/

	var colors = {
		aqua:[0,255,255],
		azure:[240,255,255],
		beige:[245,245,220],
		black:[0,0,0],
		blue:[0,0,255],
		brown:[165,42,42],
		cyan:[0,255,255],
		darkblue:[0,0,139],
		darkcyan:[0,139,139],
		darkgrey:[169,169,169],
		darkgreen:[0,100,0],
		darkkhaki:[189,183,107],
		darkmagenta:[139,0,139],
		darkolivegreen:[85,107,47],
		darkorange:[255,140,0],
		darkorchid:[153,50,204],
		darkred:[139,0,0],
		darksalmon:[233,150,122],
		darkviolet:[148,0,211],
		fuchsia:[255,0,255],
		gold:[255,215,0],
		green:[0,128,0],
		indigo:[75,0,130],
		khaki:[240,230,140],
		lightblue:[173,216,230],
		lightcyan:[224,255,255],
		lightgreen:[144,238,144],
		lightgrey:[211,211,211],
		lightpink:[255,182,193],
		lightyellow:[255,255,224],
		lime:[0,255,0],
		magenta:[255,0,255],
		maroon:[128,0,0],
		navy:[0,0,128],
		olive:[128,128,0],
		orange:[255,165,0],
		pink:[255,192,203],
		purple:[128,0,128],
		violet:[128,0,128],
		red:[255,0,0],
		silver:[192,192,192],
		white:[255,255,255],
		yellow:[255,255,0]
	};
	
})(jQuery);

;(function($) {

	/*function Field(val){
		var value = val;
		this.__defineGetter__("value", function(){
			return value;
		});
		this.__defineSetter__("value", function(val){
			value = 'a'+val;
		});
	}
	var field = new Field(23);
	field.value = 'bar';
	console.log('field',field,field.value);*/


	// private variables
	var oSettings = {};
	var oGetVars = {};
	var iW = 1024;
	var iH = 768;
	var oAp = Array.prototype;

	var iMenuAnimT = 300;

	function trace() { try {console.log.apply(console, arguments);} catch (e) {} };

	// display objects
	var $Document;
	var $Window;
	var $Body;
	var $MenuTrigger;
	var $Menus;
		var $Menu;
		var $Tags;
	var $Colofon;
	var $PageList;

	// misc
	var bHTML5 = !!document.createElement('canvas').getContext;
	//
	var bIOs = !!navigator.userAgent.match(/iPhone|iPad/i);
	//
	var bTouch = false;
	try { document.createEvent("TouchEvent"); bTouch = true; }catch(err){}
	//
	var bPageTransition = false;
	var iBasePageW = 608;
	var iBasePageH = 399; // is average 16:9 and 4:3
	var iSideMargin = 40;
	var iSideHover = 10;
	var aCurrentPages = [];
	var sCenterCssName = 'center';
	var sCenterElements = 'h2,h3,table.about,img.centerImg,ul.imgcnt,div.info,div.fwasotd';
	var oPrepareToFadeIn = {display:'block',opacity:0};

	// default settings
	$.ronvalstar = {
		 id: "Ron Valstar"
		,version: "4.0.0"
		,defaults: {
			 debug:	true
			,start:	"#home"
		}
		// public functions
	};

	// call
	$.fn.extend({
		ronvalstar: function(_settings) {
			oSettings = $.extend({}, $.ronvalstar.defaults, _settings);
			trace($.ronvalstar.id+' '+$.ronvalstar.version+' ('+oSettings.start+')');
			init();
		}
	});

	// PRIVATE FUNCTIONS

	// init
	function init(){
		getvars();
		if (oGetVars.nojs) return;
		//
		// display objects
		$Document = $(document);
		$Window = $(window);
		$Body = $('body');
		$MenuTrigger = $('#menutrigger');
		$Menus = $('#menus');
		$Menu = $('ul#menu');
		$Tags = $('ul#tagmenu');
		//
		$Body.addClass('js');
		//
		initExternalAnchors();
		initRotator();
		initPageModel();
		initMenus();
		initColofon();
		initEvents();
		//
		showRotator();
	}

	// initExternalAnchors
	function initExternalAnchors(){
		$('a[rel="external"]').attr('target','_blank');
	}

	// initRotator
	var bRotator = false;
	var $Rotator;
	var iRotator = 0;
	function initRotator(){
		$Rotator = $('<div class="rotator">0</div>');
	}
	// rotateRotator
	function rotateRotator(){
		iRotator += 1;
		$Rotator.text(iRotator%10);//+'!@#$"'
		if (bRotator) requestAnimFrame(rotateRotator);
	}
	// showRotator
	function showRotator(show){
		if (show===undefined) show = true;
		if (show!==bRotator) {
			bRotator = show;
			if (show) {
				$Rotator.appendTo($Body)
				rotateRotator();
			} else {
				$Rotator.remove();
			}
		}
	}

	// initPageModel
	var oPages = {
		 toString:	function(){return '[pages '+oPages.length+']';}
		,push:		function(o){oAp.push.apply(oPages,[o])}
		,indexOf:	function(o){oAp.indexOf.apply(oPages,[o])}
		,length:	0
	};
	function page(data) {
		var n = null;
		var o = {
			id:					n
			,title:				n
			,imgs:				n
			,currentImg:		0
			,loaded:			-1
			,tags:				n
			,page:				n
			,w:					iBasePageW
			,h:					iBasePageH
			,nr:				-1
			,infoButton:		$()
			,content:			n
			,centerElements:	n
			,toString:			function(){return '[page '+o.id+']';}
		}
		for (var oDat in data) if (o.hasOwnProperty(oDat)) o[oDat] = data[oDat];
		return o;
	}

	function initPageModel(){
		$PageList = $('ul#pages');
		var $Pages = $PageList.find('>li');
		$Pages.each(function(i,el){
			var $Page = $(el);
			$Page.click(clickPage).hover(hoverPage,hoverPage);
			//
			var $Content = $Page.find('div.content');
			//
			// tags
			var aTags = [];
			$.each($Page.attr('class').split(' '),function(i,s){
				if (['','page'].indexOf(s)===-1) aTags.push(s);
			});
			//
			// todo: maybe build ul.imgcnt from js
			$Page.find('ul.imgcnt>li').click(clickImgCnt);
			//
			// imgs
			var aImgs = [];
			$.each($Page.find('img'),function(i,el){
				var $Img = $(el);
				aImgs.push({
					src: $Img.attr('src')
					,alt: $Img.attr('alt')
				});
				if (i>0) $Img.remove();
			});
			//
			// hasImgs
			var bHasImgs = aImgs.length!==0;
			if (!bHasImgs) {
				$Page.addClass('textonly');
				$Content.show();
			}
			//
			// fwa
			if ($Page.hasClass('fwasotd')) $Page.append('<div class="fwasotd"></div>');
			//
			// info button
			if (bHasImgs&&$Content.text()!=='') {
				var $Info = $('<div class="info"></div>').appendTo($Page).click(function() {
					if ($Content.is(':visible')) {
						$Content.animate({opacity:0},{duration:300,queue:false,complete:function() {
							$Content.hide()
						}});
					} else {
						$Content.show();
						$Content.animate({opacity:1},{duration:300,queue:false});
					}
				}).hover(function(){
					$Info.animate({backgroundColor:'#F0A'},{duration:300,queue:false});
				},function(){
					$Info.animate({backgroundColor:'#599CEE'},{duration:300,queue:false});
				});
			}
			//
			// page object
			var oPage = {
				id:			$Page.attr('id')
				,title:		$Page.find('h2,h3').text()
				,imgs:		aImgs
				,currentImg:0
				,loaded:	bHasImgs?0:-1
				,tags:		aTags
				,page:		$Page
				,w:			iBasePageW
				,h:			bHasImgs?iBasePageH:$Page.height()
				,nr:		-1
				,infoButton:		$Info||$()
				,content:			$Content
				,centerElements:	$Page.find(sCenterElements)
			};
			$Page.attr('id','_'+oPage.id);
			oPages.push(oPage);
			oPages[oPage.id] = oPage;
			oPage.nr = oPages.length-1;
		});
		$Pages.detach();
	}

	// initMenus
	function initMenus() {
		//
		// menu trigger
		$MenuTrigger.click(menuAnim).mouseover(menuAnim);
		//
		// add pages
		var iTopPadding = 0;
		$.each(oPages,function(i,o){
			if (o.page.is('.textonly')) {
				iTopPadding += $('<a href="#'+o.id+'" class="home">'+(o.id=='home'?o.id:o.title)+'</a>').insertBefore($Menu).height();
			}
		});
		// add top padding to two menus ($Menu en $Tags)
		//$.merge($Menu,$Tags).css({paddingTop:iTopPadding});
		$Menu.css({paddingTop:iTopPadding});
		$Tags.css({paddingTop:iTopPadding});
		//
		// create shadows
		var iVPadding = eval(($Menu.css('padding-top')+'+'+$Menu.css('padding-bottom')).replace(/[a-z]/g,''));
		$('<div class="shade"></div>').appendTo($Menus).css({
			left: $Menu.css('left')
		}).width($Menu.width()).height($Menu.height()+iVPadding);
		$('<div class="shade"></div>').appendTo($Menus).css({
			left: $Tags.css('left')
		}).width($Tags.width()).height($Tags.height()+iVPadding);
		//
		// menus
		var iMenusTopPos = -($Menu.height()+getExtraMenuHeight());
		$Menus.css({
			top: iMenusTopPos+'px'
		}).mouseleave(function(){
			menuAnim(false);
		});
		//
		// add project tag-classes to menu li
		for (var i=0;i<oPages.length;i++) {
			var oPage = oPages[i];
			var sTagClasses = oPage.page.attr('class');
			// todo: code better
			$Menu.find('>li:has(a[href=#'+oPage.id+'])').addClass(sTagClasses).removeClass('fwasotd').removeClass('page');
		}
		//
		// regular menu
		$Menu.find('li>a').click(clickHash);
		//
		// tag menu
		$Tags.find('>li').click(function(e){
			var $Li = $(e.currentTarget);
			$Li.toggleClass('select').siblings().removeClass('select');
			$Menu.find('li').removeClass('select');
			var sSelect = '';
			$Tags.find('li.select').each(function(i,el){
				sSelect += '.'+$(el).attr('id');
			});
			$Menu.find('li.'+sSelect).each(function(i,el){
				setTimeout(function(){
					$(el).addClass('select');
				},Math.sqrt(i)*200);
			});
			return false;
		});
		//
		// click body to hide
		$Body.click(function(e){
			if (e.target.nodeName!='A'&&isMenuOpen()) $Menu.mouseleave();
		});
	}

	// initColofon
	function initColofon(){
		$Colofon = $('ul#colofon');
		$Colofon.hover(handleColofonHover,handleColofonHover);
//		$Colofon.find('>li.name').mouseenter(function(){
//			menuAnim(true);
//		});
//		$('<li class="logo"></li>').prependTo($Colofon);//.mouseover(function(){
//			menuAnim(true);
//		});
		// qr
		var $LiQr = $Colofon.find('>li.qr');
		var $Qr = $('<div id="qr"></div>').appendTo($Body);
		$LiQr.hover(function(){
			$Qr.fadeIn('fast');
		},function(){
			$Qr.fadeOut('fast');
		});
	}

	// initEvents
	function initEvents() {
		//
		// keyboard
		$Document.keydown(function(e){
			var iWay = {37:4,38:1,39:2,40:3}[e.keyCode];
			if (iWay) processHash(aCurrentPages[iWay].id);
		});
		//
		// touch and drag
		$Body.mousedown(handleDrag);//.bind('mousewheel',handleMouseWheel);
		$Document.mousemove(handleDrag).mouseup(handleDrag);
		if (bTouch) {
			var mBody = $Body.get(0);
			mBody.ontouchstart = handleDrag;
			mBody.ontouchmove = handleDrag;
			mBody.ontouchend = handleDrag;
		}
		//
		// resize
		handleResize();
		$Window.resize(handleResize);
		//
		// hash change
		if ($Window.hashchange) $Window.hashchange(function(){
			processHash(location.hash);
			return false;
		});
		processHash(location.hash==''?oSettings.start:location.hash);
	}

	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////
	//////////////////////////////////////////////////////////////////////////////

	// handleColofonHover
	function handleColofonHover(e){
		var iTime = 300;
		var bEnter = e.type=='mouseenter';
		$Colofon.animate({opacity:bEnter?1:.2},{duration:iTime,queue:false});
//		if (bEnter) {
//			var oAnim = {duration:300};
//			setTimeout(function(){
//				$Colofon.find('>li.logo').animate({backgroundColor:'#F0A'},oAnim).animate({backgroundColor:'#000'},oAnim);
//				$Colofon.find('>li.name').animate({color:'#F0A'},oAnim).animate({color:'#000'},oAnim);
//			},iTime);
//		}
	}

	// handleDrag
	var pStart;
	var pLast;
	var bDown = false;
	function handleDrag(e){
		bReturn = true;
		var pNow = eventPos(e);
		switch (e.type) {
			case 'mousedown': case 'touchstart':
				pStart = pNow.clone();
				pLast = pNow.clone();
				bDown = true;
			break;
			case 'mouseup': case 'touchend':
				bDown = false;
				var pDst = pNow.clone().subtract(pStart);
				if (pDst.size()>50) {
					var bHor = Math.abs(pDst.x)>Math.abs(pDst.y);
					var bPos = pDst[bHor?'x':'y']>0;
					aCurrentPages[bHor?(bPos?4:2):(bPos?1:3)].page.click();
					bReturn = false;
				}
			break;
			case 'mousemove': case 'touchmove':
				if (bDown) {
					pLast = pNow.clone();
				}
				bReturn = false;
			break;
		}
		return bReturn;
	}
	// eventPos
	function eventPos(e){
		var oTouch = e.targetTouches?e.targetTouches[0]:e;
		return point(
			 oTouch.pageX
			,oTouch.pageY
		);
	}

	// processHash
	function processHash(hashid){
		var sId = hashid.replace('#','');
		if (sId[0]=='_') sId = sId.substr(1);
		var bIsPage = oPages.hasOwnProperty(sId);
		(bIsPage?gotoPage:showTag)(sId);
		return bIsPage;
	}
	
	// gotoPage
	function gotoPage(id){
		var oPage = oPages[id];
		//
		var iUpDown = Math.round((oPages.length-3)/3);
		var iC = oPage.nr;
		var iL = (oPage.nr-1+oPages.length)%oPages.length;
		var iR = (oPage.nr+1+oPages.length)%oPages.length;
		var iT = (oPage.nr-iUpDown+oPages.length)%oPages.length;
		var iB = (oPage.nr+iUpDown+oPages.length)%oPages.length;
		//
		var aPages = [];
		$.each([iC,iT,iR,iB,iL],function(i,nr){
			aPages.push(oPages[nr]);
		});
		//
		var fnMarkPageLoaded = function(){
			iLoaded--;
			if (iLoaded<=0&&aCurrentPages[0]!==aPages[0]&&!bPageTransition) {
				requestAnimFrame(function(){placePages(aPages)});
			}
		};
		//
		var iLoaded = 0;
		$.each(aPages,function(i,page){
			if (page.loaded===0) {
				iLoaded++;
				var oImg = page.imgs[0];
				document.loadImage(oImg.src,function(loadedImg){
					// grayscale image
					var cnGray = Pixastic.process(loadedImg.canvas,'hsl',{hue:0,saturation:-100,lightness:80});
					page.page.css({
						 width:		loadedImg.w
						,height:	loadedImg.h
					});
					var $Img = page.page.find('img');
					if (cnGray.toDataURL) {
						$Img.attr('src',cnGray.toDataURL("image/jpeg"));
					} else {
						$Img.replaceWith(cnGray);
					}

					// update model
					$.extend(page, {
						loaded: 1
						,w:	loadedImg.w
						,h:	loadedImg.h
						,centerImage: $('<img class="centerImg" />').appendTo(page.page).attr('src',oImg.src).click(clickImg).hide()
					});
					fnMarkPageLoaded();
				});
			}
		});
		if (iLoaded===0) fnMarkPageLoaded();
		else showRotator();

	}

	// showTag
	function showTag(id){
		var $LiTag; // find li (hash id cannot be present in page to prevent scroll-y)
		$Tags.find('>li').each(function(){
			if ($LiTag===undefined) {
				var $Li =  $(this);
				if (id==$Li.text().replace(/\s/,'').toLowerCase()) $LiTag = $Li;
			}
		});
		if ($LiTag!==undefined) {
			var bSelected = $LiTag.hasClass('select');
			var bMenuOpen = isMenuOpen();
			if (!bMenuOpen||bSelected) menuAnim();
			$Menus.find('li').removeClass('select');
			history.go(-1);
			if (!$LiTag.hasClass('select')) {
				setTimeout(function(){
					$LiTag.click();
				},iMenuAnimT);
			}
		}
	}

	function getPos(nr,w,h){ // nr = center top right bottom left
		var o;
		switch(nr){
			case 0: o = {	x:parseInt(iW/2-w/2),	y:parseInt(iH/2-h/2)	}; break;
			case 1: o = {	x:parseInt(iW/2-w/2),	y:iSideMargin-h			}; break;
			case 2: o = {	x:iW-iSideMargin,		y:parseInt(iH/2-h/2)	}; break;
			case 3: o = {	x:parseInt(iW/2-w/2),	y:iH-iSideMargin		}; break;
			case 4: o = {	x:iSideMargin-w,		y:parseInt(iH/2-h/2)	}; break;
		}
		return o;
	}

	// placePages // todo: eliminate $.find ea from method
	function placePages(pages){
		showRotator(false);
		//
		var bFirstPage = aCurrentPages.length===0;
		bPageTransition = true;
		var oPage, i, $RemPages = $(), $NewPages = $();
		// staying pages
		var iBaseXDst = bFirstPage?0:2*(iW-(iW-iBasePageW)/2-iSideMargin);
		var oDst = {x:iBaseXDst,y:0};
		for (i=0;i<aCurrentPages.length;i++) {
			oPage = aCurrentPages[i];
			oPage.from = getPos(i,oPage.w,oPage.h);
			var iIndex = pages.indexOf(oPage);
			if (iIndex!==-1) {
				oPage.to = getPos(iIndex,oPage.w,oPage.h);
				oDst.x = oPage.to.x-oPage.from.x;
				oDst.y = oPage.to.y-oPage.from.y;
			} else {
				oPage.to = null;
			}
		}
		// disappearing pages
		for (i=0;i<aCurrentPages.length;i++) {
			oPage = aCurrentPages[i];
			if (!oPage.to) {
				oPage.to = {
					 x:oPage.from.x+oDst.x
					,y:oPage.from.y+oDst.y
				};
			}
			if (pages.indexOf(oPage)===-1) {
				$RemPages.push(oPage.page[0]);
			}
		}
		// appearing pages
		for (i=0;i<pages.length;i++) {
			oPage = pages[i];
			oPage.page.appendTo($PageList);
			if (aCurrentPages.indexOf(oPage)===-1) {
				oPage.to = getPos(i,oPage.w,oPage.h);
				oPage.from = {
					 x:oPage.to.x-oDst.x
					,y:oPage.to.y-oDst.y
				};
				$NewPages.push(oPage.page[0]);
			}
		}
		$NewPages.css({opacity:1}); // todo: maybe animate
		// old center
		if (!bFirstPage) {
			var oOldCenter = aCurrentPages[0];
			var $OldCenter = oOldCenter.page.removeClass(sCenterCssName);//$PageList.find('.'+sCenterCssName).removeClass(sCenterCssName);
			var $OldCenElm = $OldCenter.find(sCenterElements);//oOldCenter.centerElements;//
		}
		// new center
		var oNewCenter = pages[0];
		var $NewCenter = oNewCenter.page;
		var $NewCntElm = $NewCenter.find(sCenterElements).css(oPrepareToFadeIn);//oNewCenter.centerElements.css(oPrepareToFadeIn);//
		// background
		var fBgPos = .1;
		var aBgPos = $Body.css('background-position').replace(/[%px]]/g,'').split(' ');
		var oBgPos = {x:parseInt(aBgPos[0]),y:parseInt(aBgPos[1])};
		// animate
		var iDuration = 900;
		var bMaxEaseOutBack = false;
		$({f:0}).animate({f:1},{
			duration: iDuration
			,easing: 'linear'
			,step:function(f){
				var fEaseOutBack = $.easing.easeOutBack(f,f*iDuration,0,1,iDuration);
				//
				// current pages
				$.each(aCurrentPages.concat(pages),function(i,page){
					page.page.css({
						 left:		page.from.x + fEaseOutBack*(page.to.x-page.from.x)
						,top:		page.from.y + fEaseOutBack*(page.to.y-page.from.y)
					});
				});
				//
				// old center
				if (!bFirstPage) {
					$OldCenter.css({boxShadow:'0px 0px 16px rgba(0,0,0,'+(.1+f*.4)+')'});
					$OldCenElm.css({opacity:Math.max(0,1-2*f)});
				}
				//
				// new center
				$NewCenter.css({boxShadow:'0px 0px 16px rgba(0,0,0,'+(.1+(f-1)*.4)+')'});
				if (f>.5) $NewCntElm.css({opacity:2*(f-.5)});
				//
				// background
				$Body.css('background-position',parseInt(oBgPos.x+fEaseOutBack*fBgPos*oDst.x)+'px '+parseInt(oBgPos.y+fEaseOutBack*fBgPos*oDst.y)+'px');
				//
				// fEaseOutBack is max(1.1) als f=.6
				if (!bMaxEaseOutBack&&f>=.6) {
					// remove corner pages
					$RemPages.detach();
					// hide text info
					if (!bFirstPage&&oOldCenter.loaded>0) $OldCenter.find('div.content').css({opacity:0}).hide();
					bMaxEaseOutBack = true;
				}
			}
			,complete:function(){
				$NewCenter.addClass(sCenterCssName);
				// old center stuff
				if (!bFirstPage) {
					$OldCenElm.hide();
					oOldCenter.currentImg = 0;
					setImg();
				}
				// transition finished
				location.hash = oNewCenter.id;
				aCurrentPages = pages;
				setMenuItem();
				bPageTransition = false;
				//
				for (var j=0;j<6;j++) oNewCenter.infoButton.animate({backgroundColor:j%2?'#599CEE':'#F0A'});
				//
				if (bFirstPage) firstPage();
			}
		});
	}

	// firstPage
	function firstPage(){
		handleResize();
		setTimeout(function(){$Colofon.mouseenter()},40);
		setTimeout(function(){$Colofon.mouseleave()},1200);
	}

	// setMenuItem
	function setMenuItem(){
		$Menu.find('li').removeClass('selected');
		$Menu.find('li:has(a[href='+location.hash+'])').addClass('selected');
		$Tags.find('li').removeClass('selected');
		var sTagIds = aCurrentPages[0].page.attr('class').replace(/\s/gi,',li#');
		$Tags.find(sTagIds).addClass('selected');
	}

	// menuAnim
	var iExtraMenuHeight;
	function getExtraMenuHeight(){
		if (iExtraMenuHeight===undefined){
			iExtraMenuHeight = 0;
			iExtraMenuHeight += parseInt($Menu.css('padding-top').replace('px',''));
			iExtraMenuHeight += parseInt($Menu.css('padding-bottom').replace('px',''));

			var sCSSShade;
			$.each(['box-shadow','-moz-box-shadow','-webkit-box-shadow'],function(i,s){
				if (!sCSSShade) sCSSShade = $('body.js div#menus div.shade').css(s);
			});
			if (sCSSShade) iExtraMenuHeight += parseInt(sCSSShade.replace(/rgba\(.*\)/g,'').split(' ')[3].replace('px',''))/2;
//			iExtraMenuHeight += parseInt($('body.js div#menus div.shade').css('box-shadow').replace(/rgba\(.*\)/g,'').split(' ')[3].replace('px',''))/2;
		}
		return iExtraMenuHeight;
	}
	function menuAnim(animIn){
		if (animIn===undefined) animIn = !isMenuOpen();
		var iMenusTopPos = -($Menu.height()+getExtraMenuHeight()); // + padding and shade
		if (animIn) $Menus.animate({top:'0px'},{duration:iMenuAnimT,queue:false});
		else		$Menus.animate({top:iMenusTopPos+'px'},{duration:iMenuAnimT,queue:false});
		return animIn;
	}

	// menuShown
	function isMenuOpen(){
		return $Menus.position().top===0
	}

	// repositionPages
	function repositionPages(dffw,dffh){
		$.each(aCurrentPages,function(i,page){
			page.to = getPos(i,page.w,page.h);
			if (!bPageTransition) {
				page.page.css({
					left:	page.to.x
					,top:	page.to.y
				});
			}
			// menus
			if (i===0) {
				var iMenuX = iSideMargin+(page.to.x-iSideMargin)/2;
				var iMenuY = iSideMargin+(iH-2*iSideMargin-iBasePageH)/4;
				$MenuTrigger.css('left',iMenuX+'px');
				$Menus.css('left',Math.max(180,iMenuX)+'px');
//				$Colofon.css({top:(iMenuY)-10+'px'});
				$Colofon.css({top:.6*iMenuY-10+'px'});
//				$Colofon.css({top:.7*iMenuY-10+'px'});
			}
		});
		// background
		var aBgPos = $Body.css('background-position').replace(/[%px]]/g,'').split(' ');
		var oBgPos = {x:parseInt(aBgPos[0]),y:parseInt(aBgPos[1])};
		$Body.css('background-position',parseInt(oBgPos.x+dffw/2)+'px '+parseInt(oBgPos.y+dffh/2)+'px');

	}


	// clickImg
	function clickImg(e){
		var bReturn = true;
		var oPage = getPage($(e.currentTarget).parents('.page').get(0)).pageobj;
		var $Page = oPage.page;
		if ($Page.hasClass(sCenterCssName)) {
			oPage.currentImg = (oPage.currentImg+1)%oPage.imgs.length;
			setImg();
			bReturn = false;
		}
		return bReturn;
	}
	// clickImgCnt
	function clickImgCnt(e){
		var $Li = $(e.currentTarget);
		var oPage = aCurrentPages[0];
		oPage.currentImg = $Li.index();
		setImg();
	}
	// setImg
	function setImg(){
		var oPage = aCurrentPages[0];
		if (oPage.centerImage) {
			var oImg = oPage.imgs[oPage.currentImg];
			if (!bHTML5)	oPage.centerImage.attr('src',oImg.src).attr('alt',oImg.alt);
			else			CIMG.tween(oPage.centerImage.get(0),oImg.src,500,CIMG.transition.square,TWEEN.Easing.Quadratic.EaseOut,{toDataURL:true});
			oPage.page.find('.imgcnt>li').removeClass('current').filter(':eq('+oPage.currentImg+')').addClass('current');
		}
	}


	// clickPage
	function clickPage(e){
		var $Page = $(e.currentTarget);
		if (!$Page.hasClass(sCenterCssName)) {
			processHash($Page.attr('id'));
		}
	}

	// hoverPage
	function hoverPage(e){
		if (!bPageTransition) {
			var oHover = getPage(e.currentTarget);
			if (oHover&&oHover.side!==0) {
				var oPage = oHover.pageobj;
				var iSide = oHover.side;
				var bEnter = e.type=='mouseenter';
				var bTop = iSide%2===1;
				var sPrp = bTop?'top':'left';
				var iVal = iSide%4<2?iSideHover:-iSideHover;
				var oAnim = {};
				oAnim[sPrp] = ((bTop?oPage.to.y:oPage.to.x)+(bEnter?iVal:0))+'px';
				oPage.page.animate(oAnim,{duration:300,easing:'easeInOutQuart',queue:false});
			}
		}
	}

	// getPage
	function getPage(mpage){
		var oReturn;
		for (var i=0;i<aCurrentPages.length;i++) {
			var oPage = aCurrentPages[i];
			if (oPage.page.get(0)===mpage) {
				oReturn = {side:i,pageobj:oPage};
				break;
			}
		}
		return oReturn;
	}

	// clickHash
	function clickHash(e){
		var $A = $(e.currentTarget);
		var sHash = $A.attr('href');
		processHash(sHash);
		$Menu.mouseleave();
		return false;
	}

	// handleResize
	function handleResize(){
		var iNewW = $Window.width();
		var iNewH = $Window.height();
		var iDffW = iNewW - iW;
		var iDffH = iNewH - iH;
		iW = iNewW;
		iH = iNewH;
		repositionPages(iDffW,iDffH,iW,iH);
	}

	// getvars
	function getvars(){
		if (location.href.indexOf('?')!==-1) {
			var aGetVars = location.href.split('?').pop().replace(location.hash,'').split('&');
			$.each(aGetVars,function(i,el){
				var aVar = el.split('=');
				oGetVars[aVar.shift()] = aVar.length?aVar.join('').toType():true;
			});
		}
	}

})(jQuery);


// used functions: easeOutBack, easeInOutQuart
jQuery.extend( jQuery.easing, {
	def: 'linear',
	/*swing: function (x, t, b, c, d) {
		//alert(jQuery.easing.default);
		return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
	},
	easeInQuad: function (x, t, b, c, d) {
		return c*(t/=d)*t + b;
	},
	easeOutQuad: function (x, t, b, c, d) {
		return -c *(t/=d)*(t-2) + b;
	},
	easeInOutQuad: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t + b;
		return -c/2 * ((--t)*(t-2) - 1) + b;
	},
	easeInCubic: function (x, t, b, c, d) {
		return c*(t/=d)*t*t + b;
	},
	easeOutCubic: function (x, t, b, c, d) {
		return c*((t=t/d-1)*t*t + 1) + b;
	},
	easeInOutCubic: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t + b;
		return c/2*((t-=2)*t*t + 2) + b;
	},
	easeInQuart: function (x, t, b, c, d) {
		return c*(t/=d)*t*t*t + b;
	},
	easeOutQuart: function (x, t, b, c, d) {
		return -c * ((t=t/d-1)*t*t*t - 1) + b;
	},*/
	easeInOutQuart: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
		return -c/2 * ((t-=2)*t*t*t - 2) + b;
	},
	/*easeInQuint: function (x, t, b, c, d) {
		return c*(t/=d)*t*t*t*t + b;
	},
	easeOutQuint: function (x, t, b, c, d) {
		return c*((t=t/d-1)*t*t*t*t + 1) + b;
	},
	easeInOutQuint: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
		return c/2*((t-=2)*t*t*t*t + 2) + b;
	},
	easeInSine: function (x, t, b, c, d) {
		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
	},
	easeOutSine: function (x, t, b, c, d) {
		return c * Math.sin(t/d * (Math.PI/2)) + b;
	},
	easeInOutSine: function (x, t, b, c, d) {
		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
	},
	easeInExpo: function (x, t, b, c, d) {
		return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
	},
	easeOutExpo: function (x, t, b, c, d) {
		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
	},
	easeInOutExpo: function (x, t, b, c, d) {
		if (t==0) return b;
		if (t==d) return b+c;
		if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
		return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
	},
	easeInCirc: function (x, t, b, c, d) {
		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
	},
	easeOutCirc: function (x, t, b, c, d) {
		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
	},
	easeInOutCirc: function (x, t, b, c, d) {
		if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
		return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
	},
	easeInElastic: function (x, t, b, c, d) {
		var s=1.70158, p=0, a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; s=p/4; }
		else s = p/(2*Math.PI) * Math.asin (c/a);
		return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
	},
	easeOutElastic: function (x, t, b, c, d) {
		var s=1.70158, p=0, a=c;
		if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
		if (a < Math.abs(c)) { a=c; s=p/4; }
		else s = p/(2*Math.PI) * Math.asin (c/a);
		return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
	},
	easeInOutElastic: function (x, t, b, c, d) {
		var s=1.70158, p=0, a=c;
		if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
		if (a < Math.abs(c)) { a=c; s=p/4; }
		else s = p/(2*Math.PI) * Math.asin (c/a);
		if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
		return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
	},
	easeInBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		return c*(t/=d)*t*((s+1)*t - s) + b;
	},*/
	easeOutBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	}/*,
	easeInOutBack: function (x, t, b, c, d, s) {
		if (s == undefined) s = 1.70158;
		if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
		return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
	},
	easeInBounce: function (x, t, b, c, d) {
		return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
	},
	easeOutBounce: function (x, t, b, c, d) {
		if ((t/=d) < (1/2.75)) {
			return c*(7.5625*t*t) + b;
		} else if (t < (2/2.75)) {
			return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
		} else {
			return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
		}
	},
	easeInOutBounce: function (x, t, b, c, d) {
		if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
		return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
	}*/
});



