PageSourceSearch

https://mypaper.pchome.com.tw/js/prototype.js

js pchome.com.tw collected 2026-09-24 08:28:53 UTC 197,777 bytes, 7,510 lines download raw bytes

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

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.