var Morph = {
	// Proprietà
	config: {
		fps : 25
	},
	_cache: [null],
	// Metodi
	// ##################################
	// Loops
	// Metodo privato che crea la ricorsione
	_looper: function(c) {
		var l = Morph._cache[c];
		if(l) {
			Morph.set.apply(null, l.morphs);
			l.timeout = window.setTimeout('Morph._looper(' + c + ');', (l.time * 1000));
		}
	},
	// Imposta un loop
	setLoop: function() {
		var a = arguments, r = 0, c = Morph._cache.length, e = [], i, m, l = a.length, d;
		for(i = 0; i < l; i++) {
			o = Morph._adjust(a[i]);
			r += o.time + o.wait;
			a[i] = o;
			d = o.element;
			m = d;
			o = I(d);
			e[i] = m;
			if(!o._xFx) Morph._init(o);
			o._xFx.loop = c;
		}
		e = e.unique();
		Morph._cache[c] = {
			morphs: a,
			elements: e,
			c: c,
			time: r,
			timeout: null
		};
		Morph._looper(c, r);
		return c;
	},
	// Cancella un loop
	clearLoop: function(c, s) {
		var l = Morph._cache[c], m , t, i, k;
		if(l) {
			m = l.elements;
			t = l.timeout;
			if(s) Morph.stop(m);
			else {
				k = m.length;
				for(i = 0; i <= k; i++) m[i]._xFx.loop = null;
			}
			if(t) window.clearTimeout(l.timeout);
		}
		delete Morph._cache[c];
	},
	// Inizializzatore del morphing
	set: function() {
		// Base
		var a = arguments, l = a.length, r = 0, c = '', e = [], f,
		// Cicli
		i, u, o, x, k;
		// Controllo se è attiva un'animazione, il locking, inizializzo gli elementi e creo la lista di essi
		for(i = 0; i < l; i++) {
			a[i] = Morph._adjust(a[i]);
			u = a[i].element;
			o = I(u);
			x = o._xFx;
			if(!x) Morph._init(o);
			else if(x.animated === true) {
				if(x.locked) return false;
				Morph.stop(x.elements);
			}
			if(e.indexOf(u) == -1) {
				c += 'Morph._init("' + u + '");';
				e[e.length] = u;
			}
		}
		// Calcolo i tempi per i timeout e creo le animazioni
		for(i = 0; i < l; i++) {
			k = a[i];
			r += k.wait; k.wait = r; r += k.time;
			Morph._core(k);
		}
		// Setto il timomeout per il reset
		f = window.setTimeout(c, (r * 1000));
		l = e.length;

		for(i = 0; i < l; i++) {
			x = I(e[i])._xFx;
			x.frames = x.frames.concat(f);
			x.elements = e;
		}
		return e;
	},
	// Metodo privato del CORE del morphing
	_core : function(o) {
		var i = o.element, l = o.styles, s = {}, fps = Morph.config.fps, fpsDiv = 1000 / fps, t = Math.round(o.time * fps),
		e = o.effect, r = o.wait * 1000, c = ['in', 'cm', 'mm', 'pt', 'pc', 'em', 'ex', 'px', '%'],
		u = document.getElementById(i), f = [], z, og, oz, xFx = u._xFx, ss, ff, g, j, ll, lst, ls, ee, b,
		ii, jj, yy, mm = null, fs, p, m, exec = [], args = [];
		for(j in l) {
			ls = l[j];
			// Controllo che lo stile sia un array
			if(ls.constructor != Array) ls = [ls];
			// Ottengo lo stile attuale
			z = (j == 'opacity') ? Dom.getOpacity(i) : Dom.getStyle(i, j);
			// Se lo stile attuale è un colore diverso nel formato rg o hsl lo converto
			if(z && (z+'').match(/(hsl|rgb)\([0-9]+%?,[\s]*[0-9]+%?,[\s]*[0-9]+%?\)/i)) z = Color.css2hex(z);
			// Ottengo lo stile originale e nel caso lo setto
			og = xFx.originals[j];
			if(!og && og !== 0) { xFx.originals[j] = z; oz = z; } else oz = og;
			// Sostituisco gli stili attuali e originali
			ls = ls.replace('actual', z).replace('original', oz);
			// Se il primo elemento è una funzione la estraggo e la considero come effetto
			ee = (typeof ls[0] == 'function') ? ls.shift() : e;
			// Se il primo elemento è una unità di misura la estraggo e la conservo
			b = (c.indexOf(ls[0]) != -1) ? ls.shift() : '';
			// Lunghezza dell'array
			ll = ls.length;
			// Indice di scorrimento dei frame
			yy = 0;
			if(ls[0].toString().match(/((rgb|hsl)\([0-9]+%?,[\s]*[0-9]+%?,[\s]*[0-9]+%?\)|#[0-9ABCDEF]{3,6})/gi)) {
				if(ll < 2) {
					ls = [z].concat(ls);
					ll++;
				}
				p = Math.round(t / (ll - 1));
				var s0, s1, s2;
				for(ii = 0; ii < (ll - 1); ii++) {
					ss = Color.css2rgb(ls[ii]);
					ff = Color.css2rgb(ls[ii + 1]);
					g = (ii > 0) ? p + 1 : p;
					s0 = ss[0]; s1 = ss[1]; s2 = ss[2];
					for(jj = 0; jj < g; jj++) {
						if(ii === 0 || (ii > 0 && jj > 0)) {
							m = Color.rgb2hex([
								Math.floor(ee(jj, s0, (ff[0] - s0), g - 1)),
								Math.floor(ee(jj, s1, (ff[1] - s1), g - 1)),
								Math.floor(ee(jj, s2, (ff[2] - s2), g - 1))
							]);
							if(m !== mm) {
								ar = args[yy];
								if(!ar) exec[yy] = args[yy] = '';
								exec[yy] += 's.' + j + '="' + m + '";';
								args[yy] += ((!ar) ? '' : ',') + '"' + j + '":"' + m + '"';
								mm = m;
							}
							yy++;
						}
					}
				}
			} else if(b || typeof ls[0] == 'number') {
				if(ll < 2) {
					ls = [Tools.cleanSize(z)].concat(ls);
					ll++;
				}
				p = Math.round(t / (ll - 1));
				for(ii = 0; ii < (ll - 1); ii++) {
					ss = Tools.cleanSize(ls[ii]);
					ff = Tools.cleanSize(ls[ii + 1]);
					g = (ii > 0) ? p + 1 : p;
					for(jj = 0; jj < g; jj++) {
						if(ii === 0 || (ii > 0 && jj > 0)) {
							m = ee(jj, ss, (ff - ss), g - 1);
							if(!isNaN(m)) {
								m = ((b == 'em' || b === '') ? Math.floor(m * 100) / 100 : Math.floor(m)) + b;
								if((m || m === 0) && m !== mm) {
									ar = args[yy];
									if(!ar) exec[yy] = args[yy] = '';
									if(j == 'opacity') exec[yy] += 'Dom.setOpacity(u,' + m + ');';
									else exec[yy] += 's.' + j + '="' + m + '";';
									args[yy] += ((!ar) ? '' : ',') + '"' + j + '":"' + m + '"';
									mm = m;
								}
							}
							yy++;
						}
					}
				}
			} else {
				if(ll < 2) {
					ls = [ls[0], ls[0]];
					ll++;
				}
				p = Math.round(t / (ll - 1));

				if(!exec[0]) exec[0] = args[0] = '';
				m = ls[0];
				exec[0] += 's.' + j + '="' + m + '";';
				args[0] += '"' + j + '":"' + m + '"';

				for(ii = 1; ii < t - 1; ii++) if(ii % p === 0) {
					if(!exec[ii]) exec[ii] = args[ii] = '';
					m = ls[(ii / p)];
					exec[ii] += 's.' + j + '="' + m + '";';
					args[ii] += ',"' + j + '":"' + m + '"';
				}

				lst = ll - 1;
				if(!exec[t - 1]) exec[t - 1] = args[t - 1] = '';
				m = ls[lst];
				exec[t - 1] += 's.' + j + '="' + m + '";';
				args[t - 1] += ',"' + j + '":"' + m + '"';
			}
			if(b) ls = [b].concat(ls);
			if(e !== ee) ls = [ee].concat(ls);
			l[j] = ls;
		}
		var v = '', y = '', cd = '', cf = '', os = o.onstart, oh = o.onfinish, oc = o.onchange, of = o.onframe,
		k = 0, x = '', af, a, fl = 0;
		z = 'var u = document.getElementById("' + i + '"), s = u.style;';
		// onChange // per i frame non vuoti
		if(oc) {
			k = Morph._cache.length;
			Morph._cache[k] = oc;
			cd = 'Morph._cache[' + k + '].apply(u,';
			cf = 'delete Morph._cache[' + k + '];';
		}
		// onFrame // per ogni frame
		if(of) {
			k = Morph._cache.length;
			Morph._cache[k] = of;
			v = 'Morph._cache[' + k + '].apply(u,';
			y = 'delete Morph._cache[' + k + '];';
		}
		for(j = 0; j < t; j++) {
			x = '';
			// Se è il frame 0 e non coincide con l'ultimo, e è settato un evento iniziale
			if(j === 0 && j != (t - 1) && os) {
				k = Morph._cache.length;
				Morph._cache[k] = os;
				x += 'Morph._cache[' + k + '].apply(u);delete Morph._cache[' + k + '];';
			}
			m = exec[j];
			if(m) x += m;
			m = args[j];
			if(!m) m = '';
			ar = '[{' + m + '},' + (j + 1) + ',' + t + ']';
			//ar = '[' + (j + 1) + ',' + t + ',{' + m + '}]';

			// Se è
			if((x || j == (t - 1)) && cd) x += cd + ar + ');';
			if(v) x += v + ar + ');'; // Tolto  != ''
			if(j == (t - 1)) {
				if(oh) {
					k = Morph._cache.length;
					Morph._cache[k] = oh;
					x += 'Morph._cache[' + k + '].apply(u);delete Morph._cache[' + k + '];';
				}
				x += y + cf;
			}
			if(x) {
				x = z + x + 'u._xFx.frames.shift();';
				f[fl++] = window.setTimeout(x, Math.round((fpsDiv * (j + 1)) + r));
			}
		}
		xFx.frames = xFx.frames.concat(f);
		xFx.locked = o.locked;
		xFx.animated = true;
	},
	_adjust: function(m) {
		var i = m.element, z = m.styles, e = m.effect, s = m.onstart, f = m.onfinish, a = m.onframe, c = m.onchange,
		t = m.time, w = m.wait, h = m.hits;
		return {
			element: ((i) ? Dom.getId(i, true) : null),
			styles: ((z && typeof z == 'object') ? z : {}),
			effect: ((e) ? ((typeof e == 'function') ? e : Effects[e]) : Effects.linear),
			time: ((t) ? parseFloat(t) : 1),
			wait: ((w) ? parseFloat(w) : 0),
			hits: ((h) ? parseInt(h, 10) : 1),
			onstart: ((typeof s == 'function') ? s : null),
			onfinish: ((typeof f == 'function') ? f : null),
			onframe: ((typeof a == 'function') ? a : null),
			onchange: ((typeof c == 'function') ? c : null),
			locked: ((m.locked) ? true : false)
			//attend: ((m.attend) ? true : false)
		};
	},
	// Inizializza la proprietà privata per gli elementi in morphing
	_init: function(o) {
		o = I(o);
		if(o) {
			if(!o._xFx) o._xFx = {originals : {}};
			o = o._xFx;
			o.frames = [];
			o.animated = false;
			o.elements = [];
			o.locked = false;
			o.paused = [];
			o.loop = null;
		}
	},
	_runCode: function(o) {
		o = I(o);
		var x = o._xFx, m;
		if(x.paused.length > 0) {
			m = x.paused.shift();
			Morph.set.apply(null, m);
		}
	},
	// Resetta gli stili originali
	resetStyles: function(o) {
		o = I(o);
		var x = o._xFx, r, i;
		if(x) {
			r = x.originals;
			for(i in r) Dom.setStyle(o, i, r[i]);
		}
	},
	// Ferma il morphing
	stop: function(l) {
		if(l.constructor != Array) l = [l];

		var i, k = l.length, o, x, f, g, j, p, u;

		for(i = 0; i < k; i++) {
			o = I(l[i]); x = o._xFx;
			if(x) {
				f = x.frames; g = x.loop; p = f.length;
				for(j = 0; j < p; j++) window.clearTimeout(f[j]);
				if(g && Morph._cache[g]) {
					u = Morph._cache[g].l;
					if(u) window.clearTimeout(u);
					delete Morph._cache[g];
				}
				x.loop = null;
			}
			Morph._init(o);
		}
	}
};


var Fx = {
	// #############################################
	opacityUp: function() {
		o = Morph._adjust(o);
		o.styles.opacity = ['actual', 1];
		Morph.set(o);
	},
	opacityDown: function(o) {
		o = Morph._adjust(o);
		o.styles.opacity = ['actual', 0];
		Morph.set(o);
	},
	// Usa il morph
	opacityShift: function(o) {
		o = Morph._adjust(o);
		var i = o.element;
		i = Dom.getOpacity(i);
		if(i < 0.50) Fx.opacityUp(o);
		else Fx.opacityDown(o);
	},
	// Blind Up-Down
	blindInit: function(o, c) {
		var i = I(o), s = i.style;
		s.overflow = 'hidden';
		s.display = 'block';
		if(c) s.height = '0px';
	},
	blindUp: function(o) {
		o = Morph._adjust(o);
		var i = I(o.element), n, h;
		Fx.blindInit(i);
		n = Tools.cleanSize(Dom.getStyle(i, 'height'));
		h = Dom.realHeight(i);
		h = (h > n) ? h : n;
		o.styles.height = ['px', h, 0];
		Morph.set(o);
	},
	blindDown: function(o) {
		o = Morph._adjust(o);
		var i = I(o.element), h;
		Fx.blindInit(i);
		h = Tools.cleanSize(Dom.getStyle(i, 'height'));
		h = (h > 0) ? h : 0;
		o.styles.height = ['px', h, Dom.realHeight(i)];
		Morph.set(o);
	},
	blindShift: function(o) {
		var i = o.element, s = Fx.blindStatus(i);
		if(s < 3) Fx.blindUp(o);
		else Fx.blindDown(o);
	},
	// To check the blind
	blindStatus: function(o) {
		var r = Dom.realHeight(o), h = Tools.cleanSize(Dom.getStyle(o, 'height')), m = r / 2;
		if(h == r) return 1;
		if(h === 0) return 5;
		if(h > m) return 2;
		if(h < m) return 3;
		if(h == m) return 4;
		return false;
	},
	// Effetti complessi
	foldUp: function(o) {
		if(!o.effect) o.effect = Effects.outCubic;
		var a = Morph._adjust(o), b = Morph._adjust(o);
		var i = I(a.element), s = i.style, t = a.time / 2;
		s.overflow = 'hidden'; s.display = 'block';
		var n = Tools.cleanSize(Dom.getStyles(i, 'height').height), h = Dom.realHeight(i);
		h = (h > n) ? h : n;
		a.time = t; b.time = t;
		a.styles.height = ['px', h, 5];
		a.onfinish = null;
		b.styles.width = ['px', 0];
		b.onstart = null;
		Morph.set(a, b);
	},
	pulse: function(o){
		o = Morph._adjust(o);
		var r = [1], h = o.hits;
		for(i = 0; i < h; i++) r = r.concat([0, 1]);
		o.styles.opacity = r;
		Morph.set(o);
	},
	drop: function(o) {
		if(!o.effect) o.effect = Effects.outCubic;
		o = Morph._adjust(o);
		var i = I(o.element), s = Dom.getStyles(i, 'height', 'position', 'top'),
		t = Tools.cleanSize(s.top), h = Tools.cleanSize(s.height);
		if(s.position != 'absolute') i.style.position = 'relative';
		o.styles.opacity = [1, 0];
		o.styles.top = ['px', t, t+h];
		Morph.set(o);
	},
	vclose: function(o) {
		if(!o.effect) o.effect = Effects.outCubic;
		o = Morph._adjust(o);
		var i = o.element;
		Dom.setStyles(i, {overflow: 'hidden', display: 'block'});
		var s = Dom.getStyles(i, 'height', 'marginTop', 'marginBottom', 'fontSize'),
		n = Tools.cleanSize(s.height), h = Dom.realHeight(i),
		f = Tools.cleanSize(s.fontSize, true);
		h = (h > n) ? h : n;
		if(f[0] === 0) f = [1, 'em'];
		//o.styles.opacity = [1, 0];
		o.styles.height = ['px', h, 0];
		//o.styles.fontSize = [f[1], f[0], 0];
		o.onframe = function() {
			var a = Tools.cleanSize(Dom.getStyle(this, 'height'));
			this.style.marginTop = ((h - a) / 2) + 'px';
			this.style.marginBottom = ((h - a) / 2) + 'px';
		 };
		Morph.set(o);
	},
	vanish: function(o) {
		if(!o.effect) o.effect = Effects.outCubic;
		o = Morph._adjust(o);
		var i = o.element,
		s = Dom.getStyles(i, 'width', 'height', 'marginTop', 'marginRight', 'marginBottom', 'marginLeft', 'fontSize'),
		w = Tools.cleanSize(s.width, true), h = Tools.cleanSize(s.height, true), f = Tools.cleanSize(s.fontSize, true);
		if(f[0] === 0) f = [1, 'em'];
		s = o.styles;
		s.opacity = [1,0];
		s.width = [w[1], w[0], (w[0]*2)];
		s.height = [h[1], h[0], (h[0]*2)];
		s.fontSize = [f[1], f[0], (f[0]*2)];
		o.onframe = function() {
			var s = Dom.getStyles(this, 'width', 'height'),
			l = Tools.cleanSize(s.width), a = Tools.cleanSize(s.height);
			s = this.style;
			s.marginTop = ((h[0] - a) / 2) + h[1];
			s.marginRight = ((w[0] - l) / 2) + w[1];
			s.marginBottom = ((h[0] - a) / 2) + h[1];
			s.marginLeft = ((w[0] - l) / 2) + w[1];
		};
		Morph.set(o);
	},

	// #############################################
	// Non usa il morph
	hide: function() {
		var a = arguments, i, l = a.length;
		for(i = 0; i < l; i++) I(a[i]).style.visibility = 'hidden';
	},
	hideByTagName: function() {
		var a = arguments, l = a.length, r = [], i;
		for(i = 0; i < l; i++) r = r.concat(Dom.byTagName(a[i]));
		Fx.hide.apply(this, r);
	},
	animage: function(o, c) {
		var u = o.url, w = parseInt(o.width, 10), h = parseInt(o.height, 10), f = parseInt(o.frames, 10),
		d = o.delay, p = o.pause, v = o.vertical,
		l = o.loop, i = 'animage_' + Tools.randomString(), s = o.style, g = new Image(); g.src = u;

		if(!c || !u || !w || !h || !f) return false;

		d = (d) ? parseInt(d, 10) : 40;
		p = (p) ? parseInt(p, 10) : 40;
		l = (l) ? ((typeof l == 'number') ? parseInt(l, 10) : Infinity) : 1;
		s = (s == 'object' || s == 'string') ? s : {};

		if(!f) {
			if(v) f = Math.round(g.height / h);
			else f = Math.round(g.width / w);
		}

		Dom.create(['div',
			{
				style: {
					display: 'block',
					width: w + 'px',
					height: h + 'px',
					backgroundImage: "url('" + u + "')",
					backgroundRepeat: 'no-repeat',
					backgroundPosition: "0px 0px"
				},
				id: i,
				className: 'animage'
			}
		], c);
		Dom.setStyles(i, s);
		if(v === true) w = 0; else h = 0;
		Fx._animageLoop(i, w, h, f, d, p, l, 0);
	},
	_animageLoop: function(i, w, h, f, d, p, l, a) {
		var t = d;
		if(a === 0 || a == f) {
			a = 0;
			t = p;
			l--;
		}
		if(l >= 0) {
			I(i).style.backgroundPosition = "-" + (w * a) + "px -" + (h * a) + "px";
			a++;
			window.setTimeout("Fx._animageLoop('" + i + "'," + w + "," + h + "," + f + "," + d + "," + p + "," + l + "," + a + ")", t);
		}
	},
	makeTabs: function(o, a, e) {
		o = I(o); a = P(a, o); var l = a.length, f = false;
		for(var i = 0; i < l; i++) {
			var b = a[i];
			var n = b.tagName;
			if(n && n.toLowerCase() == 'a') {
				var h = b.getAttribute('href'), s = h.split('#'), d;
				if(s[1]) {
					d = I(s[1]);
					s = d.style;
					if(d) {
						if(!f) {
							s.display = 'block';
							Dom.addClass(b, 'active');
							f = true;
						} else {
							s.display = 'none';
							s.height = '0px';
							Dom.setOpacity(d, 0);
						}

						b.onclick = function() {
							if(Dom.hasClass(this, 'active')) return false;

							var h = null;
							for(var j = 0; j < l; j++) {
								var b = a[j];
								var n = b.tagName;
								if(n && n.toLowerCase() == 'a') {
									if(Dom.hasClass(a[j], 'active')) {
										h = b.getAttribute('href').split('#');
										Dom.removeClass(a[j], 'active');
										break;
									}
								}
							}

							var s = this.getAttribute('href').split('#');

							if(h) {
								Fx.blindUp({
									element: h[1],
									styles: {
										opacity: [1, 0],
										display: ['block', 'none']
									},
									onfinish: function() {
										Fx.blindDown({
											element: s[1],
											styles: {
												opacity: [0, 1],
												display: ['block']
											},
											time: 0.5
										});
									},
									time: 0.5
								});
							} else {
								Fx.blindDown({
									element: s[1],
									styles: {
										opacity: [0, 1],
										display: ['block']
									},
									time: 0.5
								});
							}
							Dom.addClass(this, 'active');
							return false;
						};
					}
				}
			}
		}
	},
	IEAlphaPngFix: function() {
		var e = Agent.MSIE;
		if(!e || e < 5.5 || e >= 7) return false;
		alert(true);
		var a = Types.toArray(arguments), g = (a.length > 0) ? a : T('img');
		g.forEach(function(o) {
			o = I(o);
			var s = o.src;
			if(s.match(/^[^\?]+\.png(\?.*)?(#.*)?$/gi)) {
				var a = {}, i = o.id, c = o.className, t = o.title, l = o.alt, z = o.style.cssText, g = o.align;
				if(i) a.id = i;
				if(c) a.className = c;
				if(t) a.title = t; else if(l) a.title = l;
				z = 'width:' + o.width + 'px;height:' + o.height + 'px;display:inline-block;' + z;
				if(g == "left") z = "float:left;" + z; else if(g == "right") z = "float:right;" + z;
				if(o.parentElement.href) z = "cursor:hand;" + z;
				/*if(img.useMap) {
					 strAddMap = "<img style=\"position:relative; left:-" + img.width + "px;"
					 + "height:" + img.height + "px;width:" + img.width +"\" "
					 + "src=\"" + strGif + "\" usemap=\"" + img.useMap
					 + "\" border=\"" + img.border + "\">"
				}*/
				z += ';filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + s + '\', sizingMethod=\'scale\');';
				a.style = z;
				var n = Dom.create(['span', a]);
				Dom.after(o, n);
				Event.clone(o, n);
				Dom.remove(o);
	 		}
		});
	}
};



var Color = {
	// Metodo per ottenere un oggetto contenente
	colorize: function(o, e, f, d) {
		var s = {}, r = {}, g = ['backgroundColor', 'borderTopColor', 'borderRightColor', 'borderBottomColor', 'borderLeftColor', 'color'],
			n = 0, i, j, z, c;
		o = I(o);
		if(!e) e = Color.toGrayscale; if(!f) f = '#000000';
		if(o.currentStyle) s = o.currentStyle;
		else if(document.defaultView.getComputedStyle) s = document.defaultView.getComputedStyle(o, '');
		for(i = g.length - 1; i >= 0; i--) {
			j = g[i]; z = s[j];
			if(z.length > 0 && z != 'transparent') {
				c = Color.css2hex(z);
				r[j] = (d) ? [e(c, f), c] : [c, e(c, f)];
				n++;
			}
		}
		return (n > 0) ? r : false;
	},
	// Metodi per convertire i colori
	sepia: function(o) {
		o = Color.hex2rgb(o);
		var a = o[0], b = o[1], c = o[2];
		return Color.rgb2hex([
			Math.round((a * 0.393) + (b * 0.769) + (c * 0.189)),
			Math.round((a * 0.349) + (b * 0.686) + (c * 0.168)),
			Math.round((a * 0.272) + (b * 0.534) + (c * 0.131))
		]);
	},
	negative: function(c) {
		c = Color.hex2rgb(c);
		return Color.rgb2hex([255 - c[0], 255 - c[1], 255 - c[2]]);
	},
	grayscale: function(o, f) {
		if(!f) f = 4; o = Color.hex2rgb(o);
		var a = o[0], b = o[1], c = o[2], r = [];
		switch(f) {
			case 1: case 'SimpleAverage':
				r = [Math.round((a + b + c) / 3),
					Math.round((a + b + c) / 3),
					Math.round((a + b + c) / 3)];
			break;
			case 2: case 'WeightAverage':
				r = [Math.round((3 * a) + (4 * c) + (2 * b) / 9),
					Math.round((3 * a) + (4 * c) + (2 * b) / 9),
					Math.round((3 * a) + (4 * c) + (2 * b) / 9)];
			break;
			case 3: case 'CCIRRec709':
				r = [Math.round((0.2125 * a) + (0.7154 * b) + (0.0721 * c)),
					Math.round((0.2125 * a) + (0.7154 * b) + (0.0721 * c)),
					Math.round((0.2125 * a) + (0.7154 * b) + (0.0721 * c))];
			break;
			default: case 4: case 'NtscPal':
				r = [Math.round((0.299 * a) + (0.587 * b) + (0.114 * c)),
					Math.round((0.299 * a) + (0.587 * b) + (0.114 * c)),
					Math.round((0.299 * a) + (0.587 * b) + (0.114 * c))];
			break;
		}
		return Color.rgb2hex(r);
	},
	monochrome: function(o, f) {
		o = Color.hex2rgb(o); f = Color.hex2rgb(f);
		var a = o[0], b = o[1], c = o[2], x = f[0], y = f[1], z = f[2];
		return Color.rgb2hex([
			Math.round((a * (x / 255)) + (b * (x / 255)) + (c * (x / 255))),
			Math.round((a * (y / 255)) + (b * (y / 255)) + (c * (y / 255))),
			Math.round((a * (z / 255)) + (b * (z / 255)) + (c * (z / 255)))
		]);
	},
	color: function(o, f) {
		o = Color.hex2rgb(o);
		var a = o[0], b = o[1], c = o[2];
		return Color.rgb2hex([
			a + Math.round(a / 100 * f[0]),
			b + Math.round(b / 100 * f[1]),
			c + Math.round(c / 100 * f[2])
		]);
	},
	contrast: function(c, f) {
		c = Color.hex2rgb(c);
		return Color.rgb2hex([
			((((c[0] / 255) - 0.5) * Math.pow((1 + (f / 100)), 2)) + 0.5) * 255,
			((((c[1] / 255) - 0.5) * Math.pow((1 + (f / 100)), 2)) + 0.5) * 255,
			((((c[2] / 255) - 0.5) * Math.pow((1 + (f / 100)), 2)) + 0.5) * 255
		]);
	},
	brightness: function(c, f) {
		c = Color.hex2rgb(c);
		return Color.rgb2hex([
			c[0] + Math.round(255 / 100 * f),
			c[1] + Math.round(255 / 100 * f),
			c[2] + Math.round(255 / 100 * f)
		]);
	},
	media: function() {
		var a = arguments, l = a.length, i, c, r = 0, g = 0, b = 0;
		for(i = l - 1; i >= 0; i--) {
			c = Color.hex2rgb(a[i]);
			r += c[0]; g += c[1]; b += c[2];
		}
		r /= l; g /= l; b /= l;
		return Color.rgb2hex([r, g, b]);
	},
	hex2rgb: function(h) {
		h = h.replace('#', '');
		return [Color.hex2dec(h.substring(0, 2)), Color.hex2dec(h.substring(2, 4)), Color.hex2dec(h.substring(4, 6))];
	},
	rgb2hex: function(a) {
		var r = a[0], g = a[1], b = a[2];
		if(!r) r = 0; if(!g) g = 0; if(!b) b = 0;
		return ('#' + Color.dec2hex(r) + Color.dec2hex(g) + Color.dec2hex(b)).toUpperCase();
	},
	css2hex: function(c) {
		return Color.rgb2hex(Color.css2rgb(c));
	},
	allCss2rgb: function(c) {
		var m = c.match(/((rgb|hsl)\([0-9]+%?,[\s]*[0-9]+%?,[\s]*[0-9]+%?\)|#[0-9ABCDEF]{3,6})/gi);
		if(!m)  return null;
		for(var i = 0, l = 4, r = []; i < l; i++) {
			c = m[i];
			if(c) c = Color.css2rgb(c);
			else {
				if(i == 1 || i == 2) c = r[0];
				if(i == 3) c = r[1];
			}
			r[i] = c;
		}
		return r;
	},
	css2rgb: function(c) {
		if(c.match(/^#[0-9ABCDEF]{6}$/gi)) return Color.hex2rgb(c);
		var m = c.match(/rgb\(([0-9]+%?),[\s]*([0-9]+%?),[\s]*([0-9]+%?)\)/i), r, g, b;
		if(m) {
			r = m[1]; g = m[2]; b = m[3];
			r = parseInt(r, 10) * ((r.indexOf('%') >= 0) ? 2.55 : 1);
			g = parseInt(g, 10) * ((g.indexOf('%') >= 0) ? 2.55 : 1);
			b = parseInt(b, 10) * ((b.indexOf('%') >= 0) ? 2.55 : 1);
			return [r, g, b];
		}
		m = c.match(/hsl\(([0-9]+?),[\s]*([0-9]+%),[\s]*([0-9]+%)\)/i);
		if(m) return Color.hsl2rgb([parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10)], t);
		return [0, 0, 0];
	},
	// Converte la serie di valori hls in rgb
 	hsl2rgb: function(c) {
		var h = c[0] / 360, s = c[1] / 100, l = c[2] / 100;
		if(l <= 0.5) m2 = l * (s + 1);
		else m2 = l + s - l * s;
		m1 = l * 2 - m2;
		r = Color.hue2rgb(m1, m2, h + 1 / 3);
		g = Color.hue2rgb(m1, m2, h);
		b = Color.hue2rgb(m1, m2, h - 1 / 3);
		return [Math.round(r*255), Math.round(g*255), Math.round(b*255)];
	},
	hue2rgb: function(m1, m2, h) {
		if(h < 0) h = h + 1;
		if(h > 1) h = h - 1;
		if(h * 6 < 1) return m1 + (m2 - m1) * h * 6;
		if(h * 2 < 1) return m2;
		if(h * 3 < 2) return m1 + (m2 - m1) * (2 / 3 - h) * 6;
		return m1;
	},
	// restituisce la CSS stringa rgb
	_rgb: function(c, s) {
		if(s) return 'rgb(' + c[0] + ',' + c[1] + ',' + c[2] + ')';
		return c;
	},
	hex2dec: function(d) {
		d = parseInt(d, 16);
		return ((d > 255) ? 255 : ((d < 0) ? 0 : d));
	},
	dec2hex: function(o) {
		var d = (o > 255) ? 255 : ((o < 0) ? 0 : o), h = parseInt(d, 10).toString(16);
		if(d < 16) h = '0' + h;
		return h;
	},
	/*cmyk2rgb: function(c, m, y, k) {
		var b = (255 - k) / 255;
		return [
			(255 - c) * b,
			(255 - m) * b,
			(255 - y) * b
		];
	},*/
	hex2name: function(c) {
		c = c.toUpperCase();
		var n = Color._names, l = n.length, i, d;
		for(i = l - e; i >= 0; i--) {
			d = n[i];
			if(c == d[1]) return d[0];
		}
		return null;
	},
	rgb2name: function(c) {
		return Color.hex2name(Color.rgb2hex(c));
	},
	name2hex: function(c) {
		c = c.toLowerCase();
		var n = Color._names, l = n.length, i, d;
		for(i = l - e; i >= 0; i--) {
			d = n[i];
			if(c == d[0].toLowerCase()) return d[1];
		}
		return null;
	},
	name2rgb: function(c) {
		c = Color.name2hex(c);
		if(c) c = Color.hex2rgb(c);
		return c;
	},
	_names: [
		['AliceBlue', '#F0F8FF'],
		['AntiqueWhite', '#FAEBD7'],
		['Aqua', '#00FFFF'],
		['Aquamarine', '#7FFFD4'],
		['Azure', '#F0FFFF'],
		['Beige', '#F5F5DC'],
		['Bisque', '#FFE4C4'],
		['Black', '#000000'],
		['BlanchedAlmond', '#FFEBCD'],
		['Blue', '#0000FF'],
		['BlueViolet', '#8A2BE2'],
		['Brown', '#A52A2A'],
		['BurlyWood', '#DEB887'],
		['CadetBlue', '#5F9EA0'],
		['Chartreuse', '#7FFF00'],
		['Chocolate', '#D2691E'],
		['Coral', '#FF7F50'],
		['CornflowerBlue', '#6495ED'],
		['Cornsilk', '#FFF8DC'],
		['Crimson', '#DC143C'],
		['Cyan', '#00FFFF'],
		['DarkBlue', '#00008B'],
		['DarkCyan', '#008B8B'],
		['DarkGoldenRod', '#B8860B'],
		['DarkGray', '#A9A9A9'],
		['DarkGrey', '#A9A9A9'],
		['DarkGreen', '#006400'],
		['DarkKhaki', '#BDB76B'],
		['DarkMagenta', '#8B008B'],
		['DarkOliveGreen', '#556B2F'],
		['Darkorange', '#FF8C00'],
		['DarkOrchid', '#9932CC'],
		['DarkRed', '#8B0000'],
		['DarkSalmon', '#E9967A'],
		['DarkSeaGreen', '#8FBC8F'],
		['DarkSlateBlue', '#483D8B'],
		['DarkSlateGray', '#2F4F4F'],
		['DarkSlateGrey', '#2F4F4F'],
		['DarkTurquoise', '#00CED1'],
		['DarkViolet', '#9400D3'],
		['DeepPink', '#FF1493'],
		['DeepSkyBlue', '#00BFFF'],
		['DimGray', '#696969'],
		['DimGrey', '#696969'],
		['DodgerBlue', '#1E90FF'],
		['FireBrick', '#B22222'],
		['FloralWhite', '#FFFAF0'],
		['ForestGreen', '#228B22'],
		['Fuchsia', '#FF00FF'],
		['Gainsboro', '#DCDCDC'],
		['GhostWhite', '#F8F8FF'],
		['Gold', '#FFD700'],
		['GoldenRod', '#DAA520'],
		['Gray', '#808080'],
		['Grey', '#808080'],
		['Green', '#008000'],
		['GreenYellow', '#ADFF2F'],
		['HoneyDew', '#F0FFF0'],
		['HotPink', '#FF69B4'],
		['IndianRed ', '#CD5C5C'],
		['Indigo ', '#4B0082'],
		['Ivory', '#FFFFF0'],
		['Khaki', '#F0E68C'],
		['Lavender', '#E6E6FA'],
		['LavenderBlush', '#FFF0F5'],
		['LawnGreen', '#7CFC00'],
		['LemonChiffon', '#FFFACD'],
		['LightBlue', '#ADD8E6'],
		['LightCoral', '#F08080'],
		['LightCyan', '#E0FFFF'],
		['LightGoldenRodYellow', '#FAFAD2'],
		['LightGray', '#D3D3D3'],
		['LightGrey', '#D3D3D3'],
		['LightGreen', '#90EE90'],
		['LightPink', '#FFB6C1'],
		['LightSalmon', '#FFA07A'],
		['LightSeaGreen', '#20B2AA'],
		['LightSkyBlue', '#87CEFA'],
		['LightSlateGray', '#778899'],
		['LightSlateGrey', '#778899'],
		['LightSteelBlue', '#B0C4DE'],
		['LightYellow', '#FFFFE0'],
		['Lime', '#00FF00'],
		['LimeGreen', '#32CD32'],
		['Linen', '#FAF0E6'],
		['Magenta', '#FF00FF'],
		['Maroon', '#800000'],
		['MediumAquaMarine', '#66CDAA'],
		['MediumBlue', '#0000CD'],
		['MediumOrchid', '#BA55D3'],
		['MediumPurple', '#9370D8'],
		['MediumSeaGreen', '#3CB371'],
		['MediumSlateBlue', '#7B68EE'],
		['MediumSpringGreen', '#00FA9A'],
		['MediumTurquoise', '#48D1CC'],
		['MediumVioletRed', '#C71585'],
		['MidnightBlue', '#191970'],
		['MintCream', '#F5FFFA'],
		['MistyRose', '#FFE4E1'],
		['Moccasin', '#FFE4B5'],
		['NavajoWhite', '#FFDEAD'],
		['Navy', '#000080'],
		['OldLace', '#FDF5E6'],
		['Olive', '#808000'],
		['OliveDrab', '#6B8E23'],
		['Orange', '#FFA500'],
		['OrangeRed', '#FF4500'],
		['Orchid', '#DA70D6'],
		['PaleGoldenRod', '#EEE8AA'],
		['PaleGreen', '#98FB98'],
		['PaleTurquoise', '#AFEEEE'],
		['PaleVioletRed', '#D87093'],
		['PapayaWhip', '#FFEFD5'],
		['PeachPuff', '#FFDAB9'],
		['Peru', '#CD853F'],
		['Pink', '#FFC0CB'],
		['Plum', '#DDA0DD'],
		['PowderBlue', '#B0E0E6'],
		['Purple', '#800080'],
		['Red', '#FF0000'],
		['RosyBrown', '#BC8F8F'],
		['RoyalBlue', '#4169E1'],
		['SaddleBrown', '#8B4513'],
		['Salmon', '#FA8072'],
		['SandyBrown', '#F4A460'],
		['SeaGreen', '#2E8B57'],
		['SeaShell', '#FFF5EE'],
		['Sienna', '#A0522D'],
		['Silver', '#C0C0C0'],
		['SkyBlue', '#87CEEB'],
		['SlateBlue', '#6A5ACD'],
		['SlateGray', '#708090'],
		['SlateGrey', '#708090'],
		['Snow', '#FFFAFA'],
		['SpringGreen', '#00FF7F'],
		['SteelBlue', '#4682B4'],
		['Tan', '#D2B48C'],
		['Teal', '#008080'],
		['Thistle', '#D8BFD8'],
		['Tomato', '#FF6347'],
		['Turquoise', '#40E0D0'],
		['Violet', '#EE82EE'],
		['Wheat', '#F5DEB3'],
		['White', '#FFFFFF'],
		['WhiteSmoke', '#F5F5F5'],
		['Yellow', '#FFFF00'],
		['YellowGreen', '#9ACD32']
	]
};



// Easing Equations from Robert Penner http://www.robertpenner.com/
var Effects = {
	linear: function (t, b, c, d) {
		return c*t/d + b;
	},
	inQuad: function(t, b, c, d) {
		return c*(t/=d)*t + b;
	},
	outQuad: function(t, b, c, d) {
		return -c *(t/=d)*(t-2) + b;
	},
	inOutQuad: function(t, b, c, d) {
		if ((t/=d/2) < 1) return c/2*t*t + b;
		return -c/2 * ((--t)*(t-2) - 1) + b;
	},
	inCubic: function (t, b, c, d) {
		return c*(t/=d)*t*t + b;
	},
	outCubic: function (t, b, c, d) {
		return c*((t=t/d-1)*t*t + 1) + b;
	},
	inOutCubic: function (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;
	},
	inQuart: function (t, b, c, d) {
		return c*(t/=d)*t*t*t + b;
	},
	outQuart: function (t, b, c, d) {
		return -c * ((t=t/d-1)*t*t*t - 1) + b;
	},
	inOutQuart: function (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;
	},
	inQuint: function (t, b, c, d) {
		return c*(t/=d)*t*t*t*t + b;
	},
	outQuint: function (t, b, c, d) {
		return c*((t=t/d-1)*t*t*t*t + 1) + b;
	},
	inOutQuint: function (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;
	},
	inSine: function (t, b, c, d) {
		return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
	},
	outSine: function (t, b, c, d) {
		return c * Math.sin(t/d * (Math.PI/2)) + b;
	},
	inOutSine: function (t, b, c, d) {
		return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
	},
	inExpo: function (t, b, c, d) {
		return (t===0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
	},
	outExpo: function (t, b, c, d) {
		return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
	},
	inOutExpo: function (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;
	},
	inCirc: function (t, b, c, d) {
		return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
	},
	outCirc: function (t, b, c, d) {
		return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
	},
	inOutCirc: function (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;
	},
	inElastic: function (t, b, c, d, a, p) {
		if (t===0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*0.3; if(!a) a=0;
		var s;
		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;
	},
	outElastic: function (t, b, c, d, a, p) {
		if (t===0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*0.3; if(!a) a=0;
		var s;
		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;
	},
	inOutElastic: function (t, b, c, d, a, p) {
		if (t===0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(0.3*1.5); if(!a) a=0;
		var s;
		if (a < Math.abs(c)) { a=c; s=p/4; }
		else s = p/(2*Math.PI) * Math.asin (c/a);
		if (t < 1) return -0.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 )*0.5 + c + b;
	},
	inBack: function (t, b, c, d, s) {
		if (s === undefined) s = 1.70158;
		return c*(t/=d)*t*((s+1)*t - s) + b;
	},
	outBack: function (t, b, c, d, s) {
		if (s === undefined) s = 1.70158;
		return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
	},
	inOutBack: function (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;
	},
	inBounce: function (t, b, c, d) {
		return c - Effects.outBounce (d-t, 0, c, d) + b;
	},
	outBounce: function (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 + 0.75) + b;
		} else if (t < (2.5/2.75)) {
			return c*(7.5625*(t-=(2.25/2.75))*t + 0.9375) + b;
		} else {
			return c*(7.5625*(t-=(2.625/2.75))*t + 0.984375) + b;
		}
	},
	inOutBounce: function (t, b, c, d) {
		if (t < d/2) return Effects.inBounce (t*2, 0, c, d) * 0.5 + b;
		return Effects.outBounce (t*2-d, 0, c, d) * 0.5 + c*0.5 + b;
	}
};

Effects.circleY = function(t, b, c, d) {
	return (c * Math.sin(t / d * 2 * Math.PI)) + b;
};
Effects.circleX = function(t, b, c, d) {
	return (c * Math.cos(t / d * 2 * Math.PI)) + b;
};
Effects.outSpiralY = function(t, b, c, d) {
	return ((c / d * t) * Math.sin(t / d * 2 * Math.PI)) + b;
};
Effects.outSpiralX = function(t, b, c, d) {
	return ((c / d * t) * Math.cos(t / d * 2 * Math.PI)) + b;
};
Effects.inSpiralY = function(t, b, c, d) {
	return ((c / d * (d-t)) * Math.sin(t / d * 2 * Math.PI)) + b;
};
Effects.inSpiralX = function(t, b, c, d) {
	return ((c / d * (d-t)) * Math.cos(t / d * 2 * Math.PI)) + b;
};

var Drag = {
	_active: null,
	_init: false,
	makeDraggable : function(o) {
		var u = I(o.element);

		u._xDrag = {
			xStart : 0,
			yStart : 0,
			xDelta : 0,
			yDelta : 0,
			mDelta : 0,
			dragging : false,
			onstart: o.onstart,
			onmove: o.onmove,
			onfinish: o.onfinish,
			disabled: false
		};

		if(!Drag._init) {
			// Al movimento del mouse nel documento
			Event.add(document, 'mousemove', function(e) {
				if(!e) e = window.event;
				var a = Drag._active;
				if(a) {
					var c = a._xDrag;
					if(!c.disabled) {
						var x = parseInt(e.clientX, 10), y = parseInt(e.clientY, 10), v = c.onmove;
						var xDelta = c.xStart - x, yDelta = c.yStart - y,
							mDelta = Math.sqrt((xDelta * xDelta) + (yDelta * yDelta));
						c.xDelta = xDelta;
						c.yDelta = yDelta;
						c.mDelta = mDelta;
						c.xStart = x;
						c.yStart = y;
						if(v) v.call(a, e, xDelta, yDelta, mDelta);
					}
					Event.stop(e);
				}
			});
			// Al rilascio del mouse nel documento
			Event.add(document, 'mouseup', function(e) {
				if(!e) e = window.event;
				var a = Drag._active;
				if(a) {
					var c = a._xDrag;
					if(!c.disabled) {
						var f = c.onfinish;
						c.dragging = false;
						if(f) f.call(a, e);
						Drag._active = null;
					}
				}
			});
		}
		// Alla pressione del mouse sopra all'elemento
		Event.add(u, 'mousedown', function(e) {
			if(!e) e = window.event;
			var c = this._xDrag, event = e;
			if(!c.disabled) {
				var s = c.onstart;
				c.xStart = parseInt(e.clientX, 10);
				c.yStart = parseInt(e.clientY, 10);
				c.dragging = true;
				if(s) s.call(this, e);
				Drag._active = this;
			}
		});
		/*
		// Al rilascio del mouse sopra all'elemento
		Event.add(u, 'mouseup', function() {
			var c = this._xDrag;
			if(!c.disabled) {
				var f = o.onfinish;
				c.dragging = false;
				if(f) f.apply(this);
				Drag._active = null;
			}
		});
		*/

		if(typeof u.style.MozUserSelect != "undefined") u.style.MozUserSelect = "none";
		else if(typeof u.onselectstart != "undefined") {
			Event.add(u, 'selectstart', function() {
				return false;
			});
		}
	},
	_nearestStep: function(v, l, g) {
		var gl = g.length - 1, gs = l / gl, ga = 0, gb;
		for(var i = 1; i <= gl; i++) {
			gb = ga + gs;
			if(v >= ga && v <= gb) {
				if((v - ga) < (gb - v)) return [Math.round(ga), g[i-1]];
				return [Math.round(gb), g[i]];
			}
			ga = gb;
		}
		return [0, g[0]];
	}
};