PageSourceSearch

https://www.ergoneos.fr/js/prototype/prototype.js

js ergoneos.fr collected 2026-10-01 02:10:41 UTC 199,855 bytes, 7,590 lines download raw bytes

1/*  Prototype JavaScript framework, version 1.7.3
2 *  (c) 2005-2010 Sam Stephenson
3 *
4 *  Prototype is freely distributable under the terms of an MIT-style license.
5 *  For details, see the Prototype web site: http://www.prototypejs.org/
6 *
7 *--------------------------------------------------------------------------*/
8
9var Prototype = {
10
11  Version: '1.7.3',
12
13  Browser: (function(){
14    var ua = navigator.userAgent;
15    var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
16    return {
17      IE:             !!window.attachEvent && !isOpera,
18      Opera:          isOpera,
19      WebKit:         ua.indexOf('AppleWebKit/') > -1,
20      Gecko:          ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1,
21      MobileSafari:   /Apple.*Mobile/.test(ua)
22    }
23  })(),
24
25  BrowserFeatures: {
26    XPath: !!document.evaluate,
27
28    SelectorsAPI: !!document.querySelector,
29
30    ElementExtensions: (function() {
31      var constructor = window.Element || window.HTMLElement;
32      return !!(constructor && constructor.prototype);
33    })(),
34    SpecificElementExtensions: (function() {
35      if (typeof window.HTMLDivElement !== 'undefined')
36        return true;
37
38      var div = document.createElement('div'),
39          form = document.createElement('form'),
40          isSupported = false;
41
42      if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) {
43        isSupported = true;
44      }
45
46      div = form = null;
47
48      return isSupported;
49    })()
50  },
51
52  ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script\\s*>',
53  JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/,
54
55  emptyFunction: function() { },
56
57  K: function(x) { return x }
58};
59
60if (Prototype.Browser.MobileSafari)
61  Prototype.BrowserFeatures.SpecificElementExtensions = false;
62/* Based on Alex Arnell's inheritance implementation. */
63
64var Class = (function() {
65
66  var IS_DONTENUM_BUGGY = (function(){
67    for (var p in { toString: 1 }) {
68      if (p === 'toString') return false;
69    }
70    return true;
71  })();
72
73  function subclass() {};
74  function create() {
75    var parent = null, properties = $A(arguments);
76    if (Object.isFunction(properties[0]))
77      parent = properties.shift();
78
79    function klass() {
80      this.initialize.apply(this, arguments);
81    }
82
83    Object.extend(klass, Class.Methods);
84    klass.superclass = parent;
85    klass.subclasses = [];
86
87    if (parent) {
88      subclass.prototype = parent.prototype;
89      klass.prototype = new subclass;
90      parent.subclasses.push(klass);
91    }
92
93    for (var i = 0, length = properties.length; i < length; i++)
94      klass.addMethods(properties[i]);
95
96    if (!klass.prototype.initialize)
97      klass.prototype.initialize = Prototype.emptyFunction;
98
99    klass.prototype.constructor = klass;
100    return klass;
101  }
102
103  function addMethods(source) {
104    var ancestor   = this.superclass && this.superclass.prototype,
105        properties = Object.keys(source);
106
107    if (IS_DONTENUM_BUGGY) {
108      if (source.toString != Object.prototype.toString)
109        properties.push("toString");
110      if (source.valueOf != Object.prototype.valueOf)
111        properties.push("valueOf");
112    }
113
114    for (var i = 0, length = properties.length; i < length; i++) {
115      var property = properties[i], value = source[property];
116      if (ancestor && Object.isFunction(value) &&
117          value.argumentNames()[0] == "$super") {
118        var method = value;
119        value = (function(m) {
120          return function() { return ancestor[m].apply(this, arguments); };
121        })(property).wrap(method);
122
123        value.valueOf = (function(method) {
124          return function() { return method.valueOf.call(method); };
125        })(method);
126
127        value.toString = (function(method) {
128          return function() { return method.toString.call(method); };
129        })(method);
130      }
131      this.prototype[property] = value;
132    }
133
134    return this;
135  }
136
137  return {
138    create: create,
139    Methods: {
140      addMethods: addMethods
141    }
142  };
143})();
144(function() {
145
146  var _toString = Object.prototype.toString,
147      _hasOwnProperty = Object.prototype.hasOwnProperty,
148      NULL_TYPE = 'Null',
149      UNDEFINED_TYPE = 'Undefined',
150      BOOLEAN_TYPE = 'Boolean',
151      NUMBER_TYPE = 'Number',
152      STRING_TYPE = 'String',
153      OBJECT_TYPE = 'Object',
154      FUNCTION_CLASS = '[object Function]',
155      BOOLEAN_CLASS = '[object Boolean]',
156      NUMBER_CLASS = '[object Number]',
157      STRING_CLASS = '[object String]',
158      ARRAY_CLASS = '[object Array]',
159      DATE_CLASS = '[object Date]',
160      NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON &&
161        typeof JSON.stringify === 'function' &&
162        JSON.stringify(0) === '0' &&
163        typeof JSON.stringify(Prototype.K) === 'undefined';
164
165
166
167  var DONT_ENUMS = ['toString', 'toLocaleString', 'valueOf',
168   'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'];
169
170  var IS_DONTENUM_BUGGY = (function(){
171    for (var p in { toString: 1 }) {
172      if (p === 'toString') return false;
173    }
174    return true;
175  })();
176
177  function Type(o) {
178    switch(o) {
179      case null: return NULL_TYPE;
180      case (void 0): return UNDEFINED_TYPE;
181    }
182    var type = typeof o;
183    switch(type) {
184      case 'boolean': return BOOLEAN_TYPE;
185      case 'number':  return NUMBER_TYPE;
186      case 'string':  return STRING_TYPE;
187    }
188    return OBJECT_TYPE;
189  }
190
191  function extend(destination, source) {
192    for (var property in source)
193      destination[property] = source[property];
194    return destination;
195  }
196
197  function inspect(object) {
198    try {
199      if (isUndefined(object)) return 'undefined';
200      if (object === null) return 'null';
201      return object.inspect ? object.inspect() : String(object);
202    } catch (e) {
203      if (e instanceof RangeError) return '...';
204      throw e;
205    }
206  }
207
208  function toJSON(value) {
209    return Str('', { '': value }, []);
210  }
211
212  function Str(key, holder, stack) {
213    var value = holder[key];
214    if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') {
215      value = value.toJSON(key);
216    }
217
218    var _class = _toString.call(value);
219
220    switch (_class) {
221      case NUMBER_CLASS:
222      case BOOLEAN_CLASS:
223      case STRING_CLASS:
224        value = value.valueOf();
225    }
226
227    switch (value) {
228      case null: return 'null';
229      case true: return 'true';
230      case false: return 'false';
231    }
232
233    var type = typeof value;
234    switch (type) {
235      case 'string':
236        return value.inspect(true);
237      case 'number':
238        return isFinite(value) ? String(value) : 'null';
239      case 'object':
240
241        for (var i = 0, length = stack.length; i < length; i++) {
242          if (stack[i] === value) {
243            throw new TypeError("Cyclic reference to '" + value + "' in object");
244          }
245        }
246        stack.push(value);
247
248        var partial = [];
249        if (_class === ARRAY_CLASS) {
250          for (var i = 0, length = value.length; i < length; i++) {
251            var str = Str(i, value, stack);
252            partial.push(typeof str === 'undefined' ? 'null' : str);
253          }
254          partial = '[' + partial.join(',') + ']';
255        } else {
256          var keys = Object.keys(value);
257          for (var i = 0, length = keys.length; i < length; i++) {
258            var key = keys[i], str = Str(key, value, stack);
259            if (typeof str !== "undefined") {
260               partial.push(key.inspect(true)+ ':' + str);
261             }
262          }
263          partial = '{' + partial.join(',') + '}';
264        }
265        stack.pop();
266        return partial;
267    }
268  }
269
270  function stringify(object) {
271    return JSON.stringify(object);
272  }
273
274  function toQueryString(object) {
275    return $H(object).toQueryString();
276  }
277
278  function toHTML(object) {
279    return object && object.toHTML ? object.toHTML() : String.interpret(object);
280  }
281
282  function keys(object) {
283    if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); }
284    var results = [];
285    for (var property in object) {
286      if (_hasOwnProperty.call(object, property))
287        results.push(property);
288    }
289
290    if (IS_DONTENUM_BUGGY) {
291      for (var i = 0; property = DONT_ENUMS[i]; i++) {
292        if (_hasOwnProperty.call(object, property))
293          results.push(property);
294      }
295    }
296
297    return results;
298  }
299
300  function values(object) {
301    var results = [];
302    for (var property in object)
303      results.push(object[property]);
304    return results;
305  }
306
307  function clone(object) {
308    return extend({ }, object);
309  }
310
311  function isElement(object) {
312    return !!(object && object.nodeType == 1);
313  }
314
315  function isArray(object) {
316    return _toString.call(object) === ARRAY_CLASS;
317  }
318
319  var hasNativeIsArray = (typeof Array.isArray == 'function')
320    && Array.isArray([]) && !Array.isArray({});
321
322  if (hasNativeIsArray) {
323    isArray = Array.isArray;
324  }
325
326  function isHash(object) {
327    return object instanceof Hash;
328  }
329
330  function isFunction(object) {
331    return _toString.call(object) === FUNCTION_CLASS;
332  }
333
334  function isString(object) {
335    return _toString.call(object) === STRING_CLASS;
336  }
337
338  function isNumber(object) {
339    return _toString.call(object) === NUMBER_CLASS;
340  }
341
342  function isDate(object) {
343    return _toString.call(object) === DATE_CLASS;
344  }
345
346  function isUndefined(object) {
347    return typeof object === "undefined";
348  }
349
350  extend(Object, {
351    extend:        extend,
352    inspect:       inspect,
353    toJSON:        NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON,
354    toQueryString: toQueryString,
355    toHTML:        toHTML,
356    keys:          Object.keys || keys,
357    values:        values,
358    clone:         clone,
359    isElement:     isElement,
360    isArray:       isArray,
361    isHash:        isHash,
362    isFunction:    isFunction,
363    isString:      isString,
364    isNumber:      isNumber,
365    isDate:        isDate,
366    isUndefined:   isUndefined
367  });
368})();
369Object.extend(Function.prototype, (function() {
370  var slice = Array.prototype.slice;
371
372  function update(array, args) {
373    var arrayLength = array.length, length = args.length;
374    while (length--) array[arrayLength + length] = args[length];
375    return array;
376  }
377
378  function merge(array, args) {
379    array = slice.call(array, 0);
380    return update(array, args);
381  }
382
383  function argumentNames() {
384    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
385      .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
386      .replace(/\s+/g, '').split(',');
387    return names.length == 1 && !names[0] ? [] : names;
388  }
389
390
391  function bind(context) {
392    if (arguments.length < 2 && Object.isUndefined(arguments[0]))
393      return this;
394
395    if (!Object.isFunction(this))
396      throw new TypeError("The object is not callable.");
397
398    var nop = function() {};
399    var __method = this, args = slice.call(arguments, 1);
400
401    var bound = function() {
402      var a = merge(args, arguments);
403      var c = this instanceof bound ? this : context;
404      return __method.apply(c, a);
405    };
406
407    nop.prototype   = this.prototype;
408    bound.prototype = new nop();
409
410    return bound;
411  }
412
413  function bindAsEventListener(context) {
414    var __method = this, args = slice.call(arguments, 1);
415    return function(event) {
416      var a = update([event || window.event], args);
417      return __method.apply(context, a);
418    }
419  }
420
421  function curry() {
422    if (!arguments.length) return this;
423    var __method = this, args = slice.call(arguments, 0);
424    return function() {
425      var a = merge(args, arguments);
426      return __method.apply(this, a);
427    }
428  }
429
430  function delay(timeout) {
431    var __method = this, args = slice.call(arguments, 1);
432    timeout = timeout * 1000;
433    return window.setTimeout(function() {
434      return __method.apply(__method, args);
435    }, timeout);
436  }
437
438  function defer() {
439    var args = update([0.01], arguments);
440    return this.delay.apply(this, args);
441  }
442
443  function wrap(wrapper) {
444    var __method = this;
445    return function() {
446      var a = update([__method.bind(this)], arguments);
447      return wrapper.apply(this, a);
448    }
449  }
450
451  function methodize() {
452    if (this._methodized) return this._methodized;
453    var __method = this;
454    return this._methodized = function() {
455      var a = update([this], arguments);
456      return __method.apply(null, a);
457    };
458  }
459
460  var extensions = {
461    argumentNames:       argumentNames,
462    bindAsEventListener: bindAsEventListener,
463    curry:               curry,
464    delay:               delay,
465    defer:               defer,
466    wrap:                wrap,
467    methodize:           methodize
468  };
469
470  if (!Function.prototype.bind)
471    extensions.bind = bind;
472
473  return extensions;
474})());
475
476
477
478(function(proto) {
479
480
481  function toISOString() {
482    return this.getUTCFullYear() + '-' +
483      (this.getUTCMonth() + 1).toPaddedString(2) + '-' +
484      this.getUTCDate().toPaddedString(2) + 'T' +
485      this.getUTCHours().toPaddedString(2) + ':' +
486      this.getUTCMinutes().toPaddedString(2) + ':' +
487      this.getUTCSeconds().toPaddedString(2) + 'Z';
488  }
489
490
491  function toJSON() {
492    return this.toISOString();
493  }
494
495  if (!proto.toISOString) proto.toISOString = toISOString;
496  if (!proto.toJSON) proto.toJSON = toJSON;
497
498})(Date.prototype);
499
500
501RegExp.prototype.match = RegExp.prototype.test;
502
503RegExp.escape = function(str) {
504  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
505};
506var PeriodicalExecuter = Class.create({
507  initialize: function(callback, frequency) {
508    this.callback = callback;
509    this.frequency = frequency;
510    this.currentlyExecuting = false;
511
512    this.registerCallback();
513  },
514
515  registerCallback: function() {
516    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
517  },
518
519  execute: function() {
520    this.callback(this);
521  },
522
523  stop: function() {
524    if (!this.timer) return;
525    clearInterval(this.timer);
526    this.timer = null;
527  },
528
529  onTimerEvent: function() {
530    if (!this.currentlyExecuting) {
531      try {
532        this.currentlyExecuting = true;
533        this.execute();
534        this.currentlyExecuting = false;
535      } catch(e) {
536        this.currentlyExecuting = false;
537        throw e;
538      }
539    }
540  }
541});
542Object.extend(String, {
543  interpret: function(value) {
544    return value == null ? '' : String(value);
545  },
546  specialChar: {
547    '\b': '\\b',
548    '\t': '\\t',
549    '\n': '\\n',
550    '\f': '\\f',
551    '\r': '\\r',
552    '\\': '\\\\'
553  }
554});
555
556Object.extend(String.prototype, (function() {
557  var NATIVE_JSON_PARSE_SUPPORT = window.JSON &&
558    typeof JSON.parse === 'function' &&
559    JSON.parse('{"test": true}').test;
560
561  function prepareReplacement(replacement) {
562    if (Object.isFunction(replacement)) return replacement;
563    var template = new Template(replacement);
564    return function(match) { return template.evaluate(match) };
565  }
566
567  function isNonEmptyRegExp(regexp) {
568    return regexp.source && regexp.source !== '(?:)';
569  }
570
571
572  function gsub(pattern, replacement) {
573    var result = '', source = this, match;
574    replacement = prepareReplacement(replacement);
575
576    if (Object.isString(pattern))
577      pattern = RegExp.escape(pattern);
578
579    if (!(pattern.length || isNonEmptyRegExp(pattern))) {
580      replacement = replacement('');
581      return replacement + source.split('').join(replacement) + replacement;
582    }
583
584    while (source.length > 0) {
585      match = source.match(pattern)
586      if (match && match[0].length > 0) {
587        result += source.slice(0, match.index);
588        result += String.interpret(replacement(match));
589        source  = source.slice(match.index + match[0].length);
590      } else {
591        result += source, source = '';
592      }
593    }
594    return result;
595  }
596
597  function sub(pattern, replacement, count) {
598    replacement = prepareReplacement(replacement);
599    count = Object.isUndefined(count) ? 1 : count;
600
601    return this.gsub(pattern, function(match) {
602      if (--count < 0) return match[0];
603      return replacement(match);
604    });
605  }
606
607  function scan(pattern, iterator) {
608    this.gsub(pattern, iterator);
609    return String(this);
610  }
611
612  function truncate(length, truncation) {
613    length = length || 30;
614    truncation = Object.isUndefined(truncation) ? '...' : truncation;
615    return this.length > length ?
616      this.slice(0, length - truncation.length) + truncation : String(this);
617  }
618
619  function strip() {
620    return this.replace(/^\s+/, '').replace(/\s+$/, '');
621  }
622
623  function stripTags() {
624    return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?(\/)?>|<\/\w+>/gi, '');
625  }
626
627  function stripScripts() {
628    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
629  }
630
631  function extractScripts() {
632    var matchAll = new RegExp(Prototype.ScriptFragment, 'img'),
633        matchOne = new RegExp(Prototype.ScriptFragment, 'im');
634    return (this.match(matchAll) || []).map(function(scriptTag) {
635      return (scriptTag.match(matchOne) || ['', ''])[1];
636    });
637  }
638
639  function evalScripts() {
640    return this.extractScripts().map(function(script) { return eval(script); });
641  }
642
643  function escapeHTML() {
644    return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
645  }
646
647  function unescapeHTML() {
648    return this.stripTags().replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
649  }
650
651
652  function toQueryParams(separator) {
653    var match = this.strip().match(/([^?#]*)(#.*)?$/);
654    if (!match) return { };
655
656    return match[1].split(separator || '&').inject({ }, function(hash, pair) {
657      if ((pair = pair.split('='))[0]) {
658        var key = decodeURIComponent(pair.shift()),
659            value = pair.length > 1 ? pair.join('=') : pair[0];
660
661        if (value != undefined) {
662          value = value.gsub('+', ' ');
663          value = decodeURIComponent(value);
664        }
665
666        if (key in hash) {
667          if (!Object.isArray(hash[key])) hash[key] = [hash[key]];
668          hash[key].push(value);
669        }
670        else hash[key] = value;
671      }
672      return hash;
673    });
674  }
675
676  function toArray() {
677    return this.split('');
678  }
679
680  function succ() {
681    return this.slice(0, this.length - 1) +
682      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
683  }
684
685  function times(count) {
686    return count < 1 ? '' : new Array(count + 1).join(this);
687  }
688
689  function camelize() {
690    return this.replace(/-+(.)?/g, function(match, chr) {
691      return chr ? chr.toUpperCase() : '';
692    });
693  }
694
695  function capitalize() {
696    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
697  }
698
699  function underscore() {
700    return this.replace(/::/g, '/')
701               .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
702               .replace(/([a-z\d])([A-Z])/g, '$1_$2')
703               .replace(/-/g, '_')
704               .toLowerCase();
705  }
706
707  function dasherize() {
708    return this.replace(/_/g, '-');
709  }
710
711  function inspect(useDoubleQuotes) {
712    var escapedString = this.replace(/[\x00-\x1f\\]/g, function(ch
712aracter) {
713      if (character in String.specialChar) {
714        return String.specialChar[character];
715      }
716      return '\\u00' + character.charCodeAt().toPaddedString(2, 16);
717    });
718    if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
719    return "'" + escapedString.replace(/'/g, '\\\'') + "'";
720  }
721
722  function unfilterJSON(filter) {
723    return this.replace(filter || Prototype.JSONFilter, '$1');
724  }
725
726  function isJSON() {
727    var str = this;
728    if (str.blank()) return false;
729    str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');
730    str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
731    str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
732    return (/^[\],:{}\s]*$/).test(str);
733  }
734
735  function evalJSON(sanitize) {
736    var json = this.unfilterJSON(),
737        cx = /[\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff\u0000]/g;
738    if (cx.test(json)) {
739      json = json.replace(cx, function (a) {
740        return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
741      });
742    }
743    try {
744      if (!sanitize || json.isJSON()) return eval('(' + json + ')');
745    } catch (e) { }
746    throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
747  }
748
749  function parseJSON() {
750    var json = this.unfilterJSON();
751    return JSON.parse(json);
752  }
753
754  function include(pattern) {
755    return this.indexOf(pattern) > -1;
756  }
757
758  function startsWith(pattern, position) {
759    position = Object.isNumber(position) ? position : 0;
760    return this.lastIndexOf(pattern, position) === position;
761  }
762
763  function endsWith(pattern, position) {
764    pattern = String(pattern);
765    position = Object.isNumber(position) ? position : this.length;
766    if (position < 0) position = 0;
767    if (position > this.length) position = this.length;
768    var d = position - pattern.length;
769    return d >= 0 && this.indexOf(pattern, d) === d;
770  }
771
772  function empty() {
773    return this == '';
774  }
775
776  function blank() {
777    return /^\s*$/.test(this);
778  }
779
780  function interpolate(object, pattern) {
781    return new Template(this, pattern).evaluate(object);
782  }
783
784  return {
785    gsub:           gsub,
786    sub:            sub,
787    scan:           scan,
788    truncate:       truncate,
789    strip:          String.prototype.trim || strip,
790    stripTags:      stripTags,
791    stripScripts:   stripScripts,
792    extractScripts: extractScripts,
793    evalScripts:    evalScripts,
794    escapeHTML:     escapeHTML,
795    unescapeHTML:   unescapeHTML,
796    toQueryParams:  toQueryParams,
797    parseQuery:     toQueryParams,
798    toArray:        toArray,
799    succ:           succ,
800    times:          times,
801    camelize:       camelize,
802    capitalize:     capitalize,
803    underscore:     underscore,
804    dasherize:      dasherize,
805    inspect:        inspect,
806    unfilterJSON:   unfilterJSON,
807    isJSON:         isJSON,
808    evalJSON:       NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON,
809    include:        include,
810    startsWith:     String.prototype.startsWith || startsWith,
811    endsWith:       String.prototype.endsWith || endsWith,
812    empty:          empty,
813    blank:          blank,
814    interpolate:    interpolate
815  };
816})());
817
818var Template = Class.create({
819  initialize: function(template, pattern) {
820    this.template = template.toString();
821    this.pattern = pattern || Template.Pattern;
822  },
823
824  evaluate: function(object) {
825    if (object && Object.isFunction(object.toTemplateReplacements))
826      object = object.toTemplateReplacements();
827
828    return this.template.gsub(this.pattern, function(match) {
829      if (object == null) return (match[1] + '');
830
831      var before = match[1] || '';
832      if (before == '\\') return match[2];
833
834      var ctx = object, expr = match[3],
835          pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
836
837      match = pattern.exec(expr);
838      if (match == null) return before;
839
840      while (match != null) {
841        var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
842        ctx = ctx[comp];
843        if (null == ctx || '' == match[3]) break;
844        expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
845        match = pattern.exec(expr);
846      }
847
848      return before + String.interpret(ctx);
849    });
850  }
851});
852Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
853
854var $break = { };
855
856var Enumerable = (function() {
857  function each(iterator, context) {
858    try {
859      this._each(iterator, context);
860    } catch (e) {
861      if (e != $break) throw e;
862    }
863    return this;
864  }
865
866  function eachSlice(number, iterator, context) {
867    var index = -number, slices = [], array = this.toArray();
868    if (number < 1) return array;
869    while ((index += number) < array.length)
870      slices.push(array.slice(index, index+number));
871    return slices.collect(iterator, context);
872  }
873
874  function all(iterator, context) {
875    iterator = iterator || Prototype.K;
876    var result = true;
877    this.each(function(value, index) {
878      result = result && !!iterator.call(context, value, index, this);
879      if (!result) throw $break;
880    }, this);
881    return result;
882  }
883
884  function any(iterator, context) {
885    iterator = iterator || Prototype.K;
886    var result = false;
887    this.each(function(value, index) {
888      if (result = !!iterator.call(context, value, index, this))
889        throw $break;
890    }, this);
891    return result;
892  }
893
894  function collect(iterator, context) {
895    iterator = iterator || Prototype.K;
896    var results = [];
897    this.each(function(value, index) {
898      results.push(iterator.call(context, value, index, this));
899    }, this);
900    return results;
901  }
902
903  function detect(iterator, context) {
904    var result;
905    this.each(function(value, index) {
906      if (iterator.call(context, value, index, this)) {
907        result = value;
908        throw $break;
909      }
910    }, this);
911    return result;
912  }
913
914  function findAll(iterator, context) {
915    var results = [];
916    this.each(function(value, index) {
917      if (iterator.call(context, value, index, this))
918        results.push(value);
919    }, this);
920    return results;
921  }
922
923  function grep(filter, iterator, context) {
924    iterator = iterator || Prototype.K;
925    var results = [];
926
927    if (Object.isString(filter))
928      filter = new RegExp(RegExp.escape(filter));
929
930    this.each(function(value, index) {
931      if (filter.match(value))
932        results.push(iterator.call(context, value, index, this));
933    }, this);
934    return results;
935  }
936
937  function include(object) {
938    if (Object.isFunction(this.indexOf) && this.indexOf(object) != -1)
939      return true;
940
941    var found = false;
942    this.each(function(value) {
943      if (value == object) {
944        found = true;
945        throw $break;
946      }
947    });
948    return found;
949  }
950
951  function inGroupsOf(number, fillWith) {
952    fillWith = Object.isUndefined(fillWith) ? null : fillWith;
953    return this.eachSlice(number, function(slice) {
954      while(slice.length < number) slice.push(fillWith);
955      return slice;
956    });
957  }
958
959  function inject(memo, iterator, context) {
960    this.each(function(value, index) {
961      memo = iterator.call(context, memo, value, index, this);
962    }, this);
963    return memo;
964  }
965
966  function invoke(method) {
967    var args = $A(arguments).slice(1);
968    return this.map(function(value) {
969      return value[method].apply(value, args);
970    });
971  }
972
973  function max(iterator, context) {
974    iterator = iterator || Prototype.K;
975    var result;
976    this.each(function(value, index) {
977      value = iterator.call(context, value, index, this);
978      if (result == null || value >= result)
979        result = value;
980    }, this);
981    return result;
982  }
983
984  function min(iterator, context) {
985    iterator = iterator || Prototype.K;
986    var result;
987    this.each(function(value, index) {
988      value = iterator.call(context, value, index, this);
989      if (result == null || value < result)
990        result = value;
991    }, this);
992    return result;
993  }
994
995  function partition(iterator, context) {
996    iterator = iterator || Prototype.K;
997    var trues = [], falses = [];
998    this.each(function(value, index) {
999      (iterator.call(context, value, index, this) ?
1000        trues : falses).push(value);
1001    }, this);
1002    return [trues, falses];
1003  }
1004
1005  function pluck(property) {
1006    var results = [];
1007    this.each(function(value) {
1008      results.push(value[property]);
1009    });
1010    return results;
1011  }
1012
1013  function reject(iterator, context) {
1014    var results = [];
1015    this.each(function(value, index) {
1016      if (!iterator.call(context, value, index, this))
1017        results.push(value);
1018    }, this);
1019    return results;
1020  }
1021
1022  function sortBy(iterator, context) {
1023    return this.map(function(value, index) {
1024      return {
1025        value: value,
1026        criteria: iterator.call(context, value, index, this)
1027      };
1028    }, this).sort(function(left, right) {
1029      var a = left.criteria, b = right.criteria;
1030      return a < b ? -1 : a > b ? 1 : 0;
1031    }).pluck('value');
1032  }
1033
1034  function toArray() {
1035    return this.map();
1036  }
1037
1038  function zip() {
1039    var iterator = Prototype.K, args = $A(arguments);
1040    if (Object.isFunction(args.last()))
1041      iterator = args.pop();
1042
1043    var collections = [this].concat(args).map($A);
1044    return this.map(function(value, index) {
1045      return iterator(collections.pluck(index));
1046    });
1047  }
1048
1049  function size() {
1050    return this.toArray().length;
1051  }
1052
1053  function inspect() {
1054    return '#<Enumerable:' + this.toArray().inspect() + '>';
1055  }
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065  return {
1066    each:       each,
1067    eachSlice:  eachSlice,
1068    all:        all,
1069    every:      all,
1070    any:        any,
1071    some:       any,
1072    collect:    collect,
1073    map:        collect,
1074    detect:     detect,
1075    findAll:    findAll,
1076    select:     findAll,
1077    filter:     findAll,
1078    grep:       grep,
1079    include:    include,
1080    member:     include,
1081    inGroupsOf: inGroupsOf,
1082    inject:     inject,
1083    invoke:     invoke,
1084    max:        max,
1085    min:        min,
1086    partition:  partition,
1087    pluck:      pluck,
1088    reject:     reject,
1089    sortBy:     sortBy,
1090    toArray:    toArray,
1091    entries:    toArray,
1092    zip:        zip,
1093    size:       size,
1094    inspect:    inspect,
1095    find:       detect
1096  };
1097})();
1098
1099function $A(iterable) {
1100  if (!iterable) return [];
1101  if ('toArray' in Object(iterable)) return iterable.toArray();
1102  var length = iterable.length || 0, results = new Array(length);
1103  while (length--) results[length] = iterable[length];
1104  return results;
1105}
1106
1107
1108function $w(string) {
1109  if (!Object.isString(string)) return [];
1110  string = string.strip();
1111  return string ? string.split(/\s+/) : [];
1112}
1113
1114Array.from = Array.from || $A;
1115
1116
1117(function() {
1118  var arrayProto = Array.prototype,
1119      slice = arrayProto.slice,
1120      _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
1121
1122  function each(iterator, context) {
1123    for (var i = 0, length = this.length >>> 0; i < length; i++) {
1124      if (i in this) iterator.call(context, this[i], i, this);
1125    }
1126  }
1127  if (!_each) _each = each;
1128
1129  function clear() {
1130    this.length = 0;
1131    return this;
1132  }
1133
1134  function first() {
1135    return this[0];
1136  }
1137
1138  function last() {
1139    return this[this.length - 1];
1140  }
1141
1142  function compact() {
1143    return this.select(function(value) {
1144      return value != null;
1145    });
1146  }
1147
1148  function flatten() {
1149    return this.inject([], function(array, value) {
1150      if (Object.isArray(value))
1151        return array.concat(value.flatten());
1152      array.push(value);
1153      return array;
1154    });
1155  }
1156
1157  function without() {
1158    var values = slice.call(arguments, 0);
1159    return this.select(function(value) {
1160      return !values.include(value);
1161    });
1162  }
1163
1164  function reverse(inline) {
1165    return (inline === false ? this.toArray() : this)._reverse();
1166  }
1167
1168  function uniq(sorted) {
1169    return this.inject([], function(array, value, index) {
1170      if (0 == index || (sorted ? array.last() != value : !array.include(value)))
1171        array.push(value);
1172      return array;
1173    });
1174  }
1175
1176  function intersect(array) {
1177    return this.uniq().findAll(function(item) {
1178      return array.indexOf(item) !== -1;
1179    });
1180  }
1181
1182
1183  function clone() {
1184    return slice.call(this, 0);
1185  }
1186
1187  function size() {
1188    return this.length;
1189  }
1190
1191  function inspect() {
1192    return '[' + this.map(Object.inspect).join(', ') + ']';
1193  }
1194
1195  function indexOf(item, i) {
1196    if (this == null) throw new TypeError();
1197
1198    var array = Object(this), length = array.length >>> 0;
1199    if (length === 0) return -1;
1200
1201    i = Number(i);
1202    if (isNaN(i)) {
1203      i = 0;
1204    } else if (i !== 0 && isFinite(i)) {
1205      i = (i > 0 ? 1 : -1) * Math.floor(Math.abs(i));
1206    }
1207
1208    if (i > length) return -1;
1209
1210    var k = i >= 0 ? i : Math.max(length - Math.abs(i), 0);
1211    for (; k < length; k++)
1212      if (k in array && array[k] === item) return k;
1213    return -1;
1214  }
1215
1216
1217  function lastIndexOf(item, i) {
1218    if (this == null) throw new TypeError();
1219
1220    var array = Object(this), length = array.length >>> 0;
1221    if (length === 0) return -1;
1222
1223    if (!Object.isUndefined(i)) {
1224      i = Number(i);
1225      if (isNaN(i)) {
1226        i = 0;
1227      } else if (i !== 0 && isFinite(i)) {
1228        i = (i > 0 ? 1 : -1) * Math.floor(Math.abs(i));
1229      }
1230    } else {
1231      i = length;
1232    }
1233
1234    var k = i >= 0 ? Math.min(i, length - 1) :
1235     length - Math.abs(i);
1236
1237    for (; k >= 0; k--)
1238      if (k in array && array[k] === item) return k;
1239    return -1;
1240  }
1241
1242  function concat(_) {
1243    var array = [], items = slice.call(arguments, 0), item, n = 0;
1244    items.unshift(this);
1245    for (var i = 0, length = items.length; i < length; i++) {
1246      item = items[i];
1247      if (Object.isArray(item) && !('callee' in item)) {
1248        for (var j = 0, arrayLength = item.length; j < arrayLength; j++) {
1249          if (j in item) array[n] = item[j];
1250          n++;
1251        }
1252      } else {
1253        array[n++] = item;
1254      }
1255    }
1256    array.length = n;
1257    return array;
1258  }
1259
1260
1261  function wrapNative(method) {
1262    return function() {
1263      if (arguments.length === 0) {
1264        return method.call(this, Prototype.K);
1265      } else if (arguments[0] === undefined) {
1266        var args = slice.call(arguments, 1);
1267        args.unshift(Prototype.K);
1268        return method.apply(this, args);
1269      } else {
1270        return method.apply(this, arguments);
1271      }
1272    };
1273  }
1274
1275
1276  function map(iterator) {
1277    if (this == null) throw new TypeError();
1278    iterator = iterator || Prototype.K;
1279
1280    var object = Object(this);
1281    var results = [], context = arguments[1], n = 0;
1282
1283    for (var i = 0, length = object.length >>> 0; i < length; i++) {
1284      if (i in object) {
1285        results[n] = iterator.call(context, object[i], i, object);
1286      }
1287      n++;
1288    }
1289    results.length = n;
1290    return results;
1291  }
1292
1293  if (arrayProto.map) {
1294    map = wrapNative(Array.prototype.map);
1295  }
1296
1297  function filter(iterator) {
1298    if (this == null || !Object.isFunction(iterator))
1299      throw new TypeError();
1300
1301    var object = Object(this);
1302    var results = [], context = arguments[1], value;
1303
1304    for (var i = 0, length = object.length >>> 0; i < length; i++) {
1305      if (i in object) {
1306        value = object[i];
1307        if (iterator.call(context, value, i, object)) {
1308          results.push(value);
1309        }
1310      }
1311    }
1312    return results;
1313  }
1314
1315  if (arrayProto.filter) {
1316    filter = Array.prototype.filter;
1317  }
1318
1319  function some(iterator) {
1320    if (this == null) throw new TypeError();
1321    iterator = iterator || Prototype.K;
1322    var context = arguments[1];
1323
1324    var object = Object(this);
1325    for (var i = 0, length = object.length >>> 0; i < length; i++) {
1326      if (i in object && iterator.call(context, object[i], i, object)) {
1327        return true;
1328      }
1329    }
1330
1331    return false;
1332  }
1333
1334  if (arrayProto.some) {
1335    some = wrapNative(Array.prototype.some);
1336  }
1337
1338  function every(iterator) {
1339    if (this == null) throw new TypeError();
1340    iterator = iterator || Prototype.K;
1341    var context = arguments[1];
1342
1343    var object = Object(this);
1344    for (var i = 0, length = object.length >>> 0; i < length; i++) {
1345      if (i in object && !iterator.call(context, object[i], i, object)) {
1346        return false;
1347      }
1348    }
1349
1350    return true;
1351  }
1352
1353  if (arrayProto.every) {
1354    every = wrapNative(Array.prototype.every);
1355  }
1356
1357
1358  Object.extend(arrayProto, Enumerable);
1359
1360  if (arrayProto.entries === Enumerable.entries) {
1361    delete arrayProto.entries;
1362  }
1363
1364  if (!arrayProto._reverse)
1365    arrayProto._reverse = arrayProto.reverse;
1366
1367  Object.extend(arrayProto, {
1368    _each:     _each,
1369
1370    map:       map,
1371    collect:   map,
1372    select:    filter,
1373    filter:    filter,
1374    findAll:   filter,
1375    some:      some,
1376    any:       some,
1377    every:     every,
1378    all:       every,
1379
1380    clear:     clear,
1381    first:     first,
1382    last:      last,
1383    compact:   compact,
1384    flatten:   flatten,
1385    without:   without,
1386    reverse:   reverse,
1387    uniq:      uniq,
1388    intersect: intersect,
1389    clone:     clone,
1390    toArray:   clone,
1391    size:      size,
1392    inspect:   inspect
1393  });
1394
1395  var CONCAT_ARGUMENTS_BUGGY = (function() {
1396    return [].concat(arguments)[0][0] !== 1;
1397  })(1,2);
1398
1399  if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
1400
1401  if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
1402  if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
1403})();
1404function $H(object) {
1405  return new Hash(object);
1406};
1407
1408var Hash = Class.create(Enumerable, (function() {
1409  function initialize(object) {
1410    this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
1411  }
1412
1413
1414  function _each(iterator, context) {
1415    var i = 0;
1416    for (var key in this._object) {
1417      var value = this._object[key], pair = [key, value];
1418      pair.key = key;
1419      pair.value = value;
1420      iterator.call(context, pair, i);
1421      i++;
1422    }
1423  }
1424
1425  function set(key, value) {
1426    return this._object[key] = value;
1427  }
1428
1429  function get(key) {
1430    if (this._object[key] !== Object.prototype[key])
1431      return this._object[key];
1432  }
1433
1434  function unset(key) {
1435    var value = this._object[key];
1436    delete this._object[key];
1437    return value;
1438  }
1439
1440  function toObject() {
1441    return Object.clone(this._object);
1442  }
1443
1444
1445
1446  function keys() {
1447    return this.pluck('key');
1448  }
1449
1450  function values() {
1451    return this.pluck('value');
1452  }
1453
1454  function index(value) {
1455    var match = this.detect(function(pair) {
1456      return pair.value === value;
1457    });
1458    return match && match.key;
1459  }
1460
1461  function merge(object) {
1462    return this.clone().update(object);
1463  }
1464
1465  function update(object) {
1466    return new Hash(object).inject(this, function(result, pair) {
1467      result.set(pair.key, pair.value);
1468      return result;
1469    });
1470  }
1471
1472  function toQueryPair(key, value) {
1473    if (Object.isUndefined(value)) return key;
1474
1475    value = String.interpret(value);
1476
1477    value = value.gsub(/(\r)?\n/, '\r\n');
1478    value = encodeURIComponent(value);
1479    value = value.gsub(/%20/, '+');
1480    return key + '=' + value;
1481  }
1482
1483  function toQueryString() {
1484    return this.inject([], function(results, pair) {
1485      var key = encodeURIComponent(pair.key), values = pair.value;
1486
1487      if (values && typeof values == 'object') {
1488        if (Object.isArray(values)) {
1489          var queryValues = [];
1490          for (var i = 0, len = values.length, value; i < len; i++) {
1491            value = values[i];
1492            queryValues.push(toQueryPair(key, value));
1493          }
1494          return results.concat(queryValues);
1495        }
1496      } else results.push(toQueryPair(key, values));
1497      return results;
1498    }).join('&');
1499  }
1500
1501  function inspect() {
1502    return '#<Hash:{' + this.map(function(pair) {
1503      return pair.map(Object.inspect).join(': ');
1504    }).join(', ') + '}>';
1505  }
1506
1507  function clone() {
1508    return new Hash(this);
1509  }
1510
1511  return {
1512    initialize:             initialize,
1513    _each:                  _each,
1514    set:                    set,
1515    get:                    get,
1516    unset:                  unset,
1517    toObject:               toObject,
1518    toTemplateReplacements: toObject,
1519    keys:                   keys,
1520    values:                 values,
1521    index:                  index,
1522    merge:                  merge,
1523    update:                 update,
1524    toQueryString:          toQueryString,
1525    inspect:                inspect,
1526    toJSON:                 toObject,
1527    clone:                  clone
1528  };
1529})());
1530
1531Hash.from = $H;
1532Object.extend(Number.prototype, (function() {
1533  function toColorPart() {
1534    return this.toPaddedString(2, 16);
1535  }
1536
1537  function succ() {
1538    return this + 1;
1539  }
1540
1541  function times(iterator, context) {
1542    $R(0, this, true).each(iterator, context);
1543    return this;
1544  }
1545
1546  function toPaddedString(length, radix) {
1547    var string = this.toString(radix || 10);
1548    return '0'.times(length - string.length) + string;
1549  }
1550
1551  function abs() {
1552    return Math.abs(this);
1553  }
1554
1555  function round() {
1556    return Math.round(this);
1557  }
1558
1559  function ceil() {
1560    return Math.ceil(this);
1561  }
1562
1563  function floor() {
1564    return Math.floor(this);
1565  }
1566
1567  return {
1568    toColorPart:    toColorPart,
1569    succ:           succ,
1570    times:          times,
1571    toPaddedString: toPaddedString,
1572    abs:            abs,
1573    round:          round,
1574    ceil:           ceil,
1575    floor:          floor
1576  };
1577})());
1578
1579function $R(start, end, exclusive) {
1580  return new ObjectRange(start, end, exclusive);
1581}
1582
1583var ObjectRange = Class.create(Enumerable, (function() {
1584  function initialize(start, end, exclusive) {
1585    this.start = start;
1586    this.end = end;
1587    this.exclusive = exclusive;
1588  }
1589
1590  function _each(iterator, context) {
1591    var value = this.start, i;
1592    for (i = 0; this.include(value); i++) {
1593      iterator.call(context, value, i);
1594      value = value.succ();
1595    }
1596  }
1597
1598  function include(value) {
1599    if (value < this.start)
1600      return false;
1601    if (this.exclusive)
1602      return value < this.end;
1603    return value <= this.end;
1604  }
1605
1606  return {
1607    initialize: initialize,
1608    _each:      _each,
1609    include:    include
1610  };
1611})());
1612
1613
1614
1615var Abstract = { };
1616
1617
1618var Try = {
1619  these: function() {
1620    var returnValue;
1621
1622    for (var i = 0, length = arguments.length; i < length; i++) {
1623      var lambda = arguments[i];
1624      try {
1625        returnValue = lambda();
1626        break;
1627      } catch (e) { }
1628    }
1629
1630    return returnValue;
1631  }
1632};
1633
1634var Ajax = {
1635  getTransport: function() {
1636    return Try.these(
1637      function() {return new XMLHttpRequest()},
1638      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
1639      function() {return new ActiveXObject('Microsoft.XMLHTTP')}
1640    ) || false;
1641  },
1642
1643  activeRequestCount: 0
1644};
1645
1646Ajax.Responders = {
1647  responders: [],
1648
1649  _each: function(iterator, context) {
1650    this.responders._each(iterator, context);
1651  },
1652
1653  register: function(responder) {
1654    if (!this.include(responder))
1655      this.responders.push(responder);
1656  },
1657
1658  unregister: function(responder) {
1659    this.responders = this.responders.without(responder);
1660  },
1661
1662  dispatch: function(callback, request, transport, json) {
1663    this.each(function(responder) {
1664      if (Object.isFunction(responder[callback])) {
1665        try {
1666          responder[callback].apply(responder, [request, transport, json]);
1667        } catch (e) { }
1668      }
1669    });
1670  }
1671};
1672
1673Object.extend(Ajax.Responders, Enumerable);
1674
1675Ajax.Responders.register({
1676  onCreate:   function() { Ajax.activeRequestCount++ },
1677  onComplete: function() { Ajax.activeRequestCount-- }
1678});
1679Ajax.Base = Class.create({
1680  initialize: function(options) {
1681    this.options = {
1682      method:       'post',
1683      asynchronous: true,
1684      contentType:  'application/x-www-form-urlencoded',
1685      encoding:     'UTF-8',
1686      parameters:   '',
1687      evalJSON:     true,
1688      evalJS:       true
1689    };
1690    Object.extend(this.options, options || { });
1691
1692    this.options.method = this.options.method.toLowerCase();
1693
1694    if (Object.isHash(this.options.parameters))
1695      this.options.parameters = this.options.parameters.toObject();
1696  }
1697});
1698Ajax.Request = Class.create(Ajax.Base, {
1699  _complete: false,
1700
1701  initialize: function($super, url, options) {
1702    $super(options);
1703    this.transport = Ajax.getTransport();
1704    this.request(url);
1705  },
1706
1707  request: function(url) {
1708    this.url = url;
1709    this.method = this.options.method;
1710    var params = Object.isString(this.options.parameters) ?
1711          this.options.parameters :
1712          Object.toQueryString(this.options.parameters);
1713
1714    if (!['get', 'post'].include(this.method)) {
1715      params += (params ? '&' : '') + "_method=" + this.method;
1716      this.method = 'post';
1717    }
1718
1719    if (params && this.method === 'get') {
1720      this.url += (this.url.include('?') ? '&' : '?') + params;
1721    }
1722
1723    this.parameters = params.toQueryParams();
1724
1725    try {
1726      var response = new Ajax.Response(this);
1727      if (this.options.onCreate) this.options.onCreate(response);
1728      Ajax.Responders.dispatch('onCreate', this, response);
1729
1730      this.transport.open(this.method.toUpperCase(), this.url,
1731        this.options.asynchronous);
1732
1733      if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
1734
1735      this.transport.onreadystatechange = this.onStateChange.bind(this);
1736      this.setRequestHeaders();
1737
1738      this.body = this.method == 'post' ? (this.options.postBody || params) : null;
1739      this.transport.send(this.body);
1740
1741      /* Force Firefox to handle ready state 4 for synchronous requests */
1742      if (!this.options.asynchronous && this.transport.overrideMimeType)
1743        this.onStateChange();
1744
1745    }
1746    catch (e) {
1747      this.dispatchException(e);
1748    }
1749  },
1750
1751  onStateChange: function() {
1752    var readyState = this.transport.readyState;
1753    if (readyState > 1 && !((readyState == 4) && this._complete))
1754      this.respondToReadyState(this.transport.readyState);
1755  },
1756
1757  setRequestHeaders: function() {
1758    var headers = {
1759      'X-Requested-With': 'XMLHttpRequest',
1760      'X-Prototype-Version': Prototype.Version,
1761      'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
1762    };
1763
1764    if (this.method == 'post') {
1765      headers['Content-type'] = this.options.contentType +
1766        (this.options.encoding ? '; charset=' + this.options.encoding : '');
1767
1768      /* Force "Connection: close" for older Mozilla browsers to work
1769       * around a bug where XMLHttpRequest sends an incorrect
1770       * Content-length header. See Mozilla Bugzilla #246651.
1771       */
1772      if (this.transport.overrideMimeType &&
1773          (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
1774            headers['Connection'] = 'close';
1775    }
1776
1777    if (typeof this.options.requestHeaders == 'object') {
1778      var extras = this.options.requestHeaders;
1779
1780      if (Object.isFunction(extras.push))
1781        for (var i = 0, length = extras.length; i < length; i += 2)
1782          headers[extras[i]] = extras[i+1];
1783      else
1784        $H(extras).each(function(pair) { headers[pair.key] = pair.value });
1785    }
1786
1787    for (var name in headers)
1788      if (headers[name] != null)
1789        this.transport.setRequestHeader(name, headers[name]);
1790  },
1791
1792  success: function() {
1793    var status = this.getStatus();
1794    return !status || (status >= 200 && status < 300) || status == 304;
1795  },
1796
1797  getStatus: function() {
1798    try {
1799      if (this.transport.status === 1223) return 204;
1800      return this.transport.status || 0;
1801    } catch (e) { return 0 }
1802  },
1803
1804  respondToReadyState: function(readyState) {
1805    var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this);
1806
1807    if (state == 'Complete') {
1808      try {
1809        this._complete = true;
1810        (this.options['on' + response.status]
1811         || this.options['on' + (this.success() ? 'Success' : 'Failure')]
1812         || Prototype.emptyFunction)(response, response.headerJSON);
1813      } catch (e) {
1814        this.dispatchException(e);
1815      }
1816
1817      var contentType = response.getHeader('Content-type');
1818      if (this.options.evalJS == 'force'
1819          || (this.options.evalJS && this.isSameOrigin() && contentType
1820          && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i)))
1821        this.evalResponse();
1822    }
1823
1824    try {
1825      (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON);
1826      Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON);
1827    } catch (e) {
1828      this.dispatchException(e);
1829    }
1830
1831    if (state == 'Complete') {
1832      this.transport.onreadystatechange = Prototype.emptyFunction;
1833    }
1834  },
1835
1836  isSameOrigin: function() {
1837    var m = this.url.match(/^\s*https?:\/\/[^\/]*/);
1838    return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({
1839      protocol: location.protocol,
1840      domain: document.domain,
1841      port: location.port ? ':' + location.port : ''
1842    }));
1843  },
1844
1845  getHeader: function(name) {
1846    try {
1847      return this.transport.getResponseHeader(name) || null;
1848    } catch (e) { return null; }
1849  },
1850
1851  evalResponse: function() {
1852    try {
1853      return eval((this.transport.responseText || '').unfilterJSON());
1854    } catch (e) {
1855      this.dispatchException(e);
1856    }
1857  },
1858
1859  dispatchException: function(exception) {
1860    (this.options.onException || Prototype.emptyFunction)(this, exception);
1861    Ajax.Responders.dispatch('onException', this, exception);
1862  }
1863});
1864
1865Ajax.Request.Events =
1866  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
1867
1868
1869
1870
1871
1872
1873
1874
1875Ajax.Response = Class.create({
1876  initialize: function(request){
1877    this.request = request;
1878    var transport  = this.transport  = request.transport,
1879        readyState = this.readyState = transport.readyState;
1880
1881    if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) {
1882      this.status       = this.getStatus();
1883      this.statusText   = this.getStatusText();
1884      this.responseText = String.interpret(transport.responseText);
1885      this.headerJSON   = this._getHeaderJSON();
1886    }
1887
1888    if (readyState == 4) {
1889      var xml = transport.responseXML;
1890      this.responseXML  = Object.isUndefined(xml) ? null : xml;
1891      this.responseJSON = this._getResponseJSON();
1892    }
1893  },
1894
1895  status:      0,
1896
1897  statusText: '',
1898
1899  getStatus: Ajax.Request.prototype.getStatus,
1900
1901  getStatusText: function() {
1902    try {
1903      return this.transport.statusText || '';
1904    } catch (e) { return '' }
1905  },
1906
1907  getHeader: Ajax.Request.prototype.getHeader,
1908
1909  getAllHeaders: function() {
1910    try {
1911      return this.getAllResponseHeaders();
1912    } catch (e) { return null }
1913  },
1914
1915  getResponseHeader: function(name) {
1916    return this.transport.getResponseHeader(name);
1917  },
1918
1919  getAllResponseHeaders: function() {
1920    return this.transport.getAllResponseHeaders();
1921  },
1922
1923  _getHeaderJSON: function() {
1924    var json = this.getHeader('X-JSON');
1925    if (!json) return null;
1926
1927    try {
1928      json = decodeURIComponent(escape(json));
1929    } catch(e) {
1930    }
1931
1932    try {
1933      return json.evalJSON(this.request.options.sanitizeJSON ||
1934        !this.request.isSameOrigin());
1935    } catch (e) {
1936      this.request.dispatchException(e);
1937    }
1938  },
1939
1940  _getResponseJSON: function() {
1941    var options = this.request.options;
1942    if (!options.evalJSON || (options.evalJSON != 'force' &&
1943      !(this.getHeader('Content-type') || '').include('application/json')) ||
1944        this.responseText.blank())
1945          return null;
1946    try {
1947      return this.responseText.evalJSON(options.sanitizeJSON ||
1948        !this.request.isSameOrigin());
1949    } catch (e) {
1950      this.request.dispatchException(e);
1951    }
1952  }
1953});
1954
1955Ajax.Updater = Class.create(Ajax.Request, {
1956  initialize: function($super, container, url, options) {
1957    this.container = {
1958      success: (container.success || container),
1959      failure: (container.failure || (container.success ? null : container))
1960    };
1961
1962    options = Object.clone(options);
1963    var onComplete = options.onComplete;
1964    options.onComplete = (function(response, json) {
1965      this.updateContent(response.responseText);
1966      if (Object.isFunction(onComplete)) onComplete(response, json);
1967    }).bind(this);
1968
1969    $super(url, options);
1970  },
1971
1972  updateContent: function(responseText) {
1973    var receiver = this.container[this.success() ? 'success' : 'failure'],
1974        options = this.options;
1975
1976    if (!options.evalScripts) responseText = responseText.stripScripts();
1977
1978    if (receiver = $(receiver)) {
1979      if (options.insertion) {
1980        if (Object.isString(options.insertion)) {
1981          var insertion = { }; insertion[options.insertion] = responseText;
1982          receiver.insert(insertion);
1983        }
1984        else options.insertion(receiver, responseText);
1985      }
1986      else receiver.update(responseText);
1987    }
1988  }
1989});
1990
1991Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
1992  initialize: function($super, container, url, options) {
1993    $super(options);
1994    this.onComplete = this.options.onComplete;
1995
1996    this.frequency = (this.options.frequency || 2);
1997    this.decay = (this.options.decay || 1);
1998
1999    this.updater = { };
2000    this.container = container;
2001    this.url = url;
2002
2003    this.start();
2004  },
2005
2006  start: function() {
2007    this.options.onComplete = this.updateComplete.bind(this);
2008    this.onTimerEvent();
2009  },
2010
2011  stop: function() {
2012    this.updater.options.onComplete = undefined;
2013    clearTimeout(this.timer);
2014    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
2015  },
2016
2017  updateComplete: function(response) {
2018    if (this.options.decay) {
2019      this.decay = (response.responseText == this.lastText ?
2020        this.decay * this.options.decay : 1);
2021
2022      this.lastText = response.responseText;
2023    }
2024    this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency);
2025  },
2026
2027  onTimerEvent: function() {
2028    this.updater = new Ajax.Updater(this.container, this.url, this.options);
2029  }
2030});
2031
2032(function(GLOBAL) {
2033
2034  var UNDEFINED;
2035  var SLICE = Array.prototype.slice;
2036
2037  var DIV = document.createElement('div');
2038
2039
2040  function $(element) {
2041    if (arguments.length > 1) {
2042      for (var i = 0, elements = [], length = arguments.length; i < length; i++)
2043        elements.push($(arguments[i]));
2044      return elements;
2045    }
2046
2047    if (Object.isString(element))
2048      element = document.getElementById(element);
2049    return Element.extend(element);
2050  }
2051
2052  GLOBAL.$ = $;
2053
2054
2055  if (!GLOBAL.Node) GLOBAL.Node = {};
2056
2057  if (!GLOBAL.Node.ELEMENT_NODE) {
2058    Object.extend(GLOBAL.Node, {
2059      ELEMENT_NODE:                1,
2060      ATTRIBUTE_NODE:              2,
2061      TEXT_NODE:                   3,
2062      CDATA_SECTION_NODE:          4,
2063      ENTITY_REFERENCE_NODE:       5,
2064      ENTITY_NODE:                 6,
2065      PROCESSING_INSTRUCTION_NODE: 7,
2066      COMMENT_NODE:                8,
2067      DOCUMENT_NODE:               9,
2068      DOCUMENT_TYPE_NODE:         10,
2069      DOCUMENT_FRAGMENT_NODE:     11,
2070      NOTATION_NODE:              12
2071    });
2072  }
2073
2074  var ELEMENT_CACHE = {};
2075
2076  function shouldUseCreationCache(tagName, attributes) {
2077    if (tagName === 'select') return false;
2078    if ('type' in attributes) return false;
2079    return true;
2080  }
2081
2082  var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){
2083    try {
2084      var el = document.createElement('<input name="x">');
2085      return el.tagName.toLowerCase() === 'input' && el.name === 'x';
2086    }
2087    catch(err) {
2088      return false;
2089    }
2090  })();
2091
2092
2093  var oldElement = GLOBAL.Element;
2094  function Element(tagName, attributes) {
2095    attributes = attributes || {};
2096    tagName = tagName.toLowerCase();
2097
2098    if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) {
2099      tagName = '<' + tagName + ' name="' + attributes.name + '">';
2100      delete attributes.name;
2101      return Element.writeAttribute(document.createElement(tagName), attributes);
2102    }
2103
2104    if (!ELEMENT_CACHE[tagName])
2105      ELEMENT_CACHE[tagName] = Element.extend(document.createElement(tagName));
2106
2107    var node = shouldUseCreationCache(tagName, attributes) ?
2108     ELEMENT_CACHE[tagName].cloneNode(false) : document.createElement(tagName);
2109
2110    return Element.writeAttribute(node, attributes);
2111  }
2112
2113  GLOBAL.Element = Element;
2114
2115  Object.extend(GLOBAL.Element, oldElement || {});
2116  if (oldElement) GLOBAL.Element.prototype = oldElement.prototype;
2117
2118  Element.Methods = { ByTag: {}, Simulated: {} };
2119
2120  var methods = {};
2121
2122  var INSPECT_ATTRIBUTES = { id: 'id', className: 'class' };
2123  function inspect(element) {
2124    element = $(element);
2125    var result = '<' + element.tagName.toLowerCase();
2126
2127    var attribute, value;
2128    for (var property in INSPECT_ATTRIBUTES) {
2129      attribute = INSPECT_ATTRIBUTES[property];
2130      value = (element[property] || '').toString();
2131      if (value) result += ' ' + attribute + '=' + value.inspect(true);
2132    }
2133
2134    return result + '>';
2135  }
2136
2137  methods.inspect = inspect;
2138
2139
2140  function visible(element) {
2141    return $(element).getStyle('display') !== 'none';
2142  }
2143
2144  function toggle(element, bool) {
2145    element = $(element);
2146    if (typeof bool !== 'boolean')
2147      bool = !Element.visible(element);
2148    Element[bool ? 'show' : 'hide'](element);
2149
2150    return element;
2151  }
2152
2153  function hide(element) {
2154    element = $(element);
2155    element.style.display = 'none';
2156    return element;
2157  }
2158
2159  function show(element) {
2160    element = $(element);
2161    element.style.display = '';
2162    return element;
2163  }
2164
2165
2166  Object.extend(methods, {
2167    visible: visible,
2168    toggle:  toggle,
2169    hide:    hide,
2170    show:    show
2171  });
2172
2173
2174  function remove(element) {
2175    element = $(element);
2176    if (element.parentNode) {
2177      element.parentNode.removeChild(element);
2178    }
2179    return element;
2180  }
2181
2182  var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
2183    var el = document.createElement("select"),
2184        isBuggy = true;
2185    el.innerHTML = "<option value=\"test\">test</option>";
2186    if (el.options && el.options[0]) {
2187      isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
2188    }
2189    el = null;
2190    return isBuggy;
2191  })();
2192
2193  var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
2194    try {
2195      var el = document.createElement("table");
2196      if (el && el.tBodies) {
2197        el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
2198        var isBuggy = typeof el.tBodies[0] == "undefined";
2199        el = null;
2200        return isBuggy;
2201      }
2202    } catch (e) {
2203      return true;
2204    }
2205  })();
2206
2207  var LINK_ELEMENT_INNERHTML_BUGGY = (function() {
2208    try {
2209      var el = document.createElement('div');
2210      el.innerHTML = "<link />";
2211      var isBuggy = (el.childNodes.length === 0);
2212      el = null;
2213      return isBuggy;
2214    } catch(e) {
2215      return true;
2216    }
2217  })();
2218
2219  var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
2220   TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
2221
2222  var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
2223    var s = document.createElement("script"),
2224        isBuggy = false;
2225    try {
2226      s.appendChild(document.createTextNode(""));
2227      isBuggy = !s.firstChild ||
2228        s.firstChild && s.firstChild.nodeType !== 3;
2229    } catch (e) {
2230      isBuggy = true;
2231    }
2232    s = null;
2233    return isBuggy;
2234  })();
2235
2236  function update(element, content) {
2237    element = $(element);
2238
2239    var descendants = element.getElementsByTagName('*'),
2240     i = descendants.length;
2241    while (i--) purgeElement(descendants[i]);
2242
2243    if (content && content.toElement)
2244      content = content.toElement();
2245
2246    if (Object.isElement(content))
2247      return element.update().insert(content);
2248
2249
2250    content = Object.toHTML(content);
2251    var tagName = element.tagName.toUpperCase();
2252
2253    if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
2254      element.text = content;
2255      return element;
2256    }
2257
2258    if (ANY_INNERHTML_BUGGY) {
2259      if (tagName in INSERTION_TRANSLATIONS.tags) {
2260        while (element.firstChild)
2261          element.removeChild(element.firstChild);
2262
2263        var nodes = getContentFromAnonymousElement(tagName, content.stripScripts());
2264        for (var i = 0, node; node = nodes[i]; i++)
2265          element.appendChild(node);
2266
2267      } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
2268        while (element.firstChild)
2269          element.removeChild(element.firstChild);
2270
2271        var nodes = getContentFromAnonymousElement(tagName,
2272         content.stripScripts(), true);
2273
2274        for (var i = 0, node; node = nodes[i]; i++)
2275          element.appendChild(node);
2276      } else {
2277        element.innerHTML = content.stripScripts();
2278      }
2279    } else {
2280      element.innerHTML = content.stripScripts();
2281    }
2282
2283    content.evalScripts.bind(content).defer();
2284    return element;
2285  }
2286
2287  function replace(element, content) {
2288    element = $(element);
2289
2290    if (content && content.toElement) {
2291      content = content.toElement();
2292    } else if (!Object.isElement(content)) {
2293      content = Object.toHTML(content);
2294      var range = element.ownerDocument.createRange();
2295      range.selectNode(element);
2296      content.evalScripts.bind(content).defer();
2297      content = range.createContextualFragment(content.stripScripts());
2298    }
2299
2300    element.parentNode.replaceChild(content, element);
2301    return element;
2302  }
2303
2304  var INSERTION_TRANSLATIONS = {
2305    before: function(element, node) {
2306      element.parentNode.insertBefore(node, element);
2307    },
2308    top: function(element, node) {
2309      element.insertBefore(node, element.firstChild);
2310    },
2311    bottom: function(element, node) {
2312      element.appendChild(node);
2313    },
2314    after: function(element, node) {
2315      element.parentNode.insertBefore(node, element.nextSibling);
2316    },
2317
2318    tags: {
2319      TABLE:  ['<table>',                '</table>',                   1],
2320      TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
2321      TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
2322      TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2323      SELECT: ['<select>',               '</select>',                  1]
2324    }
2325  };
2326
2327  var tags = INSERTION_TRANSLATIONS.tags;
2328
2329  Object.extend(tags, {
2330    THEAD: tags.TBODY,
2331    TFOOT: tags.TBODY,
2332    TH:    tags.TD
2333  });
2334
2335  function replace_IE(element, content) {
2336    element = $(element);
2337    if (content && content.toElement)
2338      content = content.toElement();
2339    if (Object.isElement(content)) {
2340      element.parentNode.replaceChild(content, element);
2341      return element;
2342    }
2343
2344    content = Object.toHTML(content);
2345    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
2346
2347    if (tagName in INSERTION_TRANSLATIONS.tags) {
2348      var nextSibling = Element.next(element);
2349      var fragments = getContentFromAnonymousElement(
2350       tagName, content.stripScripts());
2351
2352      parent.removeChild(element);
2353
2354      var iterator;
2355      if (nextSibling)
2356        iterator = function(node) { parent.insertBefore(node, nextSibling) };
2357      else
2358        iterator = function(node) { parent.appendChild(node); }
2359
2360      fragments.each(iterator);
2361    } else {
2362      element.outerHTML = content.stripScripts();
2363    }
2364
2365    content.evalScripts.bind(content).defer();
2366    return element;
2367  }
2368
2369  if ('outerHTML' in document.documentElement)
2370    replace = replace_IE;
2371
2372  function isContent(content) {
2373    if (Object.isUndefined(content) || content === null) return false;
2374
2375    if (Object.isString(content) || Object.isNumber(content)) return true;
2376    if (Object.isElement(content)) return true;
2377    if (content.toElement || content.toHTML) return true;
2378
2379    return false;
2380  }
2381
2382  function insertContentAt(element, content, position) {
2383    position   = position.toLowerCase();
2384    var method = INSERTION_TRANSLATIONS[position];
2385
2386    if (content && content.toElement) content = content.toElement();
2387    if (Object.isElement(content)) {
2388      method(element, content);
2389      return element;
2390    }
2391
2392    content = Object.toHTML(content);
2393    var tagName = ((position === 'before' || position === 'after') ?
2394     element.parentNode : element).tagName.toUpperCase();
2395
2396    var childNodes = getContentFromAnonymousElement(tagName, content.stripScripts());
2397
2398    if (position === 'top' || position === 'after') childNodes.reverse();
2399
2400    for (var i = 0, node; node = childNodes[i]; i++)
2401      method(element, node);
2402
2403    content.evalScripts.bind(content).defer();
2404  }
2405
2406  function insert(element, insertions) {
2407    element = $(element);
2408
2409    if (isContent(insertions))
2410      insertions = { bottom: insertions };
2411
2412    for (var position in insertions)
2413      insertContentAt(element, insertions[position], position);
2414
2415    return element;
2416  }
2417
2418  function wrap(element, wrapper, attributes) {
2419    element = $(element);
2420
2421    if (Object.isElement(wrapper)) {
2422      $(wrapper).writeAttribute(attributes || {});
2423    } else if (Object.isString(wrapper)) {
2424      wrapper = new Element(wrapper, attributes);
2425    } else {
2426      wrapper = new Element('div', wrapper);
2427    }
2428
2429    if (element.parentNode)
2430      element.parentNode.replaceChild(wrapper, element);
2431
2432    wrapper.appendChild(element);
2433
2434    return wrapper;
2435  }
2436
2437  function cleanWhitespace(element) {
2438    element = $(element);
2439    var node = element.firstChild;
2440
2441    while (node) {
2442      var nextNode = node.nextSibling;
2443      if (node.nodeType === Node.TEXT_NODE && !/\S/.test(node.nodeValue))
2444        element.removeChild(node);
2445      node = nextNode;
2446    }
2447    return element;
2448  }
2449
2450  function empty(element) {
2451    return $(element).innerHTML.blank();
2452  }
2453
2454  function getContentFromAnonymousElement(tagName, html, force) {
2455    var t = INSERTION_TRANSLATIONS.tags[tagName], div = DIV;
2456
2457    var workaround = !!t;
2458    if (!workaround && force) {
2459      workaround = true;
2460      t = ['', '', 0];
2461    }
2462
2463    if (workaround) {
2464      div.innerHTML = '&#160;' + t[0] + html + t[1];
2465      div.removeChild(div.firstChild);
2466      for (var i = t[2]; i--; )
2467        div = div.firstChild;
2468    } else {
2469      div.innerHTML = html;
2470    }
2471
2472    return $A(div.childNodes);
2473  }
2474
2475  function clone(element, deep) {
2476    if (!(element = $(element))) return;
2477    var clone = element.cloneNode(deep);
2478    if (!HAS_UNIQUE_ID_PROPERTY) {
2479      clone._prototypeUID = UNDEFINED;
2480      if (deep) {
2481        var descendants = Element.select(clone, '*'),
2482         i = descendants.length;
2483        while (i--)
2484          descendants[i]._prototypeUID = UNDEFINED;
2485      }
2486    }
2487    return Element.extend(clone);
2488  }
2489
2490  function purgeElement(element) {
2491    var uid = getUniqueElementID(element);
2492    if (uid) {
2493      Element.stopObserving(element);
2494      if (!HAS_UNIQUE_ID_PROPERTY)
2495        element._prototypeUID = UNDEFINED;
2496      delete Element.Storage[uid];
2497    }
2498  }
2499
2500  function purgeCollection(elements) {
2501    var i = elements.length;
2502    while (i--)
2503      purgeElement(elements[i]);
2504  }
2505
2506  function purgeCollection_IE(elements) {
2507    var i = elements.length, element, uid;
2508    while (i--) {
2509      element = elements[i];
2510      uid = getUniqueElementID(element);
2511      delete Element.Storage[uid];
2512      delete Event.cache[uid];
2513    }
2514  }
2515
2516  if (HAS_UNIQUE_ID_PROPERTY) {
2517    purgeCollection = purgeCollection_IE;
2518  }
2519
2520
2521  function purge(element) {
2522    if (!(element = $(element))) return;
2523    purgeElement(element);
2524
2525    var descendants = element.getElementsByTagName('*'),
2526     i = descendants.length;
2527
2528    while (i--) purgeElement(descendants[i]);
2529
2530    return null;
2531  }
2532
2533  Object.extend(methods, {
2534    remove:  remove,
2535    update:  update,
2536    replace: replace,
2537    insert:  insert,
2538    wrap:    wrap,
2539    cleanWhitespace: cleanWhitespace,
2540    empty:   empty,
2541    clone:   clone,
2542    purge:   purge
2543  });
2544
2545
2546
2547  function recursivelyCollect(element, property, maximumLength) {
2548    element = $(element);
2549    maximumLength = maximumLength || -1;
2550    var elements = [];
2551
2552    while (element = element[property]) {
2553      if (element.nodeType === Node.ELEMENT_NODE)
2554        elements.push(Element.extend(element));
2555
2556      if (elements.length === maximumLength) break;
2557    }
2558
2559    return elements;
2560  }
2561
2562
2563  function ancestors(element) {
2564    return recursivelyCollect(element, 'parentNode');
2565  }
2566
2567  function descendants(element) {
2568    return Element.select(element, '*');
2569  }
2570
2571  function firstDescendant(element) {
2572    element = $(element).firstChild;
2573    while (element && element.nodeType !== Node.ELEMENT_NODE)
2574      element = element.nextSibling;
2575
2576    return $(element);
2577  }
2578
2579  function immediateDescendants(element) {
2580    var results = [], child = $(element).firstChild;
2581
2582    while (child) {
2583      if (child.nodeType === Node.ELEMENT_NODE)
2584        results.push(Element.extend(child));
2585
2586      child = child.nextSibling;
2587    }
2588
2589    return results;
2590  }
2591
2592  function previousSiblings(element) {
2593    return recursivelyCollect(element, 'previousSibling');
2594  }
2595
2596  function nextSiblings(element) {
2597    return recursivelyCollect(element, 'nextSibling');
2598  }
2599
2600  function siblings(element) {
2601    element = $(element);
2602    var previous = previousSiblings(element),
2603     next = nextSiblings(element);
2604    return previous.reverse().concat(next);
2605  }
2606
2607  function match(element, selector) {
2608    element = $(element);
2609
2610    if (Object.isString(selector))
2611      return Prototype.Selector.match(element, selector);
2612
2613    return selector.match(element);
2614  }
2615
2616
2617  function _recursivelyFind(element, property, expression, index) {
2618    element = $(element), expression = expression || 0, index = index || 0;
2619    if (Object.isNumber(expression)) {
2620      index = expression, expression = null;
2621    }
2622
2623    while (element = element[property]) {
2624      if (element.nodeType !== 1) continue;
2625      if (expression && !Prototype.Selector.match(element, expression))
2626        continue;
2627      if (--index >= 0) continue;
2628
2629      return Element.extend(element);
2630    }
2631  }
2632
2633
2634  function up(element, expression, index) {
2635    element = $(element);
2636
2637    if (arguments.length === 1) return $(element.parentNode);
2638    return _recursivelyFind(element, 'parentNode', expression, index);
2639  }
2640
2641  function down(element, expression, index) {
2642    if (arguments.length === 1) return firstDescendant(element);
2643    element = $(element), expression = expression || 0, index = index || 0;
2644
2645    if (Object.isNumber(expression))
2646      index = expression, expression = '*';
2647
2648    var node = Prototype.Selector.select(expression, element)[index];
2649    return Element.extend(node);
2650  }
2651
2652  function previous(element, expression, index) {
2653    return _recursivelyFind(element, 'previousSibling', expression, index);
2654  }
2655
2656  function next(element, expression, index) {
2657    return _recursivelyFind(element, 'nextSibling', expression, index);
2658  }
2659
2660  function select(element) {
2661    element = $(element);
2662    var expressions = SLICE.call(arguments, 1).join(', ');
2663    return Prototype.Selector.select(expressions, element);
2664  }
2665
2666  function adjacent(element) {
2667    element = $(element);
2668    var expressions = SLICE.call(arguments, 1).join(', ');
2669    var siblings = Element.siblings(element), results = [];
2670    for (var i = 0, sibling; sibling = siblings[i]; i++) {
2671      if (Prototype.Selector.match(sibling, expressions))
2672        results.push(sibling);
2673    }
2674
2675    return results;
2676  }
2677
2678  function descendantOf_DOM(element, ancestor) {
2679    element = $(element), ancestor = $(ancestor);
2680    if (!element || !ancestor) return false;
2681    while (element = element.parentNode)
2682      if (element === ancestor) return true;
2683    return false;
2684  }
2685
2686  function descendantOf_contains(element, ancestor) {
2687    element = $(element), ancestor = $(ancestor);
2688    if (!element || !ancestor) return false;
2689    if (!ancestor.contains) return descendantOf_DOM(element, ancestor);
2690    return ancestor.contains(element) && ancestor !== element;
2691  }
2692
2693  function descendantOf_compareDocumentPosition(element, ancestor) {
2694    element = $(element), ancestor = $(ancestor);
2695    if (!element || !ancestor) return false;
2696    return (element.compareDocumentPosition(ancestor) & 8) === 8;
2697  }
2698
2699  var descendantOf;
2700  if (DIV.compareDocumentPosition) {
2701    descendantOf = descendantOf_compareDocumentPosition;
2702  } else if (DIV.contains) {
2703    descendantOf = descendantOf_contains;
2704  } else {
2705    descendantOf = descendantOf_DOM;
2706  }
2707
2708
2709  Object.extend(methods, {
2710    recursivelyCollect:   recursivelyCollect,
2711    ancestors:            ancestors,
2712    descendants:          descendants,
2713    firstDescendant:      firstDescendant,
2714    immediateDescendants: immediateDescendants,
2715    previousSiblings:     previousSiblings,
2716    nextSiblings:         nextSiblings,
2717    siblings:             siblings,
2718    match:                match,
2719    up:                   up,
2720    down:                 down,
2721    previous:             previous,
2722    next:                 next,
2723    select:               select,
2724    adjacent:             adjacent,
2725    descendantOf:         descendantOf,
2726
2727    getElementsBySelector: select,
2728
2729    childElements:         immediateDescendants
2730  });
2731
2732
2733  var idCounter = 1;
2734  function identify(element) {
2735    element = $(element);
2736    var id = Element.readAttribute(element, 'id');
2737    if (id) return id;
2738
2739    do { id = 'anonymous_element_' + idCounter++ } while ($(id));
2740
2741    Element.writeAttribute(element, 'id', id);
2742    return id;
2743  }
2744
2745
2746  function readAttribute(element, name) {
2747    return $(element).getAttribute(name);
2748  }
2749
2750  function readAttribute_IE(element, name) {
2751    element = $(element);
2752
2753    var table = ATTRIBUTE_TRANSLATIONS.read;
2754    if (table.values[name])
2755      return table.values[name](element, name);
2756
2757    if (table.names[name]) name = table.names[name];
2758
2759    if (name.include(':')) {
2760      if (!element.attributes || !element.attributes[name]) return null;
2761      return element.attributes[name].value;
2762    }
2763
2764    return element.getAttribute(name);
2765  }
2766
2767  function readAttribute_Opera(element, name) {
2768    if (name === 'title') return element.title;
2769    return element.getAttribute(name);
2770  }
2771
2772  var PROBLEMATIC_ATTRIBUTE_READING = (function() {
2773    DIV.setAttribute('onclick', []);
2774    var value = DIV.getAttribute('onclick');
2775    var isFunction = Object.isArray(value);
2776    DIV.removeAttribute('onclick');
2777    return isFunction;
2778  })();
2779
2780  if (PROBLEMATIC_ATTRIBUTE_READING) {
2781    readAttribute = readAttribute_IE;
2782  } else if (Prototype.Browser.Opera) {
2783    readAttribute = readAttribute_Opera;
2784  }
2785
2786
2787  function writeAttribute(element, name, value) {
2788    element = $(element);
2789    var attributes = {}, table = ATTRIBUTE_TRANSLATIONS.write;
2790
2791    if (typeof name === 'object') {
2792      attributes = name;
2793    } else {
2794      attributes[name] = Object.isUndefined(value) ? true : value;
2795    }
2796
2797    for (var attr in attributes) {
2798      name = table.names[attr] || attr;
2799      value = attributes[attr];
2800      if (table.values[attr]) {
2801        value = table.values[attr](element, value);
2802        if (Object.isUndefined(value)) continue;
2803      }
2804      if (value === false || value === null)
2805        element.removeAttribute(name);
2806      else if (value === true)
2807        element.setAttribute(name, name);
2808      else element.setAttribute(name, value);
2809    }
2810
2811    return element;
2812  }
2813
2814  var PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES = (function () {
2815    if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX) {
2816      return false;
2817    }
2818    var checkbox = document.createElement('<input type="checkbox">');
2819    checkbox.checked = true;
2820    var node = checkbox.getAttributeNode('checked');
2821    return !node || !node.specified;
2822  })();
2823
2824  function hasAttribute(element, attribute) {
2825    attribute = ATTRIBUTE_TRANSLATIONS.has[attribute] || attribute;
2826    var node = $(element).getAttributeNode(attribute);
2827    return !!(node && node.specified);
2828  }
2829
2830  function hasAttribute_IE(element, attribute) {
2831    if (attribute === 'checked') {
2832      return element.checked;
2833    }
2834    return hasAttribute(element, attribute);
2835  }
2836
2837  GLOBAL.Element.Methods.Simulated.hasAttribute =
2838   PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES ?
2839   hasAttribute_IE : hasAttribute;
2840
2841  function classNames(element) {
2842    return new Element.ClassNames(element);
2843  }
2844
2845  var regExpCache = {};
2846  function getRegExpForClassName(className) {
2847    if (regExpCache[className]) return regExpCache[className];
2848
2849    var re = new RegExp("(^|\\s+)" + className + "(\\s+|$)");
2850    regExpCache[className] = re;
2851    return re;
2852  }
2853
2854  function hasClassName(element, className) {
2855    if (!(element = $(element))) return;
2856
2857    var elementClassName = element.className;
2858
2859    if (elementClassName.length === 0) return false;
2860    if (elementClassName === className) return true;
2861
2862    return getRegExpForClassName(className).test(elementClassName);
2863  }
2864
2865  function addClassName(element, className) {
2866    if (!(element = $(element))) return;
2867
2868    if (!hasClassName(element, className))
2869      element.className += (element.className ? ' ' : '') + className;
2870
2871    return element;
2872  }
2873
2874  function removeClassName(element, className) {
2875    if (!(element = $(element))) return;
2876
2877    element.className = element.className.replace(
2878     getRegExpForClassName(className), ' ').strip();
2879
2880    return element;
2881  }
2882
2883  function toggleClassName(element, className, bool) {
2884    if (!(element = $(element))) return;
2885
2886    if (Object.isUndefined(bool))
2887      bool = !hasClassName(element, className);
2888
2889    var method = Element[bool ? 'addClassName' : 'removeClassName'];
2890    return method(element, className);
2891  }
2892
2893  var ATTRIBUTE_TRANSLATIONS = {};
2894
2895  var classProp = 'className', forProp = 'for';
2896
2897  DIV.setAttribute(classProp, 'x');
2898  if (DIV.className !== 'x') {
2899    DIV.setAttribute('class', 'x');
2900    if (DIV.className === 'x')
2901      classProp = 'class';
2902  }
2903
2904  var LABEL = document.createElement('label');
2905  LABEL.setAttribute(forProp, 'x');
2906  if (LABEL.htmlFor !== 'x') {
2907    LABEL.setAttribute('htmlFor', 'x');
2908    if (LABEL.htmlFor === 'x')
2909      forProp = 'htmlFor';
2910  }
2911  LABEL = null;
2912
2913  function _getAttr(element, attribute) {
2914    return element.getAttribute(attribute);
2915  }
2916
2917  function _getAttr2(element, attribute) {
2918    return element.getAttribute(attribute, 2);
2919  }
2920
2921  function _getAttrNode(element, attribute) {
2922    var node = element.getAttributeNode(attribute);
2923    return node ? node.value : '';
2924  }
2925
2926  function _getFlag(element, attribute) {
2927    return $(element).hasAttribute(attribute) ? attribute : null;
2928  }
2929
2930  DIV.onclick = Prototype.emptyFunction;
2931  var onclickValue = DIV.getAttribute('onclick');
2932
2933  var _getEv;
2934
2935  if (String(onclickValue).indexOf('{') > -1) {
2936    _getEv = function(element, attribute) {
2937      var value = element.getAttribute(attribute);
2938      if (!value) return null;
2939      value = value.toString();
2940      value = value.split('{')[1];
2941      value = value.split('}')[0];
2942      return value.strip();
2943    };
2944  }
2945  else if (onclickValue === '') {
2946    _getEv = function(element, attribute) {
2947      var value = element.getAttribute(attribute);
2948      if (!value) return null;
2949      return value.strip();
2950    };
2951  }
2952
2953  ATTRIBUTE_TRANSLATIONS.read = {
2954    names: {
2955      'class':     classProp,
2956      'className': classProp,
2957      'for':       forProp,
2958      'htmlFor':   forProp
2959    },
2960
2961    values: {
2962      style: function(element) {
2963        return element.style.cssText.toLowerCase();
2964      },
2965      title: function(element) {
2966        return element.title;
2967      }
2968    }
2969  };
2970
2971  ATTRIBUTE_TRANSLATIONS.write = {
2972    names: {
2973      className:   'class',
2974      htmlFor:     'for',
2975      cellpadding: 'cellPadding',
2976      cellspacing: 'cellSpacing'
2977    },
2978
2979    values: {
2980      checked: function(element, value) {
2981        value = !!value;
2982        element.checked = value;
2983        return value ? 'checked' : null;
2984      },
2985
2986      style: function(element, value) {
2987        element.style.cssText = value ? value : '';
2988      }
2989    }
2990  };
2991
2992  ATTRIBUTE_TRANSLATIONS.has = { names: {} };
2993
2994  Object.extend(ATTRIBUTE_TRANSLATIONS.write.names,
2995   ATTRIBUTE_TRANSLATIONS.read.names);
2996
2997  var CAMEL_CASED_ATTRIBUTE_NAMES = $w('colSpan rowSpan vAlign dateTime ' +
2998   'accessKey tabIndex encType maxLength readOnly longDesc frameBorder');
2999
3000  for (var i = 0, attr; attr = CAMEL_CASED_ATTRIBUTE_NAMES[i]; i++) {
3001    ATTRIBUTE_TRANSLATIONS.write.names[attr.toLowerCase()] = attr;
3002    ATTRIBUTE_TRANSLATIONS.has.names[attr.toLowerCase()]   = attr;
3003  }
3004
3005  Object.extend(ATTRIBUTE_TRANSLATIONS.read.values, {
3006    href:        _getAttr2,
3007    src:         _getAttr2,
3008    type:        _getAttr,
3009    action:      _getAttrNode,
3010    disabled:    _getFlag,
3011    checked:     _getFlag,
3012    readonly:    _getFlag,
3013    multiple:    _getFlag,
3014    onload:      _getEv,
3015    onunload:    _getEv,
3016    onclick:     _getEv,
3017    ondblclick:  _getEv,
3018    onmousedown: _getEv,
3019    onmouseup:   _getEv,
3020    onmouseover: _getEv,
3021    onmousemove: _getEv,
3022    onmouseout:  _getEv,
3023    onfocus:     _getEv,
3024    onblur:      _getEv,
3025    onkeypress:  _getEv,
3026    onkeydown:   _getEv,
3027    onkeyup:     _getEv,
3028    onsubmit:    _getEv,
3029    onreset:     _getEv,
3030    onselect:    _getEv,
3031    onchange:    _getEv
3032  });
3033
3034
3035  Object.extend(methods, {
3036    identify:        identify,
3037    readAttribute:   readAttribute,
3038    writeAttribute:  writeAttribute,
3039    classNames:      classNames,
3040    hasClassName:    hasClassName,
3041    addClassName:    addClassName,
3042    removeClassName: removeClassName,
3043    toggleClassName: toggleClassName
3044  });
3045
3046
3047  function normalizeStyleName(style) {
3048    if (style === 'float' || style === 'styleFloat')
3049      return 'cssFloat';
3050    return style.camelize();
3051  }
3052
3053  function normalizeStyleName_IE(style) {
3054    if (style === 'float' || style === 'cssFloat')
3055      return 'styleFloat';
3056    return style.camelize();
3057  }
3058
3059  function setStyle(element, styles) {
3060    element = $(element);
3061    var elementStyle = element.style, match;
3062
3063    if (Object.isString(styles)) {
3064      elementStyle.cssText += ';' + styles;
3065      if (styles.include('opacity')) {
3066        var opacity = styles.match(/opacity:\s*(\d?\.?\d*)/)[1];
3067        Element.setOpacity(element, opacity);
3068      }
3069      return element;
3070    }
3071
3072    for (var property in styles) {
3073      if (property === 'opacity') {
3074        Element.setOpacity(element, styles[property]);
3075      } else {
3076        var value = styles[property];
3077        if (property === 'float' || property === 'cssFloat') {
3078          property = Object.isUndefined(elementStyle.styleFloat) ?
3079           'cssFloat' : 'styleFloat';
3080        }
3081        elementStyle[property] = value;
3082      }
3083    }
3084
3085    return element;
3086  }
3087
3088
3089  function getStyle(element, style) {
3090    element = $(element);
3091    style = normalizeStyleName(style);
3092
3093    var value = element.style[style];
3094    if (!value || value === 'auto') {
3095      var css = document.defaultView.getComputedStyle(element, null);
3096      value = css ? css[style] : null;
3097    }
3098
3099    if (style === 'opacity') return value ? parseFloat(value) : 1.0;
3100    return value === 'auto' ? null : value;
3101  }
3102
3103  function getStyle_Opera(element, style) {
3104    switch (style) {
3105      case 'height': case 'width':
3106        if (!Element.visible(element)) return null;
3107
3108        var dim = parseInt(getStyle(element, style), 10);
3109
3110        if (dim !== element['offset' + style.capitalize()])
3111          return dim + 'px';
3112
3113        return Element.measure(element, style);
3114
3115      default: return getStyle(element, style);
3116    }
3117  }
3118
3119  function getStyle_IE(element, style) {
3120    element = $(element);
3121    style = normalizeStyleName_IE(style);
3122
3123    var value = element.style[style];
3124    if (!value && element.currentStyle) {
3125      value = element.currentStyle[style];
3126    }
3127
3128    if (style === 'opacity') {
3129      if (!STANDARD_CSS_OPACITY_SUPPORTED)
3130        return getOpacity_IE(element);
3131      else return value ? parseFloat(value) : 1.0;
3132    }
3133
3134    if (value === 'auto') {
3135      if ((style === 'width' || style === 'height') && Element.visible(element))
3136        return Element.measure(element, style) + 'px';
3137      return null;
3138    }
3139
3140    return value;
3141  }
3142
3143  function stripAlphaFromFilter_IE(filter) {
3144    return (filter || '').replace(/alpha\([^\)]*\)/gi, '');
3145  }
3146
3147  function hasLayout_IE(element) {
3148    if (!element.currentStyle || !element.currentStyle.hasLayout)
3149      element.style.zoom = 1;
3150    return element;
3151  }
3152
3153  var STANDARD_CSS_OPACITY_SUPPORTED = (function() {
3154    DIV.style.cssText = "opacity:.55";
3155    return /^0.55/.test(DIV.style.opacity);
3156  })();
3157
3158  function setOpacity(element, value) {
3159    element = $(element);
3160    if (value == 1 || value === '') value = '';
3161    else if (value < 0.00001) value = 0;
3162    element.style.opacity = value;
3163    return element;
3164  }
3165
3166  function setOpacity_IE(element, value) {
3167    if (STANDARD_CSS_OPACITY_SUPPORTED)
3168      return setOpacity(element, value);
3169
3170    element = hasLayout_IE($(element));
3171    var filter = Element.getStyle(element, 'filter'),
3172     style = element.style;
3173
3174    if (value == 1 || value === '') {
3175      filter = stripAlphaFromFilter_IE(filter);
3176      if (filter) style.filter = filter;
3177      else style.removeAttribute('filter');
3178      return element;
3179    }
3180
3181    if (value < 0.00001) value = 0;
3182
3183    style.filter = stripAlphaFromFilter_IE(filter) +
3184     ' alpha(opacity=' + (value * 100) + ')';
3185
3186    return element;
3187  }
3188
3189
3190  function getOpacity(element) {
3191    return Element.getStyle(element, 'opacity');
3192  }
3193
3194  function getOpacity_IE(element) {
3195    if (STANDARD_CSS_OPACITY_SUPPORTED)
3196      return getOpacity(element);
3197
3198    var filter = Element.getStyle(element, 'filter');
3199    if (filter.length === 0) return 1.0;
3200    var match = (filter || '').match(/alpha\(opacity=(.*)\)/i);
3201    if (match && match[1]) return parseFloat(match[1]) / 100;
3202    return 1.0;
3203  }
3204
3205
3206  Object.extend(methods, {
3207    setStyle:   setStyle,
3208    getStyle:   getStyle,
3209    setOpacity: setOpacity,
3210    getOpacity: getOpacity
3211  });
3212
3213  if ('styleFloat' in DIV.style) {
3214    methods.getStyle = getStyle_IE;
3215    methods.setOpacity = setOpacity_IE;
3216    methods.getOpacity = getOpacity_IE;
3217  }
3218
3219  var UID = 0;
3220
3221  GLOBAL.Element.Storage = { UID: 1 };
3222
3223  function getUniqueElementID(element) {
3224    if (element === window) return 0;
3225
3226    if (typeof element._prototypeUID === 'undefined')
3227      element._prototypeUID = Element.Storage.UID++;
3228    return element._prototypeUID;
3229  }
3230
3231  function getUniqueElementID_IE(element) {
3232    if (element === window) return 0;
3233    if (element == document) return 1;
3234    return element.uniqueID;
3235  }
3236
3237  var HAS_UNIQUE_ID_PROPERTY = ('uniqueID' in DIV);
3238  if (HAS_UNIQUE_ID_PROPERTY)
3239    getUniqueElementID = getUniqueElementID_IE;
3240
3241  function getStorage(element) {
3242    if (!(element = $(element))) return;
3243
3244    var uid = getUniqueElementID(element);
3245
3246    if (!Element.Storage[uid])
3247      Element.Storage[uid] = $H();
3248
3249    return Element.Storage[uid];
3250  }
3251
3252  function store(element, key, value) {
3253    if (!(element = $(element))) return;
3254    var storage = getStorage(element);
3255    if (arguments.length === 2) {
3256      storage.update(key);
3257    } else {
3258      storage.set(key, value);
3259    }
3260    return element;
3261  }
3262
3263  function retrieve(element, key, defaultValue) {
3264    if (!(element = $(element))) return;
3265    var storage = getStorage(element), value = storage.get(key);
3266
3267    if (Object.isUndefined(value)) {
3268      storage.set(key, defaultValue);
3269      value = defaultValue;
3270    }
3271
3272    return value;
3273  }
3274
3275
3276  Object.extend(methods, {
3277    getStorage: getStorage,
3278    store:      store,
3279    retrieve:   retrieve
3280  });
3281
3282
3283  var Methods = {}, ByTag = Element.Methods.ByTag,
3284   F = Prototype.BrowserFeatures;
3285
3286  if (!F.ElementExtensions && ('__proto__' in DIV)) {
3287    GLOBAL.HTMLElement = {};
3288    GLOBAL.HTMLElement.prototype = DIV['__proto__'];
3289    F.ElementExtensions = true;
3290  }
3291
3292  function checkElementPrototypeDeficiency(tagName) {
3293    if (typeof window.Element === 'undefined') return false;
3294    if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX) return false;
3295    var proto = window.Element.prototype;
3296    if (proto) {
3297      var id = '_' + (Math.random() + '').slice(2),
3298       el = document.createElement(tagName);
3299      proto[id] = 'x';
3300      var isBuggy = (el[id] !== 'x');
3301      delete proto[id];
3302      el = null;
3303      return isBuggy;
3304    }
3305
3306    return false;
3307  }
3308
3309  var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY =
3310   checkElementPrototypeDeficiency('object');
3311
3312  function extendElementWith(element, methods) {
3313    for (var property in methods) {
3314      var value = methods[property];
3315      if (Object.isFunction(value) && !(property in element))
3316        element[property] = value.methodize();
3317    }
3318  }
3319
3320  var EXTENDED = {};
3321  function elementIsExtended(element) {
3322    var uid = getUniqueElementID(element);
3323    return (uid in EXTENDED);
3324  }
3325
3326  function extend(element) {
3327    if (!element || elementIsExtended(element)) return element;
3328    if (element.nodeType !== Node.ELEMENT_NODE || element == window)
3329      return element;
3330
3331    var methods = Object.clone(Methods),
3332     tagName = element.tagName.toUpperCase();
3333
3334    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
3335
3336    extendElementWith(element, methods);
3337    EXTENDED[getUniqueElementID(element)] = true;
3338    return element;
3339  }
3340
3341  function extend_IE8(element) {
3342    if (!element || elementIsExtended(element)) return element;
3343
3344    var t = element.tagName;
3345    if (t && (/^(?:object|applet|embed)$/i.test(t))) {
3346      extendElementWith(element, Element.Methods);
3347      extendElementWith(element, Element.Methods.Simulated);
3348      extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
3349    }
3350
3351    return element;
3352  }
3353
3354  if (F.SpecificElementExtensions) {
3355    extend = HTMLOBJECTELEMENT_PROTOTYPE_BUGGY ? extend_IE8 : Prototype.K;
3356  }
3357
3358  function addMethodsToTagName(tagName, methods) {
3359    tagName = tagName.toUpperCase();
3360    if (!ByTag[tagName]) ByTag[tagName] = {};
3361    Object.extend(ByTag[tagName], methods);
3362  }
3363
3364  function mergeMethods(destination, methods, onlyIfAbsent) {
3365    if (Object.isUndefined(onlyIfAbsent)) onlyIfAbsent = false;
3366    for (var property in methods) {
3367      var value = methods[property];
3368      if (!Object.isFunction(value)) continue;
3369      if (!onlyIfAbsent || !(property in destination))
3370        destination[property] = value.methodize();
3371    }
3372  }
3373
3374  function findDOMClass(tagName) {
3375    var klass;
3376    var trans = {
3377      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
3378      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
3379      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
3380      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
3381      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
3382      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
3383      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
3384      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
3385      "FrameSet", "IFRAME": "IFrame"
3386    };
3387    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
3388    if (window[klass]) return window[klass];
3389    klass = 'HTML' + tagName + 'Element';
3390    if (window[klass]) return window[klass];
3391    klass = 'HTML' + tagName.capitalize() + 'Element';
3392    if (window[klass]) return window[klass];
3393
3394    var element = document.createElement(tagName),
3395     proto = element['__proto__'] || element.constructor.prototype;
3396
3397    element = null;
3398    return proto;
3399  }
3400
3401  function addMethods(methods) {
3402    if (arguments.length === 0) addFormMethods();
3403
3404    if (arguments.length === 2) {
3405      var tagName = methods;
3406      methods = arguments[1];
3407    }
3408
3409    if (!tagName) {
3410      Object.extend(Element.Methods, methods || {});
3411    } else {
3412      if (Object.isArray(tagName)) {
3413        for (var i = 0, tag; tag = tagName[i]; i++)
3414          addMethodsToTagName(tag, methods);
3415      } else {
3416        addMethodsToTagName(tagName, methods);
3417      }
3418    }
3419
3420    var ELEMENT_PROTOTYPE = window.HTMLElement ? HTMLElement.prototype :
3421     Element.prototype;
3422
3423    if (F.ElementExtensions) {
3424      mergeMethods(ELEMENT_PROTOTYPE, Element.Methods);
3425      mergeMethods(ELEMENT_PROTOTYPE, Element.Methods.Simulated, true);
3426    }
3427
3428    if (F.SpecificElementExtensions) {
3429      for (var tag in Element.Methods.ByTag) {
3430        var klass = findDOMClass(tag);
3431        if (Object.isUndefined(klass)) continue;
3432        mergeMethods(klass.prototype, ByTag[tag]);
3433      }
3434    }
3435
3436    Object.extend(Element, Element.Methods);
3437    Object.extend(Element, Element.Methods.Simulated);
3438    delete Element.ByTag;
3439    delete Element.Simulated;
3440
3441    Element.extend.refresh();
3442
3443    ELEMENT_CACHE = {};
3444  }
3445
3446  Object.extend(GLOBAL.Element, {
3447    extend:     extend,
3448    addMethods: addMethods
3449  });
3450
3451  if (extend === Prototype.K) {
3452    GLOBAL.Element.extend.refresh = Prototype.emptyFunction;
3453  } else {
3454    GLOBAL.Element.extend.refresh = function() {
3455      if (Prototype.BrowserFeatures.ElementExtensions) return;
3456      Object.extend(Methods, Element.Methods);
3457      Object.extend(Methods, Element.Methods.Simulated);
3458
3459      EXTENDED = {};
3460    };
3461  }
3462
3463  function addFormMethods() {
3464    Object.extend(Form, Form.Methods);
3465    Object.extend(Form.Element, Form.Element.Methods);
3466    Object.extend(Element.Methods.ByTag, {
3467      "FORM":     Object.clone(Form.Methods),
3468      "INPUT":    Object.clone(Form.Element.Methods),
3469      "SELECT":   Object.clone(Form.Element.Methods),
3470      "TEXTAREA": Object.clone(Form.Element.Methods),
3471      "BUTTON":   Object.clone(Form.Element.Methods)
3472    });
3473  }
3474
3475  Element.addMethods(methods);
3476
3477  function destroyCache_IE() {
3478    DIV = null;
3479    ELEMENT_CACHE = null;
3480  }
3481
3482  if (window.attachEvent)
3483    window.attachEvent('onunload', destroyCache_IE);
3484
3485})(this);
3486(function() {
3487
3488  function toDecimal(pctString) {
3489    var match = pctString.match(/^(\d+)%?$/i);
3490    if (!match) return null;
3491    return (Number(match[1]) / 100);
3492  }
3493
3494  function getRawStyle(element, style) {
3495    element = $(element);
3496
3497    var value = element.style[style];
3498    if (!value || value === 'auto') {
3499      var css = document.defaultView.getComputedStyle(element, null);
3500      value = css ? css[style] : null;
3501    }
3502
3503    if (style === 'opacity') return value ? parseFloat(value) : 1.0;
3504    return value === 'auto' ? null : value;
3505  }
3506
3507  function getRawStyle_IE(element, style) {
3508    var value = element.style[style];
3509    if (!value && element.currentStyle) {
3510      value = element.currentStyle[style];
3511    }
3512    return value;
3513  }
3514
3515  function getContentWidth(element, context) {
3516    var boxWidth = element.offsetWidth;
3517
3518    var bl = getPixelValue(element, 'borderLeftWidth',  context) || 0;
3519    var br = getPixelValue(element, 'borderRightWidth', context) || 0;
3520    var pl = getPixelValue(element, 'paddingLeft',      context) || 0;
3521    var pr = getPixelValue(element, 'paddingRight',     context) || 0;
3522
3523    return boxWidth - bl - br - pl - pr;
3524  }
3525
3526  if (!Object.isUndefined(document.documentElement.currentStyle) && !Prototype.Browser.Opera) {
3527    getRawStyle = getRawStyle_IE;
3528  }
3529
3530
3531  function getPixelValue(value, property, context) {
3532    var element = null;
3533    if (Object.isElement(value)) {
3534      element = value;
3535      value = getRawStyle(element, property);
3536    }
3537
3538    if (value === null || Object.isUndefined(value)) {
3539      return null;
3540    }
3541
3542    if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
3543      return window.parseFloat(value);
3544    }
3545
3546    var isPercentage = value.include('%'), isViewport = (context === document.viewport);
3547
3548    if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
3549      var style = element.style.left, rStyle = element.runtimeStyle.left;
3550      element.runtimeStyle.left = element.currentStyle.left;
3551      element.style.left = value || 0;
3552      value = element.style.pixelLeft;
3553      element.style.left = style;
3554      element.runtimeStyle.left = rStyle;
3555
3556      return value;
3557    }
3558
3559    if (element && isPercentage) {
3560      context = context || element.parentNode;
3561      var decimal = toDecimal(value), whole = null;
3562
3563      var isHorizontal = property.include('left') || property.include('right') ||
3564       property.include('width');
3565
3566      var isVertical   = property.include('top') || property.include('bottom') ||
3567        property.include('height');
3568
3569      if (context === document.viewport) {
3570        if (isHorizontal) {
3571          whole = document.viewport.getWidth();
3572        } else if (isVertical) {
3573          whole = document.viewport.getHeight();
3574        }
3575      } else {
3576        if (isHorizontal) {
3577          whole = $(context).measure('width');
3578        } else if (isVertical) {
3579          whole = $(context).measure('height');
3580        }
3581      }
3582
3583      return (whole === null) ? 0 : whole * decimal;
3584    }
3585
3586    return 0;
3587  }
3588
3589  function toCSSPixels(number) {
3590    if (Object.isString(number) && number.endsWith('px'))
3591      return number;
3592    return number + 'px';
3593  }
3594
3595  function isDisplayed(element) {
3596    while (element && element.parentNode) {
3597      var display = element.getStyle('display');
3598      if (display === 'none') {
3599        return false;
3600      }
3601      element = $(element.parentNode);
3602    }
3603    return true;
3604  }
3605
3606  var hasLayout = Prototype.K;
3607  if ('currentStyle' in document.documentElement) {
3608    hasLayout = function(element) {
3609      if (!element.currentStyle.hasLayout) {
3610        element.style.zoom = 1;
3611      }
3612      return element;
3613    };
3614  }
3615
3616  function cssNameFor(key) {
3617    if (key.include('border')) key = key + '-width';
3618    return key.camelize();
3619  }
3620
3621  Element.Layout = Class.create(Hash, {
3622    initialize: function($super, element, preCompute) {
3623      $super();
3624      this.element = $(element);
3625
3626      Element.Layout.PROPERTIES.each( function(property) {
3627        this._set(property, null);
3628      }, this);
3629
3630      if (preCompute) {
3631        this._preComputing = true;
3632        this._begin();
3633        Element.Layout.PROPERTIES.each( this._compute, this );
3634        this._end();
3635        this._preComputing = false;
3636      }
3637    },
3638
3639    _set: function(property, value) {
3640      return Hash.prototype.set.call(this, property, value);
3641    },
3642
3643    set: function(property, value) {
3644      throw "Properties of Element.Layout are read-only.";
3645    },
3646
3647    get: function($super, property) {
3648      var value = $super(property);
3649      return value === null ? this._compute(property) : value;
3650    },
3651
3652    _begin: function() {
3653      if (this._isPrepared()) return;
3654
3655      var element = this.element;
3656      if (isDisplayed(element)) {
3657        this._setPrepared(true);
3658        return;
3659      }
3660
3661
3662      var originalStyles = {
3663        position:   element.style.position   || '',
3664        width:      element.style.width      || '',
3665        visibility: element.style.visibility || '',
3666        display:    element.style.display    || ''
3667      };
3668
3669      element.store('prototype_original_styles', originalStyles);
3670
3671      var position = getRawStyle(element, 'position'), width = element.offsetWidth;
3672
3673      if (width === 0 || width === null) {
3674        element.style.display = 'block';
3675        width = element.offsetWidth;
3676      }
3677
3678      var context = (position === 'fixed') ? document.viewport :
3679       element.parentNode;
3680
3681      var tempStyles = {
3682        visibility: 'hidden',
3683        display:    'block'
3684      };
3685
3686      if (position !== 'fixed') tempStyles.position = 'absolute';
3687
3688      element.setStyle(tempStyles);
3689
3690      var positionedWidth = element.offsetWidth, newWidth;
3691      if (width && (positionedWidth === width)) {
3692        newWidth = getContentWidth(element, context);
3693      } else if (position === 'absolute' || position === 'fixed') {
3694        newWidth = getContentWidth(element, context);
3695      } else {
3696        var parent = element.parentNode, pLayout = $(parent).getLayout();
3697
3698        newWidth = pLayout.get('width') -
3699         this.get('margin-left') -
3700         this.get('border-left') -
3701         this.get('padding-left') -
3702         this.get('padding-right') -
3703         this.get('border-right') -
3704         this.get('margin-right');
3705      }
3706
3707      element.setStyle({ width: newWidth + 'px' });
3708
3709      this._setPrepared(true);
3710    },
3711
3712    _end: function() {
3713      var element = this.element;
3714      var originalStyles = element.retrieve('prototype_original_styles');
3715      element.store('prototype_original_styles', null);
3716      element.setStyle(originalStyles);
3717      this._setPrepared(false);
3718    },
3719
3720    _compute: function(property) {
3721      var COMPUTATIONS = Element.Layout.COMPUTATIONS;
3722      if (!(property in COMPUTATIONS)) {
3723        throw "Property not found.";
3724      }
3725
3726      return this._set(property, COMPUTATIONS[property].call(this, this.element));
3727    },
3728
3729    _isPrepared: function() {
3730      return this.element.retrieve('prototype_element_layout_prepared', false);
3731    },
3732
3733    _setPrepared: function(bool) {
3734      return this.element.store('prototype_element_layout_prepared', bool);
3735    },
3736
3737    toObject: function() {
3738      var args = $A(arguments);
3739      var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3740       args.join(' ').split(' ');
3741      var obj = {};
3742      keys.each( function(key) {
3743        if (!Element.Layout.PROPERTIES.include(key)) return;
3744        var value = this.get(key);
3745        if (value != null) obj[key] = value;
3746      }, this);
3747      return obj;
3748    },
3749
3750    toHash: function() {
3751      var obj = this.toObject.apply(this, arguments);
3752      return new Hash(obj);
3753    },
3754
3755    toCSS: function() {
3756      var args = $A(arguments);
3757      var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3758       args.join(' ').split(' ');
3759      var css = {};
3760
3761      keys.each( function(key) {
3762        if (!Element.Layout.PROPERTIES.include(key)) return;
3763        if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return;
3764
3765        var value = this.get(key);
3766        if (value != null) css[cssNameFor(key)] = value + 'px';
3767      }, this);
3768      return css;
3769    },
3770
3771    inspect: function() {
3772      return "#<Element.Layout>";
3773    }
3774  });
3775
3776  Object.extend(Element.Layout, {
3777    PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'),
3778
3779    COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
3780
3781    COMPUTATIONS: {
3782      'height': function(element) {
3783        if (!this._preComputing) this._begin();
3784
3785        var bHeight = this.get('border-box-height');
3786        if (bHeight <= 0) {
3787          if (!this._preComputing) this._end();
3788          return 0;
3789        }
3790
3791        var bTop = this.get('border-top'),
3792         bBottom = this.get('border-bottom');
3793
3794        var pTop = this.get('padding-top'),
3795         pBottom = this.get('padding-bottom');
3796
3797        if (!this._preComputing) this._end();
3798
3799        return bHeight - bTop - bBottom - pTop - pBottom;
3800      },
3801
3802      'width': function(element) {
3803        if (!this._preComputing) this._begin();
3804
3805        var bWidth = this.get('border-box-width');
3806        if (bWidth <= 0) {
3807          if (!this._preComputing) this._end();
3808          return 0;
3809        }
3810
3811        var bLeft = this.get('border-left'),
3812         bRight = this.get('border-right');
3813
3814        var pLeft = this.get('padding-left'),
3815         pRight = this.get('padding-right');
3816
3817        if (!this._preComputing) this._end();
3818        return bWidth - bLeft - bRight - pLeft - pRight;
3819      },
3820
3821      'padding-box-height': function(element) {
3822        var height = this.get('height'),
3823         pTop = this.get('padding-top'),
3824         pBottom = this.get('padding-bottom');
3825
3826        return height + pTop + pBottom;
3827      },
3828
3829      'padding-box-width': function(element) {
3830        var width = this.get('width'),
3831         pLeft = this.get('padding-left'),
3832         pRight = this.get('padding-right');
3833
3834        return width + pLeft + pRight;
3835      },
3836
3837      'border-box-height': function(element) {
3838        if (!this._preComputing) this._begin();
3839        var height = element.offsetHeight;
3840        if (!this._preComputing) this._end();
3841        return height;
3842      },
3843
3844      'border-box-width': function(element) {
3845        if (!this._preComputing) this._begin();
3846        var width = element.offsetWidth;
3847        if (!this._preComputing) this._end();
3848        return width;
3849      },
3850
3851      'margin-box-height': function(element) {
3852        var bHeight = this.get('border-box-height'),
3853         mTop = this.get('margin-top'),
3854         mBottom = this.get('margin-bottom');
3855
3856        if (bHeight <= 0) return 0;
3857
3858        return bHeight + mTop + mBottom;
3859      },
3860
3861      'margin-box-width': function(element) {
3862        var bWidth = this.get('border-box-width'),
3863         mLeft = this.get('margin-left'),
3864         mRight = this.get('margin-right');
3865
3866        if (bWidth <= 0) return 0;
3867
3868        return bWidth + mLeft + mRight;
3869      },
3870
3871      'top': function(element) {
3872        var offset = element.positionedOffset();
3873        return offset.top;
3874      },
3875
3876      'bottom': function(element) {
3877        var offset = element.positionedOffset(),
3878         parent = element.getOffsetParent(),
3879         pHeight = parent.measure('height');
3880
3881        var mHeight = this.get('border-box-height');
3882
3883        return pHeight - mHeight - offset.top;
3884      },
3885
3886      'left': function(element) {
3887        var offset = element.positionedOffset();
3888        return offset.left;
3889      },
3890
3891      'right': function(element) {
3892        var offset = element.positionedOffset(),
3893         parent = element.getOffsetParent(),
3894         pWidth = parent.measure('width');
3895
3896        var mWidth = this.get('border-box-width');
3897
3898        return pWidth - mWidth - offset.left;
3899      },
3900
3901      'padding-top': function(element) {
3902        return getPixelValue(element, 'paddingTop');
3903      },
3904
3905      'padding-bottom': function(element) {
3906        return getPixelValue(element, 'paddingBottom');
3907      },
3908
3909      'padding-left': function(element) {
3910        return getPixelValue(element, 'paddingLeft');
3911      },
3912
3913      'padding-right': function(element) {
3914        return getPixelValue(element, 'paddingRight');
3915      },
3916
3917      'border-top': function(element) {
3918        return getPixelValue(element, 'borderTopWidth');
3919      },
3920
3921      'border-bottom': function(element) {
3922        return getPixelValue(element, 'borderBottomWidth');
3923      },
3924
3925      'border-left': function(element) {
3926        return getPixelValue(element, 'borderLeftWidth');
3927      },
3928
3929      'border-right': function(element) {
3930        return getPixelValue(element, 'borderRightWidth');
3931      },
3932
3933      'margin-top': function(element) {
3934        return getPixelValue(element, 'marginTop');
3935      },
3936
3937      'margin-bottom': function(element) {
3938        return getPixelValue(element, 'marginBottom');
3939      },
3940
3941      'margin-left': function(element) {
3942        return getPixelValue(element, 'marginLeft');
3943      },
3944
3945      'margin-right': function(element) {
3946        return getPixelValue(element, 'marginRight');
3947      }
3948    }
3949  });
3950
3951  if ('getBoundingClientRect' in document.documentElement) {
3952    Object.extend(Element.Layout.COMPUTATIONS, {
3953      'right': function(element) {
3954        var parent = hasLayout(element.getOffsetParent());
3955        var rect = element.getBoundingClientRect(),
3956         pRect = parent.getBoundingClientRect();
3957
3958        return (pRect.right - rect.right).round();
3959      },
3960
3961      'bottom': function(element) {
3962        var parent = hasLayout(element.getOffsetParent());
3963        var rect = element.getBoundingClientRect(),
3964         pRect = parent.getBoundingClientRect();
3965
3966        return (pRect.bottom - rect.bottom).round();
3967      }
3968    });
3969  }
3970
3971  Element.Offset = Class.create({
3972    initialize: function(left, top) {
3973      this.left = left.round();
3974      this.top  = top.round();
3975
3976      this[0] = this.left;
3977      this[1] = this.top;
3978    },
3979
3980    relativeTo: function(offset) {
3981      return new Element.Offset(
3982        this.left - offset.left,
3983        this.top  - offset.top
3984      );
3985    },
3986
3987    inspect: function() {
3988      return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
3989    },
3990
3991    toString: function() {
3992      return "[#{left}, #{top}]".interpolate(this);
3993    },
3994
3995    toArray: function() {
3996      return [this.left, this.top];
3997    }
3998  });
3999
4000  function getLayout(element, preCompute) {
4001    return new Element.Layout(element, preCompute);
4002  }
4003
4004  function measure(element, property) {
4005    return $(element).getLayout().get(property);
4006  }
4007
4008  function getHeight(element) {
4009    return Element.getDimensions(element).height;
4010  }
4011
4012  function getWidth(element) {
4013    return Element.getDimensions(element).width;
4014  }
4015
4016  function getDimensions(element) {
4017    element = $(element);
4018    var display = Element.getStyle(element, 'display');
4019
4020    if (display && display !== 'none') {
4021      return { width: element.offsetWidth, height: element.offsetHeight };
4022    }
4023
4024    var style = element.style;
4025    var originalStyles = {
4026      visibility: style.visibility,
4027      position:   style.position,
4028      display:    style.display
4029    };
4030
4031    var newStyles = {
4032      visibility: 'hidden',
4033      display:    'block'
4034    };
4035
4036    if (originalStyles.position !== 'fixed')
4037      newStyles.position = 'absolute';
4038
4039    Element.setStyle(element, newStyles);
4040
4041    var dimensions = {
4042      width:  element.offsetWidth,
4043      height: element.offsetHeight
4044    };
4045
4046    Element.setStyle(element, originalStyles);
4047
4048    return dimensions;
4049  }
4050
4051  function getOffsetParent(element) {
4052    element = $(element);
4053
4054    function selfOrBody(element) {
4055      return isHtml(element) ? $(document.body) : $(element);
4056    }
4057
4058    if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
4059      return $(document.body);
4060
4061    var isInline = (Element.getStyle(element, 'display') === 'inline');
4062    if (!isInline && element.offsetParent) return selfOrBody(element.offsetParent);
4063
4064    while ((element = element.parentNode) && element !== document.body) {
4065      if (Element.getStyle(element, 'position') !== 'static') {
4066        return selfOrBody(element);
4067      }
4068    }
4069
4070    return $(document.body);
4071  }
4072
4073
4074  function cumulativeOffset(element) {
4075    element = $(element);
4076    var valueT = 0, valueL = 0;
4077    if (element.parentNode) {
4078      do {
4079        valueT += element.offsetTop  || 0;
4080        valueL += element.offsetLeft || 0;
4081        element = element.offsetParent;
4082      } while (element);
4083    }
4084    return new Element.Offset(valueL, valueT);
4085  }
4086
4087  function positionedOffset(element) {
4088    element = $(element);
4089
4090    var layout = element.getLayout();
4091
4092    var valueT = 0, valueL = 0;
4093    do {
4094      valueT += element.offsetTop  || 0;
4095      valueL += element.offsetLeft || 0;
4096      element = element.offsetParent;
4097      if (element) {
4098        if (isBody(element)) break;
4099        var p = Element.getStyle(element, 'position');
4100        if (p !== 'static') break;
4101      }
4102    } while (element);
4103
4104    valueL -= layout.get('margin-left');
4105    valueT -= layout.get('margin-top');
4106
4107    return new Element.Offset(valueL, valueT);
4108  }
4109
4110  function cumulativeScrollOffset(element) {
4111    var valueT = 0, valueL = 0;
4112    do {
4113      if (element === document.body) {
4114        var bodyScrollNode = document.documentElement || document.body.parentNode || document.body;
4115        valueT += !Object.isUndefined(window.pageYOffset) ? window.pageYOffset : bodyScrollNode.scrollTop || 0;
4116        valueL += !Object.isUndefined(window.pageXOffset) ? window.pageXOffset : bodyScrollNode.scrollLeft || 0;
4117        break;
4118      } else {
4119        valueT += element.scrollTop  || 0;
4120        valueL += element.scrollLeft || 0;
4121        element = element.parentNode;
4122      }
4123    } while (element);
4124    return new Element.Offset(valueL, valueT);
4125  }
4126
4127  function viewportOffset(forElement) {
4128    var valueT = 0, valueL = 0, docBody = document.body;
4129
4130    forElement = $(forElement);
4131    var element = forElement;
4132    do {
4133      valueT += element.offsetTop  || 0;
4134      valueL += element.offsetLeft || 0;
4135      if (element.offsetParent == docBody &&
4136        Element.getStyle(element, 'position') == 'absolute') break;
4137    } while (element = element.offsetParent);
4138
4139    element = forElement;
4140    do {
4141      if (element != docBody) {
4142        valueT -= element.scrollTop  || 0;
4143        valueL -= element.scrollLeft || 0;
4144      }
4145    } while (element = element.parentNode);
4146    return new Element.Offset(valueL, valueT);
4147  }
4148
4149  function absolutize(element) {
4150    element = $(element);
4151
4152    if (Element.getStyle(element, 'position') === 'absolute') {
4153      return element;
4154    }
4155
4156    var offsetParent = getOffsetParent(element);
4157    var eOffset = element.viewportOffset(),
4158     pOffset = offsetParent.viewportOffset();
4159
4160    var offset = eOffset.relativeTo(pOffset);
4161    var layout = element.getLayout();
4162
4163    element.store('prototype_absolutize_original_styles', {
4164      position: element.getStyle('position'),
4165      left:     element.getStyle('left'),
4166      top:      element.getStyle('top'),
4167      width:    element.getStyle('width'),
4168      height:   element.getStyle('height')
4169    });
4170
4171    element.setStyle({
4172      position: 'absolute',
4173      top:    offset.top + 'px',
4174      left:   offset.left + 'px',
4175      width:  layout.get('width') + 'px',
4176      height: layout.get('height') + 'px'
4177    });
4178
4179    return element;
4180  }
4181
4182  function relativize(element) {
4183    element = $(element);
4184    if (Element.getStyle(element, 'position') === 'relative') {
4185      return element;
4186    }
4187
4188    var originalStyles =
4189     element.retrieve('prototype_absolutize_original_styles');
4190
4191    if (originalStyles) element.setStyle(originalStyles);
4192    return element;
4193  }
4194
4195
4196  function scrollTo(element) {
4197    element = $(element);
4198    var pos = Element.cumulativeOffset(element);
4199    window.scrollTo(pos.left, pos.top);
4200    return element;
4201  }
4202
4203
4204  function makePositioned(element) {
4205    element = $(element);
4206    var position = Element.getStyle(element, 'position'), styles = {};
4207    if (position === 'static' || !position) {
4208      styles.position = 'relative';
4209      if (Prototype.Browser.Opera) {
4210        styles.top  = 0;
4211        styles.left = 0;
4212      }
4213      Element.setStyle(element, styles);
4214      Element.store(element, 'prototype_made_positioned', true);
4215    }
4216    return element;
4217  }
4218
4219  function undoPositioned(element) {
4220    element = $(element);
4221    var storage = Element.getStorage(element),
4222     madePositioned = storage.get('prototype_made_positioned');
4223
4224    if (madePositioned) {
4225      storage.unset('prototype_made_positioned');
4226      Element.setStyle(element, {
4227        position: '',
4228        top:      '',
4229        bottom:   '',
4230        left:     '',
4231        right:    ''
4232      });
4233    }
4234    return element;
4235  }
4236
4237  function makeClipping(element) {
4238    element = $(element);
4239
4240    var storage = Element.getStorage(element),
4241     madeClipping = storage.get('prototype_made_clipping');
4242
4243    if (Object.isUndefined(madeClipping)) {
4244      var overflow = Element.getStyle(element, 'overflow');
4245      storage.set('prototype_made_clipping', overflow);
4246      if (overflow !== 'hidden')
4247        element.style.overflow = 'hidden';
4248    }
4249
4250    return element;
4251  }
4252
4253  function undoClipping(element) {
4254    element = $(element);
4255    var storage = Element.getStorage(element),
4256     overflow = storage.get('prototype_made_clipping');
4257
4258    if (!Object.isUndefined(overflow)) {
4259      storage.unset('prototype_made_clipping');
4260      element.style.overflow = overflow || '';
4261    }
4262
4263    return element;
4264  }
4265
4266  function clonePosition(element, source, options) {
4267    options = Object.extend({
4268      setLeft:    true,
4269      setTop:     true,
4270      setWidth:   true,
4271      setHeight:  true,
4272      offsetTop:  0,
4273      offsetLeft: 0
4274    }, options || {});
4275
4276    var docEl = document.documentElement;
4277
4278    source  = $(source);
4279    element = $(element);
4280    var p, delta, layout, styles = {};
4281
4282    if (options.setLeft || options.setTop) {
4283      p = Element.viewportOffset(source);
4284      delta = [0, 0];
4285      if (Element.getStyle(element, 'position') === 'absolute') {
4286        var parent = Element.getOffsetParent(element);
4287        if (parent !== document.body) delta = Element.viewportOffset(parent);
4288      }
4289    }
4290
4291    function pageScrollXY() {
4292      var x = 0, y = 0;
4293      if (Object.isNumber(window.pageXOffset)) {
4294        x = window.pageXOffset;
4295        y = window.pageYOffset;
4296      } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
4297        x = document.body.scrollLeft;
4298        y = document.body.scrollTop;
4299      } else if (docEl && (docEl.scrollLeft || docEl.scrollTop)) {
4300        x = docEl.scrollLeft;
4301        y = docEl.scrollTop;
4302      }
4303      return { x: x, y: y };
4304    }
4305
4306    var pageXY = pageScrollXY();
4307
4308
4309    if (options.setWidth || options.setHeight) {
4310      layout = Element.getLayout(source);
4311    }
4312
4313    if (options.setLeft)
4314      styles.left = (p[0] + pageXY.x - delta[0] + options.offsetLeft) + 'px';
4315    if (options.setTop)
4316      styles.top  = (p[1] + pageXY.y - delta[1] + options.offsetTop)  + 'px';
4317
4318    var currentLayout = element.getLayout();
4319
4320    if (options.setWidth) {
4321      styles.width = layout.get('width')  + 'px';
4322    }
4323    if (options.setHeight) {
4324      styles.height = layout.get('height') + 'px';
4325    }
4326
4327    return Element.setStyle(element, styles);
4328  }
4329
4330
4331  if (Prototype.Browser.IE) {
4332    getOffsetParent = getOffsetParent.wrap(
4333      function(proceed, element) {
4334        element = $(element);
4335
4336        if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
4337          return $(document.body);
4338
4339        var position = element.getStyle('position');
4340        if (position !== 'static') return proceed(element);
4341
4342        element.setStyle({ position: 'relative' });
4343        var value = proceed(element);
4344        element.setStyle({ position: position });
4345        return value;
4346      }
4347    );
4348
4349    positionedOffset = positionedOffset.wrap(function(proceed, element) {
4350      element = $(element);
4351      if (!element.parentNode) return new Element.Offset(0, 0);
4352      var position = element.getStyle('position');
4353      if (position !== 'static') return proceed(element);
4354
4355      var offsetParent = element.getOffsetParent();
4356      if (offsetParent && offsetParent.getStyle('position') === 'fixed')
4357        hasLayout(offsetParent);
4358
4359      element.setStyle({ position: 'relative' });
4360      var value = proceed(element);
4361      element.setStyle({ position: position });
4362      return value;
4363    });
4364  } else if (Prototype.Browser.Webkit) {
4365    cumulativeOffset = function(element) {
4366      element = $(element);
4367      var valueT = 0, valueL = 0;
4368      do {
4369        valueT += element.offsetTop  || 0;
4370        valueL += element.offsetLeft || 0;
4371        if (element.offsetParent == document.body) {
4372          if (Element.getStyle(element, 'position') == 'absolute') break;
4373        }
4374
4375        element = element.offsetParent;
4376      } while (element);
4377
4378      return new Element.Offset(valueL, valueT);
4379    };
4380  }
4381
4382
4383  Element.addMethods({
4384    getLayout:              getLayout,
4385    measure:                measure,
4386    getWidth:               getWidth,
4387    getHeight:              getHeight,
4388    getDimensions:          getDimensions,
4389    getOffsetParent:        getOffsetParent,
4390    cumulativeOffset:       cumulativeOffset,
4391    positionedOffset:       positionedOffset,
4392    cumulativeScrollOffset: cumulativeScrollOffset,
4393    viewportOffset:         viewportOffset,
4394    absolutize:             absolutize,
4395    relativize:             relativize,
4396    scrollTo:               scrollTo,
4397    makePositioned:         makePositioned,
4398    undoPositioned:         undoPositioned,
4399    makeClipping:           makeClipping,
4400    undoClipping:           undoClipping,
4401    clonePosition:          clonePosition
4402  });
4403
4404  function isBody(element) {
4405    return element.nodeName.toUpperCase() === 'BODY';
4406  }
4407
4408  function isHtml(element) {
4409    return element.nodeName.toUpperCase() === 'HTML';
4410  }
4411
4412  function isDocument(element) {
4413    return element.nodeType === Node.DOCUMENT_NODE;
4414  }
4415
4416  function isDetached(element) {
4417    return element !== document.body &&
4418     !Element.descendantOf(element, document.body);
4419  }
4420
4421  if ('getBoundingClientRect' in document.documentElement) {
4422    Element.addMethods({
4423      viewportOffset: function(element) {
4424        element = $(element);
4425        if (isDetached(element)) return new Element.Offset(0, 0);
4426
4427        var rect = element.getBoundingClientRect(),
4428         docEl = document.documentElement;
4429        return new Element.Offset(rect.left - docEl.clientLeft,
4430         rect.top - docEl.clientTop);
4431      }
4432    });
4433  }
4434
4435
4436})();
4437
4438(function() {
4439
4440  var IS_OLD_OPERA = Prototype.Browser.Opera &&
4441   (window.parseFloat(window.opera.version()) < 9.5);
4442  var ROOT = null;
4443  function getRootElement() {
4444    if (ROOT) return ROOT;
4445    ROOT = IS_OLD_OPERA ? document.body : document.documentElement;
4446    return ROOT;
4447  }
4448
4449  function getDimensions() {
4450    return { width: this.getWidth(), height: this.getHeight() };
4451  }
4452
4453  function getWidth() {
4454    return getRootElement().clientWidth;
4455  }
4456
4457  function getHeight() {
4458    return getRootElement().clientHeight;
4459  }
4460
4461  function getScrollOffsets() {
4462    var x = window.pageXOffset || document.documentElement.scrollLeft ||
4463     document.body.scrollLeft;
4464    var y = window.pageYOffset || document.documentElement.scrollTop ||
4465     document.body.scrollTop;
4466
4467    return new Element.Offset(x, y);
4468  }
4469
4470  document.viewport = {
4471    getDimensions:    getDimensions,
4472    getWidth:         getWidth,
4473    getHeight:        getHeight,
4474    getScrollOffsets: getScrollOffsets
4475  };
4476
4477})();
4478window.$$ = function() {
4479  var expression = $A(arguments).join(', ');
4480  return Prototype.Selector.select(expression, document);
4481};
4482
4483Prototype.Selector = (function() {
4484
4485  function select() {
4486    throw new Error('Method "Prototype.Selector.select" must be defined.');
4487  }
4488
4489  function match() {
4490    throw new Error('Method "Prototype.Selector.match" must be defined.');
4491  }
4492
4493  function find(elements, expression, index) {
4494    index = index || 0;
4495    var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i;
4496
4497    for (i = 0; i < length; i++) {
4498      if (match(elements[i], expression) && index == matchIndex++) {
4499        return Element.extend(elements[i]);
4500      }
4501    }
4502  }
4503
4504  function extendElements(elements) {
4505    for (var i = 0, length = elements.length; i < length; i++) {
4506      Element.extend(elements[i]);
4507    }
4508    return elements;
4509  }
4510
4511
4512  var K = Prototype.K;
4513
4514  return {
4515    select: select,
4516    match: match,
4517    find: find,
4518    extendElements: (Element.extend === K) ? K : extendElements,
4519    extendElement: Element.extend
4520  };
4521})();
4522Prototype._original_property = window.Sizzle;
4523
4524;(function () {
4525  function fakeDefine(fn) {
4526    Prototype._actual_sizzle = fn();
4527  }
4528  fakeDefine.amd = true;
4529
4530  if (typeof define !== 'undefined' && define.amd) {
4531    Prototype._original_define = define;
4532    Prototype._actual_sizzle = null;
4533    window.define = fakeDefine;
4534  }
4535})();
4536
4537/*!
4538 * Sizzle CSS Selector Engine v1.10.18
4539 * http://sizzlejs.com/
4540 *
4541 * Copyright 2013 jQuery Foundation, Inc. and other contributors
4542 * Released under the MIT license
4543 * http://jquery.org/license
4544 *
4545 * Date: 2014-02-05
4546 */
4547(function( window ) {
4548
4549var i,
4550	support,
4551	Expr,
4552	getText,
4553	isXML,
4554	compile,
4555	select,
4556	outermostContext,
4557	sortInput,
4558	hasDuplicate,
4559
4560	setDocument,
4561	document,
4562	docElem,
4563	documentIsHTML,
4564	rbuggyQSA,
4565	rbuggyMatches,
4566	matches,
4567	contains,
4568
4569	expando = "sizzle" + -(new Date()),
4570	preferredDoc = window.document,
4571	dirruns = 0,
4572	done = 0,
4573	classCache = createCache(),
4574	tokenCache = createCache(),
4575	compilerCache = createCache(),
4576	sortOrder = function( a, b ) {
4577		if ( a === b ) {
4578			hasDuplicate = true;
4579		}
4580		return 0;
4581	},
4582
4583	strundefined = typeof undefined,
4584	MAX_NEGATIVE = 1 << 31,
4585
4586	hasOwn = ({}).hasOwnProperty,
4587	arr = [],
4588	pop = arr.pop,
4589	push_native = arr.push,
4590	push = arr.push,
4591	slice = arr.slice,
4592	indexOf = arr.indexOf || function( elem ) {
4593		var i = 0,
4594			len = this.length;
4595		for ( ; i < len; i++ ) {
4596			if ( this[i] === elem ) {
4597				return i;
4598			}
4599		}
4600		return -1;
4601	},
4602
4603	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
4604
4605
4606	whitespace = "[\\x20\\t\\r\\n\\f]",
4607	characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
4608
4609	identifier = characterEncoding.replace( "w", "w#" ),
4610
4611	attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
4612		"*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
4613
4614	pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
4615
4616	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
4617
4618	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
4619	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
4620
4621	rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
4622
4623	rpseudo = new RegExp( pseudos ),
4624	ridentifier = new RegExp( "^" + identifier + "$" ),
4625
4626	matchExpr = {
4627		"ID": new RegExp( "^#(" + characterEncoding + ")" ),
4628		"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
4629		"TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
4630		"ATTR": new RegExp( "^" + attributes ),
4631		"PSEUDO": new RegExp( "^" + pseudos ),
4632		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
4633			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
4634			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
4635		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
4636		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
4637			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
4638	},
4639
vendor: 38,600 bytes, lines 4640-6193
4640	rinputs = /^(?:input|select|textarea|button)$/i,
4641	rheader = /^h\d$/i,
4642
4643	rnative = /^[^{]+\{\s*\[native \w/,
4644
4645	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
4646
4647	rsibling = /[+~]/,
4648	rescape = /'|\\/g,
4649
4650	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
4651	funescape = function( _, escaped, escapedWhitespace ) {
4652		var high = "0x" + escaped - 0x10000;
4653		return high !== high || escapedWhitespace ?
4654			escaped :
4655			high < 0 ?
4656				String.fromCharCode( high + 0x10000 ) :
4657				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
4658	};
4659
4660try {
4661	push.apply(
4662		(arr = slice.call( preferredDoc.childNodes )),
4663		preferredDoc.childNodes
4664	);
4665	arr[ preferredDoc.childNodes.length ].nodeType;
4666} catch ( e ) {
4667	push = { apply: arr.length ?
4668
4669		function( target, els ) {
4670			push_native.apply( target, slice.call(els) );
4671		} :
4672
4673		function( target, els ) {
4674			var j = target.length,
4675				i = 0;
4676			while ( (target[j++] = els[i++]) ) {}
4677			target.length = j - 1;
4678		}
4679	};
4680}
4681
4682function Sizzle( selector, context, results, seed ) {
4683	var match, elem, m, nodeType,
4684		i, groups, old, nid, newContext, newSelector;
4685
4686	if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
4687		setDocument( context );
4688	}
4689
4690	context = context || document;
4691	results = results || [];
4692
4693	if ( !selector || typeof selector !== "string" ) {
4694		return results;
4695	}
4696
4697	if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
4698		return [];
4699	}
4700
4701	if ( documentIsHTML && !seed ) {
4702
4703		if ( (match = rquickExpr.exec( selector )) ) {
4704			if ( (m = match[1]) ) {
4705				if ( nodeType === 9 ) {
4706					elem = context.getElementById( m );
4707					if ( elem && elem.parentNode ) {
4708						if ( elem.id === m ) {
4709							results.push( elem );
4710							return results;
4711						}
4712					} else {
4713						return results;
4714					}
4715				} else {
4716					if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
4717						contains( context, elem ) && elem.id === m ) {
4718						results.push( elem );
4719						return results;
4720					}
4721				}
4722
4723			} else if ( match[2] ) {
4724				push.apply( results, context.getElementsByTagName( selector ) );
4725				return results;
4726
4727			} else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
4728				push.apply( results, context.getElementsByClassName( m ) );
4729				return results;
4730			}
4731		}
4732
4733		if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
4734			nid = old = expando;
4735			newContext = context;
4736			newSelector = nodeType === 9 && selector;
4737
4738			if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
4739				groups = tokenize( selector );
4740
4741				if ( (old = context.getAttribute("id")) ) {
4742					nid = old.replace( rescape, "\\$&" );
4743				} else {
4744					context.setAttribute( "id", nid );
4745				}
4746				nid = "[id='" + nid + "'] ";
4747
4748				i = groups.length;
4749				while ( i-- ) {
4750					groups[i] = nid + toSelector( groups[i] );
4751				}
4752				newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
4753				newSelector = groups.join(",");
4754			}
4755
4756			if ( newSelector ) {
4757				try {
4758					push.apply( results,
4759						newContext.querySelectorAll( newSelector )
4760					);
4761					return results;
4762				} catch(qsaError) {
4763				} finally {
4764					if ( !old ) {
4765						context.removeAttribute("id");
4766					}
4767				}
4768			}
4769		}
4770	}
4771
4772	return select( selector.replace( rtrim, "$1" ), context, results, seed );
4773}
4774
4775/**
4776 * Create key-value caches of limited size
4777 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
4778 *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
4779 *	deleting the oldest entry
4780 */
4781function createCache() {
4782	var keys = [];
4783
4784	function cache( key, value ) {
4785		if ( keys.push( key + " " ) > Expr.cacheLength ) {
4786			delete cache[ keys.shift() ];
4787		}
4788		return (cache[ key + " " ] = value);
4789	}
4790	return cache;
4791}
4792
4793/**
4794 * Mark a function for special use by Sizzle
4795 * @param {Function} fn The function to mark
4796 */
4797function markFunction( fn ) {
4798	fn[ expando ] = true;
4799	return fn;
4800}
4801
4802/**
4803 * Support testing using an element
4804 * @param {Function} fn Passed the created div and expects a boolean result
4805 */
4806function assert( fn ) {
4807	var div = document.createElement("div");
4808
4809	try {
4810		return !!fn( div );
4811	} catch (e) {
4812		return false;
4813	} finally {
4814		if ( div.parentNode ) {
4815			div.parentNode.removeChild( div );
4816		}
4817		div = null;
4818	}
4819}
4820
4821/**
4822 * Adds the same handler for all of the specified attrs
4823 * @param {String} attrs Pipe-separated list of attributes
4824 * @param {Function} handler The method that will be applied
4825 */
4826function addHandle( attrs, handler ) {
4827	var arr = attrs.split("|"),
4828		i = attrs.length;
4829
4830	while ( i-- ) {
4831		Expr.attrHandle[ arr[i] ] = handler;
4832	}
4833}
4834
4835/**
4836 * Checks document order of two siblings
4837 * @param {Element} a
4838 * @param {Element} b
4839 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
4840 */
4841function siblingCheck( a, b ) {
4842	var cur = b && a,
4843		diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
4844			( ~b.sourceIndex || MAX_NEGATIVE ) -
4845			( ~a.sourceIndex || MAX_NEGATIVE );
4846
4847	if ( diff ) {
4848		return diff;
4849	}
4850
4851	if ( cur ) {
4852		while ( (cur = cur.nextSibling) ) {
4853			if ( cur === b ) {
4854				return -1;
4855			}
4856		}
4857	}
4858
4859	return a ? 1 : -1;
4860}
4861
4862/**
4863 * Returns a function to use in pseudos for input types
4864 * @param {String} type
4865 */
4866function createInputPseudo( type ) {
4867	return function( elem ) {
4868		var name = elem.nodeName.toLowerCase();
4869		return name === "input" && elem.type === type;
4870	};
4871}
4872
4873/**
4874 * Returns a function to use in pseudos for buttons
4875 * @param {String} type
4876 */
4877function createButtonPseudo( type ) {
4878	return function( elem ) {
4879		var name = elem.nodeName.toLowerCase();
4880		return (name === "input" || name === "button") && elem.type === type;
4881	};
4882}
4883
4884/**
4885 * Returns a function to use in pseudos for positionals
4886 * @param {Function} fn
4887 */
4888function createPositionalPseudo( fn ) {
4889	return markFunction(function( argument ) {
4890		argument = +argument;
4891		return markFunction(function( seed, matches ) {
4892			var j,
4893				matchIndexes = fn( [], seed.length, argument ),
4894				i = matchIndexes.length;
4895
4896			while ( i-- ) {
4897				if ( seed[ (j = matchIndexes[i]) ] ) {
4898					seed[j] = !(matches[j] = seed[j]);
4899				}
4900			}
4901		});
4902	});
4903}
4904
4905/**
4906 * Checks a node for validity as a Sizzle context
4907 * @param {Element|Object=} context
4908 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
4909 */
4910function testContext( context ) {
4911	return context && typeof context.getElementsByTagName !== strundefined && context;
4912}
4913
4914support = Sizzle.support = {};
4915
4916/**
4917 * Detects XML nodes
4918 * @param {Element|Object} elem An element or a document
4919 * @returns {Boolean} True iff elem is a non-HTML XML node
4920 */
4921isXML = Sizzle.isXML = function( elem ) {
4922	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
4923	return documentElement ? documentElement.nodeName !== "HTML" : false;
4924};
4925
4926/**
4927 * Sets document-related variables once based on the current document
4928 * @param {Element|Object} [doc] An element or document object to use to set the document
4929 * @returns {Object} Returns the current document
4930 */
4931setDocument = Sizzle.setDocument = function( node ) {
4932	var hasCompare,
4933		doc = node ? node.ownerDocument || node : preferredDoc,
4934		parent = doc.defaultView;
4935
4936	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
4937		return document;
4938	}
4939
4940	document = doc;
4941	docElem = doc.documentElement;
4942
4943	documentIsHTML = !isXML( doc );
4944
4945	if ( parent && parent !== parent.top ) {
4946		if ( parent.addEventListener ) {
4947			parent.addEventListener( "unload", function() {
4948				setDocument();
4949			}, false );
4950		} else if ( parent.attachEvent ) {
4951			parent.attachEvent( "onunload", function() {
4952				setDocument();
4953			});
4954		}
4955	}
4956
4957	/* Attributes
4958	---------------------------------------------------------------------- */
4959
4960	support.attributes = assert(function( div ) {
4961		div.className = "i";
4962		return !div.getAttribute("className");
4963	});
4964
4965	/* getElement(s)By*
4966	---------------------------------------------------------------------- */
4967
4968	support.getElementsByTagName = assert(function( div ) {
4969		div.appendChild( doc.createComment("") );
4970		return !div.getElementsByTagName("*").length;
4971	});
4972
4973	support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
4974		div.innerHTML = "<div class='a'></div><div class='a i'></div>";
4975
4976		div.firstChild.className = "i";
4977		return div.getElementsByClassName("i").length === 2;
4978	});
4979
4980	support.getById = assert(function( div ) {
4981		docElem.appendChild( div ).id = expando;
4982		return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
4983	});
4984
4985	if ( support.getById ) {
4986		Expr.find["ID"] = function( id, context ) {
4987			if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
4988				var m = context.getElementById( id );
4989				return m && m.parentNode ? [m] : [];
4990			}
4991		};
4992		Expr.filter["ID"] = function( id ) {
4993			var attrId = id.replace( runescape, funescape );
4994			return function( elem ) {
4995				return elem.getAttribute("id") === attrId;
4996			};
4997		};
4998	} else {
4999		delete Expr.find["ID"];
5000
5001		Expr.filter["ID"] =  function( id ) {
5002			var attrId = id.replace( runescape, funescape );
5003			return function( elem ) {
5004				var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
5005				return node && node.value === attrId;
5006			};
5007		};
5008	}
5009
5010	Expr.find["TAG"] = support.getElementsByTagName ?
5011		function( tag, context ) {
5012			if ( typeof context.getElementsByTagName !== strundefined ) {
5013				return context.getElementsByTagName( tag );
5014			}
5015		} :
5016		function( tag, context ) {
5017			var elem,
5018				tmp = [],
5019				i = 0,
5020				results = context.getElementsByTagName( tag );
5021
5022			if ( tag === "*" ) {
5023				while ( (elem = results[i++]) ) {
5024					if ( elem.nodeType === 1 ) {
5025						tmp.push( elem );
5026					}
5027				}
5028
5029				return tmp;
5030			}
5031			return results;
5032		};
5033
5034	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
5035		if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
5036			return context.getElementsByClassName( className );
5037		}
5038	};
5039
5040	/* QSA/matchesSelector
5041	---------------------------------------------------------------------- */
5042
5043
5044	rbuggyMatches = [];
5045
5046	rbuggyQSA = [];
5047
5048	if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
5049		assert(function( div ) {
5050			div.innerHTML = "<select t=''><option selected=''></option></select>";
5051
5052			if ( div.querySelectorAll("[t^='']").length ) {
5053				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
5054			}
5055
5056			if ( !div.querySelectorAll("[selected]").length ) {
5057				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
5058			}
5059
5060			if ( !div.querySelectorAll(":checked").length ) {
5061				rbuggyQSA.push(":checked");
5062			}
5063		});
5064
5065		assert(function( div ) {
5066			var input = doc.createElement("input");
5067			input.setAttribute( "type", "hidden" );
5068			div.appendChild( input ).setAttribute( "name", "D" );
5069
5070			if ( div.querySelectorAll("[name=d]").length ) {
5071				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
5072			}
5073
5074			if ( !div.querySelectorAll(":enabled").length ) {
5075				rbuggyQSA.push( ":enabled", ":disabled" );
5076			}
5077
5078			div.querySelectorAll("*,:x");
5079			rbuggyQSA.push(",.*:");
5080		});
5081	}
5082
5083	if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
5084		docElem.mozMatchesSelector ||
5085		docElem.oMatchesSelector ||
5086		docElem.msMatchesSelector) )) ) {
5087
5088		assert(function( div ) {
5089			support.disconnectedMatch = matches.call( div, "div" );
5090
5091			matches.call( div, "[s!='']:x" );
5092			rbuggyMatches.push( "!=", pseudos );
5093		});
5094	}
5095
5096	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
5097	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
5098
5099	/* Contains
5100	---------------------------------------------------------------------- */
5101	hasCompare = rnative.test( docElem.compareDocumentPosition );
5102
5103	contains = hasCompare || rnative.test( docElem.contains ) ?
5104		function( a, b ) {
5105			var adown = a.nodeType === 9 ? a.documentElement : a,
5106				bup = b && b.parentNode;
5107			return a === bup || !!( bup && bup.nodeType === 1 && (
5108				adown.contains ?
5109					adown.contains( bup ) :
5110					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
5111			));
5112		} :
5113		function( a, b ) {
5114			if ( b ) {
5115				while ( (b = b.parentNode) ) {
5116					if ( b === a ) {
5117						return true;
5118					}
5119				}
5120			}
5121			return false;
5122		};
5123
5124	/* Sorting
5125	---------------------------------------------------------------------- */
5126
5127	sortOrder = hasCompare ?
5128	function( a, b ) {
5129
5130		if ( a === b ) {
5131			hasDuplicate = true;
5132			return 0;
5133		}
5134
5135		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
5136		if ( compare ) {
5137			return compare;
5138		}
5139
5140		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
5141			a.compareDocumentPosition( b ) :
5142
5143			1;
5144
5145		if ( compare & 1 ||
5146			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
5147
5148			if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
5149				return -1;
5150			}
5151			if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
5152				return 1;
5153			}
5154
5155			return sortInput ?
5156				( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5157				0;
5158		}
5159
5160		return compare & 4 ? -1 : 1;
5161	} :
5162	function( a, b ) {
5163		if ( a === b ) {
5164			hasDuplicate = true;
5165			return 0;
5166		}
5167
5168		var cur,
5169			i = 0,
5170			aup = a.parentNode,
5171			bup = b.parentNode,
5172			ap = [ a ],
5173			bp = [ b ];
5174
5175		if ( !aup || !bup ) {
5176			return a === doc ? -1 :
5177				b === doc ? 1 :
5178				aup ? -1 :
5179				bup ? 1 :
5180				sortInput ?
5181				( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5182				0;
5183
5184		} else if ( aup === bup ) {
5185			return siblingCheck( a, b );
5186		}
5187
5188		cur = a;
5189		while ( (cur = cur.parentNode) ) {
5190			ap.unshift( cur );
5191		}
5192		cur = b;
5193		while ( (cur = cur.parentNode) ) {
5194			bp.unshift( cur );
5195		}
5196
5197		while ( ap[i] === bp[i] ) {
5198			i++;
5199		}
5200
5201		return i ?
5202			siblingCheck( ap[i], bp[i] ) :
5203
5204			ap[i] === preferredDoc ? -1 :
5205			bp[i] === preferredDoc ? 1 :
5206			0;
5207	};
5208
5209	return doc;
5210};
5211
5212Sizzle.matches = function( expr, elements ) {
5213	return Sizzle( expr, null, null, elements );
5214};
5215
5216Sizzle.matchesSelector = function( elem, expr ) {
5217	if ( ( elem.ownerDocument || elem ) !== document ) {
5218		setDocument( elem );
5219	}
5220
5221	expr = expr.replace( rattributeQuotes, "='$1']" );
5222
5223	if ( support.matchesSelector && documentIsHTML &&
5224		( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
5225		( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
5226
5227		try {
5228			var ret = matches.call( elem, expr );
5229
5230			if ( ret || support.disconnectedMatch ||
5231					elem.document && elem.document.nodeType !== 11 ) {
5232				return ret;
5233			}
5234		} catch(e) {}
5235	}
5236
5237	return Sizzle( expr, document, null, [elem] ).length > 0;
5238};
5239
5240Sizzle.contains = function( context, elem ) {
5241	if ( ( context.ownerDocument || context ) !== document ) {
5242		setDocument( context );
5243	}
5244	return contains( context, elem );
5245};
5246
5247Sizzle.attr = function( elem, name ) {
5248	if ( ( elem.ownerDocument || elem ) !== document ) {
5249		setDocument( elem );
5250	}
5251
5252	var fn = Expr.attrHandle[ name.toLowerCase() ],
5253		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
5254			fn( elem, name, !documentIsHTML ) :
5255			undefined;
5256
5257	return val !== undefined ?
5258		val :
5259		support.attributes || !documentIsHTML ?
5260			elem.getAttribute( name ) :
5261			(val = elem.getAttributeNode(name)) && val.specified ?
5262				val.value :
5263				null;
5264};
5265
5266Sizzle.error = function( msg ) {
5267	throw new Error( "Syntax error, unrecognized expression: " + msg );
5268};
5269
5270/**
5271 * Document sorting and removing duplicates
5272 * @param {ArrayLike} results
5273 */
5274Sizzle.uniqueSort = function( results ) {
5275	var elem,
5276		duplicates = [],
5277		j = 0,
5278		i = 0;
5279
5280	hasDuplicate = !support.detectDuplicates;
5281	sortInput = !support.sortStable && results.slice( 0 );
5282	results.sort( sortOrder );
5283
5284	if ( hasDuplicate ) {
5285		while ( (elem = results[i++]) ) {
5286			if ( elem === results[ i ] ) {
5287				j = duplicates.push( i );
5288			}
5289		}
5290		while ( j-- ) {
5291			results.splice( duplicates[ j ], 1 );
5292		}
5293	}
5294
5295	sortInput = null;
5296
5297	return results;
5298};
5299
5300/**
5301 * Utility function for retrieving the text value of an array of DOM nodes
5302 * @param {Array|Element} elem
5303 */
5304getText = Sizzle.getText = function( elem ) {
5305	var node,
5306		ret = "",
5307		i = 0,
5308		nodeType = elem.nodeType;
5309
5310	if ( !nodeType ) {
5311		while ( (node = elem[i++]) ) {
5312			ret += getText( node );
5313		}
5314	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
5315		if ( typeof elem.textContent === "string" ) {
5316			return elem.textContent;
5317		} else {
5318			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5319				ret += getText( elem );
5320			}
5321		}
5322	} else if ( nodeType === 3 || nodeType === 4 ) {
5323		return elem.nodeValue;
5324	}
5325
5326	return ret;
5327};
5328
5329Expr = Sizzle.selectors = {
5330
5331	cacheLength: 50,
5332
5333	createPseudo: markFunction,
5334
5335	match: matchExpr,
5336
5337	attrHandle: {},
5338
5339	find: {},
5340
5341	relative: {
5342		">": { dir: "parentNode", first: true },
5343		" ": { dir: "parentNode" },
5344		"+": { dir: "previousSibling", first: true },
5345		"~": { dir: "previousSibling" }
5346	},
5347
5348	preFilter: {
5349		"ATTR": function( match ) {
5350			match[1] = match[1].replace( runescape, funescape );
5351
5352			match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
5353
5354			if ( match[2] === "~=" ) {
5355				match[3] = " " + match[3] + " ";
5356			}
5357
5358			return match.slice( 0, 4 );
5359		},
5360
5361		"CHILD": function( match ) {
5362			/* matches from matchExpr["CHILD"]
5363				1 type (only|nth|...)
5364				2 what (child|of-type)
5365				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
5366				4 xn-component of xn+y argument ([+-]?\d*n|)
5367				5 sign of xn-component
5368				6 x of xn-component
5369				7 sign of y-component
5370				8 y of y-component
5371			*/
5372			match[1] = match[1].toLowerCase();
5373
5374			if ( match[1].slice( 0, 3 ) === "nth" ) {
5375				if ( !match[3] ) {
5376					Sizzle.error( match[0] );
5377				}
5378
5379				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
5380				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
5381
5382			} else if ( match[3] ) {
5383				Sizzle.error( match[0] );
5384			}
5385
5386			return match;
5387		},
5388
5389		"PSEUDO": function( match ) {
5390			var excess,
5391				unquoted = !match[5] && match[2];
5392
5393			if ( matchExpr["CHILD"].test( match[0] ) ) {
5394				return null;
5395			}
5396
5397			if ( match[3] && match[4] !== undefined ) {
5398				match[2] = match[4];
5399
5400			} else if ( unquoted && rpseudo.test( unquoted ) &&
5401				(excess = tokenize( unquoted, true )) &&
5402				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
5403
5404				match[0] = match[0].slice( 0, excess );
5405				match[2] = unquoted.slice( 0, excess );
5406			}
5407
5408			return match.slice( 0, 3 );
5409		}
5410	},
5411
5412	filter: {
5413
5414		"TAG": function( nodeNameSelector ) {
5415			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
5416			return nodeNameSelector === "*" ?
5417				function() { return true; } :
5418				function( elem ) {
5419					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
5420				};
5421		},
5422
5423		"CLASS": function( className ) {
5424			var pattern = classCache[ className + " " ];
5425
5426			return pattern ||
5427				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
5428				classCache( className, function( elem ) {
5429					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
5430				});
5431		},
5432
5433		"ATTR": function( name, operator, check ) {
5434			return function( elem ) {
5435				var result = Sizzle.attr( elem, name );
5436
5437				if ( result == null ) {
5438					return operator === "!=";
5439				}
5440				if ( !operator ) {
5441					return true;
5442				}
5443
5444				result += "";
5445
5446				return operator === "=" ? result === check :
5447					operator === "!=" ? result !== check :
5448					operator === "^=" ? check && result.indexOf( check ) === 0 :
5449					operator === "*=" ? check && result.indexOf( check ) > -1 :
5450					operator === "$=" ? check && result.slice( -check.length ) === check :
5451					operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
5452					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
5453					false;
5454			};
5455		},
5456
5457		"CHILD": function( type, what, argument, first, last ) {
5458			var simple = type.slice( 0, 3 ) !== "nth",
5459				forward = type.slice( -4 ) !== "last",
5460				ofType = what === "of-type";
5461
5462			return first === 1 && last === 0 ?
5463
5464				function( elem ) {
5465					return !!elem.parentNode;
5466				} :
5467
5468				function( elem, context, xml ) {
5469					var cache, outerCache, node, diff, nodeIndex, start,
5470						dir = simple !== forward ? "nextSibling" : "previousSibling",
5471						parent = elem.parentNode,
5472						name = ofType && elem.nodeName.toLowerCase(),
5473						useCache = !xml && !ofType;
5474
5475					if ( parent ) {
5476
5477						if ( simple ) {
5478							while ( dir ) {
5479								node = elem;
5480								while ( (node = node[ dir ]) ) {
5481									if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
5482										return false;
5483									}
5484								}
5485								start = dir = type === "only" && !start && "nextSibling";
5486							}
5487							return true;
5488						}
5489
5490						start = [ forward ? parent.firstChild : parent.lastChild ];
5491
5492						if ( forward && useCache ) {
5493							outerCache = parent[ expando ] || (parent[ expando ] = {});
5494							cache = outerCache[ type ] || [];
5495							nodeIndex = cache[0] === dirruns && cache[1];
5496							diff = cache[0] === dirruns && cache[2];
5497							node = nodeIndex && parent.childNodes[ nodeIndex ];
5498
5499							while ( (node = ++nodeIndex && node && node[ dir ] ||
5500
5501								(diff = nodeIndex = 0) || start.pop()) ) {
5502
5503								if ( node.nodeType === 1 && ++diff && node === elem ) {
5504									outerCache[ type ] = [ dirruns, nodeIndex, diff ];
5505									break;
5506								}
5507							}
5508
5509						} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
5510							diff = cache[1];
5511
5512						} else {
5513							while ( (node = ++nodeIndex && node && node[ dir ] ||
5514								(diff = nodeIndex = 0) || start.pop()) ) {
5515
5516								if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
5517									if ( useCache ) {
5518										(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
5519									}
5520
5521									if ( node === elem ) {
5522										break;
5523									}
5524								}
5525							}
5526						}
5527
5528						diff -= last;
5529						return diff === first || ( diff % first === 0 && diff / first >= 0 );
5530					}
5531				};
5532		},
5533
5534		"PSEUDO": function( pseudo, argument ) {
5535			var args,
5536				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
5537					Sizzle.error( "unsupported pseudo: " + pseudo );
5538
5539			if ( fn[ expando ] ) {
5540				return fn( argument );
5541			}
5542
5543			if ( fn.length > 1 ) {
5544				args = [ pseudo, pseudo, "", argument ];
5545				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
5546					markFunction(function( seed, matches ) {
5547						var idx,
5548							matched = fn( seed, argument ),
5549							i = matched.length;
5550						while ( i-- ) {
5551							idx = indexOf.call( seed, matched[i] );
5552							seed[ idx ] = !( matches[ idx ] = matched[i] );
5553						}
5554					}) :
5555					function( elem ) {
5556						return fn( elem, 0, args );
5557					};
5558			}
5559
5560			return fn;
5561		}
5562	},
5563
5564	pseudos: {
5565		"not": markFunction(function( selector ) {
5566			var input = [],
5567				results = [],
5568				matcher = compile( selector.replace( rtrim, "$1" ) );
5569
5570			return matcher[ expando ] ?
5571				markFunction(function( seed, matches, context, xml ) {
5572					var elem,
5573						unmatched = matcher( seed, null, xml, [] ),
5574						i = seed.length;
5575
5576					while ( i-- ) {
5577						if ( (elem = unmatched[i]) ) {
5578							seed[i] = !(matches[i] = elem);
5579						}
5580					}
5581				}) :
5582				function( elem, context, xml ) {
5583					input[0] = elem;
5584					matcher( input, null, xml, results );
5585					return !results.pop();
5586				};
5587		}),
5588
5589		"has": markFunction(function( selector ) {
5590			return function( elem ) {
5591				return Sizzle( selector, elem ).length > 0;
5592			};
5593		}),
5594
5595		"contains": markFunction(function( text ) {
5596			return function( elem ) {
5597				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
5598			};
5599		}),
5600
5601		"lang": markFunction( function( lang ) {
5602			if ( !ridentifier.test(lang || "") ) {
5603				Sizzle.error( "unsupported lang: " + lang );
5604			}
5605			lang = lang.replace( runescape, funescape ).toLowerCase();
5606			return function( elem ) {
5607				var elemLang;
5608				do {
5609					if ( (elemLang = documentIsHTML ?
5610						elem.lang :
5611						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
5612
5613						elemLang = elemLang.toLowerCase();
5614						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
5615					}
5616				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
5617				return false;
5618			};
5619		}),
5620
5621		"target": function( elem ) {
5622			var hash = window.location && window.location.hash;
5623			return hash && hash.slice( 1 ) === elem.id;
5624		},
5625
5626		"root": function( elem ) {
5627			return elem === docElem;
5628		},
5629
5630		"focus": function( elem ) {
5631			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
5632		},
5633
5634		"enabled": function( elem ) {
5635			return elem.disabled === false;
5636		},
5637
5638		"disabled": function( elem ) {
5639			return elem.disabled === true;
5640		},
5641
5642		"checked": function( elem ) {
5643			var nodeName = elem.nodeName.toLowerCase();
5644			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
5645		},
5646
5647		"selected": function( elem ) {
5648			if ( elem.parentNode ) {
5649				elem.parentNode.selectedIndex;
5650			}
5651
5652			return elem.selected === true;
5653		},
5654
5655		"empty": function( elem ) {
5656			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5657				if ( elem.nodeType < 6 ) {
5658					return false;
5659				}
5660			}
5661			return true;
5662		},
5663
5664		"parent": function( elem ) {
5665			return !Expr.pseudos["empty"]( elem );
5666		},
5667
5668		"header": function( elem ) {
5669			return rheader.test( elem.nodeName );
5670		},
5671
5672		"input": function( elem ) {
5673			return rinputs.test( elem.nodeName );
5674		},
5675
5676		"button": function( elem ) {
5677			var name = elem.nodeName.toLowerCase();
5678			return name === "input" && elem.type === "button" || name === "button";
5679		},
5680
5681		"text": function( elem ) {
5682			var attr;
5683			return elem.nodeName.toLowerCase() === "input" &&
5684				elem.type === "text" &&
5685
5686				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
5687		},
5688
5689		"first": createPositionalPseudo(function() {
5690			return [ 0 ];
5691		}),
5692
5693		"last": createPositionalPseudo(function( matchIndexes, length ) {
5694			return [ length - 1 ];
5695		}),
5696
5697		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
5698			return [ argument < 0 ? argument + length : argument ];
5699		}),
5700
5701		"even": createPositionalPseudo(function( matchIndexes, length ) {
5702			var i = 0;
5703			for ( ; i < length; i += 2 ) {
5704				matchIndexes.push( i );
5705			}
5706			return matchIndexes;
5707		}),
5708
5709		"odd": createPositionalPseudo(function( matchIndexes, length ) {
5710			var i = 1;
5711			for ( ; i < length; i += 2 ) {
5712				matchIndexes.push( i );
5713			}
5714			return matchIndexes;
5715		}),
5716
5717		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5718			var i = argument < 0 ? argument + length : argument;
5719			for ( ; --i >= 0; ) {
5720				matchIndexes.push( i );
5721			}
5722			return matchIndexes;
5723		}),
5724
5725		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5726			var i = argument < 0 ? argument + length : argument;
5727			for ( ; ++i < length; ) {
5728				matchIndexes.push( i );
5729			}
5730			return matchIndexes;
5731		})
5732	}
5733};
5734
5735Expr.pseudos["nth"] = Expr.pseudos["eq"];
5736
5737for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
5738	Expr.pseudos[ i ] = createInputPseudo( i );
5739}
5740for ( i in { submit: true, reset: true } ) {
5741	Expr.pseudos[ i ] = createButtonPseudo( i );
5742}
5743
5744function setFilters() {}
5745setFilters.prototype = Expr.filters = Expr.pseudos;
5746Expr.setFilters = new setFilters();
5747
5748function tokenize( selector, parseOnly ) {
5749	var matched, match, tokens, type,
5750		soFar, groups, preFilters,
5751		cached = tokenCache[ selector + " " ];
5752
5753	if ( cached ) {
5754		return parseOnly ? 0 : cached.slice( 0 );
5755	}
5756
5757	soFar = selector;
5758	groups = [];
5759	preFilters = Expr.preFilter;
5760
5761	while ( soFar ) {
5762
5763		if ( !matched || (match = rcomma.exec( soFar )) ) {
5764			if ( match ) {
5765				soFar = soFar.slice( match[0].length ) || soFar;
5766			}
5767			groups.push( (tokens = []) );
5768		}
5769
5770		matched = false;
5771
5772		if ( (match = rcombinators.exec( soFar )) ) {
5773			matched = match.shift();
5774			tokens.push({
5775				value: matched,
5776				type: match[0].replace( rtrim, " " )
5777			});
5778			soFar = soFar.slice( matched.length );
5779		}
5780
5781		for ( type in Expr.filter ) {
5782			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
5783				(match = preFilters[ type ]( match ))) ) {
5784				matched = match.shift();
5785				tokens.push({
5786					value: matched,
5787					type: type,
5788					matches: match
5789				});
5790				soFar = soFar.slice( matched.length );
5791			}
5792		}
5793
5794		if ( !matched ) {
5795			break;
5796		}
5797	}
5798
5799	return parseOnly ?
5800		soFar.length :
5801		soFar ?
5802			Sizzle.error( selector ) :
5803			tokenCache( selector, groups ).slice( 0 );
5804}
5805
5806function toSelector( tokens ) {
5807	var i = 0,
5808		len = tokens.length,
5809		selector = "";
5810	for ( ; i < len; i++ ) {
5811		selector += tokens[i].value;
5812	}
5813	return selector;
5814}
5815
5816function addCombinator( matcher, combinator, base ) {
5817	var dir = combinator.dir,
5818		checkNonElements = base && dir === "parentNode",
5819		doneName = done++;
5820
5821	return combinator.first ?
5822		function( elem, context, xml ) {
5823			while ( (elem = elem[ dir ]) ) {
5824				if ( elem.nodeType === 1 || checkNonElements ) {
5825					return matcher( elem, context, xml );
5826				}
5827			}
5828		} :
5829
5830		function( elem, context, xml ) {
5831			var oldCache, outerCache,
5832				newCache = [ dirruns, doneName ];
5833
5834			if ( xml ) {
5835				while ( (elem = elem[ dir ]) ) {
5836					if ( elem.nodeType === 1 || checkNonElements ) {
5837						if ( matcher( elem, context, xml ) ) {
5838							return true;
5839						}
5840					}
5841				}
5842			} else {
5843				while ( (elem = elem[ dir ]) ) {
5844					if ( elem.nodeType === 1 || checkNonElements ) {
5845						outerCache = elem[ expando ] || (elem[ expando ] = {});
5846						if ( (oldCache = outerCache[ dir ]) &&
5847							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
5848
5849							return (newCache[ 2 ] = oldCache[ 2 ]);
5850						} else {
5851							outerCache[ dir ] = newCache;
5852
5853							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
5854								return true;
5855							}
5856						}
5857					}
5858				}
5859			}
5860		};
5861}
5862
5863function elementMatcher( matchers ) {
5864	return matchers.length > 1 ?
5865		function( elem, context, xml ) {
5866			var i = matchers.length;
5867			while ( i-- ) {
5868				if ( !matchers[i]( elem, context, xml ) ) {
5869					return false;
5870				}
5871			}
5872			return true;
5873		} :
5874		matchers[0];
5875}
5876
5877function multipleContexts( selector, contexts, results ) {
5878	var i = 0,
5879		len = contexts.length;
5880	for ( ; i < len; i++ ) {
5881		Sizzle( selector, contexts[i], results );
5882	}
5883	return results;
5884}
5885
5886function condense( unmatched, map, filter, context, xml ) {
5887	var elem,
5888		newUnmatched = [],
5889		i = 0,
5890		len = unmatched.length,
5891		mapped = map != null;
5892
5893	for ( ; i < len; i++ ) {
5894		if ( (elem = unmatched[i]) ) {
5895			if ( !filter || filter( elem, context, xml ) ) {
5896				newUnmatched.push( elem );
5897				if ( mapped ) {
5898					map.push( i );
5899				}
5900			}
5901		}
5902	}
5903
5904	return newUnmatched;
5905}
5906
5907function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
5908	if ( postFilter && !postFilter[ expando ] ) {
5909		postFilter = setMatcher( postFilter );
5910	}
5911	if ( postFinder && !postFinder[ expando ] ) {
5912		postFinder = setMatcher( postFinder, postSelector );
5913	}
5914	return markFunction(function( seed, results, context, xml ) {
5915		var temp, i, elem,
5916			preMap = [],
5917			postMap = [],
5918			preexisting = results.length,
5919
5920			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
5921
5922			matcherIn = preFilter && ( seed || !selector ) ?
5923				condense( elems, preMap, preFilter, context, xml ) :
5924				elems,
5925
5926			matcherOut = matcher ?
5927				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
5928
5929					[] :
5930
5931					results :
5932				matcherIn;
5933
5934		if ( matcher ) {
5935			matcher( matcherIn, matcherOut, context, xml );
5936		}
5937
5938		if ( postFilter ) {
5939			temp = condense( matcherOut, postMap );
5940			postFilter( temp, [], context, xml );
5941
5942			i = temp.length;
5943			while ( i-- ) {
5944				if ( (elem = temp[i]) ) {
5945					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
5946				}
5947			}
5948		}
5949
5950		if ( seed ) {
5951			if ( postFinder || preFilter ) {
5952				if ( postFinder ) {
5953					temp = [];
5954					i = matcherOut.length;
5955					while ( i-- ) {
5956						if ( (elem = matcherOut[i]) ) {
5957							temp.push( (matcherIn[i] = elem) );
5958						}
5959					}
5960					postFinder( null, (matcherOut = []), temp, xml );
5961				}
5962
5963				i = matcherOut.length;
5964				while ( i-- ) {
5965					if ( (elem = matcherOut[i]) &&
5966						(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
5967
5968						seed[temp] = !(results[temp] = elem);
5969					}
5970				}
5971			}
5972
5973		} else {
5974			matcherOut = condense(
5975				matcherOut === results ?
5976					matcherOut.splice( preexisting, matcherOut.length ) :
5977					matcherOut
5978			);
5979			if ( postFinder ) {
5980				postFinder( null, results, matcherOut, xml );
5981			} else {
5982				push.apply( results, matcherOut );
5983			}
5984		}
5985	});
5986}
5987
5988function matcherFromTokens( tokens ) {
5989	var checkContext, matcher, j,
5990		len = tokens.length,
5991		leadingRelative = Expr.relative[ tokens[0].type ],
5992		implicitRelative = leadingRelative || Expr.relative[" "],
5993		i = leadingRelative ? 1 : 0,
5994
5995		matchContext = addCombinator( function( elem ) {
5996			return elem === checkContext;
5997		}, implicitRelative, true ),
5998		matchAnyContext = addCombinator( function( elem ) {
5999			return indexOf.call( checkContext, elem ) > -1;
6000		}, implicitRelative, true ),
6001		matchers = [ function( elem, context, xml ) {
6002			return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
6003				(checkContext = context).nodeType ?
6004					matchContext( elem, context, xml ) :
6005					matchAnyContext( elem, context, xml ) );
6006		} ];
6007
6008	for ( ; i < len; i++ ) {
6009		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
6010			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
6011		} else {
6012			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
6013
6014			if ( matcher[ expando ] ) {
6015				j = ++i;
6016				for ( ; j < len; j++ ) {
6017					if ( Expr.relative[ tokens[j].type ] ) {
6018						break;
6019					}
6020				}
6021				return setMatcher(
6022					i > 1 && elementMatcher( matchers ),
6023					i > 1 && toSelector(
6024						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
6025					).replace( rtrim, "$1" ),
6026					matcher,
6027					i < j && matcherFromTokens( tokens.slice( i, j ) ),
6028					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
6029					j < len && toSelector( tokens )
6030				);
6031			}
6032			matchers.push( matcher );
6033		}
6034	}
6035
6036	return elementMatcher( matchers );
6037}
6038
6039function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
6040	var bySet = setMatchers.length > 0,
6041		byElement = elementMatchers.length > 0,
6042		superMatcher = function( seed, context, xml, results, outermost ) {
6043			var elem, j, matcher,
6044				matchedCount = 0,
6045				i = "0",
6046				unmatched = seed && [],
6047				setMatched = [],
6048				contextBackup = outermostContext,
6049				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
6050				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
6051				len = elems.length;
6052
6053			if ( outermost ) {
6054				outermostContext = context !== document && context;
6055			}
6056
6057			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
6058				if ( byElement && elem ) {
6059					j = 0;
6060					while ( (matcher = elementMatchers[j++]) ) {
6061						if ( matcher( elem, context, xml ) ) {
6062							results.push( elem );
6063							break;
6064						}
6065					}
6066					if ( outermost ) {
6067						dirruns = dirrunsUnique;
6068					}
6069				}
6070
6071				if ( bySet ) {
6072					if ( (elem = !matcher && elem) ) {
6073						matchedCount--;
6074					}
6075
6076					if ( seed ) {
6077						unmatched.push( elem );
6078					}
6079				}
6080			}
6081
6082			matchedCount += i;
6083			if ( bySet && i !== matchedCount ) {
6084				j = 0;
6085				while ( (matcher = setMatchers[j++]) ) {
6086					matcher( unmatched, setMatched, context, xml );
6087				}
6088
6089				if ( seed ) {
6090					if ( matchedCount > 0 ) {
6091						while ( i-- ) {
6092							if ( !(unmatched[i] || setMatched[i]) ) {
6093								setMatched[i] = pop.call( results );
6094							}
6095						}
6096					}
6097
6098					setMatched = condense( setMatched );
6099				}
6100
6101				push.apply( results, setMatched );
6102
6103				if ( outermost && !seed && setMatched.length > 0 &&
6104					( matchedCount + setMatchers.length ) > 1 ) {
6105
6106					Sizzle.uniqueSort( results );
6107				}
6108			}
6109
6110			if ( outermost ) {
6111				dirruns = dirrunsUnique;
6112				outermostContext = contextBackup;
6113			}
6114
6115			return unmatched;
6116		};
6117
6118	return bySet ?
6119		markFunction( superMatcher ) :
6120		superMatcher;
6121}
6122
6123compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
6124	var i,
6125		setMatchers = [],
6126		elementMatchers = [],
6127		cached = compilerCache[ selector + " " ];
6128
6129	if ( !cached ) {
6130		if ( !match ) {
6131			match = tokenize( selector );
6132		}
6133		i = match.length;
6134		while ( i-- ) {
6135			cached = matcherFromTokens( match[i] );
6136			if ( cached[ expando ] ) {
6137				setMatchers.push( cached );
6138			} else {
6139				elementMatchers.push( cached );
6140			}
6141		}
6142
6143		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
6144
6145		cached.selector = selector;
6146	}
6147	return cached;
6148};
6149
6150/**
6151 * A low-level selection function that works with Sizzle's compiled
6152 *  selector functions
6153 * @param {String|Function} selector A selector or a pre-compiled
6154 *  selector function built with Sizzle.compile
6155 * @param {Element} context
6156 * @param {Array} [results]
6157 * @param {Array} [seed] A set of elements to match against
6158 */
6159select = Sizzle.select = function( selector, context, results, seed ) {
6160	var i, tokens, token, type, find,
6161		compiled = typeof selector === "function" && selector,
6162		match = !seed && tokenize( (selector = compiled.selector || selector) );
6163
6164	results = results || [];
6165
6166	if ( match.length === 1 ) {
6167
6168		tokens = match[0] = match[0].slice( 0 );
6169		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
6170				support.getById && context.nodeType === 9 && documentIsHTML &&
6171				Expr.relative[ tokens[1].type ] ) {
6172
6173			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
6174			if ( !context ) {
6175				return results;
6176
6177			} else if ( compiled ) {
6178				context = context.parentNode;
6179			}
6180
6181			selector = selector.slice( tokens.shift().value.length );
6182		}
6183
6184		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
6185		while ( i-- ) {
6186			token = tokens[i];
6187
6188			if ( Expr.relative[ (type = token.type) ] ) {
6189				break;
6190			}
6191			if ( (find = Expr.find[ type ]) ) {
6192				if ( (seed = find(
6193					token.matches[0].replace( runescape, funescape ),
6194					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
6195				)) ) {
6196
6197					tokens.splice( i, 1 );
6198					selector = seed.length && toSelector( tokens );
6199					if ( !selector ) {
6200						push.apply( results, seed );
6201						return results;
6202					}
6203
6204					break;
6205				}
6206			}
6207		}
6208	}
6209
6210	( compiled || compile( selector, match ) )(
6211		seed,
6212		context,
6213		!documentIsHTML,
6214		results,
6215		rsibling.test( selector ) && testContext( context.parentNode ) || context
6216	);
6217	return results;
6218};
6219
6220
6221support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
6222
6223support.detectDuplicates = !!hasDuplicate;
6224
6225setDocument();
6226
6227support.sortDetached = assert(function( div1 ) {
6228	return div1.compareDocumentPosition( document.createElement("div") ) & 1;
6229});
6230
6231if ( !assert(function( div ) {
6232	div.innerHTML = "<a href='#'></a>";
6233	return div.firstChild.getAttribute("href") === "#" ;
6234}) ) {
6235	addHandle( "type|href|height|width", function( elem, name, isXML ) {
6236		if ( !isXML ) {
6237			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
6238		}
6239	});
6240}
6241
6242if ( !support.attributes || !assert(function( div ) {
6243	div.innerHTML = "<input/>";
6244	div.firstChild.setAttribute( "value", "" );
6245	return div.firstChild.getAttribute( "value" ) === "";
6246}) ) {
6247	addHandle( "value", function( elem, name, isXML ) {
6248		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
6249			return elem.defaultValue;
6250		}
6251	});
6252}
6253
6254if ( !assert(function( div ) {
6255	return div.getAttribute("disabled") == null;
6256}) ) {
6257	addHandle( booleans, function( elem, name, isXML ) {
6258		var val;
6259		if ( !isXML ) {
6260			return elem[ name ] === true ? name.toLowerCase() :
6261					(val = elem.getAttributeNode( name )) && val.specified ?
6262					val.value :
6263				null;
6264		}
6265	});
6266}
6267
6268if ( typeof define === "function" && define.amd ) {
6269	define(function() { return Sizzle; });
6270} else if ( typeof module !== "undefined" && module.exports ) {
6271	module.exports = Sizzle;
6272} else {
6273	window.Sizzle = Sizzle;
6274}
6275
6276})( window );
6277
6278;(function() {
6279  if (typeof Sizzle !== 'undefined') {
6280    return;
6281  }
6282
6283  if (typeof define !== 'undefined' && define.amd) {
6284    window.Sizzle = Prototype._actual_sizzle;
6285    window.define = Prototype._original_define;
6286    delete Prototype._actual_sizzle;
6287    delete Prototype._original_define;
6288  } else if (typeof module !== 'undefined' && module.exports) {
6289    window.Sizzle = module.exports;
6290    module.exports = {};
6291  }
6292})();
6293
6294;(function(engine) {
6295  var extendElements = Prototype.Selector.extendElements;
6296
6297  function select(selector, scope) {
6298    return extendElements(engine(selector, scope || document));
6299  }
6300
6301  function match(element, selector) {
6302    return engine.matches(selector, [element]).length == 1;
6303  }
6304
6305  Prototype.Selector.engine = engine;
6306  Prototype.Selector.select = select;
6307  Prototype.Selector.match = match;
6308})(Sizzle);
6309
6310window.Sizzle = Prototype._original_property;
6311delete Prototype._original_property;
6312
6313var Form = {
6314  reset: function(form) {
6315    form = $(form);
6316    form.reset();
6317    return form;
6318  },
6319
6320  serializeElements: function(elements, options) {
6321    if (typeof options != 'object') options = { hash: !!options };
6322    else if (Object.isUndefined(options.hash)) options.hash = true;
6323    var key, value, submitted = false, submit = options.submit, accumulator, initial;
6324
6325    if (options.hash) {
6326      initial = {};
6327      accumulator = function(result, key, value) {
6328        if (key in result) {
6329          if (!Object.isArray(result[key])) result[key] = [result[key]];
6330          result[key] = result[key].concat(value);
6331        } else result[key] = value;
6332        return result;
6333      };
6334    } else {
6335      initial = '';
6336      accumulator = function(result, key, values) {
6337        if (!Object.isArray(values)) {values = [values];}
6338        if (!values.length) {return result;}
6339        var encodedKey = encodeURIComponent(key).gsub(/%20/, '+');
6340        return result + (result ? "&" : "") + values.map(function (value) {
6341          value = value.gsub(/(\r)?\n/, '\r\n');
6342          value = encodeURIComponent(value);
6343          value = value.gsub(/%20/, '+');
6344          return encodedKey + "=" + value;
6345        }).join("&");
6346      };
6347    }
6348
6349    return elements.inject(initial, function(result, element) {
6350      if (!element.disabled && element.name) {
6351        key = element.name; value = $(element).getValue();
6352        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
6353            submit !== false && (!submit || key == submit) && (submitted = true)))) {
6354          result = accumulator(result, key, value);
6355        }
6356      }
6357      return result;
6358    });
6359  }
6360};
6361
6362Form.Methods = {
6363  serialize: function(form, options) {
6364    return Form.serializeElements(Form.getElements(form), options);
6365  },
6366
6367
6368  getElements: function(form) {
6369    var elements = $(form).getElementsByTagName('*');
6370    var element, results = [], serializers = Form.Element.Serializers;
6371
6372    for (var i = 0; element = elements[i]; i++) {
6373      if (serializers[element.tagName.toLowerCase()])
6374        results.push(Element.extend(element));
6375    }
6376    return results;
6377  },
6378
6379  getInputs: function(form, typeName, name) {
6380    form = $(form);
6381    var inputs = form.getElementsByTagName('input');
6382
6383    if (!typeName && !name) return $A(inputs).map(Element.extend);
6384
6385    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
6386      var input = inputs[i];
6387      if ((typeName && input.type != typeName) || (name && input.name != name))
6388        continue;
6389      matchingInputs.push(Element.extend(input));
6390    }
6391
6392    return matchingInputs;
6393  },
6394
6395  disable: function(form) {
6396    form = $(form);
6397    Form.getElements(form).invoke('disable');
6398    return form;
6399  },
6400
6401  enable: function(form) {
6402    form = $(form);
6403    Form.getElements(form).invoke('enable');
6404    return form;
6405  },
6406
6407  findFirstElement: function(form) {
6408    var elements = $(form).getElements().findAll(function(element) {
6409      return 'hidden' != element.type && !element.disabled;
6410    });
6411    var firstByIndex = elements.findAll(function(element) {
6412      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
6413    }).sortBy(function(element) { return element.tabIndex }).first();
6414
6415    return firstByIndex ? firstByIndex : elements.find(function(element) {
6416      return /^(?:input|select|textarea)$/i.test(element.tagName);
6417    });
6418  },
6419
6420  focusFirstElement: function(form) {
6421    form = $(form);
6422    var element = form.findFirstElement();
6423    if (element) element.activate();
6424    return form;
6425  },
6426
6427  request: function(form, options) {
6428    form = $(form), options = Object.clone(options || { });
6429
6430    var params = options.parameters, action = form.readAttribute('action') || '';
6431    if (action.blank()) action = window.location.href;
6432    options.parameters = form.serialize(true);
6433
6434    if (params) {
6435      if (Object.isString(params)) params = params.toQueryParams();
6436      Object.extend(options.parameters, params);
6437    }
6438
6439    if (form.hasAttribute('method') && !options.method)
6440      options.method = form.method;
6441
6442    return new Ajax.Request(action, options);
6443  }
6444};
6445
6446/*--------------------------------------------------------------------------*/
6447
6448
6449Form.Element = {
6450  focus: function(element) {
6451    $(element).focus();
6452    return element;
6453  },
6454
6455  select: function(element) {
6456    $(element).select();
6457    return element;
6458  }
6459};
6460
6461Form.Element.Methods = {
6462
6463  serialize: function(element) {
6464    element = $(element);
6465    if (!element.disabled && element.name) {
6466      var value = element.getValue();
6467      if (value != undefined) {
6468        var pair = { };
6469        pair[element.name] = value;
6470        return Object.toQueryString(pair);
6471      }
6472    }
6473    return '';
6474  },
6475
6476  getValue: function(element) {
6477    element = $(element);
6478    var method = element.tagName.toLowerCase();
6479    return Form.Element.Serializers[method](element);
6480  },
6481
6482  setValue: function(element, value) {
6483    element = $(element);
6484    var method = element.tagName.toLowerCase();
6485    Form.Element.Serializers[method](element, value);
6486    return element;
6487  },
6488
6489  clear: function(element) {
6490    $(element).value = '';
6491    return element;
6492  },
6493
6494  present: function(element) {
6495    return $(element).value != '';
6496  },
6497
6498  activate: function(element) {
6499    element = $(element);
6500    try {
6501      element.focus();
6502      if (element.select && (element.tagName.toLowerCase() != 'input' ||
6503          !(/^(?:button|reset|submit)$/i.test(element.type))))
6504        element.select();
6505    } catch (e) { }
6506    return element;
6507  },
6508
6509  disable: function(element) {
6510    element = $(element);
6511    element.disabled = true;
6512    return element;
6513  },
6514
6515  enable: function(element) {
6516    element = $(element);
6517    element.disabled = false;
6518    return element;
6519  }
6520};
6521
6522/*--------------------------------------------------------------------------*/
6523
6524var Field = Form.Element;
6525
6526var $F = Form.Element.Methods.getValue;
6527
6528/*--------------------------------------------------------------------------*/
6529
6530Form.Element.Serializers = (function() {
6531  function input(element, value) {
6532    switch (element.type.toLowerCase()) {
6533      case 'checkbox':
6534      case 'radio':
6535        return inputSelector(element, value);
6536      default:
6537        return valueSelector(element, value);
6538    }
6539  }
6540
6541  function inputSelector(element, value) {
6542    if (Object.isUndefined(value))
6543      return element.checked ? element.value : null;
6544    else element.checked = !!value;
6545  }
6546
6547  function valueSelector(element, value) {
6548    if (Object.isUndefined(value)) return element.value;
6549    else element.value = value;
6550  }
6551
6552  function select(element, value) {
6553    if (Object.isUndefined(value))
6554      return (element.type === 'select-one' ? selectOne : selectMany)(element);
6555
6556    var opt, currentValue, single = !Object.isArray(value);
6557    for (var i = 0, length = element.length; i < length; i++) {
6558      opt = element.options[i];
6559      currentValue = this.optionValue(opt);
6560      if (single) {
6561        if (currentValue == value) {
6562          opt.selected = true;
6563          return;
6564        }
6565      }
6566      else opt.selected = value.include(currentValue);
6567    }
6568  }
6569
6570  function selectOne(element) {
6571    var index = element.selectedIndex;
6572    return index >= 0 ? optionValue(element.options[index]) : null;
6573  }
6574
6575  function selectMany(element) {
6576    var values, length = element.length;
6577    if (!length) return null;
6578
6579    for (var i = 0, values = []; i < length; i++) {
6580      var opt = element.options[i];
6581      if (opt.selected) values.push(optionValue(opt));
6582    }
6583    return values;
6584  }
6585
6586  function optionValue(opt) {
6587    return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
6588  }
6589
6590  return {
6591    input:         input,
6592    inputSelector: inputSelector,
6593    textarea:      valueSelector,
6594    select:        select,
6595    selectOne:     selectOne,
6596    selectMany:    selectMany,
6597    optionValue:   optionValue,
6598    button:        valueSelector
6599  };
6600})();
6601
6602/*--------------------------------------------------------------------------*/
6603
6604
6605Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
6606  initialize: function($super, element, frequency, callback) {
6607    $super(callback, frequency);
6608    this.element   = $(element);
6609    this.lastValue = this.getValue();
6610  },
6611
6612  execute: function() {
6613    var value = this.getValue();
6614    if (Object.isString(this.lastValue) && Object.isString(value) ?
6615        this.lastValue != value : String(this.lastValue) != String(value)) {
6616      this.callback(this.element, value);
6617      this.lastValue = value;
6618    }
6619  }
6620});
6621
6622Form.Element.Observer = Class.create(Abstract.TimedObserver, {
6623  getValue: function() {
6624    return Form.Element.getValue(this.element);
6625  }
6626});
6627
6628Form.Observer = Class.create(Abstract.TimedObserver, {
6629  getValue: function() {
6630    return Form.serialize(this.element);
6631  }
6632});
6633
6634/*--------------------------------------------------------------------------*/
6635
6636Abstract.EventObserver = Class.create({
6637  initialize: function(element, callback) {
6638    this.element  = $(element);
6639    this.callback = callback;
6640
6641    this.lastValue = this.getValue();
6642    if (this.element.tagName.toLowerCase() == 'form')
6643      this.registerFormCallbacks();
6644    else
6645      this.registerCallback(this.element);
6646  },
6647
6648  onElementEvent: function() {
6649    var value = this.getValue();
6650    if (this.lastValue != value) {
6651      this.callback(this.element, value);
6652      this.lastValue = value;
6653    }
6654  },
6655
6656  registerFormCallbacks: function() {
6657    Form.getElements(this.element).each(this.registerCallback, this);
6658  },
6659
6660  registerCallback: function(element) {
6661    if (element.type) {
6662      switch (element.type.toLowerCase()) {
6663        case 'checkbox':
6664        case 'radio':
6665          Event.observe(element, 'click', this.onElementEvent.bind(this));
6666          break;
6667        default:
6668          Event.observe(element, 'change', this.onElementEvent.bind(this));
6669          break;
6670      }
6671    }
6672  }
6673});
6674
6675Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
6676  getValue: function() {
6677    return Form.Element.getValue(this.element);
6678  }
6679});
6680
6681Form.EventObserver = Class.create(Abstract.EventObserver, {
6682  getValue: function() {
6683    return Form.serialize(this.element);
6684  }
6685});
6686(function(GLOBAL) {
6687  var DIV = document.createElement('div');
6688  var docEl = document.documentElement;
6689  var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
6690   && 'onmouseleave' in docEl;
6691
6692  var Event = {
6693    KEY_BACKSPACE: 8,
6694    KEY_TAB:       9,
6695    KEY_RETURN:   13,
6696    KEY_ESC:      27,
6697    KEY_LEFT:     37,
6698    KEY_UP:       38,
6699    KEY_RIGHT:    39,
6700    KEY_DOWN:     40,
6701    KEY_DELETE:   46,
6702    KEY_HOME:     36,
6703    KEY_END:      35,
6704    KEY_PAGEUP:   33,
6705    KEY_PAGEDOWN: 34,
6706    KEY_INSERT:   45
6707  };
6708
6709
6710  var isIELegacyEvent = function(event) { return false; };
6711
6712  if (window.attachEvent) {
6713    if (window.addEventListener) {
6714      isIELegacyEvent = function(event) {
6715        return !(event instanceof window.Event);
6716      };
6717    } else {
6718      isIELegacyEvent = function(event) { return true; };
6719    }
6720  }
6721
6722  var _isButton;
6723
6724  function _isButtonForDOMEvents(event, code) {
6725    return event.which ? (event.which === code + 1) : (event.button === code);
6726  }
6727
6728  var legacyButtonMap = { 0: 1, 1: 4, 2: 2 };
6729  function _isButtonForLegacyEvents(event, code) {
6730    return event.button === legacyButtonMap[code];
6731  }
6732
6733  function _isButtonForWebKit(event, code) {
6734    switch (code) {
6735      case 0: return event.which == 1 && !event.metaKey;
6736      case 1: return event.which == 2 || (event.which == 1 && event.metaKey);
6737      case 2: return event.which == 3;
6738      default: return false;
6739    }
6740  }
6741
6742  if (window.attachEvent) {
6743    if (!window.addEventListener) {
6744      _isButton = _isButtonForLegacyEvents;
6745    } else {
6746      _isButton = function(event, code) {
6747        return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
6748         _isButtonForDOMEvents(event, code);
6749      }
6750    }
6751  } else if (Prototype.Browser.WebKit) {
6752    _isButton = _isButtonForWebKit;
6753  } else {
6754    _isButton = _isButtonForDOMEvents;
6755  }
6756
6757  function isLeftClick(event)   { return _isButton(event, 0) }
6758
6759  function isMiddleClick(event) { return _isButton(event, 1) }
6760
6761  function isRightClick(event)  { return _isButton(event, 2) }
6762
6763  function element(event) {
6764    return Element.extend(_element(event));
6765  }
6766
6767  function _element(event) {
6768    event = Event.extend(event);
6769
6770    var node = event.target, type = event.type,
6771     currentTarget = event.currentTarget;
6772
6773    if (currentTarget && currentTarget.tagName) {
6774      if (type === 'load' || type === 'error' ||
6775        (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
6776          && currentTarget.type === 'radio'))
6777            node = currentTarget;
6778    }
6779
6780    return node.nodeType == Node.TEXT_NODE ? node.parentNode : node;
6781  }
6782
6783  function findElement(event, expression) {
6784    var element = _element(event), selector = Prototype.Selector;
6785    if (!expression) return Element.extend(element);
6786    while (element) {
6787      if (Object.isElement(element) && selector.match(element, expression))
6788        return Element.extend(element);
6789      element = element.parentNode;
6790    }
6791  }
6792
6793  function pointer(event) {
6794    return { x: pointerX(event), y: pointerY(event) };
6795  }
6796
6797  function pointerX(event) {
6798    var docElement = document.documentElement,
6799     body = document.body || { scrollLeft: 0 };
6800
6801    return event.pageX || (event.clientX +
6802      (docElement.scrollLeft || body.scrollLeft) -
6803      (docElement.clientLeft || 0));
6804  }
6805
6806  function pointerY(event) {
6807    var docElement = document.documentElement,
6808     body = document.body || { scrollTop: 0 };
6809
6810    return  event.pageY || (event.clientY +
6811       (docElement.scrollTop || body.scrollTop) -
6812       (docElement.clientTop || 0));
6813  }
6814
6815
6816  function stop(event) {
6817    Event.extend(event);
6818    event.preventDefault();
6819    event.stopPropagation();
6820
6821    event.stopped = true;
6822  }
6823
6824
6825  Event.Methods = {
6826    isLeftClick:   isLeftClick,
6827    isMiddleClick: isMiddleClick,
6828    isRightClick:  isRightClick,
6829
6830    element:     element,
6831    findElement: findElement,
6832
6833    pointer:  pointer,
6834    pointerX: pointerX,
6835    pointerY: pointerY,
6836
6837    stop: stop
6838  };
6839
6840  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
6841    m[name] = Event.Methods[name].methodize();
6842    return m;
6843  });
6844
6845  if (window.attachEvent) {
6846    function _relatedTarget(event) {
6847      var element;
6848      switch (event.type) {
6849        case 'mouseover':
6850        case 'mouseenter':
6851          element = event.fromElement;
6852          break;
6853        case 'mouseout':
6854        case 'mouseleave':
6855          element = event.toElement;
6856          break;
6857        default:
6858          return null;
6859      }
6860      return Element.extend(element);
6861    }
6862
6863    var additionalMethods = {
6864      stopPropagation: function() { this.cancelBubble = true },
6865      preventDefault:  function() { this.returnValue = false },
6866      inspect: function() { return '[object Event]' }
6867    };
6868
6869    Event.extend = function(event, element) {
6870      if (!event) return false;
6871
6872      if (!isIELegacyEvent(event)) return event;
6873
6874      if (event._extendedByPrototype) return event;
6875      event._extendedByPrototype = Prototype.emptyFunction;
6876
6877      var pointer = Event.pointer(event);
6878
6879      Object.extend(event, {
6880        target: event.srcElement || element,
6881        relatedTarget: _relatedTarget(event),
6882        pageX:  pointer.x,
6883        pageY:  pointer.y
6884      });
6885
6886      Object.extend(event, methods);
6887      Object.extend(event, additionalMethods);
6888
6889      return event;
6890    };
6891  } else {
6892    Event.extend = Prototype.K;
6893  }
6894
6895  if (window.addEventListener) {
6896    Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
6897    Object.extend(Event.prototype, methods);
6898  }
6899
6900  var EVENT_TRANSLATIONS = {
6901    mouseenter: 'mouseover',
6902    mouseleave: 'mouseout'
6903  };
6904
6905  function getDOMEventName(eventName) {
6906    return EVENT_TRANSLATIONS[eventName] || eventName;
6907  }
6908
6909  if (MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED)
6910    getDOMEventName = Prototype.K;
6911
6912  function getUniqueElementID(element) {
6913    if (element === window) return 0;
6914
6915    if (typeof element._prototypeUID === 'undefined')
6916      element._prototypeUID = Element.Storage.UID++;
6917    return element._prototypeUID;
6918  }
6919
6920  function getUniqueElementID_IE(element) {
6921    if (element === window) return 0;
6922    if (element == document) return 1;
6923    return element.uniqueID;
6924  }
6925
6926  if ('uniqueID' in DIV)
6927    getUniqueElementID = getUniqueElementID_IE;
6928
6929  function isCustomEvent(eventName) {
6930    return eventName.include(':');
6931  }
6932
6933  Event._isCustomEvent = isCustomEvent;
6934
6935  function getOrCreateRegistryFor(element, uid) {
6936    var CACHE = GLOBAL.Event.cache;
6937    if (Object.isUndefined(uid))
6938      uid = getUniqueElementID(element);
6939    if (!CACHE[uid]) CACHE[uid] = { element: element };
6940    return CACHE[uid];
6941  }
6942
6943  function destroyRegistryForElement(element, uid) {
6944    if (Object.isUndefined(uid))
6945      uid = getUniqueElementID(element);
6946    delete GLOBAL.Event.cache[uid];
6947  }
6948
6949
6950  function register(element, eventName, handler) {
6951    var registry = getOrCreateRegistryFor(element);
6952    if (!registry[eventName]) registry[eventName] = [];
6953    var entries = registry[eventName];
6954
6955    var i = entries.length;
6956    while (i--)
6957      if (entries[i].handler === handler) return null;
6958
6959    var uid = getUniqueElementID(element);
6960    var responder = GLOBAL.Event._createResponder(uid, eventName, handler);
6961    var entry = {
6962      responder: responder,
6963      handler:   handler
6964    };
6965
6966    entries.push(entry);
6967    return entry;
6968  }
6969
6970  function unregister(element, eventName, handler) {
6971    var registry = getOrCreateRegistryFor(element);
6972    var entries = registry[eventName] || [];
6973
6974    var i = entries.length, entry;
6975    while (i--) {
6976      if (entries[i].handler === handler) {
6977        entry = entries[i];
6978        break;
6979      }
6980    }
6981
6982    if (entry) {
6983      var index = entries.indexOf(entry);
6984      entries.splice(index, 1);
6985    }
6986
6987    if (entries.length === 0) {
6988      delete registry[eventName];
6989      if (Object.keys(registry).length === 1 && ('element' in registry))
6990        destroyRegistryForElement(element);
6991    }
6992
6993    return entry;
6994  }
6995
6996
6997  function observe(element, eventName, handler) {
6998    element = $(element);
6999    var entry = register(element, eventName, handler);
7000
7001    if (entry === null) return element;
7002
7003    var responder = entry.responder;
7004    if (isCustomEvent(eventName))
7005      observeCustomEvent(element, eventName, responder);
7006    else
7007      observeStandardEvent(element, eventName, responder);
7008
7009    return element;
7010  }
7011
7012  function observeStandardEvent(element, eventName, responder) {
7013    var actualEventName = getDOMEventName(eventName);
7014    if (element.addEventListener) {
7015      element.addEventListener(actualEventName, responder, false);
7016    } else {
7017      element.attachEvent('on' + actualEventName, responder);
7018    }
7019  }
7020
7021  function observeCustomEvent(element, eventName, responder) {
7022    if (element.addEventListener) {
7023      element.addEventListener('dataavailable', responder, false);
7024    } else {
7025      element.attachEvent('ondataavailable', responder);
7026      element.attachEvent('onlosecapture',   responder);
7027    }
7028  }
7029
7030  function stopObserving(element, eventName, handler) {
7031    element = $(element);
7032    var handlerGiven = !Object.isUndefined(handler),
7033     eventNameGiven = !Object.isUndefined(eventName);
7034
7035    if (!eventNameGiven && !handlerGiven) {
7036      stopObservingElement(element);
7037      return element;
7038    }
7039
7040    if (!handlerGiven) {
7041      stopObservingEventName(element, eventName);
7042      return element;
7043    }
7044
7045    var entry = unregister(element, eventName, handler);
7046
7047    if (!entry) return element;
7048    removeEvent(element, eventName, entry.responder);
7049    return element;
7050  }
7051
7052  function stopObservingStandardEvent(element, eventName, responder) {
7053    var actualEventName = getDOMEventName(eventName);
7054    if (element.removeEventListener) {
7055      element.removeEventListener(actualEventName, responder, false);
7056    } else {
7057      element.detachEvent('on' + actualEventName, responder);
7058    }
7059  }
7060
7061  function stopObservingCustomEvent(element, eventName, responder) {
7062    if (element.removeEventListener) {
7063      element.removeEventListener('dataavailable', responder, false);
7064    } else {
7065      element.detachEvent('ondataavailable', responder);
7066      element.detachEvent('onlosecapture',   responder);
7067    }
7068  }
7069
7070
7071
7072  function stopObservingElement(element) {
7073    var uid = getUniqueElementID(element), registry = GLOBAL.Event.cache[uid];
7074    if (!registry) return;
7075
7076    destroyRegistryForElement(element, uid);
7077
7078    var entries, i;
7079    for (var eventName in registry) {
7080      if (eventName === 'element') continue;
7081
7082      entries = registry[eventName];
7083      i = entries.length;
7084      while (i--)
7085        removeEvent(element, eventName, entries[i].responder);
7086    }
7087  }
7088
7089  function stopObservingEventName(element, eventName) {
7090    var registry = getOrCreateRegistryFor(element);
7091    var entries = registry[eventName];
7092    if (entries) {
7093      delete registry[eventName];
7094    }
7095
7096    entries = entries || [];
7097
7098    var i = entries.length;
7099    while (i--)
7100      removeEvent(element, eventName, entries[i].responder);
7101
7102    for (var name in registry) {
7103      if (name === 'element') continue;
7104      return; // There is another registered event
7105    }
7106
7107    destroyRegistryForElement(element);
7108  }
7109
7110
7111  function removeEvent(element, eventName, handler) {
7112    if (isCustomEvent(eventName))
7113      stopObservingCustomEvent(element, eventName, handler);
7114    else
7115      stopObservingStandardEvent(element, eventName, handler);
7116  }
7117
7118
7119
7120  function getFireTarget(element) {
7121    if (element !== document) return element;
7122    if (document.createEvent && !element.dispatchEvent)
7123      return document.documentElement;
7124    return element;
7125  }
7126
7127  function fire(element, eventName, memo, bubble) {
7128    element = getFireTarget($(element));
7129    if (Object.isUndefined(bubble)) bubble = true;
7130    memo = memo || {};
7131
7132    var event = fireEvent(element, eventName, memo, bubble);
7133    return Event.extend(event);
7134  }
7135
7136  function fireEvent_DOM(element, eventName, memo, bubble) {
7137    var event = document.createEvent('HTMLEvents');
7138    event.initEvent('dataavailable', bubble, true);
7139
7140    event.eventName = eventName;
7141    event.memo = memo;
7142
7143    element.dispatchEvent(event);
7144    return event;
7145  }
7146
7147  function fireEvent_IE(element, eventName, memo, bubble) {
7148    var event = document.createEventObject();
7149    event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
7150
7151    event.eventName = eventName;
7152    event.memo = memo;
7153
7154    element.fireEvent(event.eventType, event);
7155    return event;
7156  }
7157
7158  var fireEvent = document.createEvent ? fireEvent_DOM : fireEvent_IE;
7159
7160
7161
7162  Event.Handler = Class.create({
7163    initialize: function(element, eventName, selector, callback) {
7164      this.element   = $(element);
7165      this.eventName = eventName;
7166      this.selector  = selector;
7167      this.callback  = callback;
7168      this.handler   = this.handleEvent.bind(this);
7169    },
7170
7171
7172    start: function() {
7173      Event.observe(this.element, this.eventName, this.handler);
7174      return this;
7175    },
7176
7177    stop: function() {
7178      Event.stopObserving(this.element, this.eventName, this.handler);
7179      return this;
7180    },
7181
7182    handleEvent: function(event) {
7183      var element = Event.findElement(event, this.selector);
7184      if (element) this.callback.call(this.element, event, element);
7185    }
7186  });
7187
7188  function on(element, eventName, selector, callback) {
7189    element = $(element);
7190    if (Object.isFunction(selector) && Object.isUndefined(callback)) {
7191      callback = selector, selector = null;
7192    }
7193
7194    return new Event.Handler(element, eventName, selector, callback).start();
7195  }
7196
7197  Object.extend(Event, Event.Methods);
7198
7199  Object.extend(Event, {
7200    fire:          fire,
7201    observe:       observe,
7202    stopObserving: stopObserving,
7203    on:            on
7204  });
7205
7206  Element.addMethods({
7207    fire:          fire,
7208
7209    observe:       observe,
7210
7211    stopObserving: stopObserving,
7212
7213    on:            on
7214  });
7215
7216  Object.extend(document, {
7217    fire:          fire.methodize(),
7218
7219    observe:       observe.methodize(),
7220
7221    stopObserving: stopObserving.methodize(),
7222
7223    on:            on.methodize(),
7224
7225    loaded:        false
7226  });
7227
7228  if (GLOBAL.Event) Object.extend(window.Event, Event);
7229  else GLOBAL.Event = Event;
7230
7231  GLOBAL.Event.cache = {};
7232
7233  function destroyCache_IE() {
7234    GLOBAL.Event.cache = null;
7235  }
7236
7237  if (window.attachEvent)
7238    window.attachEvent('onunload', destroyCache_IE);
7239
7240  DIV = null;
7241  docEl = null;
7242})(this);
7243
7244(function(GLOBAL) {
7245  /* Code for creating leak-free event responders is based on work by
7246   John-David Dalton. */
7247
7248  var docEl = document.documentElement;
7249  var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
7250    && 'onmouseleave' in docEl;
7251
7252  function isSimulatedMouseEnterLeaveEvent(eventName) {
7253    return !MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
7254     (eventName === 'mouseenter' || eventName === 'mouseleave');
7255  }
7256
7257  function createResponder(uid, eventName, handler) {
7258    if (Event._isCustomEvent(eventName))
7259      return createResponderForCustomEvent(uid, eventName, handler);
7260    if (isSimulatedMouseEnterLeaveEvent(eventName))
7261      return createMouseEnterLeaveResponder(uid, eventName, handler);
7262
7263    return function(event) {
7264      if (!Event.cache) return;
7265
7266      var element = Event.cache[uid].element;
7267      Event.extend(event, element);
7268      handler.call(element, event);
7269    };
7270  }
7271
7272  function createResponderForCustomEvent(uid, eventName, handler) {
7273    return function(event) {
7274      var cache = Event.cache[uid];
7275      var element =  cache && cache.element;
7276
7277      if (Object.isUndefined(event.eventName))
7278        return false;
7279
7280      if (event.eventName !== eventName)
7281        return false;
7282
7283      Event.extend(event, element);
7284      handler.call(element, event);
7285    };
7286  }
7287
7288  function createMouseEnterLeaveResponder(uid, eventName, handler) {
7289    return function(event) {
7290      var element = Event.cache[uid].element;
7291
7292      Event.extend(event, element);
7293      var parent = event.relatedTarget;
7294
7295      while (parent && parent !== element) {
7296        try { parent = parent.parentNode; }
7297        catch(e) { parent = element; }
7298      }
7299
7300      if (parent === element) return;
7301      handler.call(element, event);
7302    }
7303  }
7304
7305  GLOBAL.Event._createResponder = createResponder;
7306  docEl = null;
7307})(this);
7308
7309(function(GLOBAL) {
7310  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
7311     Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
7312
7313  var TIMER;
7314
7315  function fireContentLoadedEvent() {
7316    if (document.loaded) return;
7317    if (TIMER) window.clearTimeout(TIMER);
7318    document.loaded = true;
7319    document.fire('dom:loaded');
7320  }
7321
7322  function checkReadyState() {
7323    if (document.readyState === 'complete') {
7324      document.detachEvent('onreadystatechange', checkReadyState);
7325      fireContentLoadedEvent();
7326    }
7327  }
7328
7329  function pollDoScroll() {
7330    try {
7331      document.documentElement.doScroll('left');
7332    } catch (e) {
7333      TIMER = pollDoScroll.defer();
7334      return;
7335    }
7336
7337    fireContentLoadedEvent();
7338  }
7339
7340
7341  if (document.readyState === 'complete') {
7342    fireContentLoadedEvent();
7343    return;
7344  }
7345
7346  if (document.addEventListener) {
7347    document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
7348  } else {
7349    document.attachEvent('onreadystatechange', checkReadyState);
7350    if (window == top) TIMER = pollDoScroll.defer();
7351  }
7352
7353  Event.observe(window, 'load', fireContentLoadedEvent);
7354})(this);
7355
7356
7357Element.addMethods();
7358/*------------------------------- DEPRECATED -------------------------------*/
7359
7360Hash.toQueryString = Object.toQueryString;
7361
7362var Toggle = { display: Element.toggle };
7363
7364Element.addMethods({
7365  childOf: Element.Methods.descendantOf
7366});
7367
7368var Insertion = {
7369  Before: function(element, content) {
7370    return Element.insert(element, {before:content});
7371  },
7372
7373  Top: function(element, content) {
7374    return Element.insert(element, {top:content});
7375  },
7376
7377  Bottom: function(element, content) {
7378    return Element.insert(element, {bottom:content});
7379  },
7380
7381  After: function(element, content) {
7382    return Element.insert(element, {after:content});
7383  }
7384};
7385
7386var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
7387
7388var Position = {
7389  includeScrollOffsets: false,
7390
7391  prepare: function() {
7392    this.deltaX =  window.pageXOffset
7393                || document.documentElement.scrollLeft
7394                || document.body.scrollLeft
7395                || 0;
7396    this.deltaY =  window.pageYOffset
7397                || document.documentElement.scrollTop
7398                || document.body.scrollTop
7399                || 0;
7400  },
7401
7402  within: function(element, x, y) {
7403    if (this.includeScrollOffsets)
7404      return this.withinIncludingScrolloffsets(element, x, y);
7405    this.xcomp = x;
7406    this.ycomp = y;
7407    this.offset = Element.cumulativeOffset(element);
7408
7409    return (y >= this.offset[1] &&
7410            y <  this.offset[1] + element.offsetHeight &&
7411            x >= this.offset[0] &&
7412            x <  this.offset[0] + element.offsetWidth);
7413  },
7414
7415  withinIncludingScrolloffsets: function(element, x, y) {
7416    var offsetcache = Element.cumulativeScrollOffset(element);
7417
7418    this.xcomp = x + offsetcache[0] - this.deltaX;
7419    this.ycomp = y + offsetcache[1] - this.deltaY;
7420    this.offset = Element.cumulativeOffset(element);
7421
7422    return (this.ycomp >= this.offset[1] &&
7423            this.ycomp <  this.offset[1] + element.offsetHeight &&
7424            this.xcomp >= this.offset[0] &&
7425            this.xcomp <  this.offset[0] + element.offsetWidth);
7426  },
7427
7428  overlap: function(mode, element) {
7429    if (!mode) return 0;
7430    if (mode == 'vertical')
7431      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
7432        element.offsetHeight;
7433    if (mode == 'horizontal')
7434      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
7435        element.offsetWidth;
7436  },
7437
7438
7439  cumulativeOffset: Element.Methods.cumulativeOffset,
7440
7441  positionedOffset: Element.Methods.positionedOffset,
7442
7443  absolutize: function(element) {
7444    Position.prepare();
7445    return Element.absolutize(element);
7446  },
7447
7448  relativize: function(element) {
7449    Position.prepare();
7450    return Element.relativize(element);
7451  },
7452
7453  realOffset: Element.Methods.cumulativeScrollOffset,
7454
7455  offsetParent: Element.Methods.getOffsetParent,
7456
7457  page: Element.Methods.viewportOffset,
7458
7459  clone: function(source, target, options) {
7460    options = options || { };
7461    return Element.clonePosition(target, source, options);
7462  }
7463};
7464
7465/*--------------------------------------------------------------------------*/
7466
7467if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
7468  function iter(name) {
7469    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
7470  }
7471
7472  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
7473  function(element, className) {
7474    className = className.toString().strip();
7475    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
7476    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
7477  } : function(element, className) {
7478    className = className.toString().strip();
7479    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
7480    if (!classNames && !className) return elements;
7481
7482    var nodes = $(element).getElementsByTagName('*');
7483    className = ' ' + className + ' ';
7484
7485    for (var i = 0, child, cn; child = nodes[i]; i++) {
7486      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
7487          (classNames && classNames.all(function(name) {
7488            return !name.toString().blank() && cn.include(' ' + name + ' ');
7489          }))))
7490        elements.push(Element.extend(child));
7491    }
7492    return elements;
7493  };
7494
7495  return function(className, parentElement) {
7496    return $(parentElement || document.body).getElementsByClassName(className);
7497  };
7498}(Element.Methods);
7499
7500/*--------------------------------------------------------------------------*/
7501
7502Element.ClassNames = Class.create();
7503Element.ClassNames.prototype = {
7504  initialize: function(element) {
7505    this.element = $(element);
7506  },
7507
7508  _each: function(iterator, context) {
7509    this.element.className.split(/\s+/).select(function(name) {
7510      return name.length > 0;
7511    })._each(iterator, context);
7512  },
7513
7514  set: function(className) {
7515    this.element.className = className;
7516  },
7517
7518  add: function(classNameToAdd) {
7519    if (this.include(classNameToAdd)) return;
7520    this.set($A(this).concat(classNameToAdd).join(' '));
7521  },
7522
7523  remove: function(classNameToRemove) {
7524    if (!this.include(classNameToRemove)) return;
7525    this.set($A(this).without(classNameToRemove).join(' '));
7526  },
7527
7528  toString: function() {
7529    return $A(this).join(' ');
7530  }
7531};
7532
7533Object.extend(Element.ClassNames.prototype, Enumerable);
7534
7535/*--------------------------------------------------------------------------*/
7536
7537(function() {
7538  window.Selector = Class.create({
7539    initialize: function(expression) {
7540      this.expression = expression.strip();
7541    },
7542
7543    findElements: function(rootElement) {
7544      return Prototype.Selector.select(this.expression, rootElement);
7545    },
7546
7547    match: function(element) {
7548      return Prototype.Selector.match(element, this.expression);
7549    },
7550
7551    toString: function() {
7552      return this.expression;
7553    },
7554
7555    inspect: function() {
7556      return "#<Selector: " + this.expression + ">";
7557    }
7558  });
7559
7560  Object.extend(Selector, {
7561    matchElements: function(elements, expression) {
7562      var match = Prototype.Selector.match,
7563          results = [];
7564
7565      for (var i = 0, length = elements.length; i < length; i++) {
7566        var element = elements[i];
7567        if (match(element, expression)) {
7568          results.push(Element.extend(element));
7569        }
7570      }
7571      return results;
7572    },
7573
7574    findElement: function(elements, expression, index) {
7575      index = index || 0;
7576      var matchIndex = 0, element;
7577      for (var i = 0, length = elements.length; i < length; i++) {
7578        element = elements[i];
7579        if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
7580          return Element.extend(element);
7581        }
7582      }
7583    },
7584
7585    findChildElements: function(element, expressions) {
7586      var selector = expressions.toArray().join(', ');
7587      return Prototype.Selector.select(selector, element || document);
7588    }
7589  });
7590})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.