[ Index ]

PHP Cross Reference of Joomla 1.5.26 DE

title

Body

[close]

/plugins/system/mtupgrade/ -> mootools-uncompressed.js (source)

   1  /*
   2  ---
   3  
   4  name: Core
   5  
   6  description: The core of MooTools, contains all the base functions and the Native and Hash implementations. Required by all the other scripts.
   7  
   8  license: MIT-style license.
   9  
  10  copyright: Copyright (c) 2006-2008 [Valerio Proietti](http://mad4milk.net/).
  11  
  12  authors: The MooTools production team (http://mootools.net/developers/)
  13  
  14  inspiration:
  15    - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
  16    - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
  17  
  18  provides: [MooTools, Native, Hash.base, Array.each, $util]
  19  
  20  ...
  21  */
  22  
  23  var MooTools = {
  24      'version': '1.2.5',
  25      'build': '008d8f0f2fcc2044e54fdd3635341aaab274e757'
  26  };
  27  
  28  var Native = function(options){
  29      options = options || {};
  30      var name = options.name;
  31      var legacy = options.legacy;
  32      var protect = options.protect;
  33      var methods = options.implement;
  34      var generics = options.generics;
  35      var initialize = options.initialize;
  36      var afterImplement = options.afterImplement || function(){};
  37      var object = initialize || legacy;
  38      generics = generics !== false;
  39  
  40      object.constructor = Native;
  41      object.$family = {name: 'native'};
  42      if (legacy && initialize) object.prototype = legacy.prototype;
  43      object.prototype.constructor = object;
  44  
  45      if (name){
  46          var family = name.toLowerCase();
  47          object.prototype.$family = {name: family};
  48          Native.typize(object, family);
  49      }
  50  
  51      var add = function(obj, name, method, force){
  52          if (!protect || force || !obj.prototype[name]) obj.prototype[name] = method;
  53          if (generics) Native.genericize(obj, name, protect);
  54          afterImplement.call(obj, name, method);
  55          return obj;
  56      };
  57  
  58      object.alias = function(a1, a2, a3){
  59          if (typeof a1 == 'string'){
  60              var pa1 = this.prototype[a1];
  61              if ((a1 = pa1)) return add(this, a2, a1, a3);
  62          }
  63          for (var a in a1) this.alias(a, a1[a], a2);
  64          return this;
  65      };
  66  
  67      object.implement = function(a1, a2, a3){
  68          if (typeof a1 == 'string') return add(this, a1, a2, a3);
  69          for (var p in a1) add(this, p, a1[p], a2);
  70          return this;
  71      };
  72  
  73      if (methods) object.implement(methods);
  74  
  75      return object;
  76  };
  77  
  78  Native.genericize = function(object, property, check){
  79      if ((!check || !object[property]) && typeof object.prototype[property] == 'function') object[property] = function(){
  80          var args = Array.prototype.slice.call(arguments);
  81          return object.prototype[property].apply(args.shift(), args);
  82      };
  83  };
  84  
  85  Native.implement = function(objects, properties){
  86      for (var i = 0, l = objects.length; i < l; i++) objects[i].implement(properties);
  87  };
  88  
  89  Native.typize = function(object, family){
  90      if (!object.type) object.type = function(item){
  91          return ($type(item) === family);
  92      };
  93  };
  94  
  95  (function(){
  96      var natives = {'Array': Array, 'Date': Date, 'Function': Function, 'Number': Number, 'RegExp': RegExp, 'String': String};
  97      for (var n in natives) new Native({name: n, initialize: natives[n], protect: true});
  98  
  99      var types = {'boolean': Boolean, 'native': Native, 'object': Object};
 100      for (var t in types) Native.typize(types[t], t);
 101  
 102      var generics = {
 103          'Array': ["concat", "indexOf", "join", "lastIndexOf", "pop", "push", "reverse", "shift", "slice", "sort", "splice", "toString", "unshift", "valueOf"],
 104          'String': ["charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "replace", "search", "slice", "split", "substr", "substring", "toLowerCase", "toUpperCase", "valueOf"]
 105      };
 106      for (var g in generics){
 107          for (var i = generics[g].length; i--;) Native.genericize(natives[g], generics[g][i], true);
 108      }
 109  })();
 110  
 111  var Hash = new Native({
 112  
 113      name: 'Hash',
 114  
 115      initialize: function(object){
 116          if ($type(object) == 'hash') object = $unlink(object.getClean());
 117          for (var key in object) this[key] = object[key];
 118          return this;
 119      }
 120  
 121  });
 122  
 123  Hash.implement({
 124  
 125      forEach: function(fn, bind){
 126          for (var key in this){
 127              if (this.hasOwnProperty(key)) fn.call(bind, this[key], key, this);
 128          }
 129      },
 130  
 131      getClean: function(){
 132          var clean = {};
 133          for (var key in this){
 134              if (this.hasOwnProperty(key)) clean[key] = this[key];
 135          }
 136          return clean;
 137      },
 138  
 139      getLength: function(){
 140          var length = 0;
 141          for (var key in this){
 142              if (this.hasOwnProperty(key)) length++;
 143          }
 144          return length;
 145      }
 146  
 147  });
 148  
 149  Hash.alias('forEach', 'each');
 150  
 151  Array.implement({
 152  
 153      forEach: function(fn, bind){
 154          for (var i = 0, l = this.length; i < l; i++) fn.call(bind, this[i], i, this);
 155      }
 156  
 157  });
 158  
 159  Array.alias('forEach', 'each');
 160  
 161  function $A(iterable){
 162      if (iterable.item){
 163          var l = iterable.length, array = new Array(l);
 164          while (l--) array[l] = iterable[l];
 165          return array;
 166      }
 167      return Array.prototype.slice.call(iterable);
 168  };
 169  
 170  function $arguments(i){
 171      return function(){
 172          return arguments[i];
 173      };
 174  };
 175  
 176  function $chk(obj){
 177      return !!(obj || obj === 0);
 178  };
 179  
 180  function $clear(timer){
 181      clearTimeout(timer);
 182      clearInterval(timer);
 183      return null;
 184  };
 185  
 186  function $defined(obj){
 187      return (obj != undefined);
 188  };
 189  
 190  function $each(iterable, fn, bind){
 191      var type = $type(iterable);
 192      ((type == 'arguments' || type == 'collection' || type == 'array') ? Array : Hash).each(iterable, fn, bind);
 193  };
 194  
 195  function $empty(){};
 196  
 197  function $extend(original, extended){
 198      for (var key in (extended || {})) original[key] = extended[key];
 199      return original;
 200  };
 201  
 202  function $H(object){
 203      return new Hash(object);
 204  };
 205  
 206  function $lambda(value){
 207      return ($type(value) == 'function') ? value : function(){
 208          return value;
 209      };
 210  };
 211  
 212  function $merge(){
 213      var args = Array.slice(arguments);
 214      args.unshift({});
 215      return $mixin.apply(null, args);
 216  };
 217  
 218  function $mixin(mix){
 219      for (var i = 1, l = arguments.length; i < l; i++){
 220          var object = arguments[i];
 221          if ($type(object) != 'object') continue;
 222          for (var key in object){
 223              var op = object[key], mp = mix[key];
 224              mix[key] = (mp && $type(op) == 'object' && $type(mp) == 'object') ? $mixin(mp, op) : $unlink(op);
 225          }
 226      }
 227      return mix;
 228  };
 229  
 230  function $pick(){
 231      for (var i = 0, l = arguments.length; i < l; i++){
 232          if (arguments[i] != undefined) return arguments[i];
 233      }
 234      return null;
 235  };
 236  
 237  function $random(min, max){
 238      return Math.floor(Math.random() * (max - min + 1) + min);
 239  };
 240  
 241  function $splat(obj){
 242      var type = $type(obj);
 243      return (type) ? ((type != 'array' && type != 'arguments') ? [obj] : obj) : [];
 244  };
 245  
 246  var $time = Date.now || function(){
 247      return +new Date;
 248  };
 249  
 250  function $try(){
 251      for (var i = 0, l = arguments.length; i < l; i++){
 252          try {
 253              return arguments[i]();
 254          } catch(e){}
 255      }
 256      return null;
 257  };
 258  
 259  function $type(obj){
 260      if (obj == undefined) return false;
 261      if (obj.$family) return (obj.$family.name == 'number' && !isFinite(obj)) ? false : obj.$family.name;
 262      if (obj.nodeName){
 263          switch (obj.nodeType){
 264              case 1: return 'element';
 265              case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
 266          }
 267      } else if (typeof obj.length == 'number'){
 268          if (obj.callee) return 'arguments';
 269          else if (obj.item) return 'collection';
 270      }
 271      return typeof obj;
 272  };
 273  
 274  function $unlink(object){
 275      var unlinked;
 276      switch ($type(object)){
 277          case 'object':
 278              unlinked = {};
 279              for (var p in object) unlinked[p] = $unlink(object[p]);
 280          break;
 281          case 'hash':
 282              unlinked = new Hash(object);
 283          break;
 284          case 'array':
 285              unlinked = [];
 286              for (var i = 0, l = object.length; i < l; i++) unlinked[i] = $unlink(object[i]);
 287          break;
 288          default: return object;
 289      }
 290      return unlinked;
 291  };
 292  
 293  
 294  /*
 295  ---
 296  
 297  name: Browser
 298  
 299  description: The Browser Core. Contains Browser initialization, Window and Document, and the Browser Hash.
 300  
 301  license: MIT-style license.
 302  
 303  requires: [Native, $util]
 304  
 305  provides: [Browser, Window, Document, $exec]
 306  
 307  ...
 308  */
 309  
 310  var Browser = $merge({
 311  
 312      Engine: {name: 'unknown', version: 0},
 313  
 314      Platform: {name: (window.orientation != undefined) ? 'ipod' : (navigator.platform.match(/mac|win|linux/i) || ['other'])[0].toLowerCase()},
 315  
 316      Features: {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)},
 317  
 318      Plugins: {},
 319  
 320      Engines: {
 321  
 322          presto: function(){
 323              return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925));
 324          },
 325  
 326          trident: function(){
 327              return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4);
 328          },
 329  
 330          webkit: function(){
 331              return (navigator.taintEnabled) ? false : ((Browser.Features.xpath) ? ((Browser.Features.query) ? 525 : 420) : 419);
 332          },
 333  
 334          gecko: function(){
 335              return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18);
 336          }
 337  
 338      }
 339  
 340  }, Browser || {});
 341  
 342  Browser.Platform[Browser.Platform.name] = true;
 343  
 344  Browser.detect = function(){
 345  
 346      for (var engine in this.Engines){
 347          var version = this.Engines[engine]();
 348          if (version){
 349              this.Engine = {name: engine, version: version};
 350              this.Engine[engine] = this.Engine[engine + version] = true;
 351              break;
 352          }
 353      }
 354  
 355      return {name: engine, version: version};
 356  
 357  };
 358  
 359  Browser.detect();
 360  
 361  Browser.Request = function(){
 362      return $try(function(){
 363          return new XMLHttpRequest();
 364      }, function(){
 365          return new ActiveXObject('MSXML2.XMLHTTP');
 366      }, function(){
 367          return new ActiveXObject('Microsoft.XMLHTTP');
 368      });
 369  };
 370  
 371  Browser.Features.xhr = !!(Browser.Request());
 372  
 373  Browser.Plugins.Flash = (function(){
 374      var version = ($try(function(){
 375          return navigator.plugins['Shockwave Flash'].description;
 376      }, function(){
 377          return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
 378      }) || '0 r0').match(/\d+/g);
 379      return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
 380  })();
 381  
 382  function $exec(text){
 383      if (!text) return text;
 384      if (window.execScript){
 385          window.execScript(text);
 386      } else {
 387          var script = document.createElement('script');
 388          script.setAttribute('type', 'text/javascript');
 389          script[(Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerText' : 'text'] = text;
 390          document.head.appendChild(script);
 391          document.head.removeChild(script);
 392      }
 393      return text;
 394  };
 395  
 396  Native.UID = 1;
 397  
 398  var $uid = (Browser.Engine.trident) ? function(item){
 399      return (item.uid || (item.uid = [Native.UID++]))[0];
 400  } : function(item){
 401      return item.uid || (item.uid = Native.UID++);
 402  };
 403  
 404  var Window = new Native({
 405  
 406      name: 'Window',
 407  
 408      legacy: (Browser.Engine.trident) ? null: window.Window,
 409  
 410      initialize: function(win){
 411          $uid(win);
 412          if (!win.Element){
 413              win.Element = $empty;
 414              if (Browser.Engine.webkit) win.document.createElement("iframe"); //fixes safari 2
 415              win.Element.prototype = (Browser.Engine.webkit) ? window["[[DOMElement.prototype]]"] : {};
 416          }
 417          win.document.window = win;
 418          return $extend(win, Window.Prototype);
 419      },
 420  
 421      afterImplement: function(property, value){
 422          window[property] = Window.Prototype[property] = value;
 423      }
 424  
 425  });
 426  
 427  Window.Prototype = {$family: {name: 'window'}};
 428  
 429  new Window(window);
 430  
 431  var Document = new Native({
 432  
 433      name: 'Document',
 434  
 435      legacy: (Browser.Engine.trident) ? null: window.Document,
 436  
 437      initialize: function(doc){
 438          $uid(doc);
 439          doc.head = doc.getElementsByTagName('head')[0];
 440          doc.html = doc.getElementsByTagName('html')[0];
 441          if (Browser.Engine.trident && Browser.Engine.version <= 4) $try(function(){
 442              doc.execCommand("BackgroundImageCache", false, true);
 443          });
 444          if (Browser.Engine.trident) doc.window.attachEvent('onunload', function(){
 445              doc.window.detachEvent('onunload', arguments.callee);
 446              doc.head = doc.html = doc.window = null;
 447          });
 448          return $extend(doc, Document.Prototype);
 449      },
 450  
 451      afterImplement: function(property, value){
 452          document[property] = Document.Prototype[property] = value;
 453      }
 454  
 455  });
 456  
 457  Document.Prototype = {$family: {name: 'document'}};
 458  
 459  new Document(document);
 460  
 461  
 462  /*
 463  ---
 464  
 465  name: Array
 466  
 467  description: Contains Array Prototypes like each, contains, and erase.
 468  
 469  license: MIT-style license.
 470  
 471  requires: [$util, Array.each]
 472  
 473  provides: Array
 474  
 475  ...
 476  */
 477  
 478  Array.implement({
 479  
 480      every: function(fn, bind){
 481          for (var i = 0, l = this.length; i < l; i++){
 482              if (!fn.call(bind, this[i], i, this)) return false;
 483          }
 484          return true;
 485      },
 486  
 487      filter: function(fn, bind){
 488          var results = [];
 489          for (var i = 0, l = this.length; i < l; i++){
 490              if (fn.call(bind, this[i], i, this)) results.push(this[i]);
 491          }
 492          return results;
 493      },
 494  
 495      clean: function(){
 496          return this.filter($defined);
 497      },
 498  
 499      indexOf: function(item, from){
 500          var len = this.length;
 501          for (var i = (from < 0) ? Math.max(0, len + from) : from || 0; i < len; i++){
 502              if (this[i] === item) return i;
 503          }
 504          return -1;
 505      },
 506  
 507      map: function(fn, bind){
 508          var results = [];
 509          for (var i = 0, l = this.length; i < l; i++) results[i] = fn.call(bind, this[i], i, this);
 510          return results;
 511      },
 512  
 513      some: function(fn, bind){
 514          for (var i = 0, l = this.length; i < l; i++){
 515              if (fn.call(bind, this[i], i, this)) return true;
 516          }
 517          return false;
 518      },
 519  
 520      associate: function(keys){
 521          var obj = {}, length = Math.min(this.length, keys.length);
 522          for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
 523          return obj;
 524      },
 525  
 526      link: function(object){
 527          var result = {};
 528          for (var i = 0, l = this.length; i < l; i++){
 529              for (var key in object){
 530                  if (object[key](this[i])){
 531                      result[key] = this[i];
 532                      delete object[key];
 533                      break;
 534                  }
 535              }
 536          }
 537          return result;
 538      },
 539  
 540      contains: function(item, from){
 541          return this.indexOf(item, from) != -1;
 542      },
 543  
 544      extend: function(array){
 545          for (var i = 0, j = array.length; i < j; i++) this.push(array[i]);
 546          return this;
 547      },
 548      
 549      getLast: function(){
 550          return (this.length) ? this[this.length - 1] : null;
 551      },
 552  
 553      getRandom: function(){
 554          return (this.length) ? this[$random(0, this.length - 1)] : null;
 555      },
 556  
 557      include: function(item){
 558          if (!this.contains(item)) this.push(item);
 559          return this;
 560      },
 561  
 562      combine: function(array){
 563          for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
 564          return this;
 565      },
 566  
 567      erase: function(item){
 568          for (var i = this.length; i--; i){
 569              if (this[i] === item) this.splice(i, 1);
 570          }
 571          return this;
 572      },
 573  
 574      empty: function(){
 575          this.length = 0;
 576          return this;
 577      },
 578  
 579      flatten: function(){
 580          var array = [];
 581          for (var i = 0, l = this.length; i < l; i++){
 582              var type = $type(this[i]);
 583              if (!type) continue;
 584              array = array.concat((type == 'array' || type == 'collection' || type == 'arguments') ? Array.flatten(this[i]) : this[i]);
 585          }
 586          return array;
 587      },
 588  
 589      hexToRgb: function(array){
 590          if (this.length != 3) return null;
 591          var rgb = this.map(function(value){
 592              if (value.length == 1) value += value;
 593              return value.toInt(16);
 594          });
 595          return (array) ? rgb : 'rgb(' + rgb + ')';
 596      },
 597  
 598      rgbToHex: function(array){
 599          if (this.length < 3) return null;
 600          if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
 601          var hex = [];
 602          for (var i = 0; i < 3; i++){
 603              var bit = (this[i] - 0).toString(16);
 604              hex.push((bit.length == 1) ? '0' + bit : bit);
 605          }
 606          return (array) ? hex : '#' + hex.join('');
 607      }
 608  
 609  });
 610  
 611  
 612  /*
 613  ---
 614  
 615  name: Function
 616  
 617  description: Contains Function Prototypes like create, bind, pass, and delay.
 618  
 619  license: MIT-style license.
 620  
 621  requires: [Native, $util]
 622  
 623  provides: Function
 624  
 625  ...
 626  */
 627  
 628  try {
 629      delete Function.prototype.bind;
 630  } catch(e){}
 631  
 632  Function.implement({
 633  
 634      extend: function(properties){
 635          for (var property in properties) this[property] = properties[property];
 636          return this;
 637      },
 638  
 639      create: function(options){
 640          var self = this;
 641          options = options || {};
 642          return function(event){
 643              var args = options.arguments;
 644              args = (args != undefined) ? $splat(args) : Array.slice(arguments, (options.event) ? 1 : 0);
 645              if (options.event) args = [event || window.event].extend(args);
 646              var returns = function(){
 647                  return self.apply(options.bind || null, args);
 648              };
 649              if (options.delay) return setTimeout(returns, options.delay);
 650              if (options.periodical) return setInterval(returns, options.periodical);
 651              if (options.attempt) return $try(returns);
 652              return returns();
 653          };
 654      },
 655  
 656      run: function(args, bind){
 657          return this.apply(bind, $splat(args));
 658      },
 659  
 660      pass: function(args, bind){
 661          return this.create({bind: bind, arguments: args});
 662      },
 663  
 664      bind: function(bind, args){
 665          return this.create({bind: bind, arguments: args});
 666      },
 667  
 668      bindWithEvent: function(bind, args){
 669          return this.create({bind: bind, arguments: args, event: true});
 670      },
 671  
 672      attempt: function(args, bind){
 673          return this.create({bind: bind, arguments: args, attempt: true})();
 674      },
 675  
 676      delay: function(delay, bind, args){
 677          return this.create({bind: bind, arguments: args, delay: delay})();
 678      },
 679  
 680      periodical: function(periodical, bind, args){
 681          return this.create({bind: bind, arguments: args, periodical: periodical})();
 682      }
 683  
 684  });
 685  
 686  
 687  /*
 688  ---
 689  
 690  name: Number
 691  
 692  description: Contains Number Prototypes like limit, round, times, and ceil.
 693  
 694  license: MIT-style license.
 695  
 696  requires: [Native, $util]
 697  
 698  provides: Number
 699  
 700  ...
 701  */
 702  
 703  Number.implement({
 704  
 705      limit: function(min, max){
 706          return Math.min(max, Math.max(min, this));
 707      },
 708  
 709      round: function(precision){
 710          precision = Math.pow(10, precision || 0);
 711          return Math.round(this * precision) / precision;
 712      },
 713  
 714      times: function(fn, bind){
 715          for (var i = 0; i < this; i++) fn.call(bind, i, this);
 716      },
 717  
 718      toFloat: function(){
 719          return parseFloat(this);
 720      },
 721  
 722      toInt: function(base){
 723          return parseInt(this, base || 10);
 724      }
 725  
 726  });
 727  
 728  Number.alias('times', 'each');
 729  
 730  (function(math){
 731      var methods = {};
 732      math.each(function(name){
 733          if (!Number[name]) methods[name] = function(){
 734              return Math[name].apply(null, [this].concat($A(arguments)));
 735          };
 736      });
 737      Number.implement(methods);
 738  })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
 739  
 740  
 741  /*
 742  ---
 743  
 744  name: String
 745  
 746  description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
 747  
 748  license: MIT-style license.
 749  
 750  requires: Native
 751  
 752  provides: String
 753  
 754  ...
 755  */
 756  
 757  String.implement({
 758  
 759      test: function(regex, params){
 760          return ((typeof regex == 'string') ? new RegExp(regex, params) : regex).test(this);
 761      },
 762  
 763      contains: function(string, separator){
 764          return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : this.indexOf(string) > -1;
 765      },
 766  
 767      trim: function(){
 768          return this.replace(/^\s+|\s+$/g, '');
 769      },
 770  
 771      clean: function(){
 772          return this.replace(/\s+/g, ' ').trim();
 773      },
 774  
 775      camelCase: function(){
 776          return this.replace(/-\D/g, function(match){
 777              return match.charAt(1).toUpperCase();
 778          });
 779      },
 780  
 781      hyphenate: function(){
 782          return this.replace(/[A-Z]/g, function(match){
 783              return ('-' + match.charAt(0).toLowerCase());
 784          });
 785      },
 786  
 787      capitalize: function(){
 788          return this.replace(/\b[a-z]/g, function(match){
 789              return match.toUpperCase();
 790          });
 791      },
 792  
 793      escapeRegExp: function(){
 794          return this.replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
 795      },
 796  
 797      toInt: function(base){
 798          return parseInt(this, base || 10);
 799      },
 800  
 801      toFloat: function(){
 802          return parseFloat(this);
 803      },
 804  
 805      hexToRgb: function(array){
 806          var hex = this.match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
 807          return (hex) ? hex.slice(1).hexToRgb(array) : null;
 808      },
 809  
 810      rgbToHex: function(array){
 811          var rgb = this.match(/\d{1,3}/g);
 812          return (rgb) ? rgb.rgbToHex(array) : null;
 813      },
 814  
 815      stripScripts: function(option){
 816          var scripts = '';
 817          var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
 818              scripts += arguments[1] + '\n';
 819              return '';
 820          });
 821          if (option === true) $exec(scripts);
 822          else if ($type(option) == 'function') option(scripts, text);
 823          return text;
 824      },
 825  
 826      substitute: function(object, regexp){
 827          return this.replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
 828              if (match.charAt(0) == '\\') return match.slice(1);
 829              return (object[name] != undefined) ? object[name] : '';
 830          });
 831      }
 832  
 833  });
 834  
 835  
 836  /*
 837  ---
 838  
 839  name: Hash
 840  
 841  description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
 842  
 843  license: MIT-style license.
 844  
 845  requires: Hash.base
 846  
 847  provides: Hash
 848  
 849  ...
 850  */
 851  
 852  Hash.implement({
 853  
 854      has: Object.prototype.hasOwnProperty,
 855  
 856      keyOf: function(value){
 857          for (var key in this){
 858              if (this.hasOwnProperty(key) && this[key] === value) return key;
 859          }
 860          return null;
 861      },
 862  
 863      hasValue: function(value){
 864          return (Hash.keyOf(this, value) !== null);
 865      },
 866  
 867      extend: function(properties){
 868          Hash.each(properties || {}, function(value, key){
 869              Hash.set(this, key, value);
 870          }, this);
 871          return this;
 872      },
 873  
 874      combine: function(properties){
 875          Hash.each(properties || {}, function(value, key){
 876              Hash.include(this, key, value);
 877          }, this);
 878          return this;
 879      },
 880  
 881      erase: function(key){
 882          if (this.hasOwnProperty(key)) delete this[key];
 883          return this;
 884      },
 885  
 886      get: function(key){
 887          return (this.hasOwnProperty(key)) ? this[key] : null;
 888      },
 889  
 890      set: function(key, value){
 891          if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
 892          return this;
 893      },
 894  
 895      empty: function(){
 896          Hash.each(this, function(value, key){
 897              delete this[key];
 898          }, this);
 899          return this;
 900      },
 901  
 902      include: function(key, value){
 903          if (this[key] == undefined) this[key] = value;
 904          return this;
 905      },
 906  
 907      map: function(fn, bind){
 908          var results = new Hash;
 909          Hash.each(this, function(value, key){
 910              results.set(key, fn.call(bind, value, key, this));
 911          }, this);
 912          return results;
 913      },
 914  
 915      filter: function(fn, bind){
 916          var results = new Hash;
 917          Hash.each(this, function(value, key){
 918              if (fn.call(bind, value, key, this)) results.set(key, value);
 919          }, this);
 920          return results;
 921      },
 922  
 923      every: function(fn, bind){
 924          for (var key in this){
 925              if (this.hasOwnProperty(key) && !fn.call(bind, this[key], key)) return false;
 926          }
 927          return true;
 928      },
 929  
 930      some: function(fn, bind){
 931          for (var key in this){
 932              if (this.hasOwnProperty(key) && fn.call(bind, this[key], key)) return true;
 933          }
 934          return false;
 935      },
 936  
 937      getKeys: function(){
 938          var keys = [];
 939          Hash.each(this, function(value, key){
 940              keys.push(key);
 941          });
 942          return keys;
 943      },
 944  
 945      getValues: function(){
 946          var values = [];
 947          Hash.each(this, function(value){
 948              values.push(value);
 949          });
 950          return values;
 951      },
 952  
 953      toQueryString: function(base){
 954          var queryString = [];
 955          Hash.each(this, function(value, key){
 956              if (base) key = base + '[' + key + ']';
 957              var result;
 958              switch ($type(value)){
 959                  case 'object': result = Hash.toQueryString(value, key); break;
 960                  case 'array':
 961                      var qs = {};
 962                      value.each(function(val, i){
 963                          qs[i] = val;
 964                      });
 965                      result = Hash.toQueryString(qs, key);
 966                  break;
 967                  default: result = key + '=' + encodeURIComponent(value);
 968              }
 969              if (value != undefined) queryString.push(result);
 970          });
 971  
 972          return queryString.join('&');
 973      }
 974  
 975  });
 976  
 977  Hash.alias({keyOf: 'indexOf', hasValue: 'contains'});
 978  
 979  
 980  /*
 981  ---
 982  
 983  name: Event
 984  
 985  description: Contains the Event Class, to make the event object cross-browser.
 986  
 987  license: MIT-style license.
 988  
 989  requires: [Window, Document, Hash, Array, Function, String]
 990  
 991  provides: Event
 992  
 993  ...
 994  */
 995  
 996  var Event = new Native({
 997  
 998      name: 'Event',
 999  
1000      initialize: function(event, win){
1001          win = win || window;
1002          var doc = win.document;
1003          event = event || win.event;
1004          if (event.$extended) return event;
1005          this.$extended = true;
1006          var type = event.type;
1007          var target = event.target || event.srcElement;
1008          while (target && target.nodeType == 3) target = target.parentNode;
1009  
1010          if (type.test(/key/)){
1011              var code = event.which || event.keyCode;
1012              var key = Event.Keys.keyOf(code);
1013              if (type == 'keydown'){
1014                  var fKey = code - 111;
1015                  if (fKey > 0 && fKey < 13) key = 'f' + fKey;
1016              }
1017              key = key || String.fromCharCode(code).toLowerCase();
1018          } else if (type.match(/(click|mouse|menu)/i)){
1019              doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
1020              var page = {
1021                  x: event.pageX || event.clientX + doc.scrollLeft,
1022                  y: event.pageY || event.clientY + doc.scrollTop
1023              };
1024              var client = {
1025                  x: (event.pageX) ? event.pageX - win.pageXOffset : event.clientX,
1026                  y: (event.pageY) ? event.pageY - win.pageYOffset : event.clientY
1027              };
1028              if (type.match(/DOMMouseScroll|mousewheel/)){
1029                  var wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
1030              }
1031              var rightClick = (event.which == 3) || (event.button == 2);
1032              var related = null;
1033              if (type.match(/over|out/)){
1034                  switch (type){
1035                      case 'mouseover': related = event.relatedTarget || event.fromElement; break;
1036                      case 'mouseout': related = event.relatedTarget || event.toElement;
1037                  }
1038                  if (!(function(){
1039                      while (related && related.nodeType == 3) related = related.parentNode;
1040                      return true;
1041                  }).create({attempt: Browser.Engine.gecko})()) related = false;
1042              }
1043          }
1044  
1045          return $extend(this, {
1046              event: event,
1047              type: type,
1048  
1049              page: page,
1050              client: client,
1051              rightClick: rightClick,
1052  
1053              wheel: wheel,
1054  
1055              relatedTarget: related,
1056              target: target,
1057  
1058              code: code,
1059              key: key,
1060  
1061              shift: event.shiftKey,
1062              control: event.ctrlKey,
1063              alt: event.altKey,
1064              meta: event.metaKey
1065          });
1066      }
1067  
1068  });
1069  
1070  Event.Keys = new Hash({
1071      'enter': 13,
1072      'up': 38,
1073      'down': 40,
1074      'left': 37,
1075      'right': 39,
1076      'esc': 27,
1077      'space': 32,
1078      'backspace': 8,
1079      'tab': 9,
1080      'delete': 46
1081  });
1082  
1083  Event.implement({
1084  
1085      stop: function(){
1086          return this.stopPropagation().preventDefault();
1087      },
1088  
1089      stopPropagation: function(){
1090          if (this.event.stopPropagation) this.event.stopPropagation();
1091          else this.event.cancelBubble = true;
1092          return this;
1093      },
1094  
1095      preventDefault: function(){
1096          if (this.event.preventDefault) this.event.preventDefault();
1097          else this.event.returnValue = false;
1098          return this;
1099      }
1100  
1101  });
1102  
1103  
1104  /*
1105  ---
1106  
1107  name: Class
1108  
1109  description: Contains the Class Function for easily creating, extending, and implementing reusable Classes.
1110  
1111  license: MIT-style license.
1112  
1113  requires: [$util, Native, Array, String, Function, Number, Hash]
1114  
1115  provides: Class
1116  
1117  ...
1118  */
1119  
1120  function Class(params){
1121      
1122      if (params instanceof Function) params = {initialize: params};
1123      
1124      var newClass = function(){
1125          Object.reset(this);
1126          if (newClass._prototyping) return this;
1127          this._current = $empty;
1128          var value = (this.initialize) ? this.initialize.apply(this, arguments) : this;
1129          delete this._current; delete this.caller;
1130          return value;
1131      }.extend(this);
1132      
1133      newClass.implement(params);
1134      
1135      newClass.constructor = Class;
1136      newClass.prototype.constructor = newClass;
1137  
1138      return newClass;
1139  
1140  };
1141  
1142  Function.prototype.protect = function(){
1143      this._protected = true;
1144      return this;
1145  };
1146  
1147  Object.reset = function(object, key){
1148          
1149      if (key == null){
1150          for (var p in object) Object.reset(object, p);
1151          return object;
1152      }
1153      
1154      delete object[key];
1155      
1156      switch ($type(object[key])){
1157          case 'object':
1158              var F = function(){};
1159              F.prototype = object[key];
1160              var i = new F;
1161              object[key] = Object.reset(i);
1162          break;
1163          case 'array': object[key] = $unlink(object[key]); break;
1164      }
1165      
1166      return object;
1167      
1168  };
1169  
1170  new Native({name: 'Class', initialize: Class}).extend({
1171  
1172      instantiate: function(F){
1173          F._prototyping = true;
1174          var proto = new F;
1175          delete F._prototyping;
1176          return proto;
1177      },
1178      
1179      wrap: function(self, key, method){
1180          if (method._origin) method = method._origin;
1181          
1182          return function(){
1183              if (method._protected && this._current == null) throw new Error('The method "' + key + '" cannot be called.');
1184              var caller = this.caller, current = this._current;
1185              this.caller = current; this._current = arguments.callee;
1186              var result = method.apply(this, arguments);
1187              this._current = current; this.caller = caller;
1188              return result;
1189          }.extend({_owner: self, _origin: method, _name: key});
1190  
1191      }
1192      
1193  });
1194  
1195  Class.implement({
1196      
1197      implement: function(key, value){
1198          
1199          if ($type(key) == 'object'){
1200              for (var p in key) this.implement(p, key[p]);
1201              return this;
1202          }
1203          
1204          var mutator = Class.Mutators[key];
1205          
1206          if (mutator){
1207              value = mutator.call(this, value);
1208              if (value == null) return this;
1209          }
1210          
1211          var proto = this.prototype;
1212  
1213          switch ($type(value)){
1214              
1215              case 'function':
1216                  if (value._hidden) return this;
1217                  proto[key] = Class.wrap(this, key, value);
1218              break;
1219              
1220              case 'object':
1221                  var previous = proto[key];
1222                  if ($type(previous) == 'object') $mixin(previous, value);
1223                  else proto[key] = $unlink(value);
1224              break;
1225              
1226              case 'array':
1227                  proto[key] = $unlink(value);
1228              break;
1229              
1230              default: proto[key] = value;
1231  
1232          }
1233          
1234          return this;
1235  
1236      }
1237      
1238  });
1239  
1240  Class.Mutators = {
1241      
1242      Extends: function(parent){
1243  
1244          this.parent = parent;
1245          this.prototype = Class.instantiate(parent);
1246  
1247          this.implement('parent', function(){
1248              var name = this.caller._name, previous = this.caller._owner.parent.prototype[name];
1249              if (!previous) throw new Error('The method "' + name + '" has no parent.');
1250              return previous.apply(this, arguments);
1251          }.protect());
1252  
1253      },
1254  
1255      Implements: function(items){
1256          $splat(items).each(function(item){
1257              if (item instanceof Function) item = Class.instantiate(item);
1258              this.implement(item);
1259          }, this);
1260  
1261      }
1262      
1263  };
1264  
1265  
1266  /*
1267  ---
1268  
1269  name: Class.Extras
1270  
1271  description: Contains Utility Classes that can be implemented into your own Classes to ease the execution of many common tasks.
1272  
1273  license: MIT-style license.
1274  
1275  requires: Class
1276  
1277  provides: [Chain, Events, Options, Class.Extras]
1278  
1279  ...
1280  */
1281  
1282  var Chain = new Class({
1283  
1284      $chain: [],
1285  
1286      chain: function(){
1287          this.$chain.extend(Array.flatten(arguments));
1288          return this;
1289      },
1290  
1291      callChain: function(){
1292          return (this.$chain.length) ? this.$chain.shift().apply(this, arguments) : false;
1293      },
1294  
1295      clearChain: function(){
1296          this.$chain.empty();
1297          return this;
1298      }
1299  
1300  });
1301  
1302  var Events = new Class({
1303  
1304      $events: {},
1305  
1306      addEvent: function(type, fn, internal){
1307          type = Events.removeOn(type);
1308          if (fn != $empty){
1309              this.$events[type] = this.$events[type] || [];
1310              this.$events[type].include(fn);
1311              if (internal) fn.internal = true;
1312          }
1313          return this;
1314      },
1315  
1316      addEvents: function(events){
1317          for (var type in events) this.addEvent(type, events[type]);
1318          return this;
1319      },
1320  
1321      fireEvent: function(type, args, delay){
1322          type = Events.removeOn(type);
1323          if (!this.$events || !this.$events[type]) return this;
1324          this.$events[type].each(function(fn){
1325              fn.create({'bind': this, 'delay': delay, 'arguments': args})();
1326          }, this);
1327          return this;
1328      },
1329  
1330      removeEvent: function(type, fn){
1331          type = Events.removeOn(type);
1332          if (!this.$events[type]) return this;
1333          if (!fn.internal) this.$events[type].erase(fn);
1334          return this;
1335      },
1336  
1337      removeEvents: function(events){
1338          var type;
1339          if ($type(events) == 'object'){
1340              for (type in events) this.removeEvent(type, events[type]);
1341              return this;
1342          }
1343          if (events) events = Events.removeOn(events);
1344          for (type in this.$events){
1345              if (events && events != type) continue;
1346              var fns = this.$events[type];
1347              for (var i = fns.length; i--; i) this.removeEvent(type, fns[i]);
1348          }
1349          return this;
1350      }
1351  
1352  });
1353  
1354  Events.removeOn = function(string){
1355      return string.replace(/^on([A-Z])/, function(full, first){
1356          return first.toLowerCase();
1357      });
1358  };
1359  
1360  var Options = new Class({
1361  
1362      setOptions: function(){
1363          this.options = $merge.run([this.options].extend(arguments));
1364          if (!this.addEvent) return this;
1365          for (var option in this.options){
1366              if ($type(this.options[option]) != 'function' || !(/^on[A-Z]/).test(option)) continue;
1367              this.addEvent(option, this.options[option]);
1368              delete this.options[option];
1369          }
1370          return this;
1371      }
1372  
1373  });
1374  
1375  
1376  /*
1377  ---
1378  
1379  name: Element
1380  
1381  description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements.
1382  
1383  license: MIT-style license.
1384  
1385  requires: [Window, Document, Array, String, Function, Number, Hash]
1386  
1387  provides: [Element, Elements, $, $$, Iframe]
1388  
1389  ...
1390  */
1391  
1392  var Element = new Native({
1393  
1394      name: 'Element',
1395  
1396      legacy: window.Element,
1397  
1398      initialize: function(tag, props){
1399          var konstructor = Element.Constructors.get(tag);
1400          if (konstructor) return konstructor(props);
1401          if (typeof tag == 'string') return document.newElement(tag, props);
1402          return document.id(tag).set(props);
1403      },
1404  
1405      afterImplement: function(key, value){
1406          Element.Prototype[key] = value;
1407          if (Array[key]) return;
1408          Elements.implement(key, function(){
1409              var items = [], elements = true;
1410              for (var i = 0, j = this.length; i < j; i++){
1411                  var returns = this[i][key].apply(this[i], arguments);
1412                  items.push(returns);
1413                  if (elements) elements = ($type(returns) == 'element');
1414              }
1415              return (elements) ? new Elements(items) : items;
1416          });
1417      }
1418  
1419  });
1420  
1421  Element.Prototype = {$family: {name: 'element'}};
1422  
1423  Element.Constructors = new Hash;
1424  
1425  var IFrame = new Native({
1426  
1427      name: 'IFrame',
1428  
1429      generics: false,
1430  
1431      initialize: function(){
1432          var params = Array.link(arguments, {properties: Object.type, iframe: $defined});
1433          var props = params.properties || {};
1434          var iframe = document.id(params.iframe);
1435          var onload = props.onload || $empty;
1436          delete props.onload;
1437          props.id = props.name = $pick(props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + $time());
1438          iframe = new Element(iframe || 'iframe', props);
1439          var onFrameLoad = function(){
1440              var host = $try(function(){
1441                  return iframe.contentWindow.location.host;
1442              });
1443              if (!host || host == window.location.host){
1444                  var win = new Window(iframe.contentWindow);
1445                  new Document(iframe.contentWindow.document);
1446                  $extend(win.Element.prototype, Element.Prototype);
1447              }
1448              onload.call(iframe.contentWindow, iframe.contentWindow.document);
1449          };
1450          var contentWindow = $try(function(){
1451              return iframe.contentWindow;
1452          });
1453          ((contentWindow && contentWindow.document.body) || window.frames[props.id]) ? onFrameLoad() : iframe.addListener('load', onFrameLoad);
1454          return iframe;
1455      }
1456  
1457  });
1458  
1459  var Elements = new Native({
1460  
1461      initialize: function(elements, options){
1462          options = $extend({ddup: true, cash: true}, options);
1463          elements = elements || [];
1464          if (options.ddup || options.cash){
1465              var uniques = {}, returned = [];
1466              for (var i = 0, l = elements.length; i < l; i++){
1467                  var el = document.id(elements[i], !options.cash);
1468                  if (options.ddup){
1469                      if (uniques[el.uid]) continue;
1470                      uniques[el.uid] = true;
1471                  }
1472                  if (el) returned.push(el);
1473              }
1474              elements = returned;
1475          }
1476          return (options.cash) ? $extend(elements, this) : elements;
1477      }
1478  
1479  });
1480  
1481  Elements.implement({
1482  
1483      filter: function(filter, bind){
1484          if (!filter) return this;
1485          return new Elements(Array.filter(this, (typeof filter == 'string') ? function(item){
1486              return item.match(filter);
1487          } : filter, bind));
1488      }
1489  
1490  });
1491  
1492  (function(){
1493  
1494  /*<ltIE8>*/
1495  var createElementAcceptsHTML;
1496  try {
1497      var x = document.createElement('<input name=x>');
1498      createElementAcceptsHTML = (x.name == 'x');
1499  } catch(e){}
1500  
1501  var escapeQuotes = function(html){
1502      return ('' + html).replace(/&/g,'&amp;').replace(/"/g,'&quot;');
1503  };
1504  /*</ltIE8>*/
1505  
1506  Document.implement({
1507  
1508      newElement: function(tag, props){
1509          if (props && props.checked != null) props.defaultChecked = props.checked;
1510          /*<ltIE8>*/// Fix for readonly name and type properties in IE < 8
1511          if (createElementAcceptsHTML && props){
1512              tag = '<' + tag;
1513              if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"';
1514              if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"';
1515              tag += '>';
1516              delete props.name;
1517              delete props.type;
1518          }
1519          /*</ltIE8>*/
1520          return this.id(this.createElement(tag)).set(props);
1521      },
1522  
1523      newTextNode: function(text){
1524          return this.createTextNode(text);
1525      },
1526  
1527      getDocument: function(){
1528          return this;
1529      },
1530  
1531      getWindow: function(){
1532          return this.window;
1533      },
1534      
1535      id: (function(){
1536          
1537          var types = {
1538  
1539              string: function(id, nocash, doc){
1540                  id = doc.getElementById(id);
1541                  return (id) ? types.element(id, nocash) : null;
1542              },
1543              
1544              element: function(el, nocash){
1545                  $uid(el);
1546                  if (!nocash && !el.$family && !(/^object|embed$/i).test(el.tagName)){
1547                      var proto = Element.Prototype;
1548                      for (var p in proto) el[p] = proto[p];
1549                  };
1550                  return el;
1551              },
1552              
1553              object: function(obj, nocash, doc){
1554                  if (obj.toElement) return types.element(obj.toElement(doc), nocash);
1555                  return null;
1556              }
1557              
1558          };
1559  
1560          types.textnode = types.whitespace = types.window = types.document = $arguments(0);
1561          
1562          return function(el, nocash, doc){
1563              if (el && el.$family && el.uid) return el;
1564              var type = $type(el);
1565              return (types[type]) ? types[type](el, nocash, doc || document) : null;
1566          };
1567  
1568      })()
1569  
1570  });
1571  
1572  })();
1573  
1574  if (window.$ == null) Window.implement({
1575      $: function(el, nc){
1576          return document.id(el, nc, this.document);
1577      }
1578  });
1579  
1580  Window.implement({
1581  
1582      $$: function(selector){
1583          if (arguments.length == 1 && typeof selector == 'string') return this.document.getElements(selector);
1584          var elements = [];
1585          var args = Array.flatten(arguments);
1586          for (var i = 0, l = args.length; i < l; i++){
1587              var item = args[i];
1588              switch ($type(item)){
1589                  case 'element': elements.push(item); break;
1590                  case 'string': elements.extend(this.document.getElements(item, true));
1591              }
1592          }
1593          return new Elements(elements);
1594      },
1595  
1596      getDocument: function(){
1597          return this.document;
1598      },
1599  
1600      getWindow: function(){
1601          return this;
1602      }
1603  
1604  });
1605  
1606  Native.implement([Element, Document], {
1607  
1608      getElement: function(selector, nocash){
1609          return document.id(this.getElements(selector, true)[0] || null, nocash);
1610      },
1611  
1612      getElements: function(tags, nocash){
1613          tags = tags.split(',');
1614          var elements = [];
1615          var ddup = (tags.length > 1);
1616          tags.each(function(tag){
1617              var partial = this.getElementsByTagName(tag.trim());
1618              (ddup) ? elements.extend(partial) : elements = partial;
1619          }, this);
1620          return new Elements(elements, {ddup: ddup, cash: !nocash});
1621      }
1622  
1623  });
1624  
1625  (function(){
1626  
1627  var collected = {}, storage = {};
1628  var props = {input: 'checked', option: 'selected', textarea: (Browser.Engine.webkit && Browser.Engine.version < 420) ? 'innerHTML' : 'value'};
1629  
1630  var get = function(uid){
1631      return (storage[uid] || (storage[uid] = {}));
1632  };
1633  
1634  var clean = function(item, retain){
1635      if (!item) return;
1636      var uid = item.uid;
1637      if (retain !== true) retain = false;
1638      if (Browser.Engine.trident){
1639          if (item.clearAttributes){
1640              var clone = retain && item.cloneNode(false);
1641              item.clearAttributes();
1642              if (clone) item.mergeAttributes(clone);
1643          } else if (item.removeEvents){
1644              item.removeEvents();
1645          }
1646          if ((/object/i).test(item.tagName)){
1647              for (var p in item){
1648                  if (typeof item[p] == 'function') item[p] = $empty;
1649              }
1650              Element.dispose(item);
1651          }
1652      }    
1653      if (!uid) return;
1654      collected[uid] = storage[uid] = null;
1655  };
1656  
1657  var purge = function(){
1658      Hash.each(collected, clean);
1659      if (Browser.Engine.trident) $A(document.getElementsByTagName('object')).each(clean);
1660      if (window.CollectGarbage) CollectGarbage();
1661      collected = storage = null;
1662  };
1663  
1664  var walk = function(element, walk, start, match, all, nocash){
1665      var el = element[start || walk];
1666      var elements = [];
1667      while (el){
1668          if (el.nodeType == 1 && (!match || Element.match(el, match))){
1669              if (!all) return document.id(el, nocash);
1670              elements.push(el);
1671          }
1672          el = el[walk];
1673      }
1674      return (all) ? new Elements(elements, {ddup: false, cash: !nocash}) : null;
1675  };
1676  
1677  var attributes = {
1678      'html': 'innerHTML',
1679      'class': 'className',
1680      'for': 'htmlFor',
1681      'defaultValue': 'defaultValue',
1682      'text': (Browser.Engine.trident || (Browser.Engine.webkit && Browser.Engine.version < 420)) ? 'innerText' : 'textContent'
1683  };
1684  var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readonly', 'multiple', 'selected', 'noresize', 'defer'];
1685  var camels = ['value', 'type', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap'];
1686  
1687  bools = bools.associate(bools);
1688  
1689  Hash.extend(attributes, bools);
1690  Hash.extend(attributes, camels.associate(camels.map(String.toLowerCase)));
1691  
1692  var inserters = {
1693  
1694      before: function(context, element){
1695          if (element.parentNode) element.parentNode.insertBefore(context, element);
1696      },
1697  
1698      after: function(context, element){
1699          if (!element.parentNode) return;
1700          var next = element.nextSibling;
1701          (next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context);
1702      },
1703  
1704      bottom: function(context, element){
1705          element.appendChild(context);
1706      },
1707  
1708      top: function(context, element){
1709          var first = element.firstChild;
1710          (first) ? element.insertBefore(context, first) : element.appendChild(context);
1711      }
1712  
1713  };
1714  
1715  inserters.inside = inserters.bottom;
1716  
1717  Hash.each(inserters, function(inserter, where){
1718  
1719      where = where.capitalize();
1720  
1721      Element.implement('inject' + where, function(el){
1722          inserter(this, document.id(el, true));
1723          return this;
1724      });
1725  
1726      Element.implement('grab' + where, function(el){
1727          inserter(document.id(el, true), this);
1728          return this;
1729      });
1730  
1731  });
1732  
1733  Element.implement({
1734  
1735      set: function(prop, value){
1736          switch ($type(prop)){
1737              case 'object':
1738                  for (var p in prop) this.set(p, prop[p]);
1739                  break;
1740              case 'string':
1741                  var property = Element.Properties.get(prop);
1742                  (property && property.set) ? property.set.apply(this, Array.slice(arguments, 1)) : this.setProperty(prop, value);
1743          }
1744          return this;
1745      },
1746  
1747      get: function(prop){
1748          var property = Element.Properties.get(prop);
1749          return (property && property.get) ? property.get.apply(this, Array.slice(arguments, 1)) : this.getProperty(prop);
1750      },
1751  
1752      erase: function(prop){
1753          var property = Element.Properties.get(prop);
1754          (property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
1755          return this;
1756      },
1757  
1758      setProperty: function(attribute, value){
1759          var key = attributes[attribute];
1760          if (value == undefined) return this.removeProperty(attribute);
1761          if (key && bools[attribute]) value = !!value;
1762          (key) ? this[key] = value : this.setAttribute(attribute, '' + value);
1763          return this;
1764      },
1765  
1766      setProperties: function(attributes){
1767          for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]);
1768          return this;
1769      },
1770  
1771      getProperty: function(attribute){
1772          var key = attributes[attribute];
1773          var value = (key) ? this[key] : this.getAttribute(attribute, 2);
1774          return (bools[attribute]) ? !!value : (key) ? value : value || null;
1775      },
1776  
1777      getProperties: function(){
1778          var args = $A(arguments);
1779          return args.map(this.getProperty, this).associate(args);
1780      },
1781  
1782      removeProperty: function(attribute){
1783          var key = attributes[attribute];
1784          (key) ? this[key] = (key && bools[attribute]) ? false : '' : this.removeAttribute(attribute);
1785          return this;
1786      },
1787  
1788      removeProperties: function(){
1789          Array.each(arguments, this.removeProperty, this);
1790          return this;
1791      },
1792  
1793      hasClass: function(className){
1794          return this.className.contains(className, ' ');
1795      },
1796  
1797      addClass: function(className){
1798          if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean();
1799          return this;
1800      },
1801  
1802      removeClass: function(className){
1803          this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1');
1804          return this;
1805      },
1806  
1807      toggleClass: function(className){
1808          return this.hasClass(className) ? this.removeClass(className) : this.addClass(className);
1809      },
1810  
1811      adopt: function(){
1812          Array.flatten(arguments).each(function(element){
1813              element = document.id(element, true);
1814              if (element) this.appendChild(element);
1815          }, this);
1816          return this;
1817      },
1818  
1819      appendText: function(text, where){
1820          return this.grab(this.getDocument().newTextNode(text), where);
1821      },
1822  
1823      grab: function(el, where){
1824          inserters[where || 'bottom'](document.id(el, true), this);
1825          return this;
1826      },
1827  
1828      inject: function(el, where){
1829          inserters[where || 'bottom'](this, document.id(el, true));
1830          return this;
1831      },
1832  
1833      replaces: function(el){
1834          el = document.id(el, true);
1835          el.parentNode.replaceChild(this, el);
1836          return this;
1837      },
1838  
1839      wraps: function(el, where){
1840          el = document.id(el, true);
1841          return this.replaces(el).grab(el, where);
1842      },
1843  
1844      getPrevious: function(match, nocash){
1845          return walk(this, 'previousSibling', null, match, false, nocash);
1846      },
1847  
1848      getAllPrevious: function(match, nocash){
1849          return walk(this, 'previousSibling', null, match, true, nocash);
1850      },
1851  
1852      getNext: function(match, nocash){
1853          return walk(this, 'nextSibling', null, match, false, nocash);
1854      },
1855  
1856      getAllNext: function(match, nocash){
1857          return walk(this, 'nextSibling', null, match, true, nocash);
1858      },
1859  
1860      getFirst: function(match, nocash){
1861          return walk(this, 'nextSibling', 'firstChild', match, false, nocash);
1862      },
1863  
1864      getLast: function(match, nocash){
1865          return walk(this, 'previousSibling', 'lastChild', match, false, nocash);
1866      },
1867  
1868      getParent: function(match, nocash){
1869          return walk(this, 'parentNode', null, match, false, nocash);
1870      },
1871  
1872      getParents: function(match, nocash){
1873          return walk(this, 'parentNode', null, match, true, nocash);
1874      },
1875      
1876      getSiblings: function(match, nocash){
1877          return this.getParent().getChildren(match, nocash).erase(this);
1878      },
1879  
1880      getChildren: function(match, nocash){
1881          return walk(this, 'nextSibling', 'firstChild', match, true, nocash);
1882      },
1883  
1884      getWindow: function(){
1885          return this.ownerDocument.window;
1886      },
1887  
1888      getDocument: function(){
1889          return this.ownerDocument;
1890      },
1891  
1892      getElementById: function(id, nocash){
1893          var el = this.ownerDocument.getElementById(id);
1894          if (!el) return null;
1895          for (var parent = el.parentNode; parent != this; parent = parent.parentNode){
1896              if (!parent) return null;
1897          }
1898          return document.id(el, nocash);
1899      },
1900  
1901      getSelected: function(){
1902          return new Elements($A(this.options).filter(function(option){
1903              return option.selected;
1904          }));
1905      },
1906  
1907      getComputedStyle: function(property){
1908          if (this.currentStyle) return this.currentStyle[property.camelCase()];
1909          var computed = this.getDocument().defaultView.getComputedStyle(this, null);
1910          return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null;
1911      },
1912  
1913      toQueryString: function(){
1914          var queryString = [];
1915          this.getElements('input, select, textarea', true).each(function(el){
1916              if (!el.name || el.disabled || el.type == 'submit' || el.type == 'reset' || el.type == 'file') return;
1917              var value = (el.tagName.toLowerCase() == 'select') ? Element.getSelected(el).map(function(opt){
1918                  return opt.value;
1919              }) : ((el.type == 'radio' || el.type == 'checkbox') && !el.checked) ? null : el.value;
1920              $splat(value).each(function(val){
1921                  if (typeof val != 'undefined') queryString.push(el.name + '=' + encodeURIComponent(val));
1922              });
1923          });
1924          return queryString.join('&');
1925      },
1926  
1927      clone: function(contents, keepid){
1928          contents = contents !== false;
1929          var clone = this.cloneNode(contents);
1930          var clean = function(node, element){
1931              if (!keepid) node.removeAttribute('id');
1932              if (Browser.Engine.trident){
1933                  node.clearAttributes();
1934                  node.mergeAttributes(element);
1935                  node.removeAttribute('uid');
1936                  if (node.options){
1937                      var no = node.options, eo = element.options;
1938                      for (var j = no.length; j--;) no[j].selected = eo[j].selected;
1939                  }
1940              }
1941              var prop = props[element.tagName.toLowerCase()];
1942              if (prop && element[prop]) node[prop] = element[prop];
1943          };
1944  
1945          if (contents){
1946              var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*');
1947              for (var i = ce.length; i--;) clean(ce[i], te[i]);
1948          }
1949  
1950          clean(clone, this);
1951          return document.id(clone);
1952      },
1953  
1954      destroy: function(){
1955          Element.empty(this);
1956          Element.dispose(this);
1957          clean(this, true);
1958          return null;
1959      },
1960  
1961      empty: function(){
1962          $A(this.childNodes).each(function(node){
1963              Element.destroy(node);
1964          });
1965          return this;
1966      },
1967  
1968      dispose: function(){
1969          return (this.parentNode) ? this.parentNode.removeChild(this) : this;
1970      },
1971  
1972      hasChild: function(el){
1973          el = document.id(el, true);
1974          if (!el) return false;
1975          if (Browser.Engine.webkit && Browser.Engine.version < 420) return $A(this.getElementsByTagName(el.tagName)).contains(el);
1976          return (this.contains) ? (this != el && this.contains(el)) : !!(this.compareDocumentPosition(el) & 16);
1977      },
1978  
1979      match: function(tag){
1980          return (!tag || (tag == this) || (Element.get(this, 'tag') == tag));
1981      }
1982  
1983  });
1984  
1985  Native.implement([Element, Window, Document], {
1986  
1987      addListener: function(type, fn){
1988          if (type == 'unload'){
1989              var old = fn, self = this;
1990              fn = function(){
1991                  self.removeListener('unload', fn);
1992                  old();
1993              };
1994          } else {
1995              collected[this.uid] = this;
1996          }
1997          if (this.addEventListener) this.addEventListener(type, fn, false);
1998          else this.attachEvent('on' + type, fn);
1999          return this;
2000      },
2001  
2002      removeListener: function(type, fn){
2003          if (this.removeEventListener) this.removeEventListener(type, fn, false);
2004          else this.detachEvent('on' + type, fn);
2005          return this;
2006      },
2007  
2008      retrieve: function(property, dflt){
2009          var storage = get(this.uid), prop = storage[property];
2010          if (dflt != undefined && prop == undefined) prop = storage[property] = dflt;
2011          return $pick(prop);
2012      },
2013  
2014      store: function(property, value){
2015          var storage = get(this.uid);
2016          storage[property] = value;
2017          return this;
2018      },
2019  
2020      eliminate: function(property){
2021          var storage = get(this.uid);
2022          delete storage[property];
2023          return this;
2024      }
2025  
2026  });
2027  
2028  window.addListener('unload', purge);
2029  
2030  })();
2031  
2032  Element.Properties = new Hash;
2033  
2034  Element.Properties.style = {
2035  
2036      set: function(style){
2037          this.style.cssText = style;
2038      },
2039  
2040      get: function(){
2041          return this.style.cssText;
2042      },
2043  
2044      erase: function(){
2045          this.style.cssText = '';
2046      }
2047  
2048  };
2049  
2050  Element.Properties.tag = {
2051  
2052      get: function(){
2053          return this.tagName.toLowerCase();
2054      }
2055  
2056  };
2057  
2058  Element.Properties.html = (function(){
2059      var wrapper = document.createElement('div');
2060  
2061      var translations = {
2062          table: [1, '<table>', '</table>'],
2063          select: [1, '<select>', '</select>'],
2064          tbody: [2, '<table><tbody>', '</tbody></table>'],
2065          tr: [3, '<table><tbody><tr>', '</tr></tbody></table>']
2066      };
2067      translations.thead = translations.tfoot = translations.tbody;
2068  
2069      var html = {
2070          set: function(){
2071              var html = Array.flatten(arguments).join('');
2072              var wrap = Browser.Engine.trident && translations[this.get('tag')];
2073              if (wrap){
2074                  var first = wrapper;
2075                  first.innerHTML = wrap[1] + html + wrap[2];
2076                  for (var i = wrap[0]; i--;) first = first.firstChild;
2077                  this.empty().adopt(first.childNodes);
2078              } else {
2079                  this.innerHTML = html;
2080              }
2081          }
2082      };
2083  
2084      html.erase = html.set;
2085  
2086      return html;
2087  })();
2088  
2089  if (Browser.Engine.webkit && Browser.Engine.version < 420) Element.Properties.text = {
2090      get: function(){
2091          if (this.innerText) return this.innerText;
2092          var temp = this.ownerDocument.newElement('div', {html: this.innerHTML}).inject(this.ownerDocument.body);
2093          var text = temp.innerText;
2094          temp.destroy();
2095          return text;
2096      }
2097  };
2098  
2099  
2100  /*
2101  ---
2102  
2103  name: Element.Event
2104  
2105  description: Contains Element methods for dealing with events. This file also includes mouseenter and mouseleave custom Element Events.
2106  
2107  license: MIT-style license.
2108  
2109  requires: [Element, Event]
2110  
2111  provides: Element.Event
2112  
2113  ...
2114  */
2115  
2116  Element.Properties.events = {set: function(events){
2117      this.addEvents(events);
2118  }};
2119  
2120  Native.implement([Element, Window, Document], {
2121  
2122      addEvent: function(type, fn){
2123          var events = this.retrieve('events', {});
2124          events[type] = events[type] || {'keys': [], 'values': []};
2125          if (events[type].keys.contains(fn)) return this;
2126          events[type].keys.push(fn);
2127          var realType = type, custom = Element.Events.get(type), condition = fn, self = this;
2128          if (custom){
2129              if (custom.onAdd) custom.onAdd.call(this, fn);
2130              if (custom.condition){
2131                  condition = function(event){
2132                      if (custom.condition.call(this, event)) return fn.call(this, event);
2133                      return true;
2134                  };
2135              }
2136              realType = custom.base || realType;
2137          }
2138          var defn = function(){
2139              return fn.call(self);
2140          };
2141          var nativeEvent = Element.NativeEvents[realType];
2142          if (nativeEvent){
2143              if (nativeEvent == 2){
2144                  defn = function(event){
2145                      event = new Event(event, self.getWindow());
2146                      if (condition.call(self, event) === false) event.stop();
2147                  };
2148              }
2149              this.addListener(realType, defn);
2150          }
2151          events[type].values.push(defn);
2152          return this;
2153      },
2154  
2155      removeEvent: function(type, fn){
2156          var events = this.retrieve('events');
2157          if (!events || !events[type]) return this;
2158          var pos = events[type].keys.indexOf(fn);
2159          if (pos == -1) return this;
2160          events[type].keys.splice(pos, 1);
2161          var value = events[type].values.splice(pos, 1)[0];
2162          var custom = Element.Events.get(type);
2163          if (custom){
2164              if (custom.onRemove) custom.onRemove.call(this, fn);
2165              type = custom.base || type;
2166          }
2167          return (Element.NativeEvents[type]) ? this.removeListener(type, value) : this;
2168      },
2169  
2170      addEvents: function(events){
2171          for (var event in events) this.addEvent(event, events[event]);
2172          return this;
2173      },
2174  
2175      removeEvents: function(events){
2176          var type;
2177          if ($type(events) == 'object'){
2178              for (type in events) this.removeEvent(type, events[type]);
2179              return this;
2180          }
2181          var attached = this.retrieve('events');
2182          if (!attached) return this;
2183          if (!events){
2184              for (type in attached) this.removeEvents(type);
2185              this.eliminate('events');
2186          } else if (attached[events]){
2187              while (attached[events].keys[0]) this.removeEvent(events, attached[events].keys[0]);
2188              attached[events] = null;
2189          }
2190          return this;
2191      },
2192  
2193      fireEvent: function(type, args, delay){
2194          var events = this.retrieve('events');
2195          if (!events || !events[type]) return this;
2196          events[type].keys.each(function(fn){
2197              fn.create({'bind': this, 'delay': delay, 'arguments': args})();
2198          }, this);
2199          return this;
2200      },
2201  
2202      cloneEvents: function(from, type){
2203          from = document.id(from);
2204          var fevents = from.retrieve('events');
2205          if (!fevents) return this;
2206          if (!type){
2207              for (var evType in fevents) this.cloneEvents(from, evType);
2208          } else if (fevents[type]){
2209              fevents[type].keys.each(function(fn){
2210                  this.addEvent(type, fn);
2211              }, this);
2212          }
2213          return this;
2214      }
2215  
2216  });
2217  
2218  // IE9
2219  try {
2220      if (typeof HTMLElement != 'undefined')
2221          HTMLElement.prototype.fireEvent = Element.prototype.fireEvent;
2222  } catch(e){}
2223  
2224  Element.NativeEvents = {
2225      click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse buttons
2226      mousewheel: 2, DOMMouseScroll: 2, //mouse wheel
2227      mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse movement
2228      keydown: 2, keypress: 2, keyup: 2, //keyboard
2229      focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, //form elements
2230      load: 1, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1, readystatechange: 1, //window
2231      error: 1, abort: 1, scroll: 1 //misc
2232  };
2233  
2234  (function(){
2235  
2236  var $check = function(event){
2237      var related = event.relatedTarget;
2238      if (related == undefined) return true;
2239      if (related === false) return false;
2240      return ($type(this) != 'document' && related != this && related.prefix != 'xul' && !this.hasChild(related));
2241  };
2242  
2243  Element.Events = new Hash({
2244  
2245      mouseenter: {
2246          base: 'mouseover',
2247          condition: $check
2248      },
2249  
2250      mouseleave: {
2251          base: 'mouseout',
2252          condition: $check
2253      },
2254  
2255      mousewheel: {
2256          base: (Browser.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel'
2257      }
2258  
2259  });
2260  
2261  })();
2262  
2263  
2264  /*
2265  ---
2266  
2267  name: Element.Style
2268  
2269  description: Contains methods for interacting with the styles of Elements in a fashionable way.
2270  
2271  license: MIT-style license.
2272  
2273  requires: Element
2274  
2275  provides: Element.Style
2276  
2277  ...
2278  */
2279  
2280  Element.Properties.styles = {set: function(styles){
2281      this.setStyles(styles);
2282  }};
2283  
2284  Element.Properties.opacity = {
2285  
2286      set: function(opacity, novisibility){
2287          if (!novisibility){
2288              if (opacity == 0){
2289                  if (this.style.visibility != 'hidden') this.style.visibility = 'hidden';
2290              } else {
2291                  if (this.style.visibility != 'visible') this.style.visibility = 'visible';
2292              }
2293          }
2294          if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
2295          if (Browser.Engine.trident) this.style.filter = (opacity == 1) ? '' : 'alpha(opacity=' + opacity * 100 + ')';
2296          this.style.opacity = opacity;
2297          this.store('opacity', opacity);
2298      },
2299  
2300      get: function(){
2301          return this.retrieve('opacity', 1);
2302      }
2303  
2304  };
2305  
2306  Element.implement({
2307  
2308      setOpacity: function(value){
2309          return this.set('opacity', value, true);
2310      },
2311  
2312      getOpacity: function(){
2313          return this.get('opacity');
2314      },
2315  
2316      setStyle: function(property, value){
2317          switch (property){
2318              case 'opacity': return this.set('opacity', parseFloat(value));
2319              case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
2320          }
2321          property = property.camelCase();
2322          if ($type(value) != 'string'){
2323              var map = (Element.Styles.get(property) || '@').split(' ');
2324              value = $splat(value).map(function(val, i){
2325                  if (!map[i]) return '';
2326                  return ($type(val) == 'number') ? map[i].replace('@', Math.round(val)) : val;
2327              }).join(' ');
2328          } else if (value == String(Number(value))){
2329              value = Math.round(value);
2330          }
2331          this.style[property] = value;
2332          return this;
2333      },
2334  
2335      getStyle: function(property){
2336          switch (property){
2337              case 'opacity': return this.get('opacity');
2338              case 'float': property = (Browser.Engine.trident) ? 'styleFloat' : 'cssFloat';
2339          }
2340          property = property.camelCase();
2341          var result = this.style[property];
2342          if (!$chk(result)){
2343              result = [];
2344              for (var style in Element.ShortStyles){
2345                  if (property != style) continue;
2346                  for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s));
2347                  return result.join(' ');
2348              }
2349              result = this.getComputedStyle(property);
2350          }
2351          if (result){
2352              result = String(result);
2353              var color = result.match(/rgba?\([\d\s,]+\)/);
2354              if (color) result = result.replace(color[0], color[0].rgbToHex());
2355          }
2356          if (Browser.Engine.presto || (Browser.Engine.trident && !$chk(parseInt(result, 10)))){
2357              if (property.test(/^(height|width)$/)){
2358                  var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom'], size = 0;
2359                  values.each(function(value){
2360                      size += this.getStyle('border-' + value + '-width').toInt() + this.getStyle('padding-' + value).toInt();
2361                  }, this);
2362                  return this['offset' + property.capitalize()] - size + 'px';
2363              }
2364              if ((Browser.Engine.presto) && String(result).test('px')) return result;
2365              if (property.test(/(border(.+)Width|margin|padding)/)) return '0px';
2366          }
2367          return result;
2368      },
2369  
2370      setStyles: function(styles){
2371          for (var style in styles) this.setStyle(style, styles[style]);
2372          return this;
2373      },
2374  
2375      getStyles: function(){
2376          var result = {};
2377          Array.flatten(arguments).each(function(key){
2378              result[key] = this.getStyle(key);
2379          }, this);
2380          return result;
2381      }
2382  
2383  });
2384  
2385  Element.Styles = new Hash({
2386      left: '@px', top: '@px', bottom: '@px', right: '@px',
2387      width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px', minHeight: '@px',
2388      backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@, @, @)',
2389      fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px @px @px)',
2390      margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)',
2391      borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)',
2392      zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@'
2393  });
2394  
2395  Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, borderStyle: {}, borderColor: {}};
2396  
2397  ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){
2398      var Short = Element.ShortStyles;
2399      var All = Element.Styles;
2400      ['margin', 'padding'].each(function(style){
2401          var sd = style + direction;
2402          Short[style][sd] = All[sd] = '@px';
2403      });
2404      var bd = 'border' + direction;
2405      Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)';
2406      var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color';
2407      Short[bd] = {};
2408      Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px';
2409      Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@';
2410      Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)';
2411  });
2412  
2413  
2414  /*
2415  ---
2416  
2417  name: Element.Dimensions
2418  
2419  description: Contains methods to work with size, scroll, or positioning of Elements and the window object.
2420  
2421  license: MIT-style license.
2422  
2423  credits:
2424    - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and smart browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html).
2425    - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [BSD License](http://developer.yahoo.com/yui/license.html).
2426  
2427  requires: Element
2428  
2429  provides: Element.Dimensions
2430  
2431  ...
2432  */
2433  
2434  (function(){
2435  
2436  Element.implement({
2437  
2438      scrollTo: function(x, y){
2439          if (isBody(this)){
2440              this.getWindow().scrollTo(x, y);
2441          } else {
2442              this.scrollLeft = x;
2443              this.scrollTop = y;
2444          }
2445          return this;
2446      },
2447  
2448      getSize: function(){
2449          if (isBody(this)) return this.getWindow().getSize();
2450          return {x: this.offsetWidth, y: this.offsetHeight};
2451      },
2452  
2453      getScrollSize: function(){
2454          if (isBody(this)) return this.getWindow().getScrollSize();
2455          return {x: this.scrollWidth, y: this.scrollHeight};
2456      },
2457  
2458      getScroll: function(){
2459          if (isBody(this)) return this.getWindow().getScroll();
2460          return {x: this.scrollLeft, y: this.scrollTop};
2461      },
2462  
2463      getScrolls: function(){
2464          var element = this, position = {x: 0, y: 0};
2465          while (element && !isBody(element)){
2466              position.x += element.scrollLeft;
2467              position.y += element.scrollTop;
2468              element = element.parentNode;
2469          }
2470          return position;
2471      },
2472  
2473      getOffsetParent: function(){
2474          var element = this;
2475          if (isBody(element)) return null;
2476          if (!Browser.Engine.trident) return element.offsetParent;
2477          while ((element = element.parentNode) && !isBody(element)){
2478              if (styleString(element, 'position') != 'static') return element;
2479          }
2480          return null;
2481      },
2482  
2483      getOffsets: function(){
2484          if (this.getBoundingClientRect){
2485              var bound = this.getBoundingClientRect(),
2486                  html = document.id(this.getDocument().documentElement),
2487                  htmlScroll = html.getScroll(),
2488                  elemScrolls = this.getScrolls(),
2489                  elemScroll = this.getScroll(),
2490                  isFixed = (styleString(this, 'position') == 'fixed');
2491  
2492              return {
2493                  x: bound.left.toInt() + elemScrolls.x - elemScroll.x + ((isFixed) ? 0 : htmlScroll.x) - html.clientLeft,
2494                  y: bound.top.toInt()  + elemScrolls.y - elemScroll.y + ((isFixed) ? 0 : htmlScroll.y) - html.clientTop
2495              };
2496          }
2497  
2498          var element = this, position = {x: 0, y: 0};
2499          if (isBody(this)) return position;
2500  
2501          while (element && !isBody(element)){
2502              position.x += element.offsetLeft;
2503              position.y += element.offsetTop;
2504  
2505              if (Browser.Engine.gecko){
2506                  if (!borderBox(element)){
2507                      position.x += leftBorder(element);
2508                      position.y += topBorder(element);
2509                  }
2510                  var parent = element.parentNode;
2511                  if (parent && styleString(parent, 'overflow') != 'visible'){
2512                      position.x += leftBorder(parent);
2513                      position.y += topBorder(parent);
2514                  }
2515              } else if (element != this && Browser.Engine.webkit){
2516                  position.x += leftBorder(element);
2517                  position.y += topBorder(element);
2518              }
2519  
2520              element = element.offsetParent;
2521          }
2522          if (Browser.Engine.gecko && !borderBox(this)){
2523              position.x -= leftBorder(this);
2524              position.y -= topBorder(this);
2525          }
2526          return position;
2527      },
2528  
2529      getPosition: function(relative){
2530          if (isBody(this)) return {x: 0, y: 0};
2531          var offset = this.getOffsets(),
2532                  scroll = this.getScrolls();
2533          var position = {
2534              x: offset.x - scroll.x,
2535              y: offset.y - scroll.y
2536          };
2537          var relativePosition = (relative && (relative = document.id(relative))) ? relative.getPosition() : {x: 0, y: 0};
2538          return {x: position.x - relativePosition.x, y: position.y - relativePosition.y};
2539      },
2540  
2541      getCoordinates: function(element){
2542          if (isBody(this)) return this.getWindow().getCoordinates();
2543          var position = this.getPosition(element),
2544                  size = this.getSize();
2545          var obj = {
2546              left: position.x,
2547              top: position.y,
2548              width: size.x,
2549              height: size.y
2550          };
2551          obj.right = obj.left + obj.width;
2552          obj.bottom = obj.top + obj.height;
2553          return obj;
2554      },
2555  
2556      computePosition: function(obj){
2557          return {
2558              left: obj.x - styleNumber(this, 'margin-left'),
2559              top: obj.y - styleNumber(this, 'margin-top')
2560          };
2561      },
2562  
2563      setPosition: function(obj){
2564          return this.setStyles(this.computePosition(obj));
2565      }
2566  
2567  });
2568  
2569  
2570  Native.implement([Document, Window], {
2571  
2572      getSize: function(){
2573          if (Browser.Engine.presto || Browser.Engine.webkit){
2574              var win = this.getWindow();
2575              return {x: win.innerWidth, y: win.innerHeight};
2576          }
2577          var doc = getCompatElement(this);
2578          return {x: doc.clientWidth, y: doc.clientHeight};
2579      },
2580  
2581      getScroll: function(){
2582          var win = this.getWindow(), doc = getCompatElement(this);
2583          return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop};
2584      },
2585  
2586      getScrollSize: function(){
2587          var doc = getCompatElement(this), min = this.getSize();
2588          return {x: Math.max(doc.scrollWidth, min.x), y: Math.max(doc.scrollHeight, min.y)};
2589      },
2590  
2591      getPosition: function(){
2592          return {x: 0, y: 0};
2593      },
2594  
2595      getCoordinates: function(){
2596          var size = this.getSize();
2597          return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, width: size.x};
2598      }
2599  
2600  });
2601  
2602  // private methods
2603  
2604  var styleString = Element.getComputedStyle;
2605  
2606  function styleNumber(element, style){
2607      return styleString(element, style).toInt() || 0;
2608  };
2609  
2610  function borderBox(element){
2611      return styleString(element, '-moz-box-sizing') == 'border-box';
2612  };
2613  
2614  function topBorder(element){
2615      return styleNumber(element, 'border-top-width');
2616  };
2617  
2618  function leftBorder(element){
2619      return styleNumber(element, 'border-left-width');
2620  };
2621  
2622  function isBody(element){
2623      return (/^(?:body|html)$/i).test(element.tagName);
2624  };
2625  
2626  function getCompatElement(element){
2627      var doc = element.getDocument();
2628      return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
2629  };
2630  
2631  })();
2632  
2633  //aliases
2634  Element.alias('setPosition', 'position'); //compatability
2635  
2636  Native.implement([Window, Document, Element], {
2637  
2638      getHeight: function(){
2639          return this.getSize().y;
2640      },
2641  
2642      getWidth: function(){
2643          return this.getSize().x;
2644      },
2645  
2646      getScrollTop: function(){
2647          return this.getScroll().y;
2648      },
2649  
2650      getScrollLeft: function(){
2651          return this.getScroll().x;
2652      },
2653  
2654      getScrollHeight: function(){
2655          return this.getScrollSize().y;
2656      },
2657  
2658      getScrollWidth: function(){
2659          return this.getScrollSize().x;
2660      },
2661  
2662      getTop: function(){
2663          return this.getPosition().y;
2664      },
2665  
2666      getLeft: function(){
2667          return this.getPosition().x;
2668      }
2669  
2670  });
2671  
2672  
2673  /*
2674  ---
2675  
2676  name: Selectors
2677  
2678  description: Adds advanced CSS-style querying capabilities for targeting HTML Elements. Includes pseudo selectors.
2679  
2680  license: MIT-style license.
2681  
2682  requires: Element
2683  
2684  provides: Selectors
2685  
2686  ...
2687  */
2688  
2689  Native.implement([Document, Element], {
2690  
2691      getElements: function(expression, nocash){
2692          expression = expression.split(',');
2693          var items, local = {};
2694          for (var i = 0, l = expression.length; i < l; i++){
2695              var selector = expression[i], elements = Selectors.Utils.search(this, selector, local);
2696              if (i != 0 && elements.item) elements = $A(elements);
2697              items = (i == 0) ? elements : (items.item) ? $A(items).concat(elements) : items.concat(elements);
2698          }
2699          return new Elements(items, {ddup: (expression.length > 1), cash: !nocash});
2700      }
2701  
2702  });
2703  
2704  Element.implement({
2705  
2706      match: function(selector){
2707          if (!selector || (selector == this)) return true;
2708          var tagid = Selectors.Utils.parseTagAndID(selector);
2709          var tag = tagid[0], id = tagid[1];
2710          if (!Selectors.Filters.byID(this, id) || !Selectors.Filters.byTag(this, tag)) return false;
2711          var parsed = Selectors.Utils.parseSelector(selector);
2712          return (parsed) ? Selectors.Utils.filter(this, parsed, {}) : true;
2713      }
2714  
2715  });
2716  
2717  var Selectors = {Cache: {nth: {}, parsed: {}}};
2718  
2719  Selectors.RegExps = {
2720      id: (/#([\w-]+)/),
2721      tag: (/^(\w+|\*)/),
2722      quick: (/^(\w+|\*)$/),
2723      splitter: (/\s*([+>~\s])\s*([a-zA-Z#.*:\[])/g),
2724      combined: (/\.([\w-]+)|\[(\w+)(?:([!*^$~|]?=)(["']?)([^\4]*?)\4)?\]|:([\w-]+)(?:\(["']?(.*?)?["']?\)|$)/g)
2725  };
2726  
2727  Selectors.Utils = {
2728  
2729      chk: function(item, uniques){
2730          if (!uniques) return true;
2731          var uid = $uid(item);
2732          if (!uniques[uid]) return uniques[uid] = true;
2733          return false;
2734      },
2735  
2736      parseNthArgument: function(argument){
2737          if (Selectors.Cache.nth[argument]) return Selectors.Cache.nth[argument];
2738          var parsed = argument.match(/^([+-]?\d*)?([a-z]+)?([+-]?\d*)?$/);
2739          if (!parsed) return false;
2740          var inta = parseInt(parsed[1], 10);
2741          var a = (inta || inta === 0) ? inta : 1;
2742          var special = parsed[2] || false;
2743          var b = parseInt(parsed[3], 10) || 0;
2744          if (a != 0){
2745              b--;
2746              while (b < 1) b += a;
2747              while (b >= a) b -= a;
2748          } else {
2749              a = b;
2750              special = 'index';
2751          }
2752          switch (special){
2753              case 'n': parsed = {a: a, b: b, special: 'n'}; break;
2754              case 'odd': parsed = {a: 2, b: 0, special: 'n'}; break;
2755              case 'even': parsed = {a: 2, b: 1, special: 'n'}; break;
2756              case 'first': parsed = {a: 0, special: 'index'}; break;
2757              case 'last': parsed = {special: 'last-child'}; break;
2758              case 'only': parsed = {special: 'only-child'}; break;
2759              default: parsed = {a: (a - 1), special: 'index'};
2760          }
2761  
2762          return Selectors.Cache.nth[argument] = parsed;
2763      },
2764  
2765      parseSelector: function(selector){
2766          if (Selectors.Cache.parsed[selector]) return Selectors.Cache.parsed[selector];
2767          var m, parsed = {classes: [], pseudos: [], attributes: []};
2768          while ((m = Selectors.RegExps.combined.exec(selector))){
2769              var cn = m[1], an = m[2], ao = m[3], av = m[5], pn = m[6], pa = m[7];
2770              if (cn){
2771                  parsed.classes.push(cn);
2772              } else if (pn){
2773                  var parser = Selectors.Pseudo.get(pn);
2774                  if (parser) parsed.pseudos.push({parser: parser, argument: pa});
2775                  else parsed.attributes.push({name: pn, operator: '=', value: pa});
2776              } else if (an){
2777                  parsed.attributes.push({name: an, operator: ao, value: av});
2778              }
2779          }
2780          if (!parsed.classes.length) delete parsed.classes;
2781          if (!parsed.attributes.length) delete parsed.attributes;
2782          if (!parsed.pseudos.length) delete parsed.pseudos;
2783          if (!parsed.classes && !parsed.attributes && !parsed.pseudos) parsed = null;
2784          return Selectors.Cache.parsed[selector] = parsed;
2785      },
2786  
2787      parseTagAndID: function(selector){
2788          var tag = selector.match(Selectors.RegExps.tag);
2789          var id = selector.match(Selectors.RegExps.id);
2790          return [(tag) ? tag[1] : '*', (id) ? id[1] : false];
2791      },
2792  
2793      filter: function(item, parsed, local){
2794          var i;
2795          if (parsed.classes){
2796              for (i = parsed.classes.length; i--; i){
2797                  var cn = parsed.classes[i];
2798                  if (!Selectors.Filters.byClass(item, cn)) return false;
2799              }
2800          }
2801          if (parsed.attributes){
2802              for (i = parsed.attributes.length; i--; i){
2803                  var att = parsed.attributes[i];
2804                  if (!Selectors.Filters.byAttribute(item, att.name, att.operator, att.value)) return false;
2805              }
2806          }
2807          if (parsed.pseudos){
2808              for (i = parsed.pseudos.length; i--; i){
2809                  var psd = parsed.pseudos[i];
2810                  if (!Selectors.Filters.byPseudo(item, psd.parser, psd.argument, local)) return false;
2811              }
2812          }
2813          return true;
2814      },
2815  
2816      getByTagAndID: function(ctx, tag, id){
2817          if (id){
2818              var item = (ctx.getElementById) ? ctx.getElementById(id, true) : Element.getElementById(ctx, id, true);
2819              return (item && Selectors.Filters.byTag(item, tag)) ? [item] : [];
2820          } else {
2821              return ctx.getElementsByTagName(tag);
2822          }
2823      },
2824  
2825      search: function(self, expression, local){
2826          var splitters = [];
2827  
2828          var selectors = expression.trim().replace(Selectors.RegExps.splitter, function(m0, m1, m2){
2829              splitters.push(m1);
2830              return ':)' + m2;
2831          }).split(':)');
2832  
2833          var items, filtered, item;
2834  
2835          for (var i = 0, l = selectors.length; i < l; i++){
2836  
2837              var selector = selectors[i];
2838  
2839              if (i == 0 && Selectors.RegExps.quick.test(selector)){
2840                  items = self.getElementsByTagName(selector);
2841                  continue;
2842              }
2843  
2844              var splitter = splitters[i - 1];
2845  
2846              var tagid = Selectors.Utils.parseTagAndID(selector);
2847              var tag = tagid[0], id = tagid[1];
2848  
2849              if (i == 0){
2850                  items = Selectors.Utils.getByTagAndID(self, tag, id);
2851              } else {
2852                  var uniques = {}, found = [];
2853                  for (var j = 0, k = items.length; j < k; j++) found = Selectors.Getters[splitter](found, items[j], tag, id, uniques);
2854                  items = found;
2855              }
2856  
2857              var parsed = Selectors.Utils.parseSelector(selector);
2858  
2859              if (parsed){
2860                  filtered = [];
2861                  for (var m = 0, n = items.length; m < n; m++){
2862                      item = items[m];
2863                      if (Selectors.Utils.filter(item, parsed, local)) filtered.push(item);
2864                  }
2865                  items = filtered;
2866              }
2867  
2868          }
2869  
2870          return items;
2871  
2872      }
2873  
2874  };
2875  
2876  Selectors.Getters = {
2877  
2878      ' ': function(found, self, tag, id, uniques){
2879          var items = Selectors.Utils.getByTagAndID(self, tag, id);
2880          for (var i = 0, l = items.length; i < l; i++){
2881              var item = items[i];
2882              if (Selectors.Utils.chk(item, uniques)) found.push(item);
2883          }
2884          return found;
2885      },
2886  
2887      '>': function(found, self, tag, id, uniques){
2888          var children = Selectors.Utils.getByTagAndID(self, tag, id);
2889          for (var i = 0, l = children.length; i < l; i++){
2890              var child = children[i];
2891              if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child);
2892          }
2893          return found;
2894      },
2895  
2896      '+': function(found, self, tag, id, uniques){
2897          while ((self = self.nextSibling)){
2898              if (self.nodeType == 1){
2899                  if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
2900                  break;
2901              }
2902          }
2903          return found;
2904      },
2905  
2906      '~': function(found, self, tag, id, uniques){
2907          while ((self = self.nextSibling)){
2908              if (self.nodeType == 1){
2909                  if (!Selectors.Utils.chk(self, uniques)) break;
2910                  if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
2911              }
2912          }
2913          return found;
2914      }
2915  
2916  };
2917  
2918  Selectors.Filters = {
2919  
2920      byTag: function(self, tag){
2921          return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag));
2922      },
2923  
2924      byID: function(self, id){
2925          return (!id || (self.id && self.id == id));
2926      },
2927  
2928      byClass: function(self, klass){
2929          return (self.className && self.className.contains && self.className.contains(klass, ' '));
2930      },
2931  
2932      byPseudo: function(self, parser, argument, local){
2933          return parser.call(self, argument, local);
2934      },
2935  
2936      byAttribute: function(self, name, operator, value){
2937          var result = Element.prototype.getProperty.call(self, name);
2938          if (!result) return (operator == '!=');
2939          if (!operator || value == undefined) return true;
2940          switch (operator){
2941              case '=': return (result == value);
2942              case '*=': return (result.contains(value));
2943              case '^=': return (result.substr(0, value.length) == value);
2944              case '$=': return (result.substr(result.length - value.length) == value);
2945              case '!=': return (result != value);
2946              case '~=': return result.contains(value, ' ');
2947              case '|=': return result.contains(value, '-');
2948          }
2949          return false;
2950      }
2951  
2952  };
2953  
2954  Selectors.Pseudo = new Hash({
2955  
2956      // w3c pseudo selectors
2957  
2958      checked: function(){
2959          return this.checked;
2960      },
2961      
2962      empty: function(){
2963          return !(this.innerText || this.textContent || '').length;
2964      },
2965  
2966      not: function(selector){
2967          return !Element.match(this, selector);
2968      },
2969  
2970      contains: function(text){
2971          return (this.innerText || this.textContent || '').contains(text);
2972      },
2973  
2974      'first-child': function(){
2975          return Selectors.Pseudo.index.call(this, 0);
2976      },
2977  
2978      'last-child': function(){
2979          var element = this;
2980          while ((element = element.nextSibling)){
2981              if (element.nodeType == 1) return false;
2982          }
2983          return true;
2984      },
2985  
2986      'only-child': function(){
2987          var prev = this;
2988          while ((prev = prev.previousSibling)){
2989              if (prev.nodeType == 1) return false;
2990          }
2991          var next = this;
2992          while ((next = next.nextSibling)){
2993              if (next.nodeType == 1) return false;
2994          }
2995          return true;
2996      },
2997  
2998      'nth-child': function(argument, local){
2999          argument = (argument == undefined) ? 'n' : argument;
3000          var parsed = Selectors.Utils.parseNthArgument(argument);
3001          if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local);
3002          var count = 0;
3003          local.positions = local.positions || {};
3004          var uid = $uid(this);
3005          if (!local.positions[uid]){
3006              var self = this;
3007              while ((self = self.previousSibling)){
3008                  if (self.nodeType != 1) continue;
3009                  count ++;
3010                  var position = local.positions[$uid(self)];
3011                  if (position != undefined){
3012                      count = position + count;
3013                      break;
3014                  }
3015              }
3016              local.positions[uid] = count;
3017          }
3018          return (local.positions[uid] % parsed.a == parsed.b);
3019      },
3020  
3021      // custom pseudo selectors
3022  
3023      index: function(index){
3024          var element = this, count = 0;
3025          while ((element = element.previousSibling)){
3026              if (element.nodeType == 1 && ++count > index) return false;
3027          }
3028          return (count == index);
3029      },
3030  
3031      even: function(argument, local){
3032          return Selectors.Pseudo['nth-child'].call(this, '2n+1', local);
3033      },
3034  
3035      odd: function(argument, local){
3036          return Selectors.Pseudo['nth-child'].call(this, '2n', local);
3037      },
3038      
3039      selected: function(){
3040          return this.selected;
3041      },
3042      
3043      enabled: function(){
3044          return (this.disabled === false);
3045      }
3046  
3047  });
3048  
3049  
3050  /*
3051  ---
3052  
3053  name: DomReady
3054  
3055  description: Contains the custom event domready.
3056  
3057  license: MIT-style license.
3058  
3059  requires: Element.Event
3060  
3061  provides: DomReady
3062  
3063  ...
3064  */
3065  
3066  Element.Events.domready = {
3067  
3068      onAdd: function(fn){
3069          if (Browser.loaded) fn.call(this);
3070      }
3071  
3072  };
3073  
3074  (function(){
3075  
3076      var domready = function(){
3077          if (Browser.loaded) return;
3078          Browser.loaded = true;
3079          window.fireEvent('domready');
3080          document.fireEvent('domready');
3081      };
3082      
3083      window.addEvent('load', domready);
3084  
3085      if (Browser.Engine.trident){
3086          var temp = document.createElement('div');
3087          (function(){
3088              ($try(function(){
3089                  temp.doScroll(); // Technique by Diego Perini
3090                  return document.id(temp).inject(document.body).set('html', 'temp').dispose();
3091              })) ? domready() : arguments.callee.delay(50);
3092          })();
3093      } else if (Browser.Engine.webkit && Browser.Engine.version < 525){
3094          (function(){
3095              (['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50);
3096          })();
3097      } else {
3098          document.addEvent('DOMContentLoaded', domready);
3099      }
3100  
3101  })();
3102  
3103  
3104  /*
3105  ---
3106  
3107  name: JSON
3108  
3109  description: JSON encoder and decoder.
3110  
3111  license: MIT-style license.
3112  
3113  see: <http://www.json.org/>
3114  
3115  requires: [Array, String, Number, Function, Hash]
3116  
3117  provides: JSON
3118  
3119  ...
3120  */
3121  
3122  var JSON = new Hash(this.JSON && {
3123      stringify: JSON.stringify,
3124      parse: JSON.parse
3125  }).extend({
3126      
3127      $specialChars: {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},
3128  
3129      $replaceChars: function(chr){
3130          return JSON.$specialChars[chr] || '\\u00' + Math.floor(chr.charCodeAt() / 16).toString(16) + (chr.charCodeAt() % 16).toString(16);
3131      },
3132  
3133      encode: function(obj){
3134          switch ($type(obj)){
3135              case 'string':
3136                  return '"' + obj.replace(/[\x00-\x1f\\"]/g, JSON.$replaceChars) + '"';
3137              case 'array':
3138                  return '[' + String(obj.map(JSON.encode).clean()) + ']';
3139              case 'object': case 'hash':
3140                  var string = [];
3141                  Hash.each(obj, function(value, key){
3142                      var json = JSON.encode(value);
3143                      if (json) string.push(JSON.encode(key) + ':' + json);
3144                  });
3145                  return '{' + string + '}';
3146              case 'number': case 'boolean': return String(obj);
3147              case false: return 'null';
3148          }
3149          return null;
3150      },
3151  
3152      decode: function(string, secure){
3153          if ($type(string) != 'string' || !string.length) return null;
3154          if (secure && !(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(string.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''))) return null;
3155          return eval('(' + string + ')');
3156      }
3157  
3158  });
3159  
3160  
3161  /*
3162  ---
3163  
3164  name: Cookie
3165  
3166  description: Class for creating, reading, and deleting browser Cookies.
3167  
3168  license: MIT-style license.
3169  
3170  credits: Based on the functions by Peter-Paul Koch (http://quirksmode.org).
3171  
3172  requires: Options
3173  
3174  provides: Cookie
3175  
3176  ...
3177  */
3178  
3179  var Cookie = new Class({
3180  
3181      Implements: Options,
3182  
3183      options: {
3184          path: false,
3185          domain: false,
3186          duration: false,
3187          secure: false,
3188          document: document
3189      },
3190  
3191      initialize: function(key, options){
3192          this.key = key;
3193          this.setOptions(options);
3194      },
3195  
3196      write: function(value){
3197          value = encodeURIComponent(value);
3198          if (this.options.domain) value += '; domain=' + this.options.domain;
3199          if (this.options.path) value += '; path=' + this.options.path;
3200          if (this.options.duration){
3201              var date = new Date();
3202              date.setTime(date.getTime() + this.options.duration * 24 * 60 * 60 * 1000);
3203              value += '; expires=' + date.toGMTString();
3204          }
3205          if (this.options.secure) value += '; secure';
3206          this.options.document.cookie = this.key + '=' + value;
3207          return this;
3208      },
3209  
3210      read: function(){
3211          var value = this.options.document.cookie.match('(?:^|;)\\s*' + this.key.escapeRegExp() + '=([^;]*)');
3212          return (value) ? decodeURIComponent(value[1]) : null;
3213      },
3214  
3215      dispose: function(){
3216          new Cookie(this.key, $merge(this.options, {duration: -1})).write('');
3217          return this;
3218      }
3219  
3220  });
3221  
3222  Cookie.write = function(key, value, options){
3223      return new Cookie(key, options).write(value);
3224  };
3225  
3226  Cookie.read = function(key){
3227      return new Cookie(key).read();
3228  };
3229  
3230  Cookie.dispose = function(key, options){
3231      return new Cookie(key, options).dispose();
3232  };
3233  
3234  
3235  /*
3236  ---
3237  
3238  name: Swiff
3239  
3240  description: Wrapper for embedding SWF movies. Supports External Interface Communication.
3241  
3242  license: MIT-style license.
3243  
3244  credits: Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
3245  
3246  requires: [Options, $util]
3247  
3248  provides: Swiff
3249  
3250  ...
3251  */
3252  
3253  var Swiff = new Class({
3254  
3255      Implements: [Options],
3256  
3257      options: {
3258          id: null,
3259          height: 1,
3260          width: 1,
3261          container: null,
3262          properties: {},
3263          params: {
3264              quality: 'high',
3265              allowScriptAccess: 'always',
3266              wMode: 'transparent',
3267              swLiveConnect: true
3268          },
3269          callBacks: {},
3270          vars: {}
3271      },
3272  
3273      toElement: function(){
3274          return this.object;
3275      },
3276  
3277      initialize: function(path, options){
3278          this.instance = 'Swiff_' + $time();
3279  
3280          this.setOptions(options);
3281          options = this.options;
3282          var id = this.id = options.id || this.instance;
3283          var container = document.id(options.container);
3284  
3285          Swiff.CallBacks[this.instance] = {};
3286  
3287          var params = options.params, vars = options.vars, callBacks = options.callBacks;
3288          var properties = $extend({height: options.height, width: options.width}, options.properties);
3289  
3290          var self = this;
3291  
3292          for (var callBack in callBacks){
3293              Swiff.CallBacks[this.instance][callBack] = (function(option){
3294                  return function(){
3295                      return option.apply(self.object, arguments);
3296                  };
3297              })(callBacks[callBack]);
3298              vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack;
3299          }
3300  
3301          params.flashVars = Hash.toQueryString(vars);
3302          if (Browser.Engine.trident){
3303              properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
3304              params.movie = path;
3305          } else {
3306              properties.type = 'application/x-shockwave-flash';
3307              properties.data = path;
3308          }
3309          var build = '<object id="' + id + '"';
3310          for (var property in properties) build += ' ' + property + '="' + properties[property] + '"';
3311          build += '>';
3312          for (var param in params){
3313              if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />';
3314          }
3315          build += '</object>';
3316          this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild;
3317      },
3318  
3319      replaces: function(element){
3320          element = document.id(element, true);
3321          element.parentNode.replaceChild(this.toElement(), element);
3322          return this;
3323      },
3324  
3325      inject: function(element){
3326          document.id(element, true).appendChild(this.toElement());
3327          return this;
3328      },
3329  
3330      remote: function(){
3331          return Swiff.remote.apply(Swiff, [this.toElement()].extend(arguments));
3332      }
3333  
3334  });
3335  
3336  Swiff.CallBacks = {};
3337  
3338  Swiff.remote = function(obj, fn){
3339      var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>');
3340      return eval(rs);
3341  };
3342  
3343  
3344  /*
3345  ---
3346  
3347  name: Fx
3348  
3349  description: Contains the basic animation logic to be extended by all other Fx Classes.
3350  
3351  license: MIT-style license.
3352  
3353  requires: [Chain, Events, Options]
3354  
3355  provides: Fx
3356  
3357  ...
3358  */
3359  
3360  var Fx = new Class({
3361  
3362      Implements: [Chain, Events, Options],
3363  
3364      options: {
3365          /*
3366          onStart: $empty,
3367          onCancel: $empty,
3368          onComplete: $empty,
3369          */
3370          fps: 50,
3371          unit: false,
3372          duration: 500,
3373          link: 'ignore'
3374      },
3375  
3376      initialize: function(options){
3377          this.subject = this.subject || this;
3378          this.setOptions(options);
3379          this.options.duration = Fx.Durations[this.options.duration] || this.options.duration.toInt();
3380          var wait = this.options.wait;
3381          if (wait === false) this.options.link = 'cancel';
3382      },
3383  
3384      getTransition: function(){
3385          return function(p){
3386              return -(Math.cos(Math.PI * p) - 1) / 2;
3387          };
3388      },
3389  
3390      step: function(){
3391          var time = $time();
3392          if (time < this.time + this.options.duration){
3393              var delta = this.transition((time - this.time) / this.options.duration);
3394              this.set(this.compute(this.from, this.to, delta));
3395          } else {
3396              this.set(this.compute(this.from, this.to, 1));
3397              this.complete();
3398          }
3399      },
3400  
3401      set: function(now){
3402          return now;
3403      },
3404  
3405      compute: function(from, to, delta){
3406          return Fx.compute(from, to, delta);
3407      },
3408  
3409      check: function(){
3410          if (!this.timer) return true;
3411          switch (this.options.link){
3412              case 'cancel': this.cancel(); return true;
3413              case 'chain': this.chain(this.caller.bind(this, arguments)); return false;
3414          }
3415          return false;
3416      },
3417  
3418      start: function(from, to){
3419          if (!this.check(from, to)) return this;
3420          this.from = from;
3421          this.to = to;
3422          this.time = 0;
3423          this.transition = this.getTransition();
3424          this.startTimer();
3425          this.onStart();
3426          return this;
3427      },
3428  
3429      complete: function(){
3430          if (this.stopTimer()) this.onComplete();
3431          return this;
3432      },
3433  
3434      cancel: function(){
3435          if (this.stopTimer()) this.onCancel();
3436          return this;
3437      },
3438  
3439      onStart: function(){
3440          this.fireEvent('start', this.subject);
3441      },
3442  
3443      onComplete: function(){
3444          this.fireEvent('complete', this.subject);
3445          if (!this.callChain()) this.fireEvent('chainComplete', this.subject);
3446      },
3447  
3448      onCancel: function(){
3449          this.fireEvent('cancel', this.subject).clearChain();
3450      },
3451  
3452      pause: function(){
3453          this.stopTimer();
3454          return this;
3455      },
3456  
3457      resume: function(){
3458          this.startTimer();
3459          return this;
3460      },
3461  
3462      stopTimer: function(){
3463          if (!this.timer) return false;
3464          this.time = $time() - this.time;
3465          this.timer = $clear(this.timer);
3466          return true;
3467      },
3468  
3469      startTimer: function(){
3470          if (this.timer) return false;
3471          this.time = $time() - this.time;
3472          this.timer = this.step.periodical(Math.round(1000 / this.options.fps), this);
3473          return true;
3474      }
3475  
3476  });
3477  
3478  Fx.compute = function(from, to, delta){
3479      return (to - from) * delta + from;
3480  };
3481  
3482  Fx.Durations = {'short': 250, 'normal': 500, 'long': 1000};
3483  
3484  
3485  /*
3486  ---
3487  
3488  name: Fx.CSS
3489  
3490  description: Contains the CSS animation logic. Used by Fx.Tween, Fx.Morph, Fx.Elements.
3491  
3492  license: MIT-style license.
3493  
3494  requires: [Fx, Element.Style]
3495  
3496  provides: Fx.CSS
3497  
3498  ...
3499  */
3500  
3501  Fx.CSS = new Class({
3502  
3503      Extends: Fx,
3504  
3505      //prepares the base from/to object
3506  
3507      prepare: function(element, property, values){
3508          values = $splat(values);
3509          var values1 = values[1];
3510          if (!$chk(values1)){
3511              values[1] = values[0];
3512              values[0] = element.getStyle(property);
3513          }
3514          var parsed = values.map(this.parse);
3515          return {from: parsed[0], to: parsed[1]};
3516      },
3517  
3518      //parses a value into an array
3519  
3520      parse: function(value){
3521          value = $lambda(value)();
3522          value = (typeof value == 'string') ? value.split(' ') : $splat(value);
3523          return value.map(function(val){
3524              val = String(val);
3525              var found = false;
3526              Fx.CSS.Parsers.each(function(parser, key){
3527                  if (found) return;
3528                  var parsed = parser.parse(val);
3529                  if ($chk(parsed)) found = {value: parsed, parser: parser};
3530              });
3531              found = found || {value: val, parser: Fx.CSS.Parsers.String};
3532              return found;
3533          });
3534      },
3535  
3536      //computes by a from and to prepared objects, using their parsers.
3537  
3538      compute: function(from, to, delta){
3539          var computed = [];
3540          (Math.min(from.length, to.length)).times(function(i){
3541              computed.push({value: from[i].parser.compute(from[i].value, to[i].value, delta), parser: from[i].parser});
3542          });
3543          computed.$family = {name: 'fx:css:value'};
3544          return computed;
3545      },
3546  
3547      //serves the value as settable
3548  
3549      serve: function(value, unit){
3550          if ($type(value) != 'fx:css:value') value = this.parse(value);
3551          var returned = [];
3552          value.each(function(bit){
3553              returned = returned.concat(bit.parser.serve(bit.value, unit));
3554          });
3555          return returned;
3556      },
3557  
3558      //renders the change to an element
3559  
3560      render: function(element, property, value, unit){
3561          element.setStyle(property, this.serve(value, unit));
3562      },
3563  
3564      //searches inside the page css to find the values for a selector
3565  
3566      search: function(selector){
3567          if (Fx.CSS.Cache[selector]) return Fx.CSS.Cache[selector];
3568          var to = {};
3569          Array.each(document.styleSheets, function(sheet, j){
3570              var href = sheet.href;
3571              if (href && href.contains('://') && !href.contains(document.domain)) return;
3572              var rules = sheet.rules || sheet.cssRules;
3573              Array.each(rules, function(rule, i){
3574                  if (!rule.style) return;
3575                  var selectorText = (rule.selectorText) ? rule.selectorText.replace(/^\w+/, function(m){
3576                      return m.toLowerCase();
3577                  }) : null;
3578                  if (!selectorText || !selectorText.test('^' + selector + '$')) return;
3579                  Element.Styles.each(function(value, style){
3580                      if (!rule.style[style] || Element.ShortStyles[style]) return;
3581                      value = String(rule.style[style]);
3582                      to[style] = (value.test(/^rgb/)) ? value.rgbToHex() : value;
3583                  });
3584              });
3585          });
3586          return Fx.CSS.Cache[selector] = to;
3587      }
3588  
3589  });
3590  
3591  Fx.CSS.Cache = {};
3592  
3593  Fx.CSS.Parsers = new Hash({
3594  
3595      Color: {
3596          parse: function(value){
3597              if (value.match(/^#[0-9a-f]{3,6}$/i)) return value.hexToRgb(true);
3598              return ((value = value.match(/(\d+),\s*(\d+),\s*(\d+)/))) ? [value[1], value[2], value[3]] : false;
3599          },
3600          compute: function(from, to, delta){
3601              return from.map(function(value, i){
3602                  return Math.round(Fx.compute(from[i], to[i], delta));
3603              });
3604          },
3605          serve: function(value){
3606              return value.map(Number);
3607          }
3608      },
3609  
3610      Number: {
3611          parse: parseFloat,
3612          compute: Fx.compute,
3613          serve: function(value, unit){
3614              return (unit) ? value + unit : value;
3615          }
3616      },
3617  
3618      String: {
3619          parse: $lambda(false),
3620          compute: $arguments(1),
3621          serve: $arguments(0)
3622      }
3623  
3624  });
3625  
3626  
3627  /*
3628  ---
3629  
3630  name: Fx.Tween
3631  
3632  description: Formerly Fx.Style, effect to transition any CSS property for an element.
3633  
3634  license: MIT-style license.
3635  
3636  requires: Fx.CSS
3637  
3638  provides: [Fx.Tween, Element.fade, Element.highlight]
3639  
3640  ...
3641  */
3642  
3643  Fx.Tween = new Class({
3644  
3645      Extends: Fx.CSS,
3646  
3647      initialize: function(element, options){
3648          this.element = this.subject = document.id(element);
3649          this.parent(options);
3650      },
3651  
3652      set: function(property, now){
3653          if (arguments.length == 1){
3654              now = property;
3655              property = this.property || this.options.property;
3656          }
3657          this.render(this.element, property, now, this.options.unit);
3658          return this;
3659      },
3660  
3661      start: function(property, from, to){
3662          if (!this.check(property, from, to)) return this;
3663          var args = Array.flatten(arguments);
3664          this.property = this.options.property || args.shift();
3665          var parsed = this.prepare(this.element, this.property, args);
3666          return this.parent(parsed.from, parsed.to);
3667      }
3668  
3669  });
3670  
3671  Element.Properties.tween = {
3672  
3673      set: function(options){
3674          var tween = this.retrieve('tween');
3675          if (tween) tween.cancel();
3676          return this.eliminate('tween').store('tween:options', $extend({link: 'cancel'}, options));
3677      },
3678  
3679      get: function(options){
3680          if (options || !this.retrieve('tween')){
3681              if (options || !this.retrieve('tween:options')) this.set('tween', options);
3682              this.store('tween', new Fx.Tween(this, this.retrieve('tween:options')));
3683          }
3684          return this.retrieve('tween');
3685      }
3686  
3687  };
3688  
3689  Element.implement({
3690  
3691      tween: function(property, from, to){
3692          this.get('tween').start(arguments);
3693          return this;
3694      },
3695  
3696      fade: function(how){
3697          var fade = this.get('tween'), o = 'opacity', toggle;
3698          how = $pick(how, 'toggle');
3699          switch (how){
3700              case 'in': fade.start(o, 1); break;
3701              case 'out': fade.start(o, 0); break;
3702              case 'show': fade.set(o, 1); break;
3703              case 'hide': fade.set(o, 0); break;
3704              case 'toggle':
3705                  var flag = this.retrieve('fade:flag', this.get('opacity') == 1);
3706                  fade.start(o, (flag) ? 0 : 1);
3707                  this.store('fade:flag', !flag);
3708                  toggle = true;
3709              break;
3710              default: fade.start(o, arguments);
3711          }
3712          if (!toggle) this.eliminate('fade:flag');
3713          return this;
3714      },
3715  
3716      highlight: function(start, end){
3717          if (!end){
3718              end = this.retrieve('highlight:original', this.getStyle('background-color'));
3719              end = (end == 'transparent') ? '#fff' : end;
3720          }
3721          var tween = this.get('tween');
3722          tween.start('background-color', start || '#ffff88', end).chain(function(){
3723              this.setStyle('background-color', this.retrieve('highlight:original'));
3724              tween.callChain();
3725          }.bind(this));
3726          return this;
3727      }
3728  
3729  });
3730  
3731  
3732  /*
3733  ---
3734  
3735  name: Fx.Morph
3736  
3737  description: Formerly Fx.Styles, effect to transition any number of CSS properties for an element using an object of rules, or CSS based selector rules.
3738  
3739  license: MIT-style license.
3740  
3741  requires: Fx.CSS
3742  
3743  provides: Fx.Morph
3744  
3745  ...
3746  */
3747  
3748  Fx.Morph = new Class({
3749  
3750      Extends: Fx.CSS,
3751  
3752      initialize: function(element, options){
3753          this.element = this.subject = document.id(element);
3754          this.parent(options);
3755      },
3756  
3757      set: function(now){
3758          if (typeof now == 'string') now = this.search(now);
3759          for (var p in now) this.render(this.element, p, now[p], this.options.unit);
3760          return this;
3761      },
3762  
3763      compute: function(from, to, delta){
3764          var now = {};
3765          for (var p in from) now[p] = this.parent(from[p], to[p], delta);
3766          return now;
3767      },
3768  
3769      start: function(properties){
3770          if (!this.check(properties)) return this;
3771          if (typeof properties == 'string') properties = this.search(properties);
3772          var from = {}, to = {};
3773          for (var p in properties){
3774              var parsed = this.prepare(this.element, p, properties[p]);
3775              from[p] = parsed.from;
3776              to[p] = parsed.to;
3777          }
3778          return this.parent(from, to);
3779      }
3780  
3781  });
3782  
3783  Element.Properties.morph = {
3784  
3785      set: function(options){
3786          var morph = this.retrieve('morph');
3787          if (morph) morph.cancel();
3788          return this.eliminate('morph').store('morph:options', $extend({link: 'cancel'}, options));
3789      },
3790  
3791      get: function(options){
3792          if (options || !this.retrieve('morph')){
3793              if (options || !this.retrieve('morph:options')) this.set('morph', options);
3794              this.store('morph', new Fx.Morph(this, this.retrieve('morph:options')));
3795          }
3796          return this.retrieve('morph');
3797      }
3798  
3799  };
3800  
3801  Element.implement({
3802  
3803      morph: function(props){
3804          this.get('morph').start(props);
3805          return this;
3806      }
3807  
3808  });
3809  
3810  
3811  /*
3812  ---
3813  
3814  name: Fx.Transitions
3815  
3816  description: Contains a set of advanced transitions to be used with any of the Fx Classes.
3817  
3818  license: MIT-style license.
3819  
3820  credits: Easing Equations by Robert Penner, <http://www.robertpenner.com/easing/>, modified and optimized to be used with MooTools.
3821  
3822  requires: Fx
3823  
3824  provides: Fx.Transitions
3825  
3826  ...
3827  */
3828  
3829  Fx.implement({
3830  
3831      getTransition: function(){
3832          var trans = this.options.transition || Fx.Transitions.Sine.easeInOut;
3833          if (typeof trans == 'string'){
3834              var data = trans.split(':');
3835              trans = Fx.Transitions;
3836              trans = trans[data[0]] || trans[data[0].capitalize()];
3837              if (data[1]) trans = trans['ease' + data[1].capitalize() + (data[2] ? data[2].capitalize() : '')];
3838          }
3839          return trans;
3840      }
3841  
3842  });
3843  
3844  Fx.Transition = function(transition, params){
3845      params = $splat(params);
3846      return $extend(transition, {
3847          easeIn: function(pos){
3848              return transition(pos, params);
3849          },
3850          easeOut: function(pos){
3851              return 1 - transition(1 - pos, params);
3852          },
3853          easeInOut: function(pos){
3854              return (pos <= 0.5) ? transition(2 * pos, params) / 2 : (2 - transition(2 * (1 - pos), params)) / 2;
3855          }
3856      });
3857  };
3858  
3859  Fx.Transitions = new Hash({
3860  
3861      linear: $arguments(0)
3862  
3863  });
3864  
3865  Fx.Transitions.extend = function(transitions){
3866      for (var transition in transitions) Fx.Transitions[transition] = new Fx.Transition(transitions[transition]);
3867  };
3868  
3869  Fx.Transitions.extend({
3870  
3871      Pow: function(p, x){
3872          return Math.pow(p, x[0] || 6);
3873      },
3874  
3875      Expo: function(p){
3876          return Math.pow(2, 8 * (p - 1));
3877      },
3878  
3879      Circ: function(p){
3880          return 1 - Math.sin(Math.acos(p));
3881      },
3882  
3883      Sine: function(p){
3884          return 1 - Math.sin((1 - p) * Math.PI / 2);
3885      },
3886  
3887      Back: function(p, x){
3888          x = x[0] || 1.618;
3889          return Math.pow(p, 2) * ((x + 1) * p - x);
3890      },
3891  
3892      Bounce: function(p){
3893          var value;
3894          for (var a = 0, b = 1; 1; a += b, b /= 2){
3895              if (p >= (7 - 4 * a) / 11){
3896                  value = b * b - Math.pow((11 - 6 * a - 11 * p) / 4, 2);
3897                  break;
3898              }
3899          }
3900          return value;
3901      },
3902  
3903      Elastic: function(p, x){
3904          return Math.pow(2, 10 * --p) * Math.cos(20 * p * Math.PI * (x[0] || 1) / 3);
3905      }
3906  
3907  });
3908  
3909  ['Quad', 'Cubic', 'Quart', 'Quint'].each(function(transition, i){
3910      Fx.Transitions[transition] = new Fx.Transition(function(p){
3911          return Math.pow(p, [i + 2]);
3912      });
3913  });
3914  
3915  
3916  /*
3917  ---
3918  
3919  name: Request
3920  
3921  description: Powerful all purpose Request Class. Uses XMLHTTPRequest.
3922  
3923  license: MIT-style license.
3924  
3925  requires: [Element, Chain, Events, Options, Browser]
3926  
3927  provides: Request
3928  
3929  ...
3930  */
3931  
3932  var Request = new Class({
3933  
3934      Implements: [Chain, Events, Options],
3935  
3936      options: {/*
3937          onRequest: $empty,
3938          onComplete: $empty,
3939          onCancel: $empty,
3940          onSuccess: $empty,
3941          onFailure: $empty,
3942          onException: $empty,*/
3943          url: '',
3944          data: '',
3945          headers: {
3946              'X-Requested-With': 'XMLHttpRequest',
3947              'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
3948          },
3949          async: true,
3950          format: false,
3951          method: 'post',
3952          link: 'ignore',
3953          isSuccess: null,
3954          emulation: true,
3955          urlEncoded: true,
3956          encoding: 'utf-8',
3957          evalScripts: false,
3958          evalResponse: false,
3959          noCache: false
3960      },
3961  
3962      initialize: function(options){
3963          this.xhr = new Browser.Request();
3964          this.setOptions(options);
3965          this.options.isSuccess = this.options.isSuccess || this.isSuccess;
3966          this.headers = new Hash(this.options.headers);
3967      },
3968  
3969      onStateChange: function(){
3970          if (this.xhr.readyState != 4 || !this.running) return;
3971          this.running = false;
3972          this.status = 0;
3973          $try(function(){
3974              this.status = this.xhr.status;
3975          }.bind(this));
3976          this.xhr.onreadystatechange = $empty;
3977          if (this.options.isSuccess.call(this, this.status)){
3978              this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML};
3979              this.success(this.response.text, this.response.xml);
3980          } else {
3981              this.response = {text: null, xml: null};
3982              this.failure();
3983          }
3984      },
3985  
3986      isSuccess: function(){
3987          return ((this.status >= 200) && (this.status < 300));
3988      },
3989  
3990      processScripts: function(text){
3991          if (this.options.evalResponse || (/(ecma|java)script/).test(this.getHeader('Content-type'))) return $exec(text);
3992          return text.stripScripts(this.options.evalScripts);
3993      },
3994  
3995      success: function(text, xml){
3996          this.onSuccess(this.processScripts(text), xml);
3997      },
3998  
3999      onSuccess: function(){
4000          this.fireEvent('complete', arguments).fireEvent('success', arguments).callChain();
4001      },
4002  
4003      failure: function(){
4004          this.onFailure();
4005      },
4006  
4007      onFailure: function(){
4008          this.fireEvent('complete').fireEvent('failure', this.xhr);
4009      },
4010  
4011      setHeader: function(name, value){
4012          this.headers.set(name, value);
4013          return this;
4014      },
4015  
4016      getHeader: function(name){
4017          return $try(function(){
4018              return this.xhr.getResponseHeader(name);
4019          }.bind(this));
4020      },
4021  
4022      check: function(){
4023          if (!this.running) return true;
4024          switch (this.options.link){
4025              case 'cancel': this.cancel(); return true;
4026              case 'chain': this.chain(this.caller.bind(this, arguments)); return false;
4027          }
4028          return false;
4029      },
4030  
4031      send: function(options){
4032          if (!this.check(options)) return this;
4033          this.running = true;
4034  
4035          var type = $type(options);
4036          if (type == 'string' || type == 'element') options = {data: options};
4037  
4038          var old = this.options;
4039          options = $extend({data: old.data, url: old.url, method: old.method}, options);
4040          var data = options.data, url = String(options.url), method = options.method.toLowerCase();
4041  
4042          switch ($type(data)){
4043              case 'element': data = document.id(data).toQueryString(); break;
4044              case 'object': case 'hash': data = Hash.toQueryString(data);
4045          }
4046  
4047          if (this.options.format){
4048              var format = 'format=' + this.options.format;
4049              data = (data) ? format + '&' + data : format;
4050          }
4051  
4052          if (this.options.emulation && !['get', 'post'].contains(method)){
4053              var _method = '_method=' + method;
4054              data = (data) ? _method + '&' + data : _method;
4055              method = 'post';
4056          }
4057  
4058          if (this.options.urlEncoded && method == 'post'){
4059              var encoding = (this.options.encoding) ? '; charset=' + this.options.encoding : '';
4060              this.headers.set('Content-type', 'application/x-www-form-urlencoded' + encoding);
4061          }
4062  
4063          if (this.options.noCache){
4064              var noCache = 'noCache=' + new Date().getTime();
4065              data = (data) ? noCache + '&' + data : noCache;
4066          }
4067  
4068          var trimPosition = url.lastIndexOf('/');
4069          if (trimPosition > -1 && (trimPosition = url.indexOf('#')) > -1) url = url.substr(0, trimPosition);
4070  
4071          if (data && method == 'get'){
4072              url = url + (url.contains('?') ? '&' : '?') + data;
4073              data = null;
4074          }
4075  
4076          this.xhr.open(method.toUpperCase(), url, this.options.async);
4077  
4078          this.xhr.onreadystatechange = this.onStateChange.bind(this);
4079  
4080          this.headers.each(function(value, key){
4081              try {
4082                  this.xhr.setRequestHeader(key, value);
4083              } catch (e){
4084                  this.fireEvent('exception', [key, value]);
4085              }
4086          }, this);
4087  
4088          this.fireEvent('request');
4089          this.xhr.send(data);
4090          if (!this.options.async) this.onStateChange();
4091          return this;
4092      },
4093  
4094      cancel: function(){
4095          if (!this.running) return this;
4096          this.running = false;
4097          this.xhr.abort();
4098          this.xhr.onreadystatechange = $empty;
4099          this.xhr = new Browser.Request();
4100          this.fireEvent('cancel');
4101          return this;
4102      }
4103  
4104  });
4105  
4106  (function(){
4107  
4108  var methods = {};
4109  ['get', 'post', 'put', 'delete', 'GET', 'POST', 'PUT', 'DELETE'].each(function(method){
4110      methods[method] = function(){
4111          var params = Array.link(arguments, {url: String.type, data: $defined});
4112          return this.send($extend(params, {method: method}));
4113      };
4114  });
4115  
4116  Request.implement(methods);
4117  
4118  })();
4119  
4120  Element.Properties.send = {
4121  
4122      set: function(options){
4123          var send = this.retrieve('send');
4124          if (send) send.cancel();
4125          return this.eliminate('send').store('send:options', $extend({
4126              data: this, link: 'cancel', method: this.get('method') || 'post', url: this.get('action')
4127          }, options));
4128      },
4129  
4130      get: function(options){
4131          if (options || !this.retrieve('send')){
4132              if (options || !this.retrieve('send:options')) this.set('send', options);
4133              this.store('send', new Request(this.retrieve('send:options')));
4134          }
4135          return this.retrieve('send');
4136      }
4137  
4138  };
4139  
4140  Element.implement({
4141  
4142      send: function(url){
4143          var sender = this.get('send');
4144          sender.send({data: this, url: url || sender.options.url});
4145          return this;
4146      }
4147  
4148  });
4149  
4150  
4151  /*
4152  ---
4153  
4154  name: Request.HTML
4155  
4156  description: Extends the basic Request Class with additional methods for interacting with HTML responses.
4157  
4158  license: MIT-style license.
4159  
4160  requires: [Request, Element]
4161  
4162  provides: Request.HTML
4163  
4164  ...
4165  */
4166  
4167  Request.HTML = new Class({
4168  
4169      Extends: Request,
4170  
4171      options: {
4172          update: false,
4173          append: false,
4174          evalScripts: true,
4175          filter: false
4176      },
4177  
4178      processHTML: function(text){
4179          var match = text.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
4180          text = (match) ? match[1] : text;
4181  
4182          var container = new Element('div');
4183  
4184          return $try(function(){
4185              var root = '<root>' + text + '</root>', doc;
4186              if (Browser.Engine.trident){
4187                  doc = new ActiveXObject('Microsoft.XMLDOM');
4188                  doc.async = false;
4189                  doc.loadXML(root);
4190              } else {
4191                  doc = new DOMParser().parseFromString(root, 'text/xml');
4192              }
4193              root = doc.getElementsByTagName('root')[0];
4194              if (!root) return null;
4195              for (var i = 0, k = root.childNodes.length; i < k; i++){
4196                  var child = Element.clone(root.childNodes[i], true, true);
4197                  if (child) container.grab(child);
4198              }
4199              return container;
4200          }) || container.set('html', text);
4201      },
4202  
4203      success: function(text){
4204          var options = this.options, response = this.response;
4205  
4206          response.html = text.stripScripts(function(script){
4207              response.javascript = script;
4208          });
4209  
4210          var temp = this.processHTML(response.html);
4211  
4212          response.tree = temp.childNodes;
4213          response.elements = temp.getElements('*');
4214  
4215          if (options.filter) response.tree = response.elements.filter(options.filter);
4216          if (options.update) document.id(options.update).empty().set('html', response.html);
4217          else if (options.append) document.id(options.append).adopt(temp.getChildren());
4218          if (options.evalScripts) $exec(response.javascript);
4219  
4220          this.onSuccess(response.tree, response.elements, response.html, response.javascript);
4221      }
4222  
4223  });
4224  
4225  Element.Properties.load = {
4226  
4227      set: function(options){
4228          var load = this.retrieve('load');
4229          if (load) load.cancel();
4230          return this.eliminate('load').store('load:options', $extend({data: this, link: 'cancel', update: this, method: 'get'}, options));
4231      },
4232  
4233      get: function(options){
4234          if (options || ! this.retrieve('load')){
4235              if (options || !this.retrieve('load:options')) this.set('load', options);
4236              this.store('load', new Request.HTML(this.retrieve('load:options')));
4237          }
4238          return this.retrieve('load');
4239      }
4240  
4241  };
4242  
4243  Element.implement({
4244  
4245      load: function(){
4246          this.get('load').send(Array.link(arguments, {data: Object.type, url: String.type}));
4247          return this;
4248      }
4249  
4250  });
4251  
4252  
4253  /*
4254  ---
4255  
4256  name: Request.JSON
4257  
4258  description: Extends the basic Request Class with additional methods for sending and receiving JSON data.
4259  
4260  license: MIT-style license.
4261  
4262  requires: [Request, JSON]
4263  
4264  provides: [Request.JSON]
4265  
4266  ...
4267  */
4268  
4269  Request.JSON = new Class({
4270  
4271      Extends: Request,
4272  
4273      options: {
4274          secure: true
4275      },
4276  
4277      initialize: function(options){
4278          this.parent(options);
4279          this.headers.extend({'Accept': 'application/json', 'X-Request': 'JSON'});
4280      },
4281  
4282      success: function(text){
4283          this.response.json = JSON.decode(text, this.options.secure);
4284          this.onSuccess(this.response.json, text);
4285      }
4286  
4287  });
4288  
4289  /*
4290  ---
4291  
4292  script: More.js
4293  
4294  description: MooTools More
4295  
4296  license: MIT-style license
4297  
4298  authors:
4299  - Guillermo Rauch
4300  - Thomas Aylott
4301  - Scott Kyle
4302  
4303  requires:
4304  - core:1.2.4/MooTools
4305  
4306  provides: [MooTools.More]
4307  
4308  ...
4309  */
4310  
4311  MooTools.More = {
4312      'version': '1.2.4.2',
4313      'build': 'bd5a93c0913cce25917c48cbdacde568e15e02ef'
4314  };/*
4315  ---
4316  
4317  script: Fx.Elements.js
4318  
4319  description: Effect to change any number of CSS properties of any number of Elements.
4320  
4321  license: MIT-style license
4322  
4323  authors:
4324  - Valerio Proietti
4325  
4326  requires:
4327  - core:1.2.4/Fx.CSS
4328  - /MooTools.More
4329  
4330  provides: [Fx.Elements]
4331  
4332  ...
4333  */
4334  
4335  Fx.Elements = new Class({
4336  
4337      Extends: Fx.CSS,
4338  
4339      initialize: function(elements, options){
4340          this.elements = this.subject = $$(elements);
4341          this.parent(options);
4342      },
4343  
4344      compute: function(from, to, delta){
4345          var now = {};
4346          for (var i in from){
4347              var iFrom = from[i], iTo = to[i], iNow = now[i] = {};
4348              for (var p in iFrom) iNow[p] = this.parent(iFrom[p], iTo[p], delta);
4349          }
4350          return now;
4351      },
4352  
4353      set: function(now){
4354          for (var i in now){
4355              var iNow = now[i];
4356              for (var p in iNow) this.render(this.elements[i], p, iNow[p], this.options.unit);
4357          }
4358          return this;
4359      },
4360  
4361      start: function(obj){
4362          if (!this.check(obj)) return this;
4363          var from = {}, to = {};
4364          for (var i in obj){
4365              var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {};
4366              for (var p in iProps){
4367                  var parsed = this.prepare(this.elements[i], p, iProps[p]);
4368                  iFrom[p] = parsed.from;
4369                  iTo[p] = parsed.to;
4370              }
4371          }
4372          return this.parent(from, to);
4373      }
4374  
4375  });/*
4376  ---
4377  
4378  script: Fx.Accordion.js
4379  
4380  description: An Fx.Elements extension which allows you to easily create accordion type controls.
4381  
4382  license: MIT-style license
4383  
4384  authors:
4385  - Valerio Proietti
4386  
4387  requires:
4388  - core:1.2.4/Element.Event
4389  - /Fx.Elements
4390  
4391  provides: [Fx.Accordion]
4392  
4393  ...
4394  */
4395  
4396  var Accordion = Fx.Accordion = new Class({
4397  
4398      Extends: Fx.Elements,
4399  
4400      options: {/*
4401          onActive: $empty(toggler, section),
4402          onBackground: $empty(toggler, section),
4403          fixedHeight: false,
4404          fixedWidth: false,
4405          */
4406          display: 0,
4407          show: false,
4408          height: true,
4409          width: false,
4410          opacity: true,
4411          alwaysHide: false,
4412          trigger: 'click',
4413          initialDisplayFx: true,
4414          returnHeightToAuto: true
4415      },
4416  
4417      initialize: function(){
4418          var params = Array.link(arguments, {'container': Element.type, 'options': Object.type, 'togglers': $defined, 'elements': $defined});
4419          this.parent(params.elements, params.options);
4420          this.togglers = $$(params.togglers);
4421          this.container = document.id(params.container);
4422          this.previous = -1;
4423          this.internalChain = new Chain();
4424          if (this.options.alwaysHide) this.options.wait = true;
4425          if ($chk(this.options.show)){
4426              this.options.display = false;
4427              this.previous = this.options.show;
4428          }
4429          if (this.options.start){
4430              this.options.display = false;
4431              this.options.show = false;
4432          }
4433          this.effects = {};
4434          if (this.options.opacity) this.effects.opacity = 'fullOpacity';
4435          if (this.options.width) this.effects.width = this.options.fixedWidth ? 'fullWidth' : 'offsetWidth';
4436          if (this.options.height) this.effects.height = this.options.fixedHeight ? 'fullHeight' : 'scrollHeight';
4437          for (var i = 0, l = this.togglers.length; i < l; i++) this.addSection(this.togglers[i], this.elements[i]);
4438          this.elements.each(function(el, i){
4439              if (this.options.show === i){
4440                  this.fireEvent('active', [this.togglers[i], el]);
4441              } else {
4442                  for (var fx in this.effects) el.setStyle(fx, 0);
4443              }
4444          }, this);
4445          if ($chk(this.options.display)) this.display(this.options.display, this.options.initialDisplayFx);
4446          this.addEvent('complete', this.internalChain.callChain.bind(this.internalChain));
4447      },
4448  
4449      addSection: function(toggler, element){
4450          toggler = document.id(toggler);
4451          element = document.id(element);
4452          var test = this.togglers.contains(toggler);
4453          this.togglers.include(toggler);
4454          this.elements.include(element);
4455          var idx = this.togglers.indexOf(toggler);
4456          var displayer = this.display.bind(this, idx);
4457          toggler.store('accordion:display', displayer);
4458          toggler.addEvent(this.options.trigger, displayer);
4459          if (this.options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});
4460          if (this.options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});
4461          element.fullOpacity = 1;
4462          if (this.options.fixedWidth) element.fullWidth = this.options.fixedWidth;
4463          if (this.options.fixedHeight) element.fullHeight = this.options.fixedHeight;
4464          element.setStyle('overflow', 'hidden');
4465          if (!test){
4466              for (var fx in this.effects) element.setStyle(fx, 0);
4467          }
4468          return this;
4469      },
4470  
4471      detach: function(){
4472          this.togglers.each(function(toggler) {
4473              toggler.removeEvent(this.options.trigger, toggler.retrieve('accordion:display'));
4474          }, this);
4475      },
4476  
4477      display: function(index, useFx){
4478          if (!this.check(index, useFx)) return this;
4479          useFx = $pick(useFx, true);
4480          if (this.options.returnHeightToAuto){
4481              var prev = this.elements[this.previous];
4482              if (prev && !this.selfHidden){
4483                  for (var fx in this.effects){
4484                      prev.setStyle(fx, prev[this.effects[fx]]);
4485                  }
4486              }
4487          }
4488          index = ($type(index) == 'element') ? this.elements.indexOf(index) : index;
4489          if ((this.timer && this.options.wait) || (index === this.previous && !this.options.alwaysHide)) return this;
4490          this.previous = index;
4491          var obj = {};
4492          this.elements.each(function(el, i){
4493              obj[i] = {};
4494              var hide;
4495              if (i != index){
4496                  hide = true;
4497              } else if (this.options.alwaysHide && ((el.offsetHeight > 0 && this.options.height) || el.offsetWidth > 0 && this.options.width)){
4498                  hide = true;
4499                  this.selfHidden = true;
4500              }
4501              this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]);
4502              for (var fx in this.effects) obj[i][fx] = hide ? 0 : el[this.effects[fx]];
4503          }, this);
4504          this.internalChain.chain(function(){
4505              if (this.options.returnHeightToAuto && !this.selfHidden){
4506                  var el = this.elements[index];
4507                  if (el) el.setStyle('height', 'auto');
4508              };
4509          }.bind(this));
4510          return useFx ? this.start(obj) : this.set(obj);
4511      }
4512  
4513  });/*
4514  ---
4515  
4516  script: Fx.Scroll.js
4517  
4518  description: Effect to smoothly scroll any element, including the window.
4519  
4520  license: MIT-style license
4521  
4522  authors:
4523  - Valerio Proietti
4524  
4525  requires:
4526  - core:1.2.4/Fx
4527  - core:1.2.4/Element.Event
4528  - core:1.2.4/Element.Dimensions
4529  - /MooTools.More
4530  
4531  provides: [Fx.Scroll]
4532  
4533  ...
4534  */
4535  
4536  Fx.Scroll = new Class({
4537  
4538      Extends: Fx,
4539  
4540      options: {
4541          offset: {x: 0, y: 0},
4542          wheelStops: true
4543      },
4544  
4545      initialize: function(element, options){
4546          this.element = this.subject = document.id(element);
4547          this.parent(options);
4548          var cancel = this.cancel.bind(this, false);
4549  
4550          if ($type(this.element) != 'element') this.element = document.id(this.element.getDocument().body);
4551  
4552          var stopper = this.element;
4553  
4554          if (this.options.wheelStops){
4555              this.addEvent('start', function(){
4556                  stopper.addEvent('mousewheel', cancel);
4557              }, true);
4558              this.addEvent('complete', function(){
4559                  stopper.removeEvent('mousewheel', cancel);
4560              }, true);
4561          }
4562      },
4563  
4564      set: function(){
4565          var now = Array.flatten(arguments);
4566          if (Browser.Engine.gecko) now = [Math.round(now[0]), Math.round(now[1])];
4567          this.element.scrollTo(now[0], now[1]);
4568      },
4569  
4570      compute: function(from, to, delta){
4571          return [0, 1].map(function(i){
4572              return Fx.compute(from[i], to[i], delta);
4573          });
4574      },
4575  
4576      start: function(x, y){
4577          if (!this.check(x, y)) return this;
4578          var scrollSize = this.element.getScrollSize(),
4579              scroll = this.element.getScroll(), 
4580              values = {x: x, y: y};
4581          for (var z in values){
4582              var max = scrollSize[z];
4583              if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z] : max;
4584              else values[z] = scroll[z];
4585              values[z] += this.options.offset[z];
4586          }
4587          return this.parent([scroll.x, scroll.y], [values.x, values.y]);
4588      },
4589  
4590      toTop: function(){
4591          return this.start(false, 0);
4592      },
4593  
4594      toLeft: function(){
4595          return this.start(0, false);
4596      },
4597  
4598      toRight: function(){
4599          return this.start('right', false);
4600      },
4601  
4602      toBottom: function(){
4603          return this.start(false, 'bottom');
4604      },
4605  
4606      toElement: function(el){
4607          var position = document.id(el).getPosition(this.element);
4608          return this.start(position.x, position.y);
4609      },
4610  
4611      scrollIntoView: function(el, axes, offset){
4612          axes = axes ? $splat(axes) : ['x','y'];
4613          var to = {};
4614          el = document.id(el);
4615          var pos = el.getPosition(this.element);
4616          var size = el.getSize();
4617          var scroll = this.element.getScroll();
4618          var containerSize = this.element.getSize();
4619          var edge = {
4620              x: pos.x + size.x,
4621              y: pos.y + size.y
4622          };
4623          ['x','y'].each(function(axis) {
4624              if (axes.contains(axis)) {
4625                  if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis];
4626                  if (pos[axis] < scroll[axis]) to[axis] = pos[axis];
4627              }
4628              if (to[axis] == null) to[axis] = scroll[axis];
4629              if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
4630          }, this);
4631          if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
4632          return this;
4633      },
4634  
4635      scrollToCenter: function(el, axes, offset){
4636          axes = axes ? $splat(axes) : ['x', 'y'];
4637          el = $(el);
4638          var to = {},
4639              pos = el.getPosition(this.element),
4640              size = el.getSize(),
4641              scroll = this.element.getScroll(),
4642              containerSize = this.element.getSize(),
4643              edge = {
4644                  x: pos.x + size.x,
4645                  y: pos.y + size.y
4646              };
4647  
4648          ['x','y'].each(function(axis){
4649              if(axes.contains(axis)){
4650                  to[axis] = pos[axis] - (containerSize[axis] - size[axis])/2;
4651              }
4652              if(to[axis] == null) to[axis] = scroll[axis];
4653              if(offset && offset[axis]) to[axis] = to[axis] + offset[axis];
4654          }, this);
4655          if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
4656          return this;
4657      }
4658  
4659  });
4660  /*
4661  ---
4662  
4663  script: Fx.Slide.js
4664  
4665  description: Effect to slide an element in and out of view.
4666  
4667  license: MIT-style license
4668  
4669  authors:
4670  - Valerio Proietti
4671  
4672  requires:
4673  - core:1.2.4/Fx Element.Style
4674  - /MooTools.More
4675  
4676  provides: [Fx.Slide]
4677  
4678  ...
4679  */
4680  
4681  Fx.Slide = new Class({
4682  
4683      Extends: Fx,
4684  
4685      options: {
4686          mode: 'vertical',
4687          hideOverflow: true
4688      },
4689  
4690      initialize: function(element, options){
4691          this.addEvent('complete', function(){
4692              this.open = (this.wrapper['offset' + this.layout.capitalize()] != 0);
4693              if (this.open && Browser.Engine.webkit419) this.element.dispose().inject(this.wrapper);
4694          }, true);
4695          this.element = this.subject = document.id(element);
4696          this.parent(options);
4697          var wrapper = this.element.retrieve('wrapper');
4698          var styles = this.element.getStyles('margin', 'position', 'overflow');
4699          if (this.options.hideOverflow) styles = $extend(styles, {overflow: 'hidden'});
4700          this.wrapper = wrapper || new Element('div', {
4701              styles: styles
4702          }).wraps(this.element);
4703          this.element.store('wrapper', this.wrapper).setStyle('margin', 0);
4704          this.now = [];
4705          this.open = true;
4706      },
4707  
4708      vertical: function(){
4709          this.margin = 'margin-top';
4710          this.layout = 'height';
4711          this.offset = this.element.offsetHeight;
4712      },
4713  
4714      horizontal: function(){
4715          this.margin = 'margin-left';
4716          this.layout = 'width';
4717          this.offset = this.element.offsetWidth;
4718      },
4719  
4720      set: function(now){
4721          this.element.setStyle(this.margin, now[0]);
4722          this.wrapper.setStyle(this.layout, now[1]);
4723          return this;
4724      },
4725  
4726      compute: function(from, to, delta){
4727          return [0, 1].map(function(i){
4728              return Fx.compute(from[i], to[i], delta);
4729          });
4730      },
4731  
4732      start: function(how, mode){
4733          if (!this.check(how, mode)) return this;
4734          this[mode || this.options.mode]();
4735          var margin = this.element.getStyle(this.margin).toInt();
4736          var layout = this.wrapper.getStyle(this.layout).toInt();
4737          var caseIn = [[margin, layout], [0, this.offset]];
4738          var caseOut = [[margin, layout], [-this.offset, 0]];
4739          var start;
4740          switch (how){
4741              case 'in': start = caseIn; break;
4742              case 'out': start = caseOut; break;
4743              case 'toggle': start = (layout == 0) ? caseIn : caseOut;
4744          }
4745          return this.parent(start[0], start[1]);
4746      },
4747  
4748      slideIn: function(mode){
4749          return this.start('in', mode);
4750      },
4751  
4752      slideOut: function(mode){
4753          return this.start('out', mode);
4754      },
4755  
4756      hide: function(mode){
4757          this[mode || this.options.mode]();
4758          this.open = false;
4759          return this.set([-this.offset, 0]);
4760      },
4761  
4762      show: function(mode){
4763          this[mode || this.options.mode]();
4764          this.open = true;
4765          return this.set([0, this.offset]);
4766      },
4767  
4768      toggle: function(mode){
4769          return this.start('toggle', mode);
4770      }
4771  
4772  });
4773  
4774  Element.Properties.slide = {
4775  
4776      set: function(options){
4777          var slide = this.retrieve('slide');
4778          if (slide) slide.cancel();
4779          return this.eliminate('slide').store('slide:options', $extend({link: 'cancel'}, options));
4780      },
4781  
4782      get: function(options){
4783          if (options || !this.retrieve('slide')){
4784              if (options || !this.retrieve('slide:options')) this.set('slide', options);
4785              this.store('slide', new Fx.Slide(this, this.retrieve('slide:options')));
4786          }
4787          return this.retrieve('slide');
4788      }
4789  
4790  };
4791  
4792  Element.implement({
4793  
4794      slide: function(how, mode){
4795          how = how || 'toggle';
4796          var slide = this.get('slide'), toggle;
4797          switch (how){
4798              case 'hide': slide.hide(mode); break;
4799              case 'show': slide.show(mode); break;
4800              case 'toggle':
4801                  var flag = this.retrieve('slide:flag', slide.open);
4802                  slide[flag ? 'slideOut' : 'slideIn'](mode);
4803                  this.store('slide:flag', !flag);
4804                  toggle = true;
4805              break;
4806              default: slide.start(how, mode);
4807          }
4808          if (!toggle) this.eliminate('slide:flag');
4809          return this;
4810      }
4811  
4812  });
4813  /*
4814  ---
4815  
4816  script: Fx.SmoothScroll.js
4817  
4818  description: Class for creating a smooth scrolling effect to all internal links on the page.
4819  
4820  license: MIT-style license
4821  
4822  authors:
4823  - Valerio Proietti
4824  
4825  requires:
4826  - core:1.2.4/Selectors
4827  - /Fx.Scroll
4828  
4829  provides: [Fx.SmoothScroll]
4830  
4831  ...
4832  */
4833  
4834  var SmoothScroll = Fx.SmoothScroll = new Class({
4835  
4836      Extends: Fx.Scroll,
4837  
4838      initialize: function(options, context){
4839          context = context || document;
4840          this.doc = context.getDocument();
4841          var win = context.getWindow();
4842          this.parent(this.doc, options);
4843          this.links = $$(this.options.links || this.doc.links);
4844          var location = win.location.href.match(/^[^#]*/)[0] + '#';
4845          this.links.each(function(link){
4846              if (link.href.indexOf(location) != 0) {return;}
4847              var anchor = link.href.substr(location.length);
4848              if (anchor) this.useLink(link, anchor);
4849          }, this);
4850          if (!Browser.Engine.webkit419) {
4851              this.addEvent('complete', function(){
4852                  win.location.hash = this.anchor;
4853              }, true);
4854          }
4855      },
4856  
4857      useLink: function(link, anchor){
4858          var el;
4859          link.addEvent('click', function(event){
4860              if (el !== false && !el) el = document.id(anchor) || this.doc.getElement('a[name=' + anchor + ']');
4861              if (el) {
4862                  event.preventDefault();
4863                  this.anchor = anchor;
4864                  this.toElement(el).chain(function(){
4865                      this.fireEvent('scrolledTo', [link, el]);
4866                  }.bind(this));
4867                  link.blur();
4868              }
4869          }.bind(this));
4870      }
4871  });/*
4872  ---
4873  
4874  script: Drag.js
4875  
4876  description: The base Drag Class. Can be used to drag and resize Elements using mouse events.
4877  
4878  license: MIT-style license
4879  
4880  authors:
4881  - Valerio Proietti
4882  - Tom Occhinno
4883  - Jan Kassens
4884  
4885  requires:
4886  - core:1.2.4/Events
4887  - core:1.2.4/Options
4888  - core:1.2.4/Element.Event
4889  - core:1.2.4/Element.Style
4890  - /MooTools.More
4891  
4892  provides: [Drag]
4893  
4894  */
4895  
4896  var Drag = new Class({
4897  
4898      Implements: [Events, Options],
4899  
4900      options: {/*
4901          onBeforeStart: $empty(thisElement),
4902          onStart: $empty(thisElement, event),
4903          onSnap: $empty(thisElement)
4904          onDrag: $empty(thisElement, event),
4905          onCancel: $empty(thisElement),
4906          onComplete: $empty(thisElement, event),*/
4907          snap: 6,
4908          unit: 'px',
4909          grid: false,
4910          style: true,
4911          limit: false,
4912          handle: false,
4913          invert: false,
4914          preventDefault: false,
4915          stopPropagation: false,
4916          modifiers: {x: 'left', y: 'top'}
4917      },
4918  
4919      initialize: function(){
4920          var params = Array.link(arguments, {'options': Object.type, 'element': $defined});
4921          this.element = document.id(params.element);
4922          this.document = this.element.getDocument();
4923          this.setOptions(params.options || {});
4924          var htype = $type(this.options.handle);
4925          this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element;
4926          this.mouse = {'now': {}, 'pos': {}};
4927          this.value = {'start': {}, 'now': {}};
4928  
4929          this.selection = (Browser.Engine.trident) ? 'selectstart' : 'mousedown';
4930  
4931          this.bound = {
4932              start: this.start.bind(this),
4933              check: this.check.bind(this),
4934              drag: this.drag.bind(this),
4935              stop: this.stop.bind(this),
4936              cancel: this.cancel.bind(this),
4937              eventStop: $lambda(false)
4938          };
4939          this.attach();
4940      },
4941  
4942      attach: function(){
4943          this.handles.addEvent('mousedown', this.bound.start);
4944          return this;
4945      },
4946  
4947      detach: function(){
4948          this.handles.removeEvent('mousedown', this.bound.start);
4949          return this;
4950      },
4951  
4952      start: function(event){
4953          if (event.rightClick) return;
4954          if (this.options.preventDefault) event.preventDefault();
4955          if (this.options.stopPropagation) event.stopPropagation();
4956          this.mouse.start = event.page;
4957          this.fireEvent('beforeStart', this.element);
4958          var limit = this.options.limit;
4959          this.limit = {x: [], y: []};
4960          for (var z in this.options.modifiers){
4961              if (!this.options.modifiers[z]) continue;
4962              if (this.options.style) this.value.now[z] = this.element.getStyle(this.options.modifiers[z]).toInt();
4963              else this.value.now[z] = this.element[this.options.modifiers[z]];
4964              if (this.options.invert) this.value.now[z] *= -1;
4965              this.mouse.pos[z] = event.page[z] - this.value.now[z];
4966              if (limit && limit[z]){
4967                  for (var i = 2; i--; i){
4968                      if ($chk(limit[z][i])) this.limit[z][i] = $lambda(limit[z][i])();
4969                  }
4970              }
4971          }
4972          if ($type(this.options.grid) == 'number') this.options.grid = {x: this.options.grid, y: this.options.grid};
4973          this.document.addEvents({mousemove: this.bound.check, mouseup: this.bound.cancel});
4974          this.document.addEvent(this.selection, this.bound.eventStop);
4975      },
4976  
4977      check: function(event){
4978          if (this.options.preventDefault) event.preventDefault();
4979          var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
4980          if (distance > this.options.snap){
4981              this.cancel();
4982              this.document.addEvents({
4983                  mousemove: this.bound.drag,
4984                  mouseup: this.bound.stop
4985              });
4986              this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element);
4987          }
4988      },
4989  
4990      drag: function(event){
4991          if (this.options.preventDefault) event.preventDefault();
4992          this.mouse.now = event.page;
4993          for (var z in this.options.modifiers){
4994              if (!this.options.modifiers[z]) continue;
4995              this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
4996              if (this.options.invert) this.value.now[z] *= -1;
4997              if (this.options.limit && this.limit[z]){
4998                  if ($chk(this.limit[z][1]) && (this.value.now[z] > this.limit[z][1])){
4999                      this.value.now[z] = this.limit[z][1];
5000                  } else if ($chk(this.limit[z][0]) && (this.value.now[z] < this.limit[z][0])){
5001                      this.value.now[z] = this.limit[z][0];
5002                  }
5003              }
5004              if (this.options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % this.options.grid[z]);
5005              if (this.options.style) {
5006                  this.element.setStyle(this.options.modifiers[z], this.value.now[z] + this.options.unit);
5007              } else {
5008                  this.element[this.options.modifiers[z]] = this.value.now[z];
5009              }
5010          }
5011          this.fireEvent('drag', [this.element, event]);
5012      },
5013  
5014      cancel: function(event){
5015          this.document.removeEvent('mousemove', this.bound.check);
5016          this.document.removeEvent('mouseup', this.bound.cancel);
5017          if (event){
5018              this.document.removeEvent(this.selection, this.bound.eventStop);
5019              this.fireEvent('cancel', this.element);
5020          }
5021      },
5022  
5023      stop: function(event){
5024          this.document.removeEvent(this.selection, this.bound.eventStop);
5025          this.document.removeEvent('mousemove', this.bound.drag);
5026          this.document.removeEvent('mouseup', this.bound.stop);
5027          if (event) this.fireEvent('complete', [this.element, event]);
5028      }
5029  
5030  });
5031  
5032  Element.implement({
5033  
5034      makeResizable: function(options){
5035          var drag = new Drag(this, $merge({modifiers: {x: 'width', y: 'height'}}, options));
5036          this.store('resizer', drag);
5037          return drag.addEvent('drag', function(){
5038              this.fireEvent('resize', drag);
5039          }.bind(this));
5040      }
5041  
5042  });
5043  /*
5044  ---
5045  
5046  script: Drag.Move.js
5047  
5048  description: A Drag extension that provides support for the constraining of draggables to containers and droppables.
5049  
5050  license: MIT-style license
5051  
5052  authors:
5053  - Valerio Proietti
5054  - Tom Occhinno
5055  - Jan Kassens
5056  - Aaron Newton
5057  - Scott Kyle
5058  
5059  requires:
5060  - core:1.2.4/Element.Dimensions
5061  - /Drag
5062  
5063  provides: [Drag.Move]
5064  
5065  ...
5066  */
5067  
5068  Drag.Move = new Class({
5069  
5070      Extends: Drag,
5071  
5072      options: {/*
5073          onEnter: $empty(thisElement, overed),
5074          onLeave: $empty(thisElement, overed),
5075          onDrop: $empty(thisElement, overed, event),*/
5076          droppables: [],
5077          container: false,
5078          precalculate: false,
5079          includeMargins: true,
5080          checkDroppables: true
5081      },
5082  
5083      initialize: function(element, options){
5084          this.parent(element, options);
5085          element = this.element;
5086          
5087          this.droppables = $$(this.options.droppables);
5088          this.container = document.id(this.options.container);
5089          
5090          if (this.container && $type(this.container) != 'element')
5091              this.container = document.id(this.container.getDocument().body);
5092          
5093          var styles = element.getStyles('left', 'right', 'position');
5094          if (styles.left == 'auto' || styles.top == 'auto')
5095              element.setPosition(element.getPosition(element.getOffsetParent()));
5096          
5097          if (styles.position == 'static')
5098              element.setStyle('position', 'absolute');
5099  
5100          this.addEvent('start', this.checkDroppables, true);
5101  
5102          this.overed = null;
5103      },
5104  
5105      start: function(event){
5106          if (this.container) this.options.limit = this.calculateLimit();
5107          
5108          if (this.options.precalculate){
5109              this.positions = this.droppables.map(function(el){
5110                  return el.getCoordinates();
5111              });
5112          }
5113          
5114          this.parent(event);
5115      },
5116      
5117      calculateLimit: function(){
5118          var offsetParent = this.element.getOffsetParent(),
5119              containerCoordinates = this.container.getCoordinates(offsetParent),
5120              containerBorder = {},
5121              elementMargin = {},
5122              elementBorder = {},
5123              containerMargin = {},
5124              offsetParentPadding = {};
5125  
5126          ['top', 'right', 'bottom', 'left'].each(function(pad){
5127              containerBorder[pad] = this.container.getStyle('border-' + pad).toInt();
5128              elementBorder[pad] = this.element.getStyle('border-' + pad).toInt();
5129              elementMargin[pad] = this.element.getStyle('margin-' + pad).toInt();
5130              containerMargin[pad] = this.container.getStyle('margin-' + pad).toInt();
5131              offsetParentPadding[pad] = offsetParent.getStyle('padding-' + pad).toInt();
5132          }, this);
5133  
5134          var width = this.element.offsetWidth + elementMargin.left + elementMargin.right,
5135              height = this.element.offsetHeight + elementMargin.top + elementMargin.bottom,
5136              left = 0,
5137              top = 0,
5138              right = containerCoordinates.right - containerBorder.right - width,
5139              bottom = containerCoordinates.bottom - containerBorder.bottom - height;
5140  
5141          if (this.options.includeMargins){
5142              left += elementMargin.left;
5143              top += elementMargin.top;
5144          } else {
5145              right += elementMargin.right;
5146              bottom += elementMargin.bottom;
5147          }
5148          
5149          if (this.element.getStyle('position') == 'relative'){
5150              var coords = this.element.getCoordinates(offsetParent);
5151              coords.left -= this.element.getStyle('left').toInt();
5152              coords.top -= this.element.getStyle('top').toInt();
5153              
5154              left += containerBorder.left - coords.left;
5155              top += containerBorder.top - coords.top;
5156              right += elementMargin.left - coords.left;
5157              bottom += elementMargin.top - coords.top;
5158              
5159              if (this.container != offsetParent){
5160                  left += containerMargin.left + offsetParentPadding.left;
5161                  top += (Browser.Engine.trident4 ? 0 : containerMargin.top) + offsetParentPadding.top;
5162              }
5163          } else {
5164              left -= elementMargin.left;
5165              top -= elementMargin.top;
5166              
5167              if (this.container == offsetParent){
5168                  right -= containerBorder.left;
5169                  bottom -= containerBorder.top;
5170              } else {
5171                  left += containerCoordinates.left + containerBorder.left;
5172                  top += containerCoordinates.top + containerBorder.top;
5173              }
5174          }
5175          
5176          return {
5177              x: [left, right],
5178              y: [top, bottom]
5179          };
5180      },
5181  
5182      checkAgainst: function(el, i){
5183          el = (this.positions) ? this.positions[i] : el.getCoordinates();
5184          var now = this.mouse.now;
5185          return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
5186      },
5187  
5188      checkDroppables: function(){
5189          var overed = this.droppables.filter(this.checkAgainst, this).getLast();
5190          if (this.overed != overed){
5191              if (this.overed) this.fireEvent('leave', [this.element, this.overed]);
5192              if (overed) this.fireEvent('enter', [this.element, overed]);
5193              this.overed = overed;
5194          }
5195      },
5196  
5197      drag: function(event){
5198          this.parent(event);
5199          if (this.options.checkDroppables && this.droppables.length) this.checkDroppables();
5200      },
5201  
5202      stop: function(event){
5203          this.checkDroppables();
5204          this.fireEvent('drop', [this.element, this.overed, event]);
5205          this.overed = null;
5206          return this.parent(event);
5207      }
5208  
5209  });
5210  
5211  Element.implement({
5212  
5213      makeDraggable: function(options){
5214          var drag = new Drag.Move(this, options);
5215          this.store('dragger', drag);
5216          return drag;
5217      }
5218  
5219  });
5220  /*
5221  ---
5222  
5223  script: Class.Binds.js
5224  
5225  description: Automagically binds specified methods in a class to the instance of the class.
5226  
5227  license: MIT-style license
5228  
5229  authors:
5230  - Aaron Newton
5231  
5232  requires:
5233  - core:1.2.4/Class
5234  - /MooTools.More
5235  
5236  provides: [Class.Binds]
5237  
5238  ...
5239  */
5240  
5241  Class.Mutators.Binds = function(binds){
5242      return binds;
5243  };
5244  
5245  Class.Mutators.initialize = function(initialize){
5246      return function(){
5247          $splat(this.Binds).each(function(name){
5248              var original = this[name];
5249              if (original) this[name] = original.bind(this);
5250          }, this);
5251          return initialize.apply(this, arguments);
5252      };
5253  };
5254  /*
5255  ---
5256  
5257  script: Element.Measure.js
5258  
5259  description: Extends the Element native object to include methods useful in measuring dimensions.
5260  
5261  credits: "Element.measure / .expose methods by Daniel Steigerwald License: MIT-style license. Copyright: Copyright (c) 2008 Daniel Steigerwald, daniel.steigerwald.cz"
5262  
5263  license: MIT-style license
5264  
5265  authors:
5266  - Aaron Newton
5267  
5268  requires:
5269  - core:1.2.4/Element.Style
5270  - core:1.2.4/Element.Dimensions
5271  - /MooTools.More
5272  
5273  provides: [Element.Measure]
5274  
5275  ...
5276  */
5277  
5278  Element.implement({
5279  
5280      measure: function(fn){
5281          var vis = function(el) {
5282              return !!(!el || el.offsetHeight || el.offsetWidth);
5283          };
5284          if (vis(this)) return fn.apply(this);
5285          var parent = this.getParent(),
5286              restorers = [],
5287              toMeasure = []; 
5288          while (!vis(parent) && parent != document.body) {
5289              toMeasure.push(parent.expose());
5290              parent = parent.getParent();
5291          }
5292          var restore = this.expose();
5293          var result = fn.apply(this);
5294          restore();
5295          toMeasure.each(function(restore){
5296              restore();
5297          });
5298          return result;
5299      },
5300  
5301      expose: function(){
5302          if (this.getStyle('display') != 'none') return $empty;
5303          var before = this.style.cssText;
5304          this.setStyles({
5305              display: 'block',
5306              position: 'absolute',
5307              visibility: 'hidden'
5308          });
5309          return function(){
5310              this.style.cssText = before;
5311          }.bind(this);
5312      },
5313  
5314      getDimensions: function(options){
5315          options = $merge({computeSize: false},options);
5316          var dim = {};
5317          var getSize = function(el, options){
5318              return (options.computeSize)?el.getComputedSize(options):el.getSize();
5319          };
5320          var parent = this.getParent('body');
5321          if (parent && this.getStyle('display') == 'none'){
5322              dim = this.measure(function(){
5323                  return getSize(this, options);
5324              });
5325          } else if (parent){
5326              try { //safari sometimes crashes here, so catch it
5327                  dim = getSize(this, options);
5328              }catch(e){}
5329          } else {
5330              dim = {x: 0, y: 0};
5331          }
5332          return $chk(dim.x) ? $extend(dim, {width: dim.x, height: dim.y}) : $extend(dim, {x: dim.width, y: dim.height});
5333      },
5334  
5335      getComputedSize: function(options){
5336          options = $merge({
5337              styles: ['padding','border'],
5338              plains: {
5339                  height: ['top','bottom'],
5340                  width: ['left','right']
5341              },
5342              mode: 'both'
5343          }, options);
5344          var size = {width: 0,height: 0};
5345          switch (options.mode){
5346              case 'vertical':
5347                  delete size.width;
5348                  delete options.plains.width;
5349                  break;
5350              case 'horizontal':
5351                  delete size.height;
5352                  delete options.plains.height;
5353                  break;
5354          }
5355          var getStyles = [];
5356          //this function might be useful in other places; perhaps it should be outside this function?
5357          $each(options.plains, function(plain, key){
5358              plain.each(function(edge){
5359                  options.styles.each(function(style){
5360                      getStyles.push((style == 'border') ? style + '-' + edge + '-' + 'width' : style + '-' + edge);
5361                  });
5362              });
5363          });
5364          var styles = {};
5365          getStyles.each(function(style){ styles[style] = this.getComputedStyle(style); }, this);
5366          var subtracted = [];
5367          $each(options.plains, function(plain, key){ //keys: width, height, plains: ['left', 'right'], ['top','bottom']
5368              var capitalized = key.capitalize();
5369              size['total' + capitalized] = size['computed' + capitalized] = 0;
5370              plain.each(function(edge){ //top, left, right, bottom
5371                  size['computed' + edge.capitalize()] = 0;
5372                  getStyles.each(function(style, i){ //padding, border, etc.
5373                      //'padding-left'.test('left') size['totalWidth'] = size['width'] + [padding-left]
5374                      if (style.test(edge)){
5375                          styles[style] = styles[style].toInt() || 0; //styles['padding-left'] = 5;
5376                          size['total' + capitalized] = size['total' + capitalized] + styles[style];
5377                          size['computed' + edge.capitalize()] = size['computed' + edge.capitalize()] + styles[style];
5378                      }
5379                      //if width != width (so, padding-left, for instance), then subtract that from the total
5380                      if (style.test(edge) && key != style &&
5381                          (style.test('border') || style.test('padding')) && !subtracted.contains(style)){
5382                          subtracted.push(style);
5383                          size['computed' + capitalized] = size['computed' + capitalized]-styles[style];
5384                      }
5385                  });
5386              });
5387          });
5388  
5389          ['Width', 'Height'].each(function(value){
5390              var lower = value.toLowerCase();
5391              if(!$chk(size[lower])) return;
5392  
5393              size[lower] = size[lower] + this['offset' + value] + size['computed' + value];
5394              size['total' + value] = size[lower] + size['total' + value];
5395              delete size['computed' + value];
5396          }, this);
5397  
5398          return $extend(styles, size);
5399      }
5400  
5401  });/*
5402  ---
5403  
5404  script: Slider.js
5405  
5406  description: Class for creating horizontal and vertical slider controls.
5407  
5408  license: MIT-style license
5409  
5410  authors:
5411  - Valerio Proietti
5412  
5413  requires:
5414  - core:1.2.4/Element.Dimensions
5415  - /Class.Binds
5416  - /Drag
5417  - /Element.Dimensions
5418  - /Element.Measure
5419  
5420  provides: [Slider]
5421  
5422  ...
5423  */
5424  
5425  var Slider = new Class({
5426  
5427      Implements: [Events, Options],
5428  
5429      Binds: ['clickedElement', 'draggedKnob', 'scrolledElement'],
5430  
5431      options: {/*
5432          onTick: $empty(intPosition),
5433          onChange: $empty(intStep),
5434          onComplete: $empty(strStep),*/
5435          onTick: function(position){
5436              if (this.options.snap) position = this.toPosition(this.step);
5437              this.knob.setStyle(this.property, position);
5438          },
5439          initialStep: 0,
5440          snap: false,
5441          offset: 0,
5442          range: false,
5443          wheel: false,
5444          steps: 100,
5445          mode: 'horizontal'
5446      },
5447  
5448      initialize: function(element, knob, options){
5449          this.setOptions(options);
5450          this.element = document.id(element);
5451          this.knob = document.id(knob);
5452          this.previousChange = this.previousEnd = this.step = -1;
5453          var offset, limit = {}, modifiers = {'x': false, 'y': false};
5454          switch (this.options.mode){
5455              case 'vertical':
5456                  this.axis = 'y';
5457                  this.property = 'top';
5458                  offset = 'offsetHeight';
5459                  break;
5460              case 'horizontal':
5461                  this.axis = 'x';
5462                  this.property = 'left';
5463                  offset = 'offsetWidth';
5464          }
5465          
5466          this.full = this.element.measure(function(){ 
5467              this.half = this.knob[offset] / 2; 
5468              return this.element[offset] - this.knob[offset] + (this.options.offset * 2); 
5469          }.bind(this));
5470          
5471          this.min = $chk(this.options.range[0]) ? this.options.range[0] : 0;
5472          this.max = $chk(this.options.range[1]) ? this.options.range[1] : this.options.steps;
5473          this.range = this.max - this.min;
5474          this.steps = this.options.steps || this.full;
5475          this.stepSize = Math.abs(this.range) / this.steps;
5476          this.stepWidth = this.stepSize * this.full / Math.abs(this.range) ;
5477  
5478          this.knob.setStyle('position', 'relative').setStyle(this.property, this.options.initialStep ? this.toPosition(this.options.initialStep) : - this.options.offset);
5479          modifiers[this.axis] = this.property;
5480          limit[this.axis] = [- this.options.offset, this.full - this.options.offset];
5481  
5482          var dragOptions = {
5483              snap: 0,
5484              limit: limit,
5485              modifiers: modifiers,
5486              onDrag: this.draggedKnob,
5487              onStart: this.draggedKnob,
5488              onBeforeStart: (function(){
5489                  this.isDragging = true;
5490              }).bind(this),
5491              onCancel: function() {
5492                  this.isDragging = false;
5493              }.bind(this),
5494              onComplete: function(){
5495                  this.isDragging = false;
5496                  this.draggedKnob();
5497                  this.end();
5498              }.bind(this)
5499          };
5500          if (this.options.snap){
5501              dragOptions.grid = Math.ceil(this.stepWidth);
5502              dragOptions.limit[this.axis][1] = this.full;
5503          }
5504  
5505          this.drag = new Drag(this.knob, dragOptions);
5506          this.attach();
5507      },
5508  
5509      attach: function(){
5510          this.element.addEvent('mousedown', this.clickedElement);
5511          if (this.options.wheel) this.element.addEvent('mousewheel', this.scrolledElement);
5512          this.drag.attach();
5513          return this;
5514      },
5515  
5516      detach: function(){
5517          this.element.removeEvent('mousedown', this.clickedElement);
5518          this.element.removeEvent('mousewheel', this.scrolledElement);
5519          this.drag.detach();
5520          return this;
5521      },
5522  
5523      set: function(step){
5524          if (!((this.range > 0) ^ (step < this.min))) step = this.min;
5525          if (!((this.range > 0) ^ (step > this.max))) step = this.max;
5526  
5527          this.step = Math.round(step);
5528          this.checkStep();
5529          this.fireEvent('tick', this.toPosition(this.step));
5530          this.end();
5531          return this;
5532      },
5533  
5534      clickedElement: function(event){
5535          if (this.isDragging || event.target == this.knob) return;
5536  
5537          var dir = this.range < 0 ? -1 : 1;
5538          var position = event.page[this.axis] - this.element.getPosition()[this.axis] - this.half;
5539          position = position.limit(-this.options.offset, this.full -this.options.offset);
5540  
5541          this.step = Math.round(this.min + dir * this.toStep(position));
5542          this.checkStep();
5543          this.fireEvent('tick', position);
5544          this.end();
5545      },
5546  
5547      scrolledElement: function(event){
5548          var mode = (this.options.mode == 'horizontal') ? (event.wheel < 0) : (event.wheel > 0);
5549          this.set(mode ? this.step - this.stepSize : this.step + this.stepSize);
5550          event.stop();
5551      },
5552  
5553      draggedKnob: function(){
5554          var dir = this.range < 0 ? -1 : 1;
5555          var position = this.drag.value.now[this.axis];
5556          position = position.limit(-this.options.offset, this.full -this.options.offset);
5557          this.step = Math.round(this.min + dir * this.toStep(position));
5558          this.checkStep();
5559      },
5560  
5561      checkStep: function(){
5562          if (this.previousChange != this.step){
5563              this.previousChange = this.step;
5564              this.fireEvent('change', this.step);
5565          }
5566      },
5567  
5568      end: function(){
5569          if (this.previousEnd !== this.step){
5570              this.previousEnd = this.step;
5571              this.fireEvent('complete', this.step + '');
5572          }
5573      },
5574  
5575      toStep: function(position){
5576          var step = (position + this.options.offset) * this.stepSize / this.full * this.steps;
5577          return this.options.steps ? Math.round(step -= step % this.stepSize) : step;
5578      },
5579  
5580      toPosition: function(step){
5581          return (this.full * Math.abs(this.min - step)) / (this.steps * this.stepSize) - this.options.offset;
5582      }
5583  
5584  });/*
5585  ---
5586  
5587  script: Sortables.js
5588  
5589  description: Class for creating a drag and drop sorting interface for lists of items.
5590  
5591  license: MIT-style license
5592  
5593  authors:
5594  - Tom Occhino
5595  
5596  requires:
5597  - /Drag.Move
5598  
5599  provides: [Slider]
5600  
5601  ...
5602  */
5603  
5604  var Sortables = new Class({
5605  
5606      Implements: [Events, Options],
5607  
5608      options: {/*
5609          onSort: $empty(element, clone),
5610          onStart: $empty(element, clone),
5611          onComplete: $empty(element),*/
5612          snap: 4,
5613          opacity: 1,
5614          clone: false,
5615          revert: false,
5616          handle: false,
5617          constrain: false
5618      },
5619  
5620      initialize: function(lists, options){
5621          this.setOptions(options);
5622          this.elements = [];
5623          this.lists = [];
5624          this.idle = true;
5625  
5626          this.addLists($$(document.id(lists) || lists));
5627          if (!this.options.clone) this.options.revert = false;
5628          if (this.options.revert) this.effect = new Fx.Morph(null, $merge({duration: 250, link: 'cancel'}, this.options.revert));
5629      },
5630  
5631      attach: function(){
5632          this.addLists(this.lists);
5633          return this;
5634      },
5635  
5636      detach: function(){
5637          this.lists = this.removeLists(this.lists);
5638          return this;
5639      },
5640  
5641      addItems: function(){
5642          Array.flatten(arguments).each(function(element){
5643              this.elements.push(element);
5644              var start = element.retrieve('sortables:start', this.start.bindWithEvent(this, element));
5645              (this.options.handle ? element.getElement(this.options.handle) || element : element).addEvent('mousedown', start);
5646          }, this);
5647          return this;
5648      },
5649  
5650      addLists: function(){
5651          Array.flatten(arguments).each(function(list){
5652              this.lists.push(list);
5653              this.addItems(list.getChildren());
5654          }, this);
5655          return this;
5656      },
5657  
5658      removeItems: function(){
5659          return $$(Array.flatten(arguments).map(function(element){
5660              this.elements.erase(element);
5661              var start = element.retrieve('sortables:start');
5662              (this.options.handle ? element.getElement(this.options.handle) || element : element).removeEvent('mousedown', start);
5663              
5664              return element;
5665          }, this));
5666      },
5667  
5668      removeLists: function(){
5669          return $$(Array.flatten(arguments).map(function(list){
5670              this.lists.erase(list);
5671              this.removeItems(list.getChildren());
5672              
5673              return list;
5674          }, this));
5675      },
5676  
5677      getClone: function(event, element){
5678          if (!this.options.clone) return new Element('div').inject(document.body);
5679          if ($type(this.options.clone) == 'function') return this.options.clone.call(this, event, element, this.list);
5680          return element.clone(true).setStyles({
5681              margin: '0px',
5682              position: 'absolute',
5683              visibility: 'hidden',
5684              'width': element.getStyle('width')
5685          }).inject(this.list).setPosition(element.getPosition(element.getOffsetParent()));
5686      },
5687  
5688      getDroppables: function(){
5689          var droppables = this.list.getChildren();
5690          if (!this.options.constrain) droppables = this.lists.concat(droppables).erase(this.list);
5691          return droppables.erase(this.clone).erase(this.element);
5692      },
5693  
5694      insert: function(dragging, element){
5695          var where = 'inside';
5696          if (this.lists.contains(element)){
5697              this.list = element;
5698              this.drag.droppables = this.getDroppables();
5699          } else {
5700              where = this.element.getAllPrevious().contains(element) ? 'before' : 'after';
5701          }
5702          this.element.inject(element, where);
5703          this.fireEvent('sort', [this.element, this.clone]);
5704      },
5705  
5706      start: function(event, element){
5707          if (!this.idle) return;
5708          this.idle = false;
5709          this.element = element;
5710          this.opacity = element.get('opacity');
5711          this.list = element.getParent();
5712          this.clone = this.getClone(event, element);
5713  
5714          this.drag = new Drag.Move(this.clone, {
5715              snap: this.options.snap,
5716              container: this.options.constrain && this.element.getParent(),
5717              droppables: this.getDroppables(),
5718              onSnap: function(){
5719                  event.stop();
5720                  this.clone.setStyle('visibility', 'visible');
5721                  this.element.set('opacity', this.options.opacity || 0);
5722                  this.fireEvent('start', [this.element, this.clone]);
5723              }.bind(this),
5724              onEnter: this.insert.bind(this),
5725              onCancel: this.reset.bind(this),
5726              onComplete: this.end.bind(this)
5727          });
5728  
5729          this.clone.inject(this.element, 'before');
5730          this.drag.start(event);
5731      },
5732  
5733      end: function(){
5734          this.drag.detach();
5735          this.element.set('opacity', this.opacity);
5736          if (this.effect){
5737              var dim = this.element.getStyles('width', 'height');
5738              var pos = this.clone.computePosition(this.element.getPosition(this.clone.offsetParent));
5739              this.effect.element = this.clone;
5740              this.effect.start({
5741                  top: pos.top,
5742                  left: pos.left,
5743                  width: dim.width,
5744                  height: dim.height,
5745                  opacity: 0.25
5746              }).chain(this.reset.bind(this));
5747          } else {
5748              this.reset();
5749          }
5750      },
5751  
5752      reset: function(){
5753          this.idle = true;
5754          this.clone.destroy();
5755          this.fireEvent('complete', this.element);
5756      },
5757  
5758      serialize: function(){
5759          var params = Array.link(arguments, {modifier: Function.type, index: $defined});
5760          var serial = this.lists.map(function(list){
5761              return list.getChildren().map(params.modifier || function(element){
5762                  return element.get('id');
5763              }, this);
5764          }, this);
5765  
5766          var index = params.index;
5767          if (this.lists.length == 1) index = 0;
5768          return $chk(index) && index >= 0 && index < this.lists.length ? serial[index] : serial;
5769      }
5770  
5771  });
5772  /*
5773  ---
5774  
5775  script: Color.js
5776  
5777  description: Class for creating and manipulating colors in JavaScript. Supports HSB -> RGB Conversions and vice versa.
5778  
5779  license: MIT-style license
5780  
5781  authors:
5782  - Valerio Proietti
5783  
5784  requires:
5785  - core:1.2.4/Array
5786  - core:1.2.4/String
5787  - core:1.2.4/Number
5788  - core:1.2.4/Hash
5789  - core:1.2.4/Function
5790  - core:1.2.4/$util
5791  
5792  provides: [Color]
5793  
5794  ...
5795  */
5796  
5797  var Color = new Native({
5798  
5799      initialize: function(color, type){
5800          if (arguments.length >= 3){
5801              type = 'rgb'; color = Array.slice(arguments, 0, 3);
5802          } else if (typeof color == 'string'){
5803              if (color.match(/rgb/)) color = color.rgbToHex().hexToRgb(true);
5804              else if (color.match(/hsb/)) color = color.hsbToRgb();
5805              else color = color.hexToRgb(true);
5806          }
5807          type = type || 'rgb';
5808          switch (type){
5809              case 'hsb':
5810                  var old = color;
5811                  color = color.hsbToRgb();
5812                  color.hsb = old;
5813              break;
5814              case 'hex': color = color.hexToRgb(true); break;
5815          }
5816          color.rgb = color.slice(0, 3);
5817          color.hsb = color.hsb || color.rgbToHsb();
5818          color.hex = color.rgbToHex();
5819          return $extend(color, this);
5820      }
5821  
5822  });
5823  
5824  Color.implement({
5825  
5826      mix: function(){
5827          var colors = Array.slice(arguments);
5828          var alpha = ($type(colors.getLast()) == 'number') ? colors.pop() : 50;
5829          var rgb = this.slice();
5830          colors.each(function(color){
5831              color = new Color(color);
5832              for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] / 100 * (100 - alpha)) + (color[i] / 100 * alpha));
5833          });
5834          return new Color(rgb, 'rgb');
5835      },
5836  
5837      invert: function(){
5838          return new Color(this.map(function(value){
5839              return 255 - value;
5840          }));
5841      },
5842  
5843      setHue: function(value){
5844          return new Color([value, this.hsb[1], this.hsb[2]], 'hsb');
5845      },
5846  
5847      setSaturation: function(percent){
5848          return new Color([this.hsb[0], percent, this.hsb[2]], 'hsb');
5849      },
5850  
5851      setBrightness: function(percent){
5852          return new Color([this.hsb[0], this.hsb[1], percent], 'hsb');
5853      }
5854  
5855  });
5856  
5857  var $RGB = function(r, g, b){
5858      return new Color([r, g, b], 'rgb');
5859  };
5860  
5861  var $HSB = function(h, s, b){
5862      return new Color([h, s, b], 'hsb');
5863  };
5864  
5865  var $HEX = function(hex){
5866      return new Color(hex, 'hex');
5867  };
5868  
5869  Array.implement({
5870  
5871      rgbToHsb: function(){
5872          var red = this[0],
5873                  green = this[1],
5874                  blue = this[2],
5875                  hue = 0;
5876          var max = Math.max(red, green, blue),
5877                  min = Math.min(red, green, blue);
5878          var delta = max - min;
5879          var brightness = max / 255,
5880                  saturation = (max != 0) ? delta / max : 0;
5881          if(saturation != 0) {
5882              var rr = (max - red) / delta;
5883              var gr = (max - green) / delta;
5884              var br = (max - blue) / delta;
5885              if (red == max) hue = br - gr;
5886              else if (green == max) hue = 2 + rr - br;
5887              else hue = 4 + gr - rr;
5888              hue /= 6;
5889              if (hue < 0) hue++;
5890          }
5891          return [Math.round(hue * 360), Math.round(saturation * 100), Math.round(brightness * 100)];
5892      },
5893  
5894      hsbToRgb: function(){
5895          var br = Math.round(this[2] / 100 * 255);
5896          if (this[1] == 0){
5897              return [br, br, br];
5898          } else {
5899              var hue = this[0] % 360;
5900              var f = hue % 60;
5901              var p = Math.round((this[2] * (100 - this[1])) / 10000 * 255);
5902              var q = Math.round((this[2] * (6000 - this[1] * f)) / 600000 * 255);
5903              var t = Math.round((this[2] * (6000 - this[1] * (60 - f))) / 600000 * 255);
5904              switch (Math.floor(hue / 60)){
5905                  case 0: return [br, t, p];
5906                  case 1: return [q, br, p];
5907                  case 2: return [p, br, t];
5908                  case 3: return [p, q, br];
5909                  case 4: return [t, p, br];
5910                  case 5: return [br, p, q];
5911              }
5912          }
5913          return false;
5914      }
5915  
5916  });
5917  
5918  String.implement({
5919  
5920      rgbToHsb: function(){
5921          var rgb = this.match(/\d{1,3}/g);
5922          return (rgb) ? rgb.rgbToHsb() : null;
5923      },
5924  
5925      hsbToRgb: function(){
5926          var hsb = this.match(/\d{1,3}/g);
5927          return (hsb) ? hsb.hsbToRgb() : null;
5928      }
5929  
5930  });
5931  /*
5932  ---
5933  
5934  script: Group.js
5935  
5936  description: Class for monitoring collections of events
5937  
5938  license: MIT-style license
5939  
5940  authors:
5941  - Valerio Proietti
5942  
5943  requires:
5944  - core:1.2.4/Events
5945  - /MooTools.More
5946  
5947  provides: [Group]
5948  
5949  ...
5950  */
5951  
5952  var Group = new Class({
5953  
5954      initialize: function(){
5955          this.instances = Array.flatten(arguments);
5956          this.events = {};
5957          this.checker = {};
5958      },
5959  
5960      addEvent: function(type, fn){
5961          this.checker[type] = this.checker[type] || {};
5962          this.events[type] = this.events[type] || [];
5963          if (this.events[type].contains(fn)) return false;
5964          else this.events[type].push(fn);
5965          this.instances.each(function(instance, i){
5966              instance.addEvent(type, this.check.bind(this, [type, instance, i]));
5967          }, this);
5968          return this;
5969      },
5970  
5971      check: function(type, instance, i){
5972          this.checker[type][i] = true;
5973          var every = this.instances.every(function(current, j){
5974              return this.checker[type][j] || false;
5975          }, this);
5976          if (!every) return;
5977          this.checker[type] = {};
5978          this.events[type].each(function(event){
5979              event.call(this, this.instances, instance);
5980          }, this);
5981      }
5982  
5983  });
5984  /*
5985  ---
5986  
5987  script: Hash.Cookie.js
5988  
5989  description: Class for creating, reading, and deleting Cookies in JSON format.
5990  
5991  license: MIT-style license
5992  
5993  authors:
5994  - Valerio Proietti
5995  - Aaron Newton
5996  
5997  requires:
5998  - core:1.2.4/Cookie
5999  - core:1.2.4/JSON
6000  - /MooTools.More
6001  
6002  provides: [Hash.Cookie]
6003  
6004  ...
6005  */
6006  
6007  Hash.Cookie = new Class({
6008  
6009      Extends: Cookie,
6010  
6011      options: {
6012          autoSave: true
6013      },
6014  
6015      initialize: function(name, options){
6016          this.parent(name, options);
6017          this.load();
6018      },
6019  
6020      save: function(){
6021          var value = JSON.encode(this.hash);
6022          if (!value || value.length > 4096) return false; //cookie would be truncated!
6023          if (value == '{}') this.dispose();
6024          else this.write(value);
6025          return true;
6026      },
6027  
6028      load: function(){
6029          this.hash = new Hash(JSON.decode(this.read(), true));
6030          return this;
6031      }
6032  
6033  });
6034  
6035  Hash.each(Hash.prototype, function(method, name){
6036      if (typeof method == 'function') Hash.Cookie.implement(name, function(){
6037          var value = method.apply(this.hash, arguments);
6038          if (this.options.autoSave) this.save();
6039          return value;
6040      });
6041  });/*
6042  ---
6043  
6044  script: Scroller.js
6045  
6046  description: Class which scrolls the contents of any Element (including the window) when the mouse reaches the Element's boundaries.
6047  
6048  license: MIT-style license
6049  
6050  authors:
6051  - Valerio Proietti
6052  
6053  requires:
6054  - core:1.2.4/Events
6055  - core:1.2.4/Options
6056  - core:1.2.4/Element.Event
6057  - core:1.2.4/Element.Dimensions
6058  
6059  provides: [Scroller]
6060  
6061  ...
6062  */
6063  
6064  var Scroller = new Class({
6065  
6066      Implements: [Events, Options],
6067  
6068      options: {
6069          area: 20,
6070          velocity: 1,
6071          onChange: function(x, y){
6072              this.element.scrollTo(x, y);
6073          },
6074          fps: 50
6075      },
6076  
6077      initialize: function(element, options){
6078          this.setOptions(options);
6079          this.element = document.id(element);
6080          this.listener = ($type(this.element) != 'element') ? document.id(this.element.getDocument().body) : this.element;
6081          this.timer = null;
6082          this.bound = {
6083              attach: this.attach.bind(this),
6084              detach: this.detach.bind(this),
6085              getCoords: this.getCoords.bind(this)
6086          };
6087      },
6088  
6089      start: function(){
6090          this.listener.addEvents({
6091              mouseover: this.bound.attach,
6092              mouseout: this.bound.detach
6093          });
6094      },
6095  
6096      stop: function(){
6097          this.listener.removeEvents({
6098              mouseover: this.bound.attach,
6099              mouseout: this.bound.detach
6100          });
6101          this.detach();
6102          this.timer = $clear(this.timer);
6103      },
6104  
6105      attach: function(){
6106          this.listener.addEvent('mousemove', this.bound.getCoords);
6107      },
6108  
6109      detach: function(){
6110          this.listener.removeEvent('mousemove', this.bound.getCoords);
6111          this.timer = $clear(this.timer);
6112      },
6113  
6114      getCoords: function(event){
6115          this.page = (this.listener.get('tag') == 'body') ? event.client : event.page;
6116          if (!this.timer) this.timer = this.scroll.periodical(Math.round(1000 / this.options.fps), this);
6117      },
6118  
6119      scroll: function(){
6120          var size = this.element.getSize(), 
6121              scroll = this.element.getScroll(), 
6122              pos = this.element.getOffsets(), 
6123              scrollSize = this.element.getScrollSize(), 
6124              change = {x: 0, y: 0};
6125          for (var z in this.page){
6126              if (this.page[z] < (this.options.area + pos[z]) && scroll[z] != 0)
6127                  change[z] = (this.page[z] - this.options.area - pos[z]) * this.options.velocity;
6128              else if (this.page[z] + this.options.area > (size[z] + pos[z]) && scroll[z] + size[z] != scrollSize[z])
6129                  change[z] = (this.page[z] - size[z] + this.options.area - pos[z]) * this.options.velocity;
6130          }
6131          if (change.y || change.x) this.fireEvent('change', [scroll.x + change.x, scroll.y + change.y]);
6132      }
6133  
6134  });/*
6135  ---
6136  
6137  script: Tips.js
6138  
6139  name: Tips
6140  
6141  description: Class for creating nice tips that follow the mouse cursor when hovering an element.
6142  
6143  license: MIT-style license
6144  
6145  authors:
6146    - Valerio Proietti
6147    - Christoph Pojer
6148  
6149  requires:
6150    - Core:1.2.4/Options
6151    - Core:1.2.4/Events
6152    - Core:1.2.4/Element.Event
6153    - Core:1.2.4/Element.Style
6154    - Core:1.2.4/Element.Dimensions
6155    - /MooTools.More
6156  
6157  provides: [Tips]
6158  
6159  ...
6160  */
6161  
6162  (function(){
6163  
6164  var read = function(option, element){
6165      return (option) ? ($type(option) == 'function' ? option(element) : element.get(option)) : '';
6166  };
6167  
6168  this.Tips = new Class({
6169  
6170      Implements: [Events, Options],
6171  
6172      options: {
6173          /*
6174          onAttach: $empty(element),
6175          onDetach: $empty(element),
6176          */
6177          onShow: function(){
6178              this.tip.setStyle('display', 'block');
6179          },
6180          onHide: function(){
6181              this.tip.setStyle('display', 'none');
6182          },
6183          title: 'title',
6184          text: function(element){
6185              return element.get('rel') || element.get('href');
6186          },
6187          showDelay: 100,
6188          hideDelay: 100,
6189          className: 'tip-wrap',
6190          offset: {x: 16, y: 16},
6191          windowPadding: {x:0, y:0},
6192          fixed: false
6193      },
6194  
6195      initialize: function(){
6196          var params = Array.link(arguments, {options: Object.type, elements: $defined});
6197          this.setOptions(params.options);
6198          if (params.elements) this.attach(params.elements);
6199          this.container = new Element('div', {'class': 'tip'});
6200      },
6201  
6202      toElement: function(){
6203          if (this.tip) return this.tip;
6204          
6205          this.container = new Element('div', {'class': 'tip'});
6206          return this.tip = new Element('div', {
6207              'class': this.options.className,
6208              styles: {
6209                  position: 'absolute',
6210                  top: 0,
6211                  left: 0
6212              }
6213          }).adopt(
6214              new Element('div', {'class': 'tip-top'}),
6215              this.container,
6216              new Element('div', {'class': 'tip-bottom'})
6217          ).inject(document.body);
6218      },
6219  
6220      attach: function(elements){
6221          $$(elements).each(function(element){
6222              var title = read(this.options.title, element),
6223                  text = read(this.options.text, element);
6224              
6225              element.erase('title').store('tip:native', title).retrieve('tip:title', title);
6226              element.retrieve('tip:text', text);
6227              this.fireEvent('attach', [element]);
6228              
6229              var events = ['enter', 'leave'];
6230              if (!this.options.fixed) events.push('move');
6231              
6232              events.each(function(value){
6233                  var event = element.retrieve('tip:' + value);
6234                  if (!event) event = this['element' + value.capitalize()].bindWithEvent(this, element);
6235                  
6236                  element.store('tip:' + value, event).addEvent('mouse' + value, event);
6237              }, this);
6238          }, this);
6239          
6240          return this;
6241      },
6242  
6243      detach: function(elements){
6244          $$(elements).each(function(element){
6245              ['enter', 'leave', 'move'].each(function(value){
6246                  element.removeEvent('mouse' + value, element.retrieve('tip:' + value)).eliminate('tip:' + value);
6247              });
6248              
6249              this.fireEvent('detach', [element]);
6250              
6251              if (this.options.title == 'title'){ // This is necessary to check if we can revert the title
6252                  var original = element.retrieve('tip:native');
6253                  if (original) element.set('title', original);
6254              }
6255          }, this);
6256          
6257          return this;
6258      },
6259  
6260      elementEnter: function(event, element){
6261          this.container.empty();
6262          
6263          ['title', 'text'].each(function(value){
6264              var content = element.retrieve('tip:' + value);
6265              if (content) this.fill(new Element('div', {'class': 'tip-' + value}).inject(this.container), content);
6266          }, this);
6267          
6268          $clear(this.timer);
6269          this.timer = (function(){
6270              this.show(element);
6271              this.position((this.options.fixed) ? {page: element.getPosition()} : event);
6272          }).delay(this.options.showDelay, this);
6273      },
6274  
6275      elementLeave: function(event, element){
6276          $clear(this.timer);
6277          this.timer = this.hide.delay(this.options.hideDelay, this, element);
6278          this.fireForParent(event, element);
6279      },
6280  
6281      fireForParent: function(event, element){
6282          element = element.getParent();
6283          if (!element || element == document.body) return;
6284          if (element.retrieve('tip:enter')) element.fireEvent('mouseenter', event);
6285          else this.fireForParent(event, element);
6286      },
6287  
6288      elementMove: function(event, element){
6289          this.position(event);
6290      },
6291  
6292      position: function(event){
6293          if (!this.tip) document.id(this);
6294  
6295          var size = window.getSize(), scroll = window.getScroll(),
6296              tip = {x: this.tip.offsetWidth, y: this.tip.offsetHeight},
6297              props = {x: 'left', y: 'top'},
6298              obj = {};
6299          
6300          for (var z in props){
6301              obj[props[z]] = event.page[z] + this.options.offset[z];
6302              if ((obj[props[z]] + tip[z] - scroll[z]) > size[z] - this.options.windowPadding[z]) obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z];
6303          }
6304          
6305          this.tip.setStyles(obj);
6306      },
6307  
6308      fill: function(element, contents){
6309          if(typeof contents == 'string') element.set('html', contents);
6310          else element.adopt(contents);
6311      },
6312  
6313      show: function(element){
6314          if (!this.tip) document.id(this);
6315          this.fireEvent('show', [this.tip, element]);
6316      },
6317  
6318      hide: function(element){
6319          if (!this.tip) document.id(this);
6320          this.fireEvent('hide', [this.tip, element]);
6321      }
6322  
6323  });
6324  
6325  })();
6326  
6327  /*
6328  ---
6329  
6330  script: Assets.js
6331  
6332  description: Provides methods to dynamically load JavaScript, CSS, and Image files into the document.
6333  
6334  license: MIT-style license
6335  
6336  authors:
6337  - Valerio Proietti
6338  
6339  requires:
6340  - core:1.2.4/Element.Event
6341  - /MooTools.More
6342  
6343  provides: [Assets]
6344  
6345  ...
6346  */
6347  
6348  var Asset = {
6349  
6350      javascript: function(source, properties){
6351          properties = $extend({
6352              onload: $empty,
6353              document: document,
6354              check: $lambda(true)
6355          }, properties);
6356  
6357          var script = new Element('script', {src: source, type: 'text/javascript'});
6358  
6359          var load = properties.onload.bind(script), 
6360              check = properties.check, 
6361              doc = properties.document;
6362          delete properties.onload;
6363          delete properties.check;
6364          delete properties.document;
6365  
6366          script.addEvents({
6367              load: load,
6368              readystatechange: function(){
6369                  if (['loaded', 'complete'].contains(this.readyState)) load();
6370              }
6371          }).set(properties);
6372  
6373          if (Browser.Engine.webkit419) var checker = (function(){
6374              if (!$try(check)) return;
6375              $clear(checker);
6376              load();
6377          }).periodical(50);
6378  
6379          return script.inject(doc.head);
6380      },
6381  
6382      css: function(source, properties){
6383          return new Element('link', $merge({
6384              rel: 'stylesheet',
6385              media: 'screen',
6386              type: 'text/css',
6387              href: source
6388          }, properties)).inject(document.head);
6389      },
6390  
6391      image: function(source, properties){
6392          properties = $merge({
6393              onload: $empty,
6394              onabort: $empty,
6395              onerror: $empty
6396          }, properties);
6397          var image = new Image();
6398          var element = document.id(image) || new Element('img');
6399          ['load', 'abort', 'error'].each(function(name){
6400              var type = 'on' + name;
6401              var event = properties[type];
6402              delete properties[type];
6403              image[type] = function(){
6404                  if (!image) return;
6405                  if (!element.parentNode){
6406                      element.width = image.width;
6407                      element.height = image.height;
6408                  }
6409                  image = image.onload = image.onabort = image.onerror = null;
6410                  event.delay(1, element, element);
6411                  element.fireEvent(name, element, 1);
6412              };
6413          });
6414          image.src = element.src = source;
6415          if (image && image.complete) image.onload.delay(1);
6416          return element.set(properties);
6417      },
6418  
6419      images: function(sources, options){
6420          options = $merge({
6421              onComplete: $empty,
6422              onProgress: $empty,
6423              onError: $empty,
6424              properties: {}
6425          }, options);
6426          sources = $splat(sources);
6427          var images = [];
6428          var counter = 0;
6429          return new Elements(sources.map(function(source){
6430              return Asset.image(source, $extend(options.properties, {
6431                  onload: function(){
6432                      options.onProgress.call(this, counter, sources.indexOf(source));
6433                      counter++;
6434                      if (counter == sources.length) options.onComplete();
6435                  },
6436                  onerror: function(){
6437                      options.onError.call(this, counter, sources.indexOf(source));
6438                      counter++;
6439                      if (counter == sources.length) options.onComplete();
6440                  }
6441              }));
6442          }));
6443      }
6444  
6445  };
6446  
6447  /*
6448  ---
6449  
6450  script: mootools-1.1-to-1.2-upgrade-helper.js
6451  
6452  description: Provides legacy API for Mootools 1.2
6453  
6454  license: MIT-style license
6455  
6456  authors:
6457  - Aaron Newton
6458  
6459  ...
6460  */
6461  
6462  if(!window.console) var console = {};
6463  if(!console.log) console.log = function(){};
6464  if(!console.warn) console.warn = console.log;
6465  if(!console.error) console.error = console.warn;
6466  
6467  MooTools.upgradeLog = function() {
6468      if (console[this.upgradeLogLevel]) console[this.upgradeLogLevel].apply(console, arguments);
6469  };
6470  
6471  (function(){
6472      oldA = $A;
6473      window.$A = function(iterable, start, length){
6474          if (start != undefined && length != undefined) {
6475              MooTools.upgradeLog('1.1 > 1.2: $A no longer takes start and length arguments.');
6476              if (Browser.Engine.trident && $type(iterable) == 'collection'){
6477                  start = start || 0;
6478                  if (start < 0) start = iterable.length + start;
6479                  length = length || (iterable.length - start);
6480                  var array = [];
6481                  for (var i = 0; i < length; i++) array[i] = iterable[start++];
6482                  return array;
6483              }
6484              start = (start || 0) + ((start < 0) ? iterable.length : 0);
6485              var end = ((!$chk(length)) ? iterable.length : length) + start;
6486              return Array.prototype.slice.call(iterable, start, end);
6487          }
6488          return oldA(iterable);
6489      };
6490  
6491  
6492      var strs = ['Array', 'Function', 'String', 'RegExp', 'Number', 'Window', 'Document', 'Element', 'Elements'];
6493      for (var i = 0, l = strs.length; i < l; i++) {
6494          var type = strs[i];
6495          var natv = window[type];
6496          if (natv) {
6497              var extend = natv.extend;
6498              natv.extend = function(props){
6499                  MooTools.upgradeLog('1.1 > 1.2: native types no longer use .extend to add methods to prototypes but instead use .implement. NOTE: YOUR METHODS WERE NOT IMPLEMENTED ON THE NATIVE ' + type.toUpperCase() + ' PROTOTYPE.');
6500                  return extend.apply(this, arguments);
6501              };
6502          }
6503      }
6504  })();
6505  
6506  window.onDomReady = Window.onDomReady = function(fn){
6507      MooTools.upgradeLog('1.1 > 1.2: window.onDomReady is no longer supported. Use window.addEvent("domready") instead');
6508      return window.addEvent('domready', fn);
6509  };if (Browser.__defineGetter__) {
6510      Browser.__defineGetter__('hasGetter',function(){
6511          return true;
6512      });
6513  }
6514  
6515  if(Browser.hasGetter){ // webkit, gecko, opera support
6516      
6517      window.__defineGetter__('ie',function(){
6518          MooTools.upgradeLog('1.1 > 1.2: window.ie is deprecated. Use Browser.Engine.trident');
6519          return (Browser.Engine.name == 'trident') ? true : false;
6520      });
6521      window.__defineGetter__('ie6',function(){
6522          MooTools.upgradeLog('1.1 > 1.2: window.ie6 is deprecated. Use Browser.Engine.trident and Browser.Engine.version');
6523          return (Browser.Engine.name == 'trident' && Browser.Engine.version == 4) ? true : false;
6524      });
6525      window.__defineGetter__('ie7',function(){
6526          MooTools.upgradeLog('1.1 > 1.2: window.ie7 is deprecated. Use Browser.Engine.trident and Browser.Engine.version');
6527          return (Browser.Engine.name == 'trident' && Browser.Engine.version == 5) ? true : false;
6528      });
6529      window.__defineGetter__('gecko',function(){
6530          MooTools.upgradeLog('1.1 > 1.2: window.gecko is deprecated. Use Browser.Engine.gecko');
6531          return (Browser.Engine.name == 'gecko') ? true : false;
6532      });
6533      window.__defineGetter__('webkit',function(){
6534          MooTools.upgradeLog('1.1 > 1.2: window.webkit is deprecated. Use Browser.Engine.webkit');
6535          return (Browser.Engine.name == 'webkit') ? true : false;
6536      });
6537      window.__defineGetter__('webkit419',function(){
6538          MooTools.upgradeLog('1.1 > 1.2: window.webkit is deprecated. Use Browser.Engine.webkit and Browser.Engine.version');
6539          return (Browser.Engine.name == 'webkit' && Browser.Engine.version == 419) ? true : false;
6540      });
6541      window.__defineGetter__('webkit420',function(){
6542          MooTools.upgradeLog('1.1 > 1.2: window.webkit is deprecated. Use Browser.Engine.webkit and Browser.Engine.version');
6543          return (Browser.Engine.name == 'webkit' && Browser.Engine.version == 420) ? true : false;
6544      });
6545      window.__defineGetter__('opera',function(){
6546          MooTools.upgradeLog('1.1 > 1.2: window.opera is deprecated. Use Browser.Engine.presto');
6547          return (Browser.Engine.name == 'presto') ? true : false;
6548      });
6549  } else {
6550      window[Browser.Engine.name] = window[Browser.Engine.name + Browser.Engine.version] = true;
6551      window.ie = window.trident;
6552      window.ie6 = window.trident4;
6553      window.ie7 = window.trident5;    
6554  }
6555  Array.implement({
6556  
6557      copy: function(start, length){
6558          MooTools.upgradeLog('1.1 > 1.2: Array.copy is deprecated. Use Array.splice');
6559          return $A(this, start, length);
6560      },
6561  
6562      remove : function(item){
6563          MooTools.upgradeLog('1.1 > 1.2: Array.remove is deprecated. Use Array.erase');
6564          return this.erase(item);
6565      },
6566  
6567      merge : function(array){
6568          MooTools.upgradeLog('1.1 > 1.2: Array.merge is deprecated. Use Array.combine');
6569          return this.combine(array);
6570      }
6571  
6572  });
6573  Function.implement({
6574  
6575      bindAsEventListener: function(bind, args){
6576          MooTools.upgradeLog('1.1 > 1.2: Function.bindAsEventListener is deprecated. Use bindWithEvent.');
6577          return this.bindWithEvent.call(this, bind, args);
6578      }
6579  
6580  });
6581  
6582  Function.empty = function(){
6583      MooTools.upgradeLog('1.1 > 1.2: Function.empty is now just $empty.');
6584  };Hash.implement({
6585  
6586      keys : function(){
6587          MooTools.upgradeLog('1.1 > 1.2: Hash.keys is deprecated. Use Hash.getKeys');
6588          return this.getKeys();
6589      },
6590  
6591      values : function(){
6592          MooTools.upgradeLog('1.1 > 1.2: Hash.values is deprecated. Use Hash.getValues');
6593          return this.getValues();
6594      },
6595  
6596      hasKey : function(item){
6597          MooTools.upgradeLog('1.1 > 1.2: Hash.hasKey is deprecated. Use Hash.has');
6598          return this.has(item);
6599      },
6600  
6601      merge : function(properties){
6602          MooTools.upgradeLog('1.1 > 1.2: Hash.merge is deprecated. Use Hash.combine');
6603          return this.extend(properties);
6604      },
6605  
6606      remove: function(key){
6607          MooTools.upgradeLog('1.1 > 1.2: Hash.remove is deprecated. use Hash.erase');
6608          return this.erase(key);
6609      }
6610  
6611  });
6612  
6613  Object.toQueryString = function(obj){
6614      MooTools.upgradeLog('1.1 > 1.2: Object.toQueryString() is deprecated. use Hash.toQueryString() instead');
6615      $H(obj).each(function(item, key){
6616          if ($type(item) == 'object' || $type(item) == 'array'){
6617              obj[key] = item.toString();
6618          }
6619      });
6620      return Hash.toQueryString(obj);
6621  };
6622  
6623  var Abstract = function(obj){
6624      MooTools.upgradeLog('1.1 > 1.2: Abstract is deprecated. Use Hash');
6625      return new Hash(obj);
6626  };Class.empty = function(){ 
6627      MooTools.upgradeLog('1.1 > 1.2: replace Class.empty with $empty');
6628      return $empty;
6629  };
6630  
6631  //legacy .extend support
6632  
6633  (function(){
6634      var proto = function(obj) {
6635          var f = function(){
6636              return this;
6637          };
6638          f.prototype = obj;
6639          return f;
6640      };
6641  
6642      Class.prototype.extend = function(properties){
6643          MooTools.upgradeLog('1.1 > 1.2: Class.extend is deprecated. See the class Extend mutator.');
6644          var maker = proto(properties);
6645          var made = new maker();
6646          made.Extends = this;
6647          return new Class(made);
6648      };
6649  
6650      var __implement = Class.prototype.implement;
6651      Class.prototype.implement = function(){
6652          if (arguments.length > 1 && Array.every(arguments, Object.type)){
6653              MooTools.upgradeLog('1.1 > 1.2: Class.implement no longer takes more than one thing at a time, either MyClass.implement(key, value) or MyClass.implement(object) but NOT MyClass.implement(new Foo, new Bar, new Baz). See also: the class Implements mutator.');
6654              Array.each(arguments, function(argument){
6655                  __implement.call(this, argument);
6656              }, this);
6657              return this;
6658          }
6659          return __implement.apply(this, arguments);
6660      };
6661  })();(function(){
6662  
6663      var getPosition = Element.prototype.getPosition;
6664      var getCoordinates = Element.prototype.getCoordinates;
6665  
6666  	function isBody(element){
6667          return (/^(?:body|html)$/i).test(element.tagName);
6668      };
6669  
6670      var getSize = Element.prototype.getSize;
6671  
6672      Element.implement({
6673      
6674          getSize: function(){
6675              MooTools.upgradeLog('1.1 > 1.2: NOTE: getSize is different in 1.2; it no longer returns values for size, scroll, and scrollSize, but instead just returns x/y values for the dimensions of the element.');
6676              var size = getSize.apply(this, arguments);
6677              return $merge(size, {
6678                  size: size,
6679                  scroll: this.getScroll(),
6680                  scrollSize: this.getScrollSize()
6681              });
6682          },
6683  
6684          getPosition: function(relative){
6685              if (relative && $type(relative) == "array") {
6686                  MooTools.upgradeLog('1.1 > 1.2: Element.getPosition no longer accepts an array of overflown elements but rather, optionally, a single element to get relative coordinates.');
6687                  relative = null;
6688              }
6689              return getPosition.apply(this, [relative]);
6690          },
6691  
6692          getCoordinates: function(relative){
6693              if (relative && $type(relative) == "array") {
6694                  MooTools.upgradeLog('1.1 > 1.2: Element.getCoordinates no longer accepts an array of overflown elements but rather, optionally, a single element to get relative coordinates.');
6695                  relative = null;
6696              }
6697              return getCoordinates.apply(this, [relative]);
6698          }
6699      
6700      });
6701  
6702      Native.implement([Document, Window], {
6703  
6704          getSize: function(){
6705              MooTools.upgradeLog('1.1 > 1.2: NOTE: getSize is different in 1.2; it no longer returns values for size, scroll, and scrollSize, but instead just returns x/y values for the dimensions of the element.');
6706              var size;
6707              var win = this.getWindow();
6708              var doc = this.getDocument();
6709              doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.body;
6710              if (Browser.Engine.presto || Browser.Engine.webkit){
6711                  size =  {x: win.innerWidth, y: win.innerHeight};
6712              } else {
6713                  size = {x: doc.clientWidth, y: doc.clientHeight};
6714              }
6715              return $extend(size, {
6716                  size: size,
6717                  scroll: {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scrollTop},
6718                  scrollSize: {x: Math.max(doc.scrollWidth, size.x), y: Math.max(doc.scrollHeight, size.y)}
6719              });
6720          }
6721  
6722      });
6723  
6724  })();Event.keys = Event.Keys; // TODO
6725  (function(){
6726  
6727      var toQueryString = Element.prototype.toQueryString;
6728  
6729      Element.implement({
6730  
6731          getFormElements: function(){
6732              MooTools.upgradeLog('1.1 > 1.2: Element.getFormElements is deprecated, use Element.getElements("input, textarea, select");'); 
6733              return this.getElements('input, textarea, select');
6734          },
6735  
6736          replaceWith: function(el){
6737              MooTools.upgradeLog('1.1 > 1.2: Element.replaceWith is deprecated, use Element.replaces instead.'); 
6738              el = $(el);
6739              this.parentNode.replaceChild(el, this);
6740              return el;
6741          },
6742  
6743          remove: function() {
6744              MooTools.upgradeLog('1.1 > 1.2: Element.remove is deprecated - use Element.dispose.');
6745              return this.dispose.apply(this, arguments);
6746          },
6747  
6748          getText: function(){
6749              MooTools.upgradeLog('1.1 > 1.2: Element.getText is deprecated - use Element.get("text").'); 
6750              return this.get('text');
6751          },
6752  
6753          setText: function(text){
6754              MooTools.upgradeLog('1.1 > 1.2: Element.setText is deprecated - use Element.set("text", text).'); 
6755              return this.set('text', text);
6756          },
6757  
6758          setHTML: function(){
6759              MooTools.upgradeLog('1.1 > 1.2: Element.setHTML is deprecated - use Element.set("html", HTML).'); 
6760              return this.set('html', arguments);
6761          },
6762  
6763          getHTML: function(){
6764              MooTools.upgradeLog('1.1 > 1.2: Element.getHTML is deprecated - use Element.get("html").'); 
6765              return this.get('html');
6766          },
6767  
6768          getTag: function(){
6769              MooTools.upgradeLog('1.1 > 1.2: Element.getTag is deprecated - use Element.get("tag").'); 
6770              return this.get('tag');
6771          },
6772      
6773          getValue: function(){
6774              MooTools.upgradeLog('1.1 > 1.2: Element.getValue is deprecated - use Element.get("value").');
6775              switch(this.getTag()){
6776                  case 'select':
6777                      var values = [];
6778                      $each(this.options, function(option){
6779                          if (option.selected) values.push($pick(option.value, option.text));
6780                      });
6781                      return (this.multiple) ? values : values[0];
6782                  case 'input': if (!(this.checked && ['checkbox', 'radio'].contains(this.type)) && !['hidden', 'text', 'password'].contains(this.type)) break;
6783                  case 'textarea': return this.value;
6784              }
6785              return false;
6786          },
6787  
6788          toQueryString: function(){
6789              MooTools.upgradeLog('1.1 > 1.2: warning Element.toQueryString is slightly different; inputs without names are excluded, inputs with type == submit, reset, and file are excluded, and inputs with undefined values are excluded.');
6790              return toQueryString.apply(this, arguments);
6791          }
6792      });
6793  })();
6794  
6795  Element.Properties.properties = {
6796      
6797      set: function(props){
6798          MooTools.upgradeLog('1.1 > 1.2: Element.set({properties: {}}) is deprecated; instead of properties, just name the values at the root of the object (Element.set({src: url})).');
6799          $H(props).each(function(value, property){
6800              this.set(property, value);
6801          }, this);
6802      }
6803      
6804  };
6805  Element.implement({
6806  
6807      setOpacity: function(op){
6808          MooTools.upgradeLog('1.1 > 1.2: Element.setOpacity is deprecated; use Element.setStyle("opacity", value).');
6809          return this.setStyle('opacity', op);
6810      }
6811  
6812  });
6813  
6814  Element.Properties.styles = {
6815      
6816      set: function(styles){
6817          MooTools.upgradeLog('1.1 > 1.2: Element.set("styles") no longer accepts a string as an argument. Pass an object instead.');
6818          if ($type(styles) == 'string'){
6819              styles.split(";").each(function(style){
6820                  this.setStyle(style.split(":")[0], style.split(":")[1]);
6821              }, this);
6822          } else {
6823              this.setStyles(styles);
6824          }
6825      }
6826      
6827  };Fx.implement({
6828  
6829      custom: function(from, to){
6830          MooTools.upgradeLog('1.1 > 1.2: Fx.custom is deprecated. use Fx.start.');
6831          return this.start(from, to);
6832      },
6833  
6834      clearTimer: function(){
6835          MooTools.upgradeLog('1.1 > 1.2: Fx.clearTimer is deprecated. use Fx.cancel.');
6836          return this.cancel();
6837      },
6838  
6839      stop: function(){
6840          MooTools.upgradeLog('1.1 > 1.2: Fx.stop is deprecated. use Fx.cancel.');
6841          return this.cancel();
6842      }
6843  
6844  });
6845  
6846  Fx.Base = new Class({
6847      Extends: Fx,
6848      initialize: function(){
6849          MooTools.upgradeLog('1.1 > 1.2: Fx.Base is deprecated. use Fx.');
6850          this.parent.apply(this, arguments);
6851      }
6852  });
6853  Fx.Style = new Class({
6854      Extends: Fx.Tween,
6855      initialize: function(element, property, options){
6856          MooTools.upgradeLog('1.1 > 1.2: Fx.Style is deprecated. use Fx.Tween.');
6857          this.property = property;
6858          this.parent(element, options);
6859      },
6860      
6861      start: function(from, to) {
6862          return this.parent(this.property, from, to);
6863      },
6864      
6865      set: function(to) {
6866          return this.parent(this.property, to);
6867      },
6868      
6869      hide: function(){
6870          MooTools.upgradeLog('1.1 > 1.2: Fx.Style .hide() is deprecated; use Fx.Tween .set(0) instead');
6871          return this.set(0);
6872      }
6873  
6874  });
6875  
6876  Element.implement({
6877  
6878      effect: function(property, options){
6879          MooTools.upgradeLog('1.1 > 1.2: Element.effect is deprecated; use Fx.Tween or Element.tween.');
6880          return new Fx.Style(this, property, options);
6881      }
6882  
6883  });
6884  Fx.Styles = new Class({
6885      Extends: Fx.Morph,
6886      initialize: function(){
6887          MooTools.upgradeLog('1.1 > 1.2: Fx.Styles is deprecated. use Fx.Morph.');
6888          this.parent.apply(this, arguments);
6889      }
6890  });
6891  
6892  Element.implement({
6893  
6894      effects: function(options){
6895          MooTools.upgradeLog('1.1 > 1.2: Element.effects is deprecated; use Fx.Morph or Element.morph.');
6896          return new Fx.Morph(this, options);
6897      }
6898  
6899  });Fx.Scroll.implement({
6900  
6901      scrollTo: function(y, x){
6902          MooTools.upgradeLog('1.1 > 1.2: Fx.Scroll\'s .scrollTo is deprecated; use .start.');
6903          return this.start(y, x);
6904      }
6905  
6906  });Request.implement({
6907      //1.11 passed along the response text and xml to onComplete
6908      onStateChange: function(){
6909          if (this.xhr.readyState != 4 || !this.running) return;
6910          this.running = false;
6911          this.status = 0;
6912          $try(function(){
6913              this.status = this.xhr.status;
6914          }.bind(this));
6915          this.xhr.onreadystatechange = $empty;
6916          this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML};
6917          if (this.options.isSuccess.call(this, this.status)) this.success(this.response.text, this.response.xml);
6918          else this.failure(this.response.text, this.response.xml);
6919      },
6920      
6921      failure: function(){
6922          this.onFailure.apply(this, arguments);
6923      },
6924  
6925      onFailure: function(){
6926          MooTools.upgradeLog('1.1 > 1.2: Note that onComplete does not receive arguments in 1.2. Also note that onComplete is invoked on BOTH success and failure (while in 1.1 it was only invoked on success). Use the onSuccess event instead if you wish to limit this invocation to success.');
6927          this.fireEvent('complete', arguments).fireEvent('failure', this.xhr);
6928      }
6929  
6930  });
6931  
6932  var XHR = new Class({
6933  
6934      Extends: Request,
6935  
6936      options: {
6937          update: false
6938      },
6939  
6940      initialize: function(options){
6941          MooTools.upgradeLog('1.1 > 1.2: XHR is deprecated. Use Request.');
6942          this.parent(options);
6943          this.transport = this.xhr;
6944      },
6945  
6946      request: function(data){
6947          MooTools.upgradeLog('1.1 > 1.2: XHR.request() is deprecated. Use Request.send() instead.');
6948          return this.send(this.url, data || this.options.data);
6949      },
6950  
6951      send: function(url, data){
6952          if (!this.check(arguments.callee, url, data)) return this;
6953          return this.parent({url: url, data: data});
6954      },
6955  
6956      success: function(text, xml){
6957          text = this.processScripts(text);
6958          if (this.options.update) $(this.options.update).empty().set('html', text);
6959          this.onSuccess(text, xml);
6960      },
6961  
6962      failure: function(){
6963          this.fireEvent('failure', this.xhr);
6964      }
6965  
6966  });
6967  
6968  
6969  var Ajax = new Class({
6970  
6971      Extends: XHR,
6972  
6973      initialize: function(url, options){
6974          MooTools.upgradeLog('1.1 > 1.2: Ajax is deprecated. Use Request.');
6975          this.url = url;
6976          this.parent(options);
6977      },
6978  
6979      success: function(text, xml){
6980          // This version processes scripts *after* the update element is updated, like Mootools 1.1's Ajax class
6981          // Partially from Remote.Ajax.success
6982          this.processScripts(text);
6983          response = this.response;
6984          response.html = text.stripScripts(function(script){
6985                  response.javascript = script;
6986          });
6987          if (this.options.update) $(this.options.update).empty().set('html', response.html);
6988          if (this.options.evalScripts) $exec(response.javascript);
6989          this.onSuccess(text, xml);
6990      }
6991  
6992  });
6993  
6994  (function(){
6995      var send = Element.prototype.send;
6996      Element.implement({
6997          send: function(url) {
6998              if ($type(url) == "string") return send.apply(this, arguments);
6999              if ($type(url) == "object") {
7000                  MooTools.upgradeLog('1.1 > 1.2: Element.send no longer takes an options argument as its object but rather a url. See docs.');
7001                  this.set('send', url);
7002                  send.call(this);
7003              }
7004              return this;
7005          }
7006      });
7007  })();JSON.Remote = new Class({
7008  
7009      options: {
7010          key: 'json'
7011      },
7012  
7013      Extends: Request.JSON,
7014  
7015      initialize: function(url, options){
7016          MooTools.upgradeLog('JSON.Remote is deprecated. Use Request.JSON');
7017          this.parent(options);
7018          this.onComplete = $empty;
7019          this.url = url;
7020      },
7021  
7022      send: function(data){
7023          if (!this.check(arguments.callee, data)) return this;
7024          return this.parent({url: this.url, data: {json: Json.encode(data)}});
7025      },
7026  
7027      failure: function(){
7028          this.fireEvent('failure', this.xhr);
7029      }
7030  
7031  });
7032  
7033  Cookie.set = function(key, value, options){
7034      MooTools.upgradeLog('1.1 > 1.2: Cookie.set is deprecated. Use Cookie.write');
7035      return new Cookie(key, options).write(value);
7036  };
7037  
7038  Cookie.get = function(key){
7039      MooTools.upgradeLog('1.1 > 1.2: Cookie.get is deprecated. Use Cookie.read');
7040      return new Cookie(key).read();
7041  };
7042  
7043  Cookie.remove = function(key, options){
7044      MooTools.upgradeLog('1.1 > 1.2: Cookie.remove is deprecated. Use Cookie.dispose');
7045      return new Cookie(key, options).dispose();
7046  };
7047  JSON.toString = function(obj){ 
7048      MooTools.upgradeLog('1.1 > 1.2: JSON.toString is deprecated. Use JSON.encode');
7049      return JSON.encode(obj); 
7050  };
7051  JSON.evaluate = function(str){
7052      MooTools.upgradeLog('1.1 > 1.2: JSON.evaluate is deprecated. Use JSON.decode');
7053      return JSON.decode(str); 
7054  };
7055  var Json = JSON;
7056  
7057  Native.implement([Element, Document], {
7058  
7059      getElementsByClassName: function(className){
7060          MooTools.upgradeLog('1.1 > 1.2: Element.filterByTag is deprecated.');
7061          
7062          return this.getElements('.' + className);
7063      },
7064  
7065      getElementsBySelector: function(selector){
7066          MooTools.upgradeLog('1.1 > 1.2: Element.getElementsBySelector is deprecated. Use getElements()');
7067          return this.getElements(selector);
7068      }
7069  
7070  });
7071  
7072  Elements.implement({
7073  
7074      filterByTag: function(tag){
7075          MooTools.upgradeLog('1.1 > 1.2: Elements.filterByTag is deprecated. Use Elements.filter.');
7076          return this.filter(tag);
7077      },
7078  
7079      filterByClass: function(className){
7080          MooTools.upgradeLog('1.1 > 1.2: Elements.filterByClass is deprecated. Use Elements.filter.');
7081          return this.filter('.' + className);
7082      },
7083  
7084      filterById: function(id){
7085          MooTools.upgradeLog('1.1 > 1.2: Elements.filterById is deprecated. Use Elements.filter.');
7086          return this.filter('#' + id);
7087      },
7088  
7089      filterByAttribute: function(name, operator, value){
7090          MooTools.upgradeLog('1.1 > 1.2: Elements.filterByAttribute is deprecated. Use Elements.filter.');
7091          var filtered = this.filter('[' + name + (operator || '') + (value || '') + ']');
7092          if (value) filtered = filtered.filter('[' + name + ']');
7093          return filtered;
7094      }
7095  
7096  });
7097  
7098  var $E = function(selector, filter){
7099      MooTools.upgradeLog('1.1 > 1.2: $E is deprecated, use document.getElement.');
7100      return ($(filter) || document).getElement(selector);
7101  };
7102  
7103  var $ES = function(selector, filter){
7104      MooTools.upgradeLog('1.1 > 1.2: $ES is deprecated. Use $$.');
7105      return ($(filter) || document).getElements(selector);
7106  };(function(){
7107      if (!window.Tips) return;
7108  
7109      Tips.implement({
7110  
7111          initialize: function(){
7112              MooTools.upgradeLog('1.1 > 1.2: Tips DOM element layout has changed and your CSS classes may need to change.');
7113              var params = Array.link(arguments, {options: Object.type, elements: $defined});
7114              this.setOptions(params.options);
7115              if (this.options.offsets) {
7116                  MooTools.upgradeLog('1.1 > 1.2: Tips no longer have an "offsets" option; use "offset".');
7117                  this.options.offset = this.options.offsets;
7118              }
7119              document.id(this);
7120              this.addEvent('show', function(){
7121                  this.tip.addClass('tool-tip');
7122                  this.tip.getElement('.tip-title').addClass('tool-title');
7123                  this.tip.getElement('.tip-text').addClass('tool-text');
7124              });
7125              this.parseTitle(params.elements);
7126              if (params.elements) this.attach(params.elements);
7127          },
7128  
7129          parseTitle: function(elements){
7130              elements.each(function(element){
7131              var title = element.get('title');
7132                  if (title.test('::')) {
7133                      MooTools.upgradeLog('1.1 > 1.2: Tips no longer parse the title attribute for "::" for title/caption; use title and rel attributes instead.');
7134                      element.store('tip:title', title.split('::')[0]);
7135                      element.store('tip:text', title.split('::')[1]);
7136                      element.set('title', '');
7137                  }
7138              });
7139          }
7140  
7141      });
7142  
7143  })();


Generated: Wed Mar 28 15:54:07 2012 Cross-referenced by PHPXref 0.7.1