[ Index ]

PHP Cross Reference of MyBB

title

Body

[close]

/jscripts/ -> prototype.js (source)

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


Generated: Tue Oct 8 19:19:50 2013 Cross-referenced by PHPXref 0.7.1