/*  Prototype JavaScript framework, version 1.7
 *  (c) 2005-2010 Sam Stephenson
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://www.prototypejs.org/
 *
 *--------------------------------------------------------------------------*/

var Prototype = {
	
	Version : '1.7',
	
	Browser : (function () {
			var ua = navigator.userAgent;
			var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
			return {
				IE : !!window.attachEvent && !isOpera,
				Opera : isOpera,
				WebKit : ua.indexOf('AppleWebKit/') > -1,
				Gecko : ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
				MobileSafari : /Apple.*Mobile/.test(ua)
			}
		})(),
	
	BrowserFeatures : {
		XPath : !!document.evaluate,
		
		SelectorsAPI : !!document.querySelector,
		
		ElementExtensions : (function () {
				var constructor = window.Element || window.HTMLElement;
				return !!(constructor && constructor.prototype);
			})(),
		SpecificElementExtensions : (function () {
				if (typeof window.HTMLDivElement !== 'undefined')
					return true;
				
				var div = document.createElement('div'),
				form = document.createElement('form'),
				isSupported = false;
				
				if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
					isSupported = true;
				}
				
				div = form = null;
				
				return isSupported;
			})()
	},
	
	ScriptFragment : '<script[^>]*>([\\S\\s]*?)<\/script>',
	JSONFilter : /^\/\*-secure-([\s\S]*)\*\/\s*$/,
	
	emptyFunction : function () {},
	
	K : function (x) {
		return x
	}
};

if (Prototype.Browser.MobileSafari)
	Prototype.BrowserFeatures.SpecificElementExtensions = false;

var Abstract = {};

var Try = {
	these : function () {
		var returnValue;
		
		for (var i = 0, length = arguments.length; i < length; i++) {
			var lambda = arguments[i];
			try {
				returnValue = lambda();
				break;
			} catch (e) {}
		}
		
		return returnValue;
	}
};

/* Based on Alex Arnell's inheritance implementation. */

var Class = (function () {
		
		var IS_DONTENUM_BUGGY = (function () {
				for (var p in{
						toString : 1
					}) {
					if (p === 'toString')
						return false;
				}
				return true;
			})();
		
		function subclass() {};
		function create() {
			var parent = null,
			properties = $A(arguments);
			if (Object.isFunction(properties[0]))
				parent = properties.shift();
			
			function klass() {
				this.initialize.apply(this, arguments);
			}
			
			Object.extend(klass, Class.Methods);
			klass.superclass = parent;
			klass.subclasses = [];
			
			if (parent) {
				subclass.prototype = parent.prototype;
				klass.prototype = new subclass;
				parent.subclasses.push(klass);
			}
			
			for (var i = 0, length = properties.length; i < length; i++)
				klass.addMethods(properties[i]);
			
			if (!klass.prototype.initialize)
				klass.prototype.initialize = Prototype.emptyFunction;
			
			klass.prototype.constructor = klass;
			return klass;
		}
		
		function addMethods(source) {
			var ancestor = this.superclass && this.superclass.prototype,
			properties = Object.keys(source);
			
			if (IS_DONTENUM_BUGGY) {
				if (source.toString != Object.prototype.toString)
					properties.push("toString");
				if (source.valueOf != Object.prototype.valueOf)
					properties.push("valueOf");
			}
			
			for (var i = 0, length = properties.length; i < length; i++) {
				var property = properties[i],
				value = source[property];
				if (ancestor && Object.isFunction(value) &&
					value.argumentNames()[0] == "$super") {
					var method = value;
					value = (function (m) {
							return function () {
								return ancestor[m].apply(this, arguments);
							};
						})(property).wrap(method);
					
					value.valueOf = method.valueOf.bind(method);
					value.toString = method.toString.bind(method);
				}
				this.prototype[property] = value;
			}
			
			return this;
		}
		
		return {
			create : create,
			Methods : {
				addMethods : addMethods
			}
		};
	})();
(function () {
		
		var _toString = Object.prototype.toString,
		NULL_TYPE = 'Null',
		UNDEFINED_TYPE = 'Undefined',
		BOOLEAN_TYPE = 'Boolean',
		NUMBER_TYPE = 'Number',
		STRING_TYPE = 'String',
		OBJECT_TYPE = 'Object',
		FUNCTION_CLASS = '[object Function]',
		BOOLEAN_CLASS = '[object Boolean]',
		NUMBER_CLASS = '[object Number]',
		STRING_CLASS = '[object String]',
		ARRAY_CLASS = '[object Array]',
		DATE_CLASS = '[object Date]',
		NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON &&
			typeof JSON.stringify === 'function' &&
			JSON.stringify(0) === '0' &&
			typeof JSON.stringify(Prototype.K) === 'undefined';
		
		function Type(o) {
			switch (o) {
			case null:
				return NULL_TYPE;
			case (void 0):
				return UNDEFINED_TYPE;
			}
			var type = typeof o;
			switch (type) {
			case 'boolean':
				return BOOLEAN_TYPE;
			case 'number':
				return NUMBER_TYPE;
			case 'string':
				return STRING_TYPE;
			}
			return OBJECT_TYPE;
		}
		
		function extend(destination, source) {
			for (var property in source)
				destination[property] = source[property];
			return destination;
		}
		
		function inspect(object) {
			try {
				if (isUndefined(object))
					return 'undefined';
				if (object === null)
					return 'null';
				return object.inspect ? object.inspect() : String(object);
			} catch (e) {
				if (e instanceof RangeError)
					return '...';
				throw e;
			}
		}
		
		function toJSON(value) {
			return Str('', {
					'' : value
				}, []);
		}
		
		function Str(key, holder, stack) {
			var value = holder[key],
			type = typeof value;
			
			if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
				value = value.toJSON(key);
			}
			
			var _class = _toString.call(value);
			
			switch (_class) {
			case NUMBER_CLASS:
			case BOOLEAN_CLASS:
			case STRING_CLASS:
				value = value.valueOf();
			}
			
			switch (value) {
			case null:
				return 'null';
			case true:
				return 'true';
			case false:
				return 'false';
			}
			
			type = typeof value;
			switch (type) {
			case 'string':
				return value.inspect(true);
			case 'number':
				return isFinite(value) ? String(value) : 'null';
			case 'object':
				
				for (var i = 0, length = stack.length; i < length; i++) {
					if (stack[i] === value) {
						throw new TypeError();
					}
				}
				stack.push(value);
				
				var partial = [];
				if (_class === ARRAY_CLASS) {
					for (var i = 0, length = value.length; i < length; i++) {
						var str = Str(i, value, stack);
						partial.push(typeof str === 'undefined' ? 'null' : str);
					}
					partial = '[' + partial.join(',') + ']';
				} else {
					var keys = Object.keys(value);
					for (var i = 0, length = keys.length; i < length; i++) {
						var key = keys[i],
						str = Str(key, value, stack);
						if (typeof str !== "undefined") {
							partial.push(key.inspect(true) + ':' + str);
						}
					}
					partial = '{' + partial.join(',') + '}';
				}
				stack.pop();
				return partial;
			}
		}
		
		function stringify(object) {
			return JSON.stringify(object);
		}
		
		function toQueryString(object) {
			return $H(object).toQueryString();
		}
		
		function toHTML(object) {
			return object && object.toHTML ? object.toHTML() : String.interpret(object);
		}
		
		function keys(object) {
			if (Type(object) !== OBJECT_TYPE) {
				throw new TypeError();
			}
			var results = [];
			for (var property in object) {
				if (object.hasOwnProperty(property)) {
					results.push(property);
				}
			}
			return results;
		}
		
		function values(object) {
			var results = [];
			for (var property in object)
				results.push(object[property]);
			return results;
		}
		
		function clone(object) {
			return extend({}, object);
		}
		
		function isElement(object) {
			return !!(object && object.nodeType == 1);
		}
		
		function isArray(object) {
			return _toString.call(object) === ARRAY_CLASS;
		}
		
		var hasNativeIsArray = (typeof Array.isArray == 'function')
		 && Array.isArray([]) && !Array.isArray({});
		
		if (hasNativeIsArray) {
			isArray = Array.isArray;
		}
		
		function isHash(object) {
			return object instanceof Hash;
		}
		
		function isFunction(object) {
			return _toString.call(object) === FUNCTION_CLASS;
		}
		
		function isString(object) {
			return _toString.call(object) === STRING_CLASS;
		}
		
		function isNumber(object) {
			return _toString.call(object) === NUMBER_CLASS;
		}
		
		function isDate(object) {
			return _toString.call(object) === DATE_CLASS;
		}
		
		function isUndefined(object) {
			return typeof object === "undefined";
		}
		
		function each(object, fx) {
			var i = 0, p, obj;
			for (p in object) {
				if (object.hasOwnProperty(p)) {
					obj = {};
					obj[p] = object[p];
					fx(obj, i);
					i += 1;
				}
			}
		}
		
		extend(Object, {
				each : each,
				extend : extend,
				inspect : inspect,
				toJSON : NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON,
				toQueryString : toQueryString,
				toHTML : toHTML,
				keys : Object.keys || keys,
				values : values,
				clone : clone,
				isElement : isElement,
				isArray : isArray,
				isHash : isHash,
				isFunction : isFunction,
				isString : isString,
				isNumber : isNumber,
				isDate : isDate,
				isUndefined : isUndefined
			});
	})();
Object.extend(Function.prototype, (function () {
			var slice = Array.prototype.slice;
			
			function update(array, args) {
				var arrayLength = array.length,
				length = args.length;
				while (length--)
					array[arrayLength + length] = args[length];
				return array;
			}
			
			function merge(array, args) {
				array = slice.call(array, 0);
				return update(array, args);
			}
			
			function argumentNames() {
				var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
					.replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
					.replace(/\s+/g, '').split(',');
				return names.length == 1 && !names[0] ? [] : names;
			}
			
			function bind(context) {
				if (arguments.length < 2 && Object.isUndefined(arguments[0]))
					return this;
				var __method = this,
				args = slice.call(arguments, 1);
				return function () {
					var a = merge(args, arguments);
					return __method.apply(context, a);
				}
			}
			
			function bindAsEventListener(context) {
				var __method = this,
				args = slice.call(arguments, 1);
				return function (event) {
					var a = update([event || window.event], args);
					return __method.apply(context, a);
				}
			}
			
			function curry() {
				if (!arguments.length)
					return this;
				var __method = this,
				args = slice.call(arguments, 0);
				return function () {
					var a = merge(args, arguments);
					return __method.apply(this, a);
				}
			}
			
			function delay(timeout) {
				var __method = this,
				args = slice.call(arguments, 1);
				timeout = timeout * 1000;
				return window.setTimeout(function () {
						return __method.apply(__method, args);
					}, timeout);
			}
			
			function defer() {
				var args = update([0.01], arguments);
				return this.delay.apply(this, args);
			}
			
			function wrap(wrapper) {
				var __method = this;
				return function () {
					var a = update([__method.bind(this)], arguments);
					return wrapper.apply(this, a);
				}
			}
			
			function methodize() {
				if (this._methodized)
					return this._methodized;
				var __method = this;
				return this._methodized = function () {
					var a = update([this], arguments);
					return __method.apply(null, a);
				};
			}
			
			return {
				argumentNames : argumentNames,
				bind : bind,
				bindAsEventListener : bindAsEventListener,
				curry : curry,
				delay : delay,
				defer : defer,
				wrap : wrap,
				methodize : methodize
			}
		})());

(function (proto) {
		
		function toISOString() {
			return this.getUTCFullYear() + '-' +
			(this.getUTCMonth() + 1).toPaddedString(2) + '-' +
			this.getUTCDate().toPaddedString(2) + 'T' +
			this.getUTCHours().toPaddedString(2) + ':' +
			this.getUTCMinutes().toPaddedString(2) + ':' +
			this.getUTCSeconds().toPaddedString(2) + 'Z';
		}
		
		function toJSON() {
			return this.toISOString();
		}
		
		if (!proto.toISOString)
			proto.toISOString = toISOString;
		if (!proto.toJSON)
			proto.toJSON = toJSON;
		
	})(Date.prototype);

RegExp.prototype.match = RegExp.prototype.test;

RegExp.escape = function (str) {
	return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
var PeriodicalExecuter = Class.create({
			initialize : function (callback, frequency) {
				this.callback = callback;
				this.frequency = frequency;
				this.currentlyExecuting = false;
				
				this.registerCallback();
			},
			
			registerCallback : function () {
				this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
			},
			
			execute : function () {
				this.callback(this);
			},
			
			stop : function () {
				if (!this.timer)
					return;
				clearInterval(this.timer);
				this.timer = null;
			},
			
			onTimerEvent : function () {
				if (!this.currentlyExecuting) {
					try {
						this.currentlyExecuting = true;
						this.execute();
						this.currentlyExecuting = false;
					} catch (e) {
						this.currentlyExecuting = false;
						throw e;
					}
				}
			}
		});
Object.extend(String, {
		interpret : function (value) {
			return value == null ? '' : String(value);
		},
		specialChar : {
			'\b' : '\\b',
			'\t' : '\\t',
			'\n' : '\\n',
			'\f' : '\\f',
			'\r' : '\\r',
			'\\' : '\\\\'
		}
	});

Object.extend(String.prototype, (function () {
			var NATIVE_JSON_PARSE_SUPPORT = window.JSON &&
				typeof JSON.parse === 'function' &&
				JSON.parse('{"test": true}').test;
			
			function prepareReplacement(replacement) {
				if (Object.isFunction(replacement))
					return replacement;
				var template = new Template(replacement);
				return function (match) {
					return template.evaluate(match)
				};
			}
			
			function gsub(pattern, replacement) {
				var result = '',
				source = this,
				match;
				replacement = prepareReplacement(replacement);
				
				if (Object.isString(pattern))
					pattern = RegExp.escape(pattern);
				
				if (!(pattern.length || pattern.source)) {
					replacement = replacement('');
					return replacement + source.split('').join(replacement) + replacement;
				}
				while (source.length > 0) {
					if (match = source.match(pattern)) {
						result += source.slice(0, match.index);
						result += String.interpret(replacement(match));
						source = source.slice(match.index + match[0].length);
					} else {
						result += source,
						source = '';
					}
				}
				return result;
			}
			
			function sub(pattern, replacement, count) {
				replacement = prepareReplacement(replacement);
				count = Object.isUndefined(count) ? 1 : count;
				
				return this.gsub(pattern, function (match) {
						if (--count < 0)
							return match[0];
						return replacement(match);
					});
			}
			
			function scan(pattern, iterator) {
				this.gsub(pattern, iterator);
				return String(this);
			}
			
			function truncate(length, truncation) {
				length = length || 30;
				truncation = Object.isUndefined(truncation) ? '...' : truncation;
				return this.length > length ?
				this.slice(0, length - truncation.length) + truncation : String(this);
			}
			
			function strip() {
				return this.replace(/^\s+/, '').replace(/\s+$/, '');
			}
			
			function stripTags() {
				return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, '');
			}
			
			function stripScripts() {
				return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
			}
			
			function extractScripts() {
				var matchAll = new RegExp(Prototype.ScriptFragment, 'img'),
				matchOne = new RegExp(Prototype.ScriptFragment, 'im');
				return (this.match(matchAll) || []).map(function (scriptTag) {
						return (scriptTag.match(matchOne) || ['', ''])[1];
					});
			}
			
			function evalScripts() {
				return this.extractScripts().map(function (script) {
						return eval(script)
					});
			}
			
			function escapeHTML() {
				return this.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
			}
			
			function unescapeHTML() {
				return this.stripTags().replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');
			}
			
			function toQueryParams(separator) {
				var match = this.strip().match(/([^?#]*)(#.*)?$/);
				if (!match)
					return {};
				
				return match[1].split(separator || '&').inject({}, function (hash, pair) {
						if ((pair = pair.split('='))[0]) {
							var key = decodeURIComponent(pair.shift()),
							value = pair.length > 1 ? pair.join('=') : pair[0];
							
							if (value != undefined)
								value = decodeURIComponent(value);
							
							if (key in hash) {
								if (!Object.isArray(hash[key]))
									hash[key] = [hash[key]];
								hash[key].push(value);
							} else
								hash[key] = value;
						}
						return hash;
					});
			}
			
			function toArray() {
				return this.split('');
			}
			
			function succ() {
				return this.slice(0, this.length - 1) +
				String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
			}
			
			function times(count) {
				return count < 1 ? '' : new Array(count + 1).join(this);
			}
			
			function camelize() {
				return this.replace(/-+(.)?/g, function (match, chr) {
						return chr ? chr.toUpperCase() : '';
					});
			}
			
			function capitalize() {
				return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
			}
			
			function underscore() {
				return this.replace(/::/g, '/')
				.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
				.replace(/([a-z\d])([A-Z])/g, '$1_$2')
				.replace(/-/g, '_')
				.toLowerCase();
			}
			
			function dasherize() {
				return this.replace(/_/g, '-');
			}
			
			function inspect(useDoubleQuotes) {
				var escapedString = this.replace(/[\x00-\x1f\\]/g, function (character) {
							if (character in String.specialChar) {
								return String.specialChar[character];
							}
							return '\\u00' + character.charCodeAt().toPaddedString(2, 16);
						});
				if (useDoubleQuotes)
					return '"' + escapedString.replace(/"/g, '\\"') + '"';
				return "'" + escapedString.replace(/'/g, '\\\'') + "'";
			}
			
			function unfilterJSON(filter) {
				return this.replace(filter || Prototype.JSONFilter, '$1');
			}
			
			function isJSON() {
				var str = this;
				if (str.blank())
					return false;
				str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
				str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
				str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
				return (/^[\],:{}\s]*$/).test(str);
			}
			
			function evalJSON(sanitize) {
				var json = this.unfilterJSON(),
				cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
				if (cx.test(json)) {
					json = json.replace(cx, function (a) {
								return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
							});
				}
				try {
					if (!sanitize || json.isJSON())
						return eval('(' + json + ')');
				} catch (e) {}
				throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
			}
			
			function parseJSON() {
				var json = this.unfilterJSON();
				return JSON.parse(json);
			}
			
			function include(pattern) {
				return this.indexOf(pattern) > -1;
			}
			
			function startsWith(pattern) {
				return this.lastIndexOf(pattern, 0) === 0;
			}
			
			function endsWith(pattern) {
				var d = this.length - pattern.length;
				return d >= 0 && this.indexOf(pattern, d) === d;
			}
			
			function empty() {
				return this == '';
			}
			
			function blank() {
				return /^\s*$/.test(this);
			}
			
			function interpolate(object, pattern) {
				return new Template(this, pattern).evaluate(object);
			}
			
			return {
				gsub : gsub,
				sub : sub,
				scan : scan,
				truncate : truncate,
				strip : String.prototype.trim || strip,
				stripTags : stripTags,
				stripScripts : stripScripts,
				extractScripts : extractScripts,
				evalScripts : evalScripts,
				escapeHTML : escapeHTML,
				unescapeHTML : unescapeHTML,
				toQueryParams : toQueryParams,
				parseQuery : toQueryParams,
				toArray : toArray,
				succ : succ,
				times : times,
				camelize : camelize,
				capitalize : capitalize,
				underscore : underscore,
				dasherize : dasherize,
				inspect : inspect,
				unfilterJSON : unfilterJSON,
				isJSON : isJSON,
				evalJSON : NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON,
				include : include,
				startsWith : startsWith,
				endsWith : endsWith,
				empty : empty,
				blank : blank,
				interpolate : interpolate
			};
		})());

var Template = Class.create({
			initialize : function (template, pattern) {
				this.template = template.toString();
				this.pattern = pattern || Template.Pattern;
			},
			
			evaluate : function (object) {
				if (object && Object.isFunction(object.toTemplateReplacements))
					object = object.toTemplateReplacements();
				
				return this.template.gsub(this.pattern, function (match) {
						if (object == null)
							return (match[1] + '');
						
						var before = match[1] || '';
						if (before == '\\')
							return match[2];
						
						var ctx = object,
						expr = match[3],
						pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
						
						match = pattern.exec(expr);
						if (match == null)
							return before;
						while (match != null) {
							var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
							ctx = ctx[comp];
							if (null == ctx || '' == match[3])
								break;
							expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
							match = pattern.exec(expr);
						}
						
						return before + String.interpret(ctx);
					});
			}
		});
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;

var $break = {};

var Enumerable = (function () {
		function each(iterator, context) {
			var index = 0;
			try {
				this._each(function (value) {
						iterator.call(context, value, index++);
					});
			} catch (e) {
				if (e != $break)
					throw e;
			}
			return this;
		}
		
		function eachSlice(number, iterator, context) {
			var index = -number,
			slices = [],
			array = this.toArray();
			if (number < 1)
				return array;
			while ((index += number) < array.length)
				slices.push(array.slice(index, index + number));
			return slices.collect(iterator, context);
		}
		
		function all(iterator, context) {
			iterator = iterator || Prototype.K;
			var result = true;
			this.each(function (value, index) {
					result = result && !!iterator.call(context, value, index);
					if (!result)
						throw $break;
				});
			return result;
		}
		
		function any(iterator, context) {
			iterator = iterator || Prototype.K;
			var result = false;
			this.each(function (value, index) {
					if (result = !!iterator.call(context, value, index))
						throw $break;
				});
			return result;
		}
		
		function collect(iterator, context) {
			iterator = iterator || Prototype.K;
			var results = [];
			this.each(function (value, index) {
					results.push(iterator.call(context, value, index));
				});
			return results;
		}
		
		function detect(iterator, context) {
			var result;
			this.each(function (value, index) {
					if (iterator.call(context, value, index)) {
						result = value;
						throw $break;
					}
				});
			return result;
		}
		
		function findAll(iterator, context) {
			var results = [];
			this.each(function (value, index) {
					if (iterator.call(context, value, index))
						results.push(value);
				});
			return results;
		}
		
		function grep(filter, iterator, context) {
			iterator = iterator || Prototype.K;
			var results = [];
			
			if (Object.isString(filter))
				filter = new RegExp(RegExp.escape(filter));
			
			this.each(function (value, index) {
					if (filter.match(value))
						results.push(iterator.call(context, value, index));
				});
			return results;
		}
		
		function include(object) {
			if (Object.isFunction(this.indexOf))
				if (this.indexOf(object) != -1)
					return true;
			
			var found = false;
			this.each(function (value) {
					if (value == object) {
						found = true;
						throw $break;
					}
				});
			return found;
		}
		
		function inGroupsOf(number, fillWith) {
			fillWith = Object.isUndefined(fillWith) ? null : fillWith;
			return this.eachSlice(number, function (slice) {
					while (slice.length < number)
						slice.push(fillWith);
					return slice;
				});
		}
		
		function inject(memo, iterator, context) {
			this.each(function (value, index) {
					memo = iterator.call(context, memo, value, index);
				});
			return memo;
		}
		
		function invoke(method) {
			var args = $A(arguments).slice(1);
			return this.map(function (value) {
					return value[method].apply(value, args);
				});
		}
		
		function max(iterator, context) {
			iterator = iterator || Prototype.K;
			var result;
			this.each(function (value, index) {
					value = iterator.call(context, value, index);
					if (result == null || value >= result)
						result = value;
				});
			return result;
		}
		
		function min(iterator, context) {
			iterator = iterator || Prototype.K;
			var result;
			this.each(function (value, index) {
					value = iterator.call(context, value, index);
					if (result == null || value < result)
						result = value;
				});
			return result;
		}
		
		function partition(iterator, context) {
			iterator = iterator || Prototype.K;
			var trues = [],
			falses = [];
			this.each(function (value, index) {
					(iterator.call(context, value, index) ?
						trues : falses).push(value);
				});
			return [trues, falses];
		}
		
		function pluck(property) {
			var results = [];
			this.each(function (value) {
					results.push(value[property]);
				});
			return results;
		}
		
		function reject(iterator, context) {
			var results = [];
			this.each(function (value, index) {
					if (!iterator.call(context, value, index))
						results.push(value);
				});
			return results;
		}
		
		function sortBy(iterator, context) {
			return this.map(function (value, index) {
					return {
						value : value,
						criteria : iterator.call(context, value, index)
					};
				}).sort(function (left, right) {
					var a = left.criteria,
					b = right.criteria;
					return a < b ? -1 : a > b ? 1 : 0;
				}).pluck('value');
		}
		
		function toArray() {
			return this.map();
		}
		
		function zip() {
			var iterator = Prototype.K,
			args = $A(arguments);
			if (Object.isFunction(args.last()))
				iterator = args.pop();
			
			var collections = [this].concat(args).map($A);
			return this.map(function (value, index) {
					return iterator(collections.pluck(index));
				});
		}
		
		function size() {
			return this.toArray().length;
		}
		
		function inspect() {
			return '#<Enumerable:' + this.toArray().inspect() + '>';
		}
		
		return {
			each : each,
			eachSlice : eachSlice,
			all : all,
			every : all,
			any : any,
			some : any,
			collect : collect,
			map : collect,
			detect : detect,
			findAll : findAll,
			select : findAll,
			filter : findAll,
			grep : grep,
			include : include,
			member : include,
			inGroupsOf : inGroupsOf,
			inject : inject,
			invoke : invoke,
			max : max,
			min : min,
			partition : partition,
			pluck : pluck,
			reject : reject,
			sortBy : sortBy,
			toArray : toArray,
			entries : toArray,
			zip : zip,
			size : size,
			inspect : inspect,
			find : detect
		};
	})();

function $A(iterable) {
	if (!iterable)
		return [];
	if ('toArray' in Object(iterable))
		return iterable.toArray();
	var length = iterable.length || 0,
	results = new Array(length);
	while (length--)
		results[length] = iterable[length];
	return results;
}

function $w(string) {
	if (!Object.isString(string))
		return [];
	string = string.strip();
	return string ? string.split(/\s+/) : [];
}

Array.from = $A;

(function () {
		var arrayProto = Array.prototype,
		slice = arrayProto.slice,
		_each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
		
		function each(iterator, context) {
			for (var i = 0, length = this.length >>> 0; i < length; i++) {
				if (i in this)
					iterator.call(context, this[i], i, this);
			}
		}
		if (!_each)
			_each = each;
		
		function clear() {
			this.length = 0;
			return this;
		}
		
		function first() {
			return this[0];
		}
		
		function last() {
			return this[this.length - 1];
		}
		
		function compact() {
			return this.select(function (value) {
					return value != null;
				});
		}
		
		function flatten() {
			return this.inject([], function (array, value) {
					if (Object.isArray(value))
						return array.concat(value.flatten());
					array.push(value);
					return array;
				});
		}
		
		function without() {
			var values = slice.call(arguments, 0);
			return this.select(function (value) {
					return !values.include(value);
				});
		}
		
		function reverse(inline) {
			return (inline === false ? this.toArray() : this)._reverse();
		}
		
		function uniq(sorted) {
			return this.inject([], function (array, value, index) {
					if (0 == index || (sorted ? array.last() != value : !array.include(value)))
						array.push(value);
					return array;
				});
		}
		
		function intersect(array) {
			return this.uniq().findAll(function (item) {
					return array.detect(function (value) {
							return item === value
						});
				});
		}
		
		function clone() {
			return slice.call(this, 0);
		}
		
		function size() {
			return this.length;
		}
		
		function inspect() {
			return '[' + this.map(Object.inspect).join(', ') + ']';
		}
		
		function indexOf(item, i) {
			i || (i = 0);
			var length = this.length;
			if (i < 0)
				i = length + i;
			for (; i < length; i++)
				if (this[i] === item)
					return i;
			return -1;
		}
		
		function lastIndexOf(item, i) {
			i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
			var n = this.slice(0, i).reverse().indexOf(item);
			return (n < 0) ? n : i - n - 1;
		}
		
		function concat() {
			var array = slice.call(this, 0),
			item;
			for (var i = 0, length = arguments.length; i < length; i++) {
				item = arguments[i];
				if (Object.isArray(item) && !('callee' in item)) {
					for (var j = 0, arrayLength = item.length; j < arrayLength; j++)
						array.push(item[j]);
				} else {
					array.push(item);
				}
			}
			return array;
		}
		
		Object.extend(arrayProto, Enumerable);
		
		if (!arrayProto._reverse)
			arrayProto._reverse = arrayProto.reverse;
		
		Object.extend(arrayProto, {
				_each : _each,
				clear : clear,
				first : first,
				last : last,
				compact : compact,
				flatten : flatten,
				without : without,
				reverse : reverse,
				uniq : uniq,
				intersect : intersect,
				clone : clone,
				toArray : clone,
				size : size,
				inspect : inspect
			});
		
		var CONCAT_ARGUMENTS_BUGGY = (function () {
				return [].concat(arguments)[0][0] !== 1;
			})(1, 2)
		
		if (CONCAT_ARGUMENTS_BUGGY)
			arrayProto.concat = concat;
		
		if (!arrayProto.indexOf)
			arrayProto.indexOf = indexOf;
		if (!arrayProto.lastIndexOf)
			arrayProto.lastIndexOf = lastIndexOf;
	})();
function $H(object) {
	return new Hash(object);
};

var Hash = Class.create(Enumerable, (function () {
				function initialize(object) {
					this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
				}
				
				function _each(iterator) {
					for (var key in this._object) {
						var value = this._object[key],
						pair = [key, value];
						pair.key = key;
						pair.value = value;
						iterator(pair);
					}
				}
				
				function set(key, value) {
					return this._object[key] = value;
				}
				
				function get(key) {
					if (this._object[key] !== Object.prototype[key])
						return this._object[key];
				}
				
				function unset(key) {
					var value = this._object[key];
					delete this._object[key];
					return value;
				}
				
				function toObject() {
					return Object.clone(this._object);
				}
				
				function keys() {
					return this.pluck('key');
				}
				
				function values() {
					return this.pluck('value');
				}
				
				function index(value) {
					var match = this.detect(function (pair) {
								return pair.value === value;
							});
					return match && match.key;
				}
				
				function merge(object) {
					return this.clone().update(object);
				}
				
				function update(object) {
					return new Hash(object).inject(this, function (result, pair) {
							result.set(pair.key, pair.value);
							return result;
						});
				}
				
				function toQueryPair(key, value) {
					if (Object.isUndefined(value))
						return key;
					return key + '=' + encodeURIComponent(String.interpret(value));
				}
				
				function toQueryString() {
					return this.inject([], function (results, pair) {
							var key = encodeURIComponent(pair.key),
							values = pair.value;
							
							if (values && typeof values == 'object') {
								if (Object.isArray(values)) {
									var queryValues = [];
									for (var i = 0, len = values.length, value; i < len; i++) {
										value = values[i];
										queryValues.push(toQueryPair(key, value));
									}
									return results.concat(queryValues);
								}
							} else
								results.push(toQueryPair(key, values));
							return results;
						}).join('&');
				}
				
				function inspect() {
					return '#<Hash:{' + this.map(function (pair) {
							return pair.map(Object.inspect).join(': ');
						}).join(', ') + '}>';
				}
				
				function clone() {
					return new Hash(this);
				}
				
				return {
					initialize : initialize,
					_each : _each,
					set : set,
					get : get,
					unset : unset,
					toObject : toObject,
					toTemplateReplacements : toObject,
					keys : keys,
					values : values,
					index : index,
					merge : merge,
					update : update,
					toQueryString : toQueryString,
					inspect : inspect,
					toJSON : toObject,
					clone : clone
				};
			})());

Hash.from = $H;
Object.extend(Number.prototype, (function () {
			function toColorPart() {
				return this.toPaddedString(2, 16);
			}
			
			function succ() {
				return this + 1;
			}
			
			function times(iterator, context) {
				$R(0, this, true).each(iterator, context);
				return this;
			}
			
			function toPaddedString(length, radix) {
				var string = this.toString(radix || 10);
				return '0'.times(length - string.length) + string;
			}
			
			function abs() {
				return Math.abs(this);
			}
			
			function round() {
				return Math.round(this);
			}
			
			function ceil() {
				return Math.ceil(this);
			}
			
			function floor() {
				return Math.floor(this);
			}
			
			return {
				toColorPart : toColorPart,
				succ : succ,
				times : times,
				toPaddedString : toPaddedString,
				abs : abs,
				round : round,
				ceil : ceil,
				floor : floor
			};
		})());

function $R(start, end, exclusive) {
	return new ObjectRange(start, end, exclusive);
}

var ObjectRange = Class.create(Enumerable, (function () {
				function initialize(start, end, exclusive) {
					this.start = start;
					this.end = end;
					this.exclusive = exclusive;
				}
				
				function _each(iterator) {
					var value = this.start;
					while (this.include(value)) {
						iterator(value);
						value = value.succ();
					}
				}
				
				function include(value) {
					if (value < this.start)
						return false;
					if (this.exclusive)
						return value < this.end;
					return value <= this.end;
				}
				
				return {
					initialize : initialize,
					_each : _each,
					include : include
				};
			})());

var Ajax = {
	getTransport : function () {
		return Try.these(
			function () {
				return new XMLHttpRequest()
			},
			function () {
				return new ActiveXObject('Msxml2.XMLHTTP')
			},
			function () {
				return new ActiveXObject('Microsoft.XMLHTTP')
			}) || false;
	},
	
	activeRequestCount : 0
};

Ajax.Responders = {
	responders : [],
	
	_each : function (iterator) {
		this.responders._each(iterator);
	},
	
	register : function (responder) {
		if (!this.include(responder))
			this.responders.push(responder);
	},
	
	unregister : function (responder) {
		this.responders = this.responders.without(responder);
	},
	
	dispatch : function (callback, request, transport, json) {
		this.each(function (responder) {
				if (Object.isFunction(responder[callback])) {
					try {
						responder[callback].apply(responder, [request, transport, json]);
					} catch (e) {}
				}
			});
	}
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
		onCreate : function () {
			Ajax.activeRequestCount++
		},
		onComplete : function () {
			Ajax.activeRequestCount--
		}
	});
Ajax.Base = Class.create({
			initialize : function (options) {
				this.options = {
					method : 'post',
					asynchronous : true,
					contentType : 'application/x-www-form-urlencoded',
					encoding : 'UTF-8',
					parameters : '',
					evalJSON : true,
					evalJS : true
				};
				Object.extend(this.options, options || {});
				
				this.options.method = this.options.method.toLowerCase();
				
				if (Object.isHash(this.options.parameters))
					this.options.parameters = this.options.parameters.toObject();
			}
		});
Ajax.Request = Class.create(Ajax.Base, {
			_complete : false,
			
			initialize : function ($super, url, options) {
				$super(options);
				this.transport = Ajax.getTransport();
				this.request(url);
			},
			
			request : function (url) {
				this.url = url;
				this.method = this.options.method;
				var params = Object.isString(this.options.parameters) ?
					this.options.parameters :
					Object.toQueryString(this.options.parameters);
				
				if (!['get', 'post'].include(this.method)) {
					params += (params ? '&' : '') + "_method=" + this.method;
					this.method = 'post';
				}
				
				if (params && this.method === 'get') {
					this.url += (this.url.include('?') ? '&' : '?') + params;
				}
				
				this.parameters = params.toQueryParams();
				
				try {
					var response = new Ajax.Response(this);
					if (this.options.onCreate)
						this.options.onCreate(response);
					Ajax.Responders.dispatch('onCreate', this, response);
					
					this.transport.open(this.method.toUpperCase(), this.url,
						this.options.asynchronous);
					
					if (this.options.asynchronous)
						this.respondToReadyState.bind(this).defer(1);
					
					this.transport.onreadystatechange = this.onStateChange.bind(this);
					this.setRequestHeaders();
					
					this.body = this.method == 'post' ? (this.options.postBody || params) : null;
					this.transport.send(this.body);
					
					/* Force Firefox to handle ready state 4 for synchronous requests */
					if (!this.options.asynchronous && this.transport.overrideMimeType)
						this.onStateChange();
					
				} catch (e) {
					this.dispatchException(e);
				}
			},
			
			onStateChange : function () {
				var readyState = this.transport.readyState;
				if (readyState > 1 && !((readyState == 4) && this._complete))
					this.respondToReadyState(this.transport.readyState);
			},
			
			setRequestHeaders : function () {
				var headers = {
					'X-Requested-With' : 'XMLHttpRequest',
					'X-Prototype-Version' : Prototype.Version,
					'Accept' : 'text/javascript, text/html, application/xml, text/xml, */*'
				};
				
				if (this.method == 'post') {
					headers['Content-type'] = this.options.contentType +
						(this.options.encoding ? '; charset=' + this.options.encoding : '');
					
					/* Force "Connection: close" for older Mozilla browsers to work
					 * around a bug where XMLHttpRequest sends an incorrect
					 * Content-length header. See Mozilla Bugzilla #246651.
					 */
					if (this.transport.overrideMimeType &&
						(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0, 2005])[1] < 2005)
						headers['Connection'] = 'close';
				}
				
				if (typeof this.options.requestHeaders == 'object') {
					var extras = this.options.requestHeaders;
					
					if (Object.isFunction(extras.push))
						for (var i = 0, length = extras.length; i < length; i += 2)
							headers[extras[i]] = extras[i + 1];
					else
						$H(extras).each(function (pair) {
								headers[pair.key] = pair.value
							});
				}
				
				for (var name in headers)
					this.transport.setRequestHeader(name, headers[name]);
			},
			
			success : function () {
				var status = this.getStatus();
				return !status || (status >= 200 && status < 300) || status == 304;
			},
			
			getStatus : function () {
				try {
					if (this.transport.status === 1223)
						return 204;
					return this.transport.status || 0;
				} catch (e) {
					return 0
				}
			},
			
			respondToReadyState : function (readyState) {
				var state = Ajax.Request.Events[readyState],
				response = new Ajax.Response(this);
				
				if (state == 'Complete') {
					try {
						this._complete = true;
						(this.options['on' + response.status]
							 || this.options['on' + (this.success() ? 'Success' : 'Failure')]
							 || Prototype.emptyFunction)(response, response.headerJSON);
					} catch (e) {
						this.dispatchException(e);
					}
					
					var contentType = response.getHeader('Content-type');
					if (this.options.evalJS == 'force'
						 || (this.options.evalJS && this.isSameOrigin() && contentType
							 && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
						this.evalResponse();
				}
				
				try {
					(this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
					Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
				} catch (e) {
					this.dispatchException(e);
				}
				
				if (state == 'Complete') {
					this.transport.onreadystatechange = Prototype.emptyFunction;
				}
			},
			
			isSameOrigin : function () {
				var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
				return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
							protocol : location.protocol,
							domain : document.domain,
							port : location.port ? ':' + location.port : ''
						}));
			},
			
			getHeader : function (name) {
				try {
					return this.transport.getResponseHeader(name) || null;
				} catch (e) {
					return null;
				}
			},
			
			evalResponse : function () {
				try {
					return eval((this.transport.responseText || '').unfilterJSON());
				} catch (e) {
					this.dispatchException(e);
				}
			},
			
			dispatchException : function (exception) {
				(this.options.onException || Prototype.emptyFunction)(this, exception);
				Ajax.Responders.dispatch('onException', this, exception);
			}
		});

Ajax.Request.Events =
	['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Response = Class.create({
			initialize : function (request) {
				this.request = request;
				var transport = this.transport = request.transport,
				readyState = this.readyState = transport.readyState;
				
				if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
					this.status = this.getStatus();
					this.statusText = this.getStatusText();
					this.responseText = String.interpret(transport.responseText);
					this.headerJSON = this._getHeaderJSON();
				}
				
				if (readyState == 4) {
					var xml = transport.responseXML;
					this.responseXML = Object.isUndefined(xml) ? null : xml;
					this.responseJSON = this._getResponseJSON();
				}
			},
			
			status : 0,
			
			statusText : '',
			
			getStatus : Ajax.Request.prototype.getStatus,
			
			getStatusText : function () {
				try {
					return this.transport.statusText || '';
				} catch (e) {
					return ''
				}
			},
			
			getHeader : Ajax.Request.prototype.getHeader,
			
			getAllHeaders : function () {
				try {
					return this.getAllResponseHeaders();
				} catch (e) {
					return null
				}
			},
			
			getResponseHeader : function (name) {
				return this.transport.getResponseHeader(name);
			},
			
			getAllResponseHeaders : function () {
				return this.transport.getAllResponseHeaders();
			},
			
			_getHeaderJSON : function () {
				var json = this.getHeader('X-JSON');
				if (!json)
					return null;
				json = decodeURIComponent(escape(json));
				try {
					return json.evalJSON(this.request.options.sanitizeJSON ||
						!this.request.isSameOrigin());
				} catch (e) {
					this.request.dispatchException(e);
				}
			},
			
			_getResponseJSON : function () {
				var options = this.request.options;
				if (!options.evalJSON || (options.evalJSON != 'force' &&
						!(this.getHeader('Content-type') || '').include('application/json')) ||
					this.responseText.blank())
					return null;
				try {
					return this.responseText.evalJSON(options.sanitizeJSON ||
						!this.request.isSameOrigin());
				} catch (e) {
					this.request.dispatchException(e);
				}
			}
		});

Ajax.Updater = Class.create(Ajax.Request, {
			initialize : function ($super, container, url, options) {
				this.container = {
					success : (container.success || container),
					failure : (container.failure || (container.success ? null : container))
				};
				
				options = Object.clone(options);
				var onComplete = options.onComplete;
				options.onComplete = (function (response, json) {
						this.updateContent(response.responseText);
						if (Object.isFunction(onComplete))
							onComplete(response, json);
					}).bind(this);
				
				$super(url, options);
			},
			
			updateContent : function (responseText) {
				var receiver = this.container[this.success() ? 'success' : 'failure'],
				options = this.options;
				
				if (!options.evalScripts)
					responseText = responseText.stripScripts();
				
				if (receiver = $(receiver)) {
					if (options.insertion) {
						if (Object.isString(options.insertion)) {
							var insertion = {};
							insertion[options.insertion] = responseText;
							receiver.insert(insertion);
						} else
							options.insertion(receiver, responseText);
					} else
						receiver.update(responseText);
				}
			}
		});

Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
			initialize : function ($super, container, url, options) {
				$super(options);
				this.onComplete = this.options.onComplete;
				
				this.frequency = (this.options.frequency || 2);
				this.decay = (this.options.decay || 1);
				
				this.updater = {};
				this.container = container;
				this.url = url;
				
				this.start();
			},
			
			start : function () {
				this.options.onComplete = this.updateComplete.bind(this);
				this.onTimerEvent();
			},
			
			stop : function () {
				this.updater.options.onComplete = undefined;
				clearTimeout(this.timer);
				(this.onComplete || Prototype.emptyFunction).apply(this, arguments);
			},
			
			updateComplete : function (response) {
				if (this.options.decay) {
					this.decay = (response.responseText == this.lastText ?
						this.decay * this.options.decay : 1);
					
					this.lastText = response.responseText;
				}
				this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
			},
			
			onTimerEvent : function () {
				this.updater = new Ajax.Updater(this.container, this.url, this.options);
			}
		});

function $(element) {
	if (arguments.length > 1) {
		for (var i = 0, elements = [], length = arguments.length; i < length; i++)
			elements.push($(arguments[i]));
		return elements;
	}
	if (Object.isString(element))
		element = document.getElementById(element);
	return Element.extend(element);
}

if (Prototype.BrowserFeatures.XPath) {
	document._getElementsByXPath = function (expression, parentElement) {
		var results = [];
		var query = document.evaluate(expression, $(parentElement) || document,
				null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
		for (var i = 0, length = query.snapshotLength; i < length; i++)
			results.push(Element.extend(query.snapshotItem(i)));
		return results;
	};
}

/*--------------------------------------------------------------------------*/

if (!Node)
	var Node = {};

if (!Node.ELEMENT_NODE) {
	Object.extend(Node, {
			ELEMENT_NODE : 1,
			ATTRIBUTE_NODE : 2,
			TEXT_NODE : 3,
			CDATA_SECTION_NODE : 4,
			ENTITY_REFERENCE_NODE : 5,
			ENTITY_NODE : 6,
			PROCESSING_INSTRUCTION_NODE : 7,
			COMMENT_NODE : 8,
			DOCUMENT_NODE : 9,
			DOCUMENT_TYPE_NODE : 10,
			DOCUMENT_FRAGMENT_NODE : 11,
			NOTATION_NODE : 12
		});
}

(function (global) {
		function shouldUseCache(tagName, attributes) {
			if (tagName === 'select')
				return false;
			if ('type' in attributes)
				return false;
			return true;
		}
		
		var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function () {
				try {
					var el = document.createElement('<input name="x">');
					return el.tagName.toLowerCase() === 'input' && el.name === 'x';
				} catch (err) {
					return false;
				}
			})();
		
		var element = global.Element;
		
		global.Element = function (tagName, attributes) {
			attributes = attributes || {};
			tagName = tagName.toLowerCase();
			var cache = Element.cache;
			
			if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
				tagName = '<' + tagName + ' name="' + attributes.name + '">';
				delete attributes.name;
				return Element.writeAttribute(document.createElement(tagName), attributes);
			}
			
			if (!cache[tagName])
				cache[tagName] = Element.extend(document.createElement(tagName));
			
			var node = shouldUseCache(tagName, attributes) ?
				cache[tagName].cloneNode(false) : document.createElement(tagName);
			
			return Element.writeAttribute(node, attributes);
		};
		
		Object.extend(global.Element, element || {});
		if (element)
			global.Element.prototype = element.prototype;
		
	})(this);

Element.idCounter = 1;
Element.cache = {};

Element._purgeElement = function (element) {
	var uid = element._prototypeUID;
	if (uid) {
		Element.stopObserving(element);
		element._prototypeUID = void 0;
		delete Element.Storage[uid];
	}
}

Element.Methods = {
	visible : function (element) {
		return $(element).style.display != 'none';
	},
	
	toggle : function (element) {
		element = $(element);
		Element[Element.visible(element) ? 'hide' : 'show'](element);
		return element;
	},
	
	hide : function (element) {
		element = $(element);
		element.style.display = 'none';
		return element;
	},
	
	show : function (element) {
		element = $(element);
		element.style.display = '';
		return element;
	},
	
	remove : function (element) {
		element = $(element);
		element.parentNode.removeChild(element);
		return element;
	},
	
	update : (function () {
			
			var SELECT_ELEMENT_INNERHTML_BUGGY = (function () {
					var el = document.createElement("select"),
					isBuggy = true;
					el.innerHTML = "<option value=\"test\">test</option>";
					if (el.options && el.options[0]) {
						isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
					}
					el = null;
					return isBuggy;
				})();
			
			var TABLE_ELEMENT_INNERHTML_BUGGY = (function () {
					try {
						var el = document.createElement("table");
						if (el && el.tBodies) {
							el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
							var isBuggy = typeof el.tBodies[0] == "undefined";
							el = null;
							return isBuggy;
						}
					} catch (e) {
						return true;
					}
				})();
			
			var LINK_ELEMENT_INNERHTML_BUGGY = (function () {
					try {
						var el = document.createElement('div');
						el.innerHTML = "<link>";
						var isBuggy = (el.childNodes.length === 0);
						el = null;
						return isBuggy;
					} catch (e) {
						return true;
					}
				})();
			
			var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
				TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
			
			var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
					var s = document.createElement("script"),
					isBuggy = false;
					try {
						s.appendChild(document.createTextNode(""));
						isBuggy = !s.firstChild ||
							s.firstChild && s.firstChild.nodeType !== 3;
					} catch (e) {
						isBuggy = true;
					}
					s = null;
					return isBuggy;
				})();
			
			function update(element, content) {
				element = $(element);
				var purgeElement = Element._purgeElement;
				
				var descendants = element.getElementsByTagName('*'),
				i = descendants.length;
				while (i--)
					purgeElement(descendants[i]);
				
				if (content && content.toElement)
					content = content.toElement();
				
				if (Object.isElement(content))
					return element.update().insert(content);
				
				content = Object.toHTML(content);
				
				var tagName = element.tagName.toUpperCase();
				
				if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
					element.text = content;
					return element;
				}
				
				if (ANY_INNERHTML_BUGGY) {
					if (tagName in Element._insertionTranslations.tags) {
						while (element.firstChild) {
							element.removeChild(element.firstChild);
						}
						Element._getContentFromAnonymousElement(tagName, content.stripScripts())
						.each(function (node) {
								element.appendChild(node)
							});
					} else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
						while (element.firstChild) {
							element.removeChild(element.firstChild);
						}
						var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true);
						nodes.each(function (node) {
								element.appendChild(node)
							});
					} else {
						element.innerHTML = content.stripScripts();
					}
				} else {
					element.innerHTML = content.stripScripts();
				}
				
				content.evalScripts.bind(content).defer();
				return element;
			}
			
			return update;
		})(),
	
	replace : function (element, content) {
		element = $(element);
		if (content && content.toElement)
			content = content.toElement();
		else if (!Object.isElement(content)) {
			content = Object.toHTML(content);
			var range = element.ownerDocument.createRange();
			range.selectNode(element);
			content.evalScripts.bind(content).defer();
			content = range.createContextualFragment(content.stripScripts());
		}
		element.parentNode.replaceChild(content, element);
		return element;
	},
	
	insert : function (element, insertions) {
		element = $(element);
		
		if (Object.isString(insertions) || Object.isNumber(insertions) ||
			Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
			insertions = {
				bottom : insertions
			};
		
		var content,
		insert,
		tagName,
		childNodes;
		
		for (var position in insertions) {
			content = insertions[position];
			position = position.toLowerCase();
			insert = Element._insertionTranslations[position];
			
			if (content && content.toElement)
				content = content.toElement();
			if (Object.isElement(content)) {
				insert(element, content);
				continue;
			}
			
			content = Object.toHTML(content);
			
			tagName = ((position == 'before' || position == 'after')
				 ? element.parentNode : element).tagName.toUpperCase();
			
			childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
			
			if (position == 'top' || position == 'after')
				childNodes.reverse();
			childNodes.each(insert.curry(element));
			
			content.evalScripts.bind(content).defer();
		}
		
		return element;
	},
	
	wrap : function (element, wrapper, attributes) {
		element = $(element);
		if (Object.isElement(wrapper))
			$(wrapper).writeAttribute(attributes || {});
		else if (Object.isString(wrapper))
			wrapper = new Element(wrapper, attributes);
		else
			wrapper = new Element('div', wrapper);
		if (element.parentNode)
			element.parentNode.replaceChild(wrapper, element);
		wrapper.appendChild(element);
		return wrapper;
	},
	
	inspect : function (element) {
		element = $(element);
		var result = '<' + element.tagName.toLowerCase();
		$H({
				'id' : 'id',
				'className' : 'class'
			}).each(function (pair) {
				var property = pair.first(),
				attribute = pair.last(),
				value = (element[property] || '').toString();
				if (value)
					result += ' ' + attribute + '=' + value.inspect(true);
			});
		return result + '>';
	},
	
	recursivelyCollect : function (element, property, maximumLength) {
		element = $(element);
		maximumLength = maximumLength || -1;
		var elements = [];
		while (element = element[property]) {
			if (element.nodeType == 1)
				elements.push(Element.extend(element));
			if (elements.length == maximumLength)
				break;
		}
		
		return elements;
	},
	
	ancestors : function (element) {
		return Element.recursivelyCollect(element, 'parentNode');
	},
	
	descendants : function (element) {
		return Element.select(element, "*");
	},
	
	firstDescendant : function (element) {
		element = $(element).firstChild;
		while (element && element.nodeType != 1)
			element = element.nextSibling;
		return $(element);
	},
	
	immediateDescendants : function (element) {
		var results = [],
		child = $(element).firstChild;
		while (child) {
			if (child.nodeType === 1) {
				results.push(Element.extend(child));
			}
			child = child.nextSibling;
		}
		return results;
	},
	
	previousSiblings : function (element, maximumLength) {
		return Element.recursivelyCollect(element, 'previousSibling');
	},
	
	nextSiblings : function (element) {
		return Element.recursivelyCollect(element, 'nextSibling');
	},
	
	siblings : function (element) {
		element = $(element);
		return Element.previousSiblings(element).reverse()
		.concat(Element.nextSiblings(element));
	},
	
	match : function (element, selector) {
		element = $(element);
		if (Object.isString(selector))
			return Prototype.Selector.match(element, selector);
		return selector.match(element);
	},
	
	up : function (element, expression, index) {
		element = $(element);
		if (arguments.length == 1)
			return $(element.parentNode);
		var ancestors = Element.ancestors(element);
		return Object.isNumber(expression) ? ancestors[expression] :
		Prototype.Selector.find(ancestors, expression, index);
	},
	
	down : function (element, expression, index) {
		element = $(element);
		if (arguments.length == 1)
			return Element.firstDescendant(element);
		return Object.isNumber(expression) ? Element.descendants(element)[expression] :
		Element.select(element, expression)[index || 0];
	},
	
	previous : function (element, expression, index) {
		element = $(element);
		if (Object.isNumber(expression))
			index = expression, expression = false;
		if (!Object.isNumber(index))
			index = 0;
		
		if (expression) {
			return Prototype.Selector.find(element.previousSiblings(), expression, index);
		} else {
			return element.recursivelyCollect("previousSibling", index + 1)[index];
		}
	},
	
	next : function (element, expression, index) {
		element = $(element);
		if (Object.isNumber(expression))
			index = expression, expression = false;
		if (!Object.isNumber(index))
			index = 0;
		
		if (expression) {
			return Prototype.Selector.find(element.nextSiblings(), expression, index);
		} else {
			var maximumLength = Object.isNumber(index) ? index + 1 : 1;
			return element.recursivelyCollect("nextSibling", index + 1)[index];
		}
	},
	
	select : function (element) {
		element = $(element);
		var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
		return Prototype.Selector.select(expressions, element);
	},
	
	adjacent : function (element) {
		element = $(element);
		var expressions = Array.prototype.slice.call(arguments, 1).join(', ');
		return Prototype.Selector.select(expressions, element.parentNode).without(element);
	},
	
	identify : function (element) {
		element = $(element);
		var id = Element.readAttribute(element, 'id');
		if (id)
			return id;
		do {
			id = 'anonymous_element_' + Element.idCounter++
		} while ($(id));
		Element.writeAttribute(element, 'id', id);
		return id;
	},
	
	readAttribute : function (element, name) {
		element = $(element);
		if (Prototype.Browser.IE) {
			var t = Element._attributeTranslations.read;
			if (t.values[name])
				return t.values[name](element, name);
			if (t.names[name])
				name = t.names[name];
			if (name.include(':')) {
				return (!element.attributes || !element.attributes[name]) ? null :
				element.attributes[name].value;
			}
		}
		return element.getAttribute(name);
	},
	
	writeAttribute : function (element, name, value) {
		element = $(element);
		var attributes = {},
		t = Element._attributeTranslations.write;
		
		if (typeof name == 'object')
			attributes = name;
		else
			attributes[name] = Object.isUndefined(value) ? true : value;
		
		for (var attr in attributes) {
			name = t.names[attr] || attr;
			value = attributes[attr];
			if (t.values[attr])
				name = t.values[attr](element, value);
			if (value === false || value === null)
				element.removeAttribute(name);
			else if (value === true)
				element.setAttribute(name, name);
			else
				element.setAttribute(name, value);
		}
		return element;
	},
	
	getHeight : function (element) {
		return Element.getDimensions(element).height;
	},
	
	getWidth : function (element) {
		return Element.getDimensions(element).width;
	},
	
	classNames : function (element) {
		return new Element.ClassNames(element);
	},
	
	hasClassName : function (element, className) {
		if (!(element = $(element)))
			return;
		var elementClassName = element.className;
		return (elementClassName.length > 0 && (elementClassName == className ||
				new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
	},
	
	addClassName : function (element, className) {
		if (!(element = $(element)))
			return;
		if (!Element.hasClassName(element, className))
			element.className += (element.className ? ' ' : '') + className;
		return element;
	},
	
	removeClassName : function (element, className) {
		if (!(element = $(element)))
			return;
		element.className = element.className.replace(
				new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
		return element;
	},
	
	toggleClassName : function (element, className) {
		if (!(element = $(element)))
			return;
		return Element[Element.hasClassName(element, className) ?
			'removeClassName' : 'addClassName'](element, className);
	},
	
	cleanWhitespace : function (element) {
		element = $(element);
		var node = element.firstChild;
		while (node) {
			var nextNode = node.nextSibling;
			if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
				element.removeChild(node);
			node = nextNode;
		}
		return element;
	},
	
	empty : function (element) {
		return $(element).innerHTML.blank();
	},
	
	descendantOf : function (element, ancestor) {
		element = $(element),
		ancestor = $(ancestor);
		
		if (element.compareDocumentPosition)
			return (element.compareDocumentPosition(ancestor) & 8) === 8;
		
		if (ancestor.contains)
			return ancestor.contains(element) && ancestor !== element;
		while (element = element.parentNode)
			if (element == ancestor)
				return true;
		
		return false;
	},
	
	scrollTo : function (element) {
		element = $(element);
		var pos = Element.cumulativeOffset(element);
		window.scrollTo(pos[0], pos[1]);
		return element;
	},
	
	getStyle : function (element, style) {
		element = $(element);
		style = style == 'float' ? 'cssFloat' : style.camelize();
		var value = element.style[style];
		if (!value || value == 'auto') {
			var css = document.defaultView.getComputedStyle(element, null);
			value = css ? css[style] : null;
		}
		if (style == 'opacity')
			return value ? parseFloat(value) : 1.0;
		return value == 'auto' ? null : value;
	},
	
	getOpacity : function (element) {
		return $(element).getStyle('opacity');
	},
	
	setStyle : function (element, styles) {
		element = $(element);
		var elementStyle = element.style,
		match;
		if (Object.isString(styles)) {
			element.style.cssText += ';' + styles;
			return styles.include('opacity') ?
			element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
		}
		for (var property in styles)
			if (property == 'opacity')
				element.setOpacity(styles[property]);
			else
				elementStyle[(property == 'float' || property == 'cssFloat') ?
					(Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
					property] = styles[property];
		
		return element;
	},
	
	setOpacity : function (element, value) {
		element = $(element);
		element.style.opacity = (value == 1 || value === '') ? '' :
		(value < 0.00001) ? 0 : value;
		return element;
	},
	
	makePositioned : function (element) {
		element = $(element);
		var pos = Element.getStyle(element, 'position');
		if (pos == 'static' || !pos) {
			element._madePositioned = true;
			element.style.position = 'relative';
			if (Prototype.Browser.Opera) {
				element.style.top = 0;
				element.style.left = 0;
			}
		}
		return element;
	},
	
	undoPositioned : function (element) {
		element = $(element);
		if (element._madePositioned) {
			element._madePositioned = undefined;
			element.style.position =
				element.style.top =
				element.style.left =
				element.style.bottom =
				element.style.right = '';
		}
		return element;
	},
	
	makeClipping : function (element) {
		element = $(element);
		if (element._overflow)
			return element;
		element._overflow = Element.getStyle(element, 'overflow') || 'auto';
		if (element._overflow !== 'hidden')
			element.style.overflow = 'hidden';
		return element;
	},
	
	undoClipping : function (element) {
		element = $(element);
		if (!element._overflow)
			return element;
		element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
		element._overflow = null;
		return element;
	},
	
	clonePosition : function (element, source) {
		var options = Object.extend({
					setLeft : true,
					setTop : true,
					setWidth : true,
					setHeight : true,
					offsetTop : 0,
					offsetLeft : 0
				}, arguments[2] || {});
		
		source = $(source);
		var p = Element.viewportOffset(source),
		delta = [0, 0],
		parent = null;
		
		element = $(element);
		
		if (Element.getStyle(element, 'position') == 'absolute') {
			parent = Element.getOffsetParent(element);
			delta = Element.viewportOffset(parent);
		}
		
		if (parent == document.body) {
			delta[0] -= document.body.offsetLeft;
			delta[1] -= document.body.offsetTop;
		}
		
		if (options.setLeft)
			element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
		if (options.setTop)
			element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
		if (options.setWidth)
			element.style.width = source.offsetWidth + 'px';
		if (options.setHeight)
			element.style.height = source.offsetHeight + 'px';
		return element;
	}
};

Object.extend(Element.Methods, {
		getElementsBySelector : Element.Methods.select,
		
		childElements : Element.Methods.immediateDescendants
	});

Element._attributeTranslations = {
	write : {
		names : {
			className : 'class',
			htmlFor : 'for'
		},
		values : {}
	}
};

if (Prototype.Browser.Opera) {
	Element.Methods.getStyle = Element.Methods.getStyle.wrap(
			function (proceed, element, style) {
				switch (style) {
				case 'height':
				case 'width':
					if (!Element.visible(element))
						return null;
					
					var dim = parseInt(proceed(element, style), 10);
					
					if (dim !== element['offset' + style.capitalize()])
						return dim + 'px';
					
					var properties;
					if (style === 'height') {
						properties = ['border-top-width', 'padding-top',
							'padding-bottom', 'border-bottom-width'];
					} else {
						properties = ['border-left-width', 'padding-left',
							'padding-right', 'border-right-width'];
					}
					return properties.inject(dim, function (memo, property) {
							var val = proceed(element, property);
							return val === null ? memo : memo - parseInt(val, 10);
						}) + 'px';
				default:
					return proceed(element, style);
				}
			});
	
	Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
			function (proceed, element, attribute) {
				if (attribute === 'title')
					return element.title;
				return proceed(element, attribute);
			});
} else if (Prototype.Browser.IE) {
	Element.Methods.getStyle = function (element, style) {
		element = $(element);
		style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
		var value = element.style[style];
		if (!value && element.currentStyle)
			value = element.currentStyle[style];
		
		if (style == 'opacity') {
			if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
				if (value[1])
					return parseFloat(value[1]) / 100;
			return 1.0;
		}
		
		if (value == 'auto') {
			if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
				return element['offset' + style.capitalize()] + 'px';
			return null;
		}
		return value;
	};
	
	Element.Methods.setOpacity = function (element, value) {
		function stripAlpha(filter) {
			return filter.replace(/alpha\([^\)]*\)/gi, '');
		}
		element = $(element);
		var currentStyle = element.currentStyle;
		if ((currentStyle && !currentStyle.hasLayout) ||
			(!currentStyle && element.style.zoom == 'normal'))
			element.style.zoom = 1;
		
		var filter = element.getStyle('filter'),
		style = element.style;
		if (value == 1 || value === '') {
			(filter = stripAlpha(filter)) ?
			style.filter = filter : style.removeAttribute('filter');
			return element;
		} else if (value < 0.00001)
			value = 0;
		style.filter = stripAlpha(filter) +
			'alpha(opacity=' + (value * 100) + ')';
		return element;
	};
	
	Element._attributeTranslations = (function () {
			
			var classProp = 'className',
			forProp = 'for',
			el = document.createElement('div');
			
			el.setAttribute(classProp, 'x');
			
			if (el.className !== 'x') {
				el.setAttribute('class', 'x');
				if (el.className === 'x') {
					classProp = 'class';
				}
			}
			el = null;
			
			el = document.createElement('label');
			el.setAttribute(forProp, 'x');
			if (el.htmlFor !== 'x') {
				el.setAttribute('htmlFor', 'x');
				if (el.htmlFor === 'x') {
					forProp = 'htmlFor';
				}
			}
			el = null;
			
			return {
				read : {
					names : {
						'class' : classProp,
						'className' : classProp,
						'for' : forProp,
						'htmlFor' : forProp
					},
					values : {
						_getAttr : function (element, attribute) {
							return element.getAttribute(attribute);
						},
						_getAttr2 : function (element, attribute) {
							return element.getAttribute(attribute, 2);
						},
						_getAttrNode : function (element, attribute) {
							var node = element.getAttributeNode(attribute);
							return node ? node.value : "";
						},
						_getEv : (function () {
								
								var el = document.createElement('div'),
								f;
								el.onclick = Prototype.emptyFunction;
								var value = el.getAttribute('onclick');
								
								if (String(value).indexOf('{') > -1) {
									f = function (element, attribute) {
										attribute = element.getAttribute(attribute);
										if (!attribute)
											return null;
										attribute = attribute.toString();
										attribute = attribute.split('{')[1];
										attribute = attribute.split('}')[0];
										return attribute.strip();
									};
								} else if (value === '') {
									f = function (element, attribute) {
										attribute = element.getAttribute(attribute);
										if (!attribute)
											return null;
										return attribute.strip();
									};
								}
								el = null;
								return f;
							})(),
						_flag : function (element, attribute) {
							return $(element).hasAttribute(attribute) ? attribute : null;
						},
						style : function (element) {
							return element.style.cssText.toLowerCase();
						},
						title : function (element) {
							return element.title;
						}
					}
				}
			}
		})();
	
	Element._attributeTranslations.write = {
		names : Object.extend({
				cellpadding : 'cellPadding',
				cellspacing : 'cellSpacing'
			}, Element._attributeTranslations.read.names),
		values : {
			checked : function (element, value) {
				element.checked = !!value;
			},
			
			style : function (element, value) {
				element.style.cssText = value ? value : '';
			}
		}
	};
	
	Element._attributeTranslations.has = {};
	
	$w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
		'encType maxLength readOnly longDesc frameBorder').each(function (attr) {
			Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
			Element._attributeTranslations.has[attr.toLowerCase()] = attr;
		});
	
	(function (v) {
			Object.extend(v, {
					href : v._getAttr2,
					src : v._getAttr2,
					type : v._getAttr,
					action : v._getAttrNode,
					disabled : v._flag,
					checked : v._flag,
					readonly : v._flag,
					multiple : v._flag,
					onload : v._getEv,
					onunload : v._getEv,
					onclick : v._getEv,
					ondblclick : v._getEv,
					onmousedown : v._getEv,
					onmouseup : v._getEv,
					onmouseover : v._getEv,
					onmousemove : v._getEv,
					onmouseout : v._getEv,
					onfocus : v._getEv,
					onblur : v._getEv,
					onkeypress : v._getEv,
					onkeydown : v._getEv,
					onkeyup : v._getEv,
					onsubmit : v._getEv,
					onreset : v._getEv,
					onselect : v._getEv,
					onchange : v._getEv
				});
		})(Element._attributeTranslations.read.values);
	
	if (Prototype.BrowserFeatures.ElementExtensions) {
		(function () {
				function _descendants(element) {
					var nodes = element.getElementsByTagName('*'),
					results = [];
					for (var i = 0, node; node = nodes[i]; i++)
						if (node.tagName !== "!") // Filter out comment nodes.
							results.push(node);
					return results;
				}
				
				Element.Methods.down = function (element, expression, index) {
					element = $(element);
					if (arguments.length == 1)
						return element.firstDescendant();
					return Object.isNumber(expression) ? _descendants(element)[expression] :
					Element.select(element, expression)[index || 0];
				}
			})();
	}
	
} else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
	Element.Methods.setOpacity = function (element, value) {
		element = $(element);
		element.style.opacity = (value == 1) ? 0.999999 :
		(value === '') ? '' : (value < 0.00001) ? 0 : value;
		return element;
	};
} else if (Prototype.Browser.WebKit) {
	Element.Methods.setOpacity = function (element, value) {
		element = $(element);
		element.style.opacity = (value == 1 || value === '') ? '' :
		(value < 0.00001) ? 0 : value;
		
		if (value == 1)
			if (element.tagName.toUpperCase() == 'IMG' && element.width) {
				element.width++;
				element.width--;
			} else
				try {
					var n = document.createTextNode(' ');
					element.appendChild(n);
					element.removeChild(n);
				} catch (e) {}
		
		return element;
	};
}

if ('outerHTML' in document.documentElement) {
	Element.Methods.replace = function (element, content) {
		element = $(element);
		
		if (content && content.toElement)
			content = content.toElement();
		if (Object.isElement(content)) {
			element.parentNode.replaceChild(content, element);
			return element;
		}
		
		content = Object.toHTML(content);
		var parent = element.parentNode,
		tagName = parent.tagName.toUpperCase();
		
		if (Element._insertionTranslations.tags[tagName]) {
			var nextSibling = element.next(),
			fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
			parent.removeChild(element);
			if (nextSibling)
				fragments.each(function (node) {
						parent.insertBefore(node, nextSibling)
					});
			else
				fragments.each(function (node) {
						parent.appendChild(node)
					});
		} else
			element.outerHTML = content.stripScripts();
		
		content.evalScripts.bind(content).defer();
		return element;
	};
}

Element._returnOffset = function (l, t) {
	var result = [l, t];
	result.left = l;
	result.top = t;
	return result;
};

Element._getContentFromAnonymousElement = function (tagName, html, force) {
	var div = new Element('div'),
	t = Element._insertionTranslations.tags[tagName];
	
	var workaround = false;
	if (t)
		workaround = true;
	else if (force) {
		workaround = true;
		t = ['', '', 0];
	}
	
	if (workaround) {
		div.innerHTML = '&nbsp;' + t[0] + html + t[1];
		div.removeChild(div.firstChild);
		for (var i = t[2]; i--; ) {
			div = div.firstChild;
		}
	} else {
		div.innerHTML = html;
	}
	return $A(div.childNodes);
};

Element._insertionTranslations = {
	before : function (element, node) {
		element.parentNode.insertBefore(node, element);
	},
	top : function (element, node) {
		element.insertBefore(node, element.firstChild);
	},
	bottom : function (element, node) {
		element.appendChild(node);
	},
	after : function (element, node) {
		element.parentNode.insertBefore(node, element.nextSibling);
	},
	tags : {
		TABLE : ['<table>', '</table>', 1],
		TBODY : ['<table><tbody>', '</tbody></table>', 2],
		TR : ['<table><tbody><tr>', '</tr></tbody></table>', 3],
		TD : ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
		SELECT : ['<select>', '</select>', 1]
	}
};

(function () {
		var tags = Element._insertionTranslations.tags;
		Object.extend(tags, {
				THEAD : tags.TBODY,
				TFOOT : tags.TBODY,
				TH : tags.TD
			});
	})();

Element.Methods.Simulated = {
	hasAttribute : function (element, attribute) {
		attribute = Element._attributeTranslations.has[attribute] || attribute;
		var node = $(element).getAttributeNode(attribute);
		return !!(node && node.specified);
	}
};

Element.Methods.ByTag = {};

Object.extend(Element, Element.Methods);

(function (div) {
		
		if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) {
			window.HTMLElement = {};
			window.HTMLElement.prototype = div['__proto__'];
			Prototype.BrowserFeatures.ElementExtensions = true;
		}
		
		div = null;
		
	})(document.createElement('div'));

Element.extend = (function () {
		
		function checkDeficiency(tagName) {
			if (typeof window.Element != 'undefined') {
				var proto = window.Element.prototype;
				if (proto) {
					var id = '_' + (Math.random() + '').slice(2),
					el = document.createElement(tagName);
					proto[id] = 'x';
					var isBuggy = (el[id] !== 'x');
					delete proto[id];
					el = null;
					return isBuggy;
				}
			}
			return false;
		}
		
		function extendElementWith(element, methods) {
			for (var property in methods) {
				var value = methods[property];
				if (Object.isFunction(value) && !(property in element))
					element[property] = value.methodize();
			}
		}
		
		var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object');
		
		if (Prototype.BrowserFeatures.SpecificElementExtensions) {
			if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) {
				return function (element) {
					if (element && typeof element._extendedByPrototype == 'undefined') {
						var t = element.tagName;
						if (t && (/^(?:object|applet|embed)$/i.test(t))) {
							extendElementWith(element, Element.Methods);
							extendElementWith(element, Element.Methods.Simulated);
							extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
						}
					}
					return element;
				}
			}
			return Prototype.K;
		}
		
		var Methods = {},
		ByTag = Element.Methods.ByTag;
		
		var extend = Object.extend(function (element) {
					if (!element || typeof element._extendedByPrototype != 'undefined' ||
						element.nodeType != 1 || element == window)
						return element;
					
					var methods = Object.clone(Methods),
					tagName = element.tagName.toUpperCase();
					
					if (ByTag[tagName])
						Object.extend(methods, ByTag[tagName]);
					
					extendElementWith(element, methods);
					
					element._extendedByPrototype = Prototype.emptyFunction;
					return element;
					
				}, {
					refresh : function () {
						if (!Prototype.BrowserFeatures.ElementExtensions) {
							Object.extend(Methods, Element.Methods);
							Object.extend(Methods, Element.Methods.Simulated);
						}
					}
				});
		
		extend.refresh();
		return extend;
	})();

if (document.documentElement.hasAttribute) {
	Element.hasAttribute = function (element, attribute) {
		return element.hasAttribute(attribute);
	};
} else {
	Element.hasAttribute = Element.Methods.Simulated.hasAttribute;
}

Element.addMethods = function (methods) {
	var F = Prototype.BrowserFeatures,
	T = Element.Methods.ByTag;
	
	if (!methods) {
		Object.extend(Form, Form.Methods);
		Object.extend(Form.Element, Form.Element.Methods);
		Object.extend(Element.Methods.ByTag, {
				"FORM" : Object.clone(Form.Methods),
				"INPUT" : Object.clone(Form.Element.Methods),
				"SELECT" : Object.clone(Form.Element.Methods),
				"TEXTAREA" : Object.clone(Form.Element.Methods),
				"BUTTON" : Object.clone(Form.Element.Methods)
			});
	}
	
	if (arguments.length == 2) {
		var tagName = methods;
		methods = arguments[1];
	}
	
	if (!tagName)
		Object.extend(Element.Methods, methods || {});
	else {
		if (Object.isArray(tagName))
			tagName.each(extend);
		else
			extend(tagName);
	}
	
	function extend(tagName) {
		tagName = tagName.toUpperCase();
		if (!Element.Methods.ByTag[tagName])
			Element.Methods.ByTag[tagName] = {};
		Object.extend(Element.Methods.ByTag[tagName], methods);
	}
	
	function copy(methods, destination, onlyIfAbsent) {
		onlyIfAbsent = onlyIfAbsent || false;
		for (var property in methods) {
			var value = methods[property];
			if (!Object.isFunction(value))
				continue;
			if (!onlyIfAbsent || !(property in destination))
				destination[property] = value.methodize();
		}
	}
	
	function findDOMClass(tagName) {
		var klass;
		var trans = {
			"OPTGROUP" : "OptGroup",
			"TEXTAREA" : "TextArea",
			"P" : "Paragraph",
			"FIELDSET" : "FieldSet",
			"UL" : "UList",
			"OL" : "OList",
			"DL" : "DList",
			"DIR" : "Directory",
			"H1" : "Heading",
			"H2" : "Heading",
			"H3" : "Heading",
			"H4" : "Heading",
			"H5" : "Heading",
			"H6" : "Heading",
			"Q" : "Quote",
			"INS" : "Mod",
			"DEL" : "Mod",
			"A" : "Anchor",
			"IMG" : "Image",
			"CAPTION" :
			"TableCaption",
			"COL" : "TableCol",
			"COLGROUP" : "TableCol",
			"THEAD" :
			"TableSection",
			"TFOOT" : "TableSection",
			"TBODY" : "TableSection",
			"TR" :
			"TableRow",
			"TH" : "TableCell",
			"TD" : "TableCell",
			"FRAMESET" :
			"FrameSet",
			"IFRAME" : "IFrame"
		};
		if (trans[tagName])
			klass = 'HTML' + trans[tagName] + 'Element';
		if (window[klass])
			return window[klass];
		klass = 'HTML' + tagName + 'Element';
		if (window[klass])
			return window[klass];
		klass = 'HTML' + tagName.capitalize() + 'Element';
		if (window[klass])
			return window[klass];
		
		var element = document.createElement(tagName),
		proto = element['__proto__'] || element.constructor.prototype;
		
		element = null;
		return proto;
	}
	
	var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
		Element.prototype;
	
	if (F.ElementExtensions) {
		copy(Element.Methods, elementPrototype);
		copy(Element.Methods.Simulated, elementPrototype, true);
	}
	
	if (F.SpecificElementExtensions) {
		for (var tag in Element.Methods.ByTag) {
			var klass = findDOMClass(tag);
			if (Object.isUndefined(klass))
				continue;
			copy(T[tag], klass.prototype);
		}
	}
	
	Object.extend(Element, Element.Methods);
	delete Element.ByTag;
	
	if (Element.extend.refresh)
		Element.extend.refresh();
	Element.cache = {};
};

document.viewport = {
	
	getDimensions : function () {
		return {
			width : this.getWidth(),
			height : this.getHeight()
		};
	},
	
	getScrollOffsets : function () {
		return Element._returnOffset(
			window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
			window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
	}
};

(function (viewport) {
		var B = Prototype.Browser,
		doc = document,
		element,
		property = {};
		
		function getRootElement() {
			if (B.WebKit && !doc.evaluate)
				return document;
			
			if (B.Opera && window.parseFloat(window.opera.version()) < 9.5)
				return document.body;
			
			return document.documentElement;
		}
		
		function define(D) {
			if (!element)
				element = getRootElement();
			
			property[D] = 'client' + D;
			
			viewport['get' + D] = function () {
				return element[property[D]]
			};
			return viewport['get' + D]();
		}
		
		viewport.getWidth = define.curry('Width');
		
		viewport.getHeight = define.curry('Height');
	})(document.viewport);

Element.Storage = {
	UID : 1
};

Element.addMethods({
		getStorage : function (element) {
			if (!(element = $(element)))
				return;
			
			var uid;
			if (element === window) {
				uid = 0;
			} else {
				if (typeof element._prototypeUID === "undefined")
					element._prototypeUID = Element.Storage.UID++;
				uid = element._prototypeUID;
			}
			
			if (!Element.Storage[uid])
				Element.Storage[uid] = $H();
			
			return Element.Storage[uid];
		},
		
		store : function (element, key, value) {
			if (!(element = $(element)))
				return;
			
			if (arguments.length === 2) {
				Element.getStorage(element).update(key);
			} else {
				Element.getStorage(element).set(key, value);
			}
			
			return element;
		},
		
		retrieve : function (element, key, defaultValue) {
			if (!(element = $(element)))
				return;
			var hash = Element.getStorage(element),
			value = hash.get(key);
			
			if (Object.isUndefined(value)) {
				hash.set(key, defaultValue);
				value = defaultValue;
			}
			
			return value;
		},
		
		clone : function (element, deep) {
			if (!(element = $(element)))
				return;
			var clone = element.cloneNode(deep);
			clone._prototypeUID = void 0;
			if (deep) {
				var descendants = Element.select(clone, '*'),
				i = descendants.length;
				while (i--) {
					descendants[i]._prototypeUID = void 0;
				}
			}
			return Element.extend(clone);
		},
		
		purge : function (element) {
			if (!(element = $(element)))
				return;
			var purgeElement = Element._purgeElement;
			
			purgeElement(element);
			
			var descendants = element.getElementsByTagName('*'),
			i = descendants.length;
			while (i--)
				purgeElement(descendants[i]);
			
			return null;
		}
	});

(function () {
		
		function toDecimal(pctString) {
			var match = pctString.match(/^(\d+)%?$/i);
			if (!match)
				return null;
			return (Number(match[1]) / 100);
		}
		
		function getPixelValue(value, property, context) {
			var element = null;
			if (Object.isElement(value)) {
				element = value;
				value = element.getStyle(property);
			}
			
			if (value === null) {
				return null;
			}
			
			if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
				return window.parseFloat(value);
			}
			
			var isPercentage = value.include('%'),
			isViewport = (context === document.viewport);
			
			if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
				var style = element.style.left,
				rStyle = element.runtimeStyle.left;
				element.runtimeStyle.left = element.currentStyle.left;
				element.style.left = value || 0;
				value = element.style.pixelLeft;
				element.style.left = style;
				element.runtimeStyle.left = rStyle;
				
				return value;
			}
			
			if (element && isPercentage) {
				context = context || element.parentNode;
				var decimal = toDecimal(value);
				var whole = null;
				var position = element.getStyle('position');
				
				var isHorizontal = property.include('left') || property.include('right') ||
					property.include('width');
				
				var isVertical = property.include('top') || property.include('bottom') ||
					property.include('height');
				
				if (context === document.viewport) {
					if (isHorizontal) {
						whole = document.viewport.getWidth();
					} else if (isVertical) {
						whole = document.viewport.getHeight();
					}
				} else {
					if (isHorizontal) {
						whole = $(context).measure('width');
					} else if (isVertical) {
						whole = $(context).measure('height');
					}
				}
				
				return (whole === null) ? 0 : whole * decimal;
			}
			
			return 0;
		}
		
		function toCSSPixels(number) {
			if (Object.isString(number) && number.endsWith('px')) {
				return number;
			}
			return number + 'px';
		}
		
		function isDisplayed(element) {
			var originalElement = element;
			while (element && element.parentNode) {
				var display = element.getStyle('display');
				if (display === 'none') {
					return false;
				}
				element = $(element.parentNode);
			}
			return true;
		}
		
		var hasLayout = Prototype.K;
		if ('currentStyle' in document.documentElement) {
			hasLayout = function (element) {
				if (!element.currentStyle.hasLayout) {
					element.style.zoom = 1;
				}
				return element;
			};
		}
		
		function cssNameFor(key) {
			if (key.include('border'))
				key = key + '-width';
			return key.camelize();
		}
		
		Element.Layout = Class.create(Hash, {
					initialize : function ($super, element, preCompute) {
						$super();
						this.element = $(element);
						
						Element.Layout.PROPERTIES.each(function (property) {
								this._set(property, null);
							}, this);
						
						if (preCompute) {
							this._preComputing = true;
							this._begin();
							Element.Layout.PROPERTIES.each(this._compute, this);
							this._end();
							this._preComputing = false;
						}
					},
					
					_set : function (property, value) {
						return Hash.prototype.set.call(this, property, value);
					},
					
					set : function (property, value) {
						throw "Properties of Element.Layout are read-only.";
					},
					
					get : function ($super, property) {
						var value = $super(property);
						return value === null ? this._compute(property) : value;
					},
					
					_begin : function () {
						if (this._prepared)
							return;
						
						var element = this.element;
						if (isDisplayed(element)) {
							this._prepared = true;
							return;
						}
						
						var originalStyles = {
							position : element.style.position || '',
							width : element.style.width || '',
							visibility : element.style.visibility || '',
							display : element.style.display || ''
						};
						
						element.store('prototype_original_styles', originalStyles);
						
						var position = element.getStyle('position'),
						width = element.getStyle('width');
						
						if (width === "0px" || width === null) {
							element.style.display = 'block';
							width = element.getStyle('width');
						}
						
						var context = (position === 'fixed') ? document.viewport :
						element.parentNode;
						
						element.setStyle({
								position : 'absolute',
								visibility : 'hidden',
								display : 'block'
							});
						
						var positionedWidth = element.getStyle('width');
						
						var newWidth;
						if (width && (positionedWidth === width)) {
							newWidth = getPixelValue(element, 'width', context);
						} else if (position === 'absolute' || position === 'fixed') {
							newWidth = getPixelValue(element, 'width', context);
						} else {
							var parent = element.parentNode,
							pLayout = $(parent).getLayout();
							
							newWidth = pLayout.get('width') -
								this.get('margin-left') -
								this.get('border-left') -
								this.get('padding-left') -
								this.get('padding-right') -
								this.get('border-right') -
								this.get('margin-right');
						}
						
						element.setStyle({
								width : newWidth + 'px'
							});
						
						this._prepared = true;
					},
					
					_end : function () {
						var element = this.element;
						var originalStyles = element.retrieve('prototype_original_styles');
						element.store('prototype_original_styles', null);
						element.setStyle(originalStyles);
						this._prepared = false;
					},
					
					_compute : function (property) {
						var COMPUTATIONS = Element.Layout.COMPUTATIONS;
						if (!(property in COMPUTATIONS)) {
							throw "Property not found.";
						}
						
						return this._set(property, COMPUTATIONS[property].call(this, this.element));
					},
					
					toObject : function () {
						var args = $A(arguments);
						var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
						args.join(' ').split(' ');
						var obj = {};
						keys.each(function (key) {
								if (!Element.Layout.PROPERTIES.include(key))
									return;
								var value = this.get(key);
								if (value != null)
									obj[key] = value;
							}, this);
						return obj;
					},
					
					toHash : function () {
						var obj = this.toObject.apply(this, arguments);
						return new Hash(obj);
					},
					
					toCSS : function () {
						var args = $A(arguments);
						var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
						args.join(' ').split(' ');
						var css = {};
						
						keys.each(function (key) {
								if (!Element.Layout.PROPERTIES.include(key))
									return;
								if (Element.Layout.COMPOSITE_PROPERTIES.include(key))
									return;
								
								var value = this.get(key);
								if (value != null)
									css[cssNameFor(key)] = value + 'px';
							}, this);
						return css;
					},
					
					inspect : function () {
						return "#<Element.Layout>";
					}
				});
		
		Object.extend(Element.Layout, {
				PROPERTIES : $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'),
				
				COMPOSITE_PROPERTIES : $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
				
				COMPUTATIONS : {
					'height' : function (element) {
						if (!this._preComputing)
							this._begin();
						
						var bHeight = this.get('border-box-height');
						if (bHeight <= 0) {
							if (!this._preComputing)
								this._end();
							return 0;
						}
						
						var bTop = this.get('border-top'),
						bBottom = this.get('border-bottom');
						
						var pTop = this.get('padding-top'),
						pBottom = this.get('padding-bottom');
						
						if (!this._preComputing)
							this._end();
						
						return bHeight - bTop - bBottom - pTop - pBottom;
					},
					
					'width' : function (element) {
						if (!this._preComputing)
							this._begin();
						
						var bWidth = this.get('border-box-width');
						if (bWidth <= 0) {
							if (!this._preComputing)
								this._end();
							return 0;
						}
						
						var bLeft = this.get('border-left'),
						bRight = this.get('border-right');
						
						var pLeft = this.get('padding-left'),
						pRight = this.get('padding-right');
						
						if (!this._preComputing)
							this._end();
						
						return bWidth - bLeft - bRight - pLeft - pRight;
					},
					
					'padding-box-height' : function (element) {
						var height = this.get('height'),
						pTop = this.get('padding-top'),
						pBottom = this.get('padding-bottom');
						
						return height + pTop + pBottom;
					},
					
					'padding-box-width' : function (element) {
						var width = this.get('width'),
						pLeft = this.get('padding-left'),
						pRight = this.get('padding-right');
						
						return width + pLeft + pRight;
					},
					
					'border-box-height' : function (element) {
						if (!this._preComputing)
							this._begin();
						var height = element.offsetHeight;
						if (!this._preComputing)
							this._end();
						return height;
					},
					
					'border-box-width' : function (element) {
						if (!this._preComputing)
							this._begin();
						var width = element.offsetWidth;
						if (!this._preComputing)
							this._end();
						return width;
					},
					
					'margin-box-height' : function (element) {
						var bHeight = this.get('border-box-height'),
						mTop = this.get('margin-top'),
						mBottom = this.get('margin-bottom');
						
						if (bHeight <= 0)
							return 0;
						
						return bHeight + mTop + mBottom;
					},
					
					'margin-box-width' : function (element) {
						var bWidth = this.get('border-box-width'),
						mLeft = this.get('margin-left'),
						mRight = this.get('margin-right');
						
						if (bWidth <= 0)
							return 0;
						
						return bWidth + mLeft + mRight;
					},
					
					'top' : function (element) {
						var offset = element.positionedOffset();
						return offset.top;
					},
					
					'bottom' : function (element) {
						var offset = element.positionedOffset(),
						parent = element.getOffsetParent(),
						pHeight = parent.measure('height');
						
						var mHeight = this.get('border-box-height');
						
						return pHeight - mHeight - offset.top;
					},
					
					'left' : function (element) {
						var offset = element.positionedOffset();
						return offset.left;
					},
					
					'right' : function (element) {
						var offset = element.positionedOffset(),
						parent = element.getOffsetParent(),
						pWidth = parent.measure('width');
						
						var mWidth = this.get('border-box-width');
						
						return pWidth - mWidth - offset.left;
					},
					
					'padding-top' : function (element) {
						return getPixelValue(element, 'paddingTop');
					},
					
					'padding-bottom' : function (element) {
						return getPixelValue(element, 'paddingBottom');
					},
					
					'padding-left' : function (element) {
						return getPixelValue(element, 'paddingLeft');
					},
					
					'padding-right' : function (element) {
						return getPixelValue(element, 'paddingRight');
					},
					
					'border-top' : function (element) {
						return getPixelValue(element, 'borderTopWidth');
					},
					
					'border-bottom' : function (element) {
						return getPixelValue(element, 'borderBottomWidth');
					},
					
					'border-left' : function (element) {
						return getPixelValue(element, 'borderLeftWidth');
					},
					
					'border-right' : function (element) {
						return getPixelValue(element, 'borderRightWidth');
					},
					
					'margin-top' : function (element) {
						return getPixelValue(element, 'marginTop');
					},
					
					'margin-bottom' : function (element) {
						return getPixelValue(element, 'marginBottom');
					},
					
					'margin-left' : function (element) {
						return getPixelValue(element, 'marginLeft');
					},
					
					'margin-right' : function (element) {
						return getPixelValue(element, 'marginRight');
					}
				}
			});
		
		if ('getBoundingClientRect' in document.documentElement) {
			Object.extend(Element.Layout.COMPUTATIONS, {
					'right' : function (element) {
						var parent = hasLayout(element.getOffsetParent());
						var rect = element.getBoundingClientRect(),
						pRect = parent.getBoundingClientRect();
						
						return (pRect.right - rect.right).round();
					},
					
					'bottom' : function (element) {
						var parent = hasLayout(element.getOffsetParent());
						var rect = element.getBoundingClientRect(),
						pRect = parent.getBoundingClientRect();
						
						return (pRect.bottom - rect.bottom).round();
					}
				});
		}
		
		Element.Offset = Class.create({
					initialize : function (left, top) {
						this.left = left.round();
						this.top = top.round();
						
						this[0] = this.left;
						this[1] = this.top;
					},
					
					relativeTo : function (offset) {
						return new Element.Offset(
							this.left - offset.left,
							this.top - offset.top);
					},
					
					inspect : function () {
						return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
					},
					
					toString : function () {
						return "[#{left}, #{top}]".interpolate(this);
					},
					
					toArray : function () {
						return [this.left, this.top];
					}
				});
		
		function getLayout(element, preCompute) {
			return new Element.Layout(element, preCompute);
		}
		
		function measure(element, property) {
			return $(element).getLayout().get(property);
		}
		
		function getDimensions(element) {
			element = $(element);
			var display = Element.getStyle(element, 'display');
			
			if (display && display !== 'none') {
				return {
					width : element.offsetWidth,
					height : element.offsetHeight
				};
			}
			
			var style = element.style;
			var originalStyles = {
				visibility : style.visibility,
				position : style.position,
				display : style.display
			};
			
			var newStyles = {
				visibility : 'hidden',
				display : 'block'
			};
			
			if (originalStyles.position !== 'fixed')
				newStyles.position = 'absolute';
			
			Element.setStyle(element, newStyles);
			
			var dimensions = {
				width : element.offsetWidth,
				height : element.offsetHeight
			};
			
			Element.setStyle(element, originalStyles);
			
			return dimensions;
		}
		
		function getOffsetParent(element) {
			element = $(element);
			
			if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
				return $(document.body);
			
			var isInline = (Element.getStyle(element, 'display') === 'inline');
			if (!isInline && element.offsetParent)
				return $(element.offsetParent);
			while ((element = element.parentNode) && element !== document.body) {
				if (Element.getStyle(element, 'position') !== 'static') {
					return isHtml(element) ? $(document.body) : $(element);
				}
			}
			
			return $(document.body);
		}
		
		function cumulativeOffset(element) {
			element = $(element);
			var valueT = 0,
			valueL = 0;
			if (element.parentNode) {
				do {
					valueT += element.offsetTop || 0;
					valueL += element.offsetLeft || 0;
					element = element.offsetParent;
				} while (element);
			}
			return new Element.Offset(valueL, valueT);
		}
		
		function positionedOffset(element) {
			element = $(element);
			
			var layout = element.getLayout();
			
			var valueT = 0,
			valueL = 0;
			do {
				valueT += element.offsetTop || 0;
				valueL += element.offsetLeft || 0;
				element = element.offsetParent;
				if (element) {
					if (isBody(element))
						break;
					var p = Element.getStyle(element, 'position');
					if (p !== 'static')
						break;
				}
			} while (element);
			
			valueL -= layout.get('margin-top');
			valueT -= layout.get('margin-left');
			
			return new Element.Offset(valueL, valueT);
		}
		
		function cumulativeScrollOffset(element) {
			var valueT = 0,
			valueL = 0;
			do {
				valueT += element.scrollTop || 0;
				valueL += element.scrollLeft || 0;
				element = element.parentNode;
			} while (element);
			return new Element.Offset(valueL, valueT);
		}
		
		function viewportOffset(forElement) {
			element = $(element);
			var valueT = 0,
			valueL = 0,
			docBody = document.body;
			
			var element = forElement;
			do {
				valueT += element.offsetTop || 0;
				valueL += element.offsetLeft || 0;
				if (element.offsetParent == docBody &&
					Element.getStyle(element, 'position') == 'absolute')
					break;
			} while (element = element.offsetParent);
			
			element = forElement;
			do {
				if (element != docBody) {
					valueT -= element.scrollTop || 0;
					valueL -= element.scrollLeft || 0;
				}
			} while (element = element.parentNode);
			return new Element.Offset(valueL, valueT);
		}
		
		function absolutize(element) {
			element = $(element);
			
			if (Element.getStyle(element, 'position') === 'absolute') {
				return element;
			}
			
			var offsetParent = getOffsetParent(element);
			var eOffset = element.viewportOffset(),
			pOffset = offsetParent.viewportOffset();
			
			var offset = eOffset.relativeTo(pOffset);
			var layout = element.getLayout();
			
			element.store('prototype_absolutize_original_styles', {
					left : element.getStyle('left'),
					top : element.getStyle('top'),
					width : element.getStyle('width'),
					height : element.getStyle('height')
				});
			
			element.setStyle({
					position : 'absolute',
					top : offset.top + 'px',
					left : offset.left + 'px',
					width : layout.get('width') + 'px',
					height : layout.get('height') + 'px'
				});
			
			return element;
		}
		
		function relativize(element) {
			element = $(element);
			if (Element.getStyle(element, 'position') === 'relative') {
				return element;
			}
			
			var originalStyles =
				element.retrieve('prototype_absolutize_original_styles');
			
			if (originalStyles)
				element.setStyle(originalStyles);
			return element;
		}
		
		if (Prototype.Browser.IE) {
			getOffsetParent = getOffsetParent.wrap(
					function (proceed, element) {
						element = $(element);
						
						if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
							return $(document.body);
						
						var position = element.getStyle('position');
						if (position !== 'static')
							return proceed(element);
						
						element.setStyle({
								position : 'relative'
							});
						var value = proceed(element);
						element.setStyle({
								position : position
							});
						return value;
					});
			
			positionedOffset = positionedOffset.wrap(function (proceed, element) {
						element = $(element);
						if (!element.parentNode)
							return new Element.Offset(0, 0);
						var position = element.getStyle('position');
						if (position !== 'static')
							return proceed(element);
						
						var offsetParent = element.getOffsetParent();
						if (offsetParent && offsetParent.getStyle('position') === 'fixed')
							hasLayout(offsetParent);
						
						element.setStyle({
								position : 'relative'
							});
						var value = proceed(element);
						element.setStyle({
								position : position
							});
						return value;
					});
		} else if (Prototype.Browser.Webkit) {
			cumulativeOffset = function (element) {
				element = $(element);
				var valueT = 0,
				valueL = 0;
				do {
					valueT += element.offsetTop || 0;
					valueL += element.offsetLeft || 0;
					if (element.offsetParent == document.body)
						if (Element.getStyle(element, 'position') == 'absolute')
							break;
					
					element = element.offsetParent;
				} while (element);
				
				return new Element.Offset(valueL, valueT);
			};
		}
		
		Element.addMethods({
				getLayout : getLayout,
				measure : measure,
				getDimensions : getDimensions,
				getOffsetParent : getOffsetParent,
				cumulativeOffset : cumulativeOffset,
				positionedOffset : positionedOffset,
				cumulativeScrollOffset : cumulativeScrollOffset,
				viewportOffset : viewportOffset,
				absolutize : absolutize,
				relativize : relativize
			});
		
		function isBody(element) {
			return element.nodeName.toUpperCase() === 'BODY';
		}
		
		function isHtml(element) {
			return element.nodeName.toUpperCase() === 'HTML';
		}
		
		function isDocument(element) {
			return element.nodeType === Node.DOCUMENT_NODE;
		}
		
		function isDetached(element) {
			return element !== document.body &&
			!Element.descendantOf(element, document.body);
		}
		
		if ('getBoundingClientRect' in document.documentElement) {
			Element.addMethods({
					viewportOffset : function (element) {
						element = $(element);
						if (isDetached(element))
							return new Element.Offset(0, 0);
						
						var rect = element.getBoundingClientRect(),
						docEl = document.documentElement;
						return new Element.Offset(rect.left - docEl.clientLeft,
							rect.top - docEl.clientTop);
					}
				});
		}
	})();
window.$$ = function () {
	var expression = $A(arguments).join(', ');
	return Prototype.Selector.select(expression, document);
};

Prototype.Selector = (function () {
		
		function select() {
			throw new Error('Method "Prototype.Selector.select" must be defined.');
		}
		
		function match() {
			throw new Error('Method "Prototype.Selector.match" must be defined.');
		}
		
		function find(elements, expression, index) {
			index = index || 0;
			var match = Prototype.Selector.match,
			length = elements.length,
			matchIndex = 0,
			i;
			
			for (i = 0; i < length; i++) {
				if (match(elements[i], expression) && index == matchIndex++) {
					return Element.extend(elements[i]);
				}
			}
		}
		
		function extendElements(elements) {
			for (var i = 0, length = elements.length; i < length; i++) {
				Element.extend(elements[i]);
			}
			return elements;
		}
		
		var K = Prototype.K;
		
		return {
			select : select,
			match : match,
			find : find,
			extendElements : (Element.extend === K) ? K : extendElements,
			extendElement : Element.extend
		};
	})();
Prototype._original_property = window.Sizzle;
/*!
 * Sizzle CSS Selector Engine - v1.0
 *  Copyright 2009, The Dojo Foundation
 *  Released under the MIT, BSD, and GPL Licenses.
 *  More information: http://sizzlejs.com/
 */
(function () {
		
		var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
		done = 0,
		toString = Object.prototype.toString,
		hasDuplicate = false,
		baseHasDuplicate = true;
		
		[0, 0].sort(function () {
				baseHasDuplicate = false;
				return 0;
			});
		
		var Sizzle = function (selector, context, results, seed) {
			results = results || [];
			var origContext = context = context || document;
			
			if (context.nodeType !== 1 && context.nodeType !== 9) {
				return [];
			}
			
			if (!selector || typeof selector !== "string") {
				return results;
			}
			
			var parts = [],
			m,
			set,
			checkSet,
			check,
			mode,
			extra,
			prune = true,
			contextXML = isXML(context),
			soFar = selector;
			while ((chunker.exec(""), m = chunker.exec(soFar)) !== null) {
				soFar = m[3];
				
				parts.push(m[1]);
				
				if (m[2]) {
					extra = m[3];
					break;
				}
			}
			
			if (parts.length > 1 && origPOS.exec(selector)) {
				if (parts.length === 2 && Expr.relative[parts[0]]) {
					set = posProcess(parts[0] + parts[1], context);
				} else {
					set = Expr.relative[parts[0]] ?
						[context] :
						Sizzle(parts.shift(), context);
					while (parts.length) {
						selector = parts.shift();
						
						if (Expr.relative[selector])
							selector += parts.shift();
						
						set = posProcess(selector, set);
					}
				}
			} else {
				if (!seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
					Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1])) {
					var ret = Sizzle.find(parts.shift(), context, contextXML);
					context = ret.expr ? Sizzle.filter(ret.expr, ret.set)[0] : ret.set[0];
				}
				
				if (context) {
					var ret = seed ? {
							expr : parts.pop(),
							set : makeArray(seed)
						}
						 :
						Sizzle.find(parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML);
					set = ret.expr ? Sizzle.filter(ret.expr, ret.set) : ret.set;
					
					if (parts.length > 0) {
						checkSet = makeArray(set);
					} else {
						prune = false;
					}
					while (parts.length) {
						var cur = parts.pop(),
						pop = cur;
						
						if (!Expr.relative[cur]) {
							cur = "";
						} else {
							pop = parts.pop();
						}
						
						if (pop == null) {
							pop = context;
						}
						
						Expr.relative[cur](checkSet, pop, contextXML);
					}
				} else {
					checkSet = parts = [];
				}
			}
			
			if (!checkSet) {
				checkSet = set;
			}
			
			if (!checkSet) {
				throw "Syntax error, unrecognized expression: " + (cur || selector);
			}
			
			if (toString.call(checkSet) === "[object Array]") {
				if (!prune) {
					results.push.apply(results, checkSet);
				} else if (context && context.nodeType === 1) {
					for (var i = 0; checkSet[i] != null; i++) {
						if (checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i]))) {
							results.push(set[i]);
						}
					}
				} else {
					for (var i = 0; checkSet[i] != null; i++) {
						if (checkSet[i] && checkSet[i].nodeType === 1) {
							results.push(set[i]);
						}
					}
				}
			} else {
				makeArray(checkSet, results);
			}
			
			if (extra) {
				Sizzle(extra, origContext, results, seed);
				Sizzle.uniqueSort(results);
			}
			
			return results;
		};
		
		Sizzle.uniqueSort = function (results) {
			if (sortOrder) {
				hasDuplicate = baseHasDuplicate;
				results.sort(sortOrder);
				
				if (hasDuplicate) {
					for (var i = 1; i < results.length; i++) {
						if (results[i] === results[i - 1]) {
							results.splice(i--, 1);
						}
					}
				}
			}
			
			return results;
		};
		
		Sizzle.matches = function (expr, set) {
			return Sizzle(expr, null, null, set);
		};
		
		Sizzle.find = function (expr, context, isXML) {
			var set,
			match;
			
			if (!expr) {
				return [];
			}
			
			for (var i = 0, l = Expr.order.length; i < l; i++) {
				var type = Expr.order[i],
				match;
				
				if ((match = Expr.leftMatch[type].exec(expr))) {
					var left = match[1];
					match.splice(1, 1);
					
					if (left.substr(left.length - 1) !== "\\") {
						match[1] = (match[1] || "").replace(/\\/g, "");
						set = Expr.find[type](match, context, isXML);
						if (set != null) {
							expr = expr.replace(Expr.match[type], "");
							break;
						}
					}
				}
			}
			
			if (!set) {
				set = context.getElementsByTagName("*");
			}
			
			return {
				set : set,
				expr : expr
			};
		};
		
		Sizzle.filter = function (expr, set, inplace, not) {
			var old = expr,
			result = [],
			curLoop = set,
			match,
			anyFound,
			isXMLFilter = set && set[0] && isXML(set[0]);
			while (expr && set.length) {
				for (var type in Expr.filter) {
					if ((match = Expr.match[type].exec(expr)) != null) {
						var filter = Expr.filter[type],
						found,
						item;
						anyFound = false;
						
						if (curLoop == result) {
							result = [];
						}
						
						if (Expr.preFilter[type]) {
							match = Expr.preFilter[type](match, curLoop, inplace, result, not, isXMLFilter);
							
							if (!match) {
								anyFound = found = true;
							} else if (match === true) {
								continue;
							}
						}
						
						if (match) {
							for (var i = 0; (item = curLoop[i]) != null; i++) {
								if (item) {
									found = filter(item, match, i, curLoop);
									var pass = not^!!found;
									
									if (inplace && found != null) {
										if (pass) {
											anyFound = true;
										} else {
											curLoop[i] = false;
										}
									} else if (pass) {
										result.push(item);
										anyFound = true;
									}
								}
							}
						}
						
						if (found !== undefined) {
							if (!inplace) {
								curLoop = result;
							}
							
							expr = expr.replace(Expr.match[type], "");
							
							if (!anyFound) {
								return [];
							}
							
							break;
						}
					}
				}
				
				if (expr == old) {
					if (anyFound == null) {
						throw "Syntax error, unrecognized expression: " + expr;
					} else {
						break;
					}
				}
				
				old = expr;
			}
			
			return curLoop;
		};
		
		var Expr = Sizzle.selectors = {
				order : ["ID", "NAME", "TAG"],
				match : {
					ID : /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
					CLASS : /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
					NAME : /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
					ATTR : /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
					TAG : /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
					CHILD : /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
					POS : /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
					PSEUDO : /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
				},
				leftMatch : {},
				attrMap : {
					"class" : "className",
					"for" : "htmlFor"
				},
				attrHandle : {
					href : function (elem) {
						return elem.getAttribute("href");
					}
				},
				relative : {
					"+" : function (checkSet, part, isXML) {
						var isPartStr = typeof part === "string",
						isTag = isPartStr && !/\W/.test(part),
						isPartStrNotTag = isPartStr && !isTag;
						
						if (isTag && !isXML) {
							part = part.toUpperCase();
						}
						
						for (var i = 0, l = checkSet.length, elem; i < l; i++) {
							if ((elem = checkSet[i])) {
								while ((elem = elem.previousSibling) && elem.nodeType !== 1) {}
								
								checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
									elem || false :
									elem === part;
							}
						}
						
						if (isPartStrNotTag) {
							Sizzle.filter(part, checkSet, true);
						}
					},
					">" : function (checkSet, part, isXML) {
						var isPartStr = typeof part === "string";
						
						if (isPartStr && !/\W/.test(part)) {
							part = isXML ? part : part.toUpperCase();
							
							for (var i = 0, l = checkSet.length; i < l; i++) {
								var elem = checkSet[i];
								if (elem) {
									var parent = elem.parentNode;
									checkSet[i] = parent.nodeName === part ? parent : false;
								}
							}
						} else {
							for (var i = 0, l = checkSet.length; i < l; i++) {
								var elem = checkSet[i];
								if (elem) {
									checkSet[i] = isPartStr ?
										elem.parentNode :
										elem.parentNode === part;
								}
							}
							
							if (isPartStr) {
								Sizzle.filter(part, checkSet, true);
							}
						}
					},
					"" : function (checkSet, part, isXML) {
						var doneName = done++,
						checkFn = dirCheck;
						
						if (!/\W/.test(part)) {
							var nodeCheck = part = isXML ? part : part.toUpperCase();
							checkFn = dirNodeCheck;
						}
						
						checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
					},
					"~" : function (checkSet, part, isXML) {
						var doneName = done++,
						checkFn = dirCheck;
						
						if (typeof part === "string" && !/\W/.test(part)) {
							var nodeCheck = part = isXML ? part : part.toUpperCase();
							checkFn = dirNodeCheck;
						}
						
						checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
					}
				},
				find : {
					ID : function (match, context, isXML) {
						if (typeof context.getElementById !== "undefined" && !isXML) {
							var m = context.getElementById(match[1]);
							return m ? [m] : [];
						}
					},
					NAME : function (match, context, isXML) {
						if (typeof context.getElementsByName !== "undefined") {
							var ret = [],
							results = context.getElementsByName(match[1]);
							
							for (var i = 0, l = results.length; i < l; i++) {
								if (results[i].getAttribute("name") === match[1]) {
									ret.push(results[i]);
								}
							}
							
							return ret.length === 0 ? null : ret;
						}
					},
					TAG : function (match, context) {
						return context.getElementsByTagName(match[1]);
					}
				},
				preFilter : {
					CLASS : function (match, curLoop, inplace, result, not, isXML) {
						match = " " + match[1].replace(/\\/g, "") + " ";
						
						if (isXML) {
							return match;
						}
						
						for (var i = 0, elem; (elem = curLoop[i]) != null; i++) {
							if (elem) {
								if (not^(elem.className && (" " + elem.className + " ").indexOf(match) >= 0)) {
									if (!inplace)
										result.push(elem);
								} else if (inplace) {
									curLoop[i] = false;
								}
							}
						}
						
						return false;
					},
					ID : function (match) {
						return match[1].replace(/\\/g, "");
					},
					TAG : function (match, curLoop) {
						for (var i = 0; curLoop[i] === false; i++) {}
						return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
					},
					CHILD : function (match) {
						if (match[1] == "nth") {
							var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
									match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
									!/\D/.test(match[2]) && "0n+" + match[2] || match[2]);
							
							match[2] = (test[1] + (test[2] || 1)) - 0;
							match[3] = test[3] - 0;
						}
						
						match[0] = done++;
						
						return match;
					},
					ATTR : function (match, curLoop, inplace, result, not, isXML) {
						var name = match[1].replace(/\\/g, "");
						
						if (!isXML && Expr.attrMap[name]) {
							match[1] = Expr.attrMap[name];
						}
						
						if (match[2] === "~=") {
							match[4] = " " + match[4] + " ";
						}
						
						return match;
					},
					PSEUDO : function (match, curLoop, inplace, result, not) {
						if (match[1] === "not") {
							if ((chunker.exec(match[3]) || "").length > 1 || /^\w/.test(match[3])) {
								match[3] = Sizzle(match[3], null, null, curLoop);
							} else {
								var ret = Sizzle.filter(match[3], curLoop, inplace, true^not);
								if (!inplace) {
									result.push.apply(result, ret);
								}
								return false;
							}
						} else if (Expr.match.POS.test(match[0]) || Expr.match.CHILD.test(match[0])) {
							return true;
						}
						
						return match;
					},
					POS : function (match) {
						match.unshift(true);
						return match;
					}
				},
				filters : {
					enabled : function (elem) {
						return elem.disabled === false && elem.type !== "hidden";
					},
					disabled : function (elem) {
						return elem.disabled === true;
					},
					checked : function (elem) {
						return elem.checked === true;
					},
					selected : function (elem) {
						elem.parentNode.selectedIndex;
						return elem.selected === true;
					},
					parent : function (elem) {
						return !!elem.firstChild;
					},
					empty : function (elem) {
						return !elem.firstChild;
					},
					has : function (elem, i, match) {
						return !!Sizzle(match[3], elem).length;
					},
					header : function (elem) {
						return /h\d/i.test(elem.nodeName);
					},
					text : function (elem) {
						return "text" === elem.type;
					},
					radio : function (elem) {
						return "radio" === elem.type;
					},
					checkbox : function (elem) {
						return "checkbox" === elem.type;
					},
					file : function (elem) {
						return "file" === elem.type;
					},
					password : function (elem) {
						return "password" === elem.type;
					},
					submit : function (elem) {
						return "submit" === elem.type;
					},
					image : function (elem) {
						return "image" === elem.type;
					},
					reset : function (elem) {
						return "reset" === elem.type;
					},
					button : function (elem) {
						return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
					},
					input : function (elem) {
						return /input|select|textarea|button/i.test(elem.nodeName);
					}
				},
				setFilters : {
					first : function (elem, i) {
						return i === 0;
					},
					last : function (elem, i, match, array) {
						return i === array.length - 1;
					},
					even : function (elem, i) {
						return i % 2 === 0;
					},
					odd : function (elem, i) {
						return i % 2 === 1;
					},
					lt : function (elem, i, match) {
						return i < match[3] - 0;
					},
					gt : function (elem, i, match) {
						return i > match[3] - 0;
					},
					nth : function (elem, i, match) {
						return match[3] - 0 == i;
					},
					eq : function (elem, i, match) {
						return match[3] - 0 == i;
					}
				},
				filter : {
					PSEUDO : function (elem, match, i, array) {
						var name = match[1],
						filter = Expr.filters[name];
						
						if (filter) {
							return filter(elem, i, match, array);
						} else if (name === "contains") {
							return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
						} else if (name === "not") {
							var not = match[3];
							
							for (var i = 0, l = not.length; i < l; i++) {
								if (not[i] === elem) {
									return false;
								}
							}
							
							return true;
						}
					},
					CHILD : function (elem, match) {
						var type = match[1],
						node = elem;
						switch (type) {
						case 'only':
						case 'first':
							while ((node = node.previousSibling)) {
								if (node.nodeType === 1)
									return false;
							}
							if (type == 'first')
								return true;
							node = elem;
						case 'last':
							while ((node = node.nextSibling)) {
								if (node.nodeType === 1)
									return false;
							}
							return true;
						case 'nth':
							var first = match[2],
							last = match[3];
							
							if (first == 1 && last == 0) {
								return true;
							}
							
							var doneName = match[0],
							parent = elem.parentNode;
							
							if (parent && (parent.sizcache !== doneName || !elem.nodeIndex)) {
								var count = 0;
								for (node = parent.firstChild; node; node = node.nextSibling) {
									if (node.nodeType === 1) {
										node.nodeIndex = ++count;
									}
								}
								parent.sizcache = doneName;
							}
							
							var diff = elem.nodeIndex - last;
							if (first == 0) {
								return diff == 0;
							} else {
								return (diff % first == 0 && diff / first >= 0);
							}
						}
					},
					ID : function (elem, match) {
						return elem.nodeType === 1 && elem.getAttribute("id") === match;
					},
					TAG : function (elem, match) {
						return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
					},
					CLASS : function (elem, match) {
						return (" " + (elem.className || elem.getAttribute("class")) + " ")
						.indexOf(match) > -1;
					},
					ATTR : function (elem, match) {
						var name = match[1],
						result = Expr.attrHandle[name] ?
							Expr.attrHandle[name](elem) :
							elem[name] != null ?
							elem[name] :
							elem.getAttribute(name),
						value = result + "",
						type = match[2],
						check = match[4];
						
						return result == null ?
						type === "!=" :
						type === "=" ?
						value === check :
						type === "*=" ?
						value.indexOf(check) >= 0 :
						type === "~=" ?
						(" " + value + " ").indexOf(check) >= 0 :
						!check ?
						value && result !== false :
						type === "!=" ?
						value != check :
						type === "^=" ?
						value.indexOf(check) === 0 :
						type === "$=" ?
						value.substr(value.length - check.length) === check :
						type === "|=" ?
						value === check || value.substr(0, check.length + 1) === check + "-" :
						false;
					},
					POS : function (elem, match, i, array) {
						var name = match[2],
						filter = Expr.setFilters[name];
						
						if (filter) {
							return filter(elem, i, match, array);
						}
					}
				}
			};
		
		var origPOS = Expr.match.POS;
		
		for (var type in Expr.match) {
			Expr.match[type] = new RegExp(Expr.match[type].source + /(?![^\[]*\])(?![^\(]*\))/.source);
			Expr.leftMatch[type] = new RegExp(/(^(?:.|\r|\n)*?)/.source + Expr.match[type].source);
		}
		
		var makeArray = function (array, results) {
			array = Array.prototype.slice.call(array, 0);
			
			if (results) {
				results.push.apply(results, array);
				return results;
			}
			
			return array;
		};
		
		try {
			Array.prototype.slice.call(document.documentElement.childNodes, 0);
			
		} catch (e) {
			makeArray = function (array, results) {
				var ret = results || [];
				
				if (toString.call(array) === "[object Array]") {
					Array.prototype.push.apply(ret, array);
				} else {
					if (typeof array.length === "number") {
						for (var i = 0, l = array.length; i < l; i++) {
							ret.push(array[i]);
						}
					} else {
						for (var i = 0; array[i]; i++) {
							ret.push(array[i]);
						}
					}
				}
				
				return ret;
			};
		}
		
		var sortOrder;
		
		if (document.documentElement.compareDocumentPosition) {
			sortOrder = function (a, b) {
				if (!a.compareDocumentPosition || !b.compareDocumentPosition) {
					if (a == b) {
						hasDuplicate = true;
					}
					return 0;
				}
				
				var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
				if (ret === 0) {
					hasDuplicate = true;
				}
				return ret;
			};
		} else if ("sourceIndex" in document.documentElement) {
			sortOrder = function (a, b) {
				if (!a.sourceIndex || !b.sourceIndex) {
					if (a == b) {
						hasDuplicate = true;
					}
					return 0;
				}
				
				var ret = a.sourceIndex - b.sourceIndex;
				if (ret === 0) {
					hasDuplicate = true;
				}
				return ret;
			};
		} else if (document.createRange) {
			sortOrder = function (a, b) {
				if (!a.ownerDocument || !b.ownerDocument) {
					if (a == b) {
						hasDuplicate = true;
					}
					return 0;
				}
				
				var aRange = a.ownerDocument.createRange(),
				bRange = b.ownerDocument.createRange();
				aRange.setStart(a, 0);
				aRange.setEnd(a, 0);
				bRange.setStart(b, 0);
				bRange.setEnd(b, 0);
				var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
				if (ret === 0) {
					hasDuplicate = true;
				}
				return ret;
			};
		}
		
		(function () {
				var form = document.createElement("div"),
				id = "script" + (new Date).getTime();
				form.innerHTML = "<a name='" + id + "'/>";
				
				var root = document.documentElement;
				root.insertBefore(form, root.firstChild);
				
				if (!!document.getElementById(id)) {
					Expr.find.ID = function (match, context, isXML) {
						if (typeof context.getElementById !== "undefined" && !isXML) {
							var m = context.getElementById(match[1]);
							return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
						}
					};
					
					Expr.filter.ID = function (elem, match) {
						var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
						return elem.nodeType === 1 && node && node.nodeValue === match;
					};
				}
				
				root.removeChild(form);
				root = form = null; // release memory in IE
			})();
		
		(function () {
				
				var div = document.createElement("div");
				div.appendChild(document.createComment(""));
				
				if (div.getElementsByTagName("*").length > 0) {
					Expr.find.TAG = function (match, context) {
						var results = context.getElementsByTagName(match[1]);
						
						if (match[1] === "*") {
							var tmp = [];
							
							for (var i = 0; results[i]; i++) {
								if (results[i].nodeType === 1) {
									tmp.push(results[i]);
								}
							}
							
							results = tmp;
						}
						
						return results;
					};
				}
				
				div.innerHTML = "<a href='#'></a>";
				if (div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
					div.firstChild.getAttribute("href") !== "#") {
					Expr.attrHandle.href = function (elem) {
						return elem.getAttribute("href", 2);
					};
				}
				
				div = null; // release memory in IE
			})();
		
		if (document.querySelectorAll)
			(function () {
					var oldSizzle = Sizzle,
					div = document.createElement("div");
					div.innerHTML = "<p class='TEST'></p>";
					
					if (div.querySelectorAll && div.querySelectorAll(".TEST").length === 0) {
						return;
					}
					
					Sizzle = function (query, context, extra, seed) {
						context = context || document;
						
						if (!seed && context.nodeType === 9 && !isXML(context)) {
							try {
								return makeArray(context.querySelectorAll(query), extra);
							} catch (e) {}
						}
						
						return oldSizzle(query, context, extra, seed);
					};
					
					for (var prop in oldSizzle) {
						Sizzle[prop] = oldSizzle[prop];
					}
					
					div = null; // release memory in IE
				})();
		
		if (document.getElementsByClassName && document.documentElement.getElementsByClassName)
			(function () {
					var div = document.createElement("div");
					div.innerHTML = "<div class='test e'></div><div class='test'></div>";
					
					if (div.getElementsByClassName("e").length === 0)
						return;
					
					div.lastChild.className = "e";
					
					if (div.getElementsByClassName("e").length === 1)
						return;
					
					Expr.order.splice(1, 0, "CLASS");
					Expr.find.CLASS = function (match, context, isXML) {
						if (typeof context.getElementsByClassName !== "undefined" && !isXML) {
							return context.getElementsByClassName(match[1]);
						}
					};
					
					div = null; // release memory in IE
				})();
		
		function dirNodeCheck(dir, cur, doneName, checkSet, nodeCheck, isXML) {
			var sibDir = dir == "previousSibling" && !isXML;
			for (var i = 0, l = checkSet.length; i < l; i++) {
				var elem = checkSet[i];
				if (elem) {
					if (sibDir && elem.nodeType === 1) {
						elem.sizcache = doneName;
						elem.sizset = i;
					}
					elem = elem[dir];
					var match = false;
					while (elem) {
						if (elem.sizcache === doneName) {
							match = checkSet[elem.sizset];
							break;
						}
						
						if (elem.nodeType === 1 && !isXML) {
							elem.sizcache = doneName;
							elem.sizset = i;
						}
						
						if (elem.nodeName === cur) {
							match = elem;
							break;
						}
						
						elem = elem[dir];
					}
					
					checkSet[i] = match;
				}
			}
		}
		
		function dirCheck(dir, cur, doneName, checkSet, nodeCheck, isXML) {
			var sibDir = dir == "previousSibling" && !isXML;
			for (var i = 0, l = checkSet.length; i < l; i++) {
				var elem = checkSet[i];
				if (elem) {
					if (sibDir && elem.nodeType === 1) {
						elem.sizcache = doneName;
						elem.sizset = i;
					}
					elem = elem[dir];
					var match = false;
					while (elem) {
						if (elem.sizcache === doneName) {
							match = checkSet[elem.sizset];
							break;
						}
						
						if (elem.nodeType === 1) {
							if (!isXML) {
								elem.sizcache = doneName;
								elem.sizset = i;
							}
							if (typeof cur !== "string") {
								if (elem === cur) {
									match = true;
									break;
								}
								
							} else if (Sizzle.filter(cur, [elem]).length > 0) {
								match = elem;
								break;
							}
						}
						
						elem = elem[dir];
					}
					
					checkSet[i] = match;
				}
			}
		}
		
		var contains = document.compareDocumentPosition ? function (a, b) {
			return a.compareDocumentPosition(b) & 16;
		}
		 : function (a, b) {
			return a !== b && (a.contains ? a.contains(b) : true);
		};
		
		var isXML = function (elem) {
			return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
			!!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
		};
		
		var posProcess = function (selector, context) {
			var tmpSet = [],
			later = "",
			match,
			root = context.nodeType ? [context] : context;
			while ((match = Expr.match.PSEUDO.exec(selector))) {
				later += match[0];
				selector = selector.replace(Expr.match.PSEUDO, "");
			}
			
			selector = Expr.relative[selector] ? selector + "*" : selector;
			
			for (var i = 0, l = root.length; i < l; i++) {
				Sizzle(selector, root[i], tmpSet);
			}
			
			return Sizzle.filter(later, tmpSet);
		};
		
		window.Sizzle = Sizzle;
		
	})(); ;
(function (engine) {
		var extendElements = Prototype.Selector.extendElements;
		
		function select(selector, scope) {
			return extendElements(engine(selector, scope || document));
		}
		
		function match(element, selector) {
			return engine.matches(selector, [element]).length == 1;
		}
		
		Prototype.Selector.engine = engine;
		Prototype.Selector.select = select;
		Prototype.Selector.match = match;
	})(Sizzle);

window.Sizzle = Prototype._original_property;
delete Prototype._original_property;

var Form = {
	reset : function (form) {
		form = $(form);
		form.reset();
		return form;
	},
	
	serializeElements : function (elements, options) {
		if (typeof options != 'object')
			options = {
				hash : !!options
			};
		else if (Object.isUndefined(options.hash))
			options.hash = true;
		var key,
		value,
		submitted = false,
		submit = options.submit,
		accumulator,
		initial;
		
		if (options.hash) {
			initial = {};
			accumulator = function (result, key, value) {
				if (key in result) {
					if (!Object.isArray(result[key]))
						result[key] = [result[key]];
					result[key].push(value);
				} else
					result[key] = value;
				return result;
			};
		} else {
			initial = '';
			accumulator = function (result, key, value) {
				return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value);
			}
		}
		
		return elements.inject(initial, function (result, element) {
				if (!element.disabled && element.name) {
					key = element.name;
					value = $(element).getValue();
					if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
								submit !== false && (!submit || key == submit) && (submitted = true)))) {
						result = accumulator(result, key, value);
					}
				}
				return result;
			});
	}
};

Form.Methods = {
	serialize : function (form, options) {
		return Form.serializeElements(Form.getElements(form), options);
	},
	
	getElements : function (form) {
		var elements = $(form).getElementsByTagName('*'),
		element,
		arr = [],
		serializers = Form.Element.Serializers;
		for (var i = 0; element = elements[i]; i++) {
			arr.push(element);
		}
		return arr.inject([], function (elements, child) {
				if (serializers[child.tagName.toLowerCase()])
					elements.push(Element.extend(child));
				return elements;
			})
	},
	
	getInputs : function (form, typeName, name) {
		form = $(form);
		var inputs = form.getElementsByTagName('input');
		
		if (!typeName && !name)
			return $A(inputs).map(Element.extend);
		
		for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
			var input = inputs[i];
			if ((typeName && input.type != typeName) || (name && input.name != name))
				continue;
			matchingInputs.push(Element.extend(input));
		}
		
		return matchingInputs;
	},
	
	disable : function (form) {
		form = $(form);
		Form.getElements(form).invoke('disable');
		return form;
	},
	
	enable : function (form) {
		form = $(form);
		Form.getElements(form).invoke('enable');
		return form;
	},
	
	findFirstElement : function (form) {
		var elements = $(form).getElements().findAll(function (element) {
					return 'hidden' != element.type && !element.disabled;
				});
		var firstByIndex = elements.findAll(function (element) {
					return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
				}).sortBy(function (element) {
					return element.tabIndex
				}).first();
		
		return firstByIndex ? firstByIndex : elements.find(function (element) {
				return /^(?:input|select|textarea)$/i.test(element.tagName);
			});
	},
	
	focusFirstElement : function (form) {
		form = $(form);
		var element = form.findFirstElement();
		if (element)
			element.activate();
		return form;
	},
	
	request : function (form, options) {
		form = $(form),
		options = Object.clone(options || {});
		
		var params = options.parameters,
		action = form.readAttribute('action') || '';
		if (action.blank())
			action = window.location.href;
		options.parameters = form.serialize(true);
		
		if (params) {
			if (Object.isString(params))
				params = params.toQueryParams();
			Object.extend(options.parameters, params);
		}
		
		if (form.hasAttribute('method') && !options.method)
			options.method = form.method;
		
		return new Ajax.Request(action, options);
	}
};

/*--------------------------------------------------------------------------*/

Form.Element = {
	focus : function (element) {
		$(element).focus();
		return element;
	},
	
	select : function (element) {
		$(element).select();
		return element;
	}
};

Form.Element.Methods = {
	
	serialize : function (element) {
		element = $(element);
		if (!element.disabled && element.name) {
			var value = element.getValue();
			if (value != undefined) {
				var pair = {};
				pair[element.name] = value;
				return Object.toQueryString(pair);
			}
		}
		return '';
	},
	
	getValue : function (element) {
		element = $(element);
		var method = element.tagName.toLowerCase();
		return Form.Element.Serializers[method](element);
	},
	
	setValue : function (element, value) {
		element = $(element);
		var method = element.tagName.toLowerCase();
		Form.Element.Serializers[method](element, value);
		return element;
	},
	
	clear : function (element) {
		$(element).value = '';
		return element;
	},
	
	present : function (element) {
		return $(element).value != '';
	},
	
	activate : function (element) {
		element = $(element);
		try {
			element.focus();
			if (element.select && (element.tagName.toLowerCase() != 'input' ||
					!(/^(?:button|reset|submit)$/i.test(element.type))))
				element.select();
		} catch (e) {}
		return element;
	},
	
	disable : function (element) {
		element = $(element);
		element.disabled = true;
		return element;
	},
	
	enable : function (element) {
		element = $(element);
		element.disabled = false;
		return element;
	}
};

/*--------------------------------------------------------------------------*/

var Field = Form.Element;

var $F = Form.Element.Methods.getValue;

/*--------------------------------------------------------------------------*/

Form.Element.Serializers = (function () {
		function input(element, value) {
			switch (element.type.toLowerCase()) {
			case 'checkbox':
			case 'radio':
				return inputSelector(element, value);
			default:
				return valueSelector(element, value);
			}
		}
		
		function inputSelector(element, value) {
			if (Object.isUndefined(value))
				return element.checked ? element.value : null;
			else
				element.checked = !!value;
		}
		
		function valueSelector(element, value) {
			if (Object.isUndefined(value))
				return element.value;
			else
				element.value = value;
		}
		
		function select(element, value) {
			if (Object.isUndefined(value))
				return (element.type === 'select-one' ? selectOne : selectMany)(element);
			
			var opt,
			currentValue,
			single = !Object.isArray(value);
			for (var i = 0, length = element.length; i < length; i++) {
				opt = element.options[i];
				currentValue = this.optionValue(opt);
				if (single) {
					if (currentValue == value) {
						opt.selected = true;
						return;
					}
				} else
					opt.selected = value.include(currentValue);
			}
		}
		
		function selectOne(element) {
			var index = element.selectedIndex;
			return index >= 0 ? optionValue(element.options[index]) : null;
		}
		
		function selectMany(element) {
			var values,
			length = element.length;
			if (!length)
				return null;
			
			for (var i = 0, values = []; i < length; i++) {
				var opt = element.options[i];
				if (opt.selected)
					values.push(optionValue(opt));
			}
			return values;
		}
		
		function optionValue(opt) {
			return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
		}
		
		return {
			input : input,
			inputSelector : inputSelector,
			textarea : valueSelector,
			select : select,
			selectOne : selectOne,
			selectMany : selectMany,
			optionValue : optionValue,
			button : valueSelector
		};
	})();

/*--------------------------------------------------------------------------*/

Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
			initialize : function ($super, element, frequency, callback) {
				$super(callback, frequency);
				this.element = $(element);
				this.lastValue = this.getValue();
			},
			
			execute : function () {
				var value = this.getValue();
				if (Object.isString(this.lastValue) && Object.isString(value) ?
					this.lastValue != value : String(this.lastValue) != String(value)) {
					this.callback(this.element, value);
					this.lastValue = value;
				}
			}
		});

Form.Element.Observer = Class.create(Abstract.TimedObserver, {
			getValue : function () {
				return Form.Element.getValue(this.element);
			}
		});

Form.Observer = Class.create(Abstract.TimedObserver, {
			getValue : function () {
				return Form.serialize(this.element);
			}
		});

/*--------------------------------------------------------------------------*/

Abstract.EventObserver = Class.create({
			initialize : function (element, callback) {
				this.element = $(element);
				this.callback = callback;
				
				this.lastValue = this.getValue();
				if (this.element.tagName.toLowerCase() == 'form')
					this.registerFormCallbacks();
				else
					this.registerCallback(this.element);
			},
			
			onElementEvent : function () {
				var value = this.getValue();
				if (this.lastValue != value) {
					this.callback(this.element, value);
					this.lastValue = value;
				}
			},
			
			registerFormCallbacks : function () {
				Form.getElements(this.element).each(this.registerCallback, this);
			},
			
			registerCallback : function (element) {
				if (element.type) {
					switch (element.type.toLowerCase()) {
					case 'checkbox':
					case 'radio':
						Event.observe(element, 'click', this.onElementEvent.bind(this));
						break;
					default:
						Event.observe(element, 'change', this.onElementEvent.bind(this));
						break;
					}
				}
			}
		});

Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
			getValue : function () {
				return Form.Element.getValue(this.element);
			}
		});

Form.EventObserver = Class.create(Abstract.EventObserver, {
			getValue : function () {
				return Form.serialize(this.element);
			}
		});
(function () {
		
		var Event = {
			KEY_BACKSPACE : 8,
			KEY_TAB : 9,
			KEY_RETURN : 13,
			KEY_ESC : 27,
			KEY_LEFT : 37,
			KEY_UP : 38,
			KEY_RIGHT : 39,
			KEY_DOWN : 40,
			KEY_DELETE : 46,
			KEY_HOME : 36,
			KEY_END : 35,
			KEY_PAGEUP : 33,
			KEY_PAGEDOWN : 34,
			KEY_INSERT : 45,
			
			cache : {}
		};
		
		var docEl = document.documentElement;
		var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
			 && 'onmouseleave' in docEl;
		
		var isIELegacyEvent = function (event) {
			return false;
		};
		
		if (window.attachEvent) {
			if (window.addEventListener) {
				isIELegacyEvent = function (event) {
					return !(event instanceof window.Event);
				};
			} else {
				isIELegacyEvent = function (event) {
					return true;
				};
			}
		}
		
		var _isButton;
		
		function _isButtonForDOMEvents(event, code) {
			return event.which ? (event.which === code + 1) : (event.button === code);
		}
		
		var legacyButtonMap = {
			0 : 1,
			1 : 4,
			2 : 2
		};
		function _isButtonForLegacyEvents(event, code) {
			return event.button === legacyButtonMap[code];
		}
		
		function _isButtonForWebKit(event, code) {
			switch (code) {
			case 0:
				return event.which == 1 && !event.metaKey;
			case 1:
				return event.which == 2 || (event.which == 1 && event.metaKey);
			case 2:
				return event.which == 3;
			default:
				return false;
			}
		}
		
		if (window.attachEvent) {
			if (!window.addEventListener) {
				_isButton = _isButtonForLegacyEvents;
			} else {
				_isButton = function (event, code) {
					return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
					_isButtonForDOMEvents(event, code);
				}
			}
		} else if (Prototype.Browser.WebKit) {
			_isButton = _isButtonForWebKit;
		} else {
			_isButton = _isButtonForDOMEvents;
		}
		
		function isLeftClick(event) {
			return _isButton(event, 0)
		}
		
		function isMiddleClick(event) {
			return _isButton(event, 1)
		}
		
		function isRightClick(event) {
			return _isButton(event, 2)
		}
		
		function element(event) {
			event = Event.extend(event);
			
			var node = event.target,
			type = event.type,
			currentTarget = event.currentTarget;
			
			if (currentTarget && currentTarget.tagName) {
				if (type === 'load' || type === 'error' ||
					(type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
						 && currentTarget.type === 'radio'))
					node = currentTarget;
			}
			
			if (node.nodeType == Node.TEXT_NODE)
				node = node.parentNode;
			
			return Element.extend(node);
		}
		
		function findElement(event, expression) {
			var element = Event.element(event);
			
			if (!expression)
				return element;
			while (element) {
				if (Object.isElement(element) && Prototype.Selector.match(element, expression)) {
					return Element.extend(element);
				}
				element = element.parentNode;
			}
		}
		
		function pointer(event) {
			return {
				x : pointerX(event),
				y : pointerY(event)
			};
		}
		
		function pointerX(event) {
			var docElement = document.documentElement,
			body = document.body || {
					scrollLeft : 0
				};
			
			return event.pageX || (event.clientX +
				(docElement.scrollLeft || body.scrollLeft) -
				(docElement.clientLeft || 0));
		}
		
		function pointerY(event) {
			var docElement = document.documentElement,
			body = document.body || {
					scrollTop : 0
				};
			
			return event.pageY || (event.clientY +
				(docElement.scrollTop || body.scrollTop) -
				(docElement.clientTop || 0));
		}
		
		function stop(event) {
			Event.extend(event);
			event.preventDefault();
			event.stopPropagation();
			
			event.stopped = true;
		}
		
		Event.Methods = {
			isLeftClick : isLeftClick,
			isMiddleClick : isMiddleClick,
			isRightClick : isRightClick,
			
			element : element,
			findElement : findElement,
			
			pointer : pointer,
			pointerX : pointerX,
			pointerY : pointerY,
			
			stop : stop
		};
		
		var methods = Object.keys(Event.Methods).inject({}, function (m, name) {
					m[name] = Event.Methods[name].methodize();
					return m;
				});
		
		if (window.attachEvent) {
			function _relatedTarget(event) {
				var element;
				switch (event.type) {
				case 'mouseover':
				case 'mouseenter':
					element = event.fromElement;
					break;
				case 'mouseout':
				case 'mouseleave':
					element = event.toElement;
					break;
				default:
					return null;
				}
				return Element.extend(element);
			}
			
			var additionalMethods = {
				stopPropagation : function () {
					this.cancelBubble = true
				},
				preventDefault : function () {
					this.returnValue = false
				},
				inspect : function () {
					return '[object Event]'
				}
			};
			
			Event.extend = function (event, element) {
				if (!event)
					return false;
				
				if (!isIELegacyEvent(event))
					return event;
				
				if (event._extendedByPrototype)
					return event;
				event._extendedByPrototype = Prototype.emptyFunction;
				
				var pointer = Event.pointer(event);
				
				Object.extend(event, {
						target : event.srcElement || element,
						relatedTarget : _relatedTarget(event),
						pageX : pointer.x,
						pageY : pointer.y
					});
				
				Object.extend(event, methods);
				Object.extend(event, additionalMethods);
				
				return event;
			};
		} else {
			Event.extend = Prototype.K;
		}
		
		if (window.addEventListener) {
			Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
			Object.extend(Event.prototype, methods);
		}
		
		function _createResponder(element, eventName, handler) {
			var registry = Element.retrieve(element, 'prototype_event_registry');
			
			if (Object.isUndefined(registry)) {
				CACHE.push(element);
				registry = Element.retrieve(element, 'prototype_event_registry', $H());
			}
			
			var respondersForEvent = registry.get(eventName);
			if (Object.isUndefined(respondersForEvent)) {
				respondersForEvent = [];
				registry.set(eventName, respondersForEvent);
			}
			
			if (respondersForEvent.pluck('handler').include(handler))
				return false;
			
			var responder;
			if (eventName.include(":")) {
				responder = function (event) {
					if (Object.isUndefined(event.eventName))
						return false;
					
					if (event.eventName !== eventName)
						return false;
					
					Event.extend(event, element);
					handler.call(element, event);
				};
			} else {
				if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
					(eventName === "mouseenter" || eventName === "mouseleave")) {
					if (eventName === "mouseenter" || eventName === "mouseleave") {
						responder = function (event) {
							Event.extend(event, element);
							
							var parent = event.relatedTarget;
							while (parent && parent !== element) {
								try {
									parent = parent.parentNode;
								} catch (e) {
									parent = element;
								}
							}
							
							if (parent === element)
								return;
							
							handler.call(element, event);
						};
					}
				} else {
					responder = function (event) {
						Event.extend(event, element);
						handler.call(element, event);
					};
				}
			}
			
			responder.handler = handler;
			respondersForEvent.push(responder);
			return responder;
		}
		
		function _destroyCache() {
			for (var i = 0, length = CACHE.length; i < length; i++) {
				Event.stopObserving(CACHE[i]);
				CACHE[i] = null;
			}
		}
		
		var CACHE = [];
		
		if (Prototype.Browser.IE)
			window.attachEvent('onunload', _destroyCache);
		
		if (Prototype.Browser.WebKit)
			window.addEventListener('unload', Prototype.emptyFunction, false);
		
		var _getDOMEventName = Prototype.K,
		translations = {
			mouseenter : "mouseover",
			mouseleave : "mouseout"
		};
		
		if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) {
			_getDOMEventName = function (eventName) {
				return (translations[eventName] || eventName);
			};
		}
		
		function observe(element, eventName, handler) {
			element = $(element);
			
			var responder = _createResponder(element, eventName, handler);
			
			if (!responder)
				return element;
			
			if (eventName.include(':')) {
				if (element.addEventListener)
					element.addEventListener("dataavailable", responder, false);
				else {
					element.attachEvent("ondataavailable", responder);
					element.attachEvent("onlosecapture", responder);
				}
			} else {
				var actualEventName = _getDOMEventName(eventName);
				
				if (element.addEventListener)
					element.addEventListener(actualEventName, responder, false);
				else
					element.attachEvent("on" + actualEventName, responder);
			}
			
			return element;
		}
		
		function stopObserving(element, eventName, handler) {
			element = $(element);
			
			var registry = Element.retrieve(element, 'prototype_event_registry');
			if (!registry)
				return element;
			
			if (!eventName) {
				registry.each(function (pair) {
						var eventName = pair.key;
						stopObserving(element, eventName);
					});
				return element;
			}
			
			var responders = registry.get(eventName);
			if (!responders)
				return element;
			
			if (!handler) {
				responders.each(function (r) {
						stopObserving(element, eventName, r.handler);
					});
				return element;
			}
			
			var i = responders.length,
			responder;
			while (i--) {
				if (responders[i].handler === handler) {
					responder = responders[i];
					break;
				}
			}
			if (!responder)
				return element;
			
			if (eventName.include(':')) {
				if (element.removeEventListener)
					element.removeEventListener("dataavailable", responder, false);
				else {
					element.detachEvent("ondataavailable", responder);
					element.detachEvent("onlosecapture", responder);
				}
			} else {
				var actualEventName = _getDOMEventName(eventName);
				if (element.removeEventListener)
					element.removeEventListener(actualEventName, responder, false);
				else
					element.detachEvent('on' + actualEventName, responder);
			}
			
			registry.set(eventName, responders.without(responder));
			
			return element;
		}
		
		function fire(element, eventName, memo, bubble) {
			element = $(element);
			
			if (Object.isUndefined(bubble))
				bubble = true;
			
			if (element == document && document.createEvent && !element.dispatchEvent)
				element = document.documentElement;
			
			var event;
			if (document.createEvent) {
				event = document.createEvent('HTMLEvents');
				event.initEvent('dataavailable', bubble, true);
			} else {
				event = document.createEventObject();
				event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
			}
			
			event.eventName = eventName;
			event.memo = memo || {};
			
			if (document.createEvent)
				element.dispatchEvent(event);
			else
				element.fireEvent(event.eventType, event);
			
			return Event.extend(event);
		}
		
		Event.Handler = Class.create({
					initialize : function (element, eventName, selector, callback) {
						this.element = $(element);
						this.eventName = eventName;
						this.selector = selector;
						this.callback = callback;
						this.handler = this.handleEvent.bind(this);
					},
					
					start : function () {
						Event.observe(this.element, this.eventName, this.handler);
						return this;
					},
					
					stop : function () {
						Event.stopObserving(this.element, this.eventName, this.handler);
						return this;
					},
					
					handleEvent : function (event) {
						var element = Event.findElement(event, this.selector);
						if (element)
							this.callback.call(this.element, event, element);
					}
				});
		
		function on(element, eventName, selector, callback) {
			element = $(element);
			if (Object.isFunction(selector) && Object.isUndefined(callback)) {
				callback = selector,
				selector = null;
			}
			
			return new Event.Handler(element, eventName, selector, callback).start();
		}
		
		Object.extend(Event, Event.Methods);
		
		Object.extend(Event, {
				fire : fire,
				observe : observe,
				stopObserving : stopObserving,
				on : on
			});
		
		Element.addMethods({
				fire : fire,
				
				observe : observe,
				
				stopObserving : stopObserving,
				
				on : on
			});
		
		Object.extend(document, {
				fire : fire.methodize(),
				
				observe : observe.methodize(),
				
				stopObserving : stopObserving.methodize(),
				
				on : on.methodize(),
				
				loaded : false
			});
		
		if (window.Event)
			Object.extend(window.Event, Event);
		else
			window.Event = Event;
	})();

(function () {
		/* Support for the DOMContentLoaded event is based on work by Dan Webb,
		Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
		
		var timer;
		
		function fireContentLoadedEvent() {
			if (document.loaded)
				return;
			if (timer)
				window.clearTimeout(timer);
			document.loaded = true;
			document.fire('dom:loaded');
		}
		
		function checkReadyState() {
			if (document.readyState === 'complete') {
				document.stopObserving('readystatechange', checkReadyState);
				fireContentLoadedEvent();
			}
		}
		
		function pollDoScroll() {
			try {
				document.documentElement.doScroll('left');
			} catch (e) {
				timer = pollDoScroll.defer();
				return;
			}
			fireContentLoadedEvent();
		}
		
		if (document.addEventListener) {
			document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
		} else {
			document.observe('readystatechange', checkReadyState);
			if (window == top)
				timer = pollDoScroll.defer();
		}
		
		Event.observe(window, 'load', fireContentLoadedEvent);
	})();

Element.addMethods();

/*------------------------------- DEPRECATED -------------------------------*/

Hash.toQueryString = Object.toQueryString;

var Toggle = {
	display : Element.toggle
};

Element.Methods.childOf = Element.Methods.descendantOf;

var Insertion = {
	Before : function (element, content) {
		return Element.insert(element, {
				before : content
			});
	},
	
	Top : function (element, content) {
		return Element.insert(element, {
				top : content
			});
	},
	
	Bottom : function (element, content) {
		return Element.insert(element, {
				bottom : content
			});
	},
	
	After : function (element, content) {
		return Element.insert(element, {
				after : content
			});
	}
};

var $continue = new Error('"throw $continue" is deprecated, use "return" instead');

var Position = {
	includeScrollOffsets : false,
	
	prepare : function () {
		this.deltaX = window.pageXOffset
			 || document.documentElement.scrollLeft
			 || document.body.scrollLeft
			 || 0;
		this.deltaY = window.pageYOffset
			 || document.documentElement.scrollTop
			 || document.body.scrollTop
			 || 0;
	},
	
	within : function (element, x, y) {
		if (this.includeScrollOffsets)
			return this.withinIncludingScrolloffsets(element, x, y);
		this.xcomp = x;
		this.ycomp = y;
		this.offset = Element.cumulativeOffset(element);
		
		return (y >= this.offset[1] &&
			y < this.offset[1] + element.offsetHeight &&
			x >= this.offset[0] &&
			x < this.offset[0] + element.offsetWidth);
	},
	
	withinIncludingScrolloffsets : function (element, x, y) {
		var offsetcache = Element.cumulativeScrollOffset(element);
		
		this.xcomp = x + offsetcache[0] - this.deltaX;
		this.ycomp = y + offsetcache[1] - this.deltaY;
		this.offset = Element.cumulativeOffset(element);
		
		return (this.ycomp >= this.offset[1] &&
			this.ycomp < this.offset[1] + element.offsetHeight &&
			this.xcomp >= this.offset[0] &&
			this.xcomp < this.offset[0] + element.offsetWidth);
	},
	
	overlap : function (mode, element) {
		if (!mode)
			return 0;
		if (mode == 'vertical')
			return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
			element.offsetHeight;
		if (mode == 'horizontal')
			return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
			element.offsetWidth;
	},
	
	cumulativeOffset : Element.Methods.cumulativeOffset,
	
	positionedOffset : Element.Methods.positionedOffset,
	
	absolutize : function (element) {
		Position.prepare();
		return Element.absolutize(element);
	},
	
	relativize : function (element) {
		Position.prepare();
		return Element.relativize(element);
	},
	
	realOffset : Element.Methods.cumulativeScrollOffset,
	
	offsetParent : Element.Methods.getOffsetParent,
	
	page : Element.Methods.viewportOffset,
	
	clone : function (source, target, options) {
		options = options || {};
		return Element.clonePosition(target, source, options);
	}
};

/*--------------------------------------------------------------------------*/

if (!document.getElementsByClassName)
	document.getElementsByClassName = function (instanceMethods) {
		function iter(name) {
			return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
		}
		
		instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
		function (element, className) {
			className = className.toString().strip();
			var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
			return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
		}
		 : function (element, className) {
			className = className.toString().strip();
			var elements = [],
			classNames = (/\s/.test(className) ? $w(className) : null);
			if (!classNames && !className)
				return elements;
			
			var nodes = $(element).getElementsByTagName('*');
			className = ' ' + className + ' ';
			
			for (var i = 0, child, cn; child = nodes[i]; i++) {
				if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
						(classNames && classNames.all(function (name) {
									return !name.toString().blank() && cn.include(' ' + name + ' ');
								}))))
					elements.push(Element.extend(child));
			}
			return elements;
		};
		
		return function (className, parentElement) {
			return $(parentElement || document.body).getElementsByClassName(className);
		};
	}
(Element.Methods);

/*--------------------------------------------------------------------------*/

Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
	initialize : function (element) {
		this.element = $(element);
	},
	
	_each : function (iterator) {
		this.element.className.split(/\s+/).select(function (name) {
				return name.length > 0;
			})._each(iterator);
	},
	
	set : function (className) {
		this.element.className = className;
	},
	
	add : function (classNameToAdd) {
		if (this.include(classNameToAdd))
			return;
		this.set($A(this).concat(classNameToAdd).join(' '));
	},
	
	remove : function (classNameToRemove) {
		if (!this.include(classNameToRemove))
			return;
		this.set($A(this).without(classNameToRemove).join(' '));
	},
	
	toString : function () {
		return $A(this).join(' ');
	}
};

Object.extend(Element.ClassNames.prototype, Enumerable);

/*--------------------------------------------------------------------------*/

(function () {
		window.Selector = Class.create({
					initialize : function (expression) {
						this.expression = expression.strip();
					},
					
					findElements : function (rootElement) {
						return Prototype.Selector.select(this.expression, rootElement);
					},
					
					match : function (element) {
						return Prototype.Selector.match(element, this.expression);
					},
					
					toString : function () {
						return this.expression;
					},
					
					inspect : function () {
						return "#<Selector: " + this.expression + ">";
					}
				});
		
		Object.extend(Selector, {
				matchElements : function (elements, expression) {
					var match = Prototype.Selector.match,
					results = [];
					
					for (var i = 0, length = elements.length; i < length; i++) {
						var element = elements[i];
						if (match(element, expression)) {
							results.push(Element.extend(element));
						}
					}
					return results;
				},
				
				findElement : function (elements, expression, index) {
					index = index || 0;
					var matchIndex = 0,
					element;
					for (var i = 0, length = elements.length; i < length; i++) {
						element = elements[i];
						if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
							return Element.extend(element);
						}
					}
				},
				
				findChildElements : function (element, expressions) {
					var selector = expressions.toArray().join(', ');
					return Prototype.Selector.select(selector, element || document);
				}
			});
	})();
	
// simulate event
(function () {
		
		var eventMatchers = {
			'HTMLEvents' : /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll|ready)$/,
			'MouseEvents' : /^(?:click|mouse(?:down|up|over|move|out))$/
		}
		var defaultOptions = {
			pointerX : 0,
			pointerY : 0,
			button : 0,
			ctrlKey : false,
			altKey : false,
			shiftKey : false,
			metaKey : false,
			bubbles : true,
			cancelable : true
		}
		
		Event.simulate = function (element, eventName) {
			var options = Object.extend(defaultOptions, arguments[2] || {});
			var oEvent,
			eventType = null;
			
			element = $(element);
			
			for (var name in eventMatchers) {
				if (eventMatchers[name].test(eventName)) {
					eventType = name;
					break;
				}
			}
			
			if (!eventType)
				throw new SyntaxError('Only HTMLEvents and MouseEvents interfaces are supported');
			
			if (document.createEvent) {
				oEvent = document.createEvent(eventType);
				if (eventType == 'HTMLEvents') {
					oEvent.initEvent(eventName, options.bubbles, options.cancelable);
				} else {
					oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView,
						options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY,
						options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element);
				}
				element.dispatchEvent(oEvent);
			} else {
				options.clientX = options.pointerX;
				options.clientY = options.pointerY;
				oEvent = Object.extend(document.createEventObject(), options);
				element.fireEvent('on' + eventName, oEvent);
			}
			return element;
		}
		
		Element.addMethods({
				simulate : Event.simulate
			});
	})() 
