//MooTools More, <http://mootools.net/more>. Copyright (c) 2006-2008 Valerio Proietti, <http://mad4milk.net>, MIT Style License.

Fx.Slide = new Class( {
	Extends : Fx,
	options : {
		mode : "vertical"
	},
	initialize : function(B, A) {
		this.addEvent("complete",
				function() {
					this.open = (this.wrapper["offset"
							+ this.layout.capitalize()] != 0);
					if (this.open && Browser.Engine.webkit419) {
						this.element.dispose().inject(this.wrapper);
					}
				}, true);
		this.element = this.subject = $(B);
		this.parent(A);
		var C = this.element.retrieve("wrapper");
		this.wrapper = C || new Element("div", {
			styles : $extend(this.element.getStyles("margin", "position"), {
				overflow : "hidden"
			})
		}).wraps(this.element);
		this.element.store("wrapper", this.wrapper).setStyle("margin", 0);
		this.now = [];
		this.open = true;
	},
	vertical : function() {
		this.margin = "margin-top";
		this.layout = "height";
		this.offset = this.element.offsetHeight;
	},
	horizontal : function() {
		this.margin = "margin-left";
		this.layout = "width";
		this.offset = this.element.offsetWidth;
	},
	set : function(A) {
		this.element.setStyle(this.margin, A[0]);
		this.wrapper.setStyle(this.layout, A[1]);
		return this;
	},
	compute : function(E, D, C) {
		var B = [];
		var A = 2;
		A.times(function(F) {
			B[F] = Fx.compute(E[F], D[F], C);
		});
		return B;
	},
	start : function(B, E) {
		if (!this.check(arguments.callee, B, E)) {
			return this;
		}
		this[E || this.options.mode]();
		var D = this.element.getStyle(this.margin).toInt();
		var C = this.wrapper.getStyle(this.layout).toInt();
		var A = [ [ D, C ], [ 0, this.offset ] ];
		var G = [ [ D, C ], [ -this.offset, 0 ] ];
		var F;
		switch (B) {
		case "in":
			F = A;
			break;
		case "out":
			F = G;
			break;
		case "toggle":
			F = (this.wrapper["offset" + this.layout.capitalize()] == 0) ? A
					: G;
		}
		return this.parent(F[0], F[1]);
	},
	slideIn : function(A) {
		return this.start("in", A);
	},
	slideOut : function(A) {
		return this.start("out", A);
	},
	hide : function(A) {
		this[A || this.options.mode]();
		this.open = false;
		return this.set( [ -this.offset, 0 ]);
	},
	show : function(A) {
		this[A || this.options.mode]();
		this.open = true;
		return this.set( [ 0, this.offset ]);
	},
	toggle : function(A) {
		return this.start("toggle", A);
	}
});
Element.Properties.slide = {
	set : function(B) {
		var A = this.retrieve("slide");
		if (A) {
			A.cancel();
		}
		return this.eliminate("slide").store("slide:options", $extend( {
			link : "cancel"
		}, B));
	},
	get : function(A) {
		if (A || !this.retrieve("slide")) {
			if (A || !this.retrieve("slide:options")) {
				this.set("slide", A);
			}
			this.store("slide", new Fx.Slide(this, this
					.retrieve("slide:options")));
		}
		return this.retrieve("slide");
	}
};
Element.implement( {
	slide : function(D, E) {
		D = D || "toggle";
		var B = this.get("slide"), A;
		switch (D) {
		case "hide":
			B.hide(E);
			break;
		case "show":
			B.show(E);
			break;
		case "toggle":
			var C = this.retrieve("slide:flag", B.open);
			B[(C) ? "slideOut" : "slideIn"](E);
			this.store("slide:flag", !C);
			A = true;
			break;
		default:
			B.start(D, E);
		}
		if (!A) {
			this.eliminate("slide:flag");
		}
		return this;
	}
});
Fx.Scroll = new Class( {
	Extends : Fx,
	options : {
		offset : {
			x : 0,
			y : 0
		},
		wheelStops : true
	},
	initialize : function(B, A) {
		this.element = this.subject = $(B);
		this.parent(A);
		var D = this.cancel.bind(this, false);
		if ($type(this.element) != "element") {
			this.element = $(this.element.getDocument().body);
		}
		var C = this.element;
		if (this.options.wheelStops) {
			this.addEvent("start", function() {
				C.addEvent("mousewheel", D);
			}, true);
			this.addEvent("complete", function() {
				C.removeEvent("mousewheel", D);
			}, true);
		}
	},
	set : function() {
		var A = Array.flatten(arguments);
		this.element.scrollTo(A[0], A[1]);
	},
	compute : function(E, D, C) {
		var B = [];
		var A = 2;
		A.times(function(F) {
			B.push(Fx.compute(E[F], D[F], C));
		});
		return B;
	},
	start : function(C, H) {
		if (!this.check(arguments.callee, C, H)) {
			return this;
		}
		var E = this.element.getSize(), F = this.element.getScrollSize();
		var B = this.element.getScroll(), D = {
			x : C,
			y : H
		};
		for ( var G in D) {
			var A = F[G] - E[G];
			if ($chk(D[G])) {
				D[G] = ($type(D[G]) == "number") ? D[G].limit(0, A) : A;
			} else {
				D[G] = B[G];
			}
			D[G] += this.options.offset[G];
		}
		return this.parent( [ B.x, B.y ], [ D.x, D.y ]);
	},
	toTop : function() {
		return this.start(false, 0);
	},
	toLeft : function() {
		return this.start(0, false);
	},
	toRight : function() {
		return this.start("right", false);
	},
	toBottom : function() {
		return this.start(false, "bottom");
	},
	toElement : function(B) {
		var A = $(B).getPosition(this.element);
		return this.start(A.x, A.y);
	}
});
Fx.Elements = new Class( {
	Extends : Fx.CSS,
	initialize : function(B, A) {
		this.elements = this.subject = $$(B);
		this.parent(A);
	},
	compute : function(G, H, I) {
		var C = {};
		for ( var D in G) {
			var A = G[D], E = H[D], F = C[D] = {};
			for ( var B in A) {
				F[B] = this.parent(A[B], E[B], I);
			}
		}
		return C;
	},
	set : function(B) {
		for ( var C in B) {
			var A = B[C];
			for ( var D in A) {
				this.render(this.elements[C], D, A[D], this.options.unit);
			}
		}
		return this;
	},
	start : function(C) {
		if (!this.check(arguments.callee, C)) {
			return this;
		}
		var H = {}, I = {};
		for ( var D in C) {
			var F = C[D], A = H[D] = {}, G = I[D] = {};
			for ( var B in F) {
				var E = this.prepare(this.elements[D], B, F[B]);
				A[B] = E.from;
				G[B] = E.to;
			}
		}
		return this.parent(H, I);
	}
});
var Drag = new Class(
		{
			Implements : [ Events, Options ],
			options : {
				snap : 6,
				unit : "px",
				grid : false,
				style : true,
				limit : false,
				handle : false,
				invert : false,
				preventDefault : false,
				modifiers : {
					x : "left",
					y : "top"
				}
			},
			initialize : function() {
				var B = Array.link(arguments, {
					options : Object.type,
					element : $defined
				});
				this.element = $(B.element);
				this.document = this.element.getDocument();
				this.setOptions(B.options || {});
				var A = $type(this.options.handle);
				this.handles = (A == "array" || A == "collection") ? $$(this.options.handle)
						: $(this.options.handle) || this.element;
				this.mouse = {
					now : {},
					pos : {}
				};
				this.value = {
					start : {},
					now : {}
				};
				this.selection = (Browser.Engine.trident) ? "selectstart"
						: "mousedown";
				this.bound = {
					start : this.start.bind(this),
					check : this.check.bind(this),
					drag : this.drag.bind(this),
					stop : this.stop.bind(this),
					cancel : this.cancel.bind(this),
					eventStop : $lambda(false)
				};
				this.attach();
			},
			attach : function() {
				this.handles.addEvent("mousedown", this.bound.start);
				return this;
			},
			detach : function() {
				this.handles.removeEvent("mousedown", this.bound.start);
				return this;
			},
			start : function(C) {
				if (this.options.preventDefault) {
					C.preventDefault();
				}
				this.fireEvent("beforeStart", this.element);
				this.mouse.start = C.page;
				var A = this.options.limit;
				this.limit = {
					x : [],
					y : []
				};
				for ( var D in this.options.modifiers) {
					if (!this.options.modifiers[D]) {
						continue;
					}
					if (this.options.style) {
						this.value.now[D] = this.element.getStyle(
								this.options.modifiers[D]).toInt();
					} else {
						this.value.now[D] = this.element[this.options.modifiers[D]];
					}
					if (this.options.invert) {
						this.value.now[D] *= -1;
					}
					this.mouse.pos[D] = C.page[D] - this.value.now[D];
					if (A && A[D]) {
						for ( var B = 2; B--; B) {
							if ($chk(A[D][B])) {
								this.limit[D][B] = $lambda(A[D][B])();
							}
						}
					}
				}
				if ($type(this.options.grid) == "number") {
					this.options.grid = {
						x : this.options.grid,
						y : this.options.grid
					};
				}
				this.document.addEvents( {
					mousemove : this.bound.check,
					mouseup : this.bound.cancel
				});
				this.document.addEvent(this.selection, this.bound.eventStop);
			},
			check : function(A) {
				if (this.options.preventDefault) {
					A.preventDefault();
				}
				var B = Math.round(Math.sqrt(Math.pow(A.page.x
						- this.mouse.start.x, 2)
						+ Math.pow(A.page.y - this.mouse.start.y, 2)));
				if (B > this.options.snap) {
					this.cancel();
					this.document.addEvents( {
						mousemove : this.bound.drag,
						mouseup : this.bound.stop
					});
					this.fireEvent("start", this.element).fireEvent("snap",
							this.element);
				}
			},
			drag : function(A) {
				if (this.options.preventDefault) {
					A.preventDefault();
				}
				this.mouse.now = A.page;
				for ( var B in this.options.modifiers) {
					if (!this.options.modifiers[B]) {
						continue;
					}
					this.value.now[B] = this.mouse.now[B] - this.mouse.pos[B];
					if (this.options.invert) {
						this.value.now[B] *= -1;
					}
					if (this.options.limit && this.limit[B]) {
						if ($chk(this.limit[B][1])
								&& (this.value.now[B] > this.limit[B][1])) {
							this.value.now[B] = this.limit[B][1];
						} else {
							if ($chk(this.limit[B][0])
									&& (this.value.now[B] < this.limit[B][0])) {
								this.value.now[B] = this.limit[B][0];
							}
						}
					}
					if (this.options.grid[B]) {
						this.value.now[B] -= (this.value.now[B] % this.options.grid[B]);
					}
					if (this.options.style) {
						this.element.setStyle(this.options.modifiers[B],
								this.value.now[B] + this.options.unit);
					} else {
						this.element[this.options.modifiers[B]] = this.value.now[B];
					}
				}
				this.fireEvent("drag", this.element);
			},
			cancel : function(A) {
				this.document.removeEvent("mousemove", this.bound.check);
				this.document.removeEvent("mouseup", this.bound.cancel);
				if (A) {
					this.document.removeEvent(this.selection,
							this.bound.eventStop);
					this.fireEvent("cancel", this.element);
				}
			},
			stop : function(A) {
				this.document.removeEvent(this.selection, this.bound.eventStop);
				this.document.removeEvent("mousemove", this.bound.drag);
				this.document.removeEvent("mouseup", this.bound.stop);
				if (A) {
					this.fireEvent("complete", this.element);
				}
			}
		});
Element.implement( {
	makeResizable : function(A) {
		return new Drag(this, $merge( {
			modifiers : {
				x : "width",
				y : "height"
			}
		}, A));
	}
});
Drag.Move = new Class(
		{
			Extends : Drag,
			options : {
				droppables : [],
				container : false
			},
			initialize : function(C, B) {
				this.parent(C, B);
				this.droppables = $$(this.options.droppables);
				this.container = $(this.options.container);
				if (this.container && $type(this.container) != "element") {
					this.container = $(this.container.getDocument().body);
				}
				C = this.element;
				var D = C.getStyle("position");
				var A = (D != "static") ? D : "absolute";
				if (C.getStyle("left") == "auto" || C.getStyle("top") == "auto") {
					C.position(C.getPosition(C.offsetParent));
				}
				C.setStyle("position", A);
				this.addEvent("start", function() {
					this.checkDroppables();
				}, true);
			},
			start : function(B) {
				if (this.container) {
					var D = this.element, J = this.container, E = J
							.getCoordinates(D.offsetParent), F = {}, A = {};
					[ "top", "right", "bottom", "left" ].each(function(K) {
						F[K] = J.getStyle("padding-" + K).toInt();
						A[K] = D.getStyle("margin-" + K).toInt();
					}, this);
					var C = D.offsetWidth + A.left + A.right, I = D.offsetHeight
							+ A.top + A.bottom;
					var H = [ E.left + F.left, E.right - F.right - C ];
					var G = [ E.top + F.top, E.bottom - F.bottom - I ];
					this.options.limit = {
						x : H,
						y : G
					};
				}
				this.parent(B);
			},
			checkAgainst : function(B) {
				B = B.getCoordinates();
				var A = this.mouse.now;
				return (A.x > B.left && A.x < B.right && A.y < B.bottom && A.y > B.top);
			},
			checkDroppables : function() {
				var A = this.droppables.filter(this.checkAgainst, this)
						.getLast();
				if (this.overed != A) {
					if (this.overed) {
						this.fireEvent("leave", [ this.element, this.overed ]);
					}
					if (A) {
						this.overed = A;
						this.fireEvent("enter", [ this.element, A ]);
					} else {
						this.overed = null;
					}
				}
			},
			drag : function(A) {
				this.parent(A);
				if (this.droppables.length) {
					this.checkDroppables();
				}
			},
			stop : function(A) {
				this.checkDroppables();
				this.fireEvent("drop", [ this.element, this.overed ]);
				this.overed = null;
				return this.parent(A);
			}
		});
Element.implement( {
	makeDraggable : function(A) {
		return new Drag.Move(this, A);
	}
});
Hash.Cookie = new Class( {
	Extends : Cookie,
	options : {
		autoSave : true
	},
	initialize : function(B, A) {
		this.parent(B, A);
		this.load();
	},
	save : function() {
		var A = JSON.encode(this.hash);
		if (!A || A.length > 4096) {
			return false;
		}
		if (A == "{}") {
			this.dispose();
		} else {
			this.write(A);
		}
		return true;
	},
	load : function() {
		this.hash = new Hash(JSON.decode(this.read(), true));
		return this;
	}
});
Hash.Cookie.implement((function() {
	var A = {};
	Hash.each(Hash.prototype, function(C, B) {
		A[B] = function() {
			var D = C.apply(this.hash, arguments);
			if (this.options.autoSave) {
				this.save();
			}
			return D;
		};
	});
	return A;
})());
var Color = new Native( {
	initialize : function(B, C) {
		if (arguments.length >= 3) {
			C = "rgb";
			B = Array.slice(arguments, 0, 3);
		} else {
			if (typeof B == "string") {
				if (B.match(/rgb/)) {
					B = B.rgbToHex().hexToRgb(true);
				} else {
					if (B.match(/hsb/)) {
						B = B.hsbToRgb();
					} else {
						B = B.hexToRgb(true);
					}
				}
			}
		}
		C = C || "rgb";
		switch (C) {
		case "hsb":
			var A = B;
			B = B.hsbToRgb();
			B.hsb = A;
			break;
		case "hex":
			B = B.hexToRgb(true);
			break;
		}
		B.rgb = B.slice(0, 3);
		B.hsb = B.hsb || B.rgbToHsb();
		B.hex = B.rgbToHex();
		return $extend(B, this);
	}
});
Color.implement( {
	mix : function() {
		var A = Array.slice(arguments);
		var C = ($type(A.getLast()) == "number") ? A.pop() : 50;
		var B = this.slice();
		A.each(function(D) {
			D = new Color(D);
			for ( var E = 0; E < 3; E++) {
				B[E] = Math.round((B[E] / 100 * (100 - C)) + (D[E] / 100 * C));
			}
		});
		return new Color(B, "rgb");
	},
	invert : function() {
		return new Color(this.map(function(A) {
			return 255 - A;
		}));
	},
	setHue : function(A) {
		return new Color( [ A, this.hsb[1], this.hsb[2] ], "hsb");
	},
	setSaturation : function(A) {
		return new Color( [ this.hsb[0], A, this.hsb[2] ], "hsb");
	},
	setBrightness : function(A) {
		return new Color( [ this.hsb[0], this.hsb[1], A ], "hsb");
	}
});
function $RGB(C, B, A) {
	return new Color( [ C, B, A ], "rgb");
}
function $HSB(C, B, A) {
	return new Color( [ C, B, A ], "hsb");
}
function $HEX(A) {
	return new Color(A, "hex");
}
Array
		.implement( {
			rgbToHsb : function() {
				var B = this[0], C = this[1], J = this[2];
				var G, F, H;
				var I = Math.max(B, C, J), E = Math.min(B, C, J);
				var K = I - E;
				H = I / 255;
				F = (I != 0) ? K / I : 0;
				if (F == 0) {
					G = 0;
				} else {
					var D = (I - B) / K;
					var A = (I - C) / K;
					var L = (I - J) / K;
					if (B == I) {
						G = L - A;
					} else {
						if (C == I) {
							G = 2 + D - L;
						} else {
							G = 4 + A - D;
						}
					}
					G /= 6;
					if (G < 0) {
						G++;
					}
				}
				return [ Math.round(G * 360), Math.round(F * 100),
						Math.round(H * 100) ];
			},
			hsbToRgb : function() {
				var C = Math.round(this[2] / 100 * 255);
				if (this[1] == 0) {
					return [ C, C, C ];
				} else {
					var A = this[0] % 360;
					var E = A % 60;
					var F = Math
							.round((this[2] * (100 - this[1])) / 10000 * 255);
					var D = Math
							.round((this[2] * (6000 - this[1] * E)) / 600000 * 255);
					var B = Math
							.round((this[2] * (6000 - this[1] * (60 - E))) / 600000 * 255);
					switch (Math.floor(A / 60)) {
					case 0:
						return [ C, B, F ];
					case 1:
						return [ D, C, F ];
					case 2:
						return [ F, C, B ];
					case 3:
						return [ F, D, C ];
					case 4:
						return [ B, F, C ];
					case 5:
						return [ C, F, D ];
					}
				}
				return false;
			}
		});
String.implement( {
	rgbToHsb : function() {
		var A = this.match(/\d{1,3}/g);
		return (A) ? hsb.rgbToHsb() : null;
	},
	hsbToRgb : function() {
		var A = this.match(/\d{1,3}/g);
		return (A) ? A.hsbToRgb() : null;
	}
});
var Group = new Class( {
	initialize : function() {
		this.instances = Array.flatten(arguments);
		this.events = {};
		this.checker = {};
	},
	addEvent : function(B, A) {
		this.checker[B] = this.checker[B] || {};
		this.events[B] = this.events[B] || [];
		if (this.events[B].contains(A)) {
			return false;
		} else {
			this.events[B].push(A);
		}
		this.instances.each(function(C, D) {
			C.addEvent(B, this.check.bind(this, [ B, C, D ]));
		}, this);
		return this;
	},
	check : function(C, A, B) {
		this.checker[C][B] = true;
		var D = this.instances.every(function(F, E) {
			return this.checker[C][E] || false;
		}, this);
		if (!D) {
			return;
		}
		this.checker[C] = {};
		this.events[C].each(function(E) {
			E.call(this, this.instances, A);
		}, this);
	}
});
var Asset = new Hash( {
	javascript : function(F, D) {
		D = $extend( {
			onload : $empty,
			document : document,
			check : $lambda(true)
		}, D);
		var B = new Element("script", {
			src : F,
			type : "text/javascript"
		});
		var E = D.onload.bind(B), A = D.check, G = D.document;
		delete D.onload;
		delete D.check;
		delete D.document;
		B.addEvents( {
			load : E,
			readystatechange : function() {
				if ( [ "loaded", "complete" ].contains(this.readyState)) {
					E();
				}
			}
		}).setProperties(D);
		if (Browser.Engine.webkit419) {
			var C = (function() {
				if (!$try(A)) {
					return;
				}
				$clear(C);
				E();
			}).periodical(50);
		}
		return B.inject(G.head);
	},
	css : function(B, A) {
		return new Element("link", $merge( {
			rel : "stylesheet",
			media : "screen",
			type : "text/css",
			href : B
		}, A)).inject(document.head);
	},
	image : function(C, B) {
		B = $merge( {
			onload : $empty,
			onabort : $empty,
			onerror : $empty
		}, B);
		var D = new Image();
		var A = $(D) || new Element("img");
		[ "load", "abort", "error" ].each(function(E) {
			var F = "on" + E;
			var G = B[F];
			delete B[F];
			D[F] = function() {
				if (!D) {
					return;
				}
				if (!A.parentNode) {
					A.width = D.width;
					A.height = D.height;
				}
				D = D.onload = D.onabort = D.onerror = null;
				G.delay(1, A, A);
				A.fireEvent(E, A, 1);
			};
		});
		D.src = A.src = C;
		if (D && D.complete) {
			D.onload.delay(1);
		}
		return A.setProperties(B);
	},
	images : function(D, C) {
		C = $merge( {
			onComplete : $empty,
			onProgress : $empty
		}, C);
		if (!D.push) {
			D = [ D ];
		}
		var A = [];
		var B = 0;
		D.each(function(F) {
			var E = new Asset.image(F, {
				onload : function() {
					C.onProgress.call(this, B, D.indexOf(F));
					B++;
					if (B == D.length) {
						C.onComplete();
					}
				}
			});
			A.push(E);
		});
		return new Elements(A);
	}
});
var Sortables = new Class( {
	Implements : [ Events, Options ],
	options : {
		snap : 4,
		opacity : 1,
		clone : false,
		revert : false,
		handle : false,
		constrain : false
	},
	initialize : function(A, B) {
		this.setOptions(B);
		this.elements = [];
		this.lists = [];
		this.idle = true;
		this.addLists($$($(A) || A));
		if (!this.options.clone) {
			this.options.revert = false;
		}
		if (this.options.revert) {
			this.effect = new Fx.Morph(null, $merge( {
				duration : 250,
				link : "cancel"
			}, this.options.revert));
		}
	},
	attach : function() {
		this.addLists(this.lists);
		return this;
	},
	detach : function() {
		this.lists = this.removeLists(this.lists);
		return this;
	},
	addItems : function() {
		Array.flatten(arguments).each(
				function(A) {
					this.elements.push(A);
					var B = A.retrieve("sortables:start", this.start
							.bindWithEvent(this, A));
					(this.options.handle ? A.getElement(this.options.handle)
							|| A : A).addEvent("mousedown", B);
				}, this);
		return this;
	},
	addLists : function() {
		Array.flatten(arguments).each(function(A) {
			this.lists.push(A);
			this.addItems(A.getChildren());
		}, this);
		return this;
	},
	removeItems : function() {
		var A = [];
		Array.flatten(arguments).each(
				function(B) {
					A.push(B);
					this.elements.erase(B);
					var C = B.retrieve("sortables:start");
					(this.options.handle ? B.getElement(this.options.handle)
							|| B : B).removeEvent("mousedown", C);
				}, this);
		return $$(A);
	},
	removeLists : function() {
		var A = [];
		Array.flatten(arguments).each(function(B) {
			A.push(B);
			this.lists.erase(B);
			this.removeItems(B.getChildren());
		}, this);
		return $$(A);
	},
	getClone : function(B, A) {
		if (!this.options.clone) {
			return new Element("div").inject(document.body);
		}
		if ($type(this.options.clone) == "function") {
			return this.options.clone.call(this, B, A, this.list);
		}
		return A.clone(true).setStyles( {
			margin : "0px",
			position : "absolute",
			visibility : "hidden",
			width : A.getStyle("width")
		}).inject(this.list).position(A.getPosition(A.getOffsetParent()));
	},
	getDroppables : function() {
		var A = this.list.getChildren();
		if (!this.options.constrain) {
			A = this.lists.concat(A).erase(this.list);
		}
		return A.erase(this.clone).erase(this.element);
	},
	insert : function(C, B) {
		var A = "inside";
		if (this.lists.contains(B)) {
			this.list = B;
			this.drag.droppables = this.getDroppables();
		} else {
			A = this.element.getAllPrevious().contains(B) ? "before" : "after";
		}
		this.element.inject(B, A);
		this.fireEvent("sort", [ this.element, this.clone ]);
	},
	start : function(B, A) {
		if (!this.idle) {
			return;
		}
		this.idle = false;
		this.element = A;
		this.opacity = A.get("opacity");
		this.list = A.getParent();
		this.clone = this.getClone(B, A);
		this.drag = new Drag.Move(this.clone, {
			snap : this.options.snap,
			container : this.options.constrain && this.element.getParent(),
			droppables : this.getDroppables(),
			onSnap : function() {
				B.stop();
				this.clone.setStyle("visibility", "visible");
				this.element.set("opacity", this.options.opacity || 0);
				this.fireEvent("start", [ this.element, this.clone ]);
			}.bind(this),
			onEnter : this.insert.bind(this),
			onCancel : this.reset.bind(this),
			onComplete : this.end.bind(this)
		});
		this.clone.inject(this.element, "before");
		this.drag.start(B);
	},
	end : function() {
		this.drag.detach();
		this.element.set("opacity", this.opacity);
		if (this.effect) {
			var A = this.element.getStyles("width", "height");
			var B = this.clone.computePosition(this.element
					.getPosition(this.clone.offsetParent));
			this.effect.element = this.clone;
			this.effect.start( {
				top : B.top,
				left : B.left,
				width : A.width,
				height : A.height,
				opacity : 0.25
			}).chain(this.reset.bind(this));
		} else {
			this.reset();
		}
	},
	reset : function() {
		this.idle = true;
		this.clone.destroy();
		this.fireEvent("complete", this.element);
	},
	serialize : function() {
		var C = Array.link(arguments, {
			modifier : Function.type,
			index : $defined
		});
		var B = this.lists.map(function(D) {
			return D.getChildren().map(C.modifier || function(E) {
				return E.get("id");
			}, this);
		}, this);
		var A = C.index;
		if (this.lists.length == 1) {
			A = 0;
		}
		return $chk(A) && A >= 0 && A < this.lists.length ? B[A] : B;
	}
});
var Tips = new Class( {
	Implements : [ Events, Options ],
	options : {
		onShow : function(A) {
			A.setStyle("visibility", "visible");
		},
		onHide : function(A) {
			A.setStyle("visibility", "hidden");
		},
		showDelay : 100,
		hideDelay : 100,
		className : null,
		offsets : {
			x : 16,
			y : 16
		},
		fixed : false
	},
	initialize : function() {
		var C = Array.link(arguments, {
			options : Object.type,
			elements : $defined
		});
		this.setOptions(C.options || null);
		this.tip = new Element("div").inject(document.body);
		if (this.options.className) {
			this.tip.addClass(this.options.className);
		}
		var B = new Element("div", {
			"class" : "tip-top"
		}).inject(this.tip);
		this.container = new Element("div", {
			"class" : "tip"
		}).inject(this.tip);
		var A = new Element("div", {
			"class" : "tip-bottom"
		}).inject(this.tip);
		this.tip.setStyles( {
			position : "absolute",
			top : 0,
			left : 0,
			visibility : "hidden"
		});
		if (C.elements) {
			this.attach(C.elements);
		}
	},
	attach : function(A) {
		$$(A).each(
				function(D) {
					var G = D.retrieve("tip:title", D.get("title"));
					var F = D.retrieve("tip:text", D.get("rel")
							|| D.get("href"));
					var E = D.retrieve("tip:enter", this.elementEnter
							.bindWithEvent(this, D));
					var C = D.retrieve("tip:leave", this.elementLeave
							.bindWithEvent(this, D));
					D.addEvents( {
						mouseenter : E,
						mouseleave : C
					});
					if (!this.options.fixed) {
						var B = D.retrieve("tip:move", this.elementMove
								.bindWithEvent(this, D));
						D.addEvent("mousemove", B);
					}
					D.store("tip:native", D.get("title"));
					D.erase("title");
				}, this);
		return this;
	},
	detach : function(A) {
		$$(A).each(
				function(C) {
					C.removeEvent("mouseenter", C.retrieve("tip:enter")
							|| $empty);
					C.removeEvent("mouseleave", C.retrieve("tip:leave")
							|| $empty);
					C
							.removeEvent("mousemove", C.retrieve("tip:move")
									|| $empty);
					C.eliminate("tip:enter").eliminate("tip:leave").eliminate(
							"tip:move");
					var B = C.retrieve("tip:native");
					if (B) {
						C.set("title", B);
					}
				});
		return this;
	},
	elementEnter : function(B, A) {
		$A(this.container.childNodes).each(Element.dispose);
		var D = A.retrieve("tip:title");
		if (D) {
			this.titleElement = new Element("div", {
				"class" : "tip-title"
			}).inject(this.container);
			this.fill(this.titleElement, D);
		}
		var C = A.retrieve("tip:text");
		if (C) {
			this.textElement = new Element("div", {
				"class" : "tip-text"
			}).inject(this.container);
			this.fill(this.textElement, C);
		}
		this.timer = $clear(this.timer);
		this.timer = this.show.delay(this.options.showDelay, this);
		this.position((!this.options.fixed) ? B : {
			page : A.getPosition()
		});
	},
	elementLeave : function(A) {
		$clear(this.timer);
		this.timer = this.hide.delay(this.options.hideDelay, this);
	},
	elementMove : function(A) {
		this.position(A);
	},
	position : function(D) {
		var B = window.getSize(), A = window.getScroll();
		var E = {
			x : this.tip.offsetWidth,
			y : this.tip.offsetHeight
		};
		var C = {
			x : "left",
			y : "top"
		};
		for ( var F in C) {
			var G = D.page[F] + this.options.offsets[F];
			if ((G + E[F] - A[F]) > B[F]) {
				G = D.page[F] - this.options.offsets[F] - E[F];
			}
			this.tip.setStyle(C[F], G);
		}
	},
	fill : function(A, B) {
		(typeof B == "string") ? A.set("html", B) : A.adopt(B);
	},
	show : function() {
		this.fireEvent("show", this.tip);
	},
	hide : function() {
		this.fireEvent("hide", this.tip);
	}
});
var SmoothScroll = new Class( {
	Extends : Fx.Scroll,
	initialize : function(B, C) {
		C = C || document;
		var E = C.getDocument(), D = C.getWindow();
		this.parent(E, B);
		this.links = (this.options.links) ? $$(this.options.links)
				: $$(E.links);
		var A = D.location.href.match(/^[^#]*/)[0] + "#";
		this.links.each(function(G) {
			if (G.href.indexOf(A) != 0) {
				return;
			}
			var F = G.href.substr(A.length);
			if (F && $(F)) {
				this.useLink(G, F);
			}
		}, this);
		if (!Browser.Engine.webkit419) {
			this.addEvent("complete", function() {
				D.location.hash = this.anchor;
			}, true);
		}
	},
	useLink : function(B, A) {
		B.addEvent("click", function(C) {
			this.anchor = A;
			this.toElement(A);
			C.stop();
		}.bind(this));
	}
});
var Slider = new Class(
		{
			Implements : [ Events, Options ],
			options : {
				onTick : function(A) {
					if (this.options.snap) {
						A = this.toPosition(this.step);
					}
					this.knob.setStyle(this.property, A);
				},
				snap : false,
				offset : 0,
				range : false,
				wheel : false,
				steps : 100,
				mode : "horizontal"
			},
			initialize : function(E, A, D) {
				this.setOptions(D);
				this.element = $(E);
				this.knob = $(A);
				this.previousChange = this.previousEnd = this.step = -1;
				this.element.addEvent("mousedown", this.clickedElement
						.bind(this));
				if (this.options.wheel) {
					this.element.addEvent("mousewheel", this.scrolledElement
							.bindWithEvent(this));
				}
				var F, B = {}, C = {
					x : false,
					y : false
				};
				switch (this.options.mode) {
				case "vertical":
					this.axis = "y";
					this.property = "top";
					F = "offsetHeight";
					break;
				case "horizontal":
					this.axis = "x";
					this.property = "left";
					F = "offsetWidth";
				}
				this.half = this.knob[F] / 2;
				this.full = this.element[F] - this.knob[F]
						+ (this.options.offset * 2);
				this.min = $chk(this.options.range[0]) ? this.options.range[0]
						: 0;
				this.max = $chk(this.options.range[1]) ? this.options.range[1]
						: this.options.steps;
				this.range = this.max - this.min;
				this.steps = this.options.steps || this.full;
				this.stepSize = Math.abs(this.range) / this.steps;
				this.stepWidth = this.stepSize * this.full
						/ Math.abs(this.range);
				this.knob.setStyle("position", "relative").setStyle(
						this.property, -this.options.offset);
				C[this.axis] = this.property;
				B[this.axis] = [ -this.options.offset,
						this.full - this.options.offset ];
				this.drag = new Drag(this.knob, {
					snap : 0,
					limit : B,
					modifiers : C,
					onDrag : this.draggedKnob.bind(this),
					onStart : this.draggedKnob.bind(this),
					onComplete : function() {
						this.draggedKnob();
						this.end();
					}.bind(this)
				});
				if (this.options.snap) {
					this.drag.options.grid = Math.ceil(this.stepWidth);
					this.drag.options.limit[this.axis][1] = this.full;
				}
			},
			set : function(A) {
				if (!((this.range > 0) ^ (A < this.min))) {
					A = this.min;
				}
				if (!((this.range > 0) ^ (A > this.max))) {
					A = this.max;
				}
				this.step = Math.round(A);
				this.checkStep();
				this.end();
				this.fireEvent("tick", this.toPosition(this.step));
				return this;
			},
			clickedElement : function(C) {
				var B = this.range < 0 ? -1 : 1;
				var A = C.page[this.axis]
						- this.element.getPosition()[this.axis] - this.half;
				A = A.limit(-this.options.offset, this.full
						- this.options.offset);
				this.step = Math.round(this.min + B * this.toStep(A));
				this.checkStep();
				this.end();
				this.fireEvent("tick", A);
			},
			scrolledElement : function(A) {
				var B = (this.options.mode == "horizontal") ? (A.wheel < 0)
						: (A.wheel > 0);
				this.set(B ? this.step - this.stepSize : this.step
						+ this.stepSize);
				A.stop();
			},
			draggedKnob : function() {
				var B = this.range < 0 ? -1 : 1;
				var A = this.drag.value.now[this.axis];
				A = A.limit(-this.options.offset, this.full
						- this.options.offset);
				this.step = Math.round(this.min + B * this.toStep(A));
				this.checkStep();
			},
			checkStep : function() {
				if (this.previousChange != this.step) {
					this.previousChange = this.step;
					this.fireEvent("change", this.step);
				}
			},
			end : function() {
				if (this.previousEnd !== this.step) {
					this.previousEnd = this.step;
					this.fireEvent("complete", this.step + "");
				}
			},
			toStep : function(A) {
				var B = (A + this.options.offset) * this.stepSize / this.full
						* this.steps;
				return this.options.steps ? Math.round(B -= B % this.stepSize)
						: B;
			},
			toPosition : function(A) {
				return (this.full * Math.abs(this.min - A))
						/ (this.steps * this.stepSize) - this.options.offset;
			}
		});
var Scroller = new Class(
		{
			Implements : [ Events, Options ],
			options : {
				area : 20,
				velocity : 1,
				onChange : function(A, B) {
					this.element.scrollTo(A, B);
				}
			},
			initialize : function(B, A) {
				this.setOptions(A);
				this.element = $(B);
				this.listener = ($type(this.element) != "element") ? $(this.element
						.getDocument().body)
						: this.element;
				this.timer = null;
				this.coord = this.getCoords.bind(this);
			},
			start : function() {
				this.listener.addEvent("mousemove", this.coord);
			},
			stop : function() {
				this.listener.removeEvent("mousemove", this.coord);
				this.timer = $clear(this.timer);
			},
			getCoords : function(A) {
				this.page = (this.listener.get("tag") == "body") ? A.client
						: A.page;
				if (!this.timer) {
					this.timer = this.scroll.periodical(50, this);
				}
			},
			scroll : function() {
				var B = this.element.getSize(), A = this.element.getScroll(), E = this.element
						.getPosition(), D = {
					x : 0,
					y : 0
				};
				for ( var C in this.page) {
					if (this.page[C] < (this.options.area + E[C]) && A[C] != 0) {
						D[C] = (this.page[C] - this.options.area - E[C])
								* this.options.velocity;
					} else {
						if (this.page[C] + this.options.area > (B[C] + E[C])
								&& B[C] + B[C] != A[C]) {
							D[C] = (this.page[C] - B[C] + this.options.area - E[C])
									* this.options.velocity;
						}
					}
				}
				if (D.y || D.x) {
					this.fireEvent("change", [ A.x + D.x, A.y + D.y ]);
				}
			}
		});
var Accordion = new Class( {
	Extends : Fx.Elements,
	options : {
		display : 0,
		show : false,
		height : true,
		width : false,
		opacity : true,
		fixedHeight : false,
		fixedWidth : false,
		wait : false,
		alwaysHide : false
	},
	initialize : function() {
		var C = Array.link(arguments, {
			container : Element.type,
			options : Object.type,
			togglers : $defined,
			elements : $defined
		});
		this.parent(C.elements, C.options);
		this.togglers = $$(C.togglers);
		this.container = $(C.container);
		this.previous = -1;
		if (this.options.alwaysHide) {
			this.options.wait = true;
		}
		if ($chk(this.options.show)) {
			this.options.display = false;
			this.previous = this.options.show;
		}
		if (this.options.start) {
			this.options.display = false;
			this.options.show = false;
		}
		this.effects = {};
		if (this.options.opacity) {
			this.effects.opacity = "fullOpacity";
		}
		if (this.options.width) {
			this.effects.width = this.options.fixedWidth ? "fullWidth"
					: "offsetWidth";
		}
		if (this.options.height) {
			this.effects.height = this.options.fixedHeight ? "fullHeight"
					: "scrollHeight";
		}
		for ( var B = 0, A = this.togglers.length; B < A; B++) {
			this.addSection(this.togglers[B], this.elements[B]);
		}
		this.elements.each(function(E, D) {
			if (this.options.show === D) {
				this.fireEvent("active", [ this.togglers[D], E ]);
			} else {
				for ( var F in this.effects) {
					E.setStyle(F, 0);
				}
			}
		}, this);
		if ($chk(this.options.display)) {
			this.display(this.options.display);
		}
	},
	addSection : function(E, C, G) {
		E = $(E);
		C = $(C);
		var F = this.togglers.contains(E);
		var B = this.togglers.length;
		this.togglers.include(E);
		this.elements.include(C);
		if (B && (!F || G)) {
			G = $pick(G, B - 1);
			E.inject(this.togglers[G], "before");
			C.inject(E, "after");
		} else {
			if (this.container && !F) {
				E.inject(this.container);
				C.inject(this.container);
			}
		}
		var A = this.togglers.indexOf(E);
		E.addEvent("click", this.display.bind(this, A));
		if (this.options.height) {
			C.setStyles( {
				"padding-top" : 0,
				"border-top" : "none",
				"padding-bottom" : 0,
				"border-bottom" : "none"
			});
		}
		if (this.options.width) {
			C.setStyles( {
				"padding-left" : 0,
				"border-left" : "none",
				"padding-right" : 0,
				"border-right" : "none"
			});
		}
		C.fullOpacity = 1;
		if (this.options.fixedWidth) {
			C.fullWidth = this.options.fixedWidth;
		}
		if (this.options.fixedHeight) {
			C.fullHeight = this.options.fixedHeight;
		}
		C.setStyle("overflow", "hidden");
		if (!F) {
			for ( var D in this.effects) {
				C.setStyle(D, 0);
			}
		}
		return this;
	},
	display : function(A) {
		A = ($type(A) == "element") ? this.elements.indexOf(A) : A;
		if ((this.timer && this.options.wait)
				|| (A === this.previous && !this.options.alwaysHide)) {
			return this;
		}
		this.previous = A;
		var B = {};
		this.elements.each(function(E, D) {
			B[D] = {};
			var C = (D != A)
					|| (this.options.alwaysHide && (E.offsetHeight > 0));
			this
					.fireEvent(C ? "background" : "active", [ this.togglers[D],
							E ]);
			for ( var F in this.effects) {
				B[D][F] = C ? 0 : E[this.effects[F]];
			}
		}, this);
		return this.start(B);
	}
});
