PageSourceSearch

https://www.motorteiledirekt.de/js/prototype/prototype.js?v=1760513748

js motorteiledirekt.de collected 2026-10-06 13:16:45 UTC 200,295 bytes, 7,593 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+("[^"]*"|'[^']*'|[^>'"])+)?\s*("[^">]*|'[^'>
624])?(\/)?>|<\/\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(character) {
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 = $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    element.parentNode.removeChild(element);
2177    return element;
2178  }
2179
2180  var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
2181    var el = document.createElement("select"),
2182        isBuggy = true;
2183    el.innerHTML = "<option value=\"test\">test</option>";
2184    if (el.options && el.options[0]) {
2185      isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION";
2186    }
2187    el = null;
2188    return isBuggy;
2189  })();
2190
2191  var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
2192    try {
2193      var el = document.createElement("table");
2194      if (el && el.tBodies) {
2195        el.innerHTML = "<tbody><tr><td>test</td></tr></tbody>";
2196        var isBuggy = typeof el.tBodies[0] == "undefined";
2197        el = null;
2198        return isBuggy;
2199      }
2200    } catch (e) {
2201      return true;
2202    }
2203  })();
2204
2205  var LINK_ELEMENT_INNERHTML_BUGGY = (function() {
2206    try {
2207      var el = document.createElement('div');
2208      el.innerHTML = "<link />";
2209      var isBuggy = (el.childNodes.length === 0);
2210      el = null;
2211      return isBuggy;
2212    } catch(e) {
2213      return true;
2214    }
2215  })();
2216
2217  var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY ||
2218   TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY;
2219
2220  var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
2221    var s = document.createElement("script"),
2222        isBuggy = false;
2223    try {
2224      s.appendChild(document.createTextNode(""));
2225      isBuggy = !s.firstChild ||
2226        s.firstChild && s.firstChild.nodeType !== 3;
2227    } catch (e) {
2228      isBuggy = true;
2229    }
2230    s = null;
2231    return isBuggy;
2232  })();
2233
2234  function update(element, content) {
2235    element = $(element);
2236
2237    var descendants = element.getElementsByTagName('*'),
2238     i = descendants.length;
2239    while (i--) purgeElement(descendants[i]);
2240
2241    if (content && content.toElement)
2242      content = content.toElement();
2243
2244    if (Object.isElement(content))
2245      return element.update().insert(content);
2246
2247
2248    content = Object.toHTML(content);
2249    var tagName = element.tagName.toUpperCase();
2250
2251    if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
2252      element.text = content;
2253      return element;
2254    }
2255
2256    if (ANY_INNERHTML_BUGGY) {
2257      if (tagName in INSERTION_TRANSLATIONS.tags) {
2258        while (element.firstChild)
2259          element.removeChild(element.firstChild);
2260
2261        var nodes = getContentFromAnonymousElement(tagName, content.stripScripts());
2262        for (var i = 0, node; node = nodes[i]; i++)
2263          element.appendChild(node);
2264
2265      } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf('<link') > -1) {
2266        while (element.firstChild)
2267          element.removeChild(element.firstChild);
2268
2269        var nodes = getContentFromAnonymousElement(tagName,
2270         content.stripScripts(), true);
2271
2272        for (var i = 0, node; node = nodes[i]; i++)
2273          element.appendChild(node);
2274      } else {
2275        element.innerHTML = content.stripScripts();
2276      }
2277    } else {
2278      element.innerHTML = content.stripScripts();
2279    }
2280
2281    content.evalScripts.bind(content).defer();
2282    return element;
2283  }
2284
2285  function replace(element, content) {
2286    element = $(element);
2287
2288    if (content && content.toElement) {
2289      content = content.toElement();
2290    } else if (!Object.isElement(content)) {
2291      content = Object.toHTML(content);
2292      var range = element.ownerDocument.createRange();
2293      range.selectNode(element);
2294      content.evalScripts.bind(content).defer();
2295      content = range.createContextualFragment(content.stripScripts());
2296    }
2297
2298    element.parentNode.replaceChild(content, element);
2299    return element;
2300  }
2301
2302  var INSERTION_TRANSLATIONS = {
2303    before: function(element, node) {
2304      element.parentNode.insertBefore(node, element);
2305    },
2306    top: function(element, node) {
2307      element.insertBefore(node, element.firstChild);
2308    },
2309    bottom: function(element, node) {
2310      element.appendChild(node);
2311    },
2312    after: function(element, node) {
2313      element.parentNode.insertBefore(node, element.nextSibling);
2314    },
2315
2316    tags: {
2317      TABLE:  ['<table>',                '</table>',                   1],
2318      TBODY:  ['<table><tbody>',         '</tbody></table>',           2],
2319      TR:     ['<table><tbody><tr>',     '</tr></tbody></table>',      3],
2320      TD:     ['<table><tbody><tr><td>', '</td></tr></tbody></table>', 4],
2321      SELECT: ['<select>',               '</select>',                  1]
2322    }
2323  };
2324
2325  var tags = INSERTION_TRANSLATIONS.tags;
2326
2327  Object.extend(tags, {
2328    THEAD: tags.TBODY,
2329    TFOOT: tags.TBODY,
2330    TH:    tags.TD
2331  });
2332
2333  function replace_IE(element, content) {
2334    element = $(element);
2335    if (content && content.toElement)
2336      content = content.toElement();
2337    if (Object.isElement(content)) {
2338      element.parentNode.replaceChild(content, element);
2339      return element;
2340    }
2341
2342    content = Object.toHTML(content);
2343    var parent = element.parentNode, tagName = parent.tagName.toUpperCase();
2344
2345    if (tagName in INSERTION_TRANSLATIONS.tags) {
2346      var nextSibling = Element.next(element);
2347      var fragments = getContentFromAnonymousElement(
2348       tagName, content.stripScripts());
2349
2350      parent.removeChild(element);
2351
2352      var iterator;
2353      if (nextSibling)
2354        iterator = function(node) { parent.insertBefore(node, nextSibling) };
2355      else
2356        iterator = function(node) { parent.appendChild(node); }
2357
2358      fragments.each(iterator);
2359    } else {
2360      element.outerHTML = content.stripScripts();
2361    }
2362
2363    content.evalScripts.bind(content).defer();
2364    return element;
2365  }
2366
2367  if ('outerHTML' in document.documentElement)
2368    replace = replace_IE;
2369
2370  function isContent(content) {
2371    if (Object.isUndefined(content) || content === null) return false;
2372
2373    if (Object.isString(content) || Object.isNumber(content)) return true;
2374    if (Object.isElement(content)) return true;
2375    if (content.toElement || content.toHTML) return true;
2376
2377    return false;
2378  }
2379
2380  function insertContentAt(element, content, position) {
2381    position   = position.toLowerCase();
2382    var method = INSERTION_TRANSLATIONS[position];
2383
2384    if (content && content.toElement) content = content.toElement();
2385    if (Object.isElement(content)) {
2386      method(element, content);
2387      return element;
2388    }
2389
2390    content = Object.toHTML(content);
2391    var tagName = ((position === 'before' || position === 'after') ?
2392     element.parentNode : element).tagName.toUpperCase();
2393
2394    var childNodes = getContentFromAnonymousElement(tagName, content.stripScripts());
2395
2396    if (position === 'top' || position === 'after') childNodes.reverse();
2397
2398    for (var i = 0, node; node = childNodes[i]; i++)
2399      method(element, node);
2400
2401    content.evalScripts.bind(content).defer();
2402  }
2403
2404  function insert(element, insertions) {
2405    element = $(element);
2406
2407    if (isContent(insertions))
2408      insertions = { bottom: insertions };
2409
2410    for (var position in insertions)
2411      insertContentAt(element, insertions[position], position);
2412
2413    return element;
2414  }
2415
2416  function wrap(element, wrapper, attributes) {
2417    element = $(element);
2418
2419    if (Object.isElement(wrapper)) {
2420      $(wrapper).writeAttribute(attributes || {});
2421    } else if (Object.isString(wrapper)) {
2422      wrapper = new Element(wrapper, attributes);
2423    } else {
2424      wrapper = new Element('div', wrapper);
2425    }
2426
2427    if (element.parentNode)
2428      element.parentNode.replaceChild(wrapper, element);
2429
2430    wrapper.appendChild(element);
2431
2432    return wrapper;
2433  }
2434
2435  function cleanWhitespace(element) {
2436    element = $(element);
2437    var node = element.firstChild;
2438
2439    while (node) {
2440      var nextNode = node.nextSibling;
2441      if (node.nodeType === Node.TEXT_NODE && !/\S/.test(node.nodeValue))
2442        element.removeChild(node);
2443      node = nextNode;
2444    }
2445    return element;
2446  }
2447
2448  function empty(element) {
2449    return $(element).innerHTML.blank();
2450  }
2451
2452  function getContentFromAnonymousElement(tagName, html, force) {
2453    var t = INSERTION_TRANSLATIONS.tags[tagName], div = DIV;
2454
2455    var workaround = !!t;
2456    if (!workaround && force) {
2457      workaround = true;
2458      t = ['', '', 0];
2459    }
2460
2461    if (workaround) {
2462      div.innerHTML = '&#160;' + t[0] + html + t[1];
2463      div.removeChild(div.firstChild);
2464      for (var i = t[2]; i--; )
2465        div = div.firstChild;
2466    } else {
2467      div.innerHTML = html;
2468    }
2469
2470    return $A(div.childNodes);
2471  }
2472
2473  function clone(element, deep) {
2474    if (!(element = $(element))) return;
2475    var clone = element.cloneNode(deep);
2476    if (!HAS_UNIQUE_ID_PROPERTY) {
2477      clone._prototypeUID = UNDEFINED;
2478      if (deep) {
2479        var descendants = Element.select(clone, '*'),
2480         i = descendants.length;
2481        while (i--)
2482          descendants[i]._prototypeUID = UNDEFINED;
2483      }
2484    }
2485    return Element.extend(clone);
2486  }
2487
2488  function purgeElement(element) {
2489    var uid = getUniqueElementID(element);
2490    if (uid) {
2491      Element.stopObserving(element);
2492      if (!HAS_UNIQUE_ID_PROPERTY)
2493        element._prototypeUID = UNDEFINED;
2494      delete Element.Storage[uid];
2495    }
2496  }
2497
2498  function purgeCollection(elements) {
2499    var i = elements.length;
2500    while (i--)
2501      purgeElement(elements[i]);
2502  }
2503
2504  function purgeCollection_IE(elements) {
2505    var i = elements.length, element, uid;
2506    while (i--) {
2507      element = elements[i];
2508      uid = getUniqueElementID(element);
2509      delete Element.Storage[uid];
2510      delete Event.cache[uid];
2511    }
2512  }
2513
2514  if (HAS_UNIQUE_ID_PROPERTY) {
2515    purgeCollection = purgeCollection_IE;
2516  }
2517
2518
2519  function purge(element) {
2520    if (!(element = $(element))) return;
2521    purgeElement(element);
2522
2523    var descendants = element.getElementsByTagName('*'),
2524     i = descendants.length;
2525
2526    while (i--) purgeElement(descendants[i]);
2527
2528    return null;
2529  }
2530
2531  Object.extend(methods, {
2532    remove:  remove,
2533    update:  update,
2534    replace: replace,
2535    insert:  insert,
2536    wrap:    wrap,
2537    cleanWhitespace: cleanWhitespace,
2538    empty:   empty,
2539    clone:   clone,
2540    purge:   purge
2541  });
2542
2543
2544
2545  function recursivelyCollect(element, property, maximumLength) {
2546    element = $(element);
2547    maximumLength = maximumLength || -1;
2548    var elements = [];
2549
2550    while (element = element[property]) {
2551      if (element.nodeType === Node.ELEMENT_NODE)
2552        elements.push(Element.extend(element));
2553
2554      if (elements.length === maximumLength) break;
2555    }
2556
2557    return elements;
2558  }
2559
2560
2561  function ancestors(element) {
2562    return recursivelyCollect(element, 'parentNode');
2563  }
2564
2565  function descendants(element) {
2566    return Element.select(element, '*');
2567  }
2568
2569  function firstDescendant(element) {
2570    element = $(element).firstChild;
2571    while (element && element.nodeType !== Node.ELEMENT_NODE)
2572      element = element.nextSibling;
2573
2574    return $(element);
2575  }
2576
2577  function immediateDescendants(element) {
2578    var results = [], child = $(element).firstChild;
2579
2580    while (child) {
2581      if (child.nodeType === Node.ELEMENT_NODE)
2582        results.push(Element.extend(child));
2583
2584      child = child.nextSibling;
2585    }
2586
2587    return results;
2588  }
2589
2590  function previousSiblings(element) {
2591    return recursivelyCollect(element, 'previousSibling');
2592  }
2593
2594  function nextSiblings(element) {
2595    return recursivelyCollect(element, 'nextSibling');
2596  }
2597
2598  function siblings(element) {
2599    element = $(element);
2600    var previous = previousSiblings(element),
2601     next = nextSiblings(element);
2602    return previous.reverse().concat(next);
2603  }
2604
2605  function match(element, selector) {
2606    element = $(element);
2607
2608    if (Object.isString(selector))
2609      return Prototype.Selector.match(element, selector);
2610
2611    return selector.match(element);
2612  }
2613
2614
2615  function _recursivelyFind(element, property, expression, index) {
2616    element = $(element), expression = expression || 0, index = index || 0;
2617    if (Object.isNumber(expression)) {
2618      index = expression, expression = null;
2619    }
2620
2621    while (element = element[property]) {
2622      if (element.nodeType !== 1) continue;
2623      if (expression && !Prototype.Selector.match(element, expression))
2624        continue;
2625      if (--index >= 0) continue;
2626
2627      return Element.extend(element);
2628    }
2629  }
2630
2631
2632  function up(element, expression, index) {
2633    element = $(element);
2634
2635    if (arguments.length === 1) return $(element.parentNode);
2636    return _recursivelyFind(element, 'parentNode', expression, index);
2637  }
2638
2639  function down(element, expression, index) {
2640    if (arguments.length === 1) return firstDescendant(element);
2641    element = $(element), expression = expression || 0, index = index || 0;
2642
2643    if (Object.isNumber(expression))
2644      index = expression, expression = '*';
2645
2646    var node = Prototype.Selector.select(expression, element)[index];
2647    return Element.extend(node);
2648  }
2649
2650  function previous(element, expression, index) {
2651    return _recursivelyFind(element, 'previousSibling', expression, index);
2652  }
2653
2654  function next(element, expression, index) {
2655    return _recursivelyFind(element, 'nextSibling', expression, index);
2656  }
2657
2658  function select(element) {
2659    element = $(element);
2660    var expressions = SLICE.call(arguments, 1).join(', ');
2661    return Prototype.Selector.select(expressions, element);
2662  }
2663
2664  function adjacent(element) {
2665    element = $(element);
2666    var expressions = SLICE.call(arguments, 1).join(', ');
2667    var siblings = Element.siblings(element), results = [];
2668    for (var i = 0, sibling; sibling = siblings[i]; i++) {
2669      if (Prototype.Selector.match(sibling, expressions))
2670        results.push(sibling);
2671    }
2672
2673    return results;
2674  }
2675
2676  function descendantOf_DOM(element, ancestor) {
2677    element = $(element), ancestor = $(ancestor);
2678    if (!element || !ancestor) return false;
2679    while (element = element.parentNode)
2680      if (element === ancestor) return true;
2681    return false;
2682  }
2683
2684  function descendantOf_contains(element, ancestor) {
2685    element = $(element), ancestor = $(ancestor);
2686    if (!element || !ancestor) return false;
2687    if (!ancestor.contains) return descendantOf_DOM(element, ancestor);
2688    return ancestor.contains(element) && ancestor !== element;
2689  }
2690
2691  function descendantOf_compareDocumentPosition(element, ancestor) {
2692    element = $(element), ancestor = $(ancestor);
2693    if (!element || !ancestor) return false;
2694    return (element.compareDocumentPosition(ancestor) & 8) === 8;
2695  }
2696
2697  var descendantOf;
2698  if (DIV.compareDocumentPosition) {
2699    descendantOf = descendantOf_compareDocumentPosition;
2700  } else if (DIV.contains) {
2701    descendantOf = descendantOf_contains;
2702  } else {
2703    descendantOf = descendantOf_DOM;
2704  }
2705
2706
2707  Object.extend(methods, {
2708    recursivelyCollect:   recursivelyCollect,
2709    ancestors:            ancestors,
2710    descendants:          descendants,
2711    firstDescendant:      firstDescendant,
2712    immediateDescendants: immediateDescendants,
2713    previousSiblings:     previousSiblings,
2714    nextSiblings:         nextSiblings,
2715    siblings:             siblings,
2716    match:                match,
2717    up:                   up,
2718    down:                 down,
2719    previous:             previous,
2720    next:                 next,
2721    select:               select,
2722    adjacent:             adjacent,
2723    descendantOf:         descendantOf,
2724
2725    getElementsBySelector: select,
2726
2727    childElements:         immediateDescendants
2728  });
2729
2730
2731  var idCounter = 1;
2732  function identify(element) {
2733    element = $(element);
2734    var id = Element.readAttribute(element, 'id');
2735    if (id) return id;
2736
2737    do { id = 'anonymous_element_' + idCounter++ } while ($(id));
2738
2739    Element.writeAttribute(element, 'id', id);
2740    return id;
2741  }
2742
2743
2744  function readAttribute(element, name) {
2745    return $(element).getAttribute(name);
2746  }
2747
2748  function readAttribute_IE(element, name) {
2749    element = $(element);
2750
2751    var table = ATTRIBUTE_TRANSLATIONS.read;
2752    if (table.values[name])
2753      return table.values[name](element, name);
2754
2755    if (table.names[name]) name = table.names[name];
2756
2757    if (name.include(':')) {
2758      if (!element.attributes || !element.attributes[name]) return null;
2759      return element.attributes[name].value;
2760    }
2761
2762    return element.getAttribute(name);
2763  }
2764
2765  function readAttribute_Opera(element, name) {
2766    if (name === 'title') return element.title;
2767    return element.getAttribute(name);
2768  }
2769
2770  var PROBLEMATIC_ATTRIBUTE_READING = (function() {
2771    DIV.setAttribute('onclick', []);
2772    var value = DIV.getAttribute('onclick');
2773    var isFunction = Object.isArray(value);
2774    DIV.removeAttribute('onclick');
2775    return isFunction;
2776  })();
2777
2778  if (PROBLEMATIC_ATTRIBUTE_READING) {
2779    readAttribute = readAttribute_IE;
2780  } else if (Prototype.Browser.Opera) {
2781    readAttribute = readAttribute_Opera;
2782  }
2783
2784
2785  function writeAttribute(element, name, value) {
2786    element = $(element);
2787    var attributes = {}, table = ATTRIBUTE_TRANSLATIONS.write;
2788
2789    if (typeof name === 'object') {
2790      attributes = name;
2791    } else {
2792      attributes[name] = Object.isUndefined(value) ? true : value;
2793    }
2794
2795    for (var attr in attributes) {
2796      name = table.names[attr] || attr;
2797      value = attributes[attr];
2798      if (table.values[attr]) {
2799        value = table.values[attr](element, value);
2800        if (Object.isUndefined(value)) continue;
2801      }
2802      if (value === false || value === null)
2803        element.removeAttribute(name);
2804      else if (value === true)
2805        element.setAttribute(name, name);
2806      else element.setAttribute(name, value);
2807    }
2808
2809    return element;
2810  }
2811
2812  var PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES = (function () {
2813    if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX) {
2814      return false;
2815    }
2816    var checkbox = document.createElement('<input type="checkbox">');
2817    checkbox.checked = true;
2818    var node = checkbox.getAttributeNode('checked');
2819    return !node || !node.specified;
2820  })();
2821
2822  function hasAttribute(element, attribute) {
2823    attribute = ATTRIBUTE_TRANSLATIONS.has[attribute] || attribute;
2824    var node = $(element).getAttributeNode(attribute);
2825    return !!(node && node.specified);
2826  }
2827
2828  function hasAttribute_IE(element, attribute) {
2829    if (attribute === 'checked') {
2830      return element.checked;
2831    }
2832    return hasAttribute(element, attribute);
2833  }
2834
2835  GLOBAL.Element.Methods.Simulated.hasAttribute =
2836   PROBLEMATIC_HAS_ATTRIBUTE_WITH_CHECKBOXES ?
2837   hasAttribute_IE : hasAttribute;
2838
2839  function classNames(element) {
2840    return new Element.ClassNames(element);
2841  }
2842
2843  var regExpCache = {};
2844  function getRegExpForClassName(className) {
2845    if (regExpCache[className]) return regExpCache[className];
2846
2847    var re = new RegExp("(^|\\s+)" + className + "(\\s+|$)");
2848    regExpCache[className] = re;
2849    return re;
2850  }
2851
2852  function hasClassName(element, className) {
2853    if (!(element = $(element))) return;
2854
2855    var elementClassName = element.className;
2856
2857    if (elementClassName.length === 0) return false;
2858    if (elementClassName === className) return true;
2859
2860    return getRegExpForClassName(className).test(elementClassName);
2861  }
2862
2863  function addClassName(element, className) {
2864    if (!(element = $(element))) return;
2865
2866    if (!hasClassName(element, className))
2867      element.className += (element.className ? ' ' : '') + className;
2868
2869    return element;
2870  }
2871
2872  function removeClassName(element, className) {
2873    if (!(element = $(element))) return;
2874
2875    element.className = element.className.replace(
2876     getRegExpForClassName(className), ' ').strip();
2877
2878    return element;
2879  }
2880
2881  function toggleClassName(element, className, bool) {
2882    if (!(element = $(element))) return;
2883
2884    if (Object.isUndefined(bool))
2885      bool = !hasClassName(element, className);
2886
2887    var method = Element[bool ? 'addClassName' : 'removeClassName'];
2888    return method(element, className);
2889  }
2890
2891  var ATTRIBUTE_TRANSLATIONS = {};
2892
2893  var classProp = 'className', forProp = 'for';
2894
2895  DIV.setAttribute(classProp, 'x');
2896  if (DIV.className !== 'x') {
2897    DIV.setAttribute('class', 'x');
2898    if (DIV.className === 'x')
2899      classProp = 'class';
2900  }
2901
2902  var LABEL = document.createElement('label');
2903  LABEL.setAttribute(forProp, 'x');
2904  if (LABEL.htmlFor !== 'x') {
2905    LABEL.setAttribute('htmlFor', 'x');
2906    if (LABEL.htmlFor === 'x')
2907      forProp = 'htmlFor';
2908  }
2909  LABEL = null;
2910
2911  function _getAttr(element, attribute) {
2912    return element.getAttribute(attribute);
2913  }
2914
2915  function _getAttr2(element, attribute) {
2916    return element.getAttribute(attribute, 2);
2917  }
2918
2919  function _getAttrNode(element, attribute) {
2920    var node = element.getAttributeNode(attribute);
2921    return node ? node.value : '';
2922  }
2923
2924  function _getFlag(element, attribute) {
2925    return $(element).hasAttribute(attribute) ? attribute : null;
2926  }
2927
2928  DIV.onclick = Prototype.emptyFunction;
2929  var onclickValue = DIV.getAttribute('onclick');
2930
2931  var _getEv;
2932
2933  if (String(onclickValue).indexOf('{') > -1) {
2934    _getEv = function(element, attribute) {
2935      var value = element.getAttribute(attribute);
2936      if (!value) return null;
2937      value = value.toString();
2938      value = value.split('{')[1];
2939      value = value.split('}')[0];
2940      return value.strip();
2941    };
2942  }
2943  else if (onclickValue === '') {
2944    _getEv = function(element, attribute) {
2945      var value = element.getAttribute(attribute);
2946      if (!value) return null;
2947      return value.strip();
2948    };
2949  }
2950
2951  ATTRIBUTE_TRANSLATIONS.read = {
2952    names: {
2953      'class':     classProp,
2954      'className': classProp,
2955      'for':       forProp,
2956      'htmlFor':   forProp
2957    },
2958
2959    values: {
2960      style: function(element) {
2961        return element.style.cssText.toLowerCase();
2962      },
2963      title: function(element) {
2964        return element.title;
2965      }
2966    }
2967  };
2968
2969  ATTRIBUTE_TRANSLATIONS.write = {
2970    names: {
2971      className:   'class',
2972      htmlFor:     'for',
2973      cellpadding: 'cellPadding',
2974      cellspacing: 'cellSpacing'
2975    },
2976
2977    values: {
2978      checked: function(element, value) {
2979        value = !!value;
2980        element.checked = value;
2981        return value ? 'checked' : null;
2982      },
2983
2984      style: function(element, value) {
2985        element.style.cssText = value ? value : '';
2986      }
2987    }
2988  };
2989
2990  ATTRIBUTE_TRANSLATIONS.has = { names: {} };
2991
2992  Object.extend(ATTRIBUTE_TRANSLATIONS.write.names,
2993   ATTRIBUTE_TRANSLATIONS.read.names);
2994
2995  var CAMEL_CASED_ATTRIBUTE_NAMES = $w('colSpan rowSpan vAlign dateTime ' +
2996   'accessKey tabIndex encType maxLength readOnly longDesc frameBorder');
2997
2998  for (var i = 0, attr; attr = CAMEL_CASED_ATTRIBUTE_NAMES[i]; i++) {
2999    ATTRIBUTE_TRANSLATIONS.write.names[attr.toLowerCase()] = attr;
3000    ATTRIBUTE_TRANSLATIONS.has.names[attr.toLowerCase()]   = attr;
3001  }
3002
3003  Object.extend(ATTRIBUTE_TRANSLATIONS.read.values, {
3004    href:        _getAttr2,
3005    src:         _getAttr2,
3006    type:        _getAttr,
3007    action:      _getAttrNode,
3008    disabled:    _getFlag,
3009    checked:     _getFlag,
3010    readonly:    _getFlag,
3011    multiple:    _getFlag,
3012    onload:      _getEv,
3013    onunload:    _getEv,
3014    onclick:     _getEv,
3015    ondblclick:  _getEv,
3016    onmousedown: _getEv,
3017    onmouseup:   _getEv,
3018    onmouseover: _getEv,
3019    onmousemove: _getEv,
3020    onmouseout:  _getEv,
3021    onfocus:     _getEv,
3022    onblur:      _getEv,
3023    onkeypress:  _getEv,
3024    onkeydown:   _getEv,
3025    onkeyup:     _getEv,
3026    onsubmit:    _getEv,
3027    onreset:     _getEv,
3028    onselect:    _getEv,
3029    onchange:    _getEv
3030  });
3031
3032
3033  Object.extend(methods, {
3034    identify:        identify,
3035    readAttribute:   readAttribute,
3036    writeAttribute:  writeAttribute,
3037    classNames:      classNames,
3038    hasClassName:    hasClassName,
3039    addClassName:    addClassName,
3040    removeClassName: removeClassName,
3041    toggleClassName: toggleClassName
3042  });
3043
3044
3045  function normalizeStyleName(style) {
3046    if (style === 'float' || style === 'styleFloat')
3047      return 'cssFloat';
3048    return style.camelize();
3049  }
3050
3051  function normalizeStyleName_IE(style) {
3052    if (style === 'float' || style === 'cssFloat')
3053      return 'styleFloat';
3054    return style.camelize();
3055  }
3056
3057  function setStyle(element, styles) {
3058    element = $(element);
3059    var elementStyle = element.style, match;
3060
3061    if (Object.isString(styles)) {
3062      elementStyle.cssText += ';' + styles;
3063      if (styles.include('opacity')) {
3064        var opacity = styles.match(/opacity:\s*(\d?\.?\d*)/)[1];
3065        Element.setOpacity(element, opacity);
3066      }
3067      return element;
3068    }
3069
3070    for (var property in styles) {
3071      if (property === 'opacity') {
3072        Element.setOpacity(element, styles[property]);
3073      } else {
3074        var value = styles[property];
3075        if (property === 'float' || property === 'cssFloat') {
3076          property = Object.isUndefined(elementStyle.styleFloat) ?
3077           'cssFloat' : 'styleFloat';
3078        }
3079        elementStyle[property] = value;
3080      }
3081    }
3082
3083    return element;
3084  }
3085
3086
3087  function getStyle(element, style) {
3088    element = $(element);
3089    style = normalizeStyleName(style);
3090
3091    var value = element.style[style];
3092    if (!value || value === 'auto') {
3093      var css = document.defaultView.getComputedStyle(element, null);
3094      value = css ? css[style] : null;
3095    }
3096
3097    if (style === 'opacity') return value ? parseFloat(value) : 1.0;
3098    return value === 'auto' ? null : value;
3099  }
3100
3101  function getStyle_Opera(element, style) {
3102    switch (style) {
3103      case 'height': case 'width':
3104        if (!Element.visible(element)) return null;
3105
3106        var dim = parseInt(getStyle(element, style), 10);
3107
3108        if (dim !== element['offset' + style.capitalize()])
3109          return dim + 'px';
3110
3111        return Element.measure(element, style);
3112
3113      default: return getStyle(element, style);
3114    }
3115  }
3116
3117  function getStyle_IE(element, style) {
3118    element = $(element);
3119    style = normalizeStyleName_IE(style);
3120
3121    var value = element.style[style];
3122    if (!value && element.currentStyle) {
3123      value = element.currentStyle[style];
3124    }
3125
3126    if (style === 'opacity') {
3127      if (!STANDARD_CSS_OPACITY_SUPPORTED)
3128        return getOpacity_IE(element);
3129      else return value ? parseFloat(value) : 1.0;
3130    }
3131
3132    if (value === 'auto') {
3133      if ((style === 'width' || style === 'height') && Element.visible(element))
3134        return Element.measure(element, style) + 'px';
3135      return null;
3136    }
3137
3138    return value;
3139  }
3140
3141  function stripAlphaFromFilter_IE(filter) {
3142    return (filter || '').replace(/alpha\([^\)]*\)/gi, '');
3143  }
3144
3145  function hasLayout_IE(element) {
3146    if (!element.currentStyle || !element.currentStyle.hasLayout)
3147      element.style.zoom = 1;
3148    return element;
3149  }
3150
3151  var STANDARD_CSS_OPACITY_SUPPORTED = (function() {
3152    DIV.style.cssText = "opacity:.55";
3153    return /^0.55/.test(DIV.style.opacity);
3154  })();
3155
3156  function setOpacity(element, value) {
3157    element = $(element);
3158    if (value == 1 || value === '') value = '';
3159    else if (value < 0.00001) value = 0;
3160    element.style.opacity = value;
3161    return element;
3162  }
3163
3164  function setOpacity_IE(element, value) {
3165    if (STANDARD_CSS_OPACITY_SUPPORTED)
3166      return setOpacity(element, value);
3167
3168    element = hasLayout_IE($(element));
3169    var filter = Element.getStyle(element, 'filter'),
3170     style = element.style;
3171
3172    if (value == 1 || value === '') {
3173      filter = stripAlphaFromFilter_IE(filter);
3174      if (filter) style.filter = filter;
3175      else style.removeAttribute('filter');
3176      return element;
3177    }
3178
3179    if (value < 0.00001) value = 0;
3180
3181    style.filter = stripAlphaFromFilter_IE(filter) +
3182     ' alpha(opacity=' + (value * 100) + ')';
3183
3184    return element;
3185  }
3186
3187
3188  function getOpacity(element) {
3189    return Element.getStyle(element, 'opacity');
3190  }
3191
3192  function getOpacity_IE(element) {
3193    if (STANDARD_CSS_OPACITY_SUPPORTED)
3194      return getOpacity(element);
3195
3196    var filter = Element.getStyle(element, 'filter');
3197    if (filter.length === 0) return 1.0;
3198    var match = (filter || '').match(/alpha\(opacity=(.*)\)/i);
3199    if (match && match[1]) return parseFloat(match[1]) / 100;
3200    return 1.0;
3201  }
3202
3203
3204  Object.extend(methods, {
3205    setStyle:   setStyle,
3206    getStyle:   getStyle,
3207    setOpacity: setOpacity,
3208    getOpacity: getOpacity
3209  });
3210
3211  if ('styleFloat' in DIV.style) {
3212    methods.getStyle = getStyle_IE;
3213    methods.setOpacity = setOpacity_IE;
3214    methods.getOpacity = getOpacity_IE;
3215  }
3216
3217  var UID = 0;
3218
3219  GLOBAL.Element.Storage = { UID: 1 };
3220
3221  function getUniqueElementID(element) {
3222    if (element === window) return 0;
3223
3224    if (typeof element._prototypeUID === 'undefined')
3225      element._prototypeUID = Element.Storage.UID++;
3226    return element._prototypeUID;
3227  }
3228
3229  function getUniqueElementID_IE(element) {
3230    if (element === window) return 0;
3231    if (element == document) return 1;
3232    return element.uniqueID;
3233  }
3234
3235  var HAS_UNIQUE_ID_PROPERTY = ('uniqueID' in DIV);
3236  if (HAS_UNIQUE_ID_PROPERTY)
3237    getUniqueElementID = getUniqueElementID_IE;
3238
3239  function getStorage(element) {
3240    if (!(element = $(element))) return;
3241
3242    var uid = getUniqueElementID(element);
3243
3244    if (!Element.Storage[uid])
3245      Element.Storage[uid] = $H();
3246
3247    return Element.Storage[uid];
3248  }
3249
3250  function store(element, key, value) {
3251    if (!(element = $(element))) return;
3252    var storage = getStorage(element);
3253    if (arguments.length === 2) {
3254      storage.update(key);
3255    } else {
3256      storage.set(key, value);
3257    }
3258    return element;
3259  }
3260
3261  function retrieve(element, key, defaultValue) {
3262    if (!(element = $(element))) return;
3263    var storage = getStorage(element), value = storage.get(key);
3264
3265    if (Object.isUndefined(value)) {
3266      storage.set(key, defaultValue);
3267      value = defaultValue;
3268    }
3269
3270    return value;
3271  }
3272
3273
3274  Object.extend(methods, {
3275    getStorage: getStorage,
3276    store:      store,
3277    retrieve:   retrieve
3278  });
3279
3280
3281  var Methods = {}, ByTag = Element.Methods.ByTag,
3282   F = Prototype.BrowserFeatures;
3283
3284  if (!F.ElementExtensions && ('__proto__' in DIV)) {
3285    GLOBAL.HTMLElement = {};
3286    GLOBAL.HTMLElement.prototype = DIV['__proto__'];
3287    F.ElementExtensions = true;
3288  }
3289
3290  function checkElementPrototypeDeficiency(tagName) {
3291    if (typeof window.Element === 'undefined') return false;
3292    if (!HAS_EXTENDED_CREATE_ELEMENT_SYNTAX) return false;
3293    var proto = window.Element.prototype;
3294    if (proto) {
3295      var id = '_' + (Math.random() + '').slice(2),
3296       el = document.createElement(tagName);
3297      proto[id] = 'x';
3298      var isBuggy = (el[id] !== 'x');
3299      delete proto[id];
3300      el = null;
3301      return isBuggy;
3302    }
3303
3304    return false;
3305  }
3306
3307  var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY =
3308   checkElementPrototypeDeficiency('object');
3309
3310  function extendElementWith(element, methods) {
3311    for (var property in methods) {
3312      var value = methods[property];
3313      if (Object.isFunction(value) && !(property in element))
3314        element[property] = value.methodize();
3315    }
3316  }
3317
3318  var EXTENDED = {};
3319  function elementIsExtended(element) {
3320    var uid = getUniqueElementID(element);
3321    return (uid in EXTENDED);
3322  }
3323
3324  function extend(element) {
3325    if (!element || elementIsExtended(element)) return element;
3326    if (element.nodeType !== Node.ELEMENT_NODE || element == window)
3327      return element;
3328
3329    var methods = Object.clone(Methods),
3330     tagName = element.tagName.toUpperCase();
3331
3332    if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
3333
3334    extendElementWith(element, methods);
3335    EXTENDED[getUniqueElementID(element)] = true;
3336    return element;
3337  }
3338
3339  function extend_IE8(element) {
3340    if (!element || elementIsExtended(element)) return element;
3341
3342    var t = element.tagName;
3343    if (t && (/^(?:object|applet|embed)$/i.test(t))) {
3344      extendElementWith(element, Element.Methods);
3345      extendElementWith(element, Element.Methods.Simulated);
3346      extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
3347    }
3348
3349    return element;
3350  }
3351
3352  if (F.SpecificElementExtensions) {
3353    extend = HTMLOBJECTELEMENT_PROTOTYPE_BUGGY ? extend_IE8 : Prototype.K;
3354  }
3355
3356  function addMethodsToTagName(tagName, methods) {
3357    tagName = tagName.toUpperCase();
3358    if (!ByTag[tagName]) ByTag[tagName] = {};
3359    Object.extend(ByTag[tagName], methods);
3360  }
3361
3362  function mergeMethods(destination, methods, onlyIfAbsent) {
3363    if (Object.isUndefined(onlyIfAbsent)) onlyIfAbsent = false;
3364    for (var property in methods) {
3365      var value = methods[property];
3366      if (!Object.isFunction(value)) continue;
3367      if (!onlyIfAbsent || !(property in destination))
3368        destination[property] = value.methodize();
3369    }
3370  }
3371
3372  function findDOMClass(tagName) {
3373    var klass;
3374    var trans = {
3375      "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph",
3376      "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList",
3377      "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading",
3378      "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote",
3379      "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION":
3380      "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD":
3381      "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR":
3382      "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET":
3383      "FrameSet", "IFRAME": "IFrame"
3384    };
3385    if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element';
3386    if (window[klass]) return window[klass];
3387    klass = 'HTML' + tagName + 'Element';
3388    if (window[klass]) return window[klass];
3389    klass = 'HTML' + tagName.capitalize() + 'Element';
3390    if (window[klass]) return window[klass];
3391
3392    var element = document.createElement(tagName),
3393     proto = element['__proto__'] || element.constructor.prototype;
3394
3395    element = null;
3396    return proto;
3397  }
3398
3399  function addMethods(methods) {
3400    if (arguments.length === 0) addFormMethods();
3401
3402    if (arguments.length === 2) {
3403      var tagName = methods;
3404      methods = arguments[1];
3405    }
3406
3407    if (!tagName) {
3408      Object.extend(Element.Methods, methods || {});
3409    } else {
3410      if (Object.isArray(tagName)) {
3411        for (var i = 0, tag; tag = tagName[i]; i++)
3412          addMethodsToTagName(tag, methods);
3413      } else {
3414        addMethodsToTagName(tagName, methods);
3415      }
3416    }
3417
3418    var ELEMENT_PROTOTYPE = window.HTMLElement ? HTMLElement.prototype :
3419     Element.prototype;
3420
3421    if (F.ElementExtensions) {
3422      mergeMethods(ELEMENT_PROTOTYPE, Element.Methods);
3423      mergeMethods(ELEMENT_PROTOTYPE, Element.Methods.Simulated, true);
3424    }
3425
3426    if (F.SpecificElementExtensions) {
3427      for (var tag in Element.Methods.ByTag) {
3428        var klass = findDOMClass(tag);
3429        if (Object.isUndefined(klass)) continue;
3430        mergeMethods(klass.prototype, ByTag[tag]);
3431      }
3432    }
3433
3434    Object.extend(Element, Element.Methods);
3435    Object.extend(Element, Element.Methods.Simulated);
3436    delete Element.ByTag;
3437    delete Element.Simulated;
3438
3439    Element.extend.refresh();
3440
3441    ELEMENT_CACHE = {};
3442  }
3443
3444  Object.extend(GLOBAL.Element, {
3445    extend:     extend,
3446    addMethods: addMethods
3447  });
3448
3449  if (extend === Prototype.K) {
3450    GLOBAL.Element.extend.refresh = Prototype.emptyFunction;
3451  } else {
3452    GLOBAL.Element.extend.refresh = function() {
3453      if (Prototype.BrowserFeatures.ElementExtensions) return;
3454      Object.extend(Methods, Element.Methods);
3455      Object.extend(Methods, Element.Methods.Simulated);
3456
3457      EXTENDED = {};
3458    };
3459  }
3460
3461  function addFormMethods() {
3462    Object.extend(Form, Form.Methods);
3463    Object.extend(Form.Element, Form.Element.Methods);
3464    Object.extend(Element.Methods.ByTag, {
3465      "FORM":     Object.clone(Form.Methods),
3466      "INPUT":    Object.clone(Form.Element.Methods),
3467      "SELECT":   Object.clone(Form.Element.Methods),
3468      "TEXTAREA": Object.clone(Form.Element.Methods),
3469      "BUTTON":   Object.clone(Form.Element.Methods)
3470    });
3471  }
3472
3473  Element.addMethods(methods);
3474
3475  function destroyCache_IE() {
3476    DIV = null;
3477    ELEMENT_CACHE = null;
3478  }
3479
3480  if (window.attachEvent)
3481    window.attachEvent('onunload', destroyCache_IE);
3482
3483})(this);
3484(function() {
3485
3486  function toDecimal(pctString) {
3487    var match = pctString.match(/^(\d+)%?$/i);
3488    if (!match) return null;
3489    return (Number(match[1]) / 100);
3490  }
3491
3492  function getRawStyle(element, style) {
3493    element = $(element);
3494
3495    var value = element.style[style];
3496    if (!value || value === 'auto') {
3497      var css = document.defaultView.getComputedStyle(element, null);
3498      value = css ? css[style] : null;
3499    }
3500
3501    if (style === 'opacity') return value ? parseFloat(value) : 1.0;
3502    return value === 'auto' ? null : value;
3503  }
3504
3505  function getRawStyle_IE(element, style) {
3506    var value = element.style[style];
3507    if (!value && element.currentStyle) {
3508      value = element.currentStyle[style];
3509    }
3510    return value;
3511  }
3512
3513  function getContentWidth(element, context) {
3514    var boxWidth = element.offsetWidth;
3515
3516    var bl = getPixelValue(element, 'borderLeftWidth',  context) || 0;
3517    var br = getPixelValue(element, 'borderRightWidth', context) || 0;
3518    var pl = getPixelValue(element, 'paddingLeft',      context) || 0;
3519    var pr = getPixelValue(element, 'paddingRight',     context) || 0;
3520
3521    return boxWidth - bl - br - pl - pr;
3522  }
3523
3524  if (!Object.isUndefined(document.documentElement.currentStyle) && !Prototype.Browser.Opera) {
3525    getRawStyle = getRawStyle_IE;
3526  }
3527
3528
3529  function getPixelValue(value, property, context) {
3530    var element = null;
3531    if (Object.isElement(value)) {
3532      element = value;
3533      value = getRawStyle(element, property);
3534    }
3535
3536    if (value === null || Object.isUndefined(value)) {
3537      return null;
3538    }
3539
3540    if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) {
3541      return window.parseFloat(value);
3542    }
3543
3544    var isPercentage = value.include('%'), isViewport = (context === document.viewport);
3545
3546    if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) {
3547      var style = element.style.left, rStyle = element.runtimeStyle.left;
3548      element.runtimeStyle.left = element.currentStyle.left;
3549      element.style.left = value || 0;
3550      value = element.style.pixelLeft;
3551      element.style.left = style;
3552      element.runtimeStyle.left = rStyle;
3553
3554      return value;
3555    }
3556
3557    if (element && isPercentage) {
3558      context = context || element.parentNode;
3559      var decimal = toDecimal(value), whole = null;
3560
3561      var isHorizontal = property.include('left') || property.include('right') ||
3562       property.include('width');
3563
3564      var isVertical   = property.include('top') || property.include('bottom') ||
3565        property.include('height');
3566
3567      if (context === document.viewport) {
3568        if (isHorizontal) {
3569          whole = document.viewport.getWidth();
3570        } else if (isVertical) {
3571          whole = document.viewport.getHeight();
3572        }
3573      } else {
3574        if (isHorizontal) {
3575          whole = $(context).measure('width');
3576        } else if (isVertical) {
3577          whole = $(context).measure('height');
3578        }
3579      }
3580
3581      return (whole === null) ? 0 : whole * decimal;
3582    }
3583
3584    return 0;
3585  }
3586
3587  function toCSSPixels(number) {
3588    if (Object.isString(number) && number.endsWith('px'))
3589      return number;
3590    return number + 'px';
3591  }
3592
3593  function isDisplayed(element) {
3594    while (element && element.parentNode) {
3595      var display = element.getStyle('display');
3596      if (display === 'none') {
3597        return false;
3598      }
3599      element = $(element.parentNode);
3600    }
3601    return true;
3602  }
3603
3604  var hasLayout = Prototype.K;
3605  if ('currentStyle' in document.documentElement) {
3606    hasLayout = function(element) {
3607      if (!element.currentStyle.hasLayout) {
3608        element.style.zoom = 1;
3609      }
3610      return element;
3611    };
3612  }
3613
3614  function cssNameFor(key) {
3615    if (key.include('border')) key = key + '-width';
3616    return key.camelize();
3617  }
3618
3619  Element.Layout = Class.create(Hash, {
3620    initialize: function($super, element, preCompute) {
3621      $super();
3622      this.element = $(element);
3623
3624      Element.Layout.PROPERTIES.each( function(property) {
3625        this._set(property, null);
3626      }, this);
3627
3628      if (preCompute) {
3629        this._preComputing = true;
3630        this._begin();
3631        Element.Layout.PROPERTIES.each( this._compute, this );
3632        this._end();
3633        this._preComputing = false;
3634      }
3635    },
3636
3637    _set: function(property, value) {
3638      return Hash.prototype.set.call(this, property, value);
3639    },
3640
3641    set: function(property, value) {
3642      throw "Properties of Element.Layout are read-only.";
3643    },
3644
3645    get: function($super, property) {
3646      var value = $super(property);
3647      return value === null ? this._compute(property) : value;
3648    },
3649
3650    _begin: function() {
3651      if (this._isPrepared()) return;
3652
3653      var element = this.element;
3654      if (isDisplayed(element)) {
3655        this._setPrepared(true);
3656        return;
3657      }
3658
3659
3660      var originalStyles = {
3661        position:   element.style.position   || '',
3662        width:      element.style.width      || '',
3663        visibility: element.style.visibility || '',
3664        display:    element.style.display    || ''
3665      };
3666
3667      element.store('prototype_original_styles', originalStyles);
3668
3669      var position = getRawStyle(element, 'position'), width = element.offsetWidth;
3670
3671      if (width === 0 || width === null) {
3672        element.style.display = 'block';
3673        width = element.offsetWidth;
3674      }
3675
3676      var context = (position === 'fixed') ? document.viewport :
3677       element.parentNode;
3678
3679      var tempStyles = {
3680        visibility: 'hidden',
3681        display:    'block'
3682      };
3683
3684      if (position !== 'fixed') tempStyles.position = 'absolute';
3685
3686      element.setStyle(tempStyles);
3687
3688      var positionedWidth = element.offsetWidth, newWidth;
3689      if (width && (positionedWidth === width)) {
3690        newWidth = getContentWidth(element, context);
3691      } else if (position === 'absolute' || position === 'fixed') {
3692        newWidth = getContentWidth(element, context);
3693      } else {
3694        var parent = element.parentNode, pLayout = $(parent).getLayout();
3695
3696        newWidth = pLayout.get('width') -
3697         this.get('margin-left') -
3698         this.get('border-left') -
3699         this.get('padding-left') -
3700         this.get('padding-right') -
3701         this.get('border-right') -
3702         this.get('margin-right');
3703      }
3704
3705      element.setStyle({ width: newWidth + 'px' });
3706
3707      this._setPrepared(true);
3708    },
3709
3710    _end: function() {
3711      var element = this.element;
3712      var originalStyles = element.retrieve('prototype_original_styles');
3713      element.store('prototype_original_styles', null);
3714      element.setStyle(originalStyles);
3715      this._setPrepared(false);
3716    },
3717
3718    _compute: function(property) {
3719      var COMPUTATIONS = Element.Layout.COMPUTATIONS;
3720      if (!(property in COMPUTATIONS)) {
3721        throw "Property not found.";
3722      }
3723
3724      return this._set(property, COMPUTATIONS[property].call(this, this.element));
3725    },
3726
3727    _isPrepared: function() {
3728      return this.element.retrieve('prototype_element_layout_prepared', false);
3729    },
3730
3731    _setPrepared: function(bool) {
3732      return this.element.store('prototype_element_layout_prepared', bool);
3733    },
3734
3735    toObject: function() {
3736      var args = $A(arguments);
3737      var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3738       args.join(' ').split(' ');
3739      var obj = {};
3740      keys.each( function(key) {
3741        if (!Element.Layout.PROPERTIES.include(key)) return;
3742        var value = this.get(key);
3743        if (value != null) obj[key] = value;
3744      }, this);
3745      return obj;
3746    },
3747
3748    toHash: function() {
3749      var obj = this.toObject.apply(this, arguments);
3750      return new Hash(obj);
3751    },
3752
3753    toCSS: function() {
3754      var args = $A(arguments);
3755      var keys = (args.length === 0) ? Element.Layout.PROPERTIES :
3756       args.join(' ').split(' ');
3757      var css = {};
3758
3759      keys.each( function(key) {
3760        if (!Element.Layout.PROPERTIES.include(key)) return;
3761        if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return;
3762
3763        var value = this.get(key);
3764        if (value != null) css[cssNameFor(key)] = value + 'px';
3765      }, this);
3766      return css;
3767    },
3768
3769    inspect: function() {
3770      return "#<Element.Layout>";
3771    }
3772  });
3773
3774  Object.extend(Element.Layout, {
3775    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'),
3776
3777    COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'),
3778
3779    COMPUTATIONS: {
3780      'height': function(element) {
3781        if (!this._preComputing) this._begin();
3782
3783        var bHeight = this.get('border-box-height');
3784        if (bHeight <= 0) {
3785          if (!this._preComputing) this._end();
3786          return 0;
3787        }
3788
3789        var bTop = this.get('border-top'),
3790         bBottom = this.get('border-bottom');
3791
3792        var pTop = this.get('padding-top'),
3793         pBottom = this.get('padding-bottom');
3794
3795        if (!this._preComputing) this._end();
3796
3797        return bHeight - bTop - bBottom - pTop - pBottom;
3798      },
3799
3800      'width': function(element) {
3801        if (!this._preComputing) this._begin();
3802
3803        var bWidth = this.get('border-box-width');
3804        if (bWidth <= 0) {
3805          if (!this._preComputing) this._end();
3806          return 0;
3807        }
3808
3809        var bLeft = this.get('border-left'),
3810         bRight = this.get('border-right');
3811
3812        var pLeft = this.get('padding-left'),
3813         pRight = this.get('padding-right');
3814
3815        if (!this._preComputing) this._end();
3816        return bWidth - bLeft - bRight - pLeft - pRight;
3817      },
3818
3819      'padding-box-height': function(element) {
3820        var height = this.get('height'),
3821         pTop = this.get('padding-top'),
3822         pBottom = this.get('padding-bottom');
3823
3824        return height + pTop + pBottom;
3825      },
3826
3827      'padding-box-width': function(element) {
3828        var width = this.get('width'),
3829         pLeft = this.get('padding-left'),
3830         pRight = this.get('padding-right');
3831
3832        return width + pLeft + pRight;
3833      },
3834
3835      'border-box-height': function(element) {
3836        if (!this._preComputing) this._begin();
3837        var height = element.offsetHeight;
3838        if (!this._preComputing) this._end();
3839        return height;
3840      },
3841
3842      'border-box-width': function(element) {
3843        if (!this._preComputing) this._begin();
3844        var width = element.offsetWidth;
3845        if (!this._preComputing) this._end();
3846        return width;
3847      },
3848
3849      'margin-box-height': function(element) {
3850        var bHeight = this.get('border-box-height'),
3851         mTop = this.get('margin-top'),
3852         mBottom = this.get('margin-bottom');
3853
3854        if (bHeight <= 0) return 0;
3855
3856        return bHeight + mTop + mBottom;
3857      },
3858
3859      'margin-box-width': function(element) {
3860        var bWidth = this.get('border-box-width'),
3861         mLeft = this.get('margin-left'),
3862         mRight = this.get('margin-right');
3863
3864        if (bWidth <= 0) return 0;
3865
3866        return bWidth + mLeft + mRight;
3867      },
3868
3869      'top': function(element) {
3870        var offset = element.positionedOffset();
3871        return offset.top;
3872      },
3873
3874      'bottom': function(element) {
3875        var offset = element.positionedOffset(),
3876         parent = element.getOffsetParent(),
3877         pHeight = parent.measure('height');
3878
3879        var mHeight = this.get('border-box-height');
3880
3881        return pHeight - mHeight - offset.top;
3882      },
3883
3884      'left': function(element) {
3885        var offset = element.positionedOffset();
3886        return offset.left;
3887      },
3888
3889      'right': function(element) {
3890        var offset = element.positionedOffset(),
3891         parent = element.getOffsetParent(),
3892         pWidth = parent.measure('width');
3893
3894        var mWidth = this.get('border-box-width');
3895
3896        return pWidth - mWidth - offset.left;
3897      },
3898
3899      'padding-top': function(element) {
3900        return getPixelValue(element, 'paddingTop');
3901      },
3902
3903      'padding-bottom': function(element) {
3904        return getPixelValue(element, 'paddingBottom');
3905      },
3906
3907      'padding-left': function(element) {
3908        return getPixelValue(element, 'paddingLeft');
3909      },
3910
3911      'padding-right': function(element) {
3912        return getPixelValue(element, 'paddingRight');
3913      },
3914
3915      'border-top': function(element) {
3916        return getPixelValue(element, 'borderTopWidth');
3917      },
3918
3919      'border-bottom': function(element) {
3920        return getPixelValue(element, 'borderBottomWidth');
3921      },
3922
3923      'border-left': function(element) {
3924        return getPixelValue(element, 'borderLeftWidth');
3925      },
3926
3927      'border-right': function(element) {
3928        return getPixelValue(element, 'borderRightWidth');
3929      },
3930
3931      'margin-top': function(element) {
3932        return getPixelValue(element, 'marginTop');
3933      },
3934
3935      'margin-bottom': function(element) {
3936        return getPixelValue(element, 'marginBottom');
3937      },
3938
3939      'margin-left': function(element) {
3940        return getPixelValue(element, 'marginLeft');
3941      },
3942
3943      'margin-right': function(element) {
3944        return getPixelValue(element, 'marginRight');
3945      }
3946    }
3947  });
3948
3949  if ('getBoundingClientRect' in document.documentElement) {
3950    Object.extend(Element.Layout.COMPUTATIONS, {
3951      'right': function(element) {
3952        var parent = hasLayout(element.getOffsetParent());
3953        var rect = element.getBoundingClientRect(),
3954         pRect = parent.getBoundingClientRect();
3955
3956        return (pRect.right - rect.right).round();
3957      },
3958
3959      'bottom': function(element) {
3960        var parent = hasLayout(element.getOffsetParent());
3961        var rect = element.getBoundingClientRect(),
3962         pRect = parent.getBoundingClientRect();
3963
3964        return (pRect.bottom - rect.bottom).round();
3965      }
3966    });
3967  }
3968
3969  Element.Offset = Class.create({
3970    initialize: function(left, top) {
3971      this.left = left.round();
3972      this.top  = top.round();
3973
3974      this[0] = this.left;
3975      this[1] = this.top;
3976    },
3977
3978    relativeTo: function(offset) {
3979      return new Element.Offset(
3980        this.left - offset.left,
3981        this.top  - offset.top
3982      );
3983    },
3984
3985    inspect: function() {
3986      return "#<Element.Offset left: #{left} top: #{top}>".interpolate(this);
3987    },
3988
3989    toString: function() {
3990      return "[#{left}, #{top}]".interpolate(this);
3991    },
3992
3993    toArray: function() {
3994      return [this.left, this.top];
3995    }
3996  });
3997
3998  function getLayout(element, preCompute) {
3999    return new Element.Layout(element, preCompute);
4000  }
4001
4002  function measure(element, property) {
4003    return $(element).getLayout().get(property);
4004  }
4005
4006  function getHeight(element) {
4007    return Element.getDimensions(element).height;
4008  }
4009
4010  function getWidth(element) {
4011    return Element.getDimensions(element).width;
4012  }
4013
4014  function getDimensions(element) {
4015    element = $(element);
4016    var display = Element.getStyle(element, 'display');
4017
4018    if (display && display !== 'none') {
4019      return { width: element.offsetWidth, height: element.offsetHeight };
4020    }
4021
4022    var style = element.style;
4023    var originalStyles = {
4024      visibility: style.visibility,
4025      position:   style.position,
4026      display:    style.display
4027    };
4028
4029    var newStyles = {
4030      visibility: 'hidden',
4031      display:    'block'
4032    };
4033
4034    if (originalStyles.position !== 'fixed')
4035      newStyles.position = 'absolute';
4036
4037    Element.setStyle(element, newStyles);
4038
4039    var dimensions = {
4040      width:  element.offsetWidth,
4041      height: element.offsetHeight
4042    };
4043
4044    Element.setStyle(element, originalStyles);
4045
4046    return dimensions;
4047  }
4048
4049  function getOffsetParent(element) {
4050    element = $(element);
4051
4052    function selfOrBody(element) {
4053      return isHtml(element) ? $(document.body) : $(element);
4054    }
4055
4056    if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
4057      return $(document.body);
4058
4059    var isInline = (Element.getStyle(element, 'display') === 'inline');
4060    if (!isInline && element.offsetParent) return selfOrBody(element.offsetParent);
4061
4062    while ((element = element.parentNode) && element !== document.body) {
4063      if (Element.getStyle(element, 'position') !== 'static') {
4064        return selfOrBody(element);
4065      }
4066    }
4067
4068    return $(document.body);
4069  }
4070
4071
4072  function cumulativeOffset(element) {
4073    element = $(element);
4074    var valueT = 0, valueL = 0;
4075    if (element.parentNode) {
4076      do {
4077        valueT += element.offsetTop  || 0;
4078        valueL += element.offsetLeft || 0;
4079        element = element.offsetParent;
4080      } while (element);
4081    }
4082    return new Element.Offset(valueL, valueT);
4083  }
4084
4085  function positionedOffset(element) {
4086    element = $(element);
4087
4088    var layout = element.getLayout();
4089
4090    var valueT = 0, valueL = 0;
4091    do {
4092      valueT += element.offsetTop  || 0;
4093      valueL += element.offsetLeft || 0;
4094      element = element.offsetParent;
4095      if (element) {
4096        if (isBody(element)) break;
4097        var p = Element.getStyle(element, 'position');
4098        if (p !== 'static') break;
4099      }
4100    } while (element);
4101
4102    valueL -= layout.get('margin-left');
4103    valueT -= layout.get('margin-top');
4104
4105    return new Element.Offset(valueL, valueT);
4106  }
4107
4108  function cumulativeScrollOffset(element) {
4109    var valueT = 0, valueL = 0;
4110    do {
4111      if (element === document.body) {
4112        var bodyScrollNode = document.documentElement || document.body.parentNode || document.body;
4113        valueT += !Object.isUndefined(window.pageYOffset) ? window.pageYOffset : bodyScrollNode.scrollTop || 0;
4114        valueL += !Object.isUndefined(window.pageXOffset) ? window.pageXOffset : bodyScrollNode.scrollLeft || 0;
4115        break;
4116      } else {
4117        valueT += element.scrollTop  || 0;
4118        valueL += element.scrollLeft || 0;
4119        element = element.parentNode;
4120      }
4121    } while (element);
4122    return new Element.Offset(valueL, valueT);
4123  }
4124
4125  function viewportOffset(forElement) {
4126    var valueT = 0, valueL = 0, docBody = document.body;
4127
4128    forElement = $(forElement);
4129    var element = forElement;
4130    do {
4131      valueT += element.offsetTop  || 0;
4132      valueL += element.offsetLeft || 0;
4133      if (element.offsetParent == docBody &&
4134        Element.getStyle(element, 'position') == 'absolute') break;
4135    } while (element = element.offsetParent);
4136
4137    element = forElement;
4138    do {
4139      if (element != docBody) {
4140        valueT -= element.scrollTop  || 0;
4141        valueL -= element.scrollLeft || 0;
4142      }
4143    } while (element = element.parentNode);
4144    return new Element.Offset(valueL, valueT);
4145  }
4146
4147  function absolutize(element) {
4148    element = $(element);
4149
4150    if (Element.getStyle(element, 'position') === 'absolute') {
4151      return element;
4152    }
4153
4154    var offsetParent = getOffsetParent(element);
4155    var eOffset = element.viewportOffset(),
4156     pOffset = offsetParent.viewportOffset();
4157
4158    var offset = eOffset.relativeTo(pOffset);
4159    var layout = element.getLayout();
4160
4161    element.store('prototype_absolutize_original_styles', {
4162      position: element.getStyle('position'),
4163      left:     element.getStyle('left'),
4164      top:      element.getStyle('top'),
4165      width:    element.getStyle('width'),
4166      height:   element.getStyle('height')
4167    });
4168
4169    element.setStyle({
4170      position: 'absolute',
4171      top:    offset.top + 'px',
4172      left:   offset.left + 'px',
4173      width:  layout.get('width') + 'px',
4174      height: layout.get('height') + 'px'
4175    });
4176
4177    return element;
4178  }
4179
4180  function relativize(element) {
4181    element = $(element);
4182    if (Element.getStyle(element, 'position') === 'relative') {
4183      return element;
4184    }
4185
4186    var originalStyles =
4187     element.retrieve('prototype_absolutize_original_styles');
4188
4189    if (originalStyles) element.setStyle(originalStyles);
4190    return element;
4191  }
4192
4193
4194  function scrollTo(element) {
4195    element = $(element);
4196    var pos = Element.cumulativeOffset(element);
4197    window.scrollTo(pos.left, pos.top);
4198    return element;
4199  }
4200
4201
4202  function makePositioned(element) {
4203    element = $(element);
4204    var position = Element.getStyle(element, 'position'), styles = {};
4205    if (position === 'static' || !position) {
4206      styles.position = 'relative';
4207      if (Prototype.Browser.Opera) {
4208        styles.top  = 0;
4209        styles.left = 0;
4210      }
4211      Element.setStyle(element, styles);
4212      Element.store(element, 'prototype_made_positioned', true);
4213    }
4214    return element;
4215  }
4216
4217  function undoPositioned(element) {
4218    element = $(element);
4219    var storage = Element.getStorage(element),
4220     madePositioned = storage.get('prototype_made_positioned');
4221
4222    if (madePositioned) {
4223      storage.unset('prototype_made_positioned');
4224      Element.setStyle(element, {
4225        position: '',
4226        top:      '',
4227        bottom:   '',
4228        left:     '',
4229        right:    ''
4230      });
4231    }
4232    return element;
4233  }
4234
4235  function makeClipping(element) {
4236    element = $(element);
4237
4238    var storage = Element.getStorage(element),
4239     madeClipping = storage.get('prototype_made_clipping');
4240
4241    if (Object.isUndefined(madeClipping)) {
4242      var overflow = Element.getStyle(element, 'overflow');
4243      storage.set('prototype_made_clipping', overflow);
4244      if (overflow !== 'hidden')
4245        element.style.overflow = 'hidden';
4246    }
4247
4248    return element;
4249  }
4250
4251  function undoClipping(element) {
4252    element = $(element);
4253    var storage = Element.getStorage(element),
4254     overflow = storage.get('prototype_made_clipping');
4255
4256    if (!Object.isUndefined(overflow)) {
4257      storage.unset('prototype_made_clipping');
4258      element.style.overflow = overflow || '';
4259    }
4260
4261    return element;
4262  }
4263
4264  function clonePosition(element, source, options) {
4265    options = Object.extend({
4266      setLeft:    true,
4267      setTop:     true,
4268      setWidth:   true,
4269      setHeight:  true,
4270      offsetTop:  0,
4271      offsetLeft: 0
4272    }, options || {});
4273
4274    // Find page position of source.
4275    source  = $(source);
4276    element = $(element);
4277    var p, delta, layout, styles = {};
4278
4279    var isAbsolute = Element.getStyle(element, 'position') === 'absolute';
4280    var parent = Element.getOffsetParent(element);
4281
4282    if (options.setLeft || options.setTop) {
4283      // We start by measuring the source's viewport offset.
4284      p = Element.viewportOffset(source);
4285
4286      // If the element we're altering is `position: fixed`, that's all the
4287      // information we need: later we'll apply that offset to the `top` and
4288      // `left` properties directly.
4289      delta = [0, 0];
4290
4291      // But if it's `position: absolute`, we have to know where its offset
4292      // parent is positioned and take those measurements into account as
4293      // well.
4294      if (isAbsolute && parent !== document.body) {
4295        delta = Element.viewportOffset(parent);
4296      }
4297    }
4298
4299    function pageScrollXY() {
4300      var x = 0, y = 0;
4301      if (Object.isNumber(window.pageXOffset)) {
4302        // Modern browsers.
4303        x = window.pageXOffset;
4304        y = window.pageYOffset;
4305      } else if (document.body && (document.body.scrollLeft || document.body.scrollTop)) {
4306        x = document.body.scrollLeft;
4307        y = document.body.scrollTop;
4308      }
4309      return { x: x, y: y };
4310    }
4311
4312    // When the offset parent is the document body, we need to account for
4313    // scroll offsets when we set `top` and `left`. (Unless the element is
4314    // `position: fixed`; in that case we should always ignore scroll
4315    // position.)
4316    var pageXY = (isAbsolute && parent === document.body) ? pageScrollXY() : { x: 0, y: 0 };
4317
4318    // Set position.
4319    if (options.setLeft)
4320      styles.left = (p[0] + pageXY.x - delta[0] + options.offsetLeft) + 'px';
4321    if (options.setTop)
4322      styles.top  = (p[1] + pageXY.y - delta[1] + options.offsetTop)  + 'px';
4323
4324    if (options.setWidth || options.setHeight) {
4325      layout = Element.getLayout(source);
4326
4327      // Use content box when setting width/height. If padding/border are
4328      // different between source and target, that's for the user to fix;
4329      // there's no good option for us.
4330      if (options.setWidth) {
4331        styles.width = layout.get('width')  + 'px';
4332      }
4333      if (options.setHeight) {
4334        styles.height = layout.get('height') + 'px';
4335      }
4336    }
4337
4338    return Element.setStyle(element, styles);
4339  }
4340
4341
4342  if (Prototype.Browser.IE) {
4343    getOffsetParent = getOffsetParent.wrap(
4344      function(proceed, element) {
4345        element = $(element);
4346
4347        if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element))
4348          return $(document.body);
4349
4350        var position = element.getStyle('position');
4351        if (position !== 'static') return proceed(element);
4352
4353        element.setStyle({ position: 'relative' });
4354        var value = proceed(element);
4355        element.setStyle({ position: position });
4356        return value;
4357      }
4358    );
4359
4360    positionedOffset = positionedOffset.wrap(function(proceed, element) {
4361      element = $(element);
4362      if (!element.parentNode) return new Element.Offset(0, 0);
4363      var position = element.getStyle('position');
4364      if (position !== 'static') return proceed(element);
4365
4366      var offsetParent = element.getOffsetParent();
4367      if (offsetParent && offsetParent.getStyle('position') === 'fixed')
4368        hasLayout(offsetParent);
4369
4370      element.setStyle({ position: 'relative' });
4371      var value = proceed(element);
4372      element.setStyle({ position: position });
4373      return value;
4374    });
4375  } else if (Prototype.Browser.Webkit) {
4376    cumulativeOffset = function(element) {
4377      element = $(element);
4378      var valueT = 0, valueL = 0;
4379      do {
4380        valueT += element.offsetTop  || 0;
4381        valueL += element.offsetLeft || 0;
4382        if (element.offsetParent == document.body) {
4383          if (Element.getStyle(element, 'position') == 'absolute') break;
4384        }
4385
4386        element = element.offsetParent;
4387      } while (element);
4388
4389      return new Element.Offset(valueL, valueT);
4390    };
4391  }
4392
4393
4394  Element.addMethods({
4395    getLayout:              getLayout,
4396    measure:                measure,
4397    getWidth:               getWidth,
4398    getHeight:              getHeight,
4399    getDimensions:          getDimensions,
4400    getOffsetParent:        getOffsetParent,
4401    cumulativeOffset:       cumulativeOffset,
4402    positionedOffset:       positionedOffset,
4403    cumulativeScrollOffset: cumulativeScrollOffset,
4404    viewportOffset:         viewportOffset,
4405    absolutize:             absolutize,
4406    relativize:             relativize,
4407    scrollTo:               scrollTo,
4408    makePositioned:         makePositioned,
4409    undoPositioned:         undoPositioned,
4410    makeClipping:           makeClipping,
4411    undoClipping:           undoClipping,
4412    clonePosition:          clonePosition
4413  });
4414
4415  function isBody(element) {
4416    return element.nodeName.toUpperCase() === 'BODY';
4417  }
4418
4419  function isHtml(element) {
4420    return element.nodeName.toUpperCase() === 'HTML';
4421  }
4422
4423  function isDocument(element) {
4424    return element.nodeType === Node.DOCUMENT_NODE;
4425  }
4426
4427  function isDetached(element) {
4428    return element !== document.body &&
4429     !Element.descendantOf(element, document.body);
4430  }
4431
4432  if ('getBoundingClientRect' in document.documentElement) {
4433    Element.addMethods({
4434      viewportOffset: function(element) {
4435        element = $(element);
4436        if (isDetached(element)) return new Element.Offset(0, 0);
4437
4438        var rect = element.getBoundingClientRect(),
4439         docEl = document.documentElement;
4440        return new Element.Offset(rect.left - docEl.clientLeft,
4441         rect.top - docEl.clientTop);
4442      }
4443    });
4444  }
4445
4446
4447})();
4448
4449(function() {
4450
4451  var IS_OLD_OPERA = Prototype.Browser.Opera &&
4452   (window.parseFloat(window.opera.version()) < 9.5);
4453  var ROOT = null;
4454  function getRootElement() {
4455    if (ROOT) return ROOT;
4456    ROOT = IS_OLD_OPERA ? document.body : document.documentElement;
4457    return ROOT;
4458  }
4459
4460  function getDimensions() {
4461    return { width: this.getWidth(), height: this.getHeight() };
4462  }
4463
4464  function getWidth() {
4465    return getRootElement().clientWidth;
4466  }
4467
4468  function getHeight() {
4469    return getRootElement().clientHeight;
4470  }
4471
4472  function getScrollOffsets() {
4473    var x = window.pageXOffset || document.documentElement.scrollLeft ||
4474     document.body.scrollLeft;
4475    var y = window.pageYOffset || document.documentElement.scrollTop ||
4476     document.body.scrollTop;
4477
4478    return new Element.Offset(x, y);
4479  }
4480
4481  document.viewport = {
4482    getDimensions:    getDimensions,
4483    getWidth:         getWidth,
4484    getHeight:        getHeight,
4485    getScrollOffsets: getScrollOffsets
4486  };
4487
4488})();
4489window.$$ = function() {
4490  var expression = $A(arguments).join(', ');
4491  return Prototype.Selector.select(expression, document);
4492};
4493
4494Prototype.Selector = (function() {
4495
4496  function select() {
4497    throw new Error('Method "Prototype.Selector.select" must be defined.');
4498  }
4499
4500  function match() {
4501    throw new Error('Method "Prototype.Selector.match" must be defined.');
4502  }
4503
4504  function find(elements, expression, index) {
4505    index = index || 0;
4506    var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i;
4507
4508    for (i = 0; i < length; i++) {
4509      if (match(elements[i], expression) && index == matchIndex++) {
4510        return Element.extend(elements[i]);
4511      }
4512    }
4513  }
4514
4515  function extendElements(elements) {
4516    for (var i = 0, length = elements.length; i < length; i++) {
4517      Element.extend(elements[i]);
4518    }
4519    return elements;
4520  }
4521
4522
4523  var K = Prototype.K;
4524
4525  return {
4526    select: select,
4527    match: match,
4528    find: find,
4529    extendElements: (Element.extend === K) ? K : extendElements,
4530    extendElement: Element.extend
4531  };
4532})();
4533Prototype._original_property = window.Sizzle;
4534
4535;(function () {
4536  function fakeDefine(fn) {
4537    Prototype._actual_sizzle = fn();
4538  }
4539  fakeDefine.amd = true;
4540
4541  if (typeof define !== 'undefined' && define.amd) {
4542    Prototype._original_define = define;
4543    Prototype._actual_sizzle = null;
4544    window.define = fakeDefine;
4545  }
4546})();
4547
4548/*!
4549 * Sizzle CSS Selector Engine v1.10.18
4550 * http://sizzlejs.com/
4551 *
4552 * Copyright 2013 jQuery Foundation, Inc. and other contributors
4553 * Released under the MIT license
4554 * http://jquery.org/license
4555 *
4556 * Date: 2014-02-05
4557 */
4558(function( window ) {
4559
4560var i,
4561	support,
4562	Expr,
4563	getText,
4564	isXML,
4565	compile,
4566	select,
4567	outermostContext,
4568	sortInput,
4569	hasDuplicate,
4570
4571	setDocument,
4572	document,
4573	docElem,
4574	documentIsHTML,
4575	rbuggyQSA,
4576	rbuggyMatches,
4577	matches,
4578	contains,
4579
4580	expando = "sizzle" + -(new Date()),
4581	preferredDoc = window.document,
4582	dirruns = 0,
4583	done = 0,
4584	classCache = createCache(),
4585	tokenCache = createCache(),
4586	compilerCache = createCache(),
4587	sortOrder = function( a, b ) {
4588		if ( a === b ) {
4589			hasDuplicate = true;
4590		}
4591		return 0;
4592	},
4593
4594	strundefined = typeof undefined,
4595	MAX_NEGATIVE = 1 << 31,
4596
4597	hasOwn = ({}).hasOwnProperty,
4598	arr = [],
4599	pop = arr.pop,
4600	push_native = arr.push,
4601	push = arr.push,
4602	slice = arr.slice,
4603	indexOf = arr.indexOf || function( elem ) {
4604		var i = 0,
4605			len = this.length;
4606		for ( ; i < len; i++ ) {
4607			if ( this[i] === elem ) {
4608				return i;
4609			}
4610		}
4611		return -1;
4612	},
4613
4614	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
4615
4616
4617	whitespace = "[\\x20\\t\\r\\n\\f]",
4618	characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
4619
4620	identifier = characterEncoding.replace( "w", "w#" ),
4621
4622	attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace +
4623		"*(?:([*^$|!~]?=)" + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]",
4624
4625	pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)",
4626
4627	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
4628
4629	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
4630	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
4631
4632	rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
4633
4634	rpseudo = new RegExp( pseudos ),
4635	ridentifier = new RegExp( "^" + identifier + "$" ),
4636
4637	matchExpr = {
4638		"ID": new RegExp( "^#(" + characterEncoding + ")" ),
4639		"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
4640		"TAG": new RegExp( "^(" + cha
vendor: 39,187 bytes, lines 4640-6204
4640racterEncoding.replace( "w", "w*" ) + ")" ),
4641		"ATTR": new RegExp( "^" + attributes ),
4642		"PSEUDO": new RegExp( "^" + pseudos ),
4643		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
4644			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
4645			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
4646		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
4647		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
4648			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
4649	},
4650
4651	rinputs = /^(?:input|select|textarea|button)$/i,
4652	rheader = /^h\d$/i,
4653
4654	rnative = /^[^{]+\{\s*\[native \w/,
4655
4656	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
4657
4658	rsibling = /[+~]/,
4659	rescape = /'|\\/g,
4660
4661	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
4662	funescape = function( _, escaped, escapedWhitespace ) {
4663		var high = "0x" + escaped - 0x10000;
4664		return high !== high || escapedWhitespace ?
4665			escaped :
4666			high < 0 ?
4667				String.fromCharCode( high + 0x10000 ) :
4668				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
4669	};
4670
4671try {
4672	push.apply(
4673		(arr = slice.call( preferredDoc.childNodes )),
4674		preferredDoc.childNodes
4675	);
4676	arr[ preferredDoc.childNodes.length ].nodeType;
4677} catch ( e ) {
4678	push = { apply: arr.length ?
4679
4680		function( target, els ) {
4681			push_native.apply( target, slice.call(els) );
4682		} :
4683
4684		function( target, els ) {
4685			var j = target.length,
4686				i = 0;
4687			while ( (target[j++] = els[i++]) ) {}
4688			target.length = j - 1;
4689		}
4690	};
4691}
4692
4693function Sizzle( selector, context, results, seed ) {
4694	var match, elem, m, nodeType,
4695		i, groups, old, nid, newContext, newSelector;
4696
4697	if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
4698		setDocument( context );
4699	}
4700
4701	context = context || document;
4702	results = results || [];
4703
4704	if ( !selector || typeof selector !== "string" ) {
4705		return results;
4706	}
4707
4708	if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
4709		return [];
4710	}
4711
4712	if ( documentIsHTML && !seed ) {
4713
4714		if ( (match = rquickExpr.exec( selector )) ) {
4715			if ( (m = match[1]) ) {
4716				if ( nodeType === 9 ) {
4717					elem = context.getElementById( m );
4718					if ( elem && elem.parentNode ) {
4719						if ( elem.id === m ) {
4720							results.push( elem );
4721							return results;
4722						}
4723					} else {
4724						return results;
4725					}
4726				} else {
4727					if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
4728						contains( context, elem ) && elem.id === m ) {
4729						results.push( elem );
4730						return results;
4731					}
4732				}
4733
4734			} else if ( match[2] ) {
4735				push.apply( results, context.getElementsByTagName( selector ) );
4736				return results;
4737
4738			} else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
4739				push.apply( results, context.getElementsByClassName( m ) );
4740				return results;
4741			}
4742		}
4743
4744		if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
4745			nid = old = expando;
4746			newContext = context;
4747			newSelector = nodeType === 9 && selector;
4748
4749			if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
4750				groups = tokenize( selector );
4751
4752				if ( (old = context.getAttribute("id")) ) {
4753					nid = old.replace( rescape, "\\$&" );
4754				} else {
4755					context.setAttribute( "id", nid );
4756				}
4757				nid = "[id='" + nid + "'] ";
4758
4759				i = groups.length;
4760				while ( i-- ) {
4761					groups[i] = nid + toSelector( groups[i] );
4762				}
4763				newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
4764				newSelector = groups.join(",");
4765			}
4766
4767			if ( newSelector ) {
4768				try {
4769					push.apply( results,
4770						newContext.querySelectorAll( newSelector )
4771					);
4772					return results;
4773				} catch(qsaError) {
4774				} finally {
4775					if ( !old ) {
4776						context.removeAttribute("id");
4777					}
4778				}
4779			}
4780		}
4781	}
4782
4783	return select( selector.replace( rtrim, "$1" ), context, results, seed );
4784}
4785
4786/**
4787 * Create key-value caches of limited size
4788 * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
4789 *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
4790 *	deleting the oldest entry
4791 */
4792function createCache() {
4793	var keys = [];
4794
4795	function cache( key, value ) {
4796		if ( keys.push( key + " " ) > Expr.cacheLength ) {
4797			delete cache[ keys.shift() ];
4798		}
4799		return (cache[ key + " " ] = value);
4800	}
4801	return cache;
4802}
4803
4804/**
4805 * Mark a function for special use by Sizzle
4806 * @param {Function} fn The function to mark
4807 */
4808function markFunction( fn ) {
4809	fn[ expando ] = true;
4810	return fn;
4811}
4812
4813/**
4814 * Support testing using an element
4815 * @param {Function} fn Passed the created div and expects a boolean result
4816 */
4817function assert( fn ) {
4818	var div = document.createElement("div");
4819
4820	try {
4821		return !!fn( div );
4822	} catch (e) {
4823		return false;
4824	} finally {
4825		if ( div.parentNode ) {
4826			div.parentNode.removeChild( div );
4827		}
4828		div = null;
4829	}
4830}
4831
4832/**
4833 * Adds the same handler for all of the specified attrs
4834 * @param {String} attrs Pipe-separated list of attributes
4835 * @param {Function} handler The method that will be applied
4836 */
4837function addHandle( attrs, handler ) {
4838	var arr = attrs.split("|"),
4839		i = attrs.length;
4840
4841	while ( i-- ) {
4842		Expr.attrHandle[ arr[i] ] = handler;
4843	}
4844}
4845
4846/**
4847 * Checks document order of two siblings
4848 * @param {Element} a
4849 * @param {Element} b
4850 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
4851 */
4852function siblingCheck( a, b ) {
4853	var cur = b && a,
4854		diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
4855			( ~b.sourceIndex || MAX_NEGATIVE ) -
4856			( ~a.sourceIndex || MAX_NEGATIVE );
4857
4858	if ( diff ) {
4859		return diff;
4860	}
4861
4862	if ( cur ) {
4863		while ( (cur = cur.nextSibling) ) {
4864			if ( cur === b ) {
4865				return -1;
4866			}
4867		}
4868	}
4869
4870	return a ? 1 : -1;
4871}
4872
4873/**
4874 * Returns a function to use in pseudos for input types
4875 * @param {String} type
4876 */
4877function createInputPseudo( type ) {
4878	return function( elem ) {
4879		var name = elem.nodeName.toLowerCase();
4880		return name === "input" && elem.type === type;
4881	};
4882}
4883
4884/**
4885 * Returns a function to use in pseudos for buttons
4886 * @param {String} type
4887 */
4888function createButtonPseudo( type ) {
4889	return function( elem ) {
4890		var name = elem.nodeName.toLowerCase();
4891		return (name === "input" || name === "button") && elem.type === type;
4892	};
4893}
4894
4895/**
4896 * Returns a function to use in pseudos for positionals
4897 * @param {Function} fn
4898 */
4899function createPositionalPseudo( fn ) {
4900	return markFunction(function( argument ) {
4901		argument = +argument;
4902		return markFunction(function( seed, matches ) {
4903			var j,
4904				matchIndexes = fn( [], seed.length, argument ),
4905				i = matchIndexes.length;
4906
4907			while ( i-- ) {
4908				if ( seed[ (j = matchIndexes[i]) ] ) {
4909					seed[j] = !(matches[j] = seed[j]);
4910				}
4911			}
4912		});
4913	});
4914}
4915
4916/**
4917 * Checks a node for validity as a Sizzle context
4918 * @param {Element|Object=} context
4919 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
4920 */
4921function testContext( context ) {
4922	return context && typeof context.getElementsByTagName !== strundefined && context;
4923}
4924
4925support = Sizzle.support = {};
4926
4927/**
4928 * Detects XML nodes
4929 * @param {Element|Object} elem An element or a document
4930 * @returns {Boolean} True iff elem is a non-HTML XML node
4931 */
4932isXML = Sizzle.isXML = function( elem ) {
4933	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
4934	return documentElement ? documentElement.nodeName !== "HTML" : false;
4935};
4936
4937/**
4938 * Sets document-related variables once based on the current document
4939 * @param {Element|Object} [doc] An element or document object to use to set the document
4940 * @returns {Object} Returns the current document
4941 */
4942setDocument = Sizzle.setDocument = function( node ) {
4943	var hasCompare,
4944		doc = node ? node.ownerDocument || node : preferredDoc,
4945		parent = doc.defaultView;
4946
4947	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
4948		return document;
4949	}
4950
4951	document = doc;
4952	docElem = doc.documentElement;
4953
4954	documentIsHTML = !isXML( doc );
4955
4956	if ( parent && parent !== parent.top ) {
4957		if ( parent.addEventListener ) {
4958			parent.addEventListener( "unload", function() {
4959				setDocument();
4960			}, false );
4961		} else if ( parent.attachEvent ) {
4962			parent.attachEvent( "onunload", function() {
4963				setDocument();
4964			});
4965		}
4966	}
4967
4968	/* Attributes
4969	---------------------------------------------------------------------- */
4970
4971	support.attributes = assert(function( div ) {
4972		div.className = "i";
4973		return !div.getAttribute("className");
4974	});
4975
4976	/* getElement(s)By*
4977	---------------------------------------------------------------------- */
4978
4979	support.getElementsByTagName = assert(function( div ) {
4980		div.appendChild( doc.createComment("") );
4981		return !div.getElementsByTagName("*").length;
4982	});
4983
4984	support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
4985		div.innerHTML = "<div class='a'></div><div class='a i'></div>";
4986
4987		div.firstChild.className = "i";
4988		return div.getElementsByClassName("i").length === 2;
4989	});
4990
4991	support.getById = assert(function( div ) {
4992		docElem.appendChild( div ).id = expando;
4993		return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
4994	});
4995
4996	if ( support.getById ) {
4997		Expr.find["ID"] = function( id, context ) {
4998			if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
4999				var m = context.getElementById( id );
5000				return m && m.parentNode ? [m] : [];
5001			}
5002		};
5003		Expr.filter["ID"] = function( id ) {
5004			var attrId = id.replace( runescape, funescape );
5005			return function( elem ) {
5006				return elem.getAttribute("id") === attrId;
5007			};
5008		};
5009	} else {
5010		delete Expr.find["ID"];
5011
5012		Expr.filter["ID"] =  function( id ) {
5013			var attrId = id.replace( runescape, funescape );
5014			return function( elem ) {
5015				var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
5016				return node && node.value === attrId;
5017			};
5018		};
5019	}
5020
5021	Expr.find["TAG"] = support.getElementsByTagName ?
5022		function( tag, context ) {
5023			if ( typeof context.getElementsByTagName !== strundefined ) {
5024				return context.getElementsByTagName( tag );
5025			}
5026		} :
5027		function( tag, context ) {
5028			var elem,
5029				tmp = [],
5030				i = 0,
5031				results = context.getElementsByTagName( tag );
5032
5033			if ( tag === "*" ) {
5034				while ( (elem = results[i++]) ) {
5035					if ( elem.nodeType === 1 ) {
5036						tmp.push( elem );
5037					}
5038				}
5039
5040				return tmp;
5041			}
5042			return results;
5043		};
5044
5045	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
5046		if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
5047			return context.getElementsByClassName( className );
5048		}
5049	};
5050
5051	/* QSA/matchesSelector
5052	---------------------------------------------------------------------- */
5053
5054
5055	rbuggyMatches = [];
5056
5057	rbuggyQSA = [];
5058
5059	if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
5060		assert(function( div ) {
5061			div.innerHTML = "<select t=''><option selected=''></option></select>";
5062
5063			if ( div.querySelectorAll("[t^='']").length ) {
5064				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
5065			}
5066
5067			if ( !div.querySelectorAll("[selected]").length ) {
5068				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
5069			}
5070
5071			if ( !div.querySelectorAll(":checked").length ) {
5072				rbuggyQSA.push(":checked");
5073			}
5074		});
5075
5076		assert(function( div ) {
5077			var input = doc.createElement("input");
5078			input.setAttribute( "type", "hidden" );
5079			div.appendChild( input ).setAttribute( "name", "D" );
5080
5081			if ( div.querySelectorAll("[name=d]").length ) {
5082				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
5083			}
5084
5085			if ( !div.querySelectorAll(":enabled").length ) {
5086				rbuggyQSA.push( ":enabled", ":disabled" );
5087			}
5088
5089			div.querySelectorAll("*,:x");
5090			rbuggyQSA.push(",.*:");
5091		});
5092	}
5093
5094	if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
5095		docElem.mozMatchesSelector ||
5096		docElem.oMatchesSelector ||
5097		docElem.msMatchesSelector) )) ) {
5098
5099		assert(function( div ) {
5100			support.disconnectedMatch = matches.call( div, "div" );
5101
5102			matches.call( div, "[s!='']:x" );
5103			rbuggyMatches.push( "!=", pseudos );
5104		});
5105	}
5106
5107	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
5108	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
5109
5110	/* Contains
5111	---------------------------------------------------------------------- */
5112	hasCompare = rnative.test( docElem.compareDocumentPosition );
5113
5114	contains = hasCompare || rnative.test( docElem.contains ) ?
5115		function( a, b ) {
5116			var adown = a.nodeType === 9 ? a.documentElement : a,
5117				bup = b && b.parentNode;
5118			return a === bup || !!( bup && bup.nodeType === 1 && (
5119				adown.contains ?
5120					adown.contains( bup ) :
5121					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
5122			));
5123		} :
5124		function( a, b ) {
5125			if ( b ) {
5126				while ( (b = b.parentNode) ) {
5127					if ( b === a ) {
5128						return true;
5129					}
5130				}
5131			}
5132			return false;
5133		};
5134
5135	/* Sorting
5136	---------------------------------------------------------------------- */
5137
5138	sortOrder = hasCompare ?
5139	function( a, b ) {
5140
5141		if ( a === b ) {
5142			hasDuplicate = true;
5143			return 0;
5144		}
5145
5146		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
5147		if ( compare ) {
5148			return compare;
5149		}
5150
5151		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
5152			a.compareDocumentPosition( b ) :
5153
5154			1;
5155
5156		if ( compare & 1 ||
5157			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
5158
5159			if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
5160				return -1;
5161			}
5162			if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
5163				return 1;
5164			}
5165
5166			return sortInput ?
5167				( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5168				0;
5169		}
5170
5171		return compare & 4 ? -1 : 1;
5172	} :
5173	function( a, b ) {
5174		if ( a === b ) {
5175			hasDuplicate = true;
5176			return 0;
5177		}
5178
5179		var cur,
5180			i = 0,
5181			aup = a.parentNode,
5182			bup = b.parentNode,
5183			ap = [ a ],
5184			bp = [ b ];
5185
5186		if ( !aup || !bup ) {
5187			return a === doc ? -1 :
5188				b === doc ? 1 :
5189				aup ? -1 :
5190				bup ? 1 :
5191				sortInput ?
5192				( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
5193				0;
5194
5195		} else if ( aup === bup ) {
5196			return siblingCheck( a, b );
5197		}
5198
5199		cur = a;
5200		while ( (cur = cur.parentNode) ) {
5201			ap.unshift( cur );
5202		}
5203		cur = b;
5204		while ( (cur = cur.parentNode) ) {
5205			bp.unshift( cur );
5206		}
5207
5208		while ( ap[i] === bp[i] ) {
5209			i++;
5210		}
5211
5212		return i ?
5213			siblingCheck( ap[i], bp[i] ) :
5214
5215			ap[i] === preferredDoc ? -1 :
5216			bp[i] === preferredDoc ? 1 :
5217			0;
5218	};
5219
5220	return doc;
5221};
5222
5223Sizzle.matches = function( expr, elements ) {
5224	return Sizzle( expr, null, null, elements );
5225};
5226
5227Sizzle.matchesSelector = function( elem, expr ) {
5228	if ( ( elem.ownerDocument || elem ) !== document ) {
5229		setDocument( elem );
5230	}
5231
5232	expr = expr.replace( rattributeQuotes, "='$1']" );
5233
5234	if ( support.matchesSelector && documentIsHTML &&
5235		( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
5236		( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
5237
5238		try {
5239			var ret = matches.call( elem, expr );
5240
5241			if ( ret || support.disconnectedMatch ||
5242					elem.document && elem.document.nodeType !== 11 ) {
5243				return ret;
5244			}
5245		} catch(e) {}
5246	}
5247
5248	return Sizzle( expr, document, null, [elem] ).length > 0;
5249};
5250
5251Sizzle.contains = function( context, elem ) {
5252	if ( ( context.ownerDocument || context ) !== document ) {
5253		setDocument( context );
5254	}
5255	return contains( context, elem );
5256};
5257
5258Sizzle.attr = function( elem, name ) {
5259	if ( ( elem.ownerDocument || elem ) !== document ) {
5260		setDocument( elem );
5261	}
5262
5263	var fn = Expr.attrHandle[ name.toLowerCase() ],
5264		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
5265			fn( elem, name, !documentIsHTML ) :
5266			undefined;
5267
5268	return val !== undefined ?
5269		val :
5270		support.attributes || !documentIsHTML ?
5271			elem.getAttribute( name ) :
5272			(val = elem.getAttributeNode(name)) && val.specified ?
5273				val.value :
5274				null;
5275};
5276
5277Sizzle.error = function( msg ) {
5278	throw new Error( "Syntax error, unrecognized expression: " + msg );
5279};
5280
5281/**
5282 * Document sorting and removing duplicates
5283 * @param {ArrayLike} results
5284 */
5285Sizzle.uniqueSort = function( results ) {
5286	var elem,
5287		duplicates = [],
5288		j = 0,
5289		i = 0;
5290
5291	hasDuplicate = !support.detectDuplicates;
5292	sortInput = !support.sortStable && results.slice( 0 );
5293	results.sort( sortOrder );
5294
5295	if ( hasDuplicate ) {
5296		while ( (elem = results[i++]) ) {
5297			if ( elem === results[ i ] ) {
5298				j = duplicates.push( i );
5299			}
5300		}
5301		while ( j-- ) {
5302			results.splice( duplicates[ j ], 1 );
5303		}
5304	}
5305
5306	sortInput = null;
5307
5308	return results;
5309};
5310
5311/**
5312 * Utility function for retrieving the text value of an array of DOM nodes
5313 * @param {Array|Element} elem
5314 */
5315getText = Sizzle.getText = function( elem ) {
5316	var node,
5317		ret = "",
5318		i = 0,
5319		nodeType = elem.nodeType;
5320
5321	if ( !nodeType ) {
5322		while ( (node = elem[i++]) ) {
5323			ret += getText( node );
5324		}
5325	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
5326		if ( typeof elem.textContent === "string" ) {
5327			return elem.textContent;
5328		} else {
5329			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5330				ret += getText( elem );
5331			}
5332		}
5333	} else if ( nodeType === 3 || nodeType === 4 ) {
5334		return elem.nodeValue;
5335	}
5336
5337	return ret;
5338};
5339
5340Expr = Sizzle.selectors = {
5341
5342	cacheLength: 50,
5343
5344	createPseudo: markFunction,
5345
5346	match: matchExpr,
5347
5348	attrHandle: {},
5349
5350	find: {},
5351
5352	relative: {
5353		">": { dir: "parentNode", first: true },
5354		" ": { dir: "parentNode" },
5355		"+": { dir: "previousSibling", first: true },
5356		"~": { dir: "previousSibling" }
5357	},
5358
5359	preFilter: {
5360		"ATTR": function( match ) {
5361			match[1] = match[1].replace( runescape, funescape );
5362
5363			match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape );
5364
5365			if ( match[2] === "~=" ) {
5366				match[3] = " " + match[3] + " ";
5367			}
5368
5369			return match.slice( 0, 4 );
5370		},
5371
5372		"CHILD": function( match ) {
5373			/* matches from matchExpr["CHILD"]
5374				1 type (only|nth|...)
5375				2 what (child|of-type)
5376				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
5377				4 xn-component of xn+y argument ([+-]?\d*n|)
5378				5 sign of xn-component
5379				6 x of xn-component
5380				7 sign of y-component
5381				8 y of y-component
5382			*/
5383			match[1] = match[1].toLowerCase();
5384
5385			if ( match[1].slice( 0, 3 ) === "nth" ) {
5386				if ( !match[3] ) {
5387					Sizzle.error( match[0] );
5388				}
5389
5390				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
5391				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
5392
5393			} else if ( match[3] ) {
5394				Sizzle.error( match[0] );
5395			}
5396
5397			return match;
5398		},
5399
5400		"PSEUDO": function( match ) {
5401			var excess,
5402				unquoted = !match[5] && match[2];
5403
5404			if ( matchExpr["CHILD"].test( match[0] ) ) {
5405				return null;
5406			}
5407
5408			if ( match[3] && match[4] !== undefined ) {
5409				match[2] = match[4];
5410
5411			} else if ( unquoted && rpseudo.test( unquoted ) &&
5412				(excess = tokenize( unquoted, true )) &&
5413				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
5414
5415				match[0] = match[0].slice( 0, excess );
5416				match[2] = unquoted.slice( 0, excess );
5417			}
5418
5419			return match.slice( 0, 3 );
5420		}
5421	},
5422
5423	filter: {
5424
5425		"TAG": function( nodeNameSelector ) {
5426			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
5427			return nodeNameSelector === "*" ?
5428				function() { return true; } :
5429				function( elem ) {
5430					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
5431				};
5432		},
5433
5434		"CLASS": function( className ) {
5435			var pattern = classCache[ className + " " ];
5436
5437			return pattern ||
5438				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
5439				classCache( className, function( elem ) {
5440					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
5441				});
5442		},
5443
5444		"ATTR": function( name, operator, check ) {
5445			return function( elem ) {
5446				var result = Sizzle.attr( elem, name );
5447
5448				if ( result == null ) {
5449					return operator === "!=";
5450				}
5451				if ( !operator ) {
5452					return true;
5453				}
5454
5455				result += "";
5456
5457				return operator === "=" ? result === check :
5458					operator === "!=" ? result !== check :
5459					operator === "^=" ? check && result.indexOf( check ) === 0 :
5460					operator === "*=" ? check && result.indexOf( check ) > -1 :
5461					operator === "$=" ? check && result.slice( -check.length ) === check :
5462					operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
5463					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
5464					false;
5465			};
5466		},
5467
5468		"CHILD": function( type, what, argument, first, last ) {
5469			var simple = type.slice( 0, 3 ) !== "nth",
5470				forward = type.slice( -4 ) !== "last",
5471				ofType = what === "of-type";
5472
5473			return first === 1 && last === 0 ?
5474
5475				function( elem ) {
5476					return !!elem.parentNode;
5477				} :
5478
5479				function( elem, context, xml ) {
5480					var cache, outerCache, node, diff, nodeIndex, start,
5481						dir = simple !== forward ? "nextSibling" : "previousSibling",
5482						parent = elem.parentNode,
5483						name = ofType && elem.nodeName.toLowerCase(),
5484						useCache = !xml && !ofType;
5485
5486					if ( parent ) {
5487
5488						if ( simple ) {
5489							while ( dir ) {
5490								node = elem;
5491								while ( (node = node[ dir ]) ) {
5492									if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
5493										return false;
5494									}
5495								}
5496								start = dir = type === "only" && !start && "nextSibling";
5497							}
5498							return true;
5499						}
5500
5501						start = [ forward ? parent.firstChild : parent.lastChild ];
5502
5503						if ( forward && useCache ) {
5504							outerCache = parent[ expando ] || (parent[ expando ] = {});
5505							cache = outerCache[ type ] || [];
5506							nodeIndex = cache[0] === dirruns && cache[1];
5507							diff = cache[0] === dirruns && cache[2];
5508							node = nodeIndex && parent.childNodes[ nodeIndex ];
5509
5510							while ( (node = ++nodeIndex && node && node[ dir ] ||
5511
5512								(diff = nodeIndex = 0) || start.pop()) ) {
5513
5514								if ( node.nodeType === 1 && ++diff && node === elem ) {
5515									outerCache[ type ] = [ dirruns, nodeIndex, diff ];
5516									break;
5517								}
5518							}
5519
5520						} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
5521							diff = cache[1];
5522
5523						} else {
5524							while ( (node = ++nodeIndex && node && node[ dir ] ||
5525								(diff = nodeIndex = 0) || start.pop()) ) {
5526
5527								if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
5528									if ( useCache ) {
5529										(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
5530									}
5531
5532									if ( node === elem ) {
5533										break;
5534									}
5535								}
5536							}
5537						}
5538
5539						diff -= last;
5540						return diff === first || ( diff % first === 0 && diff / first >= 0 );
5541					}
5542				};
5543		},
5544
5545		"PSEUDO": function( pseudo, argument ) {
5546			var args,
5547				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
5548					Sizzle.error( "unsupported pseudo: " + pseudo );
5549
5550			if ( fn[ expando ] ) {
5551				return fn( argument );
5552			}
5553
5554			if ( fn.length > 1 ) {
5555				args = [ pseudo, pseudo, "", argument ];
5556				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
5557					markFunction(function( seed, matches ) {
5558						var idx,
5559							matched = fn( seed, argument ),
5560							i = matched.length;
5561						while ( i-- ) {
5562							idx = indexOf.call( seed, matched[i] );
5563							seed[ idx ] = !( matches[ idx ] = matched[i] );
5564						}
5565					}) :
5566					function( elem ) {
5567						return fn( elem, 0, args );
5568					};
5569			}
5570
5571			return fn;
5572		}
5573	},
5574
5575	pseudos: {
5576		"not": markFunction(function( selector ) {
5577			var input = [],
5578				results = [],
5579				matcher = compile( selector.replace( rtrim, "$1" ) );
5580
5581			return matcher[ expando ] ?
5582				markFunction(function( seed, matches, context, xml ) {
5583					var elem,
5584						unmatched = matcher( seed, null, xml, [] ),
5585						i = seed.length;
5586
5587					while ( i-- ) {
5588						if ( (elem = unmatched[i]) ) {
5589							seed[i] = !(matches[i] = elem);
5590						}
5591					}
5592				}) :
5593				function( elem, context, xml ) {
5594					input[0] = elem;
5595					matcher( input, null, xml, results );
5596					return !results.pop();
5597				};
5598		}),
5599
5600		"has": markFunction(function( selector ) {
5601			return function( elem ) {
5602				return Sizzle( selector, elem ).length > 0;
5603			};
5604		}),
5605
5606		"contains": markFunction(function( text ) {
5607			return function( elem ) {
5608				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
5609			};
5610		}),
5611
5612		"lang": markFunction( function( lang ) {
5613			if ( !ridentifier.test(lang || "") ) {
5614				Sizzle.error( "unsupported lang: " + lang );
5615			}
5616			lang = lang.replace( runescape, funescape ).toLowerCase();
5617			return function( elem ) {
5618				var elemLang;
5619				do {
5620					if ( (elemLang = documentIsHTML ?
5621						elem.lang :
5622						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
5623
5624						elemLang = elemLang.toLowerCase();
5625						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
5626					}
5627				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
5628				return false;
5629			};
5630		}),
5631
5632		"target": function( elem ) {
5633			var hash = window.location && window.location.hash;
5634			return hash && hash.slice( 1 ) === elem.id;
5635		},
5636
5637		"root": function( elem ) {
5638			return elem === docElem;
5639		},
5640
5641		"focus": function( elem ) {
5642			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
5643		},
5644
5645		"enabled": function( elem ) {
5646			return elem.disabled === false;
5647		},
5648
5649		"disabled": function( elem ) {
5650			return elem.disabled === true;
5651		},
5652
5653		"checked": function( elem ) {
5654			var nodeName = elem.nodeName.toLowerCase();
5655			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
5656		},
5657
5658		"selected": function( elem ) {
5659			if ( elem.parentNode ) {
5660				elem.parentNode.selectedIndex;
5661			}
5662
5663			return elem.selected === true;
5664		},
5665
5666		"empty": function( elem ) {
5667			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
5668				if ( elem.nodeType < 6 ) {
5669					return false;
5670				}
5671			}
5672			return true;
5673		},
5674
5675		"parent": function( elem ) {
5676			return !Expr.pseudos["empty"]( elem );
5677		},
5678
5679		"header": function( elem ) {
5680			return rheader.test( elem.nodeName );
5681		},
5682
5683		"input": function( elem ) {
5684			return rinputs.test( elem.nodeName );
5685		},
5686
5687		"button": function( elem ) {
5688			var name = elem.nodeName.toLowerCase();
5689			return name === "input" && elem.type === "button" || name === "button";
5690		},
5691
5692		"text": function( elem ) {
5693			var attr;
5694			return elem.nodeName.toLowerCase() === "input" &&
5695				elem.type === "text" &&
5696
5697				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
5698		},
5699
5700		"first": createPositionalPseudo(function() {
5701			return [ 0 ];
5702		}),
5703
5704		"last": createPositionalPseudo(function( matchIndexes, length ) {
5705			return [ length - 1 ];
5706		}),
5707
5708		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
5709			return [ argument < 0 ? argument + length : argument ];
5710		}),
5711
5712		"even": createPositionalPseudo(function( matchIndexes, length ) {
5713			var i = 0;
5714			for ( ; i < length; i += 2 ) {
5715				matchIndexes.push( i );
5716			}
5717			return matchIndexes;
5718		}),
5719
5720		"odd": createPositionalPseudo(function( matchIndexes, length ) {
5721			var i = 1;
5722			for ( ; i < length; i += 2 ) {
5723				matchIndexes.push( i );
5724			}
5725			return matchIndexes;
5726		}),
5727
5728		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5729			var i = argument < 0 ? argument + length : argument;
5730			for ( ; --i >= 0; ) {
5731				matchIndexes.push( i );
5732			}
5733			return matchIndexes;
5734		}),
5735
5736		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
5737			var i = argument < 0 ? argument + length : argument;
5738			for ( ; ++i < length; ) {
5739				matchIndexes.push( i );
5740			}
5741			return matchIndexes;
5742		})
5743	}
5744};
5745
5746Expr.pseudos["nth"] = Expr.pseudos["eq"];
5747
5748for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
5749	Expr.pseudos[ i ] = createInputPseudo( i );
5750}
5751for ( i in { submit: true, reset: true } ) {
5752	Expr.pseudos[ i ] = createButtonPseudo( i );
5753}
5754
5755function setFilters() {}
5756setFilters.prototype = Expr.filters = Expr.pseudos;
5757Expr.setFilters = new setFilters();
5758
5759function tokenize( selector, parseOnly ) {
5760	var matched, match, tokens, type,
5761		soFar, groups, preFilters,
5762		cached = tokenCache[ selector + " " ];
5763
5764	if ( cached ) {
5765		return parseOnly ? 0 : cached.slice( 0 );
5766	}
5767
5768	soFar = selector;
5769	groups = [];
5770	preFilters = Expr.preFilter;
5771
5772	while ( soFar ) {
5773
5774		if ( !matched || (match = rcomma.exec( soFar )) ) {
5775			if ( match ) {
5776				soFar = soFar.slice( match[0].length ) || soFar;
5777			}
5778			groups.push( (tokens = []) );
5779		}
5780
5781		matched = false;
5782
5783		if ( (match = rcombinators.exec( soFar )) ) {
5784			matched = match.shift();
5785			tokens.push({
5786				value: matched,
5787				type: match[0].replace( rtrim, " " )
5788			});
5789			soFar = soFar.slice( matched.length );
5790		}
5791
5792		for ( type in Expr.filter ) {
5793			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
5794				(match = preFilters[ type ]( match ))) ) {
5795				matched = match.shift();
5796				tokens.push({
5797					value: matched,
5798					type: type,
5799					matches: match
5800				});
5801				soFar = soFar.slice( matched.length );
5802			}
5803		}
5804
5805		if ( !matched ) {
5806			break;
5807		}
5808	}
5809
5810	return parseOnly ?
5811		soFar.length :
5812		soFar ?
5813			Sizzle.error( selector ) :
5814			tokenCache( selector, groups ).slice( 0 );
5815}
5816
5817function toSelector( tokens ) {
5818	var i = 0,
5819		len = tokens.length,
5820		selector = "";
5821	for ( ; i < len; i++ ) {
5822		selector += tokens[i].value;
5823	}
5824	return selector;
5825}
5826
5827function addCombinator( matcher, combinator, base ) {
5828	var dir = combinator.dir,
5829		checkNonElements = base && dir === "parentNode",
5830		doneName = done++;
5831
5832	return combinator.first ?
5833		function( elem, context, xml ) {
5834			while ( (elem = elem[ dir ]) ) {
5835				if ( elem.nodeType === 1 || checkNonElements ) {
5836					return matcher( elem, context, xml );
5837				}
5838			}
5839		} :
5840
5841		function( elem, context, xml ) {
5842			var oldCache, outerCache,
5843				newCache = [ dirruns, doneName ];
5844
5845			if ( xml ) {
5846				while ( (elem = elem[ dir ]) ) {
5847					if ( elem.nodeType === 1 || checkNonElements ) {
5848						if ( matcher( elem, context, xml ) ) {
5849							return true;
5850						}
5851					}
5852				}
5853			} else {
5854				while ( (elem = elem[ dir ]) ) {
5855					if ( elem.nodeType === 1 || checkNonElements ) {
5856						outerCache = elem[ expando ] || (elem[ expando ] = {});
5857						if ( (oldCache = outerCache[ dir ]) &&
5858							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
5859
5860							return (newCache[ 2 ] = oldCache[ 2 ]);
5861						} else {
5862							outerCache[ dir ] = newCache;
5863
5864							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
5865								return true;
5866							}
5867						}
5868					}
5869				}
5870			}
5871		};
5872}
5873
5874function elementMatcher( matchers ) {
5875	return matchers.length > 1 ?
5876		function( elem, context, xml ) {
5877			var i = matchers.length;
5878			while ( i-- ) {
5879				if ( !matchers[i]( elem, context, xml ) ) {
5880					return false;
5881				}
5882			}
5883			return true;
5884		} :
5885		matchers[0];
5886}
5887
5888function multipleContexts( selector, contexts, results ) {
5889	var i = 0,
5890		len = contexts.length;
5891	for ( ; i < len; i++ ) {
5892		Sizzle( selector, contexts[i], results );
5893	}
5894	return results;
5895}
5896
5897function condense( unmatched, map, filter, context, xml ) {
5898	var elem,
5899		newUnmatched = [],
5900		i = 0,
5901		len = unmatched.length,
5902		mapped = map != null;
5903
5904	for ( ; i < len; i++ ) {
5905		if ( (elem = unmatched[i]) ) {
5906			if ( !filter || filter( elem, context, xml ) ) {
5907				newUnmatched.push( elem );
5908				if ( mapped ) {
5909					map.push( i );
5910				}
5911			}
5912		}
5913	}
5914
5915	return newUnmatched;
5916}
5917
5918function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
5919	if ( postFilter && !postFilter[ expando ] ) {
5920		postFilter = setMatcher( postFilter );
5921	}
5922	if ( postFinder && !postFinder[ expando ] ) {
5923		postFinder = setMatcher( postFinder, postSelector );
5924	}
5925	return markFunction(function( seed, results, context, xml ) {
5926		var temp, i, elem,
5927			preMap = [],
5928			postMap = [],
5929			preexisting = results.length,
5930
5931			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
5932
5933			matcherIn = preFilter && ( seed || !selector ) ?
5934				condense( elems, preMap, preFilter, context, xml ) :
5935				elems,
5936
5937			matcherOut = matcher ?
5938				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
5939
5940					[] :
5941
5942					results :
5943				matcherIn;
5944
5945		if ( matcher ) {
5946			matcher( matcherIn, matcherOut, context, xml );
5947		}
5948
5949		if ( postFilter ) {
5950			temp = condense( matcherOut, postMap );
5951			postFilter( temp, [], context, xml );
5952
5953			i = temp.length;
5954			while ( i-- ) {
5955				if ( (elem = temp[i]) ) {
5956					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
5957				}
5958			}
5959		}
5960
5961		if ( seed ) {
5962			if ( postFinder || preFilter ) {
5963				if ( postFinder ) {
5964					temp = [];
5965					i = matcherOut.length;
5966					while ( i-- ) {
5967						if ( (elem = matcherOut[i]) ) {
5968							temp.push( (matcherIn[i] = elem) );
5969						}
5970					}
5971					postFinder( null, (matcherOut = []), temp, xml );
5972				}
5973
5974				i = matcherOut.length;
5975				while ( i-- ) {
5976					if ( (elem = matcherOut[i]) &&
5977						(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
5978
5979						seed[temp] = !(results[temp] = elem);
5980					}
5981				}
5982			}
5983
5984		} else {
5985			matcherOut = condense(
5986				matcherOut === results ?
5987					matcherOut.splice( preexisting, matcherOut.length ) :
5988					matcherOut
5989			);
5990			if ( postFinder ) {
5991				postFinder( null, results, matcherOut, xml );
5992			} else {
5993				push.apply( results, matcherOut );
5994			}
5995		}
5996	});
5997}
5998
5999function matcherFromTokens( tokens ) {
6000	var checkContext, matcher, j,
6001		len = tokens.length,
6002		leadingRelative = Expr.relative[ tokens[0].type ],
6003		implicitRelative = leadingRelative || Expr.relative[" "],
6004		i = leadingRelative ? 1 : 0,
6005
6006		matchContext = addCombinator( function( elem ) {
6007			return elem === checkContext;
6008		}, implicitRelative, true ),
6009		matchAnyContext = addCombinator( function( elem ) {
6010			return indexOf.call( checkContext, elem ) > -1;
6011		}, implicitRelative, true ),
6012		matchers = [ function( elem, context, xml ) {
6013			return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
6014				(checkContext = context).nodeType ?
6015					matchContext( elem, context, xml ) :
6016					matchAnyContext( elem, context, xml ) );
6017		} ];
6018
6019	for ( ; i < len; i++ ) {
6020		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
6021			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
6022		} else {
6023			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
6024
6025			if ( matcher[ expando ] ) {
6026				j = ++i;
6027				for ( ; j < len; j++ ) {
6028					if ( Expr.relative[ tokens[j].type ] ) {
6029						break;
6030					}
6031				}
6032				return setMatcher(
6033					i > 1 && elementMatcher( matchers ),
6034					i > 1 && toSelector(
6035						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
6036					).replace( rtrim, "$1" ),
6037					matcher,
6038					i < j && matcherFromTokens( tokens.slice( i, j ) ),
6039					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
6040					j < len && toSelector( tokens )
6041				);
6042			}
6043			matchers.push( matcher );
6044		}
6045	}
6046
6047	return elementMatcher( matchers );
6048}
6049
6050function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
6051	var bySet = setMatchers.length > 0,
6052		byElement = elementMatchers.length > 0,
6053		superMatcher = function( seed, context, xml, results, outermost ) {
6054			var elem, j, matcher,
6055				matchedCount = 0,
6056				i = "0",
6057				unmatched = seed && [],
6058				setMatched = [],
6059				contextBackup = outermostContext,
6060				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
6061				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
6062				len = elems.length;
6063
6064			if ( outermost ) {
6065				outermostContext = context !== document && context;
6066			}
6067
6068			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
6069				if ( byElement && elem ) {
6070					j = 0;
6071					while ( (matcher = elementMatchers[j++]) ) {
6072						if ( matcher( elem, context, xml ) ) {
6073							results.push( elem );
6074							break;
6075						}
6076					}
6077					if ( outermost ) {
6078						dirruns = dirrunsUnique;
6079					}
6080				}
6081
6082				if ( bySet ) {
6083					if ( (elem = !matcher && elem) ) {
6084						matchedCount--;
6085					}
6086
6087					if ( seed ) {
6088						unmatched.push( elem );
6089					}
6090				}
6091			}
6092
6093			matchedCount += i;
6094			if ( bySet && i !== matchedCount ) {
6095				j = 0;
6096				while ( (matcher = setMatchers[j++]) ) {
6097					matcher( unmatched, setMatched, context, xml );
6098				}
6099
6100				if ( seed ) {
6101					if ( matchedCount > 0 ) {
6102						while ( i-- ) {
6103							if ( !(unmatched[i] || setMatched[i]) ) {
6104								setMatched[i] = pop.call( results );
6105							}
6106						}
6107					}
6108
6109					setMatched = condense( setMatched );
6110				}
6111
6112				push.apply( results, setMatched );
6113
6114				if ( outermost && !seed && setMatched.length > 0 &&
6115					( matchedCount + setMatchers.length ) > 1 ) {
6116
6117					Sizzle.uniqueSort( results );
6118				}
6119			}
6120
6121			if ( outermost ) {
6122				dirruns = dirrunsUnique;
6123				outermostContext = contextBackup;
6124			}
6125
6126			return unmatched;
6127		};
6128
6129	return bySet ?
6130		markFunction( superMatcher ) :
6131		superMatcher;
6132}
6133
6134compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
6135	var i,
6136		setMatchers = [],
6137		elementMatchers = [],
6138		cached = compilerCache[ selector + " " ];
6139
6140	if ( !cached ) {
6141		if ( !match ) {
6142			match = tokenize( selector );
6143		}
6144		i = match.length;
6145		while ( i-- ) {
6146			cached = matcherFromTokens( match[i] );
6147			if ( cached[ expando ] ) {
6148				setMatchers.push( cached );
6149			} else {
6150				elementMatchers.push( cached );
6151			}
6152		}
6153
6154		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
6155
6156		cached.selector = selector;
6157	}
6158	return cached;
6159};
6160
6161/**
6162 * A low-level selection function that works with Sizzle's compiled
6163 *  selector functions
6164 * @param {String|Function} selector A selector or a pre-compiled
6165 *  selector function built with Sizzle.compile
6166 * @param {Element} context
6167 * @param {Array} [results]
6168 * @param {Array} [seed] A set of elements to match against
6169 */
6170select = Sizzle.select = function( selector, context, results, seed ) {
6171	var i, tokens, token, type, find,
6172		compiled = typeof selector === "function" && selector,
6173		match = !seed && tokenize( (selector = compiled.selector || selector) );
6174
6175	results = results || [];
6176
6177	if ( match.length === 1 ) {
6178
6179		tokens = match[0] = match[0].slice( 0 );
6180		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
6181				support.getById && context.nodeType === 9 && documentIsHTML &&
6182				Expr.relative[ tokens[1].type ] ) {
6183
6184			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
6185			if ( !context ) {
6186				return results;
6187
6188			} else if ( compiled ) {
6189				context = context.parentNode;
6190			}
6191
6192			selector = selector.slice( tokens.shift().value.length );
6193		}
6194
6195		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
6196		while ( i-- ) {
6197			token = tokens[i];
6198
6199			if ( Expr.relative[ (type = token.type) ] ) {
6200				break;
6201			}
6202			if ( (find = Expr.find[ type ]) ) {
6203				if ( (seed = find(
6204					token.matches[0].replace( runescape, funescape ),
6205					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
6206				)) ) {
6207
6208					tokens.splice( i, 1 );
6209					selector = seed.length && toSelector( tokens );
6210					if ( !selector ) {
6211						push.apply( results, seed );
6212						return results;
6213					}
6214
6215					break;
6216				}
6217			}
6218		}
6219	}
6220
6221	( compiled || compile( selector, match ) )(
6222		seed,
6223		context,
6224		!documentIsHTML,
6225		results,
6226		rsibling.test( selector ) && testContext( context.parentNode ) || context
6227	);
6228	return results;
6229};
6230
6231
6232support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
6233
6234support.detectDuplicates = !!hasDuplicate;
6235
6236setDocument();
6237
6238support.sortDetached = assert(function( div1 ) {
6239	return div1.compareDocumentPosition( document.createElement("div") ) & 1;
6240});
6241
6242if ( !assert(function( div ) {
6243	div.innerHTML = "<a href='#'></a>";
6244	return div.firstChild.getAttribute("href") === "#" ;
6245}) ) {
6246	addHandle( "type|href|height|width", function( elem, name, isXML ) {
6247		if ( !isXML ) {
6248			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
6249		}
6250	});
6251}
6252
6253if ( !support.attributes || !assert(function( div ) {
6254	div.innerHTML = "<input/>";
6255	div.firstChild.setAttribute( "value", "" );
6256	return div.firstChild.getAttribute( "value" ) === "";
6257}) ) {
6258	addHandle( "value", function( elem, name, isXML ) {
6259		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
6260			return elem.defaultValue;
6261		}
6262	});
6263}
6264
6265if ( !assert(function( div ) {
6266	return div.getAttribute("disabled") == null;
6267}) ) {
6268	addHandle( booleans, function( elem, name, isXML ) {
6269		var val;
6270		if ( !isXML ) {
6271			return elem[ name ] === true ? name.toLowerCase() :
6272					(val = elem.getAttributeNode( name )) && val.specified ?
6273					val.value :
6274				null;
6275		}
6276	});
6277}
6278
6279if ( typeof define === "function" && define.amd ) {
6280	define(function() { return Sizzle; });
6281} else if ( typeof module !== "undefined" && module.exports ) {
6282	module.exports = Sizzle;
6283} else {
6284	window.Sizzle = Sizzle;
6285}
6286
6287})( window );
6288
6289;(function() {
6290  if (typeof Sizzle !== 'undefined') {
6291    return;
6292  }
6293
6294  if (typeof define !== 'undefined' && define.amd) {
6295    window.Sizzle = Prototype._actual_sizzle;
6296    window.define = Prototype._original_define;
6297    delete Prototype._actual_sizzle;
6298    delete Prototype._original_define;
6299  } else if (typeof module !== 'undefined' && module.exports) {
6300    window.Sizzle = module.exports;
6301    module.exports = {};
6302  }
6303})();
6304
6305;(function(engine) {
6306  var extendElements = Prototype.Selector.extendElements;
6307
6308  function select(selector, scope) {
6309    return extendElements(engine(selector, scope || document));
6310  }
6311
6312  function match(element, selector) {
6313    return engine.matches(selector, [element]).length == 1;
6314  }
6315
6316  Prototype.Selector.engine = engine;
6317  Prototype.Selector.select = select;
6318  Prototype.Selector.match = match;
6319})(Sizzle);
6320
6321window.Sizzle = Prototype._original_property;
6322delete Prototype._original_property;
6323
6324var Form = {
6325  reset: function(form) {
6326    form = $(form);
6327    form.reset();
6328    return form;
6329  },
6330
6331  serializeElements: function(elements, options) {
6332    if (typeof options != 'object') options = { hash: !!options };
6333    else if (Object.isUndefined(options.hash)) options.hash = true;
6334    var key, value, submitted = false, submit = options.submit, accumulator, initial;
6335
6336    if (options.hash) {
6337      initial = {};
6338      accumulator = function(result, key, value) {
6339        if (key in result) {
6340          if (!Object.isArray(result[key])) result[key] = [result[key]];
6341          result[key] = result[key].concat(value);
6342        } else result[key] = value;
6343        return result;
6344      };
6345    } else {
6346      initial = '';
6347      accumulator = function(result, key, value) {
6348        return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value);
6349      };
6350    }
6351
6352    return elements.inject(initial, function(result, element) {
6353      if (!element.disabled && element.name) {
6354        key = element.name; value = $(element).getValue();
6355        if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
6356            submit !== false && (!submit || key == submit) && (submitted = true)))) {
6357          result = accumulator(result, key, value);
6358        }
6359      }
6360      return result;
6361    });
6362  }
6363};
6364
6365Form.Methods = {
6366  serialize: function(form, options) {
6367    return Form.serializeElements(Form.getElements(form), options);
6368  },
6369
6370
6371  getElements: function(form) {
6372    var elements = $(form).getElementsByTagName('*');
6373    var element, results = [], serializers = Form.Element.Serializers;
6374
6375    for (var i = 0; element = elements[i]; i++) {
6376      if (serializers[element.tagName.toLowerCase()])
6377        results.push(Element.extend(element));
6378    }
6379    return results;
6380  },
6381
6382  getInputs: function(form, typeName, name) {
6383    form = $(form);
6384    var inputs = form.getElementsByTagName('input');
6385
6386    if (!typeName && !name) return $A(inputs).map(Element.extend);
6387
6388    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
6389      var input = inputs[i];
6390      if ((typeName && input.type != typeName) || (name && input.name != name))
6391        continue;
6392      matchingInputs.push(Element.extend(input));
6393    }
6394
6395    return matchingInputs;
6396  },
6397
6398  disable: function(form) {
6399    form = $(form);
6400    Form.getElements(form).invoke('disable');
6401    return form;
6402  },
6403
6404  enable: function(form) {
6405    form = $(form);
6406    Form.getElements(form).invoke('enable');
6407    return form;
6408  },
6409
6410  findFirstElement: function(form) {
6411    var elements = $(form).getElements().findAll(function(element) {
6412      return 'hidden' != element.type && !element.disabled;
6413    });
6414    var firstByIndex = elements.findAll(function(element) {
6415      return element.hasAttribute('tabIndex') && element.tabIndex >= 0;
6416    }).sortBy(function(element) { return element.tabIndex }).first();
6417
6418    return firstByIndex ? firstByIndex : elements.find(function(element) {
6419      return /^(?:input|select|textarea)$/i.test(element.tagName);
6420    });
6421  },
6422
6423  focusFirstElement: function(form) {
6424    form = $(form);
6425    var element = form.findFirstElement();
6426    if (element) element.activate();
6427    return form;
6428  },
6429
6430  request: function(form, options) {
6431    form = $(form), options = Object.clone(options || { });
6432
6433    var params = options.parameters, action = form.readAttribute('action') || '';
6434    if (action.blank()) action = window.location.href;
6435    options.parameters = form.serialize(true);
6436
6437    if (params) {
6438      if (Object.isString(params)) params = params.toQueryParams();
6439      Object.extend(options.parameters, params);
6440    }
6441
6442    if (form.hasAttribute('method') && !options.method)
6443      options.method = form.method;
6444
6445    return new Ajax.Request(action, options);
6446  }
6447};
6448
6449/*--------------------------------------------------------------------------*/
6450
6451
6452Form.Element = {
6453  focus: function(element) {
6454    $(element).focus();
6455    return element;
6456  },
6457
6458  select: function(element) {
6459    $(element).select();
6460    return element;
6461  }
6462};
6463
6464Form.Element.Methods = {
6465
6466  serialize: function(element) {
6467    element = $(element);
6468    if (!element.disabled && element.name) {
6469      var value = element.getValue();
6470      if (value != undefined) {
6471        var pair = { };
6472        pair[element.name] = value;
6473        return Object.toQueryString(pair);
6474      }
6475    }
6476    return '';
6477  },
6478
6479  getValue: function(element) {
6480    element = $(element);
6481    var method = element.tagName.toLowerCase();
6482    return Form.Element.Serializers[method](element);
6483  },
6484
6485  setValue: function(element, value) {
6486    element = $(element);
6487    var method = element.tagName.toLowerCase();
6488    Form.Element.Serializers[method](element, value);
6489    return element;
6490  },
6491
6492  clear: function(element) {
6493    $(element).value = '';
6494    return element;
6495  },
6496
6497  present: function(element) {
6498    return $(element).value != '';
6499  },
6500
6501  activate: function(element) {
6502    element = $(element);
6503    try {
6504      element.focus();
6505      if (element.select && (element.tagName.toLowerCase() != 'input' ||
6506          !(/^(?:button|reset|submit)$/i.test(element.type))))
6507        element.select();
6508    } catch (e) { }
6509    return element;
6510  },
6511
6512  disable: function(element) {
6513    element = $(element);
6514    element.disabled = true;
6515    return element;
6516  },
6517
6518  enable: function(element) {
6519    element = $(element);
6520    element.disabled = false;
6521    return element;
6522  }
6523};
6524
6525/*--------------------------------------------------------------------------*/
6526
6527var Field = Form.Element;
6528
6529var $F = Form.Element.Methods.getValue;
6530
6531/*--------------------------------------------------------------------------*/
6532
6533Form.Element.Serializers = (function() {
6534  function input(element, value) {
6535    switch (element.type.toLowerCase()) {
6536      case 'checkbox':
6537      case 'radio':
6538        return inputSelector(element, value);
6539      default:
6540        return valueSelector(element, value);
6541    }
6542  }
6543
6544  function inputSelector(element, value) {
6545    if (Object.isUndefined(value))
6546      return element.checked ? element.value : null;
6547    else element.checked = !!value;
6548  }
6549
6550  function valueSelector(element, value) {
6551    if (Object.isUndefined(value)) return element.value;
6552    else element.value = value;
6553  }
6554
6555  function select(element, value) {
6556    if (Object.isUndefined(value))
6557      return (element.type === 'select-one' ? selectOne : selectMany)(element);
6558
6559    var opt, currentValue, single = !Object.isArray(value);
6560    for (var i = 0, length = element.length; i < length; i++) {
6561      opt = element.options[i];
6562      currentValue = this.optionValue(opt);
6563      if (single) {
6564        if (currentValue == value) {
6565          opt.selected = true;
6566          return;
6567        }
6568      }
6569      else opt.selected = value.include(currentValue);
6570    }
6571  }
6572
6573  function selectOne(element) {
6574    var index = element.selectedIndex;
6575    return index >= 0 ? optionValue(element.options[index]) : null;
6576  }
6577
6578  function selectMany(element) {
6579    var values, length = element.length;
6580    if (!length) return null;
6581
6582    for (var i = 0, values = []; i < length; i++) {
6583      var opt = element.options[i];
6584      if (opt.selected) values.push(optionValue(opt));
6585    }
6586    return values;
6587  }
6588
6589  function optionValue(opt) {
6590    return Element.hasAttribute(opt, 'value') ? opt.value : opt.text;
6591  }
6592
6593  return {
6594    input:         input,
6595    inputSelector: inputSelector,
6596    textarea:      valueSelector,
6597    select:        select,
6598    selectOne:     selectOne,
6599    selectMany:    selectMany,
6600    optionValue:   optionValue,
6601    button:        valueSelector
6602  };
6603})();
6604
6605/*--------------------------------------------------------------------------*/
6606
6607
6608Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
6609  initialize: function($super, element, frequency, callback) {
6610    $super(callback, frequency);
6611    this.element   = $(element);
6612    this.lastValue = this.getValue();
6613  },
6614
6615  execute: function() {
6616    var value = this.getValue();
6617    if (Object.isString(this.lastValue) && Object.isString(value) ?
6618        this.lastValue != value : String(this.lastValue) != String(value)) {
6619      this.callback(this.element, value);
6620      this.lastValue = value;
6621    }
6622  }
6623});
6624
6625Form.Element.Observer = Class.create(Abstract.TimedObserver, {
6626  getValue: function() {
6627    return Form.Element.getValue(this.element);
6628  }
6629});
6630
6631Form.Observer = Class.create(Abstract.TimedObserver, {
6632  getValue: function() {
6633    return Form.serialize(this.element);
6634  }
6635});
6636
6637/*--------------------------------------------------------------------------*/
6638
6639Abstract.EventObserver = Class.create({
6640  initialize: function(element, callback) {
6641    this.element  = $(element);
6642    this.callback = callback;
6643
6644    this.lastValue = this.getValue();
6645    if (this.element.tagName.toLowerCase() == 'form')
6646      this.registerFormCallbacks();
6647    else
6648      this.registerCallback(this.element);
6649  },
6650
6651  onElementEvent: function() {
6652    var value = this.getValue();
6653    if (this.lastValue != value) {
6654      this.callback(this.element, value);
6655      this.lastValue = value;
6656    }
6657  },
6658
6659  registerFormCallbacks: function() {
6660    Form.getElements(this.element).each(this.registerCallback, this);
6661  },
6662
6663  registerCallback: function(element) {
6664    if (element.type) {
6665      switch (element.type.toLowerCase()) {
6666        case 'checkbox':
6667        case 'radio':
6668          Event.observe(element, 'click', this.onElementEvent.bind(this));
6669          break;
6670        default:
6671          Event.observe(element, 'change', this.onElementEvent.bind(this));
6672          break;
6673      }
6674    }
6675  }
6676});
6677
6678Form.Element.EventObserver = Class.create(Abstract.EventObserver, {
6679  getValue: function() {
6680    return Form.Element.getValue(this.element);
6681  }
6682});
6683
6684Form.EventObserver = Class.create(Abstract.EventObserver, {
6685  getValue: function() {
6686    return Form.serialize(this.element);
6687  }
6688});
6689(function(GLOBAL) {
6690  var DIV = document.createElement('div');
6691  var docEl = document.documentElement;
6692  var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
6693   && 'onmouseleave' in docEl;
6694
6695  var Event = {
6696    KEY_BACKSPACE: 8,
6697    KEY_TAB:       9,
6698    KEY_RETURN:   13,
6699    KEY_ESC:      27,
6700    KEY_LEFT:     37,
6701    KEY_UP:       38,
6702    KEY_RIGHT:    39,
6703    KEY_DOWN:     40,
6704    KEY_DELETE:   46,
6705    KEY_HOME:     36,
6706    KEY_END:      35,
6707    KEY_PAGEUP:   33,
6708    KEY_PAGEDOWN: 34,
6709    KEY_INSERT:   45
6710  };
6711
6712
6713  var isIELegacyEvent = function(event) { return false; };
6714
6715  if (window.attachEvent) {
6716    if (window.addEventListener) {
6717      isIELegacyEvent = function(event) {
6718        return !(event instanceof window.Event);
6719      };
6720    } else {
6721      isIELegacyEvent = function(event) { return true; };
6722    }
6723  }
6724
6725  var _isButton;
6726
6727  function _isButtonForDOMEvents(event, code) {
6728    return event.which ? (event.which === code + 1) : (event.button === code);
6729  }
6730
6731  var legacyButtonMap = { 0: 1, 1: 4, 2: 2 };
6732  function _isButtonForLegacyEvents(event, code) {
6733    return event.button === legacyButtonMap[code];
6734  }
6735
6736  function _isButtonForWebKit(event, code) {
6737    switch (code) {
6738      case 0: return event.which == 1 && !event.metaKey;
6739      case 1: return event.which == 2 || (event.which == 1 && event.metaKey);
6740      case 2: return event.which == 3;
6741      default: return false;
6742    }
6743  }
6744
6745  if (window.attachEvent) {
6746    if (!window.addEventListener) {
6747      _isButton = _isButtonForLegacyEvents;
6748    } else {
6749      _isButton = function(event, code) {
6750        return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) :
6751         _isButtonForDOMEvents(event, code);
6752      }
6753    }
6754  } else if (Prototype.Browser.WebKit) {
6755    _isButton = _isButtonForWebKit;
6756  } else {
6757    _isButton = _isButtonForDOMEvents;
6758  }
6759
6760  function isLeftClick(event)   { return _isButton(event, 0) }
6761
6762  function isMiddleClick(event) { return _isButton(event, 1) }
6763
6764  function isRightClick(event)  { return _isButton(event, 2) }
6765
6766  function element(event) {
6767    return Element.extend(_element(event));
6768  }
6769
6770  function _element(event) {
6771    event = Event.extend(event);
6772
6773    var node = event.target, type = event.type,
6774     currentTarget = event.currentTarget;
6775
6776    if (currentTarget && currentTarget.tagName) {
6777      if (type === 'load' || type === 'error' ||
6778        (type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
6779          && currentTarget.type === 'radio'))
6780            node = currentTarget;
6781    }
6782
6783    return node.nodeType == Node.TEXT_NODE ? node.parentNode : node;
6784  }
6785
6786  function findElement(event, expression) {
6787    var element = _element(event), selector = Prototype.Selector;
6788    if (!expression) return Element.extend(element);
6789    while (element) {
6790      if (Object.isElement(element) && selector.match(element, expression))
6791        return Element.extend(element);
6792      element = element.parentNode;
6793    }
6794  }
6795
6796  function pointer(event) {
6797    return { x: pointerX(event), y: pointerY(event) };
6798  }
6799
6800  function pointerX(event) {
6801    var docElement = document.documentElement,
6802     body = document.body || { scrollLeft: 0 };
6803
6804    return event.pageX || (event.clientX +
6805      (docElement.scrollLeft || body.scrollLeft) -
6806      (docElement.clientLeft || 0));
6807  }
6808
6809  function pointerY(event) {
6810    var docElement = document.documentElement,
6811     body = document.body || { scrollTop: 0 };
6812
6813    return  event.pageY || (event.clientY +
6814       (docElement.scrollTop || body.scrollTop) -
6815       (docElement.clientTop || 0));
6816  }
6817
6818
6819  function stop(event) {
6820    Event.extend(event);
6821    event.preventDefault();
6822    event.stopPropagation();
6823
6824    event.stopped = true;
6825  }
6826
6827
6828  Event.Methods = {
6829    isLeftClick:   isLeftClick,
6830    isMiddleClick: isMiddleClick,
6831    isRightClick:  isRightClick,
6832
6833    element:     element,
6834    findElement: findElement,
6835
6836    pointer:  pointer,
6837    pointerX: pointerX,
6838    pointerY: pointerY,
6839
6840    stop: stop
6841  };
6842
6843  var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
6844    m[name] = Event.Methods[name].methodize();
6845    return m;
6846  });
6847
6848  if (window.attachEvent) {
6849    function _relatedTarget(event) {
6850      var element;
6851      switch (event.type) {
6852        case 'mouseover':
6853        case 'mouseenter':
6854          element = event.fromElement;
6855          break;
6856        case 'mouseout':
6857        case 'mouseleave':
6858          element = event.toElement;
6859          break;
6860        default:
6861          return null;
6862      }
6863      return Element.extend(element);
6864    }
6865
6866    var additionalMethods = {
6867      stopPropagation: function() { this.cancelBubble = true },
6868      preventDefault:  function() { this.returnValue = false },
6869      inspect: function() { return '[object Event]' }
6870    };
6871
6872    Event.extend = function(event, element) {
6873      if (!event) return false;
6874
6875      if (!isIELegacyEvent(event)) return event;
6876
6877      if (event._extendedByPrototype) return event;
6878      event._extendedByPrototype = Prototype.emptyFunction;
6879
6880      var pointer = Event.pointer(event);
6881
6882      Object.extend(event, {
6883        target: event.srcElement || element,
6884        relatedTarget: _relatedTarget(event),
6885        pageX:  pointer.x,
6886        pageY:  pointer.y
6887      });
6888
6889      Object.extend(event, methods);
6890      Object.extend(event, additionalMethods);
6891
6892      return event;
6893    };
6894  } else {
6895    Event.extend = Prototype.K;
6896  }
6897
6898  if (window.addEventListener) {
6899    Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
6900    Object.extend(Event.prototype, methods);
6901  }
6902
6903  var EVENT_TRANSLATIONS = {
6904    mouseenter: 'mouseover',
6905    mouseleave: 'mouseout'
6906  };
6907
6908  function getDOMEventName(eventName) {
6909    return EVENT_TRANSLATIONS[eventName] || eventName;
6910  }
6911
6912  if (MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED)
6913    getDOMEventName = Prototype.K;
6914
6915  function getUniqueElementID(element) {
6916    if (element === window) return 0;
6917
6918    if (typeof element._prototypeUID === 'undefined')
6919      element._prototypeUID = Element.Storage.UID++;
6920    return element._prototypeUID;
6921  }
6922
6923  function getUniqueElementID_IE(element) {
6924    if (element === window) return 0;
6925    if (element == document) return 1;
6926    return element.uniqueID;
6927  }
6928
6929  if ('uniqueID' in DIV)
6930    getUniqueElementID = getUniqueElementID_IE;
6931
6932  function isCustomEvent(eventName) {
6933    return eventName.include(':');
6934  }
6935
6936  Event._isCustomEvent = isCustomEvent;
6937
6938  function getOrCreateRegistryFor(element, uid) {
6939    var CACHE = GLOBAL.Event.cache;
6940    if (Object.isUndefined(uid))
6941      uid = getUniqueElementID(element);
6942    if (!CACHE[uid]) CACHE[uid] = { element: element };
6943    return CACHE[uid];
6944  }
6945
6946  function destroyRegistryForElement(element, uid) {
6947    if (Object.isUndefined(uid))
6948      uid = getUniqueElementID(element);
6949    delete GLOBAL.Event.cache[uid];
6950  }
6951
6952
6953  function register(element, eventName, handler) {
6954    var registry = getOrCreateRegistryFor(element);
6955    if (!registry[eventName]) registry[eventName] = [];
6956    var entries = registry[eventName];
6957
6958    var i = entries.length;
6959    while (i--)
6960      if (entries[i].handler === handler) return null;
6961
6962    var uid = getUniqueElementID(element);
6963    var responder = GLOBAL.Event._createResponder(uid, eventName, handler);
6964    var entry = {
6965      responder: responder,
6966      handler:   handler
6967    };
6968
6969    entries.push(entry);
6970    return entry;
6971  }
6972
6973  function unregister(element, eventName, handler) {
6974    var registry = getOrCreateRegistryFor(element);
6975    var entries = registry[eventName] || [];
6976
6977    var i = entries.length, entry;
6978    while (i--) {
6979      if (entries[i].handler === handler) {
6980        entry = entries[i];
6981        break;
6982      }
6983    }
6984
6985    if (entry) {
6986      var index = entries.indexOf(entry);
6987      entries.splice(index, 1);
6988    }
6989
6990    if (entries.length === 0) {
6991      delete registry[eventName];
6992      if (Object.keys(registry).length === 1 && ('element' in registry))
6993        destroyRegistryForElement(element);
6994    }
6995
6996    return entry;
6997  }
6998
6999
7000  function observe(element, eventName, handler) {
7001    element = $(element);
7002    var entry = register(element, eventName, handler);
7003
7004    if (entry === null) return element;
7005
7006    var responder = entry.responder;
7007    if (isCustomEvent(eventName))
7008      observeCustomEvent(element, eventName, responder);
7009    else
7010      observeStandardEvent(element, eventName, responder);
7011
7012    return element;
7013  }
7014
7015  function observeStandardEvent(element, eventName, responder) {
7016    var actualEventName = getDOMEventName(eventName);
7017    if (element.addEventListener) {
7018      element.addEventListener(actualEventName, responder, false);
7019    } else {
7020      element.attachEvent('on' + actualEventName, responder);
7021    }
7022  }
7023
7024  function observeCustomEvent(element, eventName, responder) {
7025    if (element.addEventListener) {
7026      element.addEventListener('dataavailable', responder, false);
7027    } else {
7028      element.attachEvent('ondataavailable', responder);
7029      element.attachEvent('onlosecapture',   responder);
7030    }
7031  }
7032
7033  function stopObserving(element, eventName, handler) {
7034    element = $(element);
7035    var handlerGiven = !Object.isUndefined(handler),
7036     eventNameGiven = !Object.isUndefined(eventName);
7037
7038    if (!eventNameGiven && !handlerGiven) {
7039      stopObservingElement(element);
7040      return element;
7041    }
7042
7043    if (!handlerGiven) {
7044      stopObservingEventName(element, eventName);
7045      return element;
7046    }
7047
7048    var entry = unregister(element, eventName, handler);
7049
7050    if (!entry) return element;
7051    removeEvent(element, eventName, entry.responder);
7052    return element;
7053  }
7054
7055  function stopObservingStandardEvent(element, eventName, responder) {
7056    var actualEventName = getDOMEventName(eventName);
7057    if (element.removeEventListener) {
7058      element.removeEventListener(actualEventName, responder, false);
7059    } else {
7060      element.detachEvent('on' + actualEventName, responder);
7061    }
7062  }
7063
7064  function stopObservingCustomEvent(element, eventName, responder) {
7065    if (element.removeEventListener) {
7066      element.removeEventListener('dataavailable', responder, false);
7067    } else {
7068      element.detachEvent('ondataavailable', responder);
7069      element.detachEvent('onlosecapture',   responder);
7070    }
7071  }
7072
7073
7074
7075  function stopObservingElement(element) {
7076    var uid = getUniqueElementID(element), registry = GLOBAL.Event.cache[uid];
7077    if (!registry) return;
7078
7079    destroyRegistryForElement(element, uid);
7080
7081    var entries, i;
7082    for (var eventName in registry) {
7083      if (eventName === 'element') continue;
7084
7085      entries = registry[eventName];
7086      i = entries.length;
7087      while (i--)
7088        removeEvent(element, eventName, entries[i].responder);
7089    }
7090  }
7091
7092  function stopObservingEventName(element, eventName) {
7093    var registry = getOrCreateRegistryFor(element);
7094    var entries = registry[eventName];
7095    if (entries) {
7096      delete registry[eventName];
7097    }
7098
7099    entries = entries || [];
7100
7101    var i = entries.length;
7102    while (i--)
7103      removeEvent(element, eventName, entries[i].responder);
7104
7105    for (var name in registry) {
7106      if (name === 'element') continue;
7107      return; // There is another registered event
7108    }
7109
7110    destroyRegistryForElement(element);
7111  }
7112
7113
7114  function removeEvent(element, eventName, handler) {
7115    if (isCustomEvent(eventName))
7116      stopObservingCustomEvent(element, eventName, handler);
7117    else
7118      stopObservingStandardEvent(element, eventName, handler);
7119  }
7120
7121
7122
7123  function getFireTarget(element) {
7124    if (element !== document) return element;
7125    if (document.createEvent && !element.dispatchEvent)
7126      return document.documentElement;
7127    return element;
7128  }
7129
7130  function fire(element, eventName, memo, bubble) {
7131    element = getFireTarget($(element));
7132    if (Object.isUndefined(bubble)) bubble = true;
7133    memo = memo || {};
7134
7135    var event = fireEvent(element, eventName, memo, bubble);
7136    return Event.extend(event);
7137  }
7138
7139  function fireEvent_DOM(element, eventName, memo, bubble) {
7140    var event = document.createEvent('HTMLEvents');
7141    event.initEvent('dataavailable', bubble, true);
7142
7143    event.eventName = eventName;
7144    event.memo = memo;
7145
7146    element.dispatchEvent(event);
7147    return event;
7148  }
7149
7150  function fireEvent_IE(element, eventName, memo, bubble) {
7151    var event = document.createEventObject();
7152    event.eventType = bubble ? 'ondataavailable' : 'onlosecapture';
7153
7154    event.eventName = eventName;
7155    event.memo = memo;
7156
7157    element.fireEvent(event.eventType, event);
7158    return event;
7159  }
7160
7161  var fireEvent = document.createEvent ? fireEvent_DOM : fireEvent_IE;
7162
7163
7164
7165  Event.Handler = Class.create({
7166    initialize: function(element, eventName, selector, callback) {
7167      this.element   = $(element);
7168      this.eventName = eventName;
7169      this.selector  = selector;
7170      this.callback  = callback;
7171      this.handler   = this.handleEvent.bind(this);
7172    },
7173
7174
7175    start: function() {
7176      Event.observe(this.element, this.eventName, this.handler);
7177      return this;
7178    },
7179
7180    stop: function() {
7181      Event.stopObserving(this.element, this.eventName, this.handler);
7182      return this;
7183    },
7184
7185    handleEvent: function(event) {
7186      var element = Event.findElement(event, this.selector);
7187      if (element) this.callback.call(this.element, event, element);
7188    }
7189  });
7190
7191  function on(element, eventName, selector, callback) {
7192    element = $(element);
7193    if (Object.isFunction(selector) && Object.isUndefined(callback)) {
7194      callback = selector, selector = null;
7195    }
7196
7197    return new Event.Handler(element, eventName, selector, callback).start();
7198  }
7199
7200  Object.extend(Event, Event.Methods);
7201
7202  Object.extend(Event, {
7203    fire:          fire,
7204    observe:       observe,
7205    stopObserving: stopObserving,
7206    on:            on
7207  });
7208
7209  Element.addMethods({
7210    fire:          fire,
7211
7212    observe:       observe,
7213
7214    stopObserving: stopObserving,
7215
7216    on:            on
7217  });
7218
7219  Object.extend(document, {
7220    fire:          fire.methodize(),
7221
7222    observe:       observe.methodize(),
7223
7224    stopObserving: stopObserving.methodize(),
7225
7226    on:            on.methodize(),
7227
7228    loaded:        false
7229  });
7230
7231  if (GLOBAL.Event) Object.extend(window.Event, Event);
7232  else GLOBAL.Event = Event;
7233
7234  GLOBAL.Event.cache = {};
7235
7236  function destroyCache_IE() {
7237    GLOBAL.Event.cache = null;
7238  }
7239
7240  if (window.attachEvent)
7241    window.attachEvent('onunload', destroyCache_IE);
7242
7243  DIV = null;
7244  docEl = null;
7245})(this);
7246
7247(function(GLOBAL) {
7248  /* Code for creating leak-free event responders is based on work by
7249   John-David Dalton. */
7250
7251  var docEl = document.documentElement;
7252  var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
7253    && 'onmouseleave' in docEl;
7254
7255  function isSimulatedMouseEnterLeaveEvent(eventName) {
7256    return !MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &&
7257     (eventName === 'mouseenter' || eventName === 'mouseleave');
7258  }
7259
7260  function createResponder(uid, eventName, handler) {
7261    if (Event._isCustomEvent(eventName))
7262      return createResponderForCustomEvent(uid, eventName, handler);
7263    if (isSimulatedMouseEnterLeaveEvent(eventName))
7264      return createMouseEnterLeaveResponder(uid, eventName, handler);
7265
7266    return function(event) {
7267      if (!Event.cache) return;
7268
7269      var element = Event.cache[uid].element;
7270      Event.extend(event, element);
7271      handler.call(element, event);
7272    };
7273  }
7274
7275  function createResponderForCustomEvent(uid, eventName, handler) {
7276    return function(event) {
7277      var cache = Event.cache[uid];
7278      var element =  cache && cache.element;
7279
7280      if (Object.isUndefined(event.eventName))
7281        return false;
7282
7283      if (event.eventName !== eventName)
7284        return false;
7285
7286      Event.extend(event, element);
7287      handler.call(element, event);
7288    };
7289  }
7290
7291  function createMouseEnterLeaveResponder(uid, eventName, handler) {
7292    return function(event) {
7293      var element = Event.cache[uid].element;
7294
7295      Event.extend(event, element);
7296      var parent = event.relatedTarget;
7297
7298      while (parent && parent !== element) {
7299        try { parent = parent.parentNode; }
7300        catch(e) { parent = element; }
7301      }
7302
7303      if (parent === element) return;
7304      handler.call(element, event);
7305    }
7306  }
7307
7308  GLOBAL.Event._createResponder = createResponder;
7309  docEl = null;
7310})(this);
7311
7312(function(GLOBAL) {
7313  /* Support for the DOMContentLoaded event is based on work by Dan Webb,
7314     Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
7315
7316  var TIMER;
7317
7318  function fireContentLoadedEvent() {
7319    if (document.loaded) return;
7320    if (TIMER) window.clearTimeout(TIMER);
7321    document.loaded = true;
7322    document.fire('dom:loaded');
7323  }
7324
7325  function checkReadyState() {
7326    if (document.readyState === 'complete') {
7327      document.detachEvent('onreadystatechange', checkReadyState);
7328      fireContentLoadedEvent();
7329    }
7330  }
7331
7332  function pollDoScroll() {
7333    try {
7334      document.documentElement.doScroll('left');
7335    } catch (e) {
7336      TIMER = pollDoScroll.defer();
7337      return;
7338    }
7339
7340    fireContentLoadedEvent();
7341  }
7342
7343
7344  if (document.readyState === 'complete') {
7345    fireContentLoadedEvent();
7346    return;
7347  }
7348
7349  if (document.addEventListener) {
7350    document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
7351  } else {
7352    document.attachEvent('onreadystatechange', checkReadyState);
7353    if (window == top) TIMER = pollDoScroll.defer();
7354  }
7355
7356  Event.observe(window, 'load', fireContentLoadedEvent);
7357})(this);
7358
7359
7360Element.addMethods();
7361/*------------------------------- DEPRECATED -------------------------------*/
7362
7363Hash.toQueryString = Object.toQueryString;
7364
7365var Toggle = { display: Element.toggle };
7366
7367Element.addMethods({
7368  childOf: Element.Methods.descendantOf
7369});
7370
7371var Insertion = {
7372  Before: function(element, content) {
7373    return Element.insert(element, {before:content});
7374  },
7375
7376  Top: function(element, content) {
7377    return Element.insert(element, {top:content});
7378  },
7379
7380  Bottom: function(element, content) {
7381    return Element.insert(element, {bottom:content});
7382  },
7383
7384  After: function(element, content) {
7385    return Element.insert(element, {after:content});
7386  }
7387};
7388
7389var $continue = new Error('"throw $continue" is deprecated, use "return" instead');
7390
7391var Position = {
7392  includeScrollOffsets: false,
7393
7394  prepare: function() {
7395    this.deltaX =  window.pageXOffset
7396                || document.documentElement.scrollLeft
7397                || document.body.scrollLeft
7398                || 0;
7399    this.deltaY =  window.pageYOffset
7400                || document.documentElement.scrollTop
7401                || document.body.scrollTop
7402                || 0;
7403  },
7404
7405  within: function(element, x, y) {
7406    if (this.includeScrollOffsets)
7407      return this.withinIncludingScrolloffsets(element, x, y);
7408    this.xcomp = x;
7409    this.ycomp = y;
7410    this.offset = Element.cumulativeOffset(element);
7411
7412    return (y >= this.offset[1] &&
7413            y <  this.offset[1] + element.offsetHeight &&
7414            x >= this.offset[0] &&
7415            x <  this.offset[0] + element.offsetWidth);
7416  },
7417
7418  withinIncludingScrolloffsets: function(element, x, y) {
7419    var offsetcache = Element.cumulativeScrollOffset(element);
7420
7421    this.xcomp = x + offsetcache[0] - this.deltaX;
7422    this.ycomp = y + offsetcache[1] - this.deltaY;
7423    this.offset = Element.cumulativeOffset(element);
7424
7425    return (this.ycomp >= this.offset[1] &&
7426            this.ycomp <  this.offset[1] + element.offsetHeight &&
7427            this.xcomp >= this.offset[0] &&
7428            this.xcomp <  this.offset[0] + element.offsetWidth);
7429  },
7430
7431  overlap: function(mode, element) {
7432    if (!mode) return 0;
7433    if (mode == 'vertical')
7434      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
7435        element.offsetHeight;
7436    if (mode == 'horizontal')
7437      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
7438        element.offsetWidth;
7439  },
7440
7441
7442  cumulativeOffset: Element.Methods.cumulativeOffset,
7443
7444  positionedOffset: Element.Methods.positionedOffset,
7445
7446  absolutize: function(element) {
7447    Position.prepare();
7448    return Element.absolutize(element);
7449  },
7450
7451  relativize: function(element) {
7452    Position.prepare();
7453    return Element.relativize(element);
7454  },
7455
7456  realOffset: Element.Methods.cumulativeScrollOffset,
7457
7458  offsetParent: Element.Methods.getOffsetParent,
7459
7460  page: Element.Methods.viewportOffset,
7461
7462  clone: function(source, target, options) {
7463    options = options || { };
7464    return Element.clonePosition(target, source, options);
7465  }
7466};
7467
7468/*--------------------------------------------------------------------------*/
7469
7470if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){
7471  function iter(name) {
7472    return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]";
7473  }
7474
7475  instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ?
7476  function(element, className) {
7477    className = className.toString().strip();
7478    var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className);
7479    return cond ? document._getElementsByXPath('.//*' + cond, element) : [];
7480  } : function(element, className) {
7481    className = className.toString().strip();
7482    var elements = [], classNames = (/\s/.test(className) ? $w(className) : null);
7483    if (!classNames && !className) return elements;
7484
7485    var nodes = $(element).getElementsByTagName('*');
7486    className = ' ' + className + ' ';
7487
7488    for (var i = 0, child, cn; child = nodes[i]; i++) {
7489      if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) ||
7490          (classNames && classNames.all(function(name) {
7491            return !name.toString().blank() && cn.include(' ' + name + ' ');
7492          }))))
7493        elements.push(Element.extend(child));
7494    }
7495    return elements;
7496  };
7497
7498  return function(className, parentElement) {
7499    return $(parentElement || document.body).getElementsByClassName(className);
7500  };
7501}(Element.Methods);
7502
7503/*--------------------------------------------------------------------------*/
7504
7505Element.ClassNames = Class.create();
7506Element.ClassNames.prototype = {
7507  initialize: function(element) {
7508    this.element = $(element);
7509  },
7510
7511  _each: function(iterator, context) {
7512    this.element.className.split(/\s+/).select(function(name) {
7513      return name.length > 0;
7514    })._each(iterator, context);
7515  },
7516
7517  set: function(className) {
7518    this.element.className = className;
7519  },
7520
7521  add: function(classNameToAdd) {
7522    if (this.include(classNameToAdd)) return;
7523    this.set($A(this).concat(classNameToAdd).join(' '));
7524  },
7525
7526  remove: function(classNameToRemove) {
7527    if (!this.include(classNameToRemove)) return;
7528    this.set($A(this).without(classNameToRemove).join(' '));
7529  },
7530
7531  toString: function() {
7532    return $A(this).join(' ');
7533  }
7534};
7535
7536Object.extend(Element.ClassNames.prototype, Enumerable);
7537
7538/*--------------------------------------------------------------------------*/
7539
7540(function() {
7541  window.Selector = Class.create({
7542    initialize: function(expression) {
7543      this.expression = expression.strip();
7544    },
7545
7546    findElements: function(rootElement) {
7547      return Prototype.Selector.select(this.expression, rootElement);
7548    },
7549
7550    match: function(element) {
7551      return Prototype.Selector.match(element, this.expression);
7552    },
7553
7554    toString: function() {
7555      return this.expression;
7556    },
7557
7558    inspect: function() {
7559      return "#<Selector: " + this.expression + ">";
7560    }
7561  });
7562
7563  Object.extend(Selector, {
7564    matchElements: function(elements, expression) {
7565      var match = Prototype.Selector.match,
7566          results = [];
7567
7568      for (var i = 0, length = elements.length; i < length; i++) {
7569        var element = elements[i];
7570        if (match(element, expression)) {
7571          results.push(Element.extend(element));
7572        }
7573      }
7574      return results;
7575    },
7576
7577    findElement: function(elements, expression, index) {
7578      index = index || 0;
7579      var matchIndex = 0, element;
7580      for (var i = 0, length = elements.length; i < length; i++) {
7581        element = elements[i];
7582        if (Prototype.Selector.match(element, expression) && index === matchIndex++) {
7583          return Element.extend(element);
7584        }
7585      }
7586    },
7587
7588    findChildElements: function(element, expressions) {
7589      var selector = expressions.toArray().join(', ');
7590      return Prototype.Selector.select(selector, element || document);
7591    }
7592  });
7593})();

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.