PageSourceSearch

https://johner.com/includes/prototype.js?v=1.7.3

js johner.com collected 2026-09-26 15:36:51 UTC 199,808 bytes, 7,590 lines download raw bytes

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

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