1/*!
2 * jQuery JavaScript Library v1.3.2
3 * http://jquery.com/
4 *
5 * Copyright (c) 2009 John Resig
6 * Dual licensed under the MIT and GPL licenses.
7 * http://docs.jquery.com/License
8 *
9 * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
10 * Revision: 6246
11 */
12(function(){
13
14var
15	// Will speed up references to window, and allows munging its name.
16	window = this,
17	// Will speed up references to undefined, and allows munging its name.
18	undefined,
19	// Map over jQuery in case of overwrite
20	_jQuery = window.jQuery,
21	// Map over the $ in case of overwrite
22	_$ = window.$,
23
24	jQuery = window.jQuery = window.$ = function( selector, context ) {
25		// The jQuery object is actually just the init constructor 'enhanced'
26		return new jQuery.fn.init( selector, context );
27	},
28
29	// A simple way to check for HTML strings or ID strings
30	// (both of which we optimize for)
31	quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
32	// Is it a simple selector
33	isSimple = /^.[^:#\[\.,]*$/;
34
35jQuery.fn = jQuery.prototype = {
36	init: function( selector, context ) {
37		// Make sure that a selection was provided
38		selector = selector || document;
39
40		// Handle $(DOMElement)
41		if ( selector.nodeType ) {
42			this[0] = selector;
43			this.length = 1;
44			this.context = selector;
45			return this;
46		}
47		// Handle HTML strings
48		if ( typeof selector === "string" ) {
49			// Are we dealing with HTML string or an ID?
50			var match = quickExpr.exec( selector );
51
52			// Verify a match, and that no context was specified for #id
53			if ( match && (match[1] || !context) ) {
54
55				// HANDLE: $(html) -> $(array)
56				if ( match[1] )
57					selector = jQuery.clean( [ match[1] ], context );
58
59				// HANDLE: $("#id")
60				else {
61					var elem = document.getElementById( match[3] );
62
63					// Handle the case where IE and Opera return items
64					// by name instead of ID
65					if ( elem && elem.id != match[3] )
66						return jQuery().find( selector );
67
68					// Otherwise, we inject the element directly into the jQuery object
69					var ret = jQuery( elem || [] );
70					ret.context = document;
71					ret.selector = selector;
72					return ret;
73				}
74
75			// HANDLE: $(expr, [context])
76			// (which is just equivalent to: $(content).find(expr)
77			} else
78				return jQuery( context ).find( selector );
79
80		// HANDLE: $(function)
81		// Shortcut for document ready
82		} else if ( jQuery.isFunction( selector ) )
83			return jQuery( document ).ready( selector );
84
85		// Make sure that old selector state is passed along
86		if ( selector.selector && selector.context ) {
87			this.selector = selector.selector;
88			this.context = selector.context;
89		}
90
91		return this.setArray(jQuery.isArray( selector ) ?
92			selector :
93			jQuery.makeArray(selector));
94	},
95
96	// Start with an empty selector
97	selector: "",
98
99	// The current version of jQuery being used
100	jquery: "1.3.2",
101
102	// The number of elements contained in the matched element set
103	size: function() {
104		return this.length;
105	},
106
107	// Get the Nth element in the matched element set OR
108	// Get the whole matched element set as a clean array
109	get: function( num ) {
110		return num === undefined ?
111
112			// Return a 'clean' array
113			Array.prototype.slice.call( this ) :
114
115			// Return just the object
116			this[ num ];
117	},
118
119	// Take an array of elements and push it onto the stack
120	// (returning the new matched element set)
121	pushStack: function( elems, name, selector ) {
122		// Build a new jQuery matched element set
123		var ret = jQuery( elems );
124
125		// Add the old object onto the stack (as a reference)
126		ret.prevObject = this;
127
128		ret.context = this.context;
129
130		if ( name === "find" )
131			ret.selector = this.selector + (this.selector ? " " : "") + selector;
132		else if ( name )
133			ret.selector = this.selector + "." + name + "(" + selector + ")";
134
135		// Return the newly-formed element set
136		return ret;
137	},
138
139	// Force the current matched set of elements to become
140	// the specified array of elements (destroying the stack in the process)
141	// You should use pushStack() in order to do this, but maintain the stack
142	setArray: function( elems ) {
143		// Resetting the length to 0, then using the native Array push
144		// is a super-fast way to populate an object with array-like properties
145		this.length = 0;
146		Array.prototype.push.apply( this, elems );
147
148		return this;
149	},
150
151	// Execute a callback for every element in the matched set.
152	// (You can seed the arguments with an array of args, but this is
153	// only used internally.)
154	each: function( callback, args ) {
155		return jQuery.each( this, callback, args );
156	},
157
158	// Determine the position of an element within
159	// the matched set of elements
160	index: function( elem ) {
161		// Locate the position of the desired element
162		return jQuery.inArray(
163			// If it receives a jQuery object, the first element is used
164			elem && elem.jquery ? elem[0] : elem
165		, this );
166	},
167
168	attr: function( name, value, type ) {
169		var options = name;
170
171		// Look for the case where we're accessing a style value
172		if ( typeof name === "string" )
173			if ( value === undefined )
174				return this[0] && jQuery[ type || "attr" ]( this[0], name );
175
176			else {
177				options = {};
178				options[ name ] = value;
179			}
180
181		// Check to see if we're setting style values
182		return this.each(function(i){
183			// Set all the styles
184			for ( name in options )
185				jQuery.attr(
186					type ?
187						this.style :
188						this,
189					name, jQuery.prop( this, options[ name ], type, i, name )
190				);
191		});
192	},
193
194	css: function( key, value ) {
195		// ignore negative width and height values
196		if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
197			value = undefined;
198		return this.attr( key, value, "curCSS" );
199	},
200
201	text: function( text ) {
202		if ( typeof text !== "object" && text != null )
203			return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
204
205		var ret = "";
206
207		jQuery.each( text || this, function(){
208			jQuery.each( this.childNodes, function(){
209				if ( this.nodeType != 8 )
210					ret += this.nodeType != 1 ?
211						this.nodeValue :
212						jQuery.fn.text( [ this ] );
213			});
214		});
215
216		return ret;
217	},
218
219	wrapAll: function( html ) {
220		if ( this[0] ) {
221			// The elements to wrap the target around
222			var wrap = jQuery( html, this[0].ownerDocument ).clone();
223
224			if ( this[0].parentNode )
225				wrap.insertBefore( this[0] );
226
227			wrap.map(function(){
228				var elem = this;
229
230				while ( elem.firstChild )
231					elem = elem.firstChild;
232
233				return elem;
234			}).append(this);
235		}
236
237		return this;
238	},
239
240	wrapInner: function( html ) {
241		return this.each(function(){
242			jQuery( this ).contents().wrapAll( html );
243		});
244	},
245
246	wrap: function( html ) {
247		return this.each(function(){
248			jQuery( this ).wrapAll( html );
249		});
250	},
251
252	append: function() {
253		return this.domManip(arguments, true, function(elem){
254			if (this.nodeType == 1)
255				this.appendChild( elem );
256		});
257	},
258
259	prepend: function() {
260		return this.domManip(arguments, true, function(elem){
261			if (this.nodeType == 1)
262				this.insertBefore( elem, this.firstChild );
263		});
264	},
265
266	before: function() {
267		return this.domManip(arguments, false, function(elem){
268			this.parentNode.insertBefore( elem, this );
269		});
270	},
271
272	after: function() {
273		return this.domManip(arguments, false, function(elem){
274			this.parentNode.insertBefore( elem, this.nextSibling );
275		});
276	},
277
278	end: function() {
279		return this.prevObject || jQuery( [] );
280	},
281
282	// For internal use only.
283	// Behaves like an Array's method, not like a jQuery method.
284	push: [].push,
285	sort: [].sort,
286	splice: [].splice,
287
288	find: function( selector ) {
289		if ( this.length === 1 ) {
290			var ret = this.pushStack( [], "find", selector );
291			ret.length = 0;
292			jQuery.find( selector, this[0], ret );
293			return ret;
294		} else {
295			return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){
296				return jQuery.find( selector, elem );
297			})), "find", selector );
298		}
299	},
300
301	clone: function( events ) {
302		// Do the clone
303		var ret = this.map(function(){
304			if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
305				// IE copies events bound via attachEvent when
306				// using cloneNode. Calling detachEvent on the
307				// clone will also remove the events from the orignal
308				// In order to get around this, we use innerHTML.
309				// Unfortunately, this means some modifications to
310				// attributes in IE that are actually only stored
311				// as properties will not be copied (such as the
312				// the name attribute on an input).
313				var html = this.outerHTML;
314				if ( !html ) {
315					var div = this.ownerDocument.createElement("div");
316					div.appendChild( this.cloneNode(true) );
317					html = div.innerHTML;
318				}
319
320				return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
321			} else
322				return this.cloneNode(true);
323		});
324
325		// Copy the events from the original to the clone
326		if ( events === true ) {
327			var orig = this.find("*").andSelf(), i = 0;
328
329			ret.find("*").andSelf().each(function(){
330				if ( this.nodeName !== orig[i].nodeName )
331					return;
332
333				var events = jQuery.data( orig[i], "events" );
334
335				for ( var type in events ) {
336					for ( var handler in events[ type ] ) {
337						jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
338					}
339				}
340
341				i++;
342			});
343		}
344
345		// Return the cloned set
346		return ret;
347	},
348
349	filter: function( selector ) {
350		return this.pushStack(
351			jQuery.isFunction( selector ) &&
352			jQuery.grep(this, function(elem, i){
353				return selector.call( elem, i );
354			}) ||
355
356			jQuery.multiFilter( selector, jQuery.grep(this, function(elem){
357				return elem.nodeType === 1;
358			}) ), "filter", selector );
359	},
360
361	closest: function( selector ) {
362		var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null,
363			closer = 0;
364
365		return this.map(function(){
366			var cur = this;
367			while ( cur && cur.ownerDocument ) {
368				if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) {
369					jQuery.data(cur, "closest", closer);
370					return cur;
371				}
372				cur = cur.parentNode;
373				closer++;
374			}
375		});
376	},
377
378	not: function( selector ) {
379		if ( typeof selector === "string" )
380			// test special case where just one selector is passed in
381			if ( isSimple.test( selector ) )
382				return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector );
383			else
384				selector = jQuery.multiFilter( selector, this );
385
386		var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
387		return this.filter(function() {
388			return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
389		});
390	},
391
392	add: function( selector ) {
393		return this.pushStack( jQuery.unique( jQuery.merge(
394			this.get(),
395			typeof selector === "string" ?
396				jQuery( selector ) :
397				jQuery.makeArray( selector )
398		)));
399	},
400
401	is: function( selector ) {
402		return !!selector && jQuery.multiFilter( selector, this ).length > 0;
403	},
404
405	hasClass: function( selector ) {
406		return !!selector && this.is( "." + selector );
407	},
408
409	val: function( value ) {
410		if ( value === undefined ) {
411			var elem = this[0];
412
413			if ( elem ) {
414				if( jQuery.nodeName( elem, 'option' ) )
415					return (elem.attributes.value || {}).specified ? elem.value : elem.text;
416
417				// We need to handle select boxes special
418				if ( jQuery.nodeName( elem, "select" ) ) {
419					var index = elem.selectedIndex,
420						values = [],
421						options = elem.options,
422						one = elem.type == "select-one";
423
424					// Nothing was selected
425					if ( index < 0 )
426						return null;
427
428					// Loop through all the selected options
429					for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
430						var option = options[ i ];
431
432						if ( option.selected ) {
433							// Get the specifc value for the option
434							value = jQuery(option).val();
435
436							// We don't need an array for one selects
437							if ( one )
438								return value;
439
440							// Multi-Selects return an array
441							values.push( value );
442						}
443					}
444
445					return values;
446				}
447
448				// Everything else, we just grab the value
449				return (elem.value || "").replace(/\r/g, "");
450
451			}
452
453			return undefined;
454		}
455
456		if ( typeof value === "number" )
457			value += '';
458
459		return this.each(function(){
460			if ( this.nodeType != 1 )
461				return;
462
463			if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) )
464				this.checked = (jQuery.inArray(this.value, value) >= 0 ||
465					jQuery.inArray(this.name, value) >= 0);
466
467			else if ( jQuery.nodeName( this, "select" ) ) {
468				var values = jQuery.makeArray(value);
469
470				jQuery( "option", this ).each(function(){
471					this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
472						jQuery.inArray( this.text, values ) >= 0);
473				});
474
475				if ( !values.length )
476					this.selectedIndex = -1;
477
478			} else
479				this.value = value;
480		});
481	},
482
483	html: function( value ) {
484		return value === undefined ?
485			(this[0] ?
486				this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
487				null) :
488			this.empty().append( value );
489	},
490
491	replaceWith: function( value ) {
492		return this.after( value ).remove();
493	},
494
495	eq: function( i ) {
496		return this.slice( i, +i + 1 );
497	},
498
499	slice: function() {
500		return this.pushStack( Array.prototype.slice.apply( this, arguments ),
501			"slice", Array.prototype.slice.call(arguments).join(",") );
502	},
503
504	map: function( callback ) {
505		return this.pushStack( jQuery.map(this, function(elem, i){
506			return callback.call( elem, i, elem );
507		}));
508	},
509
510	andSelf: function() {
511		return this.add( this.prevObject );
512	},
513
514	domManip: function( args, table, callback ) {
515		if ( this[0] ) {
516			var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
517				scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
518				first = fragment.firstChild;
519
520			if ( first )
521				for ( var i = 0, l = this.length; i < l; i++ )
522					callback.call( root(this[i], first), this.length > 1 || i > 0 ?
523							fragment.cloneNode(true) : fragment );
524
525			if ( scripts )
526				jQuery.each( scripts, evalScript );
527		}
528
529		return this;
530
531		function root( elem, cur ) {
532			return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ?
533				(elem.getElementsByTagName("tbody")[0] ||
534				elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
535				elem;
536		}
537	}
538};
539
540// Give the init function the jQuery prototype for later instantiation
541jQuery.fn.init.prototype = jQuery.fn;
542
543function evalScript( i, elem ) {
544	if ( elem.src )
545		jQuery.ajax({
546			url: elem.src,
547			async: false,
548			dataType: "script"
549		});
550
551	else
552		jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
553
554	if ( elem.parentNode )
555		elem.parentNode.removeChild( elem );
556}
557
558function now(){
559	return +new Date;
560}
561
562jQuery.extend = jQuery.fn.extend = function() {
563	// copy reference to target object
564	var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
565
566	// Handle a deep copy situation
567	if ( typeof target === "boolean" ) {
568		deep = target;
569		target = arguments[1] || {};
570		// skip the boolean and the target
571		i = 2;
572	}
573
574	// Handle case when target is a string or something (possible in deep copy)
575	if ( typeof target !== "object" && !jQuery.isFunction(target) )
576		target = {};
577
578	// extend jQuery itself if only one argument is passed
579	if ( length == i ) {
580		target = this;
581		--i;
582	}
583
584	for ( ; i < length; i++ )
585		// Only deal with non-null/undefined values
586		if ( (options = arguments[ i ]) != null )
587			// Extend the base object
588			for ( var name in options ) {
589				var src = target[ name ], copy = options[ name ];
590
591				// Prevent never-ending loop
592				if ( target === copy )
593					continue;
594
595				// Recurse if we're merging object values
596				if ( deep && copy && typeof copy === "object" && !copy.nodeType )
597					target[ name ] = jQuery.extend( deep,
598						// Never move original objects, clone them
599						src || ( copy.length != null ? [ ] : { } )
600					, copy );
601
602				// Don't bring in undefined values
603				else if ( copy !== undefined )
604					target[ name ] = copy;
605
606			}
607
608	// Return the modified object
609	return target;
610};
611
612// exclude the following css properties to add px
613var	exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
614	// cache defaultView
615	defaultView = document.defaultView || {},
616	toString = Object.prototype.toString;
617
618jQuery.extend({
619	noConflict: function( deep ) {
620		window.$ = _$;
621
622		if ( deep )
623			window.jQuery = _jQuery;
624
625		return jQuery;
626	},
627
628	// See test/unit/core.js for details concerning isFunction.
629	// Since version 1.3, DOM methods and functions like alert
630	// aren't supported. They return false on IE (#2968).
631	isFunction: function( obj ) {
632		return toString.call(obj) === "[object Function]";
633	},
634
635	isArray: function( obj ) {
636		return toString.call(obj) === "[object Array]";
637	},
638
639	// check if an element is in a (or is an) XML document
640	isXMLDoc: function( elem ) {
641		return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
642			!!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument );
643	},
644
645	// Evalulates a script in a global context
646	globalEval: function( data ) {
647		if ( data && /\S/.test(data) ) {
648			// Inspired by code by Andrea Giammarchi
649			// http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
650			var head = document.getElementsByTagName("head")[0] || document.documentElement,
651				script = document.createElement("script");
652
653			script.type = "text/javascript";
654			if ( jQuery.support.scriptEval )
655				script.appendChild( document.createTextNode( data ) );
656			else
657				script.text = data;
658
659			// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
660			// This arises when a base node is used (#2709).
661			head.insertBefore( script, head.firstChild );
662			head.removeChild( script );
663		}
664	},
665
666	nodeName: function( elem, name ) {
667		return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
668	},
669
670	// args is for internal usage only
671	each: function( object, callback, args ) {
672		var name, i = 0, length = object.length;
673
674		if ( args ) {
675			if ( length === undefined ) {
676				for ( name in object )
677					if ( callback.apply( object[ name ], args ) === false )
678						break;
679			} else
680				for ( ; i < length; )
681					if ( callback.apply( object[ i++ ], args ) === false )
682						break;
683
684		// A special, fast, case for the most common use of each
685		} else {
686			if ( length === undefined ) {
687				for ( name in object )
688					if ( callback.call( object[ name ], name, object[ name ] ) === false )
689						break;
690			} else
691				for ( var value = object[0];
692					i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
693		}
694
695		return object;
696	},
697
698	prop: function( elem, value, type, i, name ) {
699		// Handle executable functions
700		if ( jQuery.isFunction( value ) )
701			value = value.call( elem, i );
702
703		// Handle passing in a number to a CSS property
704		return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ?
705			value + "px" :
706			value;
707	},
708
709	className: {
710		// internal only, use addClass("class")
711		add: function( elem, classNames ) {
712			jQuery.each((classNames || "").split(/\s+/), function(i, className){
713				if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
714					elem.className += (elem.className ? " " : "") + className;
715			});
716		},
717
718		// internal only, use removeClass("class")
719		remove: function( elem, classNames ) {
720			if (elem.nodeType == 1)
721				elem.className = classNames !== undefined ?
722					jQuery.grep(elem.className.split(/\s+/), function(className){
723						return !jQuery.className.has( classNames, className );
724					}).join(" ") :
725					"";
726		},
727
728		// internal only, use hasClass("class")
729		has: function( elem, className ) {
730			return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
731		}
732	},
733
734	// A method for quickly swapping in/out CSS properties to get correct calculations
735	swap: function( elem, options, callback ) {
736		var old = {};
737		// Remember the old values, and insert the new ones
738		for ( var name in options ) {
739			old[ name ] = elem.style[ name ];
740			elem.style[ name ] = options[ name ];
741		}
742
743		callback.call( elem );
744
745		// Revert the old values
746		for ( var name in options )
747			elem.style[ name ] = old[ name ];
748	},
749
750	css: function( elem, name, force, extra ) {
751		if ( name == "width" || name == "height" ) {
752			var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
753
754			function getWH() {
755				val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
756
757				if ( extra === "border" )
758					return;
759
760				jQuery.each( which, function() {
761					if ( !extra )
762						val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
763					if ( extra === "margin" )
764						val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
765					else
766						val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
767				});
768			}
769
770			if ( elem.offsetWidth !== 0 )
771				getWH();
772			else
773				jQuery.swap( elem, props, getWH );
774
775			return Math.max(0, Math.round(val));
776		}
777
778		return jQuery.curCSS( elem, name, force );
779	},
780
781	curCSS: function( elem, name, force ) {
782		var ret, style = elem.style;
783
784		// We need to handle opacity special in IE
785		if ( name == "opacity" && !jQuery.support.opacity ) {
786			ret = jQuery.attr( style, "opacity" );
787
788			return ret == "" ?
789				"1" :
790				ret;
791		}
792
793		// Make sure we're using the right name for getting the float value
794		if ( name.match( /float/i ) )
795			name = styleFloat;
796
797		if ( !force && style && style[ name ] )
798			ret = style[ name ];
799
800		else if ( defaultView.getComputedStyle ) {
801
802			// Only "float" is needed here
803			if ( name.match( /float/i ) )
804				name = "float";
805
806			name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
807
808			var computedStyle = defaultView.getComputedStyle( elem, null );
809
810			if ( computedStyle )
811				ret = computedStyle.getPropertyValue( name );
812
813			// We should always get a number back from opacity
814			if ( name == "opacity" && ret == "" )
815				ret = "1";
816
817		} else if ( elem.currentStyle ) {
818			var camelCase = name.replace(/\-(\w)/g, function(all, letter){
819				return letter.toUpperCase();
820			});
821
822			ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
823
824			// From the awesome hack by Dean Edwards
825			// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
826
827			// If we're not dealing with a regular pixel number
828			// but a number that has a weird ending, we need to convert it to pixels
829			if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
830				// Remember the original values
831				var left = style.left, rsLeft = elem.runtimeStyle.left;
832
833				// Put in the new values to get a computed value out
834				elem.runtimeStyle.left = elem.currentStyle.left;
835				style.left = ret || 0;
836				ret = style.pixelLeft + "px";
837
838				// Revert the changed values
839				style.left = left;
840				elem.runtimeStyle.left = rsLeft;
841			}
842		}
843
844		return ret;
845	},
846
847	clean: function( elems, context, fragment ) {
848		context = context || document;
849
850		// !context.createElement fails in IE with an error but returns typeof 'object'
851		if ( typeof context.createElement === "undefined" )
852			context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
853
854		// If a single string is passed in and it's a single tag
855		// just do a createElement and skip the rest
856		if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
857			var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
858			if ( match )
859				return [ context.createElement( match[1] ) ];
860		}
861
862		var ret = [], scripts = [], div = context.createElement("div");
863
864		jQuery.each(elems, function(i, elem){
865			if ( typeof elem === "number" )
866				elem += '';
867
868			if ( !elem )
869				return;
870
871			// Convert html string into DOM nodes
872			if ( typeof elem === "string" ) {
873				// Fix "XHTML"-style tags in all browsers
874				elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
875					return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
876						all :
877						front + "></" + tag + ">";
878				});
879
880				// Trim whitespace, otherwise indexOf won't work as expected
881				var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();
882
883				var wrap =
884					// option or optgroup
885					!tags.indexOf("<opt") &&
886					[ 1, "<select multiple='multiple'>", "</select>" ] ||
887
888					!tags.indexOf("<leg") &&
889					[ 1, "<fieldset>", "</fieldset>" ] ||
890
891					tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
892					[ 1, "<table>", "</table>" ] ||
893
894					!tags.indexOf("<tr") &&
895					[ 2, "<table><tbody>", "</tbody></table>" ] ||
896
897				 	// <thead> matched above
898					(!tags.indexOf("<td") || !tags.indexOf("<th")) &&
899					[ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
900
901					!tags.indexOf("<col") &&
902					[ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
903
904					// IE can't serialize <link> and <script> tags normally
905					!jQuery.support.htmlSerialize &&
906					[ 1, "div<div>", "</div>" ] ||
907
908					[ 0, "", "" ];
909
910				// Go to html and back, then peel off extra wrappers
911				div.innerHTML = wrap[1] + elem + wrap[2];
912
913				// Move to the right depth
914				while ( wrap[0]-- )
915					div = div.lastChild;
916
917				// Remove IE's autoinserted <tbody> from table fragments
918				if ( !jQuery.support.tbody ) {
919
920					// String was a <table>, *may* have spurious <tbody>
921					var hasBody = /<tbody/i.test(elem),
922						tbody = !tags.indexOf("<table") && !hasBody ?
923							div.firstChild && div.firstChild.childNodes :
924
925						// String was a bare <thead> or <tfoot>
926						wrap[1] == "<table>" && !hasBody ?
927							div.childNodes :
928							[];
929
930					for ( var j = tbody.length - 1; j >= 0 ; --j )
931						if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
932							tbody[ j ].parentNode.removeChild( tbody[ j ] );
933
934					}
935
936				// IE completely kills leading whitespace when innerHTML is used
937				if ( !jQuery.support.leadingWhitespace && /^\s/.test( elem ) )
938					div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
939
940				elem = jQuery.makeArray( div.childNodes );
941			}
942
943			if ( elem.nodeType )
944				ret.push( elem );
945			else
946				ret = jQuery.merge( ret, elem );
947
948		});
949
950		if ( fragment ) {
951			for ( var i = 0; ret[i]; i++ ) {
952				if ( jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
953					scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
954				} else {
955					if ( ret[i].nodeType === 1 )
956						ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
957					fragment.appendChild( ret[i] );
958				}
959			}
960
961			return scripts;
962		}
963
964		return ret;
965	},
966
967	attr: function( elem, name, value ) {
968		// don't set attributes on text and comment nodes
969		if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
970			return undefined;
971
972		var notxml = !jQuery.isXMLDoc( elem ),
973			// Whether we are setting (or getting)
974			set = value !== undefined;
975
976		// Try to normalize/fix the name
977		name = notxml && jQuery.props[ name ] || name;
978
979		// Only do all the following if this is a node (faster for style)
980		// IE elem.getAttribute passes even for style
981		if ( elem.tagName ) {
982
983			// These attributes require special treatment
984			var special = /href|src|style/.test( name );
985
986			// Safari mis-reports the default selected property of a hidden option
987			// Accessing the parent's selectedIndex property fixes it
988			if ( name == "selected" && elem.parentNode )
989				elem.parentNode.selectedIndex;
990
991			// If applicable, access the attribute via the DOM 0 way
992			if ( name in elem && notxml && !special ) {
993				if ( set ){
994					// We can't allow the type property to be changed (since it causes problems in IE)
995					if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
996						throw "type property can't be changed";
997
998					elem[ name ] = value;
999				}
1000
1001				// browsers index elements by id/name on forms, give priority to attributes.
1002				if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) )
1003					return elem.getAttributeNode( name ).nodeValue;
1004
1005				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
1006				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
1007				if ( name == "tabIndex" ) {
1008					var attributeNode = elem.getAttributeNode( "tabIndex" );
1009					return attributeNode && attributeNode.specified
1010						? attributeNode.value
1011						: elem.nodeName.match(/(button|input|object|select|textarea)/i)
1012							? 0
1013							: elem.nodeName.match(/^(a|area)$/i) && elem.href
1014								? 0
1015								: undefined;
1016				}
1017
1018				return elem[ name ];
1019			}
1020
1021			if ( !jQuery.support.style && notxml &&  name == "style" )
1022				return jQuery.attr( elem.style, "cssText", value );
1023
1024			if ( set )
1025				// convert the value to a string (all browsers do this but IE) see #1070
1026				elem.setAttribute( name, "" + value );
1027
1028			var attr = !jQuery.support.hrefNormalized && notxml && special
1029					// Some attributes require a special call on IE
1030					? elem.getAttribute( name, 2 )
1031					: elem.getAttribute( name );
1032
1033			// Non-existent attributes return null, we normalize to undefined
1034			return attr === null ? undefined : attr;
1035		}
1036
1037		// elem is actually elem.style ... set the style
1038
1039		// IE uses filters for opacity
1040		if ( !jQuery.support.opacity && name == "opacity" ) {
1041			if ( set ) {
1042				// IE has trouble with opacity if it does not have layout
1043				// Force it by setting the zoom level
1044				elem.zoom = 1;
1045
1046				// Set the alpha filter to set the opacity
1047				elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
1048					(parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
1049			}
1050
1051			return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
1052				(parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
1053				"";
1054		}
1055
1056		name = name.replace(/-([a-z])/ig, function(all, letter){
1057			return letter.toUpperCase();
1058		});
1059
1060		if ( set )
1061			elem[ name ] = value;
1062
1063		return elem[ name ];
1064	},
1065
1066	trim: function( text ) {
1067		return (text || "").replace( /^\s+|\s+$/g, "" );
1068	},
1069
1070	makeArray: function( array ) {
1071		var ret = [];
1072
1073		if( array != null ){
1074			var i = array.length;
1075			// The window, strings (and functions) also have 'length'
1076			if( i == null || typeof array === "string" || jQuery.isFunction(array) || array.setInterval )
1077				ret[0] = array;
1078			else
1079				while( i )
1080					ret[--i] = array[i];
1081		}
1082
1083		return ret;
1084	},
1085
1086	inArray: function( elem, array ) {
1087		for ( var i = 0, length = array.length; i < length; i++ )
1088		// Use === because on IE, window == document
1089			if ( array[ i ] === elem )
1090				return i;
1091
1092		return -1;
1093	},
1094
1095	merge: function( first, second ) {
1096		// We have to loop this way because IE & Opera overwrite the length
1097		// expando of getElementsByTagName
1098		var i = 0, elem, pos = first.length;
1099		// Also, we need to make sure that the correct elements are being returned
1100		// (IE returns comment nodes in a '*' query)
1101		if ( !jQuery.support.getAll ) {
1102			while ( (elem = second[ i++ ]) != null )
1103				if ( elem.nodeType != 8 )
1104					first[ pos++ ] = elem;
1105
1106		} else
1107			while ( (elem = second[ i++ ]) != null )
1108				first[ pos++ ] = elem;
1109
1110		return first;
1111	},
1112
1113	unique: function( array ) {
1114		var ret = [], done = {};
1115
1116		try {
1117
1118			for ( var i = 0, length = array.length; i < length; i++ ) {
1119				var id = jQuery.data( array[ i ] );
1120
1121				if ( !done[ id ] ) {
1122					done[ id ] = true;
1123					ret.push( array[ i ] );
1124				}
1125			}
1126
1127		} catch( e ) {
1128			ret = array;
1129		}
1130
1131		return ret;
1132	},
1133
1134	grep: function( elems, callback, inv ) {
1135		var ret = [];
1136
1137		// Go through the array, only saving the items
1138		// that pass the validator function
1139		for ( var i = 0, length = elems.length; i < length; i++ )
1140			if ( !inv != !callback( elems[ i ], i ) )
1141				ret.push( elems[ i ] );
1142
1143		return ret;
1144	},
1145
1146	map: function( elems, callback ) {
1147		var ret = [];
1148
1149		// Go through the array, translating each of the items to their
1150		// new value (or values).
1151		for ( var i = 0, length = elems.length; i < length; i++ ) {
1152			var value = callback( elems[ i ], i );
1153
1154			if ( value != null )
1155				ret[ ret.length ] = value;
1156		}
1157
1158		return ret.concat.apply( [], ret );
1159	}
1160});
1161
1162// Use of jQuery.browser is deprecated.
1163// It's included for backwards compatibility and plugins,
1164// although they should work to migrate away.
1165
1166var userAgent = navigator.userAgent.toLowerCase();
1167
1168// Figure out what browser is being used
1169jQuery.browser = {
1170	version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1],
1171	safari: /webkit/.test( userAgent ),
1172	opera: /opera/.test( userAgent ),
1173	msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
1174	mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
1175};
1176
1177jQuery.each({
1178	parent: function(elem){return elem.parentNode;},
1179	parents: function(elem){return jQuery.dir(elem,"parentNode");},
1180	next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
1181	prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
1182	nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
1183	prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
1184	siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
1185	children: function(elem){return jQuery.sibling(elem.firstChild);},
1186	contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
1187}, function(name, fn){
1188	jQuery.fn[ name ] = function( selector ) {
1189		var ret = jQuery.map( this, fn );
1190
1191		if ( selector && typeof selector == "string" )
1192			ret = jQuery.multiFilter( selector, ret );
1193
1194		return this.pushStack( jQuery.unique( ret ), name, selector );
1195	};
1196});
1197
1198jQuery.each({
1199	appendTo: "append",
1200	prependTo: "prepend",
1201	insertBefore: "before",
1202	insertAfter: "after",
1203	replaceAll: "replaceWith"
1204}, function(name, original){
1205	jQuery.fn[ name ] = function( selector ) {
1206		var ret = [], insert = jQuery( selector );
1207
1208		for ( var i = 0, l = insert.length; i < l; i++ ) {
1209			var elems = (i > 0 ? this.clone(true) : this).get();
1210			jQuery.fn[ original ].apply( jQuery(insert[i]), elems );
1211			ret = ret.concat( elems );
1212		}
1213
1214		return this.pushStack( ret, name, selector );
1215	};
1216});
1217
1218jQuery.each({
1219	removeAttr: function( name ) {
1220		jQuery.attr( this, name, "" );
1221		if (this.nodeType == 1)
1222			this.removeAttribute( name );
1223	},
1224
1225	addClass: function( classNames ) {
1226		jQuery.className.add( this, classNames );
1227	},
1228
1229	removeClass: function( classNames ) {
1230		jQuery.className.remove( this, classNames );
1231	},
1232
1233	toggleClass: function( classNames, state ) {
1234		if( typeof state !== "boolean" )
1235			state = !jQuery.className.has( this, classNames );
1236		jQuery.className[ state ? "add" : "remove" ]( this, classNames );
1237	},
1238
1239	remove: function( selector ) {
1240		if ( !selector || jQuery.filter( selector, [ this ] ).length ) {
1241			// Prevent memory leaks
1242			jQuery( "*", this ).add([this]).each(function(){
1243				jQuery.event.remove(this);
1244				jQuery.removeData(this);
1245			});
1246			if (this.parentNode)
1247				this.parentNode.removeChild( this );
1248		}
1249	},
1250
1251	empty: function() {
1252		// Remove element nodes and prevent memory leaks
1253		jQuery(this).children().remove();
1254
1255		// Remove any remaining nodes
1256		while ( this.firstChild )
1257			this.removeChild( this.firstChild );
1258	}
1259}, function(name, fn){
1260	jQuery.fn[ name ] = function(){
1261		return this.each( fn, arguments );
1262	};
1263});
1264
1265// Helper function used by the dimensions and offset modules
1266function num(elem, prop) {
1267	return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
1268}
1269var expando = "jQuery" + now(), uuid = 0, windowData = {};
1270
1271jQuery.extend({
1272	cache: {},
1273
1274	data: function( elem, name, data ) {
1275		elem = elem == window ?
1276			windowData :
1277			elem;
1278
1279		var id = elem[ expando ];
1280
1281		// Compute a unique ID for the element
1282		if ( !id )
1283			id = elem[ expando ] = ++uuid;
1284
1285		// Only generate the data cache if we're
1286		// trying to access or manipulate it
1287		if ( name && !jQuery.cache[ id ] )
1288			jQuery.cache[ id ] = {};
1289
1290		// Prevent overriding the named cache with undefined values
1291		if ( data !== undefined )
1292			jQuery.cache[ id ][ name ] = data;
1293
1294		// Return the named cache data, or the ID for the element
1295		return name ?
1296			jQuery.cache[ id ][ name ] :
1297			id;
1298	},
1299
1300	removeData: function( elem, name ) {
1301		elem = elem == window ?
1302			windowData :
1303			elem;
1304
1305		var id = elem[ expando ];
1306
1307		// If we want to remove a specific section of the element's data
1308		if ( name ) {
1309			if ( jQuery.cache[ id ] ) {
1310				// Remove the section of cache data
1311				delete jQuery.cache[ id ][ name ];
1312
1313				// If we've removed all the data, remove the element's cache
1314				name = "";
1315
1316				for ( name in jQuery.cache[ id ] )
1317					break;
1318
1319				if ( !name )
1320					jQuery.removeData( elem );
1321			}
1322
1323		// Otherwise, we want to remove all of the element's data
1324		} else {
1325			// Clean up the element expando
1326			try {
1327				delete elem[ expando ];
1328			} catch(e){
1329				// IE has trouble directly removing the expando
1330				// but it's ok with using removeAttribute
1331				if ( elem.removeAttribute )
1332					elem.removeAttribute( expando );
1333			}
1334
1335			// Completely remove the data cache
1336			delete jQuery.cache[ id ];
1337		}
1338	},
1339	queue: function( elem, type, data ) {
1340		if ( elem ){
1341
1342			type = (type || "fx") + "queue";
1343
1344			var q = jQuery.data( elem, type );
1345
1346			if ( !q || jQuery.isArray(data) )
1347				q = jQuery.data( elem, type, jQuery.makeArray(data) );
1348			else if( data )
1349				q.push( data );
1350
1351		}
1352		return q;
1353	},
1354
1355	dequeue: function( elem, type ){
1356		var queue = jQuery.queue( elem, type ),
1357			fn = queue.shift();
1358
1359		if( !type || type === "fx" )
1360			fn = queue[0];
1361
1362		if( fn !== undefined )
1363			fn.call(elem);
1364	}
1365});
1366
1367jQuery.fn.extend({
1368	data: function( key, value ){
1369		var parts = key.split(".");
1370		parts[1] = parts[1] ? "." + parts[1] : "";
1371
1372		if ( value === undefined ) {
1373			var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
1374
1375			if ( data === undefined && this.length )
1376				data = jQuery.data( this[0], key );
1377
1378			return data === undefined && parts[1] ?
1379				this.data( parts[0] ) :
1380				data;
1381		} else
1382			return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
1383				jQuery.data( this, key, value );
1384			});
1385	},
1386
1387	removeData: function( key ){
1388		return this.each(function(){
1389			jQuery.removeData( this, key );
1390		});
1391	},
1392	queue: function(type, data){
1393		if ( typeof type !== "string" ) {
1394			data = type;
1395			type = "fx";
1396		}
1397
1398		if ( data === undefined )
1399			return jQuery.queue( this[0], type );
1400
1401		return this.each(function(){
1402			var queue = jQuery.queue( this, type, data );
1403
1404			 if( type == "fx" && queue.length == 1 )
1405				queue[0].call(this);
1406		});
1407	},
1408	dequeue: function(type){
1409		return this.each(function(){
1410			jQuery.dequeue( this, type );
1411		});
1412	}
1413});/*!
1414 * Sizzle CSS Selector Engine - v0.9.3
1415 *  Copyright 2009, The Dojo Foundation
1416 *  Released under the MIT, BSD, and GPL Licenses.
1417 *  More information: http://sizzlejs.com/
1418 */
1419(function(){
1420
1421var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
1422	done = 0,
1423	toString = Object.prototype.toString;
1424
1425var Sizzle = function(selector, context, results, seed) {
1426	results = results || [];
1427	context = context || document;
1428
1429	if ( context.nodeType !== 1 && context.nodeType !== 9 )
1430		return [];
1431
1432	if ( !selector || typeof selector !== "string" ) {
1433		return results;
1434	}
1435
1436	var parts = [], m, set, checkSet, check, mode, extra, prune = true;
1437
1438	// Reset the position of the chunker regexp (start from head)
1439	chunker.lastIndex = 0;
1440
1441	while ( (m = chunker.exec(selector)) !== null ) {
1442		parts.push( m[1] );
1443
1444		if ( m[2] ) {
1445			extra = RegExp.rightContext;
1446			break;
1447		}
1448	}
1449
1450	if ( parts.length > 1 && origPOS.exec( selector ) ) {
1451		if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
1452			set = posProcess( parts[0] + parts[1], context );
1453		} else {
1454			set = Expr.relative[ parts[0] ] ?
1455				[ context ] :
1456				Sizzle( parts.shift(), context );
1457
1458			while ( parts.length ) {
1459				selector = parts.shift();
1460
1461				if ( Expr.relative[ selector ] )
1462					selector += parts.shift();
1463
1464				set = posProcess( selector, set );
1465			}
1466		}
1467	} else {
1468		var ret = seed ?
1469			{ expr: parts.pop(), set: makeArray(seed) } :
1470			Sizzle.find( parts.pop(), parts.length === 1 && context.parentNode ? context.parentNode : context, isXML(context) );
1471		set = Sizzle.filter( ret.expr, ret.set );
1472
1473		if ( parts.length > 0 ) {
1474			checkSet = makeArray(set);
1475		} else {
1476			prune = false;
1477		}
1478
1479		while ( parts.length ) {
1480			var cur = parts.pop(), pop = cur;
1481
1482			if ( !Expr.relative[ cur ] ) {
1483				cur = "";
1484			} else {
1485				pop = parts.pop();
1486			}
1487
1488			if ( pop == null ) {
1489				pop = context;
1490			}
1491
1492			Expr.relative[ cur ]( checkSet, pop, isXML(context) );
1493		}
1494	}
1495
1496	if ( !checkSet ) {
1497		checkSet = set;
1498	}
1499
1500	if ( !checkSet ) {
1501		throw "Syntax error, unrecognized expression: " + (cur || selector);
1502	}
1503
1504	if ( toString.call(checkSet) === "[object Array]" ) {
1505		if ( !prune ) {
1506			results.push.apply( results, checkSet );
1507		} else if ( context.nodeType === 1 ) {
1508			for ( var i = 0; checkSet[i] != null; i++ ) {
1509				if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
1510					results.push( set[i] );
1511				}
1512			}
1513		} else {
1514			for ( var i = 0; checkSet[i] != null; i++ ) {
1515				if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
1516					results.push( set[i] );
1517				}
1518			}
1519		}
1520	} else {
1521		makeArray( checkSet, results );
1522	}
1523
1524	if ( extra ) {
1525		Sizzle( extra, context, results, seed );
1526
1527		if ( sortOrder ) {
1528			hasDuplicate = false;
1529			results.sort(sortOrder);
1530
1531			if ( hasDuplicate ) {
1532				for ( var i = 1; i < results.length; i++ ) {
1533					if ( results[i] === results[i-1] ) {
1534						results.splice(i--, 1);
1535					}
1536				}
1537			}
1538		}
1539	}
1540
1541	return results;
1542};
1543
1544Sizzle.matches = function(expr, set){
1545	return Sizzle(expr, null, null, set);
1546};
1547
1548Sizzle.find = function(expr, context, isXML){
1549	var set, match;
1550
1551	if ( !expr ) {
1552		return [];
1553	}
1554
1555	for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
1556		var type = Expr.order[i], match;
1557
1558		if ( (match = Expr.match[ type ].exec( expr )) ) {
1559			var left = RegExp.leftContext;
1560
1561			if ( left.substr( left.length - 1 ) !== "\\" ) {
1562				match[1] = (match[1] || "").replace(/\\/g, "");
1563				set = Expr.find[ type ]( match, context, isXML );
1564				if ( set != null ) {
1565					expr = expr.replace( Expr.match[ type ], "" );
1566					break;
1567				}
1568			}
1569		}
1570	}
1571
1572	if ( !set ) {
1573		set = context.getElementsByTagName("*");
1574	}
1575
1576	return {set: set, expr: expr};
1577};
1578
1579Sizzle.filter = function(expr, set, inplace, not){
1580	var old = expr, result = [], curLoop = set, match, anyFound,
1581		isXMLFilter = set && set[0] && isXML(set[0]);
1582
1583	while ( expr && set.length ) {
1584		for ( var type in Expr.filter ) {
1585			if ( (match = Expr.match[ type ].exec( expr )) != null ) {
1586				var filter = Expr.filter[ type ], found, item;
1587				anyFound = false;
1588
1589				if ( curLoop == result ) {
1590					result = [];
1591				}
1592
1593				if ( Expr.preFilter[ type ] ) {
1594					match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
1595
1596					if ( !match ) {
1597						anyFound = found = true;
1598					} else if ( match === true ) {
1599						continue;
1600					}
1601				}
1602
1603				if ( match ) {
1604					for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
1605						if ( item ) {
1606							found = filter( item, match, i, curLoop );
1607							var pass = not ^ !!found;
1608
1609							if ( inplace && found != null ) {
1610								if ( pass ) {
1611									anyFound = true;
1612								} else {
1613									curLoop[i] = false;
1614								}
1615							} else if ( pass ) {
1616								result.push( item );
1617								anyFound = true;
1618							}
1619						}
1620					}
1621				}
1622
1623				if ( found !== undefined ) {
1624					if ( !inplace ) {
1625						curLoop = result;
1626					}
1627
1628					expr = expr.replace( Expr.match[ type ], "" );
1629
1630					if ( !anyFound ) {
1631						return [];
1632					}
1633
1634					break;
1635				}
1636			}
1637		}
1638
1639		// Improper expression
1640		if ( expr == old ) {
1641			if ( anyFound == null ) {
1642				throw "Syntax error, unrecognized expression: " + expr;
1643			} else {
1644				break;
1645			}
1646		}
1647
1648		old = expr;
1649	}
1650
1651	return curLoop;
1652};
1653
1654var Expr = Sizzle.selectors = {
1655	order: [ "ID", "NAME", "TAG" ],
1656	match: {
1657		ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
1658		CLASS: /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
1659		NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,
1660		ATTR: /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
1661		TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
1662		CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
1663		POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
1664		PSEUDO: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
1665	},
1666	attrMap: {
1667		"class": "className",
1668		"for": "htmlFor"
1669	},
1670	attrHandle: {
1671		href: function(elem){
1672			return elem.getAttribute("href");
1673		}
1674	},
1675	relative: {
1676		"+": function(checkSet, part, isXML){
1677			var isPartStr = typeof part === "string",
1678				isTag = isPartStr && !/\W/.test(part),
1679				isPartStrNotTag = isPartStr && !isTag;
1680
1681			if ( isTag && !isXML ) {
1682				part = part.toUpperCase();
1683			}
1684
1685			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
1686				if ( (elem = checkSet[i]) ) {
1687					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
1688
1689					checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
1690						elem || false :
1691						elem === part;
1692				}
1693			}
1694
1695			if ( isPartStrNotTag ) {
1696				Sizzle.filter( part, checkSet, true );
1697			}
1698		},
1699		">": function(checkSet, part, isXML){
1700			var isPartStr = typeof part === "string";
1701
1702			if ( isPartStr && !/\W/.test(part) ) {
1703				part = isXML ? part : part.toUpperCase();
1704
1705				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
1706					var elem = checkSet[i];
1707					if ( elem ) {
1708						var parent = elem.parentNode;
1709						checkSet[i] = parent.nodeName === part ? parent : false;
1710					}
1711				}
1712			} else {
1713				for ( var i = 0, l = checkSet.length; i < l; i++ ) {
1714					var elem = checkSet[i];
1715					if ( elem ) {
1716						checkSet[i] = isPartStr ?
1717							elem.parentNode :
1718							elem.parentNode === part;
1719					}
1720				}
1721
1722				if ( isPartStr ) {
1723					Sizzle.filter( part, checkSet, true );
1724				}
1725			}
1726		},
1727		"": function(checkSet, part, isXML){
1728			var doneName = done++, checkFn = dirCheck;
1729
1730			if ( !part.match(/\W/) ) {
1731				var nodeCheck = part = isXML ? part : part.toUpperCase();
1732				checkFn = dirNodeCheck;
1733			}
1734
1735			checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
1736		},
1737		"~": function(checkSet, part, isXML){
1738			var doneName = done++, checkFn = dirCheck;
1739
1740			if ( typeof part === "string" && !part.match(/\W/) ) {
1741				var nodeCheck = part = isXML ? part : part.toUpperCase();
1742				checkFn = dirNodeCheck;
1743			}
1744
1745			checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
1746		}
1747	},
1748	find: {
1749		ID: function(match, context, isXML){
1750			if ( typeof context.getElementById !== "undefined" && !isXML ) {
1751				var m = context.getElementById(match[1]);
1752				return m ? [m] : [];
1753			}
1754		},
1755		NAME: function(match, context, isXML){
1756			if ( typeof context.getElementsByName !== "undefined" ) {
1757				var ret = [], results = context.getElementsByName(match[1]);
1758
1759				for ( var i = 0, l = results.length; i < l; i++ ) {
1760					if ( results[i].getAttribute("name") === match[1] ) {
1761						ret.push( results[i] );
1762					}
1763				}
1764
1765				return ret.length === 0 ? null : ret;
1766			}
1767		},
1768		TAG: function(match, context){
1769			return context.getElementsByTagName(match[1]);
1770		}
1771	},
1772	preFilter: {
1773		CLASS: function(match, curLoop, inplace, result, not, isXML){
1774			match = " " + match[1].replace(/\\/g, "") + " ";
1775
1776			if ( isXML ) {
1777				return match;
1778			}
1779
1780			for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
1781				if ( elem ) {
1782					if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
1783						if ( !inplace )
1784							result.push( elem );
1785					} else if ( inplace ) {
1786						curLoop[i] = false;
1787					}
1788				}
1789			}
1790
1791			return false;
1792		},
1793		ID: function(match){
1794			return match[1].replace(/\\/g, "");
1795		},
1796		TAG: function(match, curLoop){
1797			for ( var i = 0; curLoop[i] === false; i++ ){}
1798			return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
1799		},
1800		CHILD: function(match){
1801			if ( match[1] == "nth" ) {
1802				// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
1803				var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
1804					match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
1805					!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
1806
1807				// calculate the numbers (first)n+(last) including if they are negative
1808				match[2] = (test[1] + (test[2] || 1)) - 0;
1809				match[3] = test[3] - 0;
1810			}
1811
1812			// TODO: Move to normal caching system
1813			match[0] = done++;
1814
1815			return match;
1816		},
1817		ATTR: function(match, curLoop, inplace, result, not, isXML){
1818			var name = match[1].replace(/\\/g, "");
1819
1820			if ( !isXML && Expr.attrMap[name] ) {
1821				match[1] = Expr.attrMap[name];
1822			}
1823
1824			if ( match[2] === "~=" ) {
1825				match[4] = " " + match[4] + " ";
1826			}
1827
1828			return match;
1829		},
1830		PSEUDO: function(match, curLoop, inplace, result, not){
1831			if ( match[1] === "not" ) {
1832				// If we're dealing with a complex expression, or a simple one
1833				if ( match[3].match(chunker).length > 1 || /^\w/.test(match[3]) ) {
1834					match[3] = Sizzle(match[3], null, null, curLoop);
1835				} else {
1836					var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
1837					if ( !inplace ) {
1838						result.push.apply( result, ret );
1839					}
1840					return false;
1841				}
1842			} else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
1843				return true;
1844			}
1845
1846			return match;
1847		},
1848		POS: function(match){
1849			match.unshift( true );
1850			return match;
1851		}
1852	},
1853	filters: {
1854		enabled: function(elem){
1855			return elem.disabled === false && elem.type !== "hidden";
1856		},
1857		disabled: function(elem){
1858			return elem.disabled === true;
1859		},
1860		checked: function(elem){
1861			return elem.checked === true;
1862		},
1863		selected: function(elem){
1864			// Accessing this property makes selected-by-default
1865			// options in Safari work properly
1866			elem.parentNode.selectedIndex;
1867			return elem.selected === true;
1868		},
1869		parent: function(elem){
1870			return !!elem.firstChild;
1871		},
1872		empty: function(elem){
1873			return !elem.firstChild;
1874		},
1875		has: function(elem, i, match){
1876			return !!Sizzle( match[3], elem ).length;
1877		},
1878		header: function(elem){
1879			return /h\d/i.test( elem.nodeName );
1880		},
1881		text: function(elem){
1882			return "text" === elem.type;
1883		},
1884		radio: function(elem){
1885			return "radio" === elem.type;
1886		},
1887		checkbox: function(elem){
1888			return "checkbox" === elem.type;
1889		},
1890		file: function(elem){
1891			return "file" === elem.type;
1892		},
1893		password: function(elem){
1894			return "password" === elem.type;
1895		},
1896		submit: function(elem){
1897			return "submit" === elem.type;
1898		},
1899		image: function(elem){
1900			return "image" === elem.type;
1901		},
1902		reset: function(elem){
1903			return "reset" === elem.type;
1904		},
1905		button: function(elem){
1906			return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
1907		},
1908		input: function(elem){
1909			return /input|select|textarea|button/i.test(elem.nodeName);
1910		}
1911	},
1912	setFilters: {
1913		first: function(elem, i){
1914			return i === 0;
1915		},
1916		last: function(elem, i, match, array){
1917			return i === array.length - 1;
1918		},
1919		even: function(elem, i){
1920			return i % 2 === 0;
1921		},
1922		odd: function(elem, i){
1923			return i % 2 === 1;
1924		},
1925		lt: function(elem, i, match){
1926			return i < match[3] - 0;
1927		},
1928		gt: function(elem, i, match){
1929			return i > match[3] - 0;
1930		},
1931		nth: function(elem, i, match){
1932			return match[3] - 0 == i;
1933		},
1934		eq: function(elem, i, match){
1935			return match[3] - 0 == i;
1936		}
1937	},
1938	filter: {
1939		PSEUDO: function(elem, match, i, array){
1940			var name = match[1], filter = Expr.filters[ name ];
1941
1942			if ( filter ) {
1943				return filter( elem, i, match, array );
1944			} else if ( name === "contains" ) {
1945				return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
1946			} else if ( name === "not" ) {
1947				var not = match[3];
1948
1949				for ( var i = 0, l = not.length; i < l; i++ ) {
1950					if ( not[i] === elem ) {
1951						return false;
1952					}
1953				}
1954
1955				return true;
1956			}
1957		},
1958		CHILD: function(elem, match){
1959			var type = match[1], node = elem;
1960			switch (type) {
1961				case 'only':
1962				case 'first':
1963					while (node = node.previousSibling)  {
1964						if ( node.nodeType === 1 ) return false;
1965					}
1966					if ( type == 'first') return true;
1967					node = elem;
1968				case 'last':
1969					while (node = node.nextSibling)  {
1970						if ( node.nodeType === 1 ) return false;
1971					}
1972					return true;
1973				case 'nth':
1974					var first = match[2], last = match[3];
1975
1976					if ( first == 1 && last == 0 ) {
1977						return true;
1978					}
1979
1980					var doneName = match[0],
1981						parent = elem.parentNode;
1982
1983					if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
1984						var count = 0;
1985						for ( node = parent.firstChild; node; node = node.nextSibling ) {
1986							if ( node.nodeType === 1 ) {
1987								node.nodeIndex = ++count;
1988							}
1989						}
1990						parent.sizcache = doneName;
1991					}
1992
1993					var diff = elem.nodeIndex - last;
1994					if ( first == 0 ) {
1995						return diff == 0;
1996					} else {
1997						return ( diff % first == 0 && diff / first >= 0 );
1998					}
1999			}
2000		},
2001		ID: function(elem, match){
2002			return elem.nodeType === 1 && elem.getAttribute("id") === match;
2003		},
2004		TAG: function(elem, match){
2005			return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
2006		},
2007		CLASS: function(elem, match){
2008			return (" " + (elem.className || elem.getAttribute("class")) + " ")
2009				.indexOf( match ) > -1;
2010		},
2011		ATTR: function(elem, match){
2012			var name = match[1],
2013				result = Expr.attrHandle[ name ] ?
2014					Expr.attrHandle[ name ]( elem ) :
2015					elem[ name ] != null ?
2016						elem[ name ] :
2017						elem.getAttribute( name ),
2018				value = result + "",
2019				type = match[2],
2020				check = match[4];
2021
2022			return result == null ?
2023				type === "!=" :
2024				type === "=" ?
2025				value === check :
2026				type === "*=" ?
2027				value.indexOf(check) >= 0 :
2028				type === "~=" ?
2029				(" " + value + " ").indexOf(check) >= 0 :
2030				!check ?
2031				value && result !== false :
2032				type === "!=" ?
2033				value != check :
2034				type === "^=" ?
2035				value.indexOf(check) === 0 :
2036				type === "$=" ?
2037				value.substr(value.length - check.length) === check :
2038				type === "|=" ?
2039				value === check || value.substr(0, check.length + 1) === check + "-" :
2040				false;
2041		},
2042		POS: function(elem, match, i, array){
2043			var name = match[2], filter = Expr.setFilters[ name ];
2044
2045			if ( filter ) {
2046				return filter( elem, i, match, array );
2047			}
2048		}
2049	}
2050};
2051
2052var origPOS = Expr.match.POS;
2053
2054for ( var type in Expr.match ) {
2055	Expr.match[ type ] = RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
2056}
2057
2058var makeArray = function(array, results) {
2059	array = Array.prototype.slice.call( array );
2060
2061	if ( results ) {
2062		results.push.apply( results, array );
2063		return results;
2064	}
2065
2066	return array;
2067};
2068
2069// Perform a simple check to determine if the browser is capable of
2070// converting a NodeList to an array using builtin methods.
2071try {
2072	Array.prototype.slice.call( document.documentElement.childNodes );
2073
2074// Provide a fallback method if it does not work
2075} catch(e){
2076	makeArray = function(array, results) {
2077		var ret = results || [];
2078
2079		if ( toString.call(array) === "[object Array]" ) {
2080			Array.prototype.push.apply( ret, array );
2081		} else {
2082			if ( typeof array.length === "number" ) {
2083				for ( var i = 0, l = array.length; i < l; i++ ) {
2084					ret.push( array[i] );
2085				}
2086			} else {
2087				for ( var i = 0; array[i]; i++ ) {
2088					ret.push( array[i] );
2089				}
2090			}
2091		}
2092
2093		return ret;
2094	};
2095}
2096
2097var sortOrder;
2098
2099if ( document.documentElement.compareDocumentPosition ) {
2100	sortOrder = function( a, b ) {
2101		var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
2102		if ( ret === 0 ) {
2103			hasDuplicate = true;
2104		}
2105		return ret;
2106	};
2107} else if ( "sourceIndex" in document.documentElement ) {
2108	sortOrder = function( a, b ) {
2109		var ret = a.sourceIndex - b.sourceIndex;
2110		if ( ret === 0 ) {
2111			hasDuplicate = true;
2112		}
2113		return ret;
2114	};
2115} else if ( document.createRange ) {
2116	sortOrder = function( a, b ) {
2117		var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
2118		aRange.selectNode(a);
2119		aRange.collapse(true);
2120		bRange.selectNode(b);
2121		bRange.collapse(true);
2122		var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
2123		if ( ret === 0 ) {
2124			hasDuplicate = true;
2125		}
2126		return ret;
2127	};
2128}
2129
2130// Check to see if the browser returns elements by name when
2131// querying by getElementById (and provide a workaround)
2132(function(){
2133	// We're going to inject a fake input element with a specified name
2134	var form = document.createElement("form"),
2135		id = "script" + (new Date).getTime();
2136	form.innerHTML = "<input name='" + id + "'/>";
2137
2138	// Inject it into the root element, check its status, and remove it quickly
2139	var root = document.documentElement;
2140	root.insertBefore( form, root.firstChild );
2141
2142	// The workaround has to do additional checks after a getElementById
2143	// Which slows things down for other browsers (hence the branching)
2144	if ( !!document.getElementById( id ) ) {
2145		Expr.find.ID = function(match, context, isXML){
2146			if ( typeof context.getElementById !== "undefined" && !isXML ) {
2147				var m = context.getElementById(match[1]);
2148				return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
2149			}
2150		};
2151
2152		Expr.filter.ID = function(elem, match){
2153			var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
2154			return elem.nodeType === 1 && node && node.nodeValue === match;
2155		};
2156	}
2157
2158	root.removeChild( form );
2159})();
2160
2161(function(){
2162	// Check to see if the browser returns only elements
2163	// when doing getElementsByTagName("*")
2164
2165	// Create a fake element
2166	var div = document.createElement("div");
2167	div.appendChild( document.createComment("") );
2168
2169	// Make sure no comments are found
2170	if ( div.getElementsByTagName("*").length > 0 ) {
2171		Expr.find.TAG = function(match, context){
2172			var results = context.getElementsByTagName(match[1]);
2173
2174			// Filter out possible comments
2175			if ( match[1] === "*" ) {
2176				var tmp = [];
2177
2178				for ( var i = 0; results[i]; i++ ) {
2179					if ( results[i].nodeType === 1 ) {
2180						tmp.push( results[i] );
2181					}
2182				}
2183
2184				results = tmp;
2185			}
2186
2187			return results;
2188		};
2189	}
2190
2191	// Check to see if an attribute returns normalized href attributes
2192	div.innerHTML = "<a href='#'></a>";
2193	if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
2194			div.firstChild.getAttribute("href") !== "#" ) {
2195		Expr.attrHandle.href = function(elem){
2196			return elem.getAttribute("href", 2);
2197		};
2198	}
2199})();
2200
2201if ( document.querySelectorAll ) (function(){
2202	var oldSizzle = Sizzle, div = document.createElement("div");
2203	div.innerHTML = "<p class='TEST'></p>";
2204
2205	// Safari can't handle uppercase or unicode characters when
2206	// in quirks mode.
2207	if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
2208		return;
2209	}
2210
2211	Sizzle = function(query, context, extra, seed){
2212		context = context || document;
2213
2214		// Only use querySelectorAll on non-XML documents
2215		// (ID selectors don't work in non-HTML documents)
2216		if ( !seed && context.nodeType === 9 && !isXML(context) ) {
2217			try {
2218				return makeArray( context.querySelectorAll(query), extra );
2219			} catch(e){}
2220		}
2221
2222		return oldSizzle(query, context, extra, seed);
2223	};
2224
2225	Sizzle.find = oldSizzle.find;
2226	Sizzle.filter = oldSizzle.filter;
2227	Sizzle.selectors = oldSizzle.selectors;
2228	Sizzle.matches = oldSizzle.matches;
2229})();
2230
2231if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
2232	var div = document.createElement("div");
2233	div.innerHTML = "<div class='test e'></div><div class='test'></div>";
2234
2235	// Opera can't find a second classname (in 9.6)
2236	if ( div.getElementsByClassName("e").length === 0 )
2237		return;
2238
2239	// Safari caches class attributes, doesn't catch changes (in 3.2)
2240	div.lastChild.className = "e";
2241
2242	if ( div.getElementsByClassName("e").length === 1 )
2243		return;
2244
2245	Expr.order.splice(1, 0, "CLASS");
2246	Expr.find.CLASS = function(match, context, isXML) {
2247		if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
2248			return context.getElementsByClassName(match[1]);
2249		}
2250	};
2251})();
2252
2253function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
2254	var sibDir = dir == "previousSibling" && !isXML;
2255	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
2256		var elem = checkSet[i];
2257		if ( elem ) {
2258			if ( sibDir && elem.nodeType === 1 ){
2259				elem.sizcache = doneName;
2260				elem.sizset = i;
2261			}
2262			elem = elem[dir];
2263			var match = false;
2264
2265			while ( elem ) {
2266				if ( elem.sizcache === doneName ) {
2267					match = checkSet[elem.sizset];
2268					break;
2269				}
2270
2271				if ( elem.nodeType === 1 && !isXML ){
2272					elem.sizcache = doneName;
2273					elem.sizset = i;
2274				}
2275
2276				if ( elem.nodeName === cur ) {
2277					match = elem;
2278					break;
2279				}
2280
2281				elem = elem[dir];
2282			}
2283
2284			checkSet[i] = match;
2285		}
2286	}
2287}
2288
2289function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
2290	var sibDir = dir == "previousSibling" && !isXML;
2291	for ( var i = 0, l = checkSet.length; i < l; i++ ) {
2292		var elem = checkSet[i];
2293		if ( elem ) {
2294			if ( sibDir && elem.nodeType === 1 ) {
2295				elem.sizcache = doneName;
2296				elem.sizset = i;
2297			}
2298			elem = elem[dir];
2299			var match = false;
2300
2301			while ( elem ) {
2302				if ( elem.sizcache === doneName ) {
2303					match = checkSet[elem.sizset];
2304					break;
2305				}
2306
2307				if ( elem.nodeType === 1 ) {
2308					if ( !isXML ) {
2309						elem.sizcache = doneName;
2310						elem.sizset = i;
2311					}
2312					if ( typeof cur !== "string" ) {
2313						if ( elem === cur ) {
2314							match = true;
2315							break;
2316						}
2317
2318					} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
2319						match = elem;
2320						break;
2321					}
2322				}
2323
2324				elem = elem[dir];
2325			}
2326
2327			checkSet[i] = match;
2328		}
2329	}
2330}
2331
2332var contains = document.compareDocumentPosition ?  function(a, b){
2333	return a.compareDocumentPosition(b) & 16;
2334} : function(a, b){
2335	return a !== b && (a.contains ? a.contains(b) : true);
2336};
2337
2338var isXML = function(elem){
2339	return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
2340		!!elem.ownerDocument && isXML( elem.ownerDocument );
2341};
2342
2343var posProcess = function(selector, context){
2344	var tmpSet = [], later = "", match,
2345		root = context.nodeType ? [context] : context;
2346
2347	// Position selectors must be done after the filter
2348	// And so must :not(positional) so we move all PSEUDOs to the end
2349	while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
2350		later += match[0];
2351		selector = selector.replace( Expr.match.PSEUDO, "" );
2352	}
2353
2354	selector = Expr.relative[selector] ? selector + "*" : selector;
2355
2356	for ( var i = 0, l = root.length; i < l; i++ ) {
2357		Sizzle( selector, root[i], tmpSet );
2358	}
2359
2360	return Sizzle.filter( later, tmpSet );
2361};
2362
2363// EXPOSE
2364jQuery.find = Sizzle;
2365jQuery.filter = Sizzle.filter;
2366jQuery.expr = Sizzle.selectors;
2367jQuery.expr[":"] = jQuery.expr.filters;
2368
2369Sizzle.selectors.filters.hidden = function(elem){
2370	return elem.offsetWidth === 0 || elem.offsetHeight === 0;
2371};
2372
2373Sizzle.selectors.filters.visible = function(elem){
2374	return elem.offsetWidth > 0 || elem.offsetHeight > 0;
2375};
2376
2377Sizzle.selectors.filters.animated = function(elem){
2378	return jQuery.grep(jQuery.timers, function(fn){
2379		return elem === fn.elem;
2380	}).length;
2381};
2382
2383jQuery.multiFilter = function( expr, elems, not ) {
2384	if ( not ) {
2385		expr = ":not(" + expr + ")";
2386	}
2387
2388	return Sizzle.matches(expr, elems);
2389};
2390
2391jQuery.dir = function( elem, dir ){
2392	var matched = [], cur = elem[dir];
2393	while ( cur && cur != document ) {
2394		if ( cur.nodeType == 1 )
2395			matched.push( cur );
2396		cur = cur[dir];
2397	}
2398	return matched;
2399};
2400
2401jQuery.nth = function(cur, result, dir, elem){
2402	result = result || 1;
2403	var num = 0;
2404
2405	for ( ; cur; cur = cur[dir] )
2406		if ( cur.nodeType == 1 && ++num == result )
2407			break;
2408
2409	return cur;
2410};
2411
2412jQuery.sibling = function(n, elem){
2413	var r = [];
2414
2415	for ( ; n; n = n.nextSibling ) {
2416		if ( n.nodeType == 1 && n != elem )
2417			r.push( n );
2418	}
2419
2420	return r;
2421};
2422
2423return;
2424
2425window.Sizzle = Sizzle;
2426
2427})();
2428/*
2429 * A number of helper functions used for managing events.
2430 * Many of the ideas behind this code originated from
2431 * Dean Edwards' addEvent library.
2432 */
2433jQuery.event = {
2434
2435	// Bind an event to an element
2436	// Original by Dean Edwards
2437	add: function(elem, types, handler, data) {
2438		if ( elem.nodeType == 3 || elem.nodeType == 8 )
2439			return;
2440
2441		// For whatever reason, IE has trouble passing the window object
2442		// around, causing it to be cloned in the process
2443		if ( elem.setInterval && elem != window )
2444			elem = window;
2445
2446		// Make sure that the function being executed has a unique ID
2447		if ( !handler.guid )
2448			handler.guid = this.guid++;
2449
2450		// if data is passed, bind to handler
2451		if ( data !== undefined ) {
2452			// Create temporary function pointer to original handler
2453			var fn = handler;
2454
2455			// Create unique handler function, wrapped around original handler
2456			handler = this.proxy( fn );
2457
2458			// Store data in unique handler
2459			handler.data = data;
2460		}
2461
2462		// Init the element's event structure
2463		var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
2464			handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
2465				// Handle the second event of a trigger and when
2466				// an event is called after a page has unloaded
2467				return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
2468					jQuery.event.handle.apply(arguments.callee.elem, arguments) :
2469					undefined;
2470			});
2471		// Add elem as a property of the handle function
2472		// This is to prevent a memory leak with non-native
2473		// event in IE.
2474		handle.elem = elem;
2475
2476		// Handle multiple events separated by a space
2477		// jQuery(...).bind("mouseover mouseout", fn);
2478		jQuery.each(types.split(/\s+/), function(index, type) {
2479			// Namespaced event handlers
2480			var namespaces = type.split(".");
2481			type = namespaces.shift();
2482			handler.type = namespaces.slice().sort().join(".");
2483
2484			// Get the current list of functions bound to this event
2485			var handlers = events[type];
2486
2487			if ( jQuery.event.specialAll[type] )
2488				jQuery.event.specialAll[type].setup.call(elem, data, namespaces);
2489
2490			// Init the event handler queue
2491			if (!handlers) {
2492				handlers = events[type] = {};
2493
2494				// Check for a special event handler
2495				// Only use addEventListener/attachEvent if the special
2496				// events handler returns false
2497				if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem, data, namespaces) === false ) {
2498					// Bind the global event handler to the element
2499					if (elem.addEventListener)
2500						elem.addEventListener(type, handle, false);
2501					else if (elem.attachEvent)
2502						elem.attachEvent("on" + type, handle);
2503				}
2504			}
2505
2506			// Add the function to the element's handler list
2507			handlers[handler.guid] = handler;
2508
2509			// Keep track of which events have been used, for global triggering
2510			jQuery.event.global[type] = true;
2511		});
2512
2513		// Nullify elem to prevent memory leaks in IE
2514		elem = null;
2515	},
2516
2517	guid: 1,
2518	global: {},
2519
2520	// Detach an event or set of events from an element
2521	remove: function(elem, types, handler) {
2522		// don't do events on text and comment nodes
2523		if ( elem.nodeType == 3 || elem.nodeType == 8 )
2524			return;
2525
2526		var events = jQuery.data(elem, "events"), ret, index;
2527
2528		if ( events ) {
2529			// Unbind all events for the element
2530			if ( types === undefined || (typeof types === "string" && types.charAt(0) == ".") )
2531				for ( var type in events )
2532					this.remove( elem, type + (types || "") );
2533			else {
2534				// types is actually an event object here
2535				if ( types.type ) {
2536					handler = types.handler;
2537					types = types.type;
2538				}
2539
2540				// Handle multiple events seperated by a space
2541				// jQuery(...).unbind("mouseover mouseout", fn);
2542				jQuery.each(types.split(/\s+/), function(index, type){
2543					// Namespaced event handlers
2544					var namespaces = type.split(".");
2545					type = namespaces.shift();
2546					var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
2547
2548					if ( events[type] ) {
2549						// remove the given handler for the given type
2550						if ( handler )
2551							delete events[type][handler.guid];
2552
2553						// remove all handlers for the given type
2554						else
2555							for ( var handle in events[type] )
2556								// Handle the removal of namespaced events
2557								if ( namespace.test(events[type][handle].type) )
2558									delete events[type][handle];
2559
2560						if ( jQuery.event.specialAll[type] )
2561							jQuery.event.specialAll[type].teardown.call(elem, namespaces);
2562
2563						// remove generic event handler if no more handlers exist
2564						for ( ret in events[type] ) break;
2565						if ( !ret ) {
2566							if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem, namespaces) === false ) {
2567								if (elem.removeEventListener)
2568									elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
2569								else if (elem.detachEvent)
2570									elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
2571							}
2572							ret = null;
2573							delete events[type];
2574						}
2575					}
2576				});
2577			}
2578
2579			// Remove the expando if it's no longer used
2580			for ( ret in events ) break;
2581			if ( !ret ) {
2582				var handle = jQuery.data( elem, "handle" );
2583				if ( handle ) handle.elem = null;
2584				jQuery.removeData( elem, "events" );
2585				jQuery.removeData( elem, "handle" );
2586			}
2587		}
2588	},
2589
2590	// bubbling is internal
2591	trigger: function( event, data, elem, bubbling ) {
2592		// Event object or event type
2593		var type = event.type || event;
2594
2595		if( !bubbling ){
2596			event = typeof event === "object" ?
2597				// jQuery.Event object
2598				event[expando] ? event :
2599				// Object literal
2600				jQuery.extend( jQuery.Event(type), event ) :
2601				// Just the event type (string)
2602				jQuery.Event(type);
2603
2604			if ( type.indexOf("!") >= 0 ) {
2605				event.type = type = type.slice(0, -1);
2606				event.exclusive = true;
2607			}
2608
2609			// Handle a global trigger
2610			if ( !elem ) {
2611				// Don't bubble custom events when global (to avoid too much overhead)
2612				event.stopPropagation();
2613				// Only trigger if we've ever bound an event for it
2614				if ( this.global[type] )
2615					jQuery.each( jQuery.cache, function(){
2616						if ( this.events && this.events[type] )
2617							jQuery.event.trigger( event, data, this.handle.elem );
2618					});
2619			}
2620
2621			// Handle triggering a single element
2622
2623			// don't do events on text and comment nodes
2624			if ( !elem || elem.nodeType == 3 || elem.nodeType == 8 )
2625				return undefined;
2626
2627			// Clean up in case it is reused
2628			event.result = undefined;
2629			event.target = elem;
2630
2631			// Clone the incoming data, if any
2632			data = jQuery.makeArray(data);
2633			data.unshift( event );
2634		}
2635
2636		event.currentTarget = elem;
2637
2638		// Trigger the event, it is assumed that "handle" is a function
2639		var handle = jQuery.data(elem, "handle");
2640		if ( handle )
2641			handle.apply( elem, data );
2642
2643		// Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
2644		if ( (!elem[type] || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
2645			event.result = false;
2646
2647		// Trigger the native events (except for clicks on links)
2648		if ( !bubbling && elem[type] && !event.isDefaultPrevented() && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
2649			this.triggered = true;
2650			try {
2651				elem[ type ]();
2652			// prevent IE from throwing an error for some hidden elements
2653			} catch (e) {}
2654		}
2655
2656		this.triggered = false;
2657
2658		if ( !event.isPropagationStopped() ) {
2659			var parent = elem.parentNode || elem.ownerDocument;
2660			if ( parent )
2661				jQuery.event.trigger(event, data, parent, true);
2662		}
2663	},
2664
2665	handle: function(event) {
2666		// returned undefined or false
2667		var all, handlers;
2668
2669		event = arguments[0] = jQuery.event.fix( event || window.event );
2670		event.currentTarget = this;
2671
2672		// Namespaced event handlers
2673		var namespaces = event.type.split(".");
2674		event.type = namespaces.shift();
2675
2676		// Cache this now, all = true means, any handler
2677		all = !namespaces.length && !event.exclusive;
2678
2679		var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");
2680
2681		handlers = ( jQuery.data(this, "events") || {} )[event.type];
2682
2683		for ( var j in handlers ) {
2684			var handler = handlers[j];
2685
2686			// Filter the functions by class
2687			if ( all || namespace.test(handler.type) ) {
2688				// Pass in a reference to the handler function itself
2689				// So that we can later remove it
2690				event.handler = handler;
2691				event.data = handler.data;
2692
2693				var ret = handler.apply(this, arguments);
2694
2695				if( ret !== undefined ){
2696					event.result = ret;
2697					if ( ret === false ) {
2698						event.preventDefault();
2699						event.stopPropagation();
2700					}
2701				}
2702
2703				if( event.isImmediatePropagationStopped() )
2704					break;
2705
2706			}
2707		}
2708	},
2709
2710	props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
2711
2712	fix: function(event) {
2713		if ( event[expando] )
2714			return event;
2715
2716		// store a copy of the original event object
2717		// and "clone" to set read-only properties
2718		var originalEvent = event;
2719		event = jQuery.Event( originalEvent );
2720
2721		for ( var i = this.props.length, prop; i; ){
2722			prop = this.props[ --i ];
2723			event[ prop ] = originalEvent[ prop ];
2724		}
2725
2726		// Fix target property, if necessary
2727		if ( !event.target )
2728			event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
2729
2730		// check if target is a textnode (safari)
2731		if ( event.target.nodeType == 3 )
2732			event.target = event.target.parentNode;
2733
2734		// Add relatedTarget, if necessary
2735		if ( !event.relatedTarget && event.fromElement )
2736			event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
2737
2738		// Calculate pageX/Y if missing and clientX/Y available
2739		if ( event.pageX == null && event.clientX != null ) {
2740			var doc = document.documentElement, body = document.body;
2741			event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
2742			event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
2743		}
2744
2745		// Add which for key events
2746		if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
2747			event.which = event.charCode || event.keyCode;
2748
2749		// Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
2750		if ( !event.metaKey && event.ctrlKey )
2751			event.metaKey = event.ctrlKey;
2752
2753		// Add which for click: 1 == left; 2 == middle; 3 == right
2754		// Note: button is not normalized, so don't use it
2755		if ( !event.which && event.button )
2756			event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
2757
2758		return event;
2759	},
2760
2761	proxy: function( fn, proxy ){
2762		proxy = proxy || function(){ return fn.apply(this, arguments); };
2763		// Set the guid of unique handler to the same of original handler, so it can be removed
2764		proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
2765		// So proxy can be declared as an argument
2766		return proxy;
2767	},
2768
2769	special: {
2770		ready: {
2771			// Make sure the ready event is setup
2772			setup: bindReady,
2773			teardown: function() {}
2774		}
2775	},
2776
2777	specialAll: {
2778		live: {
2779			setup: function( selector, namespaces ){
2780				jQuery.event.add( this, namespaces[0], liveHandler );
2781			},
2782			teardown:  function( namespaces ){
2783				if ( namespaces.length ) {
2784					var remove = 0, name = RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
2785
2786					jQuery.each( (jQuery.data(this, "events").live || {}), function(){
2787						if ( name.test(this.type) )
2788							remove++;
2789					});
2790
2791					if ( remove < 1 )
2792						jQuery.event.remove( this, namespaces[0], liveHandler );
2793				}
2794			}
2795		}
2796	}
2797};
2798
2799jQuery.Event = function( src ){
2800	// Allow instantiation without the 'new' keyword
2801	if( !this.preventDefault )
2802		return new jQuery.Event(src);
2803
2804	// Event object
2805	if( src && src.type ){
2806		this.originalEvent = src;
2807		this.type = src.type;
2808	// Event type
2809	}else
2810		this.type = src;
2811
2812	// timeStamp is buggy for some events on Firefox(#3843)
2813	// So we won't rely on the native value
2814	this.timeStamp = now();
2815
2816	// Mark it as fixed
2817	this[expando] = true;
2818};
2819
2820function returnFalse(){
2821	return false;
2822}
2823function returnTrue(){
2824	return true;
2825}
2826
2827// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
2828// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
2829jQuery.Event.prototype = {
2830	preventDefault: function() {
2831		this.isDefaultPrevented = returnTrue;
2832
2833		var e = this.originalEvent;
2834		if( !e )
2835			return;
2836		// if preventDefault exists run it on the original event
2837		if (e.preventDefault)
2838			e.preventDefault();
2839		// otherwise set the returnValue property of the original event to false (IE)
2840		e.returnValue = false;
2841	},
2842	stopPropagation: function() {
2843		this.isPropagationStopped = returnTrue;
2844
2845		var e = this.originalEvent;
2846		if( !e )
2847			return;
2848		// if stopPropagation exists run it on the original event
2849		if (e.stopPropagation)
2850			e.stopPropagation();
2851		// otherwise set the cancelBubble property of the original event to true (IE)
2852		e.cancelBubble = true;
2853	},
2854	stopImmediatePropagation:function(){
2855		this.isImmediatePropagationStopped = returnTrue;
2856		this.stopPropagation();
2857	},
2858	isDefaultPrevented: returnFalse,
2859	isPropagationStopped: returnFalse,
2860	isImmediatePropagationStopped: returnFalse
2861};
2862// Checks if an event happened on an element within another element
2863// Used in jQuery.event.special.mouseenter and mouseleave handlers
2864var withinElement = function(event) {
2865	// Check if mouse(over|out) are still within the same parent element
2866	var parent = event.relatedTarget;
2867	// Traverse up the tree
2868	while ( parent && parent != this )
2869		try { parent = parent.parentNode; }
2870		catch(e) { parent = this; }
2871
2872	if( parent != this ){
2873		// set the correct event type
2874		event.type = event.data;
2875		// handle event if we actually just moused on to a non sub-element
2876		jQuery.event.handle.apply( this, arguments );
2877	}
2878};
2879
2880jQuery.each({
2881	mouseover: 'mouseenter',
2882	mouseout: 'mouseleave'
2883}, function( orig, fix ){
2884	jQuery.event.special[ fix ] = {
2885		setup: function(){
2886			jQuery.event.add( this, orig, withinElement, fix );
2887		},
2888		teardown: function(){
2889			jQuery.event.remove( this, orig, withinElement );
2890		}
2891	};
2892});
2893
2894jQuery.fn.extend({
2895	bind: function( type, data, fn ) {
2896		return type == "unload" ? this.one(type, data, fn) : this.each(function(){
2897			jQuery.event.add( this, type, fn || data, fn && data );
2898		});
2899	},
2900
2901	one: function( type, data, fn ) {
2902		var one = jQuery.event.proxy( fn || data, function(event) {
2903			jQuery(this).unbind(event, one);
2904			return (fn || data).apply( this, arguments );
2905		});
2906		return this.each(function(){
2907			jQuery.event.add( this, type, one, fn && data);
2908		});
2909	},
2910
2911	unbind: function( type, fn ) {
2912		return this.each(function(){
2913			jQuery.event.remove( this, type, fn );
2914		});
2915	},
2916
2917	trigger: function( type, data ) {
2918		return this.each(function(){
2919			jQuery.event.trigger( type, data, this );
2920		});
2921	},
2922
2923	triggerHandler: function( type, data ) {
2924		if( this[0] ){
2925			var event = jQuery.Event(type);
2926			event.preventDefault();
2927			event.stopPropagation();
2928			jQuery.event.trigger( event, data, this[0] );
2929			return event.result;
2930		}
2931	},
2932
2933	toggle: function( fn ) {
2934		// Save reference to arguments for access in closure
2935		var args = arguments, i = 1;
2936
2937		// link all the functions, so any of them can unbind this click handler
2938		while( i < args.length )
2939			jQuery.event.proxy( fn, args[i++] );
2940
2941		return this.click( jQuery.event.proxy( fn, function(event) {
2942			// Figure out which function to execute
2943			this.lastToggle = ( this.lastToggle || 0 ) % i;
2944
2945			// Make sure that clicks stop
2946			event.preventDefault();
2947
2948			// and execute the function
2949			return args[ this.lastToggle++ ].apply( this, arguments ) || false;
2950		}));
2951	},
2952
2953	hover: function(fnOver, fnOut) {
2954		return this.mouseenter(fnOver).mouseleave(fnOut);
2955	},
2956
2957	ready: function(fn) {
2958		// Attach the listeners
2959		bindReady();
2960
2961		// If the DOM is already ready
2962		if ( jQuery.isReady )
2963			// Execute the function immediately
2964			fn.call( document, jQuery );
2965
2966		// Otherwise, remember the function for later
2967		else
2968			// Add the function to the wait list
2969			jQuery.readyList.push( fn );
2970
2971		return this;
2972	},
2973
2974	live: function( type, fn ){
2975		var proxy = jQuery.event.proxy( fn );
2976		proxy.guid += this.selector + type;
2977
2978		jQuery(document).bind( liveConvert(type, this.selector), this.selector, proxy );
2979
2980		return this;
2981	},
2982
2983	die: function( type, fn ){
2984		jQuery(document).unbind( liveConvert(type, this.selector), fn ? { guid: fn.guid + this.selector + type } : null );
2985		return this;
2986	}
2987});
2988
2989function liveHandler( event ){
2990	var check = RegExp("(^|\\.)" + event.type + "(\\.|$)"),
2991		stop = true,
2992		elems = [];
2993
2994	jQuery.each(jQuery.data(this, "events").live || [], function(i, fn){
2995		if ( check.test(fn.type) ) {
2996			var elem = jQuery(event.target).closest(fn.data)[0];
2997			if ( elem )
2998				elems.push({ elem: elem, fn: fn });
2999		}
3000	});
3001
3002	elems.sort(function(a,b) {
3003		return jQuery.data(a.elem, "closest") - jQuery.data(b.elem, "closest");
3004	});
3005
3006	jQuery.each(elems, function(){
3007		if ( this.fn.call(this.elem, event, this.fn.data) === false )
3008			return (stop = false);
3009	});
3010
3011	return stop;
3012}
3013
3014function liveConvert(type, selector){
3015	return ["live", type, selector.replace(/\./g, "`").replace(/ /g, "|")].join(".");
3016}
3017
3018jQuery.extend({
3019	isReady: false,
3020	readyList: [],
3021	// Handle when the DOM is ready
3022	ready: function() {
3023		// Make sure that the DOM is not already loaded
3024		if ( !jQuery.isReady ) {
3025			// Remember that the DOM is ready
3026			jQuery.isReady = true;
3027
3028			// If there are functions bound, to execute
3029			if ( jQuery.readyList ) {
3030				// Execute all of them
3031				jQuery.each( jQuery.readyList, function(){
3032					this.call( document, jQuery );
3033				});
3034
3035				// Reset the list of functions
3036				jQuery.readyList = null;
3037			}
3038
3039			// Trigger any bound ready events
3040			jQuery(document).triggerHandler("ready");
3041		}
3042	}
3043});
3044
3045var readyBound = false;
3046
3047function bindReady(){
3048	if ( readyBound ) return;
3049	readyBound = true;
3050
3051	// Mozilla, Opera and webkit nightlies currently support this event
3052	if ( document.addEventListener ) {
3053		// Use the handy event callback
3054		document.addEventListener( "DOMContentLoaded", function(){
3055			document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
3056			jQuery.ready();
3057		}, false );
3058
3059	// If IE event model is used
3060	} else if ( document.attachEvent ) {
3061		// ensure firing before onload,
3062		// maybe late but safe also for iframes
3063		document.attachEvent("onreadystatechange", function(){
3064			if ( document.readyState === "complete" ) {
3065				document.detachEvent( "onreadystatechange", arguments.callee );
3066				jQuery.ready();
3067			}
3068		});
3069
3070		// If IE and not an iframe
3071		// continually check to see if the document is ready
3072		if ( document.documentElement.doScroll && window == window.top ) (function(){
3073			if ( jQuery.isReady ) return;
3074
3075			try {
3076				// If IE is used, use the trick by Diego Perini
3077				// http://javascript.nwbox.com/IEContentLoaded/
3078				document.documentElement.doScroll("left");
3079			} catch( error ) {
3080				setTimeout( arguments.callee, 0 );
3081				return;
3082			}
3083
3084			// and execute any waiting functions
3085			jQuery.ready();
3086		})();
3087	}
3088
3089	// A fallback to window.onload, that will always work
3090	jQuery.event.add( window, "load", jQuery.ready );
3091}
3092
3093jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
3094	"mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave," +
3095	"change,select,submit,keydown,keypress,keyup,error").split(","), function(i, name){
3096
3097	// Handle event binding
3098	jQuery.fn[name] = function(fn){
3099		return fn ? this.bind(name, fn) : this.trigger(name);
3100	};
3101});
3102
3103// Prevent memory leaks in IE
3104// And prevent errors on refresh with events like mouseover in other browsers
3105// Window isn't included so as not to unbind existing unload events
3106jQuery( window ).bind( 'unload', function(){
3107	for ( var id in jQuery.cache )
3108		// Skip the window
3109		if ( id != 1 && jQuery.cache[ id ].handle )
3110			jQuery.event.remove( jQuery.cache[ id ].handle.elem );
3111});
3112(function(){
3113
3114	jQuery.support = {};
3115
3116	var root = document.documentElement,
3117		script = document.createElement("script"),
3118		div = document.createElement("div"),
3119		id = "script" + (new Date).getTime();
3120
3121	div.style.display = "none";
3122	div.innerHTML = '   <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';
3123
3124	var all = div.getElementsByTagName("*"),
3125		a = div.getElementsByTagName("a")[0];
3126
3127	// Can't get basic test support
3128	if ( !all || !all.length || !a ) {
3129		return;
3130	}
3131
3132	jQuery.support = {
3133		// IE strips leading whitespace when .innerHTML is used
3134		leadingWhitespace: div.firstChild.nodeType == 3,
3135
3136		// Make sure that tbody elements aren't automatically inserted
3137		// IE will insert them into empty tables
3138		tbody: !div.getElementsByTagName("tbody").length,
3139
3140		// Make sure that you can get all elements in an <object> element
3141		// IE 7 always returns no results
3142		objectAll: !!div.getElementsByTagName("object")[0]
3143			.getElementsByTagName("*").length,
3144
3145		// Make sure that link elements get serialized correctly by innerHTML
3146		// This requires a wrapper element in IE
3147		htmlSerialize: !!div.getElementsByTagName("link").length,
3148
3149		// Get the style information from getAttribute
3150		// (IE uses .cssText insted)
3151		style: /red/.test( a.getAttribute("style") ),
3152
3153		// Make sure that URLs aren't manipulated
3154		// (IE normalizes it by default)
3155		hrefNormalized: a.getAttribute("href") === "/a",
3156
3157		// Make sure that element opacity exists
3158		// (IE uses filter instead)
3159		opacity: a.style.opacity === "0.5",
3160
3161		// Verify style float existence
3162		// (IE uses styleFloat instead of cssFloat)
3163		cssFloat: !!a.style.cssFloat,
3164
3165		// Will be defined later
3166		scriptEval: false,
3167		noCloneEvent: true,
3168		boxModel: null
3169	};
3170
3171	script.type = "text/javascript";
3172	try {
3173		script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
3174	} catch(e){}
3175
3176	root.insertBefore( script, root.firstChild );
3177
3178	// Make sure that the execution of code works by injecting a script
3179	// tag with appendChild/createTextNode
3180	// (IE doesn't support this, fails, and uses .text instead)
3181	if ( window[ id ] ) {
3182		jQuery.support.scriptEval = true;
3183		delete window[ id ];
3184	}
3185
3186	root.removeChild( script );
3187
3188	if ( div.attachEvent && div.fireEvent ) {
3189		div.attachEvent("onclick", function(){
3190			// Cloning a node shouldn't copy over any
3191			// bound event handlers (IE does this)
3192			jQuery.support.noCloneEvent = false;
3193			div.detachEvent("onclick", arguments.callee);
3194		});
3195		div.cloneNode(true).fireEvent("onclick");
3196	}
3197
3198	// Figure out if the W3C box model works as expected
3199	// document.body must exist before we can do this
3200	jQuery(function(){
3201		var div = document.createElement("div");
3202		div.style.width = div.style.paddingLeft = "1px";
3203
3204		document.body.appendChild( div );
3205		jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
3206		document.body.removeChild( div ).style.display = 'none';
3207	});
3208})();
3209
3210var styleFloat = jQuery.support.cssFloat ? "cssFloat" : "styleFloat";
3211
3212jQuery.props = {
3213	"for": "htmlFor",
3214	"class": "className",
3215	"float": styleFloat,
3216	cssFloat: styleFloat,
3217	styleFloat: styleFloat,
3218	readonly: "readOnly",
3219	maxlength: "maxLength",
3220	cellspacing: "cellSpacing",
3221	rowspan: "rowSpan",
3222	tabindex: "tabIndex"
3223};
3224jQuery.fn.extend({
3225	// Keep a copy of the old load
3226	_load: jQuery.fn.load,
3227
3228	load: function( url, params, callback ) {
3229		if ( typeof url !== "string" )
3230			return this._load( url );
3231
3232		var off = url.indexOf(" ");
3233		if ( off >= 0 ) {
3234			var selector = url.slice(off, url.length);
3235			url = url.slice(0, off);
3236		}
3237
3238		// Default to a GET request
3239		var type = "GET";
3240
3241		// If the second parameter was provided
3242		if ( params )
3243			// If it's a function
3244			if ( jQuery.isFunction( params ) ) {
3245				// We assume that it's the callback
3246				callback = params;
3247				params = null;
3248
3249			// Otherwise, build a param string
3250			} else if( typeof params === "object" ) {
3251				params = jQuery.param( params );
3252				type = "POST";
3253			}
3254
3255		var self = this;
3256
3257		// Request the remote document
3258		jQuery.ajax({
3259			url: url,
3260			type: type,
3261			dataType: "html",
3262			data: params,
3263			complete: function(res, status){
3264				// If successful, inject the HTML into all the matched elements
3265				if ( status == "success" || status == "notmodified" )
3266					// See if a selector was specified
3267					self.html( selector ?
3268						// Create a dummy div to hold the results
3269						jQuery("<div/>")
3270							// inject the contents of the document in, removing the scripts
3271							// to avoid any 'Permission Denied' errors in IE
3272							.append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
3273
3274							// Locate the specified elements
3275							.find(selector) :
3276
3277						// If not, just inject the full result
3278						res.responseText );
3279
3280				if( callback )
3281					self.each( callback, [res.responseText, status, res] );
3282			}
3283		});
3284		return this;
3285	},
3286
3287	serialize: function() {
3288		return jQuery.param(this.serializeArray());
3289	},
3290	serializeArray: function() {
3291		return this.map(function(){
3292			return this.elements ? jQuery.makeArray(this.elements) : this;
3293		})
3294		.filter(function(){
3295			return this.name && !this.disabled &&
3296				(this.checked || /select|textarea/i.test(this.nodeName) ||
3297					/text|hidden|password|search/i.test(this.type));
3298		})
3299		.map(function(i, elem){
3300			var val = jQuery(this).val();
3301			return val == null ? null :
3302				jQuery.isArray(val) ?
3303					jQuery.map( val, function(val, i){
3304						return {name: elem.name, value: val};
3305					}) :
3306					{name: elem.name, value: val};
3307		}).get();
3308	}
3309});
3310
3311// Attach a bunch of functions for handling common AJAX events
3312jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
3313	jQuery.fn[o] = function(f){
3314		return this.bind(o, f);
3315	};
3316});
3317
3318var jsc = now();
3319
3320jQuery.extend({
3321
3322	get: function( url, data, callback, type ) {
3323		// shift arguments if data argument was ommited
3324		if ( jQuery.isFunction( data ) ) {
3325			callback = data;
3326			data = null;
3327		}
3328
3329		return jQuery.ajax({
3330			type: "GET",
3331			url: url,
3332			data: data,
3333			success: callback,
3334			dataType: type
3335		});
3336	},
3337
3338	getScript: function( url, callback ) {
3339		return jQuery.get(url, null, callback, "script");
3340	},
3341
3342	getJSON: function( url, data, callback ) {
3343		return jQuery.get(url, data, callback, "json");
3344	},
3345
3346	post: function( url, data, callback, type ) {
3347		if ( jQuery.isFunction( data ) ) {
3348			callback = data;
3349			data = {};
3350		}
3351
3352		return jQuery.ajax({
3353			type: "POST",
3354			url: url,
3355			data: data,
3356			success: callback,
3357			dataType: type
3358		});
3359	},
3360
3361	ajaxSetup: function( settings ) {
3362		jQuery.extend( jQuery.ajaxSettings, settings );
3363	},
3364
3365	ajaxSettings: {
3366		url: location.href,
3367		global: true,
3368		type: "GET",
3369		contentType: "application/x-www-form-urlencoded",
3370		processData: true,
3371		async: true,
3372		/*
3373		timeout: 0,
3374		data: null,
3375		username: null,
3376		password: null,
3377		*/
3378		// Create the request object; Microsoft failed to properly
3379		// implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
3380		// This function can be overriden by calling jQuery.ajaxSetup
3381		xhr:function(){
3382			return window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
3383		},
3384		accepts: {
3385			xml: "application/xml, text/xml",
3386			html: "text/html",
3387			script: "text/javascript, application/javascript",
3388			json: "application/json, text/javascript",
3389			text: "text/plain",
3390			_default: "*/*"
3391		}
3392	},
3393
3394	// Last-Modified header cache for next request
3395	lastModified: {},
3396
3397	ajax: function( s ) {
3398		// Extend the settings, but re-extend 's' so that it can be
3399		// checked again later (in the test suite, specifically)
3400		s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
3401
3402		var jsonp, jsre = /=\?(&|$)/g, status, data,
3403			type = s.type.toUpperCase();
3404
3405		// convert data if not already a string
3406		if ( s.data && s.processData && typeof s.data !== "string" )
3407			s.data = jQuery.param(s.data);
3408
3409		// Handle JSONP Parameter Callbacks
3410		if ( s.dataType == "jsonp" ) {
3411			if ( type == "GET" ) {
3412				if ( !s.url.match(jsre) )
3413					s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
3414			} else if ( !s.data || !s.data.match(jsre) )
3415				s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
3416			s.dataType = "json";
3417		}
3418
3419		// Build temporary JSONP function
3420		if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
3421			jsonp = "jsonp" + jsc++;
3422
3423			// Replace the =? sequence both in the query string and the data
3424			if ( s.data )
3425				s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
3426			s.url = s.url.replace(jsre, "=" + jsonp + "$1");
3427
3428			// We need to make sure
3429			// that a JSONP style response is executed properly
3430			s.dataType = "script";
3431
3432			// Handle JSONP-style loading
3433			window[ jsonp ] = function(tmp){
3434				data = tmp;
3435				success();
3436				complete();
3437				// Garbage collect
3438				window[ jsonp ] = undefined;
3439				try{ delete window[ jsonp ]; } catch(e){}
3440				if ( head )
3441					head.removeChild( script );
3442			};
3443		}
3444
3445		if ( s.dataType == "script" && s.cache == null )
3446			s.cache = false;
3447
3448		if ( s.cache === false && type == "GET" ) {
3449			var ts = now();
3450			// try replacing _= if it is there
3451			var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
3452			// if nothing was replaced, add timestamp to the end
3453			s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
3454		}
3455
3456		// If data is available, append data to url for get requests
3457		if ( s.data && type == "GET" ) {
3458			s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
3459
3460			// IE likes to send both get and post data, prevent this
3461			s.data = null;
3462		}
3463
3464		// Watch for a new set of requests
3465		if ( s.global && ! jQuery.active++ )
3466			jQuery.event.trigger( "ajaxStart" );
3467
3468		// Matches an absolute URL, and saves the domain
3469		var parts = /^(\w+:)?\/\/([^\/?#]+)/.exec( s.url );
3470
3471		// If we're requesting a remote document
3472		// and trying to load JSON or Script with a GET
3473		if ( s.dataType == "script" && type == "GET" && parts
3474			&& ( parts[1] && parts[1] != location.protocol || parts[2] != location.host )){
3475
3476			var head = document.getElementsByTagName("head")[0];
3477			var script = document.createElement("script");
3478			script.src = s.url;
3479			if (s.scriptCharset)
3480				script.charset = s.scriptCharset;
3481
3482			// Handle Script loading
3483			if ( !jsonp ) {
3484				var done = false;
3485
3486				// Attach handlers for all browsers
3487				script.onload = script.onreadystatechange = function(){
3488					if ( !done && (!this.readyState ||
3489							this.readyState == "loaded" || this.readyState == "complete") ) {
3490						done = true;
3491						success();
3492						complete();
3493
3494						// Handle memory leak in IE
3495						script.onload = script.onreadystatechange = null;
3496						head.removeChild( script );
3497					}
3498				};
3499			}
3500
3501			head.appendChild(script);
3502
3503			// We handle everything using the script element injection
3504			return undefined;
3505		}
3506
3507		var requestDone = false;
3508
3509		// Create the request object
3510		var xhr = s.xhr();
3511
3512		// Open the socket
3513		// Passing null username, generates a login popup on Opera (#2865)
3514		if( s.username )
3515			xhr.open(type, s.url, s.async, s.username, s.password);
3516		else
3517			xhr.open(type, s.url, s.async);
3518
3519		// Need an extra try/catch for cross domain requests in Firefox 3
3520		try {
3521			// Set the correct header, if data is being sent
3522			if ( s.data )
3523				xhr.setRequestHeader("Content-Type", s.contentType);
3524
3525			// Set the If-Modified-Since header, if ifModified mode.
3526			if ( s.ifModified )
3527				xhr.setRequestHeader("If-Modified-Since",
3528					jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
3529
3530			// Set header so the called script knows that it's an XMLHttpRequest
3531			xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
3532
3533			// Set the Accepts header for the server, depending on the dataType
3534			xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
3535				s.accepts[ s.dataType ] + ", */*" :
3536				s.accepts._default );
3537		} catch(e){}
3538
3539		// Allow custom headers/mimetypes and early abort
3540		if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
3541			// Handle the global AJAX counter
3542			if ( s.global && ! --jQuery.active )
3543				jQuery.event.trigger( "ajaxStop" );
3544			// close opended socket
3545			xhr.abort();
3546			return false;
3547		}
3548
3549		if ( s.global )
3550			jQuery.event.trigger("ajaxSend", [xhr, s]);
3551
3552		// Wait for a response to come back
3553		var onreadystatechange = function(isTimeout){
3554			// The request was aborted, clear the interval and decrement jQuery.active
3555			if (xhr.readyState == 0) {
3556				if (ival) {
3557					// clear poll interval
3558					clearInterval(ival);
3559					ival = null;
3560					// Handle the global AJAX counter
3561					if ( s.global && ! --jQuery.active )
3562						jQuery.event.trigger( "ajaxStop" );
3563				}
3564			// The transfer is complete and the data is available, or the request timed out
3565			} else if ( !requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout") ) {
3566				requestDone = true;
3567
3568				// clear poll interval
3569				if (ival) {
3570					clearInterval(ival);
3571					ival = null;
3572				}
3573
3574				status = isTimeout == "timeout" ? "timeout" :
3575					!jQuery.httpSuccess( xhr ) ? "error" :
3576					s.ifModified && jQuery.httpNotModified( xhr, s.url ) ? "notmodified" :
3577					"success";
3578
3579				if ( status == "success" ) {
3580					// Watch for, and catch, XML document parse errors
3581					try {
3582						// process the data (runs the xml through httpData regardless of callback)
3583						data = jQuery.httpData( xhr, s.dataType, s );
3584					} catch(e) {
3585						status = "parsererror";
3586					}
3587				}
3588
3589				// Make sure that the request was successful or notmodified
3590				if ( status == "success" ) {
3591					// Cache Last-Modified header, if ifModified mode.
3592					var modRes;
3593					try {
3594						modRes = xhr.getResponseHeader("Last-Modified");
3595					} catch(e) {} // swallow exception thrown by FF if header is not available
3596
3597					if ( s.ifModified && modRes )
3598						jQuery.lastModified[s.url] = modRes;
3599
3600					// JSONP handles its own success callback
3601					if ( !jsonp )
3602						success();
3603				} else
3604					jQuery.handleError(s, xhr, status);
3605
3606				// Fire the complete handlers
3607				complete();
3608
3609				if ( isTimeout )
3610					xhr.abort();
3611
3612				// Stop memory leaks
3613				if ( s.async )
3614					xhr = null;
3615			}
3616		};
3617
3618		if ( s.async ) {
3619			// don't attach the handler to the request, just poll it instead
3620			var ival = setInterval(onreadystatechange, 13);
3621
3622			// Timeout checker
3623			if ( s.timeout > 0 )
3624				setTimeout(function(){
3625					// Check to see if the request is still happening
3626					if ( xhr && !requestDone )
3627						onreadystatechange( "timeout" );
3628				}, s.timeout);
3629		}
3630
3631		// Send the data
3632		try {
3633			xhr.send(s.data);
3634		} catch(e) {
3635			jQuery.handleError(s, xhr, null, e);
3636		}
3637
3638		// firefox 1.5 doesn't fire statechange for sync requests
3639		if ( !s.async )
3640			onreadystatechange();
3641
3642		function success(){
3643			// If a local callback was specified, fire it and pass it the data
3644			if ( s.success )
3645				s.success( data, status );
3646
3647			// Fire the global callback
3648			if ( s.global )
3649				jQuery.event.trigger( "ajaxSuccess", [xhr, s] );
3650		}
3651
3652		function complete(){
3653			// Process result
3654			if ( s.complete )
3655				s.complete(xhr, status);
3656
3657			// The request was completed
3658			if ( s.global )
3659				jQuery.event.trigger( "ajaxComplete", [xhr, s] );
3660
3661			// Handle the global AJAX counter
3662			if ( s.global && ! --jQuery.active )
3663				jQuery.event.trigger( "ajaxStop" );
3664		}
3665
3666		// return XMLHttpRequest to allow aborting the request etc.
3667		return xhr;
3668	},
3669
3670	handleError: function( s, xhr, status, e ) {
3671		// If a local callback was specified, fire it
3672		if ( s.error ) s.error( xhr, status, e );
3673
3674		// Fire the global callback
3675		if ( s.global )
3676			jQuery.event.trigger( "ajaxError", [xhr, s, e] );
3677	},
3678
3679	// Counter for holding the number of active queries
3680	active: 0,
3681
3682	// Determines if an XMLHttpRequest was successful or not
3683	httpSuccess: function( xhr ) {
3684		try {
3685			// IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
3686			return !xhr.status && location.protocol == "file:" ||
3687				( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223;
3688		} catch(e){}
3689		return false;
3690	},
3691
3692	// Determines if an XMLHttpRequest returns NotModified
3693	httpNotModified: function( xhr, url ) {
3694		try {
3695			var xhrRes = xhr.getResponseHeader("Last-Modified");
3696
3697			// Firefox always returns 200. check Last-Modified date
3698			return xhr.status == 304 || xhrRes == jQuery.lastModified[url];
3699		} catch(e){}
3700		return false;
3701	},
3702
3703	httpData: function( xhr, type, s ) {
3704		var ct = xhr.getResponseHeader("content-type"),
3705			xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
3706			data = xml ? xhr.responseXML : xhr.responseText;
3707
3708		if ( xml && data.documentElement.tagName == "parsererror" )
3709			throw "parsererror";
3710
3711		// Allow a pre-filtering function to sanitize the response
3712		// s != null is checked to keep backwards compatibility
3713		if( s && s.dataFilter )
3714			data = s.dataFilter( data, type );
3715
3716		// The filter can actually parse the response
3717		if( typeof data === "string" ){
3718
3719			// If the type is "script", eval it in global context
3720			if ( type == "script" )
3721				jQuery.globalEval( data );
3722
3723			// Get the JavaScript object, if JSON is used.
3724			if ( type == "json" )
3725				data = window["eval"]("(" + data + ")");
3726		}
3727
3728		return data;
3729	},
3730
3731	// Serialize an array of form elements or a set of
3732	// key/values into a query string
3733	param: function( a ) {
3734		var s = [ ];
3735
3736		function add( key, value ){
3737			s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
3738		};
3739
3740		// If an array was passed in, assume that it is an array
3741		// of form elements
3742		if ( jQuery.isArray(a) || a.jquery )
3743			// Serialize the form elements
3744			jQuery.each( a, function(){
3745				add( this.name, this.value );
3746			});
3747
3748		// Otherwise, assume that it's an object of key/value pairs
3749		else
3750			// Serialize the key/values
3751			for ( var j in a )
3752				// If the value is an array then the key names need to be repeated
3753				if ( jQuery.isArray(a[j]) )
3754					jQuery.each( a[j], function(){
3755						add( j, this );
3756					});
3757				else
3758					add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
3759
3760		// Return the resulting serialization
3761		return s.join("&").replace(/%20/g, "+");
3762	}
3763
3764});
3765var elemdisplay = {},
3766	timerId,
3767	fxAttrs = [
3768		// height animations
3769		[ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
3770		// width animations
3771		[ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
3772		// opacity animations
3773		[ "opacity" ]
3774	];
3775
3776function genFx( type, num ){
3777	var obj = {};
3778	jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function(){
3779		obj[ this ] = type;
3780	});
3781	return obj;
3782}
3783
3784jQuery.fn.extend({
3785	show: function(speed,callback){
3786		if ( speed ) {
3787			return this.animate( genFx("show", 3), speed, callback);
3788		} else {
3789			for ( var i = 0, l = this.length; i < l; i++ ){
3790				var old = jQuery.data(this[i], "olddisplay");
3791
3792				this[i].style.display = old || "";
3793
3794				if ( jQuery.css(this[i], "display") === "none" ) {
3795					var tagName = this[i].tagName, display;
3796
3797					if ( elemdisplay[ tagName ] ) {
3798						display = elemdisplay[ tagName ];
3799					} else {
3800						var elem = jQuery("<" + tagName + " />").appendTo("body");
3801
3802						display = elem.css("display");
3803						if ( display === "none" )
3804							display = "block";
3805
3806						elem.remove();
3807
3808						elemdisplay[ tagName ] = display;
3809					}
3810
3811					jQuery.data(this[i], "olddisplay", display);
3812				}
3813			}
3814
3815			// Set the display of the elements in a second loop
3816			// to avoid the constant reflow
3817			for ( var i = 0, l = this.length; i < l; i++ ){
3818				this[i].style.display = jQuery.data(this[i], "olddisplay") || "";
3819			}
3820
3821			return this;
3822		}
3823	},
3824
3825	hide: function(speed,callback){
3826		if ( speed ) {
3827			return this.animate( genFx("hide", 3), speed, callback);
3828		} else {
3829			for ( var i = 0, l = this.length; i < l; i++ ){
3830				var old = jQuery.data(this[i], "olddisplay");
3831				if ( !old && old !== "none" )
3832					jQuery.data(this[i], "olddisplay", jQuery.css(this[i], "display"));
3833			}
3834
3835			// Set the display of the elements in a second loop
3836			// to avoid the constant reflow
3837			for ( var i = 0, l = this.length; i < l; i++ ){
3838				this[i].style.display = "none";
3839			}
3840
3841			return this;
3842		}
3843	},
3844
3845	// Save the old toggle function
3846	_toggle: jQuery.fn.toggle,
3847
3848	toggle: function( fn, fn2 ){
3849		var bool = typeof fn === "boolean";
3850
3851		return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
3852			this._toggle.apply( this, arguments ) :
3853			fn == null || bool ?
3854				this.each(function(){
3855					var state = bool ? fn : jQuery(this).is(":hidden");
3856					jQuery(this)[ state ? "show" : "hide" ]();
3857				}) :
3858				this.animate(genFx("toggle", 3), fn, fn2);
3859	},
3860
3861	fadeTo: function(speed,to,callback){
3862		return this.animate({opacity: to}, speed, callback);
3863	},
3864
3865	animate: function( prop, speed, easing, callback ) {
3866		var optall = jQuery.speed(speed, easing, callback);
3867
3868		return this[ optall.queue === false ? "each" : "queue" ](function(){
3869
3870			var opt = jQuery.extend({}, optall), p,
3871				hidden = this.nodeType == 1 && jQuery(this).is(":hidden"),
3872				self = this;
3873
3874			for ( p in prop ) {
3875				if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
3876					return opt.complete.call(this);
3877
3878				if ( ( p == "height" || p == "width" ) && this.style ) {
3879					// Store display property
3880					opt.display = jQuery.css(this, "display");
3881
3882					// Make sure that nothing sneaks out
3883					opt.overflow = this.style.overflow;
3884				}
3885			}
3886
3887			if ( opt.overflow != null )
3888				this.style.overflow = "hidden";
3889
3890			opt.curAnim = jQuery.extend({}, prop);
3891
3892			jQuery.each( prop, function(name, val){
3893				var e = new jQuery.fx( self, opt, name );
3894
3895				if ( /toggle|show|hide/.test(val) )
3896					e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
3897				else {
3898					var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
3899						start = e.cur(true) || 0;
3900
3901					if ( parts ) {
3902						var end = parseFloat(parts[2]),
3903							unit = parts[3] || "px";
3904
3905						// We need to compute starting value
3906						if ( unit != "px" ) {
3907							self.style[ name ] = (end || 1) + unit;
3908							start = ((end || 1) / e.cur(true)) * start;
3909							self.style[ name ] = start + unit;
3910						}
3911
3912						// If a +=/-= token was provided, we're doing a relative animation
3913						if ( parts[1] )
3914							end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
3915
3916						e.custom( start, end, unit );
3917					} else
3918						e.custom( start, val, "" );
3919				}
3920			});
3921
3922			// For JS strict compliance
3923			return true;
3924		});
3925	},
3926
3927	stop: function(clearQueue, gotoEnd){
3928		var timers = jQuery.timers;
3929
3930		if (clearQueue)
3931			this.queue([]);
3932
3933		this.each(function(){
3934			// go in reverse order so anything added to the queue during the loop is ignored
3935			for ( var i = timers.length - 1; i >= 0; i-- )
3936				if ( timers[i].elem == this ) {
3937					if (gotoEnd)
3938						// force the next step to be the last
3939						timers[i](true);
3940					timers.splice(i, 1);
3941				}
3942		});
3943
3944		// start the next in the queue if the last step wasn't forced
3945		if (!gotoEnd)
3946			this.dequeue();
3947
3948		return this;
3949	}
3950
3951});
3952
3953// Generate shortcuts for custom animations
3954jQuery.each({
3955	slideDown: genFx("show", 1),
3956	slideUp: genFx("hide", 1),
3957	slideToggle: genFx("toggle", 1),
3958	fadeIn: { opacity: "show" },
3959	fadeOut: { opacity: "hide" }
3960}, function( name, props ){
3961	jQuery.fn[ name ] = function( speed, callback ){
3962		return this.animate( props, speed, callback );
3963	};
3964});
3965
3966jQuery.extend({
3967
3968	speed: function(speed, easing, fn) {
3969		var opt = typeof speed === "object" ? speed : {
3970			complete: fn || !fn && easing ||
3971				jQuery.isFunction( speed ) && speed,
3972			duration: speed,
3973			easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
3974		};
3975
3976		opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
3977			jQuery.fx.speeds[opt.duration] || jQuery.fx.speeds._default;
3978
3979		// Queueing
3980		opt.old = opt.complete;
3981		opt.complete = function(){
3982			if ( opt.queue !== false )
3983				jQuery(this).dequeue();
3984			if ( jQuery.isFunction( opt.old ) )
3985				opt.old.call( this );
3986		};
3987
3988		return opt;
3989	},
3990
3991	easing: {
3992		linear: function( p, n, firstNum, diff ) {
3993			return firstNum + diff * p;
3994		},
3995		swing: function( p, n, firstNum, diff ) {
3996			return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
3997		}
3998	},
3999
4000	timers: [],
4001
4002	fx: function( elem, options, prop ){
4003		this.options = options;
4004		this.elem = elem;
4005		this.prop = prop;
4006
4007		if ( !options.orig )
4008			options.orig = {};
4009	}
4010
4011});
4012
4013jQuery.fx.prototype = {
4014
4015	// Simple function for setting a style value
4016	update: function(){
4017		if ( this.options.step )
4018			this.options.step.call( this.elem, this.now, this );
4019
4020		(jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
4021
4022		// Set display property to block for height/width animations
4023		if ( ( this.prop == "height" || this.prop == "width" ) && this.elem.style )
4024			this.elem.style.display = "block";
4025	},
4026
4027	// Get the current size
4028	cur: function(force){
4029		if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) )
4030			return this.elem[ this.prop ];
4031
4032		var r = parseFloat(jQuery.css(this.elem, this.prop, force));
4033		return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
4034	},
4035
4036	// Start an animation from one number to another
4037	custom: function(from, to, unit){
4038		this.startTime = now();
4039		this.start = from;
4040		this.end = to;
4041		this.unit = unit || this.unit || "px";
4042		this.now = this.start;
4043		this.pos = this.state = 0;
4044
4045		var self = this;
4046		function t(gotoEnd){
4047			return self.step(gotoEnd);
4048		}
4049
4050		t.elem = this.elem;
4051
4052		if ( t() && jQuery.timers.push(t) && !timerId ) {
4053			timerId = setInterval(function(){
4054				var timers = jQuery.timers;
4055
4056				for ( var i = 0; i < timers.length; i++ )
4057					if ( !timers[i]() )
4058						timers.splice(i--, 1);
4059
4060				if ( !timers.length ) {
4061					clearInterval( timerId );
4062					timerId = undefined;
4063				}
4064			}, 13);
4065		}
4066	},
4067
4068	// Simple 'show' function
4069	show: function(){
4070		// Remember where we started, so that we can go back to it later
4071		this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
4072		this.options.show = true;
4073
4074		// Begin the animation
4075		// Make sure that we start at a small width/height to avoid any
4076		// flash of content
4077		this.custom(this.prop == "width" || this.prop == "height" ? 1 : 0, this.cur());
4078
4079		// Start by showing the element
4080		jQuery(this.elem).show();
4081	},
4082
4083	// Simple 'hide' function
4084	hide: function(){
4085		// Remember where we started, so that we can go back to it later
4086		this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
4087		this.options.hide = true;
4088
4089		// Begin the animation
4090		this.custom(this.cur(), 0);
4091	},
4092
4093	// Each step of an animation
4094	step: function(gotoEnd){
4095		var t = now();
4096
4097		if ( gotoEnd || t >= this.options.duration + this.startTime ) {
4098			this.now = this.end;
4099			this.pos = this.state = 1;
4100			this.update();
4101
4102			this.options.curAnim[ this.prop ] = true;
4103
4104			var done = true;
4105			for ( var i in this.options.curAnim )
4106				if ( this.options.curAnim[i] !== true )
4107					done = false;
4108
4109			if ( done ) {
4110				if ( this.options.display != null ) {
4111					// Reset the overflow
4112					this.elem.style.overflow = this.options.overflow;
4113
4114					// Reset the display
4115					this.elem.style.display = this.options.display;
4116					if ( jQuery.css(this.elem, "display") == "none" )
4117						this.elem.style.display = "block";
4118				}
4119
4120				// Hide the element if the "hide" operation was done
4121				if ( this.options.hide )
4122					jQuery(this.elem).hide();
4123
4124				// Reset the properties, if the item has been hidden or shown
4125				if ( this.options.hide || this.options.show )
4126					for ( var p in this.options.curAnim )
4127						jQuery.attr(this.elem.style, p, this.options.orig[p]);
4128
4129				// Execute the complete function
4130				this.options.complete.call( this.elem );
4131			}
4132
4133			return false;
4134		} else {
4135			var n = t - this.startTime;
4136			this.state = n / this.options.duration;
4137
4138			// Perform the easing function, defaults to swing
4139			this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
4140			this.now = this.start + ((this.end - this.start) * this.pos);
4141
4142			// Perform the next step of the animation
4143			this.update();
4144		}
4145
4146		return true;
4147	}
4148
4149};
4150
4151jQuery.extend( jQuery.fx, {
4152	speeds:{
4153		slow: 600,
4154 		fast: 200,
4155 		// Default speed
4156 		_default: 400
4157	},
4158	step: {
4159
4160		opacity: function(fx){
4161			jQuery.attr(fx.elem.style, "opacity", fx.now);
4162		},
4163
4164		_default: function(fx){
4165			if ( fx.elem.style && fx.elem.style[ fx.prop ] != null )
4166				fx.elem.style[ fx.prop ] = fx.now + fx.unit;
4167			else
4168				fx.elem[ fx.prop ] = fx.now;
4169		}
4170	}
4171});
4172if ( document.documentElement["getBoundingClientRect"] )
4173	jQuery.fn.offset = function() {
4174		if ( !this[0] ) return { top: 0, left: 0 };
4175		if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
4176		var box  = this[0].getBoundingClientRect(), doc = this[0].ownerDocument, body = doc.body, docElem = doc.documentElement,
4177			clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0,
4178			top  = box.top  + (self.pageYOffset || jQuery.boxModel && docElem.scrollTop  || body.scrollTop ) - clientTop,
4179			left = box.left + (self.pageXOffset || jQuery.boxModel && docElem.scrollLeft || body.scrollLeft) - clientLeft;
4180		return { top: top, left: left };
4181	};
4182else
4183	jQuery.fn.offset = function() {
4184		if ( !this[0] ) return { top: 0, left: 0 };
4185		if ( this[0] === this[0].ownerDocument.body ) return jQuery.offset.bodyOffset( this[0] );
4186		jQuery.offset.initialized || jQuery.offset.initialize();
4187
4188		var elem = this[0], offsetParent = elem.offsetParent, prevOffsetParent = elem,
4189			doc = elem.ownerDocument, computedStyle, docElem = doc.documentElement,
4190			body = doc.body, defaultView = doc.defaultView,
4191			prevComputedStyle = defaultView.getComputedStyle(elem, null),
4192			top = elem.offsetTop, left = elem.offsetLeft;
4193
4194		while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
4195			computedStyle = defaultView.getComputedStyle(elem, null);
4196			top -= elem.scrollTop, left -= elem.scrollLeft;
4197			if ( elem === offsetParent ) {
4198				top += elem.offsetTop, left += elem.offsetLeft;
4199				if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && /^t(able|d|h)$/i.test(elem.tagName)) )
4200					top  += parseInt( computedStyle.borderTopWidth,  10) || 0,
4201					left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
4202				prevOffsetParent = offsetParent, offsetParent = elem.offsetParent;
4203			}
4204			if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" )
4205				top  += parseInt( computedStyle.borderTopWidth,  10) || 0,
4206				left += parseInt( computedStyle.borderLeftWidth, 10) || 0;
4207			prevComputedStyle = computedStyle;
4208		}
4209
4210		if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" )
4211			top  += body.offsetTop,
4212			left += body.offsetLeft;
4213
4214		if ( prevComputedStyle.position === "fixed" )
4215			top  += Math.max(docElem.scrollTop, body.scrollTop),
4216			left += Math.max(docElem.scrollLeft, body.scrollLeft);
4217
4218		return { top: top, left: left };
4219	};
4220
4221jQuery.offset = {
4222	initialize: function() {
4223		if ( this.initialized ) return;
4224		var body = document.body, container = document.createElement('div'), innerDiv, checkDiv, table, td, rules, prop, bodyMarginTop = body.style.marginTop,
4225			html = '<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';
4226
4227		rules = { position: 'absolute', top: 0, left: 0, margin: 0, border: 0, width: '1px', height: '1px', visibility: 'hidden' };
4228		for ( prop in rules ) container.style[prop] = rules[prop];
4229
4230		container.innerHTML = html;
4231		body.insertBefore(container, body.firstChild);
4232		innerDiv = container.firstChild, checkDiv = innerDiv.firstChild, td = innerDiv.nextSibling.firstChild.firstChild;
4233
4234		this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
4235		this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
4236
4237		innerDiv.style.overflow = 'hidden', innerDiv.style.position = 'relative';
4238		this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
4239
4240		body.style.marginTop = '1px';
4241		this.doesNotIncludeMarginInBodyOffset = (body.offsetTop === 0);
4242		body.style.marginTop = bodyMarginTop;
4243
4244		body.removeChild(container);
4245		this.initialized = true;
4246	},
4247
4248	bodyOffset: function(body) {
4249		jQuery.offset.initialized || jQuery.offset.initialize();
4250		var top = body.offsetTop, left = body.offsetLeft;
4251		if ( jQuery.offset.doesNotIncludeMarginInBodyOffset )
4252			top  += parseInt( jQuery.curCSS(body, 'marginTop',  true), 10 ) || 0,
4253			left += parseInt( jQuery.curCSS(body, 'marginLeft', true), 10 ) || 0;
4254		return { top: top, left: left };
4255	}
4256};
4257
4258
4259jQuery.fn.extend({
4260	position: function() {
4261		var left = 0, top = 0, results;
4262
4263		if ( this[0] ) {
4264			// Get *real* offsetParent
4265			var offsetParent = this.offsetParent(),
4266
4267			// Get correct offsets
4268			offset       = this.offset(),
4269			parentOffset = /^body|html$/i.test(offsetParent[0].tagName) ? { top: 0, left: 0 } : offsetParent.offset();
4270
4271			// Subtract element margins
4272			// note: when an element has margin: auto the offsetLeft and marginLeft
4273			// are the same in Safari causing offset.left to incorrectly be 0
4274			offset.top  -= num( this, 'marginTop'  );
4275			offset.left -= num( this, 'marginLeft' );
4276
4277			// Add offsetParent borders
4278			parentOffset.top  += num( offsetParent, 'borderTopWidth'  );
4279			parentOffset.left += num( offsetParent, 'borderLeftWidth' );
4280
4281			// Subtract the two offsets
4282			results = {
4283				top:  offset.top  - parentOffset.top,
4284				left: offset.left - parentOffset.left
4285			};
4286		}
4287
4288		return results;
4289	},
4290
4291	offsetParent: function() {
4292		var offsetParent = this[0].offsetParent || document.body;
4293		while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && jQuery.css(offsetParent, 'position') == 'static') )
4294			offsetParent = offsetParent.offsetParent;
4295		return jQuery(offsetParent);
4296	}
4297});
4298
4299
4300// Create scrollLeft and scrollTop methods
4301jQuery.each( ['Left', 'Top'], function(i, name) {
4302	var method = 'scroll' + name;
4303
4304	jQuery.fn[ method ] = function(val) {
4305		if (!this[0]) return null;
4306
4307		return val !== undefined ?
4308
4309			// Set the scroll offset
4310			this.each(function() {
4311				this == window || this == document ?
4312					window.scrollTo(
4313						!i ? val : jQuery(window).scrollLeft(),
4314						 i ? val : jQuery(window).scrollTop()
4315					) :
4316					this[ method ] = val;
4317			}) :
4318
4319			// Return the scroll offset
4320			this[0] == window || this[0] == document ?
4321				self[ i ? 'pageYOffset' : 'pageXOffset' ] ||
4322					jQuery.boxModel && document.documentElement[ method ] ||
4323					document.body[ method ] :
4324				this[0][ method ];
4325	};
4326});
4327// Create innerHeight, innerWidth, outerHeight and outerWidth methods
4328jQuery.each([ "Height", "Width" ], function(i, name){
4329
4330	var tl = i ? "Left"  : "Top",  // top or left
4331		br = i ? "Right" : "Bottom", // bottom or right
4332		lower = name.toLowerCase();
4333
4334	// innerHeight and innerWidth
4335	jQuery.fn["inner" + name] = function(){
4336		return this[0] ?
4337			jQuery.css( this[0], lower, false, "padding" ) :
4338			null;
4339	};
4340
4341	// outerHeight and outerWidth
4342	jQuery.fn["outer" + name] = function(margin) {
4343		return this[0] ?
4344			jQuery.css( this[0], lower, false, margin ? "margin" : "border" ) :
4345			null;
4346	};
4347
4348	var type = name.toLowerCase();
4349
4350	jQuery.fn[ type ] = function( size ) {
4351		// Get window width or height
4352		return this[0] == window ?
4353			// Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
4354			document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] ||
4355			document.body[ "client" + name ] :
4356
4357			// Get document width or height
4358			this[0] == document ?
4359				// Either scroll[Width/Height] or offset[Width/Height], whichever is greater
4360				Math.max(
4361					document.documentElement["client" + name],
4362					document.body["scroll" + name], document.documentElement["scroll" + name],
4363					document.body["offset" + name], document.documentElement["offset" + name]
4364				) :
4365
4366				// Get or set width or height on the element
4367				size === undefined ?
4368					// Get width or height on the element
4369					(this.length ? jQuery.css( this[0], type ) : null) :
4370
4371					// Set the width or height on the element (default to pixels if value is unitless)
4372					this.css( type, typeof size === "string" ? size : size + "px" );
4373	};
4374
4375});
4376})();
4377/*
4378Script: Core.js
4379	MooTools - My Object Oriented JavaScript Tools.
4380
4381License:
4382	MIT-style license.
4383
4384Copyright:
4385	Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/).
4386
4387Code & Documentation:
4388	[The MooTools production team](http://mootools.net/developers/).
4389
4390Inspiration:
4391	- Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
4392	- Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
4393*/
4394
4395var MooTools = {
4396	'version': '1.2.2',
4397	'build': 'f0491d62fbb7e906789aa3733d6a67d43e5af7c9'
4398};
4399
4400var Native = function(options){
4401	options = options || {};
4402	var name = options.name;
4403	var legacy = options.legacy;
4404	var protect = options.protect;
4405	var methods = options.implement;
4406	var generics = options.generics;
4407	var initialize = options.initialize;
4408	var afterImplement = options.afterImplement || function(){};
4409	var object = initialize || legacy;
4410	generics = generics !== false;
4411
4412	object.constructor = Native;
4413	object.$family = {name: 'native'};
4414	if (legacy && initialize) object.prototype = legacy.prototype;
4415	object.prototype.constructor = object;
4416
4417	if (name){
4418		var family = name.toLowerCase();
4419		object.prototype.$family = {name: family};
4420		Native.typize(object, family);
4421	}
4422
4423	var add = function(obj, name, method, force){
4424		if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method;
4425		if (generics) Native.genericize(obj, name, protect);
4426		afterImplement.call(obj, name, method);
4427		return obj;
4428	};
4429
4430	object.alias = function(a1, a2, a3){
4431		if (typeof a1 == 'string'){
4432			if ((a1 = this.prototype[a1])) return add(this, a2, a1, a3);
4433		}
4434		for (var a in a1) this.alias(a, a1[a], a2);
4435		return this;
4436	};
4437
4438	object.implement = function(a1, a2, a3){
4439		if (typeof a1 == 'string') return add(this, a1, a2, a3);
4440		for (var p in a1) add(this, p, a1[p], a2);
4441		return this;
4442	};
4443
4444	if (methods) object.implement(methods);
4445
4446	return object;
4447};
4448
4449Native.genericize = function(object, property, check){
4450	if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){
4451		var args = Array.prototype.slice.call(arguments);
4452		return object.prototype[property].apply(args.shift(), args);
4453	};
4454};
4455
4456Native.implement = function(objects, properties){
4457	for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties);
4458};
4459
4460Native.typize = function(object, family){
4461	if (!object.type) object.type = function(item){
4462		return ($type(item) === family);
4463	};
4464};
4465
4466(function(){
4467	var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String};
4468	for (var n in natives) new Native({name: n, initialize: natives[n], protect: true});
4469
4470	var types = {'boolean': Boolean, 'native': Native, 'object': Object};
4471	for (var t in types) Native.typize(types[t], t);
4472
4473	var generics = {
4474		'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"],
4475		'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"]
4476	};
4477	for (var g in generics){
4478		for (var i = generics[g].length; i--;) Native.genericize(window[g], generics[g][i], true);
4479	}
4480})();
4481
4482var Hash = new Native({
4483
4484	name: 'Hash',
4485
4486	initialize: function(object){
4487		if ($type(object) == 'hash') object = $unlink(object.getClean());
4488		for (var key in object) this[key] = object[key];
4489		return this;
4490	}
4491
4492});
4493
4494Hash.implement({
4495
4496	forEach: function(fn, bind){
4497		for (var key in this){
4498			if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this);
4499		}
4500	},
4501
4502	getClean: function(){
4503		var clean = {};
4504		for (var key in this){
4505			if (this.hasOwnProperty(key)) clean[key] = this[key];
4506		}
4507		return clean;
4508	},
4509
4510	getLength: function(){
4511		var length = 0;
4512		for (var key in this){
4513			if (this.hasOwnProperty(key)) length++;
4514		}
4515		return length;
4516	}
4517
4518});
4519
4520Hash.alias('forEach', 'each');
4521
4522Array.implement({
4523
4524	forEach: function(fn, bind){
4525		for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this);
4526	}
4527
4528});
4529
4530Array.alias('forEach', 'each');
4531
4532function $A(iterable){
4533	if (iterable.item){
4534		var l = iterable.length, array = new Array(l);
4535		while (l--) array[l] = iterable[l];
4536		return array;
4537	}
4538	return Array.prototype.slice.call(iterable);
4539};
4540
4541function $arguments(i){
4542	return function(){
4543		return arguments[i];
4544	};
4545};
4546
4547function $chk(obj){
4548	return !!(obj || obj === 0);
4549};
4550
4551function $clear(timer){
4552	clearTimeout(timer);
4553	clearInterval(timer);
4554	return null;
4555};
4556
4557function $defined(obj){
4558	return (obj != undefined);
4559};
4560
4561function $each(iterable, fn, bind){
4562	var type = $type(iterable);
4563	((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind);
4564};
4565
4566function $empty(){};
4567
4568function $extend(original, extended){
4569	for (var key in (extended || {})) original[key] = extended[key];
4570	return original;
4571};
4572
4573function $H(object){
4574	return new Hash(object);
4575};
4576
4577function $lambda(value){
4578	return (typeof value == 'function') ? value : function(){
4579		return value;
4580	};
4581};
4582
4583function $merge(){
4584	var args = Array.slice(arguments);
4585	args.unshift({});
4586	return $mixin.apply(null, args);
4587};
4588
4589function $mixin(mix){
4590	for (var i = 1, l = arguments.length; i < l; i++){
4591		var object = arguments[i];
4592		if ($type(object) != 'object') continue;
4593		for (var key in object){
4594			var op = object[key], mp = mix[key];
4595			mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $mixin(mp, op) : $unlink(op);
4596		}
4597	}
4598	return mix;
4599};
4600
4601function $pick(){
4602	for (var i = 0, l = arguments.length; i < l; i++){
4603		if (arguments[i] != undefined) return arguments[i];
4604	}
4605	return null;
4606};
4607
4608function $random(min, max){
4609	return Math.floor(Math.random() * (max - min + 1) + min);
4610};
4611
4612function $splat(obj){
4613	var type = $type(obj);
4614	return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : [];
4615};
4616
4617var $time = Date.now || function(){
4618	return +new Date;
4619};
4620
4621function $try(){
4622	for (var i = 0, l = arguments.length; i < l; i++){
4623		try {
4624			return arguments[i]();
4625		} catch(e){}
4626	}
4627	return null;
4628};
4629
4630function $type(obj){
4631	if (obj == undefined) return false;
4632	if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name;
4633	if (obj.nodeName){
4634		switch (obj.nodeType){
4635			case 1: return 'element';
4636			case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
4637		}
4638	} else if (typeof obj.length == 'number'){
4639		if (obj.callee) return 'arguments';
4640		else if (obj.item) return 'collection';
4641	}
4642	return typeof obj;
4643};
4644
4645function $unlink(object){
4646	var unlinked;
4647	switch ($type(object)){
4648		case 'object':
4649			unlinked = {};
4650			for (var p in object) unlinked[p] = $unlink(object[p]);
4651		break;
4652		case 'hash':
4653			unlinked = new Hash(object);
4654		break;
4655		case 'array':
4656			unlinked = [];
4657			for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]);
4658		break;
4659		default: return object;
4660	}
4661	return unlinked;
4662};
4663
4664
4665/*
4666Script: Browser.js
4667	The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash.
4668
4669License:
4670	MIT-style license.
4671*/
4672
4673var Browser = $merge({
4674
4675	Engine: {name: 'unknown', version: 0},
4676
4677	Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()},
4678
4679	Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)},
4680
4681	Plugins: {},
4682
4683	Engines: {
4684
4685		presto: function(){
4686			return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925));
4687		},
4688
4689		trident: function(){
4690			return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? 5 : 4);
4691		},
4692
4693		webkit: function(){
4694			return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419);
4695		},
4696
4697		gecko: function(){
4698			return (document.getBoxObjectFor == undefined) ? false : ((document.getElementsByClassName) ? 19 : 18);
4699		}
4700
4701	}
4702
4703}, Browser || {});
4704
4705Browser.Platform[Browser.Platform.name] = true;
4706
4707Browser.detect = function(){
4708
4709	for (var engine in this.Engines){
4710		var version = this.Engines[engine]();
4711		if (version){
4712			this.Engine = {name: engine, version: version};
4713			this.Engine[engine] = this.Engine[engine + version] = true;
4714			break;
4715		}
4716	}
4717
4718	return {name: engine, version: version};
4719
4720};
4721
4722Browser.detect();
4723
4724Browser.Request = function(){
4725	return $try(function(){
4726		return new XMLHttpRequest();
4727	}, function(){
4728		return new ActiveXObject('MSXML2.XMLHTTP');
4729	});
4730};
4731
4732Browser.Features.xhr = !!(Browser.Request());
4733
4734Browser.Plugins.Flash = (function(){
4735	var version = ($try(function(){
4736		return navigator.plugins['Shockwave Flash'].description;
4737	}, function(){
4738		return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
4739	}) || '0 r0').match(/\d+/g);
4740	return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
4741})();
4742
4743function $exec(text){
4744	if (!text) return text;
4745	if (window.execScript){
4746		window.execScript(text);
4747	} else {
4748		var script = document.createElement('script');
4749		script.setAttribute('type', 'text/javascript');
4750		script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text;
4751		document.head.appendChild(script);
4752		document.head.removeChild(script);
4753	}
4754	return text;
4755};
4756
4757Native.UID = 1;
4758
4759var $uid = (Browser.Engine.trident) ? function(item){
4760	return (item.uid || (item.uid = [Native.UID++]))[0];
4761} : function(item){
4762	return item.uid || (item.uid = Native.UID++);
4763};
4764
4765var Window = new Native({
4766
4767	name: 'Window',
4768
4769	legacy: (Browser.Engine.trident) ? null: window.Window,
4770
4771	initialize: function(win){
4772		$uid(win);
4773		if (!win.Element){
4774			win.Element = $empty;
4775			if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2
4776			win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {};
4777		}
4778		win.document.window = win;
4779		return $extend(win, Window.Prototype);
4780	},
4781
4782	afterImplement: function(property, value){
4783		window[property] = Window.Prototype[property] = value;
4784	}
4785
4786});
4787
4788Window.Prototype = {$family: {name: 'window'}};
4789
4790new Window(window);
4791
4792var Document = new Native({
4793
4794	name: 'Document',
4795
4796	legacy: (Browser.Engine.trident) ? null: window.Document,
4797
4798	initialize: function(doc){
4799		$uid(doc);
4800		doc.head = doc.getElementsByTagName('head')[0];
4801		doc.html = doc.getElementsByTagName('html')[0];
4802		if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){
4803			doc.execCommand("BackgroundImageCache", false, true);
4804		});
4805		if (Browser.Engine.trident) doc.window.attachEvent('onunload', function() {
4806			doc.window.detachEvent('onunload', arguments.callee);
4807			doc.head = doc.html = doc.window = null;
4808		});
4809		return $extend(doc, Document.Prototype);
4810	},
4811
4812	afterImplement: function(property, value){
4813		document[property] = Document.Prototype[property] = value;
4814	}
4815
4816});
4817
4818Document.Prototype = {$family: {name: 'document'}};
4819
4820new Document(document);
4821
4822
4823/*
4824Script: Array.js
4825	Contains Array Prototypes like each, contains, and erase.
4826
4827License:
4828	MIT-style license.
4829*/
4830
4831Array.implement({
4832
4833	every: function(fn, bind){
4834		for (var i = 0, l = this.length; i < l; i++){
4835			if (!fn.call(bind, this[i], i, this)) return false;
4836		}
4837		return true;
4838	},
4839
4840	filter: function(fn, bind){
4841		var results = [];
4842		for (var i = 0, l = this.length; i < l; i++){
4843			if (fn.call(bind, this[i], i, this)) results.push(this[i]);
4844		}
4845		return results;
4846	},
4847
4848	clean: function() {
4849		return this.filter($defined);
4850	},
4851
4852	indexOf: function(item, from){
4853		var len = this.length;
4854		for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
4855			if (this[i] === item) return i;
4856		}
4857		return -1;
4858	},
4859
4860	map: function(fn, bind){
4861		var results = [];
4862		for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this);
4863		return results;
4864	},
4865
4866	some: function(fn, bind){
4867		for (var i = 0, l = this.length; i < l; i++){
4868			if (fn.call(bind, this[i], i, this)) return true;
4869		}
4870		return false;
4871	},
4872
4873	associate: function(keys){
4874		var obj = {}, length = Math.min(this.length, keys.length);
4875		for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
4876		return obj;
4877	},
4878
4879	link: function(object){
4880		var result = {};
4881		for (var i = 0, l = this.length; i < l; i++){
4882			for (var key in object){
4883				if (object[key](this[i])){
4884					result[key] = this[i];
4885					delete object[key];
4886					break;
4887				}
4888			}
4889		}
4890		return result;
4891	},
4892
4893	contains: function(item, from){
4894		return this.indexOf(item, from) != -1;
4895	},
4896
4897	extend: function(array){
4898		for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
4899		return this;
4900	},
4901
4902	getLast: function(){
4903		return (this.length) ? this[this.length - 1] : null;
4904	},
4905
4906	getRandom: function(){
4907		return (this.length) ? this[$random(0, this.length - 1)] : null;
4908	},
4909
4910	include: function(item){
4911		if (!this.contains(item)) this.push(item);
4912		return this;
4913	},
4914
4915	combine: function(array){
4916		for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
4917		return this;
4918	},
4919
4920	erase: function(item){
4921		for (var i = this.length; i--; i){
4922			if (this[i] === item) this.splice(i, 1);
4923		}
4924		return this;
4925	},
4926
4927	empty: function(){
4928		this.length = 0;
4929		return this;
4930	},
4931
4932	flatten: function(){
4933		var array = [];
4934		for (var i = 0, l = this.length; i < l; i++){
4935			var type = $type(this[i]);
4936			if (!type) continue;
4937			array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]);
4938		}
4939		return array;
4940	},
4941
4942	hexToRgb: function(array){
4943		if (this.length != 3) return null;
4944		var rgb = this.map(function(value){
4945			if (value.length == 1) value += value;
4946			return value.toInt(16);
4947		});
4948		return (array) ? rgb : 'rgb(' + rgb + ')';
4949	},
4950
4951	rgbToHex: function(array){
4952		if (this.length < 3) return null;
4953		if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
4954		var hex = [];
4955		for (var i = 0; i < 3; i++){
4956			var bit = (this[i] - 0).toString(16);
4957			hex.push((bit.length == 1) ? '0' + bit : bit);
4958		}
4959		return (array) ? hex : '#' + hex.join('');
4960	}
4961
4962});
4963
4964
4965/*
4966Script: Function.js
4967	Contains Function Prototypes like create, bind, pass, and delay.
4968
4969License:
4970	MIT-style license.
4971*/
4972
4973Function.implement({
4974
4975	extend: function(properties){
4976		for (var property in properties) this[property] = properties[property];
4977		return this;
4978	},
4979
4980	create: function(options){
4981		var self = this;
4982		options = options || {};
4983		return function(event){
4984			var args = options.arguments;
4985			args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0);
4986			if (options.event) args = [event || window.event].extend(args);
4987			var returns = function(){
4988				return self.apply(options.bind || null, args);
4989			};
4990			if (options.delay) return setTimeout(returns, options.delay);
4991			if (options.periodical) return setInterval(returns, options.periodical);
4992			if (options.attempt) return $try(returns);
4993			return returns();
4994		};
4995	},
4996
4997	run: function(args, bind){
4998		return this.apply(bind, $splat(args));
4999	},
5000
5001	pass: function(args, bind){
5002		return this.create({bind: bind, arguments: args});
5003	},
5004
5005	bind: function(bind, args){
5006		return this.create({bind: bind, arguments: args});
5007	},
5008
5009	bindWithEvent: function(bind, args){
5010		return this.create({bind: bind, arguments: args, event: true});
5011	},
5012
5013	attempt: function(args, bind){
5014		return this.create({bind: bind, arguments: args, attempt: true})();
5015	},
5016
5017	delay: function(delay, bind, args){
5018		return this.create({bind: bind, arguments: args, delay: delay})();
5019	},
5020
5021	periodical: function(periodical, bind, args){
5022		return this.create({bind: bind, arguments: args, periodical: periodical})();
5023	}
5024
5025});
5026
5027
5028/*
5029Script: Number.js
5030	Contains Number Prototypes like limit, round, times, and ceil.
5031
5032License:
5033	MIT-style license.
5034*/
5035
5036Number.implement({
5037
5038	limit: function(min, max){
5039		return Math.min(max, Math.max(min, this));
5040	},
5041
5042	round: function(precision){
5043		precision = Math.pow(10, precision || 0);
5044		return Math.round(this * precision) / precision;
5045	},
5046
5047	times: function(fn, bind){
5048		for (var i = 0; i < this; i++) fn.call(bind, i, this);
5049	},
5050
5051	toFloat: function(){
5052		return parseFloat(this);
5053	},
5054
5055	toInt: function(base){
5056		return parseInt(this, base || 10);
5057	}
5058
5059});
5060
5061Number.alias('times', 'each');
5062
5063(function(math){
5064	var methods = {};
5065	math.each(function(name){
5066		if (!Number[name]) methods[name] = function(){
5067			return Math[name].apply(null, [this].concat($A(arguments)));
5068		};
5069	});
5070	Number.implement(methods);
5071})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
5072
5073
5074/*
5075Script: String.js
5076	Contains String Prototypes like camelCase, capitalize, test, and toInt.
5077
5078License:
5079	MIT-style license.
5080*/
5081
5082String.implement({
5083
5084	test: function(regex, params){
5085		return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this);
5086	},
5087
5088	contains: function(string, separator){
5089		return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1;
5090	},
5091
5092	trim: function(){
5093		return this.replace(/^\s+|\s+$/g, '');
5094	},
5095
5096	clean: function(){
5097		return this.replace(/\s+/g, ' ').trim();
5098	},
5099
5100	camelCase: function(){
5101		return this.replace(/-\D/g, function(match){
5102			return match.charAt(1).toUpperCase();
5103		});
5104	},
5105
5106	hyphenate: function(){
5107		return this.replace(/[A-Z]/g, function(match){
5108			return ('-' + match.charAt(0).toLowerCase());
5109		});
5110	},
5111
5112	capitalize: function(){
5113		return this.replace(/\b[a-z]/g, function(match){
5114			return match.toUpperCase();
5115		});
5116	},
5117
5118	escapeRegExp: function(){
5119		return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
5120	},
5121
5122	toInt: function(base){
5123		return parseInt(this, base || 10);
5124	},
5125
5126	toFloat: function(){
5127		return parseFloat(this);
5128	},
5129
5130	hexToRgb: function(array){
5131		var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
5132		return (hex) ? hex.slice(1).hexToRgb(array) : null;
5133	},
5134
5135	rgbToHex: function(array){
5136		var rgb = this.match(/\d{1,3}/g);
5137		return (rgb) ? rgb.rgbToHex(array) : null;
5138	},
5139
5140	stripScripts: function(option){
5141		var scripts = '';
5142		var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
5143			scripts += arguments[1] + '\n';
5144			return '';
5145		});
5146		if (option === true) $exec(scripts);
5147		else if ($type(option) == 'function') option(scripts, text);
5148		return text;
5149	},
5150
5151	substitute: function(object, regexp){
5152		return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
5153			if (match.charAt(0) == '\\') return match.slice(1);
5154			return (object[name] != undefined) ? object[name] : '';
5155		});
5156	}
5157
5158});
5159
5160
5161/*
5162Script: Hash.js
5163	Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
5164
5165License:
5166	MIT-style license.
5167*/
5168
5169Hash.implement({
5170
5171	has: Object.prototype.hasOwnProperty,
5172
5173	keyOf: function(value){
5174		for (var key in this){
5175			if (this.hasOwnProperty(key) && this[key] === value) return key;
5176		}
5177		return null;
5178	},
5179
5180	hasValue: function(value){
5181		return (Hash.keyOf(this, value) !== null);
5182	},
5183
5184	extend: function(properties){
5185		Hash.each(properties, function(value, key){
5186			Hash.set(this, key, value);
5187		}, this);
5188		return this;
5189	},
5190
5191	combine: function(properties){
5192		Hash.each(properties, function(value, key){
5193			Hash.include(this, key, value);
5194		}, this);
5195		return this;
5196	},
5197
5198	erase: function(key){
5199		if (this.hasOwnProperty(key)) delete this[key];
5200		return this;
5201	},
5202
5203	get: function(key){
5204		return (this.hasOwnProperty(key)) ? this[key] : null;
5205	},
5206
5207	set: function(key, value){
5208		if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
5209		return this;
5210	},
5211
5212	empty: function(){
5213		Hash.each(this, function(value, key){
5214			delete this[key];
5215		}, this);
5216		return this;
5217	},
5218
5219	include: function(key, value){
5220		if (this[key] == undefined) this[key] = value;
5221		return this;
5222	},
5223
5224	map: function(fn, bind){
5225		var results = new Hash;
5226		Hash.each(this, function(value, key){
5227			results.set(key, fn.call(bind, value, key, this));
5228		}, this);
5229		return results;
5230	},
5231
5232	filter: function(fn, bind){
5233		var results = new Hash;
5234		Hash.each(this, function(value, key){
5235			if (fn.call(bind, value, key, this)) results.set(key, value);
5236		}, this);
5237		return results;
5238	},
5239
5240	every: function(fn, bind){
5241		for (var key in this){
5242			if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false;
5243		}
5244		return true;
5245	},
5246
5247	some: function(fn, bind){
5248		for (var key in this){
5249			if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true;
5250		}
5251		return false;
5252	},
5253
5254	getKeys: function(){
5255		var keys = [];
5256		Hash.each(this, function(value, key){
5257			keys.push(key);
5258		});
5259		return keys;
5260	},
5261
5262	getValues: function(){
5263		var values = [];
5264		Hash.each(this, function(value){
5265			values.push(value);
5266		});
5267		return values;
5268	},
5269
5270	toQueryString: function(base){
5271		var queryString = [];
5272		Hash.each(this, function(value, key){
5273			if (base) key = base + '[' + key + ']';
5274			var result;
5275			switch ($type(value)){
5276				case 'object': result = Hash.toQueryString(value, key); break;
5277				case 'array':
5278					var qs = {};
5279					value.each(function(val, i){
5280						qs[i] = val;
5281					});
5282					result = Hash.toQueryString(qs, key);
5283				break;
5284				default: result = key + '=' + encodeURIComponent(value);
5285			}
5286			if (value != undefined) queryString.push(result);
5287		});
5288
5289		return queryString.join('&');
5290	}
5291
5292});
5293
5294Hash.alias({keyOf: 'indexOf', hasValue: 'contains'});
5295
5296
5297/*
5298Script: Event.js
5299	Contains the Event Native, to make the event object completely crossbrowser.
5300
5301License:
5302	MIT-style license.
5303*/
5304
5305var Event = new Native({
5306
5307	name: 'Event',
5308
5309	initialize: function(event, win){
5310		win = win || window;
5311		var doc = win.document;
5312		event = event || win.event;
5313		if (event.$extended) return event;
5314		this.$extended = true;
5315		var type = event.type;
5316		var target = event.target || event.srcElement;
5317		while (target && target.nodeType == 3) target = target.parentNode;
5318
5319		if (type.test(/key/)){
5320			var code = event.which || event.keyCode;
5321			var key = Event.Keys.keyOf(code);
5322			if (type == 'keydown'){
5323				var fKey = code - 111;
5324				if (fKey > 0 && fKey < 13) key = 'f' + fKey;
5325			}
5326			key = key || String.fromCharCode(code).toLowerCase();
5327		} else if (type.match(/(click|mouse|menu)/i)){
5328			doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
5329			var page = {
5330				x: event.pageX || event.clientX + doc.scrollLeft,
5331				y: event.pageY || event.clientY + doc.scrollTop
5332			};
5333			var client = {
5334				x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX,
5335				y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY
5336			};
5337			if (type.match(/DOMMouseScroll|mousewheel/)){
5338				var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
5339			}
5340			var rightClick = (event.which == 3) || (event.button == 2);
5341			var related = null;
5342			if (type.match(/over|out/)){
5343				switch (type){
5344					case 'mouseover': related = event.relatedTarget || event.fromElement; break;
5345					case 'mouseout': related = event.relatedTarget || event.toElement;
5346				}
5347				if (!(function(){
5348					while (related && related.nodeType == 3) related = related.parentNode;
5349					return true;
5350				}).create({attempt: Browser.Engine.gecko})()) related = false;
5351			}
5352		}
5353
5354		return $extend(this, {
5355			event: event,
5356			type: type,
5357
5358			page: page,
5359			client: client,
5360			rightClick: rightClick,
5361
5362			wheel: wheel,
5363
5364			relatedTarget: related,
5365			target: target,
5366
5367			code: code,
5368			key: key,
5369
5370			shift: event.shiftKey,
5371			control: event.ctrlKey,
5372			alt: event.altKey,
5373			meta: event.metaKey
5374		});
5375	}
5376
5377});
5378
5379Event.Keys = new Hash({
5380	'enter': 13,
5381	'up': 38,
5382	'down': 40,
5383	'left': 37,
5384	'right': 39,
5385	'esc': 27,
5386	'space': 32,
5387	'backspace': 8,
5388	'tab': 9,
5389	'delete': 46
5390});
5391
5392Event.implement({
5393
5394	stop: function(){
5395		return this.stopPropagation().preventDefault();
5396	},
5397
5398	stopPropagation: function(){
5399		if (this.event.stopPropagation) this.event.stopPropagation();
5400		else this.event.cancelBubble = true;
5401		return this;
5402	},
5403
5404	preventDefault: function(){
5405		if (this.event.preventDefault) this.event.preventDefault();
5406		else this.event.returnValue = false;
5407		return this;
5408	}
5409
5410});
5411
5412
5413/*
5414Script: Class.js
5415	Contains the Class Function for easily creating, extending, and implementing reusable Classes.
5416
5417License:
5418	MIT-style license.
5419*/
5420
5421function Class(params){
5422
5423	if (params instanceof Function) params = {initialize: params};
5424
5425	var newClass = function(){
5426		Object.reset(this);
5427		if (newClass._prototyping) return this;
5428		this._current = $empty;
5429		var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
5430		delete this._current; delete this.caller;
5431		return value;
5432	}.extend(this);
5433
5434	newClass.implement(params);
5435
5436	newClass.constructor = Class;
5437	newClass.prototype.constructor = newClass;
5438
5439	return newClass;
5440
5441};
5442
5443Function.prototype.protect = function(){
5444	this._protected = true;
5445	return this;
5446};
5447
5448Object.reset = function(object, key){
5449
5450	if (key == null){
5451		for (var p in object) Object.reset(object, p);
5452		return object;
5453	}
5454
5455	delete object[key];
5456
5457	switch ($type(object[key])){
5458		case 'object':
5459			var F = function(){};
5460			F.prototype = object[key];
5461			var i = new F;
5462			object[key] = Object.reset(i);
5463		break;
5464		case 'array': object[key] = $unlink(object[key]); break;
5465	}
5466
5467	return object;
5468
5469};
5470
5471new Native({name: 'Class', initialize: Class}).extend({
5472
5473	instantiate: function(F){
5474		F._prototyping = true;
5475		var proto = new F;
5476		delete F._prototyping;
5477		return proto;
5478	},
5479
5480	wrap: function(self, key, method){
5481		if (method._origin) method = method._origin;
5482
5483		return function(){
5484			if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.');
5485			var caller = this.caller, current = this._current;
5486			this.caller = current; this._current = arguments.callee;
5487			var result = method.apply(this, arguments);
5488			this._current = current; this.caller = caller;
5489			return result;
5490		}.extend({_owner: self, _origin: method, _name: key});
5491
5492	}
5493
5494});
5495
5496Class.implement({
5497
5498	implement: function(key, value){
5499
5500		if ($type(key) == 'object'){
5501			for (var p in key) this.implement(p, key[p]);
5502			return this;
5503		}
5504
5505		var mutator = Class.Mutators[key];
5506
5507		if (mutator){
5508			value = mutator.call(this, value);
5509			if (value == null) return this;
5510		}
5511
5512		var proto = this.prototype;
5513
5514		switch ($type(value)){
5515
5516			case 'function':
5517				if (value._hidden) return this;
5518				proto[key] = Class.wrap(this, key, value);
5519			break;
5520
5521			case 'object':
5522				var previous = proto[key];
5523				if ($type(previous) == 'object') $mixin(previous, value);
5524				else proto[key] = $unlink(value);
5525			break;
5526
5527			case 'array':
5528				proto[key] = $unlink(value);
5529			break;
5530
5531			default: proto[key] = value;
5532
5533		}
5534
5535		return this;
5536
5537	}
5538
5539});
5540
5541Class.Mutators = {
5542
5543	Extends: function(parent){
5544
5545		this.parent = parent;
5546		this.prototype = Class.instantiate(parent);
5547
5548		this.implement('parent', function(){
5549			var name = this.caller._name, previous = this.caller._owner.parent.prototype[name];
5550			if (!previous) throw new Error('The method "' + name + '" has no parent.');
5551			return previous.apply(this, arguments);
5552		}.protect());
5553
5554	},
5555
5556	Implements: function(items){
5557		$splat(items).each(function(item){
5558			if (item instanceof Function) item = Class.instantiate(item);
5559			this.implement(item);
5560		}, this);
5561
5562	}
5563
5564};
5565
5566
5567/*
5568Script: Class.Extras.js
5569	Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
5570
5571License:
5572	MIT-style license.
5573*/
5574
5575var Chain = new Class({
5576
5577	$chain: [],
5578
5579	chain: function(){
5580		this.$chain.extend(Array.flatten(arguments));
5581		return this;
5582	},
5583
5584	callChain: function(){
5585		return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
5586	},
5587
5588	clearChain: function(){
5589		this.$chain.empty();
5590		return this;
5591	}
5592
5593});
5594
5595var Events = new Class({
5596
5597	$events: {},
5598
5599	addEvent: function(type, fn, internal){
5600		type = Events.removeOn(type);
5601		if (fn != $empty){
5602			this.$events[type] = this.$events[type] || [];
5603			this.$events[type].include(fn);
5604			if (internal) fn.internal = true;
5605		}
5606		return this;
5607	},
5608
5609	addEvents: function(events){
5610		for (var type in events) this.addEvent(type, events[type]);
5611		return this;
5612	},
5613
5614	fireEvent: function(type, args, delay){
5615		type = Events.removeOn(type);
5616		if (!this.$events || !this.$events[type]) return this;
5617		this.$events[type].each(function(fn){
5618			fn.create({'bind': this, 'delay': delay, 'arguments': args})();
5619		}, this);
5620		return this;
5621	},
5622
5623	removeEvent: function(type, fn){
5624		type = Events.removeOn(type);
5625		if (!this.$events[type]) return this;
5626		if (!fn.internal) this.$events[type].erase(fn);
5627		return this;
5628	},
5629
5630	removeEvents: function(events){
5631		var type;
5632		if ($type(events) == 'object'){
5633			for (type in events) this.removeEvent(type, events[type]);
5634			return this;
5635		}
5636		if (events) events = Events.removeOn(events);
5637		for (type in this.$events){
5638			if (events && events != type) continue;
5639			var fns = this.$events[type];
5640			for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]);
5641		}
5642		return this;
5643	}
5644
5645});
5646
5647Events.removeOn = function(string){
5648	return string.replace(/^on([A-Z])/, function(full, first) {
5649		return first.toLowerCase();
5650	});
5651};
5652
5653var Options = new Class({
5654
5655	setOptions: function(){
5656		this.options = $merge.run([this.options].extend(arguments));
5657		if (!this.addEvent) return this;
5658		for (var option in this.options){
5659			if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
5660			this.addEvent(option, this.options[option]);
5661			delete this.options[option];
5662		}
5663		return this;
5664	}
5665
5666});
5667
5668
5669/*
5670Script: Element.js
5671	One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser,
5672	time-saver methods to let you easily work with HTML Elements.
5673
5674License:
5675	MIT-style license.
5676*/
5677
5678var Element = new Native({
5679
5680	name: 'Element',
5681
5682	legacy: window.Element,
5683
5684	initialize: function(tag, props){
5685		var konstructor = Element.Constructors.get(tag);
5686		if (konstructor) return konstructor(props);
5687		if (typeof tag == 'string') return document.newElement(tag, props);
5688		return $(tag).set(props);
5689	},
5690
5691	afterImplement: function(key, value){
5692		Element.Prototype[key] = value;
5693		if (Array[key]) return;
5694		Elements.implement(key, function(){
5695			var items = [], elements = true;
5696			for (var i = 0, j = this.length; i < j; i++){
5697				var returns = this[i][key].apply(this[i], arguments);
5698				items.push(returns);
5699				if (elements) elements = ($type(returns) == 'element');
5700			}
5701			return (elements) ? new Elements(items) : items;
5702		});
5703	}
5704
5705});
5706
5707Element.Prototype = {$family: {name: 'element'}};
5708
5709Element.Constructors = new Hash;
5710
5711var IFrame = new Native({
5712
5713	name: 'IFrame',
5714
5715	generics: false,
5716
5717	initialize: function(){
5718		var params = Array.link(arguments, {properties: Object.type, iframe: $defined});
5719		var props = params.properties || {};
5720		var iframe = $(params.iframe) || false;
5721		var onload = props.onload || $empty;
5722		delete props.onload;
5723		props.id = props.name = $pick(props.id, props.name, iframe.id, iframe.name, 'IFrame_' + $time());
5724		iframe = new Element(iframe || 'iframe', props);
5725		var onFrameLoad = function(){
5726			var host = $try(function(){
5727				return iframe.contentWindow.location.host;
5728			});
5729			if (host && host == window.location.host){
5730				var win = new Window(iframe.contentWindow);
5731				new Document(iframe.contentWindow.document);
5732				$extend(win.Element.prototype, Element.Prototype);
5733			}
5734			onload.call(iframe.contentWindow, iframe.contentWindow.document);
5735		};
5736		(window.frames[props.id]) ? onFrameLoad() : iframe.addListener('load', onFrameLoad);
5737		return iframe;
5738	}
5739
5740});
5741
5742var Elements = new Native({
5743
5744	initialize: function(elements, options){
5745		options = $extend({ddup: true, cash: true}, options);
5746		elements = elements || [];
5747		if (options.ddup || options.cash){
5748			var uniques = {}, returned = [];
5749			for (var i = 0, l = elements.length; i < l; i++){
5750				var el = $.element(elements[i], !options.cash);
5751				if (options.ddup){
5752					if (uniques[el.uid]) continue;
5753					uniques[el.uid] = true;
5754				}
5755				returned.push(el);
5756			}
5757			elements = returned;
5758		}
5759		return (options.cash) ? $extend(elements, this) : elements;
5760	}
5761
5762});
5763
5764Elements.implement({
5765
5766	filter: function(filter, bind){
5767		if (!filter) return this;
5768		return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){
5769			return item.match(filter);
5770		} : filter, bind));
5771	}
5772
5773});
5774
5775Document.implement({
5776
5777	newElement: function(tag, props){
5778		if (Browser.Engine.trident && props){
5779			['name', 'type', 'checked'].each(function(attribute){
5780				if (!props[attribute]) return;
5781				tag += ' ' + attribute + '="' + props[attribute] + '"';
5782				if (attribute != 'checked') delete props[attribute];
5783			});
5784			tag = '<' + tag + '>';
5785		}
5786		return $.element(this.createElement(tag)).set(props);
5787	},
5788
5789	newTextNode: function(text){
5790		return this.createTextNode(text);
5791	},
5792
5793	getDocument: function(){
5794		return this;
5795	},
5796
5797	getWindow: function(){
5798		return this.window;
5799	}
5800
5801});
5802
5803Window.implement({
5804
5805	$: function(el, nocash){
5806		if (el && el.$family && el.uid) return el;
5807		var type = $type(el);
5808		return ($[type]) ? $[type](el, nocash, this.document) : null;
5809	},
5810
5811	$$: function(selector){
5812		if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector);
5813		var elements = [];
5814		var args = Array.flatten(arguments);
5815		for (var i = 0, l = args.length; i < l; i++){
5816			var item = args[i];
5817			switch ($type(item)){
5818				case 'element': elements.push(item); break;
5819				case 'string': elements.extend(this.document.getElements(item, true));
5820			}
5821		}
5822		return new Elements(elements);
5823	},
5824
5825	getDocument: function(){
5826		return this.document;
5827	},
5828
5829	getWindow: function(){
5830		return this;
5831	}
5832
5833});
5834
5835$.string = function(id, nocash, doc){
5836	id = doc.getElementById(id);
5837	return (id) ? $.element(id, nocash) : null;
5838};
5839
5840$.element = function(el, nocash){
5841	$uid(el);
5842	if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){
5843		var proto = Element.Prototype;
5844		for (var p in proto) el[p] = proto[p];
5845	};
5846	return el;
5847};
5848
5849$.object = function(obj, nocash, doc){
5850	if (obj.toElement) return $.element(obj.toElement(doc), nocash);
5851	return null;
5852};
5853
5854$.textnode = $.whitespace = $.window = $.document = $arguments(0);
5855
5856Native.implement([Element, Document], {
5857
5858	getElement: function(selector, nocash){
5859		return $(this.getElements(selector, true)[0] || null, nocash);
5860	},
5861
5862	getElements: function(tags, nocash){
5863		tags = tags.split(',');
5864		var elements = [];
5865		var ddup = (tags.length > 1);
5866		tags.each(function(tag){
5867			var partial = this.getElementsByTagName(tag.trim());
5868			(ddup) ? elements.extend(partial) : elements = partial;
5869		}, this);
5870		return new Elements(elements, {ddup: ddup, cash: !nocash});
5871	}
5872
5873});
5874
5875(function(){
5876
5877var collected = {}, storage = {};
5878var props = {input: 'checked', option: 'selected', textarea: (Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerHTML' : 'value'};
5879
5880var get = function(uid){
5881	return (storage[uid] || (storage[uid] = {}));
5882};
5883
5884var clean = function(item, retain){
5885	if (!item) return;
5886	var uid = item.uid;
5887	if (Browser.Engine.trident){
5888		if (item.clearAttributes){
5889			var clone = retain && item.cloneNode(false);
5890			item.clearAttributes();
5891			if (clone) item.mergeAttributes(clone);
5892		} else if (item.removeEvents){
5893			item.removeEvents();
5894		}
5895		if ((/object/i).test(item.tagName)){
5896			for (var p in item){
5897				if (typeof item[p] == 'function') item[p] = $empty;
5898			}
5899			Element.dispose(item);
5900		}
5901	}
5902	if (!uid) return;
5903	collected[uid] = storage[uid] = null;
5904};
5905
5906var purge = function(){
5907	Hash.each(collected, clean);
5908	if (Browser.Engine.trident) $A(document.getElementsByTagName('object')).each(clean);
5909	if (window.CollectGarbage) CollectGarbage();
5910	collected = storage = null;
5911};
5912
5913var walk = function(element, walk, start, match, all, nocash){
5914	var el = element[start || walk];
5915	var elements = [];
5916	while (el){
5917		if (el.nodeType == 1 && (!match || Element.match(el, match))){
5918			if (!all) return $(el, nocash);
5919			elements.push(el);
5920		}
5921		el = el[walk];
5922	}
5923	return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : null;
5924};
5925
5926var attributes = {
5927	'html': 'innerHTML',
5928	'class': 'className',
5929	'for': 'htmlFor',
5930	'text': (Browser.Engine.trident || (Browser.Engine.webkit && Browser.Engine.version < 420)) ? 'innerText' : 'textContent'
5931};
5932var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer'];
5933var camels = ['value', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap'];
5934
5935bools = bools.associate(bools);
5936
5937Hash.extend(attributes, bools);
5938Hash.extend(attributes, camels.associate(camels.map(String.toLowerCase)));
5939
5940var inserters = {
5941
5942	before: function(context, element){
5943		if (element.parentNode) element.parentNode.insertBefore(context, element);
5944	},
5945
5946	after: function(context, element){
5947		if (!element.parentNode) return;
5948		var next = element.nextSibling;
5949		(next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context);
5950	},
5951
5952	bottom: function(context, element){
5953		element.appendChild(context);
5954	},
5955
5956	top: function(context, element){
5957		var first = element.firstChild;
5958		(first) ? element.insertBefore(context, first) : element.appendChild(context);
5959	}
5960
5961};
5962
5963inserters.inside = inserters.bottom;
5964
5965Hash.each(inserters, function(inserter, where){
5966
5967	where = where.capitalize();
5968
5969	Element.implement('inject' + where, function(el){
5970		inserter(this, $(el, true));
5971		return this;
5972	});
5973
5974	Element.implement('grab' + where, function(el){
5975		inserter($(el, true), this);
5976		return this;
5977	});
5978
5979});
5980
5981Element.implement({
5982
5983	set: function(prop, value){
5984		switch ($type(prop)){
5985			case 'object':
5986				for (var p in prop) this.set(p, prop[p]);
5987				break;
5988			case 'string':
5989				var property = Element.Properties.get(prop);
5990				(property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value);
5991		}
5992		return this;
5993	},
5994
5995	get: function(prop){
5996		var property = Element.Properties.get(prop);
5997		return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop);
5998	},
5999
6000	erase: function(prop){
6001		var property = Element.Properties.get(prop);
6002		(property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
6003		return this;
6004	},
6005
6006	setProperty: function(attribute, value){
6007		var key = attributes[attribute];
6008		if (value == undefined) return this.removeProperty(attribute);
6009		if (key && bools[attribute]) value = !!value;
6010		(key) ? this[key] = value : this.setAttribute(attribute, '' + value);
6011		return this;
6012	},
6013
6014	setProperties: function(attributes){
6015		for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
6016		return this;
6017	},
6018
6019	getProperty: function(attribute){
6020		var key = attributes[attribute];
6021		var value = (key) ? this[key] : this.getAttribute(attribute, 2);
6022		return (bools[attribute]) ? !!value : (key) ? value : value || null;
6023	},
6024
6025	getProperties: function(){
6026		var args = $A(arguments);
6027		return args.map(this.getProperty, this).associate(args);
6028	},
6029
6030	removeProperty: function(attribute){
6031		var key = attributes[attribute];
6032		(key) ? this[key] = (key && bools[attribute]) ? false : '' : this.removeAttribute(attribute);
6033		return this;
6034	},
6035
6036	removeProperties: function(){
6037		Array.each(arguments, this.removeProperty, this);
6038		return this;
6039	},
6040
6041	hasClass: function(className){
6042		return this.className.contains(className, ' ');
6043	},
6044
6045	addClass: function(className){
6046		if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
6047		return this;
6048	},
6049
6050	removeClass: function(className){
6051		this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
6052		return this;
6053	},
6054
6055	toggleClass: function(className){
6056		return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
6057	},
6058
6059	adopt: function(){
6060		Array.flatten(arguments).each(function(element){
6061			element = $(element, true);
6062			if (element) this.appendChild(element);
6063		}, this);
6064		return this;
6065	},
6066
6067	appendText: function(text, where){
6068		return this.grab(this.getDocument().newTextNode(text), where);
6069	},
6070
6071	grab: function(el, where){
6072		inserters[where || 'bottom']($(el, true), this);
6073		return this;
6074	},
6075
6076	inject: function(el, where){
6077		inserters[where || 'bottom'](this, $(el, true));
6078		return this;
6079	},
6080
6081	replaces: function(el){
6082		el = $(el, true);
6083		el.parentNode.replaceChild(this, el);
6084		return this;
6085	},
6086
6087	wraps: function(el, where){
6088		el = $(el, true);
6089		return this.replaces(el).grab(el, where);
6090	},
6091
6092	getPrevious: function(match, nocash){
6093		return walk(this, 'previousSibling', null, match, false, nocash);
6094	},
6095
6096	getAllPrevious: function(match, nocash){
6097		return walk(this, 'previousSibling', null, match, true, nocash);
6098	},
6099
6100	getNext: function(match, nocash){
6101		return walk(this, 'nextSibling', null, match, false, nocash);
6102	},
6103
6104	getAllNext: function(match, nocash){
6105		return walk(this, 'nextSibling', null, match, true, nocash);
6106	},
6107
6108	getFirst: function(match, nocash){
6109		return walk(this, 'nextSibling', 'firstChild', match, false, nocash);
6110	},
6111
6112	getLast: function(match, nocash){
6113		return walk(this, 'previousSibling', 'lastChild', match, false, nocash);
6114	},
6115
6116	getParent: function(match, nocash){
6117		return walk(this, 'parentNode', null, match, false, nocash);
6118	},
6119
6120	getParents: function(match, nocash){
6121		return walk(this, 'parentNode', null, match, true, nocash);
6122	},
6123
6124	getSiblings: function(match, nocash) {
6125		return this.getParent().getChildren(match, nocash).erase(this);
6126	},
6127
6128	getChildren: function(match, nocash){
6129		return walk(this, 'nextSibling', 'firstChild', match, true, nocash);
6130	},
6131
6132	getWindow: function(){
6133		return this.ownerDocument.window;
6134	},
6135
6136	getDocument: function(){
6137		return this.ownerDocument;
6138	},
6139
6140	getElementById: function(id, nocash){
6141		var el = this.ownerDocument.getElementById(id);
6142		if (!el) return null;
6143		for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
6144			if (!parent) return null;
6145		}
6146		return $.element(el, nocash);
6147	},
6148
6149	getSelected: function(){
6150		return new Elements($A(this.options).filter(function(option){
6151			return option.selected;
6152		}));
6153	},
6154
6155	getComputedStyle: function(property){
6156		if (this.currentStyle) return this.currentStyle[property.camelCase()];
6157		var computed = this.getDocument().defaultView.getComputedStyle(this, null);
6158		return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null;
6159	},
6160
6161	toQueryString: function(){
6162		var queryString = [];
6163		this.getElements('input, select, textarea', true).each(function(el){
6164			if (!el.name || el.disabled) return;
6165			var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){
6166				return opt.value;
6167			}) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value;
6168			$splat(value).each(function(val){
6169				if (typeof val != 'undefined') queryString.push(el.name + '=' + encodeURIComponent(val));
6170			});
6171		});
6172		return queryString.join('&');
6173	},
6174
6175	clone: function(contents, keepid){
6176		contents = contents !== false;
6177		var clone = this.cloneNode(contents);
6178		var clean = function(node, element){
6179			if (!keepid) node.removeAttribute('id');
6180			if (Browser.Engine.trident){
6181				node.clearAttributes();
6182				node.mergeAttributes(element);
6183				node.removeAttribute('uid');
6184				if (node.options){
6185					var no = node.options, eo = element.options;
6186					for (var j = no.length; j--;) no[j].selected = eo[j].selected;
6187				}
6188			}
6189			var prop = props[element.tagName.toLowerCase()];
6190			if (prop && element[prop]) node[prop] = element[prop];
6191		};
6192
6193		if (contents){
6194			var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*');
6195			for (var i = ce.length; i--;) clean(ce[i], te[i]);
6196		}
6197
6198		clean(clone, this);
6199		return $(clone);
6200	},
6201
6202	destroy: function(){
6203		Element.empty(this);
6204		Element.dispose(this);
6205		clean(this, true);
6206		return null;
6207	},
6208
6209	empty: function(){
6210		$A(this.childNodes).each(function(node){
6211			Element.destroy(node);
6212		});
6213		return this;
6214	},
6215
6216	dispose: function(){
6217		return (this.parentNode) ? this.parentNode.removeChild(this) : this;
6218	},
6219
6220	hasChild: function(el){
6221		el = $(el, true);
6222		if (!el) return false;
6223		if (Browser.Engine.webkit && Browser.Engine.version < 420) return $A(this.getElementsByTagName(el.tagName)).contains(el);
6224		return (this.contains) ? (this != el && this.contains(el)) : !!(this.compareDocumentPosition(el) & 16);
6225	},
6226
6227	match: function(tag){
6228		return (!tag || (tag == this) || (Element.get(this, 'tag') == tag));
6229	}
6230
6231});
6232
6233Native.implement([Element, Window, Document], {
6234
6235	addListener: function(type, fn){
6236		if (type == 'unload'){
6237			var old = fn, self = this;
6238			fn = function(){
6239				self.removeListener('unload', fn);
6240				old();
6241			};
6242		} else {
6243			collected[this.uid] = this;
6244		}
6245		if (this.addEventListener) this.addEventListener(type, fn, false);
6246		else this.attachEvent('on' + type, fn);
6247		return this;
6248	},
6249
6250	removeListener: function(type, fn){
6251		if (this.removeEventListener) this.removeEventListener(type, fn, false);
6252		else this.detachEvent('on' + type, fn);
6253		return this;
6254	},
6255
6256	retrieve: function(property, dflt){
6257		var storage = get(this.uid), prop = storage[property];
6258		if (dflt != undefined && prop == undefined) prop = storage[property] = dflt;
6259		return $pick(prop);
6260	},
6261
6262	store: function(property, value){
6263		var storage = get(this.uid);
6264		storage[property] = value;
6265		return this;
6266	},
6267
6268	eliminate: function(property){
6269		var storage = get(this.uid);
6270		delete storage[property];
6271		return this;
6272	}
6273
6274});
6275
6276window.addListener('unload', purge);
6277
6278})();
6279
6280Element.Properties = new Hash;
6281
6282Element.Properties.style = {
6283
6284	set: function(style){
6285		this.style.cssText = style;
6286	},
6287
6288	get: function(){
6289		return this.style.cssText;
6290	},
6291
6292	erase: function(){
6293		this.style.cssText = '';
6294	}
6295
6296};
6297
6298Element.Properties.tag = {
6299
6300	get: function(){
6301		return this.tagName.toLowerCase();
6302	}
6303
6304};
6305
6306Element.Properties.html = (function(){
6307	var wrapper = document.createElement('div');
6308
6309	var translations = {
6310		table: [1, '<table>', '</table>'],
6311		select: [1, '<select>', '</select>'],
6312		tbody: [2, '<table><tbody>', '</tbody></table>'],
6313		tr: [3, '<table><tbody><tr>', '</tr></tbody></table>']
6314	};
6315	translations.thead = translations.tfoot = translations.tbody;
6316
6317	var html = {
6318		set: function(){
6319			var html = Array.flatten(arguments).join('');
6320			var wrap = Browser.Engine.trident && translations[this.get('tag')];
6321			if (wrap){
6322				var first = wrapper;
6323				first.innerHTML = wrap[1] + html + wrap[2];
6324				for (var i = wrap[0]; i--;) first = first.firstChild;
6325				this.empty().adopt(first.childNodes);
6326			} else {
6327				this.innerHTML = html;
6328			}
6329		}
6330	};
6331
6332	html.erase = html.set;
6333
6334	return html;
6335})();
6336
6337if (Browser.Engine.webkit && Browser.Engine.version < 420) Element.Properties.text = {
6338	get: function(){
6339		if (this.innerText) return this.innerText;
6340		var temp = this.ownerDocument.newElement('div', {html: this.innerHTML}).inject(this.ownerDocument.body);
6341		var text = temp.innerText;
6342		temp.destroy();
6343		return text;
6344	}
6345};
6346
6347
6348/*
6349Script: Element.Event.js
6350	Contains Element methods for dealing with events, and custom Events.
6351
6352License:
6353	MIT-style license.
6354*/
6355
6356Element.Properties.events = {set: function(events){
6357	this.addEvents(events);
6358}};
6359
6360Native.implement([Element, Window, Document], {
6361
6362	addEvent: function(type, fn){
6363		var events = this.retrieve('events', {});
6364		events[type] = events[type] || {'keys': [], 'values': []};
6365		if (events[type].keys.contains(fn)) return this;
6366		events[type].keys.push(fn);
6367		var realType = type, custom = Element.Events.get(type), condition = fn, self = this;
6368		if (custom){
6369			if (custom.onAdd) custom.onAdd.call(this, fn);
6370			if (custom.condition){
6371				condition = function(event){
6372					if (custom.condition.call(this, event)) return fn.call(this, event);
6373					return true;
6374				};
6375			}
6376			realType = custom.base || realType;
6377		}
6378		var defn = function(){
6379			return fn.call(self);
6380		};
6381		var nativeEvent = Element.NativeEvents[realType];
6382		if (nativeEvent){
6383			if (nativeEvent == 2){
6384				defn = function(event){
6385					event = new Event(event, self.getWindow());
6386					if (condition.call(self, event) === false) event.stop();
6387				};
6388			}
6389			this.addListener(realType, defn);
6390		}
6391		events[type].values.push(defn);
6392		return this;
6393	},
6394
6395	removeEvent: function(type, fn){
6396		var events = this.retrieve('events');
6397		if (!events || !events[type]) return this;
6398		var pos = events[type].keys.indexOf(fn);
6399		if (pos == -1) return this;
6400		events[type].keys.splice(pos, 1);
6401		var value = events[type].values.splice(pos, 1)[0];
6402		var custom = Element.Events.get(type);
6403		if (custom){
6404			if (custom.onRemove) custom.onRemove.call(this, fn);
6405			type = custom.base || type;
6406		}
6407		return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this;
6408	},
6409
6410	addEvents: function(events){
6411		for (var event in events) this.addEvent(event, events[event]);
6412		return this;
6413	},
6414
6415	removeEvents: function(events){
6416		var type;
6417		if ($type(events) == 'object'){
6418			for (type in events) this.removeEvent(type, events[type]);
6419			return this;
6420		}
6421		var attached = this.retrieve('events');
6422		if (!attached) return this;
6423		if (!events){
6424			for (type in attached) this.removeEvents(type);
6425			this.eliminate('events');
6426		} else if (attached[events]){
6427			while (attached[events].keys[0]) this.removeEvent(events, attached[events].keys[0]);
6428			attached[events] = null;
6429		}
6430		return this;
6431	},
6432
6433	fireEvent: function(type, args, delay){
6434		var events = this.retrieve('events');
6435		if (!events || !events[type]) return this;
6436		events[type].keys.each(function(fn){
6437			fn.create({'bind': this, 'delay': delay, 'arguments': args})();
6438		}, this);
6439		return this;
6440	},
6441
6442	cloneEvents: function(from, type){
6443		from = $(from);
6444		var fevents = from.retrieve('events');
6445		if (!fevents) return this;
6446		if (!type){
6447			for (var evType in fevents) this.cloneEvents(from, evType);
6448		} else if (fevents[type]){
6449			fevents[type].keys.each(function(fn){
6450				this.addEvent(type, fn);
6451			}, this);
6452		}
6453		return this;
6454	}
6455
6456});
6457
6458Element.NativeEvents = {
6459	click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
6460	mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
6461	mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
6462	keydown: 2, keypress: 2, keyup: 2, //keyboard
6463	focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements
6464	load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
6465	error: 1, abort: 1, scroll: 1 //misc
6466};
6467
6468(function(){
6469
6470var $check = function(event){
6471	var related = event.relatedTarget;
6472	if (related == undefined) return true;
6473	if (related === false) return false;
6474	return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related));
6475};
6476
6477Element.Events = new Hash({
6478
6479	mouseenter: {
6480		base: 'mouseover',
6481		condition: $check
6482	},
6483
6484	mouseleave: {
6485		base: 'mouseout',
6486		condition: $check
6487	},
6488
6489	mousewheel: {
6490		base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel'
6491	}
6492
6493});
6494
6495})();
6496
6497
6498/*
6499Script: Element.Style.js
6500	Contains methods for interacting with the styles of Elements in a fashionable way.
6501
6502License:
6503	MIT-style license.
6504*/
6505
6506Element.Properties.styles = {set: function(styles){
6507	this.setStyles(styles);
6508}};
6509
6510Element.Properties.opacity = {
6511
6512	set: function(opacity, novisibility){
6513		if (!novisibility){
6514			if (opacity == 0){
6515				if (this.style.visibility != 'hidden') this.style.visibility = 'hidden';
6516			} else {
6517				if (this.style.visibility != 'visible') this.style.visibility = 'visible';
6518			}
6519		}
6520		if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
6521		if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')';
6522		this.style.opacity = opacity;
6523		this.store('opacity', opacity);
6524	},
6525
6526	get: function(){
6527		return this.retrieve('opacity', 1);
6528	}
6529
6530};
6531
6532Element.implement({
6533
6534	setOpacity: function(value){
6535		return this.set('opacity', value, true);
6536	},
6537
6538	getOpacity: function(){
6539		return this.get('opacity');
6540	},
6541
6542	setStyle: function(property, value){
6543		switch (property){
6544			case 'opacity': return this.set('opacity', parseFloat(value));
6545			case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
6546		}
6547		property = property.camelCase();
6548		if ($type(value) != 'string'){
6549			var map = (Element.Styles.get(property) || '@').split(' ');
6550			value = $splat(value).map(function(val, i){
6551				if (!map[i]) return '';
6552				return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
6553			}).join(' ');
6554		} else if (value == String(Number(value))){
6555			value = Math.round(value);
6556		}
6557		this.style[property] = value;
6558		return this;
6559	},
6560
6561	getStyle: function(property){
6562		switch (property){
6563			case 'opacity': return this.get('opacity');
6564			case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
6565		}
6566		property = property.camelCase();
6567		var result = this.style[property];
6568		if (!$chk(result)){
6569			result = [];
6570			for (var style in Element.ShortStyles){
6571				if (property != style) continue;
6572				for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
6573				return result.join(' ');
6574			}
6575			result = this.getComputedStyle(property);
6576		}
6577		if (result){
6578			result = String(result);
6579			var color = result.match(/rgba?\([\d\s,]+\)/);
6580			if (color) result = result.replace(color[0], color[0].rgbToHex());
6581		}
6582		if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result, 10)))){
6583			if (property.test(/^(height|width)$/)){
6584				var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
6585				values.each(function(value){
6586					size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
6587				}, this);
6588				return this['offset' + property.capitalize()] - size + 'px';
6589			}
6590			if ((Browser.Engine.presto) && String(result).test('px')) return result;
6591			if (property.test(/(border(.+)Width|margin|padding)/)) return '0px';
6592		}
6593		return result;
6594	},
6595
6596	setStyles: function(styles){
6597		for (var style in styles) this.setStyle(style, styles[style]);
6598		return this;
6599	},
6600
6601	getStyles: function(){
6602		var result = {};
6603		Array.each(arguments, function(key){
6604			result[key] = this.getStyle(key);
6605		}, this);
6606		return result;
6607	}
6608
6609});
6610
6611Element.Styles = new Hash({
6612	left: '@px', top: '@px', bottom: '@px', right: '@px',
6613	width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
6614	backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
6615	fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
6616	margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
6617	borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
6618	zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
6619});
6620
6621Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
6622
6623['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
6624	var Short = Element.ShortStyles;
6625	var All = Element.Styles;
6626	['margin', 'padding'].each(function(style){
6627		var sd = style + direction;
6628		Short[style][sd] = All[sd] = '@px';
6629	});
6630	var bd = 'border' + direction;
6631	Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
6632	var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
6633	Short[bd] = {};
6634	Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
6635	Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
6636	Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
6637});
6638
6639
6640/*
6641Script: Element.Dimensions.js
6642	Contains methods to work with size, scroll, or positioning of Elements and the window object.
6643
6644License:
6645	MIT-style license.
6646
6647Credits:
6648	- Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
6649	- Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
6650*/
6651
6652(function(){
6653
6654Element.implement({
6655
6656	scrollTo: function(x, y){
6657		if (isBody(this)){
6658			this.getWindow().scrollTo(x, y);
6659		} else {
6660			this.scrollLeft = x;
6661			this.scrollTop = y;
6662		}
6663		return this;
6664	},
6665
6666	getSize: function(){
6667		if (isBody(this)) return this.getWindow().getSize();
6668		return {x: this.offsetWidth, y: this.offsetHeight};
6669	},
6670
6671	getScrollSize: function(){
6672		if (isBody(this)) return this.getWindow().getScrollSize();
6673		return {x: this.scrollWidth, y: this.scrollHeight};
6674	},
6675
6676	getScroll: function(){
6677		if (isBody(this)) return this.getWindow().getScroll();
6678		return {x: this.scrollLeft, y: this.scrollTop};
6679	},
6680
6681	getScrolls: function(){
6682		var element = this, position = {x: 0, y: 0};
6683		while (element && !isBody(element)){
6684			position.x += element.scrollLeft;
6685			position.y += element.scrollTop;
6686			element = element.parentNode;
6687		}
6688		return position;
6689	},
6690
6691	getOffsetParent: function(){
6692		var element = this;
6693		if (isBody(element)) return null;
6694		if (!Browser.Engine.trident) return element.offsetParent;
6695		while ((element = element.parentNode) && !isBody(element)){
6696			if (styleString(element, 'position') != 'static') return element;
6697		}
6698		return null;
6699	},
6700
6701	getOffsets: function(){
6702		if (Browser.Engine.trident){
6703			var bound = this.getBoundingClientRect(), html = this.getDocument().documentElement;
6704			var isFixed = styleString(this, 'position') == 'fixed';
6705			return {
6706				x: bound.left + ((isFixed) ? 0 : html.scrollLeft) - html.clientLeft,
6707				y: bound.top +  ((isFixed) ? 0 : html.scrollTop)  - html.clientTop
6708			};
6709		}
6710
6711		var element = this, position = {x: 0, y: 0};
6712		if (isBody(this)) return position;
6713
6714		while (element && !isBody(element)){
6715			position.x += element.offsetLeft;
6716			position.y += element.offsetTop;
6717
6718			if (Browser.Engine.gecko){
6719				if (!borderBox(element)){
6720					position.x += leftBorder(element);
6721					position.y += topBorder(element);
6722				}
6723				var parent = element.parentNode;
6724				if (parent && styleString(parent, 'overflow') != 'visible'){
6725					position.x += leftBorder(parent);
6726					position.y += topBorder(parent);
6727				}
6728			} else if (element != this && Browser.Engine.webkit){
6729				position.x += leftBorder(element);
6730				position.y += topBorder(element);
6731			}
6732
6733			element = element.offsetParent;
6734		}
6735		if (Browser.Engine.gecko && !borderBox(this)){
6736			position.x -= leftBorder(this);
6737			position.y -= topBorder(this);
6738		}
6739		return position;
6740	},
6741
6742	getPosition: function(relative){
6743		if (isBody(this)) return {x: 0, y: 0};
6744		var offset = this.getOffsets(), scroll = this.getScrolls();
6745		var position = {x: offset.x - scroll.x, y: offset.y - scroll.y};
6746		var relativePosition = (relative && (relative = $(relative))) ? relative.getPosition() : {x: 0, y: 0};
6747		return {x: position.x - relativePosition.x, y: position.y - relativePosition.y};
6748	},
6749
6750	getCoordinates: function(element){
6751		if (isBody(this)) return this.getWindow().getCoordinates();
6752		var position = this.getPosition(element), size = this.getSize();
6753		var obj = {left: position.x, top: position.y, width: size.x, height: size.y};
6754		obj.right = obj.left + obj.width;
6755		obj.bottom = obj.top + obj.height;
6756		return obj;
6757	},
6758
6759	computePosition: function(obj){
6760		return {left: obj.x - styleNumber(this, 'margin-left'), top: obj.y - styleNumber(this, 'margin-top')};
6761	},
6762
6763	position: function(obj){
6764		return this.setStyles(this.computePosition(obj));
6765	}
6766
6767});
6768
6769Native.implement([Document, Window], {
6770
6771	getSize: function(){
6772		if (Browser.Engine.presto || Browser.Engine.webkit) {
6773			var win = this.getWindow();
6774			return {x: win.innerWidth, y: win.innerHeight};
6775		}
6776		var doc = getCompatElement(this);
6777		return {x: doc.clientWidth, y: doc.clientHeight};
6778	},
6779
6780	getScroll: function(){
6781		var win = this.getWindow(), doc = getCompatElement(this);
6782		return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
6783	},
6784
6785	getScrollSize: function(){
6786		var doc = getCompatElement(this), min = this.getSize();
6787		return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)};
6788	},
6789
6790	getPosition: function(){
6791		return {x: 0, y: 0};
6792	},
6793
6794	getCoordinates: function(){
6795		var size = this.getSize();
6796		return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
6797	}
6798
6799});
6800
6801// private methods
6802
6803var styleString = Element.getComputedStyle;
6804
6805function styleNumber(element, style){
6806	return styleString(element, style).toInt() || 0;
6807};
6808
6809function borderBox(element){
6810	return styleString(element, '-moz-box-sizing') == 'border-box';
6811};
6812
6813function topBorder(element){
6814	return styleNumber(element, 'border-top-width');
6815};
6816
6817function leftBorder(element){
6818	return styleNumber(element, 'border-left-width');
6819};
6820
6821function isBody(element){
6822	return (/^(?:body|html)$/i).test(element.tagName);
6823};
6824
6825function getCompatElement(element){
6826	var doc = element.getDocument();
6827	return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
6828};
6829
6830})();
6831
6832//aliases
6833
6834Native.implement([Window, Document, Element], {
6835
6836	getHeight: function(){
6837		return this.getSize().y;
6838	},
6839
6840	getWidth: function(){
6841		return this.getSize().x;
6842	},
6843
6844	getScrollTop: function(){
6845		return this.getScroll().y;
6846	},
6847
6848	getScrollLeft: function(){
6849		return this.getScroll().x;
6850	},
6851
6852	getScrollHeight: function(){
6853		return this.getScrollSize().y;
6854	},
6855
6856	getScrollWidth: function(){
6857		return this.getScrollSize().x;
6858	},
6859
6860	getTop: function(){
6861		return this.getPosition().y;
6862	},
6863
6864	getLeft: function(){
6865		return this.getPosition().x;
6866	}
6867
6868});
6869
6870
6871/*
6872Script: Selectors.js
6873	Adds advanced CSS Querying capabilities for targeting elements. Also includes pseudoselectors support.
6874
6875License:
6876	MIT-style license.
6877*/
6878
6879Native.implement([Document, Element], {
6880
6881	getElements: function(expression, nocash){
6882		expression = expression.split(',');
6883		var items, local = {};
6884		for (var i = 0, l = expression.length; i < l; i++){
6885			var selector = expression[i], elements = Selectors.Utils.search(this, selector, local);
6886			if (i != 0 && elements.item) elements = $A(elements);
6887			items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements);
6888		}
6889		return new Elements(items, {ddup: (expression.length > 1), cash: !nocash});
6890	}
6891
6892});
6893
6894Element.implement({
6895
6896	match: function(selector){
6897		if (!selector || (selector == this)) return true;
6898		var tagid = Selectors.Utils.parseTagAndID(selector);
6899		var tag = tagid[0], id = tagid[1];
6900		if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false;
6901		var parsed = Selectors.Utils.parseSelector(selector);
6902		return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true;
6903	}
6904
6905});
6906
6907var Selectors = {Cache: {nth: {}, parsed: {}}};
6908
6909Selectors.RegExps = {
6910	id: (/#([\w-]+)/),
6911	tag: (/^(\w+|\*)/),
6912	quick: (/^(\w+|\*)$/),
6913	splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),
6914	combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)
6915};
6916
6917Selectors.Utils = {
6918
6919	chk: function(item, uniques){
6920		if (!uniques) return true;
6921		var uid = $uid(item);
6922		if (!uniques[uid]) return uniques[uid] = true;
6923		return false;
6924	},
6925
6926	parseNthArgument: function(argument){
6927		if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument];
6928		var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);
6929		if (!parsed) return false;
6930		var inta = parseInt(parsed[1], 10);
6931		var a = (inta || inta === 0) ? inta : 1;
6932		var special = parsed[2] || false;
6933		var b = parseInt(parsed[3], 10) || 0;
6934		if (a != 0){
6935			b--;
6936			while (b < 1) b += a;
6937			while (b >= a) b -= a;
6938		} else {
6939			a = b;
6940			special = 'index';
6941		}
6942		switch (special){
6943			case 'n': parsed = {a: a, b: b, special: 'n'}; break;
6944			case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break;
6945			case 'even': parsed = {a: 2, b: 1, special: 'n'}; break;
6946			case 'first': parsed = {a: 0, special: 'index'}; break;
6947			case 'last': parsed = {special: 'last-child'}; break;
6948			case 'only': parsed = {special: 'only-child'}; break;
6949			default: parsed = {a: (a - 1), special: 'index'};
6950		}
6951
6952		return Selectors.Cache.nth[argument] = parsed;
6953	},
6954
6955	parseSelector: function(selector){
6956		if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector];
6957		var m, parsed = {classes: [], pseudos: [], attributes: []};
6958		while ((m = Selectors.RegExps.combined.exec(selector))){
6959			var cn = m[1], an = m[2], ao = m[3], av = m[5], pn = m[6], pa = m[7];
6960			if (cn){
6961				parsed.classes.push(cn);
6962			} else if (pn){
6963				var parser = Selectors.Pseudo.get(pn);
6964				if (parser) parsed.pseudos.push({parser: parser, argument: pa});
6965				else parsed.attributes.push({name: pn, operator: '=', value: pa});
6966			} else if (an){
6967				parsed.attributes.push({name: an, operator: ao, value: av});
6968			}
6969		}
6970		if (!parsed.classes.length) delete parsed.classes;
6971		if (!parsed.attributes.length) delete parsed.attributes;
6972		if (!parsed.pseudos.length) delete parsed.pseudos;
6973		if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null;
6974		return Selectors.Cache.parsed[selector] = parsed;
6975	},
6976
6977	parseTagAndID: function(selector){
6978		var tag = selector.match(Selectors.RegExps.tag);
6979		var id = selector.match(Selectors.RegExps.id);
6980		return [(tag) ? tag[1] : '*', (id) ? id[1] : false];
6981	},
6982
6983	filter: function(item, parsed, local){
6984		var i;
6985		if (parsed.classes){
6986			for (i = parsed.classes.length; i--; i){
6987				var cn = parsed.classes[i];
6988				if (!Selectors.Filters.byClass(item, cn)) return false;
6989			}
6990		}
6991		if (parsed.attributes){
6992			for (i = parsed.attributes.length; i--; i){
6993				var att = parsed.attributes[i];
6994				if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false;
6995			}
6996		}
6997		if (parsed.pseudos){
6998			for (i = parsed.pseudos.length; i--; i){
6999				var psd = parsed.pseudos[i];
7000				if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false;
7001			}
7002		}
7003		return true;
7004	},
7005
7006	getByTagAndID: function(ctx, tag, id){
7007		if (id){
7008			var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true);
7009			return (item && Selectors.Filters.byTag(item, tag)) ? [item] : [];
7010		} else {
7011			return ctx.getElementsByTagName(tag);
7012		}
7013	},
7014
7015	search: function(self, expression, local){
7016		var splitters = [];
7017
7018		var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){
7019			splitters.push(m1);
7020			return ':)' + m2;
7021		}).split(':)');
7022
7023		var items, filtered, item;
7024
7025		for (var i = 0, l = selectors.length; i < l; i++){
7026
7027			var selector = selectors[i];
7028
7029			if (i == 0 && Selectors.RegExps.quick.test(selector)){
7030				items = self.getElementsByTagName(selector);
7031				continue;
7032			}
7033
7034			var splitter = splitters[i - 1];
7035
7036			var tagid = Selectors.Utils.parseTagAndID(selector);
7037			var tag = tagid[0], id = tagid[1];
7038
7039			if (i == 0){
7040				items = Selectors.Utils.getByTagAndID(self, tag, id);
7041			} else {
7042				var uniques = {}, found = [];
7043				for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques);
7044				items = found;
7045			}
7046
7047			var parsed = Selectors.Utils.parseSelector(selector);
7048
7049			if (parsed){
7050				filtered = [];
7051				for (var m = 0, n = items.length; m < n; m++){
7052					item = items[m];
7053					if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item);
7054				}
7055				items = filtered;
7056			}
7057
7058		}
7059
7060		return items;
7061
7062	}
7063
7064};
7065
7066Selectors.Getters = {
7067
7068	' ': function(found, self, tag, id, uniques){
7069		var items = Selectors.Utils.getByTagAndID(self, tag, id);
7070		for (var i = 0, l = items.length; i < l; i++){
7071			var item = items[i];
7072			if (Selectors.Utils.chk(item, uniques)) found.push(item);
7073		}
7074		return found;
7075	},
7076
7077	'>': function(found, self, tag, id, uniques){
7078		var children = Selectors.Utils.getByTagAndID(self, tag, id);
7079		for (var i = 0, l = children.length; i < l; i++){
7080			var child = children[i];
7081			if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child);
7082		}
7083		return found;
7084	},
7085
7086	'+': function(found, self, tag, id, uniques){
7087		while ((self = self.nextSibling)){
7088			if (self.nodeType == 1){
7089				if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
7090				break;
7091			}
7092		}
7093		return found;
7094	},
7095
7096	'~': function(found, self, tag, id, uniques){
7097		while ((self = self.nextSibling)){
7098			if (self.nodeType == 1){
7099				if (!Selectors.Utils.chk(self, uniques)) break;
7100				if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
7101			}
7102		}
7103		return found;
7104	}
7105
7106};
7107
7108Selectors.Filters = {
7109
7110	byTag: function(self, tag){
7111		return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag));
7112	},
7113
7114	byID: function(self, id){
7115		return (!id || (self.id && self.id == id));
7116	},
7117
7118	byClass: function(self, klass){
7119		return (self.className && self.className.contains(klass, ' '));
7120	},
7121
7122	byPseudo: function(self, parser, argument, local){
7123		return parser.call(self, argument, local);
7124	},
7125
7126	byAttribute: function(self, name, operator, value){
7127		var result = Element.prototype.getProperty.call(self, name);
7128		if (!result) return (operator == '!=');
7129		if (!operator || value == undefined) return true;
7130		switch (operator){
7131			case '=': return (result == value);
7132			case '*=': return (result.contains(value));
7133			case '^=': return (result.substr(0, value.length) == value);
7134			case '$=': return (result.substr(result.length - value.length) == value);
7135			case '!=': return (result != value);
7136			case '~=': return result.contains(value, ' ');
7137			case '|=': return result.contains(value, '-');
7138		}
7139		return false;
7140	}
7141
7142};
7143
7144Selectors.Pseudo = new Hash({
7145
7146	// w3c pseudo selectors
7147
7148	checked: function(){
7149		return this.checked;
7150	},
7151
7152	empty: function(){
7153		return !(this.innerText || this.textContent || '').length;
7154	},
7155
7156	not: function(selector){
7157		return !Element.match(this, selector);
7158	},
7159
7160	contains: function(text){
7161		return (this.innerText || this.textContent || '').contains(text);
7162	},
7163
7164	'first-child': function(){
7165		return Selectors.Pseudo.index.call(this, 0);
7166	},
7167
7168	'last-child': function(){
7169		var element = this;
7170		while ((element = element.nextSibling)){
7171			if (element.nodeType == 1) return false;
7172		}
7173		return true;
7174	},
7175
7176	'only-child': function(){
7177		var prev = this;
7178		while ((prev = prev.previousSibling)){
7179			if (prev.nodeType == 1) return false;
7180		}
7181		var next = this;
7182		while ((next = next.nextSibling)){
7183			if (next.nodeType == 1) return false;
7184		}
7185		return true;
7186	},
7187
7188	'nth-child': function(argument, local){
7189		argument = (argument == undefined) ? 'n' : argument;
7190		var parsed = Selectors.Utils.parseNthArgument(argument);
7191		if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local);
7192		var count = 0;
7193		local.positions = local.positions || {};
7194		var uid = $uid(this);
7195		if (!local.positions[uid]){
7196			var self = this;
7197			while ((self = self.previousSibling)){
7198				if (self.nodeType != 1) continue;
7199				count ++;
7200				var position = local.positions[$uid(self)];
7201				if (position != undefined){
7202					count = position + count;
7203					break;
7204				}
7205			}
7206			local.positions[uid] = count;
7207		}
7208		return (local.positions[uid] % parsed.a == parsed.b);
7209	},
7210
7211	// custom pseudo selectors
7212
7213	index: function(index){
7214		var element = this, count = 0;
7215		while ((element = element.previousSibling)){
7216			if (element.nodeType == 1 && ++count > index) return false;
7217		}
7218		return (count == index);
7219	},
7220
7221	even: function(argument, local){
7222		return Selectors.Pseudo['nth-child'].call(this, '2n+1', local);
7223	},
7224
7225	odd: function(argument, local){
7226		return Selectors.Pseudo['nth-child'].call(this, '2n', local);
7227	},
7228
7229	selected: function() {
7230		return this.selected;
7231	}
7232
7233});
7234
7235
7236/*
7237Script: Domready.js
7238	Contains the domready custom event.
7239
7240License:
7241	MIT-style license.
7242*/
7243
7244Element.Events.domready = {
7245
7246	onAdd: function(fn){
7247		if (Browser.loaded) fn.call(this);
7248	}
7249
7250};
7251
7252(function(){
7253
7254	var domready = function(){
7255		if (Browser.loaded) return;
7256		Browser.loaded = true;
7257		window.fireEvent('domready');
7258		document.fireEvent('domready');
7259	};
7260
7261	if (Browser.Engine.trident){
7262		var temp = document.createElement('div');
7263		(function(){
7264			($try(function(){
7265				temp.doScroll('left');
7266				return $(temp).inject(document.body).set('html', 'temp').dispose();
7267			})) ? domready() : arguments.callee.delay(50);
7268		})();
7269	} else if (Browser.Engine.webkit && Browser.Engine.version < 525){
7270		(function(){
7271			(['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50);
7272		})();
7273	} else {
7274		window.addEvent('load', domready);
7275		document.addEvent('DOMContentLoaded', domready);
7276	}
7277
7278})();
7279
7280
7281/*
7282Script: JSON.js
7283	JSON encoder and decoder.
7284
7285License:
7286	MIT-style license.
7287
7288See Also:
7289	<http://www.json.org/>
7290*/
7291
7292var JSON = new Hash({
7293
7294	$specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},
7295
7296	$replaceChars: function(chr){
7297		return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16);
7298	},
7299
7300	encode: function(obj){
7301		switch ($type(obj)){
7302			case 'string':
7303				return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"';
7304			case 'array':
7305				return '[' + String(obj.map(JSON.encode).filter($defined)) + ']';
7306			case 'object': case 'hash':
7307				var string = [];
7308				Hash.each(obj, function(value, key){
7309					var json = JSON.encode(value);
7310					if (json) string.push(JSON.encode(key) + ':' + json);
7311				});
7312				return '{' + string + '}';
7313			case 'number': case 'boolean': return String(obj);
7314			case false: return 'null';
7315		}
7316		return null;
7317	},
7318
7319	decode: function(string, secure){
7320		if ($type(string) != 'string' || !string.length) return null;
7321		if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null;
7322		return eval('(' + string + ')');
7323	}
7324
7325});
7326
7327Native.implement([Hash, Array, String, Number], {
7328
7329	toJSON: function(){
7330		return JSON.encode(this);
7331	}
7332
7333});
7334
7335
7336/*
7337Script: Cookie.js
7338	Class for creating, loading, and saving browser Cookies.
7339
7340License:
7341	MIT-style license.
7342
7343Credits:
7344	Based on the functions by Peter-Paul Koch (http://quirksmode.org).
7345*/
7346
7347var Cookie = new Class({
7348
7349	Implements: Options,
7350
7351	options: {
7352		path: false,
7353		domain: false,
7354		duration: false,
7355		secure: false,
7356		document: document
7357	},
7358
7359	initialize: function(key, options){
7360		this.key = key;
7361		this.setOptions(options);
7362	},
7363
7364	write: function(value){
7365		value = encodeURIComponent(value);
7366		if (this.options.domain) value += '; domain=' + this.options.domain;
7367		if (this.options.path) value += '; path=' + this.options.path;
7368		if (this.options.duration){
7369			var date = new Date();
7370			date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
7371			value += '; expires=' + date.toGMTString();
7372		}
7373		if (this.options.secure) value += '; secure';
7374		this.options.document.cookie = this.key + '=' + value;
7375		return this;
7376	},
7377
7378	read: function(){
7379		var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
7380		return (value) ? decodeURIComponent(value[1]) : null;
7381	},
7382
7383	dispose: function(){
7384		new Cookie(this.key, $merge(this.options, {duration: -1})).write('');
7385		return this;
7386	}
7387
7388});
7389
7390Cookie.write = function(key, value, options){
7391	return new Cookie(key, options).write(value);
7392};
7393
7394Cookie.read = function(key){
7395	return new Cookie(key).read();
7396};
7397
7398Cookie.dispose = function(key, options){
7399	return new Cookie(key, options).dispose();
7400};
7401
7402
7403/*
7404Script: Swiff.js
7405	Wrapper for embedding SWF movies. Supports (and fixes) External Interface Communication.
7406
7407License:
7408	MIT-style license.
7409
7410Credits:
7411	Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
7412*/
7413
7414var Swiff = new Class({
7415
7416	Implements: [Options],
7417
7418	options: {
7419		id: null,
7420		height: 1,
7421		width: 1,
7422		container: null,
7423		properties: {},
7424		params: {
7425			quality: 'high',
7426			allowScriptAccess: 'always',
7427			wMode: 'transparent',
7428			swLiveConnect: true
7429		},
7430		callBacks: {},
7431		vars: {}
7432	},
7433
7434	toElement: function(){
7435		return this.object;
7436	},
7437
7438	initialize: function(path, options){
7439		this.instance = 'Swiff_' + $time();
7440
7441		this.setOptions(options);
7442		options = this.options;
7443		var id = this.id = options.id || this.instance;
7444		var container = $(options.container);
7445
7446		Swiff.CallBacks[this.instance] = {};
7447
7448		var params = options.params, vars = options.vars, callBacks = options.callBacks;
7449		var properties = $extend({height: options.height, width: options.width}, options.properties);
7450
7451		var self = this;
7452
7453		for (var callBack in callBacks){
7454			Swiff.CallBacks[this.instance][callBack] = (function(option){
7455				return function(){
7456					return option.apply(self.object, arguments);
7457				};
7458			})(callBacks[callBack]);
7459			vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack;
7460		}
7461
7462		params.flashVars = Hash.toQueryString(vars);
7463		if (Browser.Engine.trident){
7464			properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
7465			params.movie = path;
7466		} else {
7467			properties.type = 'application/x-shockwave-flash';
7468			properties.data = path;
7469		}
7470		var build = '<object id="' + id + '"';
7471		for (var property in properties) build += ' ' + property + '="' + properties[property] + '"';
7472		build += '>';
7473		for (var param in params){
7474			if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />';
7475		}
7476		build += '</object>';
7477		this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild;
7478	},
7479
7480	replaces: function(element){
7481		element = $(element, true);
7482		element.parentNode.replaceChild(this.toElement(), element);
7483		return this;
7484	},
7485
7486	inject: function(element){
7487		$(element, true).appendChild(this.toElement());
7488		return this;
7489	},
7490
7491	remote: function(){
7492		return Swiff.remote.apply(Swiff, [this.toElement()].extend(arguments));
7493	}
7494
7495});
7496
7497Swiff.CallBacks = {};
7498
7499Swiff.remote = function(obj, fn){
7500	var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>');
7501	return eval(rs);
7502};
7503
7504
7505/*
7506Script: Fx.js
7507	Contains the basic animation logic to be extended by all other Fx Classes.
7508
7509License:
7510	MIT-style license.
7511*/
7512
7513var Fx = new Class({
7514
7515	Implements: [Chain, Events, Options],
7516
7517	options: {
7518		/*
7519		onStart: $empty,
7520		onCancel: $empty,
7521		onComplete: $empty,
7522		*/
7523		fps: 50,
7524		unit: false,
7525		duration: 500,
7526		link: 'ignore'
7527	},
7528
7529	initialize: function(options){
7530		this.subject = this.subject || this;
7531		this.setOptions(options);
7532		this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt();
7533		var wait = this.options.wait;
7534		if (wait === false) this.options.link = 'cancel';
7535	},
7536
7537	getTransition: function(){
7538		return function(p){
7539			return -(Math.cos(Math.PI * p) - 1) / 2;
7540		};
7541	},
7542
7543	step: function(){
7544		var time = $time();
7545		if (time < this.time + this.options.duration){
7546			var delta = this.transition((time - this.time) / this.options.duration);
7547			this.set(this.compute(this.from, this.to, delta));
7548		} else {
7549			this.set(this.compute(this.from, this.to, 1));
7550			this.complete();
7551		}
7552	},
7553
7554	set: function(now){
7555		return now;
7556	},
7557
7558	compute: function(from, to, delta){
7559		return Fx.compute(from, to, delta);
7560	},
7561
7562	check: function(){
7563		if (!this.timer) return true;
7564		switch (this.options.link){
7565			case 'cancel': this.cancel(); return true;
7566			case 'chain': this.chain(this.caller.bind(this, arguments)); return false;
7567		}
7568		return false;
7569	},
7570
7571	start: function(from, to){
7572		if (!this.check(from, to)) return this;
7573		this.from = from;
7574		this.to = to;
7575		this.time = 0;
7576		this.transition = this.getTransition();
7577		this.startTimer();
7578		this.onStart();
7579		return this;
7580	},
7581
7582	complete: function(){
7583		if (this.stopTimer()) this.onComplete();
7584		return this;
7585	},
7586
7587	cancel: function(){
7588		if (this.stopTimer()) this.onCancel();
7589		return this;
7590	},
7591
7592	onStart: function(){
7593		this.fireEvent('start', this.subject);
7594	},
7595
7596	onComplete: function(){
7597		this.fireEvent('complete', this.subject);
7598		if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
7599	},
7600
7601	onCancel: function(){
7602		this.fireEvent('cancel', this.subject).clearChain();
7603	},
7604
7605	pause: function(){
7606		this.stopTimer();
7607		return this;
7608	},
7609
7610	resume: function(){
7611		this.startTimer();
7612		return this;
7613	},
7614
7615	stopTimer: function(){
7616		if (!this.timer) return false;
7617		this.time = $time() - this.time;
7618		this.timer = $clear(this.timer);
7619		return true;
7620	},
7621
7622	startTimer: function(){
7623		if (this.timer) return false;
7624		this.time = $time() - this.time;
7625		this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
7626		return true;
7627	}
7628
7629});
7630
7631Fx.compute = function(from, to, delta){
7632	return (to - from) * delta + from;
7633};
7634
7635Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
7636
7637
7638/*
7639Script: Fx.CSS.js
7640	Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
7641
7642License:
7643	MIT-style license.
7644*/
7645
7646Fx.CSS = new Class({
7647
7648	Extends: Fx,
7649
7650	//prepares the base from/to object
7651
7652	prepare: function(element, property, values){
7653		values = $splat(values);
7654		var values1 = values[1];
7655		if (!$chk(values1)){
7656			values[1] = values[0];
7657			values[0] = element.getStyle(property);
7658		}
7659		var parsed = values.map(this.parse);
7660		return {from: parsed[0], to: parsed[1]};
7661	},
7662
7663	//parses a value into an array
7664
7665	parse: function(value){
7666		value = $lambda(value)();
7667		value = (typeof value == 'string') ? value.split(' ') : $splat(value);
7668		return value.map(function(val){
7669			val = String(val);
7670			var found = false;
7671			Fx.CSS.Parsers.each(function(parser, key){
7672				if (found) return;
7673				var parsed = parser.parse(val);
7674				if ($chk(parsed)) found = {value: parsed, parser: parser};
7675			});
7676			found = found || {value: val, parser: Fx.CSS.Parsers.String};
7677			return found;
7678		});
7679	},
7680
7681	//computes by a from and to prepared objects, using their parsers.
7682
7683	compute: function(from, to, delta){
7684		var computed = [];
7685		(Math.min(from.length, to.length)).times(function(i){
7686			computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
7687		});
7688		computed.$family = {name: 'fx:css:value'};
7689		return computed;
7690	},
7691
7692	//serves the value as settable
7693
7694	serve: function(value, unit){
7695		if ($type(value) != 'fx:css:value') value = this.parse(value);
7696		var returned = [];
7697		value.each(function(bit){
7698			returned = returned.concat(bit.parser.serve(bit.value, unit));
7699		});
7700		return returned;
7701	},
7702
7703	//renders the change to an element
7704
7705	render: function(element, property, value, unit){
7706		element.setStyle(property, this.serve(value, unit));
7707	},
7708
7709	//searches inside the page css to find the values for a selector
7710
7711	search: function(selector){
7712		if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
7713		var to = {};
7714		Array.each(document.styleSheets, function(sheet, j){
7715			var href = sheet.href;
7716			if (href && href.contains('://') && !href.contains(document.domain)) return;
7717			var rules = sheet.rules || sheet.cssRules;
7718			Array.each(rules, function(rule, i){
7719				if (!rule.style) return;
7720				var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
7721					return m.toLowerCase();
7722				}) : null;
7723				if (!selectorText || !selectorText.test('^' + selector + '$')) return;
7724				Element.Styles.each(function(value, style){
7725					if (!rule.style[style] || Element.ShortStyles[style]) return;
7726					value = String(rule.style[style]);
7727					to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value;
7728				});
7729			});
7730		});
7731		return Fx.CSS.Cache[selector] = to;
7732	}
7733
7734});
7735
7736Fx.CSS.Cache = {};
7737
7738Fx.CSS.Parsers = new Hash({
7739
7740	Color: {
7741		parse: function(value){
7742			if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
7743			return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
7744		},
7745		compute: function(from, to, delta){
7746			return from.map(function(value, i){
7747				return Math.round(Fx.compute(from[i], to[i], delta));
7748			});
7749		},
7750		serve: function(value){
7751			return value.map(Number);
7752		}
7753	},
7754
7755	Number: {
7756		parse: parseFloat,
7757		compute: Fx.compute,
7758		serve: function(value, unit){
7759			return (unit) ? value + unit : value;
7760		}
7761	},
7762
7763	String: {
7764		parse: $lambda(false),
7765		compute: $arguments(1),
7766		serve: $arguments(0)
7767	}
7768
7769});
7770
7771
7772/*
7773Script: Fx.Tween.js
7774	Formerly Fx.Style, effect to transition any CSS property for an element.
7775
7776License:
7777	MIT-style license.
7778*/
7779
7780Fx.Tween = new Class({
7781
7782	Extends: Fx.CSS,
7783
7784	initialize: function(element, options){
7785		this.element = this.subject = $(element);
7786		this.parent(options);
7787	},
7788
7789	set: function(property, now){
7790		if (arguments.length == 1){
7791			now = property;
7792			property = this.property || this.options.property;
7793		}
7794		this.render(this.element, property, now, this.options.unit);
7795		return this;
7796	},
7797
7798	start: function(property, from, to){
7799		if (!this.check(property, from, to)) return this;
7800		var args = Array.flatten(arguments);
7801		this.property = this.options.property || args.shift();
7802		var parsed = this.prepare(this.element, this.property, args);
7803		return this.parent(parsed.from, parsed.to);
7804	}
7805
7806});
7807
7808Element.Properties.tween = {
7809
7810	set: function(options){
7811		var tween = this.retrieve('tween');
7812		if (tween) tween.cancel();
7813		return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options));
7814	},
7815
7816	get: function(options){
7817		if (options || !this.retrieve('tween')){
7818			if (options || !this.retrieve('tween:options')) this.set('tween', options);
7819			this.store('tween', new Fx.Tween(this, this.retrieve('tween:options')));
7820		}
7821		return this.retrieve('tween');
7822	}
7823
7824};
7825
7826Element.implement({
7827
7828	tween: function(property, from, to){
7829		this.get('tween').start(arguments);
7830		return this;
7831	},
7832
7833	fade: function(how){
7834		var fade = this.get('tween'), o = 'opacity', toggle;
7835		how = $pick(how, 'toggle');
7836		switch (how){
7837			case 'in': fade.start(o, 1); break;
7838			case 'out': fade.start(o, 0); break;
7839			case 'show': fade.set(o, 1); break;
7840			case 'hide': fade.set(o, 0); break;
7841			case 'toggle':
7842				var flag = this.retrieve('fade:flag', this.get('opacity') == 1);
7843				fade.start(o, (flag) ? 0 : 1);
7844				this.store('fade:flag', !flag);
7845				toggle = true;
7846			break;
7847			default: fade.start(o, arguments);
7848		}
7849		if (!toggle) this.eliminate('fade:flag');
7850		return this;
7851	},
7852
7853	highlight: function(start, end){
7854		if (!end){
7855			end = this.retrieve('highlight:original', this.getStyle('background-color'));
7856			end = (end == 'transparent') ? '#fff' : end;
7857		}
7858		var tween = this.get('tween');
7859		tween.start('background-color', start || '#ffff88', end).chain(function(){
7860			this.setStyle('background-color', this.retrieve('highlight:original'));
7861			tween.callChain();
7862		}.bind(this));
7863		return this;
7864	}
7865
7866});
7867
7868
7869/*
7870Script: Fx.Morph.js
7871	Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
7872
7873License:
7874	MIT-style license.
7875*/
7876
7877Fx.Morph = new Class({
7878
7879	Extends: Fx.CSS,
7880
7881	initialize: function(element, options){
7882		this.element = this.subject = $(element);
7883		this.parent(options);
7884	},
7885
7886	set: function(now){
7887		if (typeof now == 'string') now = this.search(now);
7888		for (var p in now) this.render(this.element, p, now[p], this.options.unit);
7889		return this;
7890	},
7891
7892	compute: function(from, to, delta){
7893		var now = {};
7894		for (var p in from) now[p] = this.parent(from[p], to[p], delta);
7895		return now;
7896	},
7897
7898	start: function(properties){
7899		if (!this.check(properties)) return this;
7900		if (typeof properties == 'string') properties = this.search(properties);
7901		var from = {}, to = {};
7902		for (var p in properties){
7903			var parsed = this.prepare(this.element, p, properties[p]);
7904			from[p] = parsed.from;
7905			to[p] = parsed.to;
7906		}
7907		return this.parent(from, to);
7908	}
7909
7910});
7911
7912Element.Properties.morph = {
7913
7914	set: function(options){
7915		var morph = this.retrieve('morph');
7916		if (morph) morph.cancel();
7917		return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options));
7918	},
7919
7920	get: function(options){
7921		if (options || !this.retrieve('morph')){
7922			if (options || !this.retrieve('morph:options')) this.set('morph', options);
7923			this.store('morph', new Fx.Morph(this, this.retrieve('morph:options')));
7924		}
7925		return this.retrieve('morph');
7926	}
7927
7928};
7929
7930Element.implement({
7931
7932	morph: function(props){
7933		this.get('morph').start(props);
7934		return this;
7935	}
7936
7937});
7938
7939
7940/*
7941Script: Fx.Transitions.js
7942	Contains a set of advanced transitions to be used with any of the Fx Classes.
7943
7944License:
7945	MIT-style license.
7946
7947Credits:
7948	Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
7949*/
7950
7951Fx.implement({
7952
7953	getTransition: function(){
7954		var trans = this.options.transition || Fx.Transitions.Sine.easeInOut;
7955		if (typeof trans == 'string'){
7956			var data = trans.split(':');
7957			trans = Fx.Transitions;
7958			trans = trans[data[0]] || trans[data[0].capitalize()];
7959			if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')];
7960		}
7961		return trans;
7962	}
7963
7964});
7965
7966Fx.Transition = function(transition, params){
7967	params = $splat(params);
7968	return $extend(transition, {
7969		easeIn: function(pos){
7970			return transition(pos, params);
7971		},
7972		easeOut: function(pos){
7973			return 1 - transition(1 - pos, params);
7974		},
7975		easeInOut: function(pos){
7976			return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
7977		}
7978	});
7979};
7980
7981Fx.Transitions = new Hash({
7982
7983	linear: $arguments(0)
7984
7985});
7986
7987Fx.Transitions.extend = function(transitions){
7988	for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
7989};
7990
7991Fx.Transitions.extend({
7992
7993	Pow: function(p, x){
7994		return Math.pow(p, x[0] || 6);
7995	},
7996
7997	Expo: function(p){
7998		return Math.pow(2, 8 * (p - 1));
7999	},
8000
8001	Circ: function(p){
8002		return 1 - Math.sin(Math.acos(p));
8003	},
8004
8005	Sine: function(p){
8006		return 1 - Math.sin((1 - p) * Math.PI / 2);
8007	},
8008
8009	Back: function(p, x){
8010		x = x[0] || 1.618;
8011		return Math.pow(p, 2) * ((x + 1) * p - x);
8012	},
8013
8014	Bounce: function(p){
8015		var value;
8016		for (var a = 0, b = 1; 1; a += b, b /= 2){
8017			if (p >= (7 - 4 * a) / 11){
8018				value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
8019				break;
8020			}
8021		}
8022		return value;
8023	},
8024
8025	Elastic: function(p, x){
8026		return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
8027	}
8028
8029});
8030
8031['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
8032	Fx.Transitions[transition] = new Fx.Transition(function(p){
8033		return Math.pow(p, [i + 2]);
8034	});
8035});
8036
8037
8038/*
8039Script: Request.js
8040	Powerful all purpose Request Class. Uses XMLHTTPRequest.
8041
8042License:
8043	MIT-style license.
8044*/
8045
8046var Request = new Class({
8047
8048	Implements: [Chain, Events, Options],
8049
8050	options: {/*
8051		onRequest: $empty,
8052		onComplete: $empty,
8053		onCancel: $empty,
8054		onSuccess: $empty,
8055		onFailure: $empty,
8056		onException: $empty,*/
8057		url: '',
8058		data: '',
8059		headers: {
8060			'X-Requested-With': 'XMLHttpRequest',
8061			'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
8062		},
8063		async: true,
8064		format: false,
8065		method: 'post',
8066		link: 'ignore',
8067		isSuccess: null,
8068		emulation: true,
8069		urlEncoded: true,
8070		encoding: 'utf-8',
8071		evalScripts: false,
8072		evalResponse: false,
8073		noCache: false
8074	},
8075
8076	initialize: function(options){
8077		this.xhr = new Browser.Request();
8078		this.setOptions(options);
8079		this.options.isSuccess = this.options.isSuccess || this.isSuccess;
8080		this.headers = new Hash(this.options.headers);
8081	},
8082
8083	onStateChange: function(){
8084		if (this.xhr.readyState != 4 || !this.running) return;
8085		this.running = false;
8086		this.status = 0;
8087		$try(function(){
8088			this.status = this.xhr.status;
8089		}.bind(this));
8090		if (this.options.isSuccess.call(this, this.status)){
8091			this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML};
8092			this.success(this.response.text, this.response.xml);
8093		} else {
8094			this.response = {text: null, xml: null};
8095			this.failure();
8096		}
8097		this.xhr.onreadystatechange = $empty;
8098	},
8099
8100	isSuccess: function(){
8101		return ((this.status >= 200) && (this.status < 300));
8102	},
8103
8104	processScripts: function(text){
8105		if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text);
8106		return text.stripScripts(this.options.evalScripts);
8107	},
8108
8109	success: function(text, xml){
8110		this.onSuccess(this.processScripts(text), xml);
8111	},
8112
8113	onSuccess: function(){
8114		this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
8115	},
8116
8117	failure: function(){
8118		this.onFailure();
8119	},
8120
8121	onFailure: function(){
8122		this.fireEvent('complete').fireEvent('failure', this.xhr);
8123	},
8124
8125	setHeader: function(name, value){
8126		this.headers.set(name, value);
8127		return this;
8128	},
8129
8130	getHeader: function(name){
8131		return $try(function(){
8132			return this.xhr.getResponseHeader(name);
8133		}.bind(this));
8134	},
8135
8136	check: function(){
8137		if (!this.running) return true;
8138		switch (this.options.link){
8139			case 'cancel': this.cancel(); return true;
8140			case 'chain': this.chain(this.caller.bind(this, arguments)); return false;
8141		}
8142		return false;
8143	},
8144
8145	send: function(options){
8146		if (!this.check(options)) return this;
8147		this.running = true;
8148
8149		var type = $type(options);
8150		if (type == 'string' || type == 'element') options = {data: options};
8151
8152		var old = this.options;
8153		options = $extend({data: old.data, url: old.url, method: old.method}, options);
8154		var data = options.data, url = options.url, method = options.method;
8155
8156		switch ($type(data)){
8157			case 'element': data = $(data).toQueryString(); break;
8158			case 'object': case 'hash': data = Hash.toQueryString(data);
8159		}
8160
8161		if (this.options.format){
8162			var format = 'format=' + this.options.format;
8163			data = (data) ? format + '&' + data : format;
8164		}
8165
8166		if (this.options.emulation && ['put', 'delete'].contains(method)){
8167			var _method = '_method=' + method;
8168			data = (data) ? _method + '&' + data : _method;
8169			method = 'post';
8170		}
8171
8172		if (this.options.urlEncoded && method == 'post'){
8173			var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
8174			this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding);
8175		}
8176
8177		if(this.options.noCache) {
8178			var noCache = "noCache=" + new Date().getTime();
8179			data = (data) ? noCache + '&' + data : noCache;
8180		}
8181
8182
8183		if (data && method == 'get'){
8184			url = url + (url.contains('?') ? '&' : '?') + data;
8185			data = null;
8186		}
8187
8188
8189		this.xhr.open(method.toUpperCase(), url, this.options.async);
8190
8191		this.xhr.onreadystatechange = this.onStateChange.bind(this);
8192
8193		this.headers.each(function(value, key){
8194			try {
8195				this.xhr.setRequestHeader(key, value);
8196			} catch (e){
8197				this.fireEvent('exception', [key, value]);
8198			}
8199		}, this);
8200
8201		this.fireEvent('request');
8202		this.xhr.send(data);
8203		if (!this.options.async) this.onStateChange();
8204		return this;
8205	},
8206
8207	cancel: function(){
8208		if (!this.running) return this;
8209		this.running = false;
8210		this.xhr.abort();
8211		this.xhr.onreadystatechange = $empty;
8212		this.xhr = new Browser.Request();
8213		this.fireEvent('cancel');
8214		return this;
8215	}
8216
8217});
8218
8219(function(){
8220
8221var methods = {};
8222['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
8223	methods[method] = function(){
8224		var params = Array.link(arguments, {url: String.type, data: $defined});
8225		return this.send($extend(params, {method: method.toLowerCase()}));
8226	};
8227});
8228
8229Request.implement(methods);
8230
8231})();
8232
8233/*
8234Script: Request.HTML.js
8235	Extends the basic Request Class with additional methods for interacting with HTML responses.
8236
8237License:
8238	MIT-style license.
8239*/
8240
8241Request.HTML = new Class({
8242
8243	Extends: Request,
8244
8245	options: {
8246		update: false,
8247		append: false,
8248		evalScripts: true,
8249		filter: false
8250	},
8251
8252	processHTML: function(text){
8253		var match = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
8254		text = (match) ? match[1] : text;
8255
8256		var container = new Element('div');
8257
8258		return $try(function(){
8259			var root = '<root>' + text + '</root>', doc;
8260			if (Browser.Engine.trident){
8261				doc = new ActiveXObject('Microsoft.XMLDOM');
8262				doc.async = false;
8263				doc.loadXML(root);
8264			} else {
8265				doc = new DOMParser().parseFromString(root, 'text/xml');
8266			}
8267			root = doc.getElementsByTagName('root')[0];
8268			if (!root) return null;
8269			for (var i = 0, k = root.childNodes.length; i < k; i++){
8270				var child = Element.clone(root.childNodes[i], true, true);
8271				if (child) container.grab(child);
8272			}
8273			return container;
8274		}) || container.set('html', text);
8275	},
8276
8277	success: function(text){
8278		var options = this.options, response = this.response;
8279
8280		response.html = text.stripScripts(function(script){
8281			response.javascript = script;
8282		});
8283
8284		var temp = this.processHTML(response.html);
8285
8286		response.tree = temp.childNodes;
8287		response.elements = temp.getElements('*');
8288
8289		if (options.filter) response.tree = response.elements.filter(options.filter);
8290		if (options.update) $(options.update).empty().set('html', response.html);
8291		else if (options.append) $(options.append).adopt(temp.getChildren());
8292		if (options.evalScripts) $exec(response.javascript);
8293
8294		this.onSuccess(response.tree, response.elements, response.html, response.javascript);
8295	}
8296
8297});
8298
8299Element.Properties.send = {
8300
8301	set: function(options){
8302		var send = this.retrieve('send');
8303		if (send) send.cancel();
8304		return this.eliminate('send').store('send:options', $extend({
8305			data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action')
8306		}, options));
8307	},
8308
8309	get: function(options){
8310		if (options || !this.retrieve('send')){
8311			if (options || !this.retrieve('send:options')) this.set('send', options);
8312			this.store('send', new Request(this.retrieve('send:options')));
8313		}
8314		return this.retrieve('send');
8315	}
8316
8317};
8318
8319Element.Properties.load = {
8320
8321	set: function(options){
8322		var load = this.retrieve('load');
8323		if (load) load.cancel();
8324		return this.eliminate('load').store('load:options', $extend({data: this, link: 'cancel', update: this, method: 'get'}, options));
8325	},
8326
8327	get: function(options){
8328		if (options || ! this.retrieve('load')){
8329			if (options || !this.retrieve('load:options')) this.set('load', options);
8330			this.store('load', new Request.HTML(this.retrieve('load:options')));
8331		}
8332		return this.retrieve('load');
8333	}
8334
8335};
8336
8337Element.implement({
8338
8339	send: function(url){
8340		var sender = this.get('send');
8341		sender.send({data: this, url: url || sender.options.url});
8342		return this;
8343	},
8344
8345	load: function(){
8346		this.get('load').send(Array.link(arguments, {data: Object.type, url: String.type}));
8347		return this;
8348	}
8349
8350});
8351
8352
8353/*
8354Script: Request.JSON.js
8355	Extends the basic Request Class with additional methods for sending and receiving JSON data.
8356
8357License:
8358	MIT-style license.
8359*/
8360
8361Request.JSON = new Class({
8362
8363	Extends: Request,
8364
8365	options: {
8366		secure: true
8367	},
8368
8369	initialize: function(options){
8370		this.parent(options);
8371		this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'});
8372	},
8373
8374	success: function(text){
8375		this.response.json = JSON.decode(text, this.options.secure);
8376		this.onSuccess(this.response.json, text);
8377	}
8378
8379});
8380/*  Prototype JavaScript framework, version 1.6.0.3
8381 *  (c) 2005-2008 Sam Stephenson
8382 *
8383 *  Prototype is freely distributable under the terms of an MIT-style license.
8384 *  For details, see the Prototype web site: http://www.prototypejs.org/
8385 *
8386 *--------------------------------------------------------------------------*/
8387
8388var Prototype = {
8389  Version: '1.6.0.3',
8390
8391  Browser: {
8392    IE:     !!(window.attachEvent &&
8393      navigator.userAgent.indexOf('Opera') === -1),
8394    Opera:  navigator.userAgent.indexOf('Opera') > -1,
8395    WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
8396    Gecko:  navigator.userAgent.indexOf('Gecko') > -1 &&
8397      navigator.userAgent.indexOf('KHTML') === -1,
8398    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
8399  },
8400
8401  BrowserFeatures: {
8402    XPath: !!document.evaluate,
8403    SelectorsAPI: !!document.querySelector,
8404    ElementExtensions: !!window.HTMLElement,
8405    SpecificElementExtensions:
8406      document.createElement('div')['__proto__'] &&
8407      document.createElement('div')['__proto__'] !==
8408        document.createElement('form')['__proto__']
8409  },
8410
8411  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
8412  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
8413
8414  emptyFunction: function() { },
8415  K: function(x) { return x }
8416};
8417
8418if (Prototype.Browser.MobileSafari)
8419  Prototype.BrowserFeatures.SpecificElementExtensions = false;
8420
8421
8422/* Based on Alex Arnell's inheritance implementation. */
8423var Class = {
8424  create: function() {
8425    var parent = null, properties = $A(arguments);
8426    if (Object.isFunction(properties[0]))
8427      parent = properties.shift();
8428
8429    function klass() {
8430      this.initialize.apply(this, arguments);
8431    }
8432
8433    Object.extend(klass, Class.Methods);
8434    klass.superclass = parent;
8435    klass.subclasses = [];
8436
8437    if (parent) {
8438      var subclass = function() { };
8439      subclass.prototype = parent.prototype;
8440      klass.prototype = new subclass;
8441      parent.subclasses.push(klass);
8442    }
8443
8444    for (var i = 0; i < properties.length; i++)
8445      klass.addMethods(properties[i]);
8446
8447    if (!klass.prototype.initialize)
8448      klass.prototype.initialize = Prototype.emptyFunction;
8449
8450    klass.prototype.constructor = klass;
8451
8452    return klass;
8453  }
8454};
8455
8456Class.Methods = {
8457  addMethods: function(source) {
8458    var ancestor   = this.superclass && this.superclass.prototype;
8459    var properties = Object.keys(source);
8460
8461    if (!Object.keys({ toString: true }).length)
8462      properties.push("toString", "valueOf");
8463
8464    for (var i = 0, length = properties.length; i < length; i++) {
8465      var property = properties[i], value = source[property];
8466      if (ancestor && Object.isFunction(value) &&
8467          value.argumentNames().first() == "$super") {
8468        var method = value;
8469        value = (function(m) {
8470          return function() { return ancestor[m].apply(this, arguments) };
8471        })(property).wrap(method);
8472
8473        value.valueOf = method.valueOf.bind(method);
8474        value.toString = method.toString.bind(method);
8475      }
8476      this.prototype[property] = value;
8477    }
8478
8479    return this;
8480  }
8481};
8482
8483var Abstract = { };
8484
8485Object.extend = function(destination, source) {
8486  for (var property in source)
8487    destination[property] = source[property];
8488  return destination;
8489};
8490
8491Object.extend(Object, {
8492  inspect: function(object) {
8493    try {
8494      if (Object.isUndefined(object)) return 'undefined';
8495      if (object === null) return 'null';
8496      return object.inspect ? object.inspect() : String(object);
8497    } catch (e) {
8498      if (e instanceof RangeError) return '...';
8499      throw e;
8500    }
8501  },
8502
8503  toJSON: function(object) {
8504    var type = typeof object;
8505    switch (type) {
8506      case 'undefined':
8507      case 'function':
8508      case 'unknown': return;
8509      case 'boolean': return object.toString();
8510    }
8511
8512    if (object === null) return 'null';
8513    if (object.toJSON) return object.toJSON();
8514    if (Object.isElement(object)) return;
8515
8516    var results = [];
8517    for (var property in object) {
8518      var value = Object.toJSON(object[property]);
8519      if (!Object.isUndefined(value))
8520        results.push(property.toJSON() + ': ' + value);
8521    }
8522
8523    return '{' + results.join(', ') + '}';
8524  },
8525
8526  toQueryString: function(object) {
8527    return $H(object).toQueryString();
8528  },
8529
8530  toHTML: function(object) {
8531    return object && object.toHTML ? object.toHTML() : String.interpret(object);
8532  },
8533
8534  keys: function(object) {
8535    var keys = [];
8536    for (var property in object)
8537      keys.push(property);
8538    return keys;
8539  },
8540
8541  values: function(object) {
8542    var values = [];
8543    for (var property in object)
8544      values.push(object[property]);
8545    return values;
8546  },
8547
8548  clone: function(object) {
8549    return Object.extend({ }, object);
8550  },
8551
8552  isElement: function(object) {
8553    return !!(object && object.nodeType == 1);
8554  },
8555
8556  isArray: function(object) {
8557    return object != null && typeof object == "object" &&
8558      'splice' in object && 'join' in object;
8559  },
8560
8561  isHash: function(object) {
8562    return object instanceof Hash;
8563  },
8564
8565  isFunction: function(object) {
8566    return typeof object == "function";
8567  },
8568
8569  isString: function(object) {
8570    return typeof object == "string";
8571  },
8572
8573  isNumber: function(object) {
8574    return typeof object == "number";
8575  },
8576
8577  isUndefined: function(object) {
8578    return typeof object == "undefined";
8579  }
8580});
8581
8582Object.extend(Function.prototype, {
8583  argumentNames: function() {
8584    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
8585      .replace(/\s+/g, '').split(',');
8586    return names.length == 1 && !names[0] ? [] : names;
8587  },
8588
8589  bind: function() {
8590    if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this;
8591    var __method = this, args = $A(arguments), object = args.shift();
8592    return function() {
8593      return __method.apply(object, args.concat($A(arguments)));
8594    }
8595  },
8596
8597  bindAsEventListener: function() {
8598    var __method = this, args = $A(arguments), object = args.shift();
8599    return function(event) {
8600      return __method.apply(object, [event || window.event].concat(args));
8601    }
8602  },
8603
8604  curry: function() {
8605    if (!arguments.length) return this;
8606    var __method = this, args = $A(arguments);
8607    return function() {
8608      return __method.apply(this, args.concat($A(arguments)));
8609    }
8610  },
8611
8612  delay: function() {
8613    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
8614    return window.setTimeout(function() {
8615      return __method.apply(__method, args);
8616    }, timeout);
8617  },
8618
8619  defer: function() {
8620    var args = [0.01].concat($A(arguments));
8621    return this.delay.apply(this, args);
8622  },
8623
8624  wrap: function(wrapper) {
8625    var __method = this;
8626    return function() {
8627      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
8628    }
8629  },
8630
8631  methodize: function() {
8632    if (this._methodized) return this._methodized;
8633    var __method = this;
8634    return this._methodized = function() {
8635      return __method.apply(null, [this].concat($A(arguments)));
8636    };
8637  }
8638});
8639
8640Date.prototype.toJSON = function() {
8641  return '"' + this.getUTCFullYear() + '-' +
8642    (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
8643    this.getUTCDate().toPaddedString(2) + 'T' +
8644    this.getUTCHours().toPaddedString(2) + ':' +
8645    this.getUTCMinutes().toPaddedString(2) + ':' +
8646    this.getUTCSeconds().toPaddedString(2) + 'Z"';
8647};
8648
8649var Try = {
8650  these: function() {
8651    var returnValue;
8652
8653    for (var i = 0, length = arguments.length; i < length; i++) {
8654      var lambda = arguments[i];
8655      try {
8656        returnValue = lambda();
8657        break;
8658      } catch (e) { }
8659    }
8660
8661    return returnValue;
8662  }
8663};
8664
8665RegExp.prototype.match = RegExp.prototype.test;
8666
8667RegExp.escape = function(str) {
8668  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
8669};
8670
8671/*--------------------------------------------------------------------------*/
8672
8673var PeriodicalExecuter = Class.create({
8674  initialize: function(callback, frequency) {
8675    this.callback = callback;
8676    this.frequency = frequency;
8677    this.currentlyExecuting = false;
8678
8679    this.registerCallback();
8680  },
8681
8682  registerCallback: function() {
8683    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
8684  },
8685
8686  execute: function() {
8687    this.callback(this);
8688  },
8689
8690  stop: function() {
8691    if (!this.timer) return;
8692    clearInterval(this.timer);
8693    this.timer = null;
8694  },
8695
8696  onTimerEvent: function() {
8697    if (!this.currentlyExecuting) {
8698      try {
8699        this.currentlyExecuting = true;
8700        this.execute();
8701      } finally {
8702        this.currentlyExecuting = false;
8703      }
8704    }
8705  }
8706});
8707Object.extend(String, {
8708  interpret: function(value) {
8709    return value == null ? '' : String(value);
8710  },
8711  specialChar: {
8712    '\b': '\\b',
8713    '\t': '\\t',
8714    '\n': '\\n',
8715    '\f': '\\f',
8716    '\r': '\\r',
8717    '\\': '\\\\'
8718  }
8719});
8720
8721Object.extend(String.prototype, {
8722  gsub: function(pattern, replacement) {
8723    var result = '', source = this, match;
8724    replacement = arguments.callee.prepareReplacement(replacement);
8725
8726    while (source.length > 0) {
8727      if (match = source.match(pattern)) {
8728        result += source.slice(0, match.index);
8729        result += String.interpret(replacement(match));
8730        source  = source.slice(match.index + match[0].length);
8731      } else {
8732        result += source, source = '';
8733      }
8734    }
8735    return result;
8736  },
8737
8738  sub: function(pattern, replacement, count) {
8739    replacement = this.gsub.prepareReplacement(replacement);
8740    count = Object.isUndefined(count) ? 1 : count;
8741
8742    return this.gsub(pattern, function(match) {
8743      if (--count < 0) return match[0];
8744      return replacement(match);
8745    });
8746  },
8747
8748  scan: function(pattern, iterator) {
8749    this.gsub(pattern, iterator);
8750    return String(this);
8751  },
8752
8753  truncate: function(length, truncation) {
8754    length = length || 30;
8755    truncation = Object.isUndefined(truncation) ? '...' : truncation;
8756    return this.length > length ?
8757      this.slice(0, length - truncation.length) + truncation : String(this);
8758  },
8759
8760  strip: function() {
8761    return this.replace(/^\s+/, '').replace(/\s+$/, '');
8762  },
8763
8764  stripTags: function() {
8765    return this.replace(/<\/?[^>]+>/gi, '');
8766  },
8767
8768  stripScripts: function() {
8769    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
8770  },
8771
8772  extractScripts: function() {
8773    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
8774    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
8775    return (this.match(matchAll) || []).map(function(scriptTag) {
8776      return (scriptTag.match(matchOne) || ['', ''])[1];
8777    });
8778  },
8779
8780  evalScripts: function() {
8781    return this.extractScripts().map(function(script) { return eval(script) });
8782  },
8783
8784  escapeHTML: function() {
8785    var self = arguments.callee;
8786    self.text.data = this;
8787    return self.div.innerHTML;
8788  },
8789
8790  unescapeHTML: function() {
8791    var div = new Element('div');
8792    div.innerHTML = this.stripTags();
8793    return div.childNodes[0] ? (div.childNodes.length > 1 ?
8794      $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
8795      div.childNodes[0].nodeValue) : '';
8796  },
8797
8798  toQueryParams: function(separator) {
8799    var match = this.strip().match(/([^?#]*)(#.*)?$/);
8800    if (!match) return { };
8801
8802    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
8803      if ((pair = pair.split('='))[0]) {
8804        var key = decodeURIComponent(pair.shift());
8805        var value = pair.length > 1 ? pair.join('=') : pair[0];
8806        if (value != undefined) value = decodeURIComponent(value);
8807
8808        if (key in hash) {
8809          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
8810          hash[key].push(value);
8811        }
8812        else hash[key] = value;
8813      }
8814      return hash;
8815    });
8816  },
8817
8818  toArray: function() {
8819    return this.split('');
8820  },
8821
8822  succ: function() {
8823    return this.slice(0, this.length - 1) +
8824      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
8825  },
8826
8827  times: function(count) {
8828    return count < 1 ? '' : new Array(count + 1).join(this);
8829  },
8830
8831  camelize: function() {
8832    var parts = this.split('-'), len = parts.length;
8833    if (len == 1) return parts[0];
8834
8835    var camelized = this.charAt(0) == '-'
8836      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
8837      : parts[0];
8838
8839    for (var i = 1; i < len; i++)
8840      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
8841
8842    return camelized;
8843  },
8844
8845  capitalize: function() {
8846    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
8847  },
8848
8849  underscore: function() {
8850    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
8851  },
8852
8853  dasherize: function() {
8854    return this.gsub(/_/,'-');
8855  },
8856
8857  inspect: function(useDoubleQuotes) {
8858    var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
8859      var character = String.specialChar[match[0]];
8860      return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
8861    });
8862    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
8863    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
8864  },
8865
8866  toJSON: function() {
8867    return this.inspect(true);
8868  },
8869
8870  unfilterJSON: function(filter) {
8871    return this.sub(filter || Prototype.JSONFilter, '#{1}');
8872  },
8873
8874  isJSON: function() {
8875    var str = this;
8876    if (str.blank()) return false;
8877    str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '');
8878    return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
8879  },
8880
8881  evalJSON: function(sanitize) {
8882    var json = this.unfilterJSON();
8883    try {
8884      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
8885    } catch (e) { }
8886    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
8887  },
8888
8889  include: function(pattern) {
8890    return this.indexOf(pattern) > -1;
8891  },
8892
8893  startsWith: function(pattern) {
8894    return this.indexOf(pattern) === 0;
8895  },
8896
8897  endsWith: function(pattern) {
8898    var d = this.length - pattern.length;
8899    return d >= 0 && this.lastIndexOf(pattern) === d;
8900  },
8901
8902  empty: function() {
8903    return this == '';
8904  },
8905
8906  blank: function() {
8907    return /^\s*$/.test(this);
8908  },
8909
8910  interpolate: function(object, pattern) {
8911    return new Template(this, pattern).evaluate(object);
8912  }
8913});
8914
8915if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
8916  escapeHTML: function() {
8917    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
8918  },
8919  unescapeHTML: function() {
8920    return this.stripTags().replace(/&amp;/g,'&').replace(/&lt;/g,'<').replace(/&gt;/g,'>');
8921  }
8922});
8923
8924String.prototype.gsub.prepareReplacement = function(replacement) {
8925  if (Object.isFunction(replacement)) return replacement;
8926  var template = new Template(replacement);
8927  return function(match) { return template.evaluate(match) };
8928};
8929
8930String.prototype.parseQuery = String.prototype.toQueryParams;
8931
8932Object.extend(String.prototype.escapeHTML, {
8933  div:  document.createElement('div'),
8934  text: document.createTextNode('')
8935});
8936
8937String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
8938
8939var Template = Class.create({
8940  initialize: function(template, pattern) {
8941    this.template = template.toString();
8942    this.pattern = pattern || Template.Pattern;
8943  },
8944
8945  evaluate: function(object) {
8946    if (Object.isFunction(object.toTemplateReplacements))
8947      object = object.toTemplateReplacements();
8948
8949    return this.template.gsub(this.pattern, function(match) {
8950      if (object == null) return '';
8951
8952      var before = match[1] || '';
8953      if (before == '\\') return match[2];
8954
8955      var ctx = object, expr = match[3];
8956      var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
8957      match = pattern.exec(expr);
8958      if (match == null) return before;
8959
8960      while (match != null) {
8961        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
8962        ctx = ctx[comp];
8963        if (null == ctx || '' == match[3]) break;
8964        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
8965        match = pattern.exec(expr);
8966      }
8967
8968      return before + String.interpret(ctx);
8969    });
8970  }
8971});
8972Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
8973
8974var $break = { };
8975
8976var Enumerable = {
8977  each: function(iterator, context) {
8978    var index = 0;
8979    try {
8980      this._each(function(value) {
8981        iterator.call(context, value, index++);
8982      });
8983    } catch (e) {
8984      if (e != $break) throw e;
8985    }
8986    return this;
8987  },
8988
8989  eachSlice: function(number, iterator, context) {
8990    var index = -number, slices = [], array = this.toArray();
8991    if (number < 1) return array;
8992    while ((index += number) < array.length)
8993      slices.push(array.slice(index, index+number));
8994    return slices.collect(iterator, context);
8995  },
8996
8997  all: function(iterator, context) {
8998    iterator = iterator || Prototype.K;
8999    var result = true;
9000    this.each(function(value, index) {
9001      result = result && !!iterator.call(context, value, index);
9002      if (!result) throw $break;
9003    });
9004    return result;
9005  },
9006
9007  any: function(iterator, context) {
9008    iterator = iterator || Prototype.K;
9009    var result = false;
9010    this.each(function(value, index) {
9011      if (result = !!iterator.call(context, value, index))
9012        throw $break;
9013    });
9014    return result;
9015  },
9016
9017  collect: function(iterator, context) {
9018    iterator = iterator || Prototype.K;
9019    var results = [];
9020    this.each(function(value, index) {
9021      results.push(iterator.call(context, value, index));
9022    });
9023    return results;
9024  },
9025
9026  detect: function(iterator, context) {
9027    var result;
9028    this.each(function(value, index) {
9029      if (iterator.call(context, value, index)) {
9030        result = value;
9031        throw $break;
9032      }
9033    });
9034    return result;
9035  },
9036
9037  findAll: function(iterator, context) {
9038    var results = [];
9039    this.each(function(value, index) {
9040      if (iterator.call(context, value, index))
9041        results.push(value);
9042    });
9043    return results;
9044  },
9045
9046  grep: function(filter, iterator, context) {
9047    iterator = iterator || Prototype.K;
9048    var results = [];
9049
9050    if (Object.isString(filter))
9051      filter = new RegExp(filter);
9052
9053    this.each(function(value, index) {
9054      if (filter.match(value))
9055        results.push(iterator.call(context, value, index));
9056    });
9057    return results;
9058  },
9059
9060  include: function(object) {
9061    if (Object.isFunction(this.indexOf))
9062      if (this.indexOf(object) != -1) return true;
9063
9064    var found = false;
9065    this.each(function(value) {
9066      if (value == object) {
9067        found = true;
9068        throw $break;
9069      }
9070    });
9071    return found;
9072  },
9073
9074  inGroupsOf: function(number, fillWith) {
9075    fillWith = Object.isUndefined(fillWith) ? null : fillWith;
9076    return this.eachSlice(number, function(slice) {
9077      while(slice.length < number) slice.push(fillWith);
9078      return slice;
9079    });
9080  },
9081
9082  inject: function(memo, iterator, context) {
9083    this.each(function(value, index) {
9084      memo = iterator.call(context, memo, value, index);
9085    });
9086    return memo;
9087  },
9088
9089  invoke: function(method) {
9090    var args = $A(arguments).slice(1);
9091    return this.map(function(value) {
9092      return value[method].apply(value, args);
9093    });
9094  },
9095
9096  max: function(iterator, context) {
9097    iterator = iterator || Prototype.K;
9098    var result;
9099    this.each(function(value, index) {
9100      value = iterator.call(context, value, index);
9101      if (result == null || value >= result)
9102        result = value;
9103    });
9104    return result;
9105  },
9106
9107  min: function(iterator, context) {
9108    iterator = iterator || Prototype.K;
9109    var result;
9110    this.each(function(value, index) {
9111      value = iterator.call(context, value, index);
9112      if (result == null || value < result)
9113        result = value;
9114    });
9115    return result;
9116  },
9117
9118  partition: function(iterator, context) {
9119    iterator = iterator || Prototype.K;
9120    var trues = [], falses = [];
9121    this.each(function(value, index) {
9122      (iterator.call(context, value, index) ?
9123        trues : falses).push(value);
9124    });
9125    return [trues, falses];
9126  },
9127
9128  pluck: function(property) {
9129    var results = [];
9130    this.each(function(value) {
9131      results.push(value[property]);
9132    });
9133    return results;
9134  },
9135
9136  reject: function(iterator, context) {
9137    var results = [];
9138    this.each(function(value, index) {
9139      if (!iterator.call(context, value, index))
9140        results.push(value);
9141    });
9142    return results;
9143  },
9144
9145  sortBy: function(iterator, context) {
9146    return this.map(function(value, index) {
9147      return {
9148        value: value,
9149        criteria: iterator.call(context, value, index)
9150      };
9151    }).sort(function(left, right) {
9152      var a = left.criteria, b = right.criteria;
9153      return a < b ? -1 : a > b ? 1 : 0;
9154    }).pluck('value');
9155  },
9156
9157  toArray: function() {
9158    return this.map();
9159  },
9160
9161  zip: function() {
9162    var iterator = Prototype.K, args = $A(arguments);
9163    if (Object.isFunction(args.last()))
9164      iterator = args.pop();
9165
9166    var collections = [this].concat(args).map($A);
9167    return this.map(function(value, index) {
9168      return iterator(collections.pluck(index));
9169    });
9170  },
9171
9172  size: function() {
9173    return this.toArray().length;
9174  },
9175
9176  inspect: function() {
9177    return '#<Enumerable:' + this.toArray().inspect() + '>';
9178  }
9179};
9180
9181Object.extend(Enumerable, {
9182  map:     Enumerable.collect,
9183  find:    Enumerable.detect,
9184  select:  Enumerable.findAll,
9185  filter:  Enumerable.findAll,
9186  member:  Enumerable.include,
9187  entries: Enumerable.toArray,
9188  every:   Enumerable.all,
9189  some:    Enumerable.any
9190});
9191function $A(iterable) {
9192  if (!iterable) return [];
9193  if (iterable.toArray) return iterable.toArray();
9194  var length = iterable.length || 0, results = new Array(length);
9195  while (length--) results[length] = iterable[length];
9196  return results;
9197}
9198
9199if (Prototype.Browser.WebKit) {
9200  $A = function(iterable) {
9201    if (!iterable) return [];
9202    // In Safari, only use the `toArray` method if it's not a NodeList.
9203    // A NodeList is a function, has an function `item` property, and a numeric
9204    // `length` property. Adapted from Google Doctype.
9205    if (!(typeof iterable === 'function' && typeof iterable.length ===
9206        'number' && typeof iterable.item === 'function') && iterable.toArray)
9207      return iterable.toArray();
9208    var length = iterable.length || 0, results = new Array(length);
9209    while (length--) results[length] = iterable[length];
9210    return results;
9211  };
9212}
9213
9214Array.from = $A;
9215
9216Object.extend(Array.prototype, Enumerable);
9217
9218if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
9219
9220Object.extend(Array.prototype, {
9221  _each: function(iterator) {
9222    for (var i = 0, length = this.length; i < length; i++)
9223      iterator(this[i]);
9224  },
9225
9226  clear: function() {
9227    this.length = 0;
9228    return this;
9229  },
9230
9231  first: function() {
9232    return this[0];
9233  },
9234
9235  last: function() {
9236    return this[this.length - 1];
9237  },
9238
9239  compact: function() {
9240    return this.select(function(value) {
9241      return value != null;
9242    });
9243  },
9244
9245  flatten: function() {
9246    return this.inject([], function(array, value) {
9247      return array.concat(Object.isArray(value) ?
9248        value.flatten() : [value]);
9249    });
9250  },
9251
9252  without: function() {
9253    var values = $A(arguments);
9254    return this.select(function(value) {
9255      return !values.include(value);
9256    });
9257  },
9258
9259  reverse: function(inline) {
9260    return (inline !== false ? this : this.toArray())._reverse();
9261  },
9262
9263  reduce: function() {
9264    return this.length > 1 ? this : this[0];
9265  },
9266
9267  uniq: function(sorted) {
9268    return this.inject([], function(array, value, index) {
9269      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
9270        array.push(value);
9271      return array;
9272    });
9273  },
9274
9275  intersect: function(array) {
9276    return this.uniq().findAll(function(item) {
9277      return array.detect(function(value) { return item === value });
9278    });
9279  },
9280
9281  clone: function() {
9282    return [].concat(this);
9283  },
9284
9285  size: function() {
9286    return this.length;
9287  },
9288
9289  inspect: function() {
9290    return '[' + this.map(Object.inspect).join(', ') + ']';
9291  },
9292
9293  toJSON: function() {
9294    var results = [];
9295    this.each(function(object) {
9296      var value = Object.toJSON(object);
9297      if (!Object.isUndefined(value)) results.push(value);
9298    });
9299    return '[' + results.join(', ') + ']';
9300  }
9301});
9302
9303// use native browser JS 1.6 implementation if available
9304if (Object.isFunction(Array.prototype.forEach))
9305  Array.prototype._each = Array.prototype.forEach;
9306
9307if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
9308  i || (i = 0);
9309  var length = this.length;
9310  if (i < 0) i = length + i;
9311  for (; i < length; i++)
9312    if (this[i] === item) return i;
9313  return -1;
9314};
9315
9316if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
9317  i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1;
9318  var n = this.slice(0, i).reverse().indexOf(item);
9319  return (n < 0) ? n : i - n - 1;
9320};
9321
9322Array.prototype.toArray = Array.prototype.clone;
9323
9324function $w(string) {
9325  if (!Object.isString(string)) return [];
9326  string = string.strip();
9327  return string ? string.split(/\s+/) : [];
9328}
9329
9330if (Prototype.Browser.Opera){
9331  Array.prototype.concat = function() {
9332    var array = [];
9333    for (var i = 0, length = this.length; i < length; i++) array.push(this[i]);
9334    for (var i = 0, length = arguments.length; i < length; i++) {
9335      if (Object.isArray(arguments[i])) {
9336        for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
9337          array.push(arguments[i][j]);
9338      } else {
9339        array.push(arguments[i]);
9340      }
9341    }
9342    return array;
9343  };
9344}
9345Object.extend(Number.prototype, {
9346  toColorPart: function() {
9347    return this.toPaddedString(2, 16);
9348  },
9349
9350  succ: function() {
9351    return this + 1;
9352  },
9353
9354  times: function(iterator, context) {
9355    $R(0, this, true).each(iterator, context);
9356    return this;
9357  },
9358
9359  toPaddedString: function(length, radix) {
9360    var string = this.toString(radix || 10);
9361    return '0'.times(length - string.length) + string;
9362  },
9363
9364  toJSON: function() {
9365    return isFinite(this) ? this.toString() : 'null';
9366  }
9367});
9368
9369$w('abs round ceil floor').each(function(method){
9370  Number.prototype[method] = Math[method].methodize();
9371});
9372function $H(object) {
9373  return new Hash(object);
9374};
9375
9376var Hash = Class.create(Enumerable, (function() {
9377
9378  function toQueryPair(key, value) {
9379    if (Object.isUndefined(value)) return key;
9380    return key + '=' + encodeURIComponent(String.interpret(value));
9381  }
9382
9383  return {
9384    initialize: function(object) {
9385      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
9386    },
9387
9388    _each: function(iterator) {
9389      for (var key in this._object) {
9390        var value = this._object[key], pair = [key, value];
9391        pair.key = key;
9392        pair.value = value;
9393        iterator(pair);
9394      }
9395    },
9396
9397    set: function(key, value) {
9398      return this._object[key] = value;
9399    },
9400
9401    get: function(key) {
9402      // simulating poorly supported hasOwnProperty
9403      if (this._object[key] !== Object.prototype[key])
9404        return this._object[key];
9405    },
9406
9407    unset: function(key) {
9408      var value = this._object[key];
9409      delete this._object[key];
9410      return value;
9411    },
9412
9413    toObject: function() {
9414      return Object.clone(this._object);
9415    },
9416
9417    keys: function() {
9418      return this.pluck('key');
9419    },
9420
9421    values: function() {
9422      return this.pluck('value');
9423    },
9424
9425    index: function(value) {
9426      var match = this.detect(function(pair) {
9427        return pair.value === value;
9428      });
9429      return match && match.key;
9430    },
9431
9432    merge: function(object) {
9433      return this.clone().update(object);
9434    },
9435
9436    update: function(object) {
9437      return new Hash(object).inject(this, function(result, pair) {
9438        result.set(pair.key, pair.value);
9439        return result;
9440      });
9441    },
9442
9443    toQueryString: function() {
9444      return this.inject([], function(results, pair) {
9445        var key = encodeURIComponent(pair.key), values = pair.value;
9446
9447        if (values && typeof values == 'object') {
9448          if (Object.isArray(values))
9449            return results.concat(values.map(toQueryPair.curry(key)));
9450        } else results.push(toQueryPair(key, values));
9451        return results;
9452      }).join('&');
9453    },
9454
9455    inspect: function() {
9456      return '#<Hash:{' + this.map(function(pair) {
9457        return pair.map(Object.inspect).join(': ');
9458      }).join(', ') + '}>';
9459    },
9460
9461    toJSON: function() {
9462      return Object.toJSON(this.toObject());
9463    },
9464
9465    clone: function() {
9466      return new Hash(this);
9467    }
9468  }
9469})());
9470
9471Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
9472Hash.from = $H;
9473var ObjectRange = Class.create(Enumerable, {
9474  initialize: function(start, end, exclusive) {
9475    this.start = start;
9476    this.end = end;
9477    this.exclusive = exclusive;
9478  },
9479
9480  _each: function(iterator) {
9481    var value = this.start;
9482    while (this.include(value)) {
9483      iterator(value);
9484      value = value.succ();
9485    }
9486  },
9487
9488  include: function(value) {
9489    if (value < this.start)
9490      return false;
9491    if (this.exclusive)
9492      return value < this.end;
9493    return value <= this.end;
9494  }
9495});
9496
9497var $R = function(start, end, exclusive) {
9498  return new ObjectRange(start, end, exclusive);
9499};
9500
9501var Ajax = {
9502  getTransport: function() {
9503    return Try.these(
9504      function() {return new XMLHttpRequest()},
9505      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
9506      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
9507    ) || false;
9508  },
9509
9510  activeRequestCount: 0
9511};
9512
9513Ajax.Responders = {
9514  responders: [],
9515
9516  _each: function(iterator) {
9517    this.responders._each(iterator);
9518  },
9519
9520  register: function(responder) {
9521    if (!this.include(responder))
9522      this.responders.push(responder);
9523  },
9524
9525  unregister: function(responder) {
9526    this.responders = this.responders.without(responder);
9527  },
9528
9529  dispatch: function(callback, request, transport, json) {
9530    this.each(function(responder) {
9531      if (Object.isFunction(responder[callback])) {
9532        try {
9533          responder[callback].apply(responder, [request, transport, json]);
9534        } catch (e) { }
9535      }
9536    });
9537  }
9538};
9539
9540Object.extend(Ajax.Responders, Enumerable);
9541
9542Ajax.Responders.register({
9543  onCreate:   function() { Ajax.activeRequestCount++ },
9544  onComplete: function() { Ajax.activeRequestCount-- }
9545});
9546
9547Ajax.Base = Class.create({
9548  initialize: function(options) {
9549    this.options = {
9550      method:       'post',
9551      asynchronous: true,
9552      contentType:  'application/x-www-form-urlencoded',
9553      encoding:     'UTF-8',
9554      parameters:   '',
9555      evalJSON:     true,
9556      evalJS:       true
9557    };
9558    Object.extend(this.options, options || { });
9559
9560    this.options.method = this.options.method.toLowerCase();
9561
9562    if (Object.isString(this.options.parameters))
9563      this.options.parameters = this.options.parameters.toQueryParams();
9564    else if (Object.isHash(this.options.parameters))
9565      this.options.parameters = this.options.parameters.toObject();
9566  }
9567});
9568
9569Ajax.Request = Class.create(Ajax.Base, {
9570  _complete: false,
9571
9572  initialize: function($super, url, options) {
9573    $super(options);
9574    this.transport = Ajax.getTransport();
9575    this.request(url);
9576  },
9577
9578  request: function(url) {
9579    this.url = url;
9580    this.method = this.options.method;
9581    var params = Object.clone(this.options.parameters);
9582
9583    if (!['get', 'post'].include(this.method)) {
9584      // simulate other verbs over post
9585      params['_method'] = this.method;
9586      this.method = 'post';
9587    }
9588
9589    this.parameters = params;
9590
9591    if (params = Object.toQueryString(params)) {
9592      // when GET, append parameters to URL
9593      if (this.method == 'get')
9594        this.url += (this.url.include('?') ? '&' : '?') + params;
9595      else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
9596        params += '&_=';
9597    }
9598
9599    try {
9600      var response = new Ajax.Response(this);
9601      if (this.options.onCreate) this.options.onCreate(response);
9602      Ajax.Responders.dispatch('onCreate', this, response);
9603
9604      this.transport.open(this.method.toUpperCase(), this.url,
9605        this.options.asynchronous);
9606
9607      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
9608
9609      this.transport.onreadystatechange = this.onStateChange.bind(this);
9610      this.setRequestHeaders();
9611
9612      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
9613      this.transport.send(this.body);
9614
9615      /* Force Firefox to handle ready state 4 for synchronous requests */
9616      if (!this.options.asynchronous && this.transport.overrideMimeType)
9617        this.onStateChange();
9618
9619    }
9620    catch (e) {
9621      this.dispatchException(e);
9622    }
9623  },
9624
9625  onStateChange: function() {
9626    var readyState = this.transport.readyState;
9627    if (readyState > 1 && !((readyState == 4) && this._complete))
9628      this.respondToReadyState(this.transport.readyState);
9629  },
9630
9631  setRequestHeaders: function() {
9632    var headers = {
9633      'X-Requested-With': 'XMLHttpRequest',
9634      'X-Prototype-Version': Prototype.Version,
9635      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
9636    };
9637
9638    if (this.method == 'post') {
9639      headers['Content-type'] = this.options.contentType +
9640        (this.options.encoding ? '; charset=' + this.options.encoding : '');
9641
9642      /* Force "Connection: close" for older Mozilla browsers to work
9643       * around a bug where XMLHttpRequest sends an incorrect
9644       * Content-length header. See Mozilla Bugzilla #246651.
9645       */
9646      if (this.transport.overrideMimeType &&
9647          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
9648            headers['Connection'] = 'close';
9649    }
9650
9651    // user-defined headers
9652    if (typeof this.options.requestHeaders == 'object') {
9653      var extras = this.options.requestHeaders;
9654
9655      if (Object.isFunction(extras.push))
9656        for (var i = 0, length = extras.length; i < length; i += 2)
9657          headers[extras[i]] = extras[i+1];
9658      else
9659        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
9660    }
9661
9662    for (var name in headers)
9663      this.transport.setRequestHeader(name, headers[name]);
9664  },
9665
9666  success: function() {
9667    var status = this.getStatus();
9668    return !status || (status >= 200 && status < 300);
9669  },
9670
9671  getStatus: function() {
9672    try {
9673      return this.transport.status || 0;
9674    } catch (e) { return 0 }
9675  },
9676
9677  respondToReadyState: function(readyState) {
9678    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
9679
9680    if (state == 'Complete') {
9681      try {
9682        this._complete = true;
9683        (this.options['on' + response.status]
9684         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
9685         || Prototype.emptyFunction)(response, response.headerJSON);
9686      } catch (e) {
9687        this.dispatchException(e);
9688      }
9689
9690      var contentType = response.getHeader('Content-type');
9691      if (this.options.evalJS == 'force'
9692          || (this.options.evalJS && this.isSameOrigin() && contentType
9693          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
9694        this.evalResponse();
9695    }
9696
9697    try {
9698      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
9699      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
9700    } catch (e) {
9701      this.dispatchException(e);
9702    }
9703
9704    if (state == 'Complete') {
9705      // avoid memory leak in MSIE: clean up
9706      this.transport.onreadystatechange = Prototype.emptyFunction;
9707    }
9708  },
9709
9710  isSameOrigin: function() {
9711    var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
9712    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
9713      protocol: location.protocol,
9714      domain: document.domain,
9715      port: location.port ? ':' + location.port : ''
9716    }));
9717  },
9718
9719  getHeader: function(name) {
9720    try {
9721      return this.transport.getResponseHeader(name) || null;
9722    } catch (e) { return null }
9723  },
9724
9725  evalResponse: function() {
9726    try {
9727      return eval((this.transport.responseText || '').unfilterJSON());
9728    } catch (e) {
9729      this.dispatchException(e);
9730    }
9731  },
9732
9733  dispatchException: function(exception) {
9734    (this.options.onException || Prototype.emptyFunction)(this, exception);
9735    Ajax.Responders.dispatch('onException', this, exception);
9736  }
9737});
9738
9739Ajax.Request.Events =
9740  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
9741
9742Ajax.Response = Class.create({
9743  initialize: function(request){
9744    this.request = request;
9745    var transport  = this.transport  = request.transport,
9746        readyState = this.readyState = transport.readyState;
9747
9748    if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
9749      this.status       = this.getStatus();
9750      this.statusText   = this.getStatusText();
9751      this.responseText = String.interpret(transport.responseText);
9752      this.headerJSON   = this._getHeaderJSON();
9753    }
9754
9755    if(readyState == 4) {
9756      var xml = transport.responseXML;
9757      this.responseXML  = Object.isUndefined(xml) ? null : xml;
9758      this.responseJSON = this._getResponseJSON();
9759    }
9760  },
9761
9762  status:      0,
9763  statusText: '',
9764
9765  getStatus: Ajax.Request.prototype.getStatus,
9766
9767  getStatusText: function() {
9768    try {
9769      return this.transport.statusText || '';
9770    } catch (e) { return '' }
9771  },
9772
9773  getHeader: Ajax.Request.prototype.getHeader,
9774
9775  getAllHeaders: function() {
9776    try {
9777      return this.getAllResponseHeaders();
9778    } catch (e) { return null }
9779  },
9780
9781  getResponseHeader: function(name) {
9782    return this.transport.getResponseHeader(name);
9783  },
9784
9785  getAllResponseHeaders: function() {
9786    return this.transport.getAllResponseHeaders();
9787  },
9788
9789  _getHeaderJSON: function() {
9790    var json = this.getHeader('X-JSON');
9791    if (!json) return null;
9792    json = decodeURIComponent(escape(json));
9793    try {
9794      return json.evalJSON(this.request.options.sanitizeJSON ||
9795        !this.request.isSameOrigin());
9796    } catch (e) {
9797      this.request.dispatchException(e);
9798    }
9799  },
9800
9801  _getResponseJSON: function() {
9802    var options = this.request.options;
9803    if (!options.evalJSON || (options.evalJSON != 'force' &&
9804      !(this.getHeader('Content-type') || '').include('application/json')) ||
9805        this.responseText.blank())
9806          return null;
9807    try {
9808      return this.responseText.evalJSON(options.sanitizeJSON ||
9809        !this.request.isSameOrigin());
9810    } catch (e) {
9811      this.request.dispatchException(e);
9812    }
9813  }
9814});
9815
9816Ajax.Updater = Class.create(Ajax.Request, {
9817  initialize: function($super, container, url, options) {
9818    this.container = {
9819      success: (container.success || container),
9820      failure: (container.failure || (container.success ? null : container))
9821    };
9822
9823    options = Object.clone(options);
9824    var onComplete = options.onComplete;
9825    options.onComplete = (function(response, json) {
9826      this.updateContent(response.responseText);
9827      if (Object.isFunction(onComplete)) onComplete(response, json);
9828    }).bind(this);
9829
9830    $super(url, options);
9831  },
9832
9833  updateContent: function(responseText) {
9834    var receiver = this.container[this.success() ? 'success' : 'failure'],
9835        options = this.options;
9836
9837    if (!options.evalScripts) responseText = responseText.stripScripts();
9838
9839    if (receiver = $(receiver)) {
9840      if (options.insertion) {
9841        if (Object.isString(options.insertion)) {
9842          var insertion = { }; insertion[options.insertion] = responseText;
9843          receiver.insert(insertion);
9844        }
9845        else options.insertion(receiver, responseText);
9846      }
9847      else receiver.update(responseText);
9848    }
9849  }
9850});
9851
9852Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
9853  initialize: function($super, container, url, options) {
9854    $super(options);
9855    this.onComplete = this.options.onComplete;
9856
9857    this.frequency = (this.options.frequency || 2);
9858    this.decay = (this.options.decay || 1);
9859
9860    this.updater = { };
9861    this.container = container;
9862    this.url = url;
9863
9864    this.start();
9865  },
9866
9867  start: function() {
9868    this.options.onComplete = this.updateComplete.bind(this);
9869    this.onTimerEvent();
9870  },
9871
9872  stop: function() {
9873    this.updater.options.onComplete = undefined;
9874    clearTimeout(this.timer);
9875    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
9876  },
9877
9878  updateComplete: function(response) {
9879    if (this.options.decay) {
9880      this.decay = (response.responseText == this.lastText ?
9881        this.decay * this.options.decay : 1);
9882
9883      this.lastText = response.responseText;
9884    }
9885    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
9886  },
9887
9888  onTimerEvent: function() {
9889    this.updater = new Ajax.Updater(this.container, this.url, this.options);
9890  }
9891});
9892function $(element) {
9893  if (arguments.length > 1) {
9894    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
9895      elements.push($(arguments[i]));
9896    return elements;
9897  }
9898  if (Object.isString(element))
9899    element = document.getElementById(element);
9900  return Element.extend(element);
9901}
9902
9903if (Prototype.BrowserFeatures.XPath) {
9904  document._getElementsByXPath = function(expression, parentElement) {
9905    var results = [];
9906    var query = document.evaluate(expression, $(parentElement) || document,
9907      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
9908    for (var i = 0, length = query.snapshotLength; i < length; i++)
9909      results.push(Element.extend(query.snapshotItem(i)));
9910    return results;
9911  };
9912}
9913
9914/*--------------------------------------------------------------------------*/
9915
9916if (!window.Node) var Node = { };
9917
9918if (!Node.ELEMENT_NODE) {
9919  // DOM level 2 ECMAScript Language Binding
9920  Object.extend(Node, {
9921    ELEMENT_NODE: 1,
9922    ATTRIBUTE_NODE: 2,
9923    TEXT_NODE: 3,
9924    CDATA_SECTION_NODE: 4,
9925    ENTITY_REFERENCE_NODE: 5,
9926    ENTITY_NODE: 6,
9927    PROCESSING_INSTRUCTION_NODE: 7,
9928    COMMENT_NODE: 8,
9929    DOCUMENT_NODE: 9,
9930    DOCUMENT_TYPE_NODE: 10,
9931    DOCUMENT_FRAGMENT_NODE: 11,
9932    NOTATION_NODE: 12
9933  });
9934}
9935
9936(function() {
9937  var element = this.Element;
9938  this.Element = function(tagName, attributes) {
9939    attributes = attributes || { };
9940    tagName = tagName.toLowerCase();
9941    var cache = Element.cache;
9942    if (Prototype.Browser.IE && attributes.name) {
9943      tagName = '<' + tagName + ' name="' + attributes.name + '">';
9944      delete attributes.name;
9945      return Element.writeAttribute(document.createElement(tagName), attributes);
9946    }
9947    if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
9948    return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
9949  };
9950  Object.extend(this.Element, element || { });
9951  if (element) this.Element.prototype = element.prototype;
9952}).call(window);
9953
9954Element.cache = { };
9955
9956Element.Methods = {
9957  visible: function(element) {
9958    return $(element).style.display != 'none';
9959  },
9960
9961  toggle: function(element) {
9962    element = $(element);
9963    Element[Element.visible(element) ? 'hide' : 'show'](element);
9964    return element;
9965  },
9966
9967  hide: function(element) {
9968    element = $(element);
9969    element.style.display = 'none';
9970    return element;
9971  },
9972
9973  show: function(element) {
9974    element = $(element);
9975    element.style.display = '';
9976    return element;
9977  },
9978
9979  remove: function(element) {
9980    element = $(element);
9981    element.parentNode.removeChild(element);
9982    return element;
9983  },
9984
9985  update: function(element, content) {
9986    element = $(element);
9987    if (content && content.toElement) content = content.toElement();
9988    if (Object.isElement(content)) return element.update().insert(content);
9989    content = Object.toHTML(content);
9990    element.innerHTML = content.stripScripts();
9991    content.evalScripts.bind(content).defer();
9992    return element;
9993  },
9994
9995  replace: function(element, content) {
9996    element = $(element);
9997    if (content && content.toElement) content = content.toElement();
9998    else if (!Object.isElement(content)) {
9999      content = Object.toHTML(content);
10000      var range = element.ownerDocument.createRange();
10001      range.selectNode(element);
10002      content.evalScripts.bind(content).defer();
10003      content = range.createContextualFragment(content.stripScripts());
10004    }
10005    element.parentNode.replaceChild(content, element);
10006    return element;
10007  },
10008
10009  insert: function(element, insertions) {
10010    element = $(element);
10011
10012    if (Object.isString(insertions) || Object.isNumber(insertions) ||
10013        Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
10014          insertions = {bottom:insertions};
10015
10016    var content, insert, tagName, childNodes;
10017
10018    for (var position in insertions) {
10019      content  = insertions[position];
10020      position = position.toLowerCase();
10021      insert = Element._insertionTranslations[position];
10022
10023      if (content && content.toElement) content = content.toElement();
10024      if (Object.isElement(content)) {
10025        insert(element, content);
10026        continue;
10027      }
10028
10029      content = Object.toHTML(content);
10030
10031      tagName = ((position == 'before' || position == 'after')
10032        ? element.parentNode : element).tagName.toUpperCase();
10033
10034      childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
10035
10036      if (position == 'top' || position == 'after') childNodes.reverse();
10037      childNodes.each(insert.curry(element));
10038
10039      content.evalScripts.bind(content).defer();
10040    }
10041
10042    return element;
10043  },
10044
10045  wrap: function(element, wrapper, attributes) {
10046    element = $(element);
10047    if (Object.isElement(wrapper))
10048      $(wrapper).writeAttribute(attributes || { });
10049    else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes);
10050    else wrapper = new Element('div', wrapper);
10051    if (element.parentNode)
10052      element.parentNode.replaceChild(wrapper, element);
10053    wrapper.appendChild(element);
10054    return wrapper;
10055  },
10056
10057  inspect: function(element) {
10058    element = $(element);
10059    var result = '<' + element.tagName.toLowerCase();
10060    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
10061      var property = pair.first(), attribute = pair.last();
10062      var value = (element[property] || '').toString();
10063      if (value) result += ' ' + attribute + '=' + value.inspect(true);
10064    });
10065    return result + '>';
10066  },
10067
10068  recursivelyCollect: function(element, property) {
10069    element = $(element);
10070    var elements = [];
10071    while (element = element[property])
10072      if (element.nodeType == 1)
10073        elements.push(Element.extend(element));
10074    return elements;
10075  },
10076
10077  ancestors: function(element) {
10078    return $(element).recursivelyCollect('parentNode');
10079  },
10080
10081  descendants: function(element) {
10082    return $(element).select("*");
10083  },
10084
10085  firstDescendant: function(element) {
10086    element = $(element).firstChild;
10087    while (element && element.nodeType != 1) element = element.nextSibling;
10088    return $(element);
10089  },
10090
10091  immediateDescendants: function(element) {
10092    if (!(element = $(element).firstChild)) return [];
10093    while (element && element.nodeType != 1) element = element.nextSibling;
10094    if (element) return [element].concat($(element).nextSiblings());
10095    return [];
10096  },
10097
10098  previousSiblings: function(element) {
10099    return $(element).recursivelyCollect('previousSibling');
10100  },
10101
10102  nextSiblings: function(element) {
10103    return $(element).recursivelyCollect('nextSibling');
10104  },
10105
10106  siblings: function(element) {
10107    element = $(element);
10108    return element.previousSiblings().reverse().concat(element.nextSiblings());
10109  },
10110
10111  match: function(element, selector) {
10112    if (Object.isString(selector))
10113      selector = new Selector(selector);
10114    return selector.match($(element));
10115  },
10116
10117  up: function(element, expression, index) {
10118    element = $(element);
10119    if (arguments.length == 1) return $(element.parentNode);
10120    var ancestors = element.ancestors();
10121    return Object.isNumber(expression) ? ancestors[expression] :
10122      Selector.findElement(ancestors, expression, index);
10123  },
10124
10125  down: function(element, expression, index) {
10126    element = $(element);
10127    if (arguments.length == 1) return element.firstDescendant();
10128    return Object.isNumber(expression) ? element.descendants()[expression] :
10129      Element.select(element, expression)[index || 0];
10130  },
10131
10132  previous: function(element, expression, index) {
10133    element = $(element);
10134    if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
10135    var previousSiblings = element.previousSiblings();
10136    return Object.isNumber(expression) ? previousSiblings[expression] :
10137      Selector.findElement(previousSiblings, expression, index);
10138  },
10139
10140  next: function(element, expression, index) {
10141    element = $(element);
10142    if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
10143    var nextSiblings = element.nextSiblings();
10144    return Object.isNumber(expression) ? nextSiblings[expression] :
10145      Selector.findElement(nextSiblings, expression, index);
10146  },
10147
10148  select: function() {
10149    var args = $A(arguments), element = $(args.shift());
10150    return Selector.findChildElements(element, args);
10151  },
10152
10153  adjacent: function() {
10154    var args = $A(arguments), element = $(args.shift());
10155    return Selector.findChildElements(element.parentNode, args).without(element);
10156  },
10157
10158  identify: function(element) {
10159    element = $(element);
10160    var id = element.readAttribute('id'), self = arguments.callee;
10161    if (id) return id;
10162    do { id = 'anonymous_element_' + self.counter++ } while ($(id));
10163    element.writeAttribute('id', id);
10164    return id;
10165  },
10166
10167  readAttribute: function(element, name) {
10168    element = $(element);
10169    if (Prototype.Browser.IE) {
10170      var t = Element._attributeTranslations.read;
10171      if (t.values[name]) return t.values[name](element, name);
10172      if (t.names[name]) name = t.names[name];
10173      if (name.include(':')) {
10174        return (!element.attributes || !element.attributes[name]) ? null :
10175         element.attributes[name].value;
10176      }
10177    }
10178    return element.getAttribute(name);
10179  },
10180
10181  writeAttribute: function(element, name, value) {
10182    element = $(element);
10183    var attributes = { }, t = Element._attributeTranslations.write;
10184
10185    if (typeof name == 'object') attributes = name;
10186    else attributes[name] = Object.isUndefined(value) ? true : value;
10187
10188    for (var attr in attributes) {
10189      name = t.names[attr] || attr;
10190      value = attributes[attr];
10191      if (t.values[attr]) name = t.values[attr](element, value);
10192      if (value === false || value === null)
10193        element.removeAttribute(name);
10194      else if (value === true)
10195        element.setAttribute(name, name);
10196      else element.setAttribute(name, value);
10197    }
10198    return element;
10199  },
10200
10201  getHeight: function(element) {
10202    return $(element).getDimensions().height;
10203  },
10204
10205  getWidth: function(element) {
10206    return $(element).getDimensions().width;
10207  },
10208
10209  classNames: function(element) {
10210    return new Element.ClassNames(element);
10211  },
10212
10213  hasClassName: function(element, className) {
10214    if (!(element = $(element))) return;
10215    var elementClassName = element.className;
10216    return (elementClassName.length > 0 && (elementClassName == className ||
10217      new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName)));
10218  },
10219
10220  addClassName: function(element, className) {
10221    if (!(element = $(element))) return;
10222    if (!element.hasClassName(className))
10223      element.className += (element.className ? ' ' : '') + className;
10224    return element;
10225  },
10226
10227  removeClassName: function(element, className) {
10228    if (!(element = $(element))) return;
10229    element.className = element.className.replace(
10230      new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip();
10231    return element;
10232  },
10233
10234  toggleClassName: function(element, className) {
10235    if (!(element = $(element))) return;
10236    return element[element.hasClassName(className) ?
10237      'removeClassName' : 'addClassName'](className);
10238  },
10239
10240  // removes whitespace-only text node children
10241  cleanWhitespace: function(element) {
10242    element = $(element);
10243    var node = element.firstChild;
10244    while (node) {
10245      var nextNode = node.nextSibling;
10246      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
10247        element.removeChild(node);
10248      node = nextNode;
10249    }
10250    return element;
10251  },
10252
10253  empty: function(element) {
10254    return $(element).innerHTML.blank();
10255  },
10256
10257  descendantOf: function(element, ancestor) {
10258    element = $(element), ancestor = $(ancestor);
10259
10260    if (element.compareDocumentPosition)
10261      return (element.compareDocumentPosition(ancestor) & 8) === 8;
10262
10263    if (ancestor.contains)
10264      return ancestor.contains(element) && ancestor !== element;
10265
10266    while (element = element.parentNode)
10267      if (element == ancestor) return true;
10268
10269    return false;
10270  },
10271
10272  scrollTo: function(element) {
10273    element = $(element);
10274    var pos = element.cumulativeOffset();
10275    window.scrollTo(pos[0], pos[1]);
10276    return element;
10277  },
10278
10279  getStyle: function(element, style) {
10280    element = $(element);
10281    style = style == 'float' ? 'cssFloat' : style.camelize();
10282    var value = element.style[style];
10283    if (!value || value == 'auto') {
10284      var css = document.defaultView.getComputedStyle(element, null);
10285      value = css ? css[style] : null;
10286    }
10287    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
10288    return value == 'auto' ? null : value;
10289  },
10290
10291  getOpacity: function(element) {
10292    return $(element).getStyle('opacity');
10293  },
10294
10295  setStyle: function(element, styles) {
10296    element = $(element);
10297    var elementStyle = element.style, match;
10298    if (Object.isString(styles)) {
10299      element.style.cssText += ';' + styles;
10300      return styles.include('opacity') ?
10301        element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element;
10302    }
10303    for (var property in styles)
10304      if (property == 'opacity') element.setOpacity(styles[property]);
10305      else
10306        elementStyle[(property == 'float' || property == 'cssFloat') ?
10307          (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') :
10308            property] = styles[property];
10309
10310    return element;
10311  },
10312
10313  setOpacity: function(element, value) {
10314    element = $(element);
10315    element.style.opacity = (value == 1 || value === '') ? '' :
10316      (value < 0.00001) ? 0 : value;
10317    return element;
10318  },
10319
10320  getDimensions: function(element) {
10321    element = $(element);
10322    var display = element.getStyle('display');
10323    if (display != 'none' && display != null) // Safari bug
10324      return {width: element.offsetWidth, height: element.offsetHeight};
10325
10326    // All *Width and *Height properties give 0 on elements with display none,
10327    // so enable the element temporarily
10328    var els = element.style;
10329    var originalVisibility = els.visibility;
10330    var originalPosition = els.position;
10331    var originalDisplay = els.display;
10332    els.visibility = 'hidden';
10333    els.position = 'absolute';
10334    els.display = 'block';
10335    var originalWidth = element.clientWidth;
10336    var originalHeight = element.clientHeight;
10337    els.display = originalDisplay;
10338    els.position = originalPosition;
10339    els.visibility = originalVisibility;
10340    return {width: originalWidth, height: originalHeight};
10341  },
10342
10343  makePositioned: function(element) {
10344    element = $(element);
10345    var pos = Element.getStyle(element, 'position');
10346    if (pos == 'static' || !pos) {
10347      element._madePositioned = true;
10348      element.style.position = 'relative';
10349      // Opera returns the offset relative to the positioning context, when an
10350      // element is position relative but top and left have not been defined
10351      if (Prototype.Browser.Opera) {
10352        element.style.top = 0;
10353        element.style.left = 0;
10354      }
10355    }
10356    return element;
10357  },
10358
10359  undoPositioned: function(element) {
10360    element = $(element);
10361    if (element._madePositioned) {
10362      element._madePositioned = undefined;
10363      element.style.position =
10364        element.style.top =
10365        element.style.left =
10366        element.style.bottom =
10367        element.style.right = '';
10368    }
10369    return element;
10370  },
10371
10372  makeClipping: function(element) {
10373    element = $(element);
10374    if (element._overflow) return element;
10375    element._overflow = Element.getStyle(element, 'overflow') || 'auto';
10376    if (element._overflow !== 'hidden')
10377      element.style.overflow = 'hidden';
10378    return element;
10379  },
10380
10381  undoClipping: function(element) {
10382    element = $(element);
10383    if (!element._overflow) return element;
10384    element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
10385    element._overflow = null;
10386    return element;
10387  },
10388
10389  cumulativeOffset: function(element) {
10390    var valueT = 0, valueL = 0;
10391    do {
10392      valueT += element.offsetTop  || 0;
10393      valueL += element.offsetLeft || 0;
10394      element = element.offsetParent;
10395    } while (element);
10396    return Element._returnOffset(valueL, valueT);
10397  },
10398
10399  positionedOffset: function(element) {
10400    var valueT = 0, valueL = 0;
10401    do {
10402      valueT += element.offsetTop  || 0;
10403      valueL += element.offsetLeft || 0;
10404      element = element.offsetParent;
10405      if (element) {
10406        if (element.tagName.toUpperCase() == 'BODY') break;
10407        var p = Element.getStyle(element, 'position');
10408        if (p !== 'static') break;
10409      }
10410    } while (element);
10411    return Element._returnOffset(valueL, valueT);
10412  },
10413
10414  absolutize: function(element) {
10415    element = $(element);
10416    if (element.getStyle('position') == 'absolute') return element;
10417    // Position.prepare(); // To be done manually by Scripty when it needs it.
10418
10419    var offsets = element.positionedOffset();
10420    var top     = offsets[1];
10421    var left    = offsets[0];
10422    var width   = element.clientWidth;
10423    var height  = element.clientHeight;
10424
10425    element._originalLeft   = left - parseFloat(element.style.left  || 0);
10426    element._originalTop    = top  - parseFloat(element.style.top || 0);
10427    element._originalWidth  = element.style.width;
10428    element._originalHeight = element.style.height;
10429
10430    element.style.position = 'absolute';
10431    element.style.top    = top + 'px';
10432    element.style.left   = left + 'px';
10433    element.style.width  = width + 'px';
10434    element.style.height = height + 'px';
10435    return element;
10436  },
10437
10438  relativize: function(element) {
10439    element = $(element);
10440    if (element.getStyle('position') == 'relative') return element;
10441    // Position.prepare(); // To be done manually by Scripty when it needs it.
10442
10443    element.style.position = 'relative';
10444    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
10445    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
10446
10447    element.style.top    = top + 'px';
10448    element.style.left   = left + 'px';
10449    element.style.height = element._originalHeight;
10450    element.style.width  = element._originalWidth;
10451    return element;
10452  },
10453
10454  cumulativeScrollOffset: function(element) {
10455    var valueT = 0, valueL = 0;
10456    do {
10457      valueT += element.scrollTop  || 0;
10458      valueL += element.scrollLeft || 0;
10459      element = element.parentNode;
10460    } while (element);
10461    return Element._returnOffset(valueL, valueT);
10462  },
10463
10464  getOffsetParent: function(element) {
10465    if (element.offsetParent) return $(element.offsetParent);
10466    if (element == document.body) return $(element);
10467
10468    while ((element = element.parentNode) && element != document.body)
10469      if (Element.getStyle(element, 'position') != 'static')
10470        return $(element);
10471
10472    return $(document.body);
10473  },
10474
10475  viewportOffset: function(forElement) {
10476    var valueT = 0, valueL = 0;
10477
10478    var element = forElement;
10479    do {
10480      valueT += element.offsetTop  || 0;
10481      valueL += element.offsetLeft || 0;
10482
10483      // Safari fix
10484      if (element.offsetParent == document.body &&
10485        Element.getStyle(element, 'position') == 'absolute') break;
10486
10487    } while (element = element.offsetParent);
10488
10489    element = forElement;
10490    do {
10491      if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) {
10492        valueT -= element.scrollTop  || 0;
10493        valueL -= element.scrollLeft || 0;
10494      }
10495    } while (element = element.parentNode);
10496
10497    return Element._returnOffset(valueL, valueT);
10498  },
10499
10500  clonePosition: function(element, source) {
10501    var options = Object.extend({
10502      setLeft:    true,
10503      setTop:     true,
10504      setWidth:   true,
10505      setHeight:  true,
10506      offsetTop:  0,
10507      offsetLeft: 0
10508    }, arguments[2] || { });
10509
10510    // find page position of source
10511    source = $(source);
10512    var p = source.viewportOffset();
10513
10514    // find coordinate system to use
10515    element = $(element);
10516    var delta = [0, 0];
10517    var parent = null;
10518    // delta [0,0] will do fine with position: fixed elements,
10519    // position:absolute needs offsetParent deltas
10520    if (Element.getStyle(element, 'position') == 'absolute') {
10521      parent = element.getOffsetParent();
10522      delta = parent.viewportOffset();
10523    }
10524
10525    // correct by body offsets (fixes Safari)
10526    if (parent == document.body) {
10527      delta[0] -= document.body.offsetLeft;
10528      delta[1] -= document.body.offsetTop;
10529    }
10530
10531    // set position
10532    if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
10533    if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
10534    if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
10535    if (options.setHeight) element.style.height = source.offsetHeight + 'px';
10536    return element;
10537  }
10538};
10539
10540Element.Methods.identify.counter = 1;
10541
10542Object.extend(Element.Methods, {
10543  getElementsBySelector: Element.Methods.select,
10544  childElements: Element.Methods.immediateDescendants
10545});
10546
10547Element._attributeTranslations = {
10548  write: {
10549    names: {
10550      className: 'class',
10551      htmlFor:   'for'
10552    },
10553    values: { }
10554  }
10555};
10556
10557if (Prototype.Browser.Opera) {
10558  Element.Methods.getStyle = Element.Methods.getStyle.wrap(
10559    function(proceed, element, style) {
10560      switch (style) {
10561        case 'left': case 'top': case 'right': case 'bottom':
10562          if (proceed(element, 'position') === 'static') return null;
10563        case 'height': case 'width':
10564          // returns '0px' for hidden elements; we want it to return null
10565          if (!Element.visible(element)) return null;
10566
10567          // returns the border-box dimensions rather than the content-box
10568          // dimensions, so we subtract padding and borders from the value
10569          var dim = parseInt(proceed(element, style), 10);
10570
10571          if (dim !== element['offset' + style.capitalize()])
10572            return dim + 'px';
10573
10574          var properties;
10575          if (style === 'height') {
10576            properties = ['border-top-width', 'padding-top',
10577             'padding-bottom', 'border-bottom-width'];
10578          }
10579          else {
10580            properties = ['border-left-width', 'padding-left',
10581             'padding-right', 'border-right-width'];
10582          }
10583          return properties.inject(dim, function(memo, property) {
10584            var val = proceed(element, property);
10585            return val === null ? memo : memo - parseInt(val, 10);
10586          }) + 'px';
10587        default: return proceed(element, style);
10588      }
10589    }
10590  );
10591
10592  Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
10593    function(proceed, element, attribute) {
10594      if (attribute === 'title') return element.title;
10595      return proceed(element, attribute);
10596    }
10597  );
10598}
10599
10600else if (Prototype.Browser.IE) {
10601  // IE doesn't report offsets correctly for static elements, so we change them
10602  // to "relative" to get the values, then change them back.
10603  Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
10604    function(proceed, element) {
10605      element = $(element);
10606      // IE throws an error if element is not in document
10607      try { element.offsetParent }
10608      catch(e) { return $(document.body) }
10609      var position = element.getStyle('position');
10610      if (position !== 'static') return proceed(element);
10611      element.setStyle({ position: 'relative' });
10612      var value = proceed(element);
10613      element.setStyle({ position: position });
10614      return value;
10615    }
10616  );
10617
10618  $w('positionedOffset viewportOffset').each(function(method) {
10619    Element.Methods[method] = Element.Methods[method].wrap(
10620      function(proceed, element) {
10621        element = $(element);
10622        try { element.offsetParent }
10623        catch(e) { return Element._returnOffset(0,0) }
10624        var position = element.getStyle('position');
10625        if (position !== 'static') return proceed(element);
10626        // Trigger hasLayout on the offset parent so that IE6 reports
10627        // accurate offsetTop and offsetLeft values for position: fixed.
10628        var offsetParent = element.getOffsetParent();
10629        if (offsetParent && offsetParent.getStyle('position') === 'fixed')
10630          offsetParent.setStyle({ zoom: 1 });
10631        element.setStyle({ position: 'relative' });
10632        var value = proceed(element);
10633        element.setStyle({ position: position });
10634        return value;
10635      }
10636    );
10637  });
10638
10639  Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
10640    function(proceed, element) {
10641      try { element.offsetParent }
10642      catch(e) { return Element._returnOffset(0,0) }
10643      return proceed(element);
10644    }
10645  );
10646
10647  Element.Methods.getStyle = function(element, style) {
10648    element = $(element);
10649    style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
10650    var value = element.style[style];
10651    if (!value && element.currentStyle) value = element.currentStyle[style];
10652
10653    if (style == 'opacity') {
10654      if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
10655        if (value[1]) return parseFloat(value[1]) / 100;
10656      return 1.0;
10657    }
10658
10659    if (value == 'auto') {
10660      if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none'))
10661        return element['offset' + style.capitalize()] + 'px';
10662      return null;
10663    }
10664    return value;
10665  };
10666
10667  Element.Methods.setOpacity = function(element, value) {
10668    function stripAlpha(filter){
10669      return filter.replace(/alpha\([^\)]*\)/gi,'');
10670    }
10671    element = $(element);
10672    var currentStyle = element.currentStyle;
10673    if ((currentStyle && !currentStyle.hasLayout) ||
10674      (!currentStyle && element.style.zoom == 'normal'))
10675        element.style.zoom = 1;
10676
10677    var filter = element.getStyle('filter'), style = element.style;
10678    if (value == 1 || value === '') {
10679      (filter = stripAlpha(filter)) ?
10680        style.filter = filter : style.removeAttribute('filter');
10681      return element;
10682    } else if (value < 0.00001) value = 0;
10683    style.filter = stripAlpha(filter) +
10684      'alpha(opacity=' + (value * 100) + ')';
10685    return element;
10686  };
10687
10688  Element._attributeTranslations = {
10689    read: {
10690      names: {
10691        'class': 'className',
10692        'for':   'htmlFor'
10693      },
10694      values: {
10695        _getAttr: function(element, attribute) {
10696          return element.getAttribute(attribute, 2);
10697        },
10698        _getAttrNode: function(element, attribute) {
10699          var node = element.getAttributeNode(attribute);
10700          return node ? node.value : "";
10701        },
10702        _getEv: function(element, attribute) {
10703          attribute = element.getAttribute(attribute);
10704          return attribute ? attribute.toString().slice(23, -2) : null;
10705        },
10706        _flag: function(element, attribute) {
10707          return $(element).hasAttribute(attribute) ? attribute : null;
10708        },
10709        style: function(element) {
10710          return element.style.cssText.toLowerCase();
10711        },
10712        title: function(element) {
10713          return element.title;
10714        }
10715      }
10716    }
10717  };
10718
10719  Element._attributeTranslations.write = {
10720    names: Object.extend({
10721      cellpadding: 'cellPadding',
10722      cellspacing: 'cellSpacing'
10723    }, Element._attributeTranslations.read.names),
10724    values: {
10725      checked: function(element, value) {
10726        element.checked = !!value;
10727      },
10728
10729      style: function(element, value) {
10730        element.style.cssText = value ? value : '';
10731      }
10732    }
10733  };
10734
10735  Element._attributeTranslations.has = {};
10736
10737  $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
10738      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
10739    Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
10740    Element._attributeTranslations.has[attr.toLowerCase()] = attr;
10741  });
10742
10743  (function(v) {
10744    Object.extend(v, {
10745      href:        v._getAttr,
10746      src:         v._getAttr,
10747      type:        v._getAttr,
10748      action:      v._getAttrNode,
10749      disabled:    v._flag,
10750      checked:     v._flag,
10751      readonly:    v._flag,
10752      multiple:    v._flag,
10753      onload:      v._getEv,
10754      onunload:    v._getEv,
10755      onclick:     v._getEv,
10756      ondblclick:  v._getEv,
10757      onmousedown: v._getEv,
10758      onmouseup:   v._getEv,
10759      onmouseover: v._getEv,
10760      onmousemove: v._getEv,
10761      onmouseout:  v._getEv,
10762      onfocus:     v._getEv,
10763      onblur:      v._getEv,
10764      onkeypress:  v._getEv,
10765      onkeydown:   v._getEv,
10766      onkeyup:     v._getEv,
10767      onsubmit:    v._getEv,
10768      onreset:     v._getEv,
10769      onselect:    v._getEv,
10770      onchange:    v._getEv
10771    });
10772  })(Element._attributeTranslations.read.values);
10773}
10774
10775else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) {
10776  Element.Methods.setOpacity = function(element, value) {
10777    element = $(element);
10778    element.style.opacity = (value == 1) ? 0.999999 :
10779      (value === '') ? '' : (value < 0.00001) ? 0 : value;
10780    return element;
10781  };
10782}
10783
10784else if (Prototype.Browser.WebKit) {
10785  Element.Methods.setOpacity = function(element, value) {
10786    element = $(element);
10787    element.style.opacity = (value == 1 || value === '') ? '' :
10788      (value < 0.00001) ? 0 : value;
10789
10790    if (value == 1)
10791      if(element.tagName.toUpperCase() == 'IMG' && element.width) {
10792        element.width++; element.width--;
10793      } else try {
10794        var n = document.createTextNode(' ');
10795        element.appendChild(n);
10796        element.removeChild(n);
10797      } catch (e) { }
10798
10799    return element;
10800  };
10801
10802  // Safari returns margins on body which is incorrect if the child is absolutely
10803  // positioned.  For performance reasons, redefine Element#cumulativeOffset for
10804  // KHTML/WebKit only.
10805  Element.Methods.cumulativeOffset = function(element) {
10806    var valueT = 0, valueL = 0;
10807    do {
10808      valueT += element.offsetTop  || 0;
10809      valueL += element.offsetLeft || 0;
10810      if (element.offsetParent == document.body)
10811        if (Element.getStyle(element, 'position') == 'absolute') break;
10812
10813      element = element.offsetParent;
10814    } while (element);
10815
10816    return Element._returnOffset(valueL, valueT);
10817  };
10818}
10819
10820if (Prototype.Browser.IE || Prototype.Browser.Opera) {
10821  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
10822  Element.Methods.update = function(element, content) {
10823    element = $(element);
10824
10825    if (content && content.toElement) content = content.toElement();
10826    if (Object.isElement(content)) return element.update().insert(content);
10827
10828    content = Object.toHTML(content);
10829    var tagName = element.tagName.toUpperCase();
10830
10831    if (tagName in Element._insertionTranslations.tags) {
10832      $A(element.childNodes).each(function(node) { element.removeChild(node) });
10833      Element._getContentFromAnonymousElement(tagName, content.stripScripts())
10834        .each(function(node) { element.appendChild(node) });
10835    }
10836    else element.innerHTML = content.stripScripts();
10837
10838    content.evalScripts.bind(content).defer();
10839    return element;
10840  };
10841}
10842
10843if ('outerHTML' in document.createElement('div')) {
10844  Element.Methods.replace = function(element, content) {
10845    element = $(element);
10846
10847    if (content && content.toElement) content = content.toElement();
10848    if (Object.isElement(content)) {
10849      element.parentNode.replaceChild(content, element);
10850      return element;
10851    }
10852
10853    content = Object.toHTML(content);
10854    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
10855
10856    if (Element._insertionTranslations.tags[tagName]) {
10857      var nextSibling = element.next();
10858      var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
10859      parent.removeChild(element);
10860      if (nextSibling)
10861        fragments.each(function(node) { parent.insertBefore(node, nextSibling) });
10862      else
10863        fragments.each(function(node) { parent.appendChild(node) });
10864    }
10865    else element.outerHTML = content.stripScripts();
10866
10867    content.evalScripts.bind(content).defer();
10868    return element;
10869  };
10870}
10871
10872Element._returnOffset = function(l, t) {
10873  var result = [l, t];
10874  result.left = l;
10875  result.top = t;
10876  return result;
10877};
10878
10879Element._getContentFromAnonymousElement = function(tagName, html) {
10880  var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
10881  if (t) {
10882    div.innerHTML = t[0] + html + t[1];
10883    t[2].times(function() { div = div.firstChild });
10884  } else div.innerHTML = html;
10885  return $A(div.childNodes);
10886};
10887
10888Element._insertionTranslations = {
10889  before: function(element, node) {
10890    element.parentNode.insertBefore(node, element);
10891  },
10892  top: function(element, node) {
10893    element.insertBefore(node, element.firstChild);
10894  },
10895  bottom: function(element, node) {
10896    element.appendChild(node);
10897  },
10898  after: function(element, node) {
10899    element.parentNode.insertBefore(node, element.nextSibling);
10900  },
10901  tags: {
10902    TABLE:  ['<table>',                '</table>',                   1],
10903    TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
10904    TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
10905    TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
10906    SELECT: ['<select>',               '</select>',                  1]
10907  }
10908};
10909
10910(function() {
10911  Object.extend(this.tags, {
10912    THEAD: this.tags.TBODY,
10913    TFOOT: this.tags.TBODY,
10914    TH:    this.tags.TD
10915  });
10916}).call(Element._insertionTranslations);
10917
10918Element.Methods.Simulated = {
10919  hasAttribute: function(element, attribute) {
10920    attribute = Element._attributeTranslations.has[attribute] || attribute;
10921    var node = $(element).getAttributeNode(attribute);
10922    return !!(node && node.specified);
10923  }
10924};
10925
10926Element.Methods.ByTag = { };
10927
10928Object.extend(Element, Element.Methods);
10929
10930if (!Prototype.BrowserFeatures.ElementExtensions &&
10931    document.createElement('div')['__proto__']) {
10932  window.HTMLElement = { };
10933  window.HTMLElement.prototype = document.createElement('div')['__proto__'];
10934  Prototype.BrowserFeatures.ElementExtensions = true;
10935}
10936
10937Element.extend = (function() {
10938  if (Prototype.BrowserFeatures.SpecificElementExtensions)
10939    return Prototype.K;
10940
10941  var Methods = { }, ByTag = Element.Methods.ByTag;
10942
10943  var extend = Object.extend(function(element) {
10944    if (!element || element._extendedByPrototype ||
10945        element.nodeType != 1 || element == window) return element;
10946
10947    var methods = Object.clone(Methods),
10948      tagName = element.tagName.toUpperCase(), property, value;
10949
10950    // extend methods for specific tags
10951    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
10952
10953    for (property in methods) {
10954      value = methods[property];
10955      if (Object.isFunction(value) && !(property in element))
10956        element[property] = value.methodize();
10957    }
10958
10959    element._extendedByPrototype = Prototype.emptyFunction;
10960    return element;
10961
10962  }, {
10963    refresh: function() {
10964      // extend methods for all tags (Safari doesn't need this)
10965      if (!Prototype.BrowserFeatures.ElementExtensions) {
10966        Object.extend(Methods, Element.Methods);
10967        Object.extend(Methods, Element.Methods.Simulated);
10968      }
10969    }
10970  });
10971
10972  extend.refresh();
10973  return extend;
10974})();
10975
10976Element.hasAttribute = function(element, attribute) {
10977  if (element.hasAttribute) return element.hasAttribute(attribute);
10978  return Element.Methods.Simulated.hasAttribute(element, attribute);
10979};
10980
10981Element.addMethods = function(methods) {
10982  var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag;
10983
10984  if (!methods) {
10985    Object.extend(Form, Form.Methods);
10986    Object.extend(Form.Element, Form.Element.Methods);
10987    Object.extend(Element.Methods.ByTag, {
10988      "FORM":     Object.clone(Form.Methods),
10989      "INPUT":    Object.clone(Form.Element.Methods),
10990      "SELECT":   Object.clone(Form.Element.Methods),
10991      "TEXTAREA": Object.clone(Form.Element.Methods)
10992    });
10993  }
10994
10995  if (arguments.length == 2) {
10996    var tagName = methods;
10997    methods = arguments[1];
10998  }
10999
11000  if (!tagName) Object.extend(Element.Methods, methods || { });
11001  else {
11002    if (Object.isArray(tagName)) tagName.each(extend);
11003    else extend(tagName);
11004  }
11005
11006  function extend(tagName) {
11007    tagName = tagName.toUpperCase();
11008    if (!Element.Methods.ByTag[tagName])
11009      Element.Methods.ByTag[tagName] = { };
11010    Object.extend(Element.Methods.ByTag[tagName], methods);
11011  }
11012
11013  function copy(methods, destination, onlyIfAbsent) {
11014    onlyIfAbsent = onlyIfAbsent || false;
11015    for (var property in methods) {
11016      var value = methods[property];
11017      if (!Object.isFunction(value)) continue;
11018      if (!onlyIfAbsent || !(property in destination))
11019        destination[property] = value.methodize();
11020    }
11021  }
11022
11023  function findDOMClass(tagName) {
11024    var klass;
11025    var trans = {
11026      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
11027      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
11028      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
11029      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
11030      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
11031      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
11032      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
11033      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
11034      "FrameSet", "IFRAME": "IFrame"
11035    };
11036    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
11037    if (window[klass]) return window[klass];
11038    klass = 'HTML' + tagName + 'Element';
11039    if (window[klass]) return window[klass];
11040    klass = 'HTML' + tagName.capitalize() + 'Element';
11041    if (window[klass]) return window[klass];
11042
11043    window[klass] = { };
11044    window[klass].prototype = document.createElement(tagName)['__proto__'];
11045    return window[klass];
11046  }
11047
11048  if (F.ElementExtensions) {
11049    copy(Element.Methods, HTMLElement.prototype);
11050    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
11051  }
11052
11053  if (F.SpecificElementExtensions) {
11054    for (var tag in Element.Methods.ByTag) {
11055      var klass = findDOMClass(tag);
11056      if (Object.isUndefined(klass)) continue;
11057      copy(T[tag], klass.prototype);
11058    }
11059  }
11060
11061  Object.extend(Element, Element.Methods);
11062  delete Element.ByTag;
11063
11064  if (Element.extend.refresh) Element.extend.refresh();
11065  Element.cache = { };
11066};
11067
11068document.viewport = {
11069  getDimensions: function() {
11070    var dimensions = { }, B = Prototype.Browser;
11071    $w('width height').each(function(d) {
11072      var D = d.capitalize();
11073      if (B.WebKit && !document.evaluate) {
11074        // Safari <3.0 needs self.innerWidth/Height
11075        dimensions[d] = self['inner' + D];
11076      } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) {
11077        // Opera <9.5 needs document.body.clientWidth/Height
11078        dimensions[d] = document.body['client' + D]
11079      } else {
11080        dimensions[d] = document.documentElement['client' + D];
11081      }
11082    });
11083    return dimensions;
11084  },
11085
11086  getWidth: function() {
11087    return this.getDimensions().width;
11088  },
11089
11090  getHeight: function() {
11091    return this.getDimensions().height;
11092  },
11093
11094  getScrollOffsets: function() {
11095    return Element._returnOffset(
11096      window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
11097      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
11098  }
11099};
11100/* Portions of the Selector class are derived from Jack Slocum's DomQuery,
11101 * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
11102 * license.  Please see http://www.yui-ext.com/ for more information. */
11103
11104var Selector = Class.create({
11105  initialize: function(expression) {
11106    this.expression = expression.strip();
11107
11108    if (this.shouldUseSelectorsAPI()) {
11109      this.mode = 'selectorsAPI';
11110    } else if (this.shouldUseXPath()) {
11111      this.mode = 'xpath';
11112      this.compileXPathMatcher();
11113    } else {
11114      this.mode = "normal";
11115      this.compileMatcher();
11116    }
11117
11118  },
11119
11120  shouldUseXPath: function() {
11121    if (!Prototype.BrowserFeatures.XPath) return false;
11122
11123    var e = this.expression;
11124
11125    // Safari 3 chokes on :*-of-type and :empty
11126    if (Prototype.Browser.WebKit &&
11127     (e.include("-of-type") || e.include(":empty")))
11128      return false;
11129
11130    // XPath can't do namespaced attributes, nor can it read
11131    // the "checked" property from DOM nodes
11132    if ((/(\[[\w-]*?:|:checked)/).test(e))
11133      return false;
11134
11135    return true;
11136  },
11137
11138  shouldUseSelectorsAPI: function() {
11139    if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
11140
11141    if (!Selector._div) Selector._div = new Element('div');
11142
11143    // Make sure the browser treats the selector as valid. Test on an
11144    // isolated element to minimize cost of this check.
11145    try {
11146      Selector._div.querySelector(this.expression);
11147    } catch(e) {
11148      return false;
11149    }
11150
11151    return true;
11152  },
11153
11154  compileMatcher: function() {
11155    var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
11156        c = Selector.criteria, le, p, m;
11157
11158    if (Selector._cache[e]) {
11159      this.matcher = Selector._cache[e];
11160      return;
11161    }
11162
11163    this.matcher = ["this.matcher = function(root) {",
11164                    "var r = root, h = Selector.handlers, c = false, n;"];
11165
11166    while (e && le != e && (/\S/).test(e)) {
11167      le = e;
11168      for (var i in ps) {
11169        p = ps[i];
11170        if (m = e.match(p)) {
11171          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
11172            new Template(c[i]).evaluate(m));
11173          e = e.replace(m[0], '');
11174          break;
11175        }
11176      }
11177    }
11178
11179    this.matcher.push("return h.unique(n);\n}");
11180    eval(this.matcher.join('\n'));
11181    Selector._cache[this.expression] = this.matcher;
11182  },
11183
11184  compileXPathMatcher: function() {
11185    var e = this.expression, ps = Selector.patterns,
11186        x = Selector.xpath, le, m;
11187
11188    if (Selector._cache[e]) {
11189      this.xpath = Selector._cache[e]; return;
11190    }
11191
11192    this.matcher = ['.//*'];
11193    while (e && le != e && (/\S/).test(e)) {
11194      le = e;
11195      for (var i in ps) {
11196        if (m = e.match(ps[i])) {
11197          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
11198            new Template(x[i]).evaluate(m));
11199          e = e.replace(m[0], '');
11200          break;
11201        }
11202      }
11203    }
11204
11205    this.xpath = this.matcher.join('');
11206    Selector._cache[this.expression] = this.xpath;
11207  },
11208
11209  findElements: function(root) {
11210    root = root || document;
11211    var e = this.expression, results;
11212
11213    switch (this.mode) {
11214      case 'selectorsAPI':
11215        // querySelectorAll queries document-wide, then filters to descendants
11216        // of the context element. That's not what we want.
11217        // Add an explicit context to the selector if necessary.
11218        if (root !== document) {
11219          var oldId = root.id, id = $(root).identify();
11220          e = "#" + id + " " + e;
11221        }
11222
11223        results = $A(root.querySelectorAll(e)).map(Element.extend);
11224        root.id = oldId;
11225
11226        return results;
11227      case 'xpath':
11228        return document._getElementsByXPath(this.xpath, root);
11229      default:
11230       return this.matcher(root);
11231    }
11232  },
11233
11234  match: function(element) {
11235    this.tokens = [];
11236
11237    var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
11238    var le, p, m;
11239
11240    while (e && le !== e && (/\S/).test(e)) {
11241      le = e;
11242      for (var i in ps) {
11243        p = ps[i];
11244        if (m = e.match(p)) {
11245          // use the Selector.assertions methods unless the selector
11246          // is too complex.
11247          if (as[i]) {
11248            this.tokens.push([i, Object.clone(m)]);
11249            e = e.replace(m[0], '');
11250          } else {
11251            // reluctantly do a document-wide search
11252            // and look for a match in the array
11253            return this.findElements(document).include(element);
11254          }
11255        }
11256      }
11257    }
11258
11259    var match = true, name, matches;
11260    for (var i = 0, token; token = this.tokens[i]; i++) {
11261      name = token[0], matches = token[1];
11262      if (!Selector.assertions[name](element, matches)) {
11263        match = false; break;
11264      }
11265    }
11266
11267    return match;
11268  },
11269
11270  toString: function() {
11271    return this.expression;
11272  },
11273
11274  inspect: function() {
11275    return "#<Selector:" + this.expression.inspect() + ">";
11276  }
11277});
11278
11279Object.extend(Selector, {
11280  _cache: { },
11281
11282  xpath: {
11283    descendant:   "//*",
11284    child:        "/*",
11285    adjacent:     "/following-sibling::*[1]",
11286    laterSibling: '/following-sibling::*',
11287    tagName:      function(m) {
11288      if (m[1] == '*') return '';
11289      return "[local-name()='" + m[1].toLowerCase() +
11290             "' or local-name()='" + m[1].toUpperCase() + "']";
11291    },
11292    className:    "[contains(concat(' ', @class, ' '), ' #{1} ')]",
11293    id:           "[@id='#{1}']",
11294    attrPresence: function(m) {
11295      m[1] = m[1].toLowerCase();
11296      return new Template("[@#{1}]").evaluate(m);
11297    },
11298    attr: function(m) {
11299      m[1] = m[1].toLowerCase();
11300      m[3] = m[5] || m[6];
11301      return new Template(Selector.xpath.operators[m[2]]).evaluate(m);
11302    },
11303    pseudo: function(m) {
11304      var h = Selector.xpath.pseudos[m[1]];
11305      if (!h) return '';
11306      if (Object.isFunction(h)) return h(m);
11307      return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m);
11308    },
11309    operators: {
11310      '=':  "[@#{1}='#{3}']",
11311      '!=': "[@#{1}!='#{3}']",
11312      '^=': "[starts-with(@#{1}, '#{3}')]",
11313      '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']",
11314      '*=': "[contains(@#{1}, '#{3}')]",
11315      '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]",
11316      '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]"
11317    },
11318    pseudos: {
11319      'first-child': '[not(preceding-sibling::*)]',
11320      'last-child':  '[not(following-sibling::*)]',
11321      'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
11322      'empty':       "[count(*) = 0 and (count(text()) = 0)]",
11323      'checked':     "[@checked]",
11324      'disabled':    "[(@disabled) and (@type!='hidden')]",
11325      'enabled':     "[not(@disabled) and (@type!='hidden')]",
11326      'not': function(m) {
11327        var e = m[6], p = Selector.patterns,
11328            x = Selector.xpath, le, v;
11329
11330        var exclusion = [];
11331        while (e && le != e && (/\S/).test(e)) {
11332          le = e;
11333          for (var i in p) {
11334            if (m = e.match(p[i])) {
11335              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
11336              exclusion.push("(" + v.substring(1, v.length - 1) + ")");
11337              e = e.replace(m[0], '');
11338              break;
11339            }
11340          }
11341        }
11342        return "[not(" + exclusion.join(" and ") + ")]";
11343      },
11344      'nth-child':      function(m) {
11345        return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m);
11346      },
11347      'nth-last-child': function(m) {
11348        return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m);
11349      },
11350      'nth-of-type':    function(m) {
11351        return Selector.xpath.pseudos.nth("position() ", m);
11352      },
11353      'nth-last-of-type': function(m) {
11354        return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m);
11355      },
11356      'first-of-type':  function(m) {
11357        m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m);
11358      },
11359      'last-of-type':   function(m) {
11360        m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m);
11361      },
11362      'only-of-type':   function(m) {
11363        var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m);
11364      },
11365      nth: function(fragment, m) {
11366        var mm, formula = m[6], predicate;
11367        if (formula == 'even') formula = '2n+0';
11368        if (formula == 'odd')  formula = '2n+1';
11369        if (mm = formula.match(/^(\d+)$/)) // digit only
11370          return '[' + fragment + "= " + mm[1] + ']';
11371        if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
11372          if (mm[1] == "-") mm[1] = -1;
11373          var a = mm[1] ? Number(mm[1]) : 1;
11374          var b = mm[2] ? Number(mm[2]) : 0;
11375          predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " +
11376          "((#{fragment} - #{b}) div #{a} >= 0)]";
11377          return new Template(predicate).evaluate({
11378            fragment: fragment, a: a, b: b });
11379        }
11380      }
11381    }
11382  },
11383
11384  criteria: {
11385    tagName:      'n = h.tagName(n, r, "#{1}", c);      c = false;',
11386    className:    'n = h.className(n, r, "#{1}", c);    c = false;',
11387    id:           'n = h.id(n, r, "#{1}", c);           c = false;',
11388    attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
11389    attr: function(m) {
11390      m[3] = (m[5] || m[6]);
11391      return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
11392    },
11393    pseudo: function(m) {
11394      if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
11395      return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m);
11396    },
11397    descendant:   'c = "descendant";',
11398    child:        'c = "child";',
11399    adjacent:     'c = "adjacent";',
11400    laterSibling: 'c = "laterSibling";'
11401  },
11402
11403  patterns: {
11404    // combinators must be listed first
11405    // (and descendant needs to be last combinator)
11406    laterSibling: /^\s*~\s*/,
11407    child:        /^\s*>\s*/,
11408    adjacent:     /^\s*\+\s*/,
11409    descendant:   /^\s/,
11410
11411    // selectors follow
11412    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
11413    id:           /^#([\w\-\*]+)(\b|$)/,
11414    className:    /^\.([\w\-\*]+)(\b|$)/,
11415    pseudo:
11416/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
11417    attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/,
11418    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
11419  },
11420
11421  // for Selector.match and Element#match
11422  assertions: {
11423    tagName: function(element, matches) {
11424      return matches[1].toUpperCase() == element.tagName.toUpperCase();
11425    },
11426
11427    className: function(element, matches) {
11428      return Element.hasClassName(element, matches[1]);
11429    },
11430
11431    id: function(element, matches) {
11432      return element.id === matches[1];
11433    },
11434
11435    attrPresence: function(element, matches) {
11436      return Element.hasAttribute(element, matches[1]);
11437    },
11438
11439    attr: function(element, matches) {
11440      var nodeValue = Element.readAttribute(element, matches[1]);
11441      return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]);
11442    }
11443  },
11444
11445  handlers: {
11446    // UTILITY FUNCTIONS
11447    // joins two collections
11448    concat: function(a, b) {
11449      for (var i = 0, node; node = b[i]; i++)
11450        a.push(node);
11451      return a;
11452    },
11453
11454    // marks an array of nodes for counting
11455    mark: function(nodes) {
11456      var _true = Prototype.emptyFunction;
11457      for (var i = 0, node; node = nodes[i]; i++)
11458        node._countedByPrototype = _true;
11459      return nodes;
11460    },
11461
11462    unmark: function(nodes) {
11463      for (var i = 0, node; node = nodes[i]; i++)
11464        node._countedByPrototype = undefined;
11465      return nodes;
11466    },
11467
11468    // mark each child node with its position (for nth calls)
11469    // "ofType" flag indicates whether we're indexing for nth-of-type
11470    // rather than nth-child
11471    index: function(parentNode, reverse, ofType) {
11472      parentNode._countedByPrototype = Prototype.emptyFunction;
11473      if (reverse) {
11474        for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) {
11475          var node = nodes[i];
11476          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
11477        }
11478      } else {
11479        for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++)
11480          if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++;
11481      }
11482    },
11483
11484    // filters out duplicates and extends all nodes
11485    unique: function(nodes) {
11486      if (nodes.length == 0) return nodes;
11487      var results = [], n;
11488      for (var i = 0, l = nodes.length; i < l; i++)
11489        if (!(n = nodes[i])._countedByPrototype) {
11490          n._countedByPrototype = Prototype.emptyFunction;
11491          results.push(Element.extend(n));
11492        }
11493      return Selector.handlers.unmark(results);
11494    },
11495
11496    // COMBINATOR FUNCTIONS
11497    descendant: function(nodes) {
11498      var h = Selector.handlers;
11499      for (var i = 0, results = [], node; node = nodes[i]; i++)
11500        h.concat(results, node.getElementsByTagName('*'));
11501      return results;
11502    },
11503
11504    child: function(nodes) {
11505      var h = Selector.handlers;
11506      for (var i = 0, results = [], node; node = nodes[i]; i++) {
11507        for (var j = 0, child; child = node.childNodes[j]; j++)
11508          if (child.nodeType == 1 && child.tagName != '!') results.push(child);
11509      }
11510      return results;
11511    },
11512
11513    adjacent: function(nodes) {
11514      for (var i = 0, results = [], node; node = nodes[i]; i++) {
11515        var next = this.nextElementSibling(node);
11516        if (next) results.push(next);
11517      }
11518      return results;
11519    },
11520
11521    laterSibling: function(nodes) {
11522      var h = Selector.handlers;
11523      for (var i = 0, results = [], node; node = nodes[i]; i++)
11524        h.concat(results, Element.nextSiblings(node));
11525      return results;
11526    },
11527
11528    nextElementSibling: function(node) {
11529      while (node = node.nextSibling)
11530        if (node.nodeType == 1) return node;
11531      return null;
11532    },
11533
11534    previousElementSibling: function(node) {
11535      while (node = node.previousSibling)
11536        if (node.nodeType == 1) return node;
11537      return null;
11538    },
11539
11540    // TOKEN FUNCTIONS
11541    tagName: function(nodes, root, tagName, combinator) {
11542      var uTagName = tagName.toUpperCase();
11543      var results = [], h = Selector.handlers;
11544      if (nodes) {
11545        if (combinator) {
11546          // fastlane for ordinary descendant combinators
11547          if (combinator == "descendant") {
11548            for (var i = 0, node; node = nodes[i]; i++)
11549              h.concat(results, node.getElementsByTagName(tagName));
11550            return results;
11551          } else nodes = this[combinator](nodes);
11552          if (tagName == "*") return nodes;
11553        }
11554        for (var i = 0, node; node = nodes[i]; i++)
11555          if (node.tagName.toUpperCase() === uTagName) results.push(node);
11556        return results;
11557      } else return root.getElementsByTagName(tagName);
11558    },
11559
11560    id: function(nodes, root, id, combinator) {
11561      var targetNode = $(id), h = Selector.handlers;
11562      if (!targetNode) return [];
11563      if (!nodes && root == document) return [targetNode];
11564      if (nodes) {
11565        if (combinator) {
11566          if (combinator == 'child') {
11567            for (var i = 0, node; node = nodes[i]; i++)
11568              if (targetNode.parentNode == node) return [targetNode];
11569          } else if (combinator == 'descendant') {
11570            for (var i = 0, node; node = nodes[i]; i++)
11571              if (Element.descendantOf(targetNode, node)) return [targetNode];
11572          } else if (combinator == 'adjacent') {
11573            for (var i = 0, node; node = nodes[i]; i++)
11574              if (Selector.handlers.previousElementSibling(targetNode) == node)
11575                return [targetNode];
11576          } else nodes = h[combinator](nodes);
11577        }
11578        for (var i = 0, node; node = nodes[i]; i++)
11579          if (node == targetNode) return [targetNode];
11580        return [];
11581      }
11582      return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : [];
11583    },
11584
11585    className: function(nodes, root, className, combinator) {
11586      if (nodes && combinator) nodes = this[combinator](nodes);
11587      return Selector.handlers.byClassName(nodes, root, className);
11588    },
11589
11590    byClassName: function(nodes, root, className) {
11591      if (!nodes) nodes = Selector.handlers.descendant([root]);
11592      var needle = ' ' + className + ' ';
11593      for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) {
11594        nodeClassName = node.className;
11595        if (nodeClassName.length == 0) continue;
11596        if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle))
11597          results.push(node);
11598      }
11599      return results;
11600    },
11601
11602    attrPresence: function(nodes, root, attr, combinator) {
11603      if (!nodes) nodes = root.getElementsByTagName("*");
11604      if (nodes && combinator) nodes = this[combinator](nodes);
11605      var results = [];
11606      for (var i = 0, node; node = nodes[i]; i++)
11607        if (Element.hasAttribute(node, attr)) results.push(node);
11608      return results;
11609    },
11610
11611    attr: function(nodes, root, attr, value, operator, combinator) {
11612      if (!nodes) nodes = root.getElementsByTagName("*");
11613      if (nodes && combinator) nodes = this[combinator](nodes);
11614      var handler = Selector.operators[operator], results = [];
11615      for (var i = 0, node; node = nodes[i]; i++) {
11616        var nodeValue = Element.readAttribute(node, attr);
11617        if (nodeValue === null) continue;
11618        if (handler(nodeValue, value)) results.push(node);
11619      }
11620      return results;
11621    },
11622
11623    pseudo: function(nodes, name, value, root, combinator) {
11624      if (nodes && combinator) nodes = this[combinator](nodes);
11625      if (!nodes) nodes = root.getElementsByTagName("*");
11626      return Selector.pseudos[name](nodes, value, root);
11627    }
11628  },
11629
11630  pseudos: {
11631    'first-child': function(nodes, value, root) {
11632      for (var i = 0, results = [], node; node = nodes[i]; i++) {
11633        if (Selector.handlers.previousElementSibling(node)) continue;
11634          results.push(node);
11635      }
11636      return results;
11637    },
11638    'last-child': function(nodes, value, root) {
11639      for (var i = 0, results = [], node; node = nodes[i]; i++) {
11640        if (Selector.handlers.nextElementSibling(node)) continue;
11641          results.push(node);
11642      }
11643      return results;
11644    },
11645    'only-child': function(nodes, value, root) {
11646      var h = Selector.handlers;
11647      for (var i = 0, results = [], node; node = nodes[i]; i++)
11648        if (!h.previousElementSibling(node) && !h.nextElementSibling(node))
11649          results.push(node);
11650      return results;
11651    },
11652    'nth-child':        function(nodes, formula, root) {
11653      return Selector.pseudos.nth(nodes, formula, root);
11654    },
11655    'nth-last-child':   function(nodes, formula, root) {
11656      return Selector.pseudos.nth(nodes, formula, root, true);
11657    },
11658    'nth-of-type':      function(nodes, formula, root) {
11659      return Selector.pseudos.nth(nodes, formula, root, false, true);
11660    },
11661    'nth-last-of-type': function(nodes, formula, root) {
11662      return Selector.pseudos.nth(nodes, formula, root, true, true);
11663    },
11664    'first-of-type':    function(nodes, formula, root) {
11665      return Selector.pseudos.nth(nodes, "1", root, false, true);
11666    },
11667    'last-of-type':     function(nodes, formula, root) {
11668      return Selector.pseudos.nth(nodes, "1", root, true, true);
11669    },
11670    'only-of-type':     function(nodes, formula, root) {
11671      var p = Selector.pseudos;
11672      return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
11673    },
11674
11675    // handles the an+b logic
11676    getIndices: function(a, b, total) {
11677      if (a == 0) return b > 0 ? [b] : [];
11678      return $R(1, total).inject([], function(memo, i) {
11679        if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i);
11680        return memo;
11681      });
11682    },
11683
11684    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
11685    nth: function(nodes, formula, root, reverse, ofType) {
11686      if (nodes.length == 0) return [];
11687      if (formula == 'even') formula = '2n+0';
11688      if (formula == 'odd')  formula = '2n+1';
11689      var h = Selector.handlers, results = [], indexed = [], m;
11690      h.mark(nodes);
11691      for (var i = 0, node; node = nodes[i]; i++) {
11692        if (!node.parentNode._countedByPrototype) {
11693          h.index(node.parentNode, reverse, ofType);
11694          indexed.push(node.parentNode);
11695        }
11696      }
11697      if (formula.match(/^\d+$/)) { // just a number
11698        formula = Number(formula);
11699        for (var i = 0, node; node = nodes[i]; i++)
11700          if (node.nodeIndex == formula) results.push(node);
11701      } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b
11702        if (m[1] == "-") m[1] = -1;
11703        var a = m[1] ? Number(m[1]) : 1;
11704        var b = m[2] ? Number(m[2]) : 0;
11705        var indices = Selector.pseudos.getIndices(a, b, nodes.length);
11706        for (var i = 0, node, l = indices.length; node = nodes[i]; i++) {
11707          for (var j = 0; j < l; j++)
11708            if (node.nodeIndex == indices[j]) results.push(node);
11709        }
11710      }
11711      h.unmark(nodes);
11712      h.unmark(indexed);
11713      return results;
11714    },
11715
11716    'empty': function(nodes, value, root) {
11717      for (var i = 0, results = [], node; node = nodes[i]; i++) {
11718        // IE treats comments as element nodes
11719        if (node.tagName == '!' || node.firstChild) continue;
11720        results.push(node);
11721      }
11722      return results;
11723    },
11724
11725    'not': function(nodes, selector, root) {
11726      var h = Selector.handlers, selectorType, m;
11727      var exclusions = new Selector(selector).findElements(root);
11728      h.mark(exclusions);
11729      for (var i = 0, results = [], node; node = nodes[i]; i++)
11730        if (!node._countedByPrototype) results.push(node);
11731      h.unmark(exclusions);
11732      return results;
11733    },
11734
11735    'enabled': function(nodes, value, root) {
11736      for (var i = 0, results = [], node; node = nodes[i]; i++)
11737        if (!node.disabled && (!node.type || node.type !== 'hidden'))
11738          results.push(node);
11739      return results;
11740    },
11741
11742    'disabled': function(nodes, value, root) {
11743      for (var i = 0, results = [], node; node = nodes[i]; i++)
11744        if (node.disabled) results.push(node);
11745      return results;
11746    },
11747
11748    'checked': function(nodes, value, root) {
11749      for (var i = 0, results = [], node; node = nodes[i]; i++)
11750        if (node.checked) results.push(node);
11751      return results;
11752    }
11753  },
11754
11755  operators: {
11756    '=':  function(nv, v) { return nv == v; },
11757    '!=': function(nv, v) { return nv != v; },
11758    '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
11759    '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
11760    '*=': function(nv, v) { return nv == v || nv && nv.include(v); },
11761    '$=': function(nv, v) { return nv.endsWith(v); },
11762    '*=': function(nv, v) { return nv.include(v); },
11763    '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
11764    '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
11765     '-').include('-' + (v || "").toUpperCase() + '-'); }
11766  },
11767
11768  split: function(expression) {
11769    var expressions = [];
11770    expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
11771      expressions.push(m[1].strip());
11772    });
11773    return expressions;
11774  },
11775
11776  matchElements: function(elements, expression) {
11777    var matches = $$(expression), h = Selector.handlers;
11778    h.mark(matches);
11779    for (var i = 0, results = [], element; element = elements[i]; i++)
11780      if (element._countedByPrototype) results.push(element);
11781    h.unmark(matches);
11782    return results;
11783  },
11784
11785  findElement: function(elements, expression, index) {
11786    if (Object.isNumber(expression)) {
11787      index = expression; expression = false;
11788    }
11789    return Selector.matchElements(elements, expression || '*')[index || 0];
11790  },
11791
11792  findChildElements: function(element, expressions) {
11793    expressions = Selector.split(expressions.join(','));
11794    var results = [], h = Selector.handlers;
11795    for (var i = 0, l = expressions.length, selector; i < l; i++) {
11796      selector = new Selector(expressions[i].strip());
11797      h.concat(results, selector.findElements(element));
11798    }
11799    return (l > 1) ? h.unique(results) : results;
11800  }
11801});
11802
11803if (Prototype.Browser.IE) {
11804  Object.extend(Selector.handlers, {
11805    // IE returns comment nodes on getElementsByTagName("*").
11806    // Filter them out.
11807    concat: function(a, b) {
11808      for (var i = 0, node; node = b[i]; i++)
11809        if (node.tagName !== "!") a.push(node);
11810      return a;
11811    },
11812
11813    // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
11814    unmark: function(nodes) {
11815      for (var i = 0, node; node = nodes[i]; i++)
11816        node.removeAttribute('_countedByPrototype');
11817      return nodes;
11818    }
11819  });
11820}
11821
11822function $$() {
11823  return Selector.findChildElements(document, $A(arguments));
11824}
11825var Form = {
11826  reset: function(form) {
11827    $(form).reset();
11828    return form;
11829  },
11830
11831  serializeElements: function(elements, options) {
11832    if (typeof options != 'object') options = { hash: !!options };
11833    else if (Object.isUndefined(options.hash)) options.hash = true;
11834    var key, value, submitted = false, submit = options.submit;
11835
11836    var data = elements.inject({ }, function(result, element) {
11837      if (!element.disabled && element.name) {
11838        key = element.name; value = $(element).getValue();
11839        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
11840            submit !== false && (!submit || key == submit) && (submitted = true)))) {
11841          if (key in result) {
11842            // a key is already present; construct an array of values
11843            if (!Object.isArray(result[key])) result[key] = [result[key]];
11844            result[key].push(value);
11845          }
11846          else result[key] = value;
11847        }
11848      }
11849      return result;
11850    });
11851
11852    return options.hash ? data : Object.toQueryString(data);
11853  }
11854};
11855
11856Form.Methods = {
11857  serialize: function(form, options) {
11858    return Form.serializeElements(Form.getElements(form), options);
11859  },
11860
11861  getElements: function(form) {
11862    return $A($(form).getElementsByTagName('*')).inject([],
11863      function(elements, child) {
11864        if (Form.Element.Serializers[child.tagName.toLowerCase()])
11865          elements.push(Element.extend(child));
11866        return elements;
11867      }
11868    );
11869  },
11870
11871  getInputs: function(form, typeName, name) {
11872    form = $(form);
11873    var inputs = form.getElementsByTagName('input');
11874
11875    if (!typeName && !name) return $A(inputs).map(Element.extend);
11876
11877    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
11878      var input = inputs[i];
11879      if ((typeName && input.type != typeName) || (name && input.name != name))
11880        continue;
11881      matchingInputs.push(Element.extend(input));
11882    }
11883
11884    return matchingInputs;
11885  },
11886
11887  disable: function(form) {
11888    form = $(form);
11889    Form.getElements(form).invoke('disable');
11890    return form;
11891  },
11892
11893  enable: function(form) {
11894    form = $(form);
11895    Form.getElements(form).invoke('enable');
11896    return form;
11897  },
11898
11899  findFirstElement: function(form) {
11900    var elements = $(form).getElements().findAll(function(element) {
11901      return 'hidden' != element.type && !element.disabled;
11902    });
11903    var firstByIndex = elements.findAll(function(element) {
11904      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
11905    }).sortBy(function(element) { return element.tabIndex }).first();
11906
11907    return firstByIndex ? firstByIndex : elements.find(function(element) {
11908      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
11909    });
11910  },
11911
11912  focusFirstElement: function(form) {
11913    form = $(form);
11914    form.findFirstElement().activate();
11915    return form;
11916  },
11917
11918  request: function(form, options) {
11919    form = $(form), options = Object.clone(options || { });
11920
11921    var params = options.parameters, action = form.readAttribute('action') || '';
11922    if (action.blank()) action = window.location.href;
11923    options.parameters = form.serialize(true);
11924
11925    if (params) {
11926      if (Object.isString(params)) params = params.toQueryParams();
11927      Object.extend(options.parameters, params);
11928    }
11929
11930    if (form.hasAttribute('method') && !options.method)
11931      options.method = form.method;
11932
11933    return new Ajax.Request(action, options);
11934  }
11935};
11936
11937/*--------------------------------------------------------------------------*/
11938
11939Form.Element = {
11940  focus: function(element) {
11941    $(element).focus();
11942    return element;
11943  },
11944
11945  select: function(element) {
11946    $(element).select();
11947    return element;
11948  }
11949};
11950
11951Form.Element.Methods = {
11952  serialize: function(element) {
11953    element = $(element);
11954    if (!element.disabled && element.name) {
11955      var value = element.getValue();
11956      if (value != undefined) {
11957        var pair = { };
11958        pair[element.name] = value;
11959        return Object.toQueryString(pair);
11960      }
11961    }
11962    return '';
11963  },
11964
11965  getValue: function(element) {
11966    element = $(element);
11967    var method = element.tagName.toLowerCase();
11968    return Form.Element.Serializers[method](element);
11969  },
11970
11971  setValue: function(element, value) {
11972    element = $(element);
11973    var method = element.tagName.toLowerCase();
11974    Form.Element.Serializers[method](element, value);
11975    return element;
11976  },
11977
11978  clear: function(element) {
11979    $(element).value = '';
11980    return element;
11981  },
11982
11983  present: function(element) {
11984    return $(element).value != '';
11985  },
11986
11987  activate: function(element) {
11988    element = $(element);
11989    try {
11990      element.focus();
11991      if (element.select && (element.tagName.toLowerCase() != 'input' ||
11992          !['button', 'reset', 'submit'].include(element.type)))
11993        element.select();
11994    } catch (e) { }
11995    return element;
11996  },
11997
11998  disable: function(element) {
11999    element = $(element);
12000    element.disabled = true;
12001    return element;
12002  },
12003
12004  enable: function(element) {
12005    element = $(element);
12006    element.disabled = false;
12007    return element;
12008  }
12009};
12010
12011/*--------------------------------------------------------------------------*/
12012
12013var Field = Form.Element;
12014var $F = Form.Element.Methods.getValue;
12015
12016/*--------------------------------------------------------------------------*/
12017
12018Form.Element.Serializers = {
12019  input: function(element, value) {
12020    switch (element.type.toLowerCase()) {
12021      case 'checkbox':
12022      case 'radio':
12023        return Form.Element.Serializers.inputSelector(element, value);
12024      default:
12025        return Form.Element.Serializers.textarea(element, value);
12026    }
12027  },
12028
12029  inputSelector: function(element, value) {
12030    if (Object.isUndefined(value)) return element.checked ? element.value : null;
12031    else element.checked = !!value;
12032  },
12033
12034  textarea: function(element, value) {
12035    if (Object.isUndefined(value)) return element.value;
12036    else element.value = value;
12037  },
12038
12039  select: function(element, value) {
12040    if (Object.isUndefined(value))
12041      return this[element.type == 'select-one' ?
12042        'selectOne' : 'selectMany'](element);
12043    else {
12044      var opt, currentValue, single = !Object.isArray(value);
12045      for (var i = 0, length = element.length; i < length; i++) {
12046        opt = element.options[i];
12047        currentValue = this.optionValue(opt);
12048        if (single) {
12049          if (currentValue == value) {
12050            opt.selected = true;
12051            return;
12052          }
12053        }
12054        else opt.selected = value.include(currentValue);
12055      }
12056    }
12057  },
12058
12059  selectOne: function(element) {
12060    var index = element.selectedIndex;
12061    return index >= 0 ? this.optionValue(element.options[index]) : null;
12062  },
12063
12064  selectMany: function(element) {
12065    var values, length = element.length;
12066    if (!length) return null;
12067
12068    for (var i = 0, values = []; i < length; i++) {
12069      var opt = element.options[i];
12070      if (opt.selected) values.push(this.optionValue(opt));
12071    }
12072    return values;
12073  },
12074
12075  optionValue: function(opt) {
12076    // extend element because hasAttribute may not be native
12077    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
12078  }
12079};
12080
12081/*--------------------------------------------------------------------------*/
12082
12083Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
12084  initialize: function($super, element, frequency, callback) {
12085    $super(callback, frequency);
12086    this.element   = $(element);
12087    this.lastValue = this.getValue();
12088  },
12089
12090  execute: function() {
12091    var value = this.getValue();
12092    if (Object.isString(this.lastValue) && Object.isString(value) ?
12093        this.lastValue != value : String(this.lastValue) != String(value)) {
12094      this.callback(this.element, value);
12095      this.lastValue = value;
12096    }
12097  }
12098});
12099
12100Form.Element.Observer = Class.create(Abstract.TimedObserver, {
12101  getValue: function() {
12102    return Form.Element.getValue(this.element);
12103  }
12104});
12105
12106Form.Observer = Class.create(Abstract.TimedObserver, {
12107  getValue: function() {
12108    return Form.serialize(this.element);
12109  }
12110});
12111
12112/*--------------------------------------------------------------------------*/
12113
12114Abstract.EventObserver = Class.create({
12115  initialize: function(element, callback) {
12116    this.element  = $(element);
12117    this.callback = callback;
12118
12119    this.lastValue = this.getValue();
12120    if (this.element.tagName.toLowerCase() == 'form')
12121      this.registerFormCallbacks();
12122    else
12123      this.registerCallback(this.element);
12124  },
12125
12126  onElementEvent: function() {
12127    var value = this.getValue();
12128    if (this.lastValue != value) {
12129      this.callback(this.element, value);
12130      this.lastValue = value;
12131    }
12132  },
12133
12134  registerFormCallbacks: function() {
12135    Form.getElements(this.element).each(this.registerCallback, this);
12136  },
12137
12138  registerCallback: function(element) {
12139    if (element.type) {
12140      switch (element.type.toLowerCase()) {
12141        case 'checkbox':
12142        case 'radio':
12143          Event.observe(element, 'click', this.onElementEvent.bind(this));
12144          break;
12145        default:
12146          Event.observe(element, 'change', this.onElementEvent.bind(this));
12147          break;
12148      }
12149    }
12150  }
12151});
12152
12153Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
12154  getValue: function() {
12155    return Form.Element.getValue(this.element);
12156  }
12157});
12158
12159Form.EventObserver = Class.create(Abstract.EventObserver, {
12160  getValue: function() {
12161    return Form.serialize(this.element);
12162  }
12163});
12164if (!window.Event) var Event = { };
12165
12166Object.extend(Event, {
12167  KEY_BACKSPACE: 8,
12168  KEY_TAB:       9,
12169  KEY_RETURN:   13,
12170  KEY_ESC:      27,
12171  KEY_LEFT:     37,
12172  KEY_UP:       38,
12173  KEY_RIGHT:    39,
12174  KEY_DOWN:     40,
12175  KEY_DELETE:   46,
12176  KEY_HOME:     36,
12177  KEY_END:      35,
12178  KEY_PAGEUP:   33,
12179  KEY_PAGEDOWN: 34,
12180  KEY_INSERT:   45,
12181
12182  cache: { },
12183
12184  relatedTarget: function(event) {
12185    var element;
12186    switch(event.type) {
12187      case 'mouseover': element = event.fromElement; break;
12188      case 'mouseout':  element = event.toElement;   break;
12189      default: return null;
12190    }
12191    return Element.extend(element);
12192  }
12193});
12194
12195Event.Methods = (function() {
12196  var isButton;
12197
12198  if (Prototype.Browser.IE) {
12199    var buttonMap = { 0: 1, 1: 4, 2: 2 };
12200    isButton = function(event, code) {
12201      return event.button == buttonMap[code];
12202    };
12203
12204  } else if (Prototype.Browser.WebKit) {
12205    isButton = function(event, code) {
12206      switch (code) {
12207        case 0: return event.which == 1 && !event.metaKey;
12208        case 1: return event.which == 1 && event.metaKey;
12209        default: return false;
12210      }
12211    };
12212
12213  } else {
12214    isButton = function(event, code) {
12215      return event.which ? (event.which === code + 1) : (event.button === code);
12216    };
12217  }
12218
12219  return {
12220    isLeftClick:   function(event) { return isButton(event, 0) },
12221    isMiddleClick: function(event) { return isButton(event, 1) },
12222    isRightClick:  function(event) { return isButton(event, 2) },
12223
12224    element: function(event) {
12225      event = Event.extend(event);
12226
12227      var node          = event.target,
12228          type          = event.type,
12229          currentTarget = event.currentTarget;
12230
12231      if (currentTarget && currentTarget.tagName) {
12232        // Firefox screws up the "click" event when moving between radio buttons
12233        // via arrow keys. It also screws up the "load" and "error" events on images,
12234        // reporting the document as the target instead of the original image.
12235        if (type === 'load' || type === 'error' ||
12236          (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
12237            && currentTarget.type === 'radio'))
12238              node = currentTarget;
12239      }
12240      if (node.nodeType == Node.TEXT_NODE) node = node.parentNode;
12241      return Element.extend(node);
12242    },
12243
12244    findElement: function(event, expression) {
12245      var element = Event.element(event);
12246      if (!expression) return element;
12247      var elements = [element].concat(element.ancestors());
12248      return Selector.findElement(elements, expression, 0);
12249    },
12250
12251    pointer: function(event) {
12252      var docElement = document.documentElement,
12253      body = document.body || { scrollLeft: 0, scrollTop: 0 };
12254      return {
12255        x: event.pageX || (event.clientX +
12256          (docElement.scrollLeft || body.scrollLeft) -
12257          (docElement.clientLeft || 0)),
12258        y: event.pageY || (event.clientY +
12259          (docElement.scrollTop || body.scrollTop) -
12260          (docElement.clientTop || 0))
12261      };
12262    },
12263
12264    pointerX: function(event) { return Event.pointer(event).x },
12265    pointerY: function(event) { return Event.pointer(event).y },
12266
12267    stop: function(event) {
12268      Event.extend(event);
12269      event.preventDefault();
12270      event.stopPropagation();
12271      event.stopped = true;
12272    }
12273  };
12274})();
12275
12276Event.extend = (function() {
12277  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
12278    m[name] = Event.Methods[name].methodize();
12279    return m;
12280  });
12281
12282  if (Prototype.Browser.IE) {
12283    Object.extend(methods, {
12284      stopPropagation: function() { this.cancelBubble = true },
12285      preventDefault:  function() { this.returnValue = false },
12286      inspect: function() { return "[object Event]" }
12287    });
12288
12289    return function(event) {
12290      if (!event) return false;
12291      if (event._extendedByPrototype) return event;
12292
12293      event._extendedByPrototype = Prototype.emptyFunction;
12294      var pointer = Event.pointer(event);
12295      Object.extend(event, {
12296        target: event.srcElement,
12297        relatedTarget: Event.relatedTarget(event),
12298        pageX:  pointer.x,
12299        pageY:  pointer.y
12300      });
12301      return Object.extend(event, methods);
12302    };
12303
12304  } else {
12305    Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__'];
12306    Object.extend(Event.prototype, methods);
12307    return Prototype.K;
12308  }
12309})();
12310
12311Object.extend(Event, (function() {
12312  var cache = Event.cache;
12313
12314  function getEventID(element) {
12315    if (element._prototypeEventID) return element._prototypeEventID[0];
12316    arguments.callee.id = arguments.callee.id || 1;
12317    return element._prototypeEventID = [++arguments.callee.id];
12318  }
12319
12320  function getDOMEventName(eventName) {
12321    if (eventName && eventName.include(':')) return "dataavailable";
12322    return eventName;
12323  }
12324
12325  function getCacheForID(id) {
12326    return cache[id] = cache[id] || { };
12327  }
12328
12329  function getWrappersForEventName(id, eventName) {
12330    var c = getCacheForID(id);
12331    return c[eventName] = c[eventName] || [];
12332  }
12333
12334  function createWrapper(element, eventName, handler) {
12335    var id = getEventID(element);
12336    var c = getWrappersForEventName(id, eventName);
12337    if (c.pluck("handler").include(handler)) return false;
12338
12339    var wrapper = function(event) {
12340      if (!Event || !Event.extend ||
12341        (event.eventName && event.eventName != eventName))
12342          return false;
12343
12344      Event.extend(event);
12345      handler.call(element, event);
12346    };
12347
12348    wrapper.handler = handler;
12349    c.push(wrapper);
12350    return wrapper;
12351  }
12352
12353  function findWrapper(id, eventName, handler) {
12354    var c = getWrappersForEventName(id, eventName);
12355    return c.find(function(wrapper) { return wrapper.handler == handler });
12356  }
12357
12358  function destroyWrapper(id, eventName, handler) {
12359    var c = getCacheForID(id);
12360    if (!c[eventName]) return false;
12361    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
12362  }
12363
12364  function destroyCache() {
12365    for (var id in cache)
12366      for (var eventName in cache[id])
12367        cache[id][eventName] = null;
12368  }
12369
12370
12371  // Internet Explorer needs to remove event handlers on page unload
12372  // in order to avoid memory leaks.
12373  if (window.attachEvent) {
12374    window.attachEvent("onunload", destroyCache);
12375  }
12376
12377  // Safari has a dummy event handler on page unload so that it won't
12378  // use its bfcache. Safari <= 3.1 has an issue with restoring the "document"
12379  // object when page is returned to via the back button using its bfcache.
12380  if (Prototype.Browser.WebKit) {
12381    window.addEventListener('unload', Prototype.emptyFunction, false);
12382  }
12383
12384  return {
12385    observe: function(element, eventName, handler) {
12386      element = $(element);
12387      var name = getDOMEventName(eventName);
12388
12389      var wrapper = createWrapper(element, eventName, handler);
12390      if (!wrapper) return element;
12391
12392      if (element.addEventListener) {
12393        element.addEventListener(name, wrapper, false);
12394      } else {
12395        element.attachEvent("on" + name, wrapper);
12396      }
12397
12398      return element;
12399    },
12400
12401    stopObserving: function(element, eventName, handler) {
12402      element = $(element);
12403      var id = getEventID(element), name = getDOMEventName(eventName);
12404
12405      if (!handler && eventName) {
12406        getWrappersForEventName(id, eventName).each(function(wrapper) {
12407          element.stopObserving(eventName, wrapper.handler);
12408        });
12409        return element;
12410
12411      } else if (!eventName) {
12412        Object.keys(getCacheForID(id)).each(function(eventName) {
12413          element.stopObserving(eventName);
12414        });
12415        return element;
12416      }
12417
12418      var wrapper = findWrapper(id, eventName, handler);
12419      if (!wrapper) return element;
12420
12421      if (element.removeEventListener) {
12422        element.removeEventListener(name, wrapper, false);
12423      } else {
12424        element.detachEvent("on" + name, wrapper);
12425      }
12426
12427      destroyWrapper(id, eventName, handler);
12428
12429      return element;
12430    },
12431
12432    fire: function(element, eventName, memo) {
12433      element = $(element);
12434      if (element == document && document.createEvent && !element.dispatchEvent)
12435        element = document.documentElement;
12436
12437      var event;
12438      if (document.createEvent) {
12439        event = document.createEvent("HTMLEvents");
12440        event.initEvent("dataavailable", true, true);
12441      } else {
12442        event = document.createEventObject();
12443        event.eventType = "ondataavailable";
12444      }
12445
12446      event.eventName = eventName;
12447      event.memo = memo || { };
12448
12449      if (document.createEvent) {
12450        element.dispatchEvent(event);
12451      } else {
12452        element.fireEvent(event.eventType, event);
12453      }
12454
12455      return Event.extend(event);
12456    }
12457  };
12458})());
12459
12460Object.extend(Event, Event.Methods);
12461
12462Element.addMethods({
12463  fire:          Event.fire,
12464  observe:       Event.observe,
12465  stopObserving: Event.stopObserving
12466});
12467
12468Object.extend(document, {
12469  fire:          Element.Methods.fire.methodize(),
12470  observe:       Element.Methods.observe.methodize(),
12471  stopObserving: Element.Methods.stopObserving.methodize(),
12472  loaded:        false
12473});
12474
12475(function() {
12476  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
12477     Matthias Miller, Dean Edwards and John Resig. */
12478
12479  var timer;
12480
12481  function fireContentLoadedEvent() {
12482    if (document.loaded) return;
12483    if (timer) window.clearInterval(timer);
12484    document.fire("dom:loaded");
12485    document.loaded = true;
12486  }
12487
12488  if (document.addEventListener) {
12489    if (Prototype.Browser.WebKit) {
12490      timer = window.setInterval(function() {
12491        if (/loaded|complete/.test(document.readyState))
12492          fireContentLoadedEvent();
12493      }, 0);
12494
12495      Event.observe(window, "load", fireContentLoadedEvent);
12496
12497    } else {
12498      document.addEventListener("DOMContentLoaded",
12499        fireContentLoadedEvent, false);
12500    }
12501
12502  } else {
12503    document.write("<script id=__onDOMContentLoaded defer src=//:><\/script>");
12504    $("__onDOMContentLoaded").onreadystatechange = function() {
12505      if (this.readyState == "complete") {
12506        this.onreadystatechange = null;
12507        fireContentLoadedEvent();
12508      }
12509    };
12510  }
12511})();
12512/*------------------------------- DEPRECATED -------------------------------*/
12513
12514Hash.toQueryString = Object.toQueryString;
12515
12516var Toggle = { display: Element.toggle };
12517
12518Element.Methods.childOf = Element.Methods.descendantOf;
12519
12520var Insertion = {
12521  Before: function(element, content) {
12522    return Element.insert(element, {before:content});
12523  },
12524
12525  Top: function(element, content) {
12526    return Element.insert(element, {top:content});
12527  },
12528
12529  Bottom: function(element, content) {
12530    return Element.insert(element, {bottom:content});
12531  },
12532
12533  After: function(element, content) {
12534    return Element.insert(element, {after:content});
12535  }
12536};
12537
12538var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
12539
12540// This should be moved to script.aculo.us; notice the deprecated methods
12541// further below, that map to the newer Element methods.
12542var Position = {
12543  // set to true if needed, warning: firefox performance problems
12544  // NOT neeeded for page scrolling, only if draggable contained in
12545  // scrollable elements
12546  includeScrollOffsets: false,
12547
12548  // must be called before calling withinIncludingScrolloffset, every time the
12549  // page is scrolled
12550  prepare: function() {
12551    this.deltaX =  window.pageXOffset
12552                || document.documentElement.scrollLeft
12553                || document.body.scrollLeft
12554                || 0;
12555    this.deltaY =  window.pageYOffset
12556                || document.documentElement.scrollTop
12557                || document.body.scrollTop
12558                || 0;
12559  },
12560
12561  // caches x/y coordinate pair to use with overlap
12562  within: function(element, x, y) {
12563    if (this.includeScrollOffsets)
12564      return this.withinIncludingScrolloffsets(element, x, y);
12565    this.xcomp = x;
12566    this.ycomp = y;
12567    this.offset = Element.cumulativeOffset(element);
12568
12569    return (y >= this.offset[1] &&
12570            y <  this.offset[1] + element.offsetHeight &&
12571            x >= this.offset[0] &&
12572            x <  this.offset[0] + element.offsetWidth);
12573  },
12574
12575  withinIncludingScrolloffsets: function(element, x, y) {
12576    var offsetcache = Element.cumulativeScrollOffset(element);
12577
12578    this.xcomp = x + offsetcache[0] - this.deltaX;
12579    this.ycomp = y + offsetcache[1] - this.deltaY;
12580    this.offset = Element.cumulativeOffset(element);
12581
12582    return (this.ycomp >= this.offset[1] &&
12583            this.ycomp <  this.offset[1] + element.offsetHeight &&
12584            this.xcomp >= this.offset[0] &&
12585            this.xcomp <  this.offset[0] + element.offsetWidth);
12586  },
12587
12588  // within must be called directly before
12589  overlap: function(mode, element) {
12590    if (!mode) return 0;
12591    if (mode == 'vertical')
12592      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
12593        element.offsetHeight;
12594    if (mode == 'horizontal')
12595      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
12596        element.offsetWidth;
12597  },
12598
12599  // Deprecation layer -- use newer Element methods now (1.5.2).
12600
12601  cumulativeOffset: Element.Methods.cumulativeOffset,
12602
12603  positionedOffset: Element.Methods.positionedOffset,
12604
12605  absolutize: function(element) {
12606    Position.prepare();
12607    return Element.absolutize(element);
12608  },
12609
12610  relativize: function(element) {
12611    Position.prepare();
12612    return Element.relativize(element);
12613  },
12614
12615  realOffset: Element.Methods.cumulativeScrollOffset,
12616
12617  offsetParent: Element.Methods.getOffsetParent,
12618
12619  page: Element.Methods.viewportOffset,
12620
12621  clone: function(source, target, options) {
12622    options = options || { };
12623    return Element.clonePosition(target, source, options);
12624  }
12625};
12626
12627/*--------------------------------------------------------------------------*/
12628
12629if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
12630  function iter(name) {
12631    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
12632  }
12633
12634  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
12635  function(element, className) {
12636    className = className.toString().strip();
12637    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
12638    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
12639  } : function(element, className) {
12640    className = className.toString().strip();
12641    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
12642    if (!classNames && !className) return elements;
12643
12644    var nodes = $(element).getElementsByTagName('*');
12645    className = ' ' + className + ' ';
12646
12647    for (var i = 0, child, cn; child = nodes[i]; i++) {
12648      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
12649          (classNames && classNames.all(function(name) {
12650            return !name.toString().blank() && cn.include(' ' + name + ' ');
12651          }))))
12652        elements.push(Element.extend(child));
12653    }
12654    return elements;
12655  };
12656
12657  return function(className, parentElement) {
12658    return $(parentElement || document.body).getElementsByClassName(className);
12659  };
12660}(Element.Methods);
12661
12662/*--------------------------------------------------------------------------*/
12663
12664Element.ClassNames = Class.create();
12665Element.ClassNames.prototype = {
12666  initialize: function(element) {
12667    this.element = $(element);
12668  },
12669
12670  _each: function(iterator) {
12671    this.element.className.split(/\s+/).select(function(name) {
12672      return name.length > 0;
12673    })._each(iterator);
12674  },
12675
12676  set: function(className) {
12677    this.element.className = className;
12678  },
12679
12680  add: function(classNameToAdd) {
12681    if (this.include(classNameToAdd)) return;
12682    this.set($A(this).concat(classNameToAdd).join(' '));
12683  },
12684
12685  remove: function(classNameToRemove) {
12686    if (!this.include(classNameToRemove)) return;
12687    this.set($A(this).without(classNameToRemove).join(' '));
12688  },
12689
12690  toString: function() {
12691    return $A(this).join(' ');
12692  }
12693};
12694
12695Object.extend(Element.ClassNames.prototype, Enumerable);
12696
12697/*--------------------------------------------------------------------------*/
12698
12699Element.addMethods();
12700