<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>templates/html/assets/images/alias.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/images/class_method.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/images/class_property.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/images/description.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/images/grid.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/images/information.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/images/instance_method.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/images/instance_property.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/images/related_to.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/images/subclass.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/images/superclass.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/images/utility.png</filename>
    </added>
    <added>
      <filename>templates/html/assets/stylesheets/core.css</filename>
    </added>
    <added>
      <filename>templates/html/partials/breadcrumbs.erb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -1,11 +1,31 @@
 if (typeof PDoc === &quot;undefined&quot;) window.PDoc = {};
 
-PDoc.highlightSelected = function(element) {
-  if (!element &amp;&amp; !window.location.hash) return;
-  element = (element || $(window.location.hash.substr(1)));
+// Poor-man's history manager. Polls for changes to the hash.
+(function() {  
+  var PREVIOUS_HASH = null;
+  
+  Event.observe(window, &quot;load&quot;, function() {    
+    var hash = window.location.hash;
+    if (hash &amp;&amp; hash !== PREVIOUS_HASH) {
+      document.fire(&quot;hash:changed&quot;,
+       { previous: PREVIOUS_HASH, current: hash });        
+      PREVIOUS_HASH = hash;      
+    }
+    
+    window.setTimeout(arguments.callee, 100);  
+  });  
+})();
+
+// Place a &quot;frame&quot; around the element described by the hash.
+// Update the frame when the hash changes.
+PDoc.highlightSelected = function() {
+  if (!window.location.hash) return;  
+  element = $(window.location.hash.substr(1));
   if (element) PDoc.highlight(element.up('li, div'));
 };
 
+document.observe(&quot;hash:changed&quot;, PDoc.highlightSelected);
+
 PDoc.highlight = function(element) {
   var self = arguments.callee;
   if (!self.frame) {
@@ -17,26 +37,29 @@ PDoc.highlight = function(element) {
   
   element.getOffsetParent().appendChild(frame);
   
-  frame.clonePosition(element, { offsetLeft: -5, offsetTop: -5 });
+  var offset = element.positionedOffset();
   var w = parseFloat(element.getStyle('width')),
       h = parseFloat(element.getStyle('height'));
-  
+      
   frame.setStyle({
-    width:  (w + 10) + 'px',
-    height: (h + 10) + 'px'
+    position: 'absolute',
+    top: (offset.top - 15) + 'px',
+    left: (offset.left - 12) + 'px',
+    width:  (w + 20) + 'px',
+    height: (h + 30) + 'px'
   });
+  
+  // Defer this call because Safari hasn't yet scrolled the viewport.
+  (function() {
+    var frameOffset = frame.viewportOffset(frame);
+    if (frameOffset.top &lt; 0) {
+      window.scrollBy(0, frameOffset.top - 10);
+    }    
+  }).defer();
+  
 };
 
-PDoc.HighlightOptions = {
-  startcolor: '#e4e4e4',
-  restorecolor: true,
-  queue: {
-    position:'end',
-    scope: 'global',
-    limit: 1
-  }
-};
-
+// Live API search.
 var Filterer = Class.create({
   initialize: function(element, options) {
     this.element = $(element);
@@ -48,9 +71,9 @@ var Filterer = Class.create({
     this.element.writeAttribute(&quot;autocomplete&quot;, &quot;off&quot;);    
     this.element.up('form').observe(&quot;submit&quot;, Event.stop);
     
-    // The Safari-only &quot;search&quot; input type is prettier
-    if (Prototype.Browser.WebKit)
-      this.element.type = &quot;search&quot;;
+    // // The Safari-only &quot;search&quot; input type is prettier
+    // if (Prototype.Browser.WebKit)
+    //   this.element.type = &quot;search&quot;;
     
     this.menu = this.options.menu;
     this.links = this.menu.select('a');
@@ -78,7 +101,7 @@ var Filterer = Class.create({
   filter: function(event) {
     if (this._timer) window.clearTimeout(this._timer);
     
-    // clear the text box on ESC
+    // Clear the text box on ESC
     if (event.keyCode &amp;&amp; event.keyCode === Event.KEY_ESC) {
       this.element.value = '';
     }
@@ -96,7 +119,7 @@ var Filterer = Class.create({
     this.buildResults(urls);
   },
   
-  keydown: function(event) {    
+  keydown: function(event) {
     if (![Event.KEY_UP, Event.KEY_DOWN, Event.KEY_RETURN].include(event.keyCode))
       return;
       
@@ -108,7 +131,7 @@ var Filterer = Class.create({
     
     var highlighted = this.resultsElement.down('.highlighted');
     if (event.keyCode === Event.KEY_RETURN) {
-      // follow the highlighted item
+      // Follow the highlighted item.
       if (!highlighted) return;
       window.location.href = highlighted.down('a').href;
     } else {
@@ -119,10 +142,10 @@ var Filterer = Class.create({
     
     if ([Event.KEY_UP, Event.KEY_DOWN].include(event.keyCode) &amp;&amp;
      !Prototype.Browser.WebKit) {    
-      // if up/down key is held down, list should keep scrolling
+      // If up/down key is held down, list should keep scrolling.
       // Safari does this automatically because it fires the keydown
-      // event over and over
-      this._timer = window.setTimeout(this.scrollList.bind(this, direction), 100);
+      // event over and over.
+      this._timer = window.setTimeout(this.scrollList.bind(this, direction), 1000);
     }
   },
   
@@ -163,18 +186,24 @@ var Filterer = Class.create({
     this._timer = window.setTimeout(this.scrollList.bind(this, direction), 100);
   },
   
+  // Given a path with any number of `../`s in front of it, remove them all.
+  // TODO: Fix this a better way.
+  _fixPath: function(path) {
+    return path.replace('../', '');
+  },
+  
   buildResults: function(urls) {
     this.resultsElement.update();
     var ul = this.resultsElement;
     urls.each( function(url) {
       var a  = new Element('a', {
         'class': url.type.gsub(/\s/, '_'),
-        href:    PDoc.pathPrefix + url.path
+        href:    PDoc.pathPrefix + this._fixPath(url.path)
       }).update(url.name);
-      var li = new Element('li');
+      var li = new Element('li', { 'class': 'menu-item' });
       li.appendChild(a);
       ul.appendChild(li);
-    });    
+    }, this);    
     this.showResults();
   },
     
@@ -193,6 +222,7 @@ var Filterer = Class.create({
   
   showResults: function() {
     this.resultsElement.show();
+    document.stopObserving(&quot;keydown&quot;, this.events.keydown);
     document.observe(&quot;keydown&quot;, this.events.keydown);
   },
   
@@ -203,20 +233,12 @@ var Filterer = Class.create({
 });
 
 document.observe('dom:loaded', function() {
-  new Filterer($('search'), { menu: $('api_menu'), resultsElement: $('search_results') });
-});
-
-document.observe('click', function(event) {
-  var element = event.findElement('a');
-  if (!element) return;
-  var href = element.readAttribute('href');
-  if (!href.include('#')) return;
-  if (element = $(href.split('#').last())) {
-    PDoc.highlightSelected(element);
-  }
+  new Filterer($('search'), {
+    menu: $('api_menu'), 
+    resultsElement: $('search_results')
+  });
 });
 
-document.observe('dom:loaded', function() { PDoc.highlightSelected() });
 
 Event.observe(window, 'load', function() {
   var menu = $('menu');
@@ -227,5 +249,141 @@ Event.observe(window, 'load', function() {
     if (sOffset.top &gt; OFFSET) {
       menu.addClassName('fixed');
     } else menu.removeClassName('fixed');
-  })
+  });
+});
+
+(function() {
+  function menuButtonMouseOver(event) {
+    var menuButton = $('api_menu_button');
+    var target = event.element();
+    if (target === menuButton || target.descendantOf(menuButton)) {
+      $('api_menu').show();
+    }
+  }
+  
+  function menuButtonMouseOut(event) {
+    var menuButton = $('api_menu_button');
+    var menu = $('api_menu');
+    var target = event.element(), related = event.relatedTarget || event.toElement;
+    
+    if (related &amp;&amp; (related === menu || related.descendantOf(menu))) return;
+    menu.hide();
+  }
+  
+  function menuMouseOut(event) {
+    var menu = $('api_menu'), related = event.relatedTarget || event.toElement;
+    if (related &amp;&amp; !related.descendantOf(menu)) {
+      arguments.callee.timer = Element.hide.delay(0.5, menu);
+    } else {
+      window.clearTimeout(arguments.callee.timer);
+    }
+  }
+  
+  function menuItemMouseOver(event) {
+    var element = event.element();    
+    if (element.tagName.toLowerCase() === 'a') {
+      element.addClassName('highlighted');
+    }
+  }
+  
+  function menuItemMouseOut(event) {
+    var element = event.element();    
+    if (element.tagName.toLowerCase() === 'a') {
+      element.removeClassName('highlighted');
+    }
+  }
+  
+  var MENU_ITEMS;
+  
+  document.observe('dom:loaded', function() {
+    MENU_ITEMS = $$('.api-box .menu-item a');
+    
+    $('api_menu_button').observe('mouseenter', menuButtonMouseOver);
+    $('api_menu_button').observe('mouseleave', menuButtonMouseOut );
+    
+    $('api_menu').observe('mouseleave', menuMouseOut);
+    
+    if (Prototype.Browser.IE) {
+      $('api_menu').observe('mouseover', menuItemMouseOver);
+      $('api_menu').observe('mouseout',  menuItemMouseOut);
+    }
+  });
+})();
+
+Form.GhostedField = Class.create({
+  initialize: function(element, title, options) {
+    this.element = $(element);
+    this.title = title;
+    
+    options = options || {};
+    
+    this.isGhosted = true;
+    
+    if (options.cloak) {
+      // Wrap the native getValue function so that it never returns the
+      // ghosted value. This is optional because it presumes the ghosted
+      // value isn't valid input for the field.
+      this.element.getValue = this.element.getValue.wrap(this.wrappedGetValue.bind(this));      
+    }    
+    
+    this.addObservers();
+    this.onBlur();
+  },
+  
+  wrappedGetValue: function($proceed) {
+    var value = $proceed();
+    return value === this.title ? &quot;&quot; : value;
+  },
+  
+  addObservers: function() {
+    this.element.observe('focus', this.onFocus.bind(this));
+    this.element.observe('blur',  this.onBlur.bind(this));
+    
+    var form = this.element.up('form');
+    if (form) {
+      form.observe('submit', this.onSubmit.bind(this));
+    }
+    
+    // Firefox's bfcache means that form fields need to be re-initialized
+    // when you hit the &quot;back&quot; button to return to the page.
+    if (Prototype.Browser.Gecko) {
+      window.addEventListener('pageshow', this.onBlur.bind(this), false);
+    }
+  },
+  
+  onFocus: function() {
+    if (this.isGhosted) {
+      this.element.setValue('');
+      this.setGhosted(false);
+    }
+  },
+  
+  onBlur: function() {
+    var value = this.element.getValue();
+    if (value.blank() || value == this.title) {
+      this.setGhosted(true);
+    } else {
+      this.setGhosted(false);
+    }
+  },
+  
+  setGhosted: function(isGhosted) {
+    this.isGhosted = isGhosted;
+    this.element[isGhosted ? 'addClassName' : 'removeClassName']('ghosted');
+    if (isGhosted) {
+      this.element.setValue(this.title);
+    }    
+  },
+
+  // Hook into the enclosing form's `onsubmit` event so that we clear any
+  // ghosted text before the form is sent.
+  onSubmit: function() {
+    if (this.isGhosted) {
+      this.element.setValue('');
+    }
+  }
+});
+
+document.observe(&quot;dom:loaded&quot;, function() {
+  new Form.GhostedField($('search'), &quot;Search&quot;);
 });
\ No newline at end of file</diff>
      <filename>templates/html/assets/javascripts/application.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,251 +1,251 @@
-/* Unobtrustive Code Highlighter By Dan Webb 11/2005
-   Version: 0.4
-	
-	Usage:
-		Add a script tag for this script and any stylesets you need to use
-		to the page in question, add correct class names to CODE elements, 
-		define CSS styles for elements. That's it! 
-	
-	Known to work on:
-		IE 5.5+ PC
-		Firefox/Mozilla PC/Mac
-		Opera 7.23 + PC
-		Safari 2
-		
-	Known to degrade gracefully on:
-		IE5.0 PC
-	
-	Note: IE5.0 fails due to the use of lookahead in some stylesets.  To avoid script errors
-	in older browsers use expressions that use lookahead in string format when defining stylesets.
-	
-	This script is inspired by star-light by entirely cunning Dean Edwards
-	http://dean.edwards.name/star-light/.  
-*/
-
-// replace callback support for safari.
-if (&quot;a&quot;.replace(/a/, function() {return &quot;b&quot;}) != &quot;b&quot;) (function(){
-  var default_replace = String.prototype.replace;
-  String.prototype.replace = function(search,replace){
-	// replace is not function
-	if(typeof replace != &quot;function&quot;){
-		return default_replace.apply(this,arguments)
-	}
-	var str = &quot;&quot; + this;
-	var callback = replace;
-	// search string is not RegExp
-	if(!(search instanceof RegExp)){
-		var idx = str.indexOf(search);
-		return (
-			idx == -1 ? str :
-			default_replace.apply(str,[search,callback(search, idx, str)])
-		)
-	}
-	var reg = search;
-	var result = [];
-	var lastidx = reg.lastIndex;
-	var re;
-	while((re = reg.exec(str)) != null){
-		var idx  = re.index;
-		var args = re.concat(idx, str);
-		result.push(
-			str.slice(lastidx,idx),
-			callback.apply(null,args).toString()
-		);
-		if(!reg.global){
-			lastidx += RegExp.lastMatch.length;
-			break
-		}else{
-			lastidx = reg.lastIndex;
-		}
-	}
-	result.push(str.slice(lastidx));
-	return result.join(&quot;&quot;)
-  }
-})();
-
-var CodeHighlighter = { styleSets : new Array };
-
-CodeHighlighter.addStyle = function(name, rules) {
-	// using push test to disallow older browsers from adding styleSets
-	if ([].push) this.styleSets.push({
-		name : name, 
-		rules : rules,
-		ignoreCase : arguments[2] || false
-	})
-	
-	function setEvent() {
-		// set highlighter to run on load (use LowPro if present)
-		if (typeof Event != 'undefined' &amp;&amp; typeof Event.onReady == 'function') 
-		  return Event.onReady(CodeHighlighter.init.bind(CodeHighlighter));
-		
-		var old = window.onload;
-		
-		if (typeof window.onload != 'function') {
-			window.onload = function() { CodeHighlighter.init() };
-		} else {
-			window.onload = function() {
-				old();
-				CodeHighlighter.init();
-			}
-		}
-	}
-	
-	// only set the event when the first style is added
-	if (this.styleSets.length==1) setEvent();
-}
-
-CodeHighlighter.init = function() {
-	if (!document.getElementsByTagName) return; 
-	if (&quot;a&quot;.replace(/a/, function() {return &quot;b&quot;}) != &quot;b&quot;) return; // throw out Safari versions that don't support replace function
-	// throw out older browsers
-	
-	var codeEls = document.getElementsByTagName(&quot;CODE&quot;);
-	// collect array of all pre elements
-	codeEls.filter = function(f) {
-		var a =  new Array;
-		for (var i = 0; i &lt; this.length; i++) if (f(this[i])) a[a.length] = this[i];
-		return a;
-	} 
-	
-	var rules = new Array;
-	rules.toString = function() {
-		// joins regexes into one big parallel regex
-		var exps = new Array;
-		for (var i = 0; i &lt; this.length; i++) exps.push(this[i].exp);
-		return exps.join(&quot;|&quot;);
-	}
-	
-	function addRule(className, rule) {
-		// add a replace rule
-		var exp = (typeof rule.exp != &quot;string&quot;)?String(rule.exp).substr(1, String(rule.exp).length-2):rule.exp;
-		// converts regex rules to strings and chops of the slashes
-		rules.push({
-			className : className,
-			exp : &quot;(&quot; + exp + &quot;)&quot;,
-			length : (exp.match(/(^|[^\\])\([^?]/g) || &quot;&quot;).length + 1, // number of subexps in rule
-			replacement : rule.replacement || null 
-		});
-	}
-	
-	function parse(text, ignoreCase) {
-		// main text parsing and replacement
-		return text.replace(new RegExp(rules, (ignoreCase)?&quot;gi&quot;:&quot;g&quot;), function() {
-			var i = 0, j = 1, rule;
-			while (rule = rules[i++]) {
-				if (arguments[j]) {
-					// if no custom replacement defined do the simple replacement
-					if (!rule.replacement) return &quot;&lt;span class=\&quot;&quot; + rule.className + &quot;\&quot;&gt;&quot; + arguments[0] + &quot;&lt;/span&gt;&quot;;
-					else {
-						// replace $0 with the className then do normal replaces
-						var str = rule.replacement.replace(&quot;$0&quot;, rule.className);
-						for (var k = 1; k &lt;= rule.length - 1; k++) str = str.replace(&quot;$&quot; + k, arguments[j + k]);
-						return str;
-					}
-				} else j+= rule.length;
-			}
-		});
-	}
-	
-	function highlightCode(styleSet) {
-		// clear rules array
-		var parsed;
-		rules.length = 0;
-		
-		// get stylable elements by filtering out all code elements without the correct className	
-		var stylableEls = codeEls.filter(function(item) {return (item.className.indexOf(styleSet.name)&gt;=0)});
-		
-		// add style rules to parser
-		for (var className in styleSet.rules) addRule(className, styleSet.rules[className]);
-		
-			
-		// replace for all elements
-		for (var i = 0; i &lt; stylableEls.length; i++) {
-			// EVIL hack to fix IE whitespace badness if it's inside a &lt;pre&gt;
-			if (/MSIE/.test(navigator.appVersion) &amp;&amp; stylableEls[i].parentNode.nodeName == 'PRE') {
-				stylableEls[i] = stylableEls[i].parentNode;
-				
-				parsed = stylableEls[i].innerHTML.replace(/(&lt;code[^&gt;]*&gt;)([^&lt;]*)&lt;\/code&gt;/i, function() {
-					return arguments[1] + parse(arguments[2], styleSet.ignoreCase) + &quot;&lt;/code&gt;&quot;
-				});
-				parsed = parsed.replace(/\n( *)/g, function() { 
-					var spaces = &quot;&quot;;
-					for (var i = 0; i &lt; arguments[1].length; i++) spaces+= &quot;&amp;nbsp;&quot;;
-					return &quot;\n&quot; + spaces;  
-				});
-				parsed = parsed.replace(/\t/g, &quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;);
-				parsed = parsed.replace(/\n(&lt;\/\w+&gt;)?/g, &quot;&lt;br /&gt;$1&quot;).replace(/&lt;br \/&gt;[\n\r\s]*&lt;br \/&gt;/g, &quot;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&quot;);
-				
-			} else parsed = parse(stylableEls[i].innerHTML, styleSet.ignoreCase);
-			
-			stylableEls[i].innerHTML = parsed;
-		}
-	}
-	
-	// run highlighter on all stylesets
-	for (var i=0; i &lt; this.styleSets.length; i++) {
-		highlightCode(this.styleSets[i]);
-	}
-};
-
-CodeHighlighter.addStyle(&quot;css&quot;, {
-	comment : {
-		exp  : /\/\*[^*]*\*+([^\/][^*]*\*+)*\//
-	},
-	keywords : {
-		exp  : /@\w[\w\s]*/
-	},
-	selectors : {
-		exp  : &quot;([\\w-:\\[.#][^{};&gt;]*)(?={)&quot;
-	},
-	properties : {
-		exp  : &quot;([\\w-]+)(?=\\s*:)&quot;
-	},
-	units : {
-		exp  : /([0-9])(em|en|px|%|pt)\b/,
-		replacement : &quot;$1&lt;span class=\&quot;$0\&quot;&gt;$2&lt;/span&gt;&quot;
-	},
-	urls : {
-		exp  : /url\([^\)]*\)/
-	}
-});
-
-CodeHighlighter.addStyle(&quot;html&quot;, {
-	comment : {
-		exp: /&amp;lt;!\s*(--([^-]|[\r\n]|-[^-])*--\s*)&amp;gt;/
-	},
-	tag : {
-		exp: /(&amp;lt;\/?)([a-zA-Z]+\s?)/, 
-		replacement: &quot;$1&lt;span class=\&quot;$0\&quot;&gt;$2&lt;/span&gt;&quot;
-	},
-	string : {
-		exp  : /'[^']*'|&quot;[^&quot;]*&quot;/
-	},
-	attribute : {
-		exp: /\b([a-zA-Z-:]+)(=)/, 
-		replacement: &quot;&lt;span class=\&quot;$0\&quot;&gt;$1&lt;/span&gt;$2&quot;
-	},
-	doctype : {
-		exp: /&amp;lt;!DOCTYPE([^&amp;]|&amp;[^g]|&amp;g[^t])*&amp;gt;/
-	}
-});
-
-CodeHighlighter.addStyle(&quot;javascript&quot;,{
-	comment : {
-		exp  : /(\/\/[^\n]*(\n|$))|(\/\*[^*]*\*+([^\/][^*]*\*+)*\/)/
-	},
-	brackets : {
-		exp  : /\(|\)/
-	},
-	regex : {
-         exp : /\/(.*?)[g|s|m]?\/[;|\n]/
-  },
-	string : {
-		exp  : /'(?:\.|(\\\')|[^\''])*'|&quot;(?:\.|(\\\&quot;)|[^\&quot;&quot;])*&quot;/
-	},
-	keywords : {
-		exp  : /\b(arguments|break|case|continue|default|delete|do|else|false|for|function|if|in|instanceof|new|null|return|switch|this|true|typeof|var|void|while|with)\b/
-	},
-	global : {
-		exp  : /\b(toString|valueOf|window|element|prototype|constructor|document|escape|unescape|parseInt|parseFloat|setTimeout|clearTimeout|setInterval|clearInterval|NaN|isNaN|Infinity|alert|prompt|confirm)\b/
-	}
-});
+/* Unobtrustive Code Highlighter By Dan Webb 11/2005
+   Version: 0.4
+	
+	Usage:
+		Add a script tag for this script and any stylesets you need to use
+		to the page in question, add correct class names to CODE elements, 
+		define CSS styles for elements. That's it! 
+	
+	Known to work on:
+		IE 5.5+ PC
+		Firefox/Mozilla PC/Mac
+		Opera 7.23 + PC
+		Safari 2
+		
+	Known to degrade gracefully on:
+		IE5.0 PC
+	
+	Note: IE5.0 fails due to the use of lookahead in some stylesets.  To avoid script errors
+	in older browsers use expressions that use lookahead in string format when defining stylesets.
+	
+	This script is inspired by star-light by entirely cunning Dean Edwards
+	http://dean.edwards.name/star-light/.  
+*/
+
+// replace callback support for safari.
+if (&quot;a&quot;.replace(/a/, function() {return &quot;b&quot;}) != &quot;b&quot;) (function(){
+  var default_replace = String.prototype.replace;
+  String.prototype.replace = function(search,replace){
+	// replace is not function
+	if(typeof replace != &quot;function&quot;){
+		return default_replace.apply(this,arguments)
+	}
+	var str = &quot;&quot; + this;
+	var callback = replace;
+	// search string is not RegExp
+	if(!(search instanceof RegExp)){
+		var idx = str.indexOf(search);
+		return (
+			idx == -1 ? str :
+			default_replace.apply(str,[search,callback(search, idx, str)])
+		)
+	}
+	var reg = search;
+	var result = [];
+	var lastidx = reg.lastIndex;
+	var re;
+	while((re = reg.exec(str)) != null){
+		var idx  = re.index;
+		var args = re.concat(idx, str);
+		result.push(
+			str.slice(lastidx,idx),
+			callback.apply(null,args).toString()
+		);
+		if(!reg.global){
+			lastidx += RegExp.lastMatch.length;
+			break
+		}else{
+			lastidx = reg.lastIndex;
+		}
+	}
+	result.push(str.slice(lastidx));
+	return result.join(&quot;&quot;)
+  }
+})();
+
+var CodeHighlighter = { styleSets : new Array };
+
+CodeHighlighter.addStyle = function(name, rules) {
+	// using push test to disallow older browsers from adding styleSets
+	if ([].push) this.styleSets.push({
+		name : name, 
+		rules : rules,
+		ignoreCase : arguments[2] || false
+	})
+	
+	function setEvent() {
+		// set highlighter to run on load (use LowPro if present)
+		if (typeof Event != 'undefined' &amp;&amp; typeof Event.onReady == 'function') 
+		  return Event.onReady(CodeHighlighter.init.bind(CodeHighlighter));
+		
+		var old = window.onload;
+		
+		if (typeof window.onload != 'function') {
+			window.onload = function() { CodeHighlighter.init() };
+		} else {
+			window.onload = function() {
+				old();
+				CodeHighlighter.init();
+			}
+		}
+	}
+	
+	// only set the event when the first style is added
+	if (this.styleSets.length==1) setEvent();
+}
+
+CodeHighlighter.init = function() {
+	if (!document.getElementsByTagName) return; 
+	if (&quot;a&quot;.replace(/a/, function() {return &quot;b&quot;}) != &quot;b&quot;) return; // throw out Safari versions that don't support replace function
+	// throw out older browsers
+	
+	var codeEls = document.getElementsByTagName(&quot;CODE&quot;);
+	// collect array of all pre elements
+	codeEls.filter = function(f) {
+		var a =  new Array;
+		for (var i = 0; i &lt; this.length; i++) if (f(this[i])) a[a.length] = this[i];
+		return a;
+	} 
+	
+	var rules = new Array;
+	rules.toString = function() {
+		// joins regexes into one big parallel regex
+		var exps = new Array;
+		for (var i = 0; i &lt; this.length; i++) exps.push(this[i].exp);
+		return exps.join(&quot;|&quot;);
+	}
+	
+	function addRule(className, rule) {
+		// add a replace rule
+		var exp = (typeof rule.exp != &quot;string&quot;)?String(rule.exp).substr(1, String(rule.exp).length-2):rule.exp;
+		// converts regex rules to strings and chops of the slashes
+		rules.push({
+			className : className,
+			exp : &quot;(&quot; + exp + &quot;)&quot;,
+			length : (exp.match(/(^|[^\\])\([^?]/g) || &quot;&quot;).length + 1, // number of subexps in rule
+			replacement : rule.replacement || null 
+		});
+	}
+	
+	function parse(text, ignoreCase) {
+		// main text parsing and replacement
+		return text.replace(new RegExp(rules, (ignoreCase)?&quot;gi&quot;:&quot;g&quot;), function() {
+			var i = 0, j = 1, rule;
+			while (rule = rules[i++]) {
+				if (arguments[j]) {
+					// if no custom replacement defined do the simple replacement
+					if (!rule.replacement) return &quot;&lt;span class=\&quot;&quot; + rule.className + &quot;\&quot;&gt;&quot; + arguments[0] + &quot;&lt;/span&gt;&quot;;
+					else {
+						// replace $0 with the className then do normal replaces
+						var str = rule.replacement.replace(&quot;$0&quot;, rule.className);
+						for (var k = 1; k &lt;= rule.length - 1; k++) str = str.replace(&quot;$&quot; + k, arguments[j + k]);
+						return str;
+					}
+				} else j+= rule.length;
+			}
+		});
+	}
+	
+	function highlightCode(styleSet) {
+		// clear rules array
+		var parsed;
+		rules.length = 0;
+		
+		// get stylable elements by filtering out all code elements without the correct className	
+		var stylableEls = codeEls.filter(function(item) {return (item.className.indexOf(styleSet.name)&gt;=0)});
+		
+		// add style rules to parser
+		for (var className in styleSet.rules) addRule(className, styleSet.rules[className]);
+		
+			
+		// replace for all elements
+		for (var i = 0; i &lt; stylableEls.length; i++) {
+			// EVIL hack to fix IE whitespace badness if it's inside a &lt;pre&gt;
+			if (/MSIE/.test(navigator.appVersion) &amp;&amp; stylableEls[i].parentNode.nodeName == 'PRE') {
+				stylableEls[i] = stylableEls[i].parentNode;
+				
+				parsed = stylableEls[i].innerHTML.replace(/(&lt;code[^&gt;]*&gt;)([^&lt;]*)&lt;\/code&gt;/i, function() {
+					return arguments[1] + parse(arguments[2], styleSet.ignoreCase) + &quot;&lt;/code&gt;&quot;
+				});
+				parsed = parsed.replace(/\n( *)/g, function() { 
+					var spaces = &quot;&quot;;
+					for (var i = 0; i &lt; arguments[1].length; i++) spaces+= &quot;&amp;nbsp;&quot;;
+					return &quot;\n&quot; + spaces;  
+				});
+				parsed = parsed.replace(/\t/g, &quot;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&quot;);
+				parsed = parsed.replace(/\n(&lt;\/\w+&gt;)?/g, &quot;&lt;br /&gt;$1&quot;).replace(/&lt;br \/&gt;[\n\r\s]*&lt;br \/&gt;/g, &quot;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&quot;);
+				
+			} else parsed = parse(stylableEls[i].innerHTML, styleSet.ignoreCase);
+			
+			stylableEls[i].innerHTML = parsed;
+		}
+	}
+	
+	// run highlighter on all stylesets
+	for (var i=0; i &lt; this.styleSets.length; i++) {
+		highlightCode(this.styleSets[i]);
+	}
+};
+
+CodeHighlighter.addStyle(&quot;css&quot;, {
+	comment : {
+		exp  : /\/\*[^*]*\*+([^\/][^*]*\*+)*\//
+	},
+	keywords : {
+		exp  : /@\w[\w\s]*/
+	},
+	selectors : {
+		exp  : &quot;([\\w-:\\[.#][^{};&gt;]*)(?={)&quot;
+	},
+	properties : {
+		exp  : &quot;([\\w-]+)(?=\\s*:)&quot;
+	},
+	units : {
+		exp  : /([0-9])(em|en|px|%|pt)\b/,
+		replacement : &quot;$1&lt;span class=\&quot;$0\&quot;&gt;$2&lt;/span&gt;&quot;
+	},
+	urls : {
+		exp  : /url\([^\)]*\)/
+	}
+});
+
+CodeHighlighter.addStyle(&quot;html&quot;, {
+	comment : {
+		exp: /&amp;lt;!\s*(--([^-]|[\r\n]|-[^-])*--\s*)&amp;gt;/
+	},
+	tag : {
+		exp: /(&amp;lt;\/?)([a-zA-Z]+\s?)/, 
+		replacement: &quot;$1&lt;span class=\&quot;$0\&quot;&gt;$2&lt;/span&gt;&quot;
+	},
+	string : {
+		exp  : /'[^']*'|&quot;[^&quot;]*&quot;/
+	},
+	attribute : {
+		exp: /\b([a-zA-Z-:]+)(=)/, 
+		replacement: &quot;&lt;span class=\&quot;$0\&quot;&gt;$1&lt;/span&gt;$2&quot;
+	},
+	doctype : {
+		exp: /&amp;lt;!DOCTYPE([^&amp;]|&amp;[^g]|&amp;g[^t])*&amp;gt;/
+	}
+});
+
+CodeHighlighter.addStyle(&quot;javascript&quot;,{
+	comment : {
+		exp  : /(\/\/[^\n]*(\n|$))|(\/\*[^*]*\*+([^\/][^*]*\*+)*\/)/
+	},
+	brackets : {
+		exp  : /\(|\)/
+	},
+	regex : {
+         exp : /\/(.*?)[g|s|m]?\/[;|\n]/
+  },
+	string : {
+		exp  : /'(?:\.|(\\\')|[^\''])*'|&quot;(?:\.|(\\\&quot;)|[^\&quot;&quot;])*&quot;/
+	},
+	keywords : {
+		exp  : /\b(arguments|break|case|continue|default|delete|do|else|false|for|function|if|in|instanceof|new|null|return|switch|this|true|typeof|var|void|while|with)\b/
+	},
+	global : {
+		exp  : /\b(toString|valueOf|window|element|prototype|constructor|document|escape|unescape|parseInt|parseFloat|setTimeout|clearTimeout|setInterval|clearInterval|NaN|isNaN|Infinity|alert|prompt|confirm)\b/
+	}
+});</diff>
      <filename>templates/html/assets/javascripts/code_highlighter.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
-/*  Prototype JavaScript framework, version 1.6.0.2
- *  (c) 2005-2008 Sam Stephenson
+/*  Prototype JavaScript framework, version 1.6.0.3
+ *  (c) 2005-2009 Sam Stephenson
  *
  *  Prototype is freely distributable under the terms of an MIT-style license.
  *  For details, see the Prototype web site: http://www.prototypejs.org/
@@ -7,23 +7,39 @@
  *--------------------------------------------------------------------------*/
 
 var Prototype = {
-  Version: '1.6.0.2',
+  Version: '1.6.0.4_rc0',
 
   Browser: {
-    IE:     !!(window.attachEvent &amp;&amp; !window.opera),
-    Opera:  !!window.opera,
+    IE:     !!(window.attachEvent &amp;&amp;
+      navigator.userAgent.indexOf('Opera') === -1),
+    Opera:  navigator.userAgent.indexOf('Opera') &gt; -1,
     WebKit: navigator.userAgent.indexOf('AppleWebKit/') &gt; -1,
-    Gecko:  navigator.userAgent.indexOf('Gecko') &gt; -1 &amp;&amp; navigator.userAgent.indexOf('KHTML') == -1,
+    Gecko:  navigator.userAgent.indexOf('Gecko') &gt; -1 &amp;&amp;
+      navigator.userAgent.indexOf('KHTML') === -1,
     MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
   },
 
   BrowserFeatures: {
     XPath: !!document.evaluate,
-    ElementExtensions: !!window.HTMLElement,
-    SpecificElementExtensions:
-      document.createElement('div').__proto__ &amp;&amp;
-      document.createElement('div').__proto__ !==
-        document.createElement('form').__proto__
+    SelectorsAPI: !!document.querySelector,
+    ElementExtensions: (function() {
+      if (window.HTMLElement &amp;&amp; window.HTMLElement.prototype)
+        return true;
+      if (window.Element &amp;&amp; window.Element.prototype)
+        return true;
+    })(),
+    SpecificElementExtensions: (function() {
+      if (typeof window.HTMLDivElement !== 'undefined')
+        return true;
+
+      var div = document.createElement('div');
+      if (div['__proto__'] &amp;&amp; div['__proto__'] !==
+       document.createElement('form')['__proto__']) {
+        return true;
+      }
+
+      return false;
+    })()
   },
 
   ScriptFragment: '&lt;script[^&gt;]*&gt;([\\S\\s]*?)&lt;\/script&gt;',
@@ -37,9 +53,29 @@ if (Prototype.Browser.MobileSafari)
   Prototype.BrowserFeatures.SpecificElementExtensions = false;
 
 
+var Abstract = { };
+
+
+var Try = {
+  these: function() {
+    var returnValue;
+
+    for (var i = 0, length = arguments.length; i &lt; length; i++) {
+      var lambda = arguments[i];
+      try {
+        returnValue = lambda();
+        break;
+      } catch (e) { }
+    }
+
+    return returnValue;
+  }
+};
+
 /* Based on Alex Arnell's inheritance implementation. */
-var Class = {
-  create: function() {
+
+var Class = (function() {
+  function create() {
     var parent = null, properties = $A(arguments);
     if (Object.isFunction(properties[0]))
       parent = properties.shift();
@@ -53,7 +89,7 @@ var Class = {
     klass.subclasses = [];
 
     if (parent) {
-      var subclass = function() { };
+      var subclass = function() {};
       subclass.prototype = parent.prototype;
       klass.prototype = new subclass;
       parent.subclasses.push(klass);
@@ -66,58 +102,70 @@ var Class = {
       klass.prototype.initialize = Prototype.emptyFunction;
 
     klass.prototype.constructor = klass;
-
     return klass;
   }
-};
 
-Class.Methods = {
-  addMethods: function(source) {
+  function addMethods(source) {
     var ancestor   = this.superclass &amp;&amp; this.superclass.prototype;
     var properties = Object.keys(source);
 
-    if (!Object.keys({ toString: true }).length)
-      properties.push(&quot;toString&quot;, &quot;valueOf&quot;);
+    if (!Object.keys({ toString: true }).length) {
+      if (source.toString != Object.prototype.toString)
+        properties.push(&quot;toString&quot;);
+      if (source.valueOf != Object.prototype.valueOf)
+        properties.push(&quot;valueOf&quot;);
+    }
 
     for (var i = 0, length = properties.length; i &lt; length; i++) {
       var property = properties[i], value = source[property];
       if (ancestor &amp;&amp; Object.isFunction(value) &amp;&amp;
           value.argumentNames().first() == &quot;$super&quot;) {
-        var method = value, value = Object.extend((function(m) {
-          return function() { return ancestor[m].apply(this, arguments) };
-        })(property).wrap(method), {
-          valueOf:  function() { return method },
-          toString: function() { return method.toString() }
-        });
+        var method = value;
+        value = (function(m) {
+          return function() { return ancestor[m].apply(this, arguments); };
+        })(property).wrap(method);
+
+        value.valueOf = method.valueOf.bind(method);
+        value.toString = method.toString.bind(method);
       }
       this.prototype[property] = value;
     }
 
     return this;
   }
-};
 
-var Abstract = { };
+  return {
+    create: create,
+    Methods: {
+      addMethods: addMethods
+    }
+  };
+})();
+(function() {
 
-Object.extend = function(destination, source) {
-  for (var property in source)
-    destination[property] = source[property];
-  return destination;
-};
+  function getClass(object) {
+    return Object.prototype.toString.call(object)
+     .match(/^\[object\s(.*)\]$/)[1];
+  }
+
+  function extend(destination, source) {
+    for (var property in source)
+      destination[property] = source[property];
+    return destination;
+  }
 
-Object.extend(Object, {
-  inspect: function(object) {
+  function inspect(object) {
     try {
-      if (Object.isUndefined(object)) return 'undefined';
+      if (isUndefined(object)) return 'undefined';
       if (object === null) return 'null';
       return object.inspect ? object.inspect() : String(object);
     } catch (e) {
       if (e instanceof RangeError) return '...';
       throw e;
     }
-  },
+  }
 
-  toJSON: function(object) {
+  function toJSON(object) {
     var type = typeof object;
     switch (type) {
       case 'undefined':
@@ -128,127 +176,180 @@ Object.extend(Object, {
 
     if (object === null) return 'null';
     if (object.toJSON) return object.toJSON();
-    if (Object.isElement(object)) return;
+    if (isElement(object)) return;
 
     var results = [];
     for (var property in object) {
-      var value = Object.toJSON(object[property]);
-      if (!Object.isUndefined(value))
+      var value = toJSON(object[property]);
+      if (!isUndefined(value))
         results.push(property.toJSON() + ': ' + value);
     }
 
     return '{' + results.join(', ') + '}';
-  },
+  }
 
-  toQueryString: function(object) {
+  function toQueryString(object) {
     return $H(object).toQueryString();
-  },
+  }
 
-  toHTML: function(object) {
+  function toHTML(object) {
     return object &amp;&amp; object.toHTML ? object.toHTML() : String.interpret(object);
-  },
+  }
 
-  keys: function(object) {
-    var keys = [];
+  function keys(object) {
+    var results = [];
     for (var property in object)
-      keys.push(property);
-    return keys;
-  },
+      results.push(property);
+    return results;
+  }
 
-  values: function(object) {
-    var values = [];
+  function values(object) {
+    var results = [];
     for (var property in object)
-      values.push(object[property]);
-    return values;
-  },
+      results.push(object[property]);
+    return results;
+  }
 
-  clone: function(object) {
-    return Object.extend({ }, object);
-  },
+  function clone(object) {
+    return extend({ }, object);
+  }
 
-  isElement: function(object) {
-    return object &amp;&amp; object.nodeType == 1;
-  },
+  function isElement(object) {
+    return !!(object &amp;&amp; object.nodeType == 1);
+  }
+
+  function isArray(object) {
+    return getClass(object) === &quot;Array&quot;;
+  }
 
-  isArray: function(object) {
-    return object != null &amp;&amp; typeof object == &quot;object&quot; &amp;&amp;
-      'splice' in object &amp;&amp; 'join' in object;
-  },
 
-  isHash: function(object) {
+  function isHash(object) {
     return object instanceof Hash;
-  },
+  }
 
-  isFunction: function(object) {
-    return typeof object == &quot;function&quot;;
-  },
+  function isFunction(object) {
+    return typeof object === &quot;function&quot;;
+  }
 
-  isString: function(object) {
-    return typeof object == &quot;string&quot;;
-  },
+  function isString(object) {
+    return getClass(object) === &quot;String&quot;;
+  }
 
-  isNumber: function(object) {
-    return typeof object == &quot;number&quot;;
-  },
+  function isNumber(object) {
+    return getClass(object) === &quot;Number&quot;;
+  }
 
-  isUndefined: function(object) {
-    return typeof object == &quot;undefined&quot;;
+  function isUndefined(object) {
+    return typeof object === &quot;undefined&quot;;
+  }
+
+  extend(Object, {
+    extend:        extend,
+    inspect:       inspect,
+    toJSON:        toJSON,
+    toQueryString: toQueryString,
+    toHTML:        toHTML,
+    keys:          keys,
+    values:        values,
+    clone:         clone,
+    isElement:     isElement,
+    isArray:       isArray,
+    isHash:        isHash,
+    isFunction:    isFunction,
+    isString:      isString,
+    isNumber:      isNumber,
+    isUndefined:   isUndefined
+  });
+})();
+Object.extend(Function.prototype, (function() {
+  var slice = Array.prototype.slice;
+
+  function update(array, args) {
+    var arrayLength = array.length, length = args.length;
+    while (length--) array[arrayLength + length] = args[length];
+    return array;
+  }
+
+  function merge(array, args) {
+    array = slice.call(array, 0);
+    return update(array, args);
   }
-});
 
-Object.extend(Function.prototype, {
-  argumentNames: function() {
-    var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(&quot;,&quot;).invoke(&quot;strip&quot;);
+  function argumentNames() {
+    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
+      .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
+      .replace(/\s+/g, '').split(',');
     return names.length == 1 &amp;&amp; !names[0] ? [] : names;
-  },
+  }
 
-  bind: function() {
+  function bind(context) {
     if (arguments.length &lt; 2 &amp;&amp; Object.isUndefined(arguments[0])) return this;
-    var __method = this, args = $A(arguments), object = args.shift();
+    var __method = this, args = slice.call(arguments, 1);
     return function() {
-      return __method.apply(object, args.concat($A(arguments)));
+      var a = merge(args, arguments);
+      return __method.apply(context, a);
     }
-  },
+  }
 
-  bindAsEventListener: function() {
-    var __method = this, args = $A(arguments), object = args.shift();
+  function bindAsEventListener(context) {
+    var __method = this, args = slice.call(arguments, 1);
     return function(event) {
-      return __method.apply(object, [event || window.event].concat(args));
+      var a = update([event || window.event], args);
+      return __method.apply(context, a);
     }
-  },
+  }
 
-  curry: function() {
+  function curry() {
     if (!arguments.length) return this;
-    var __method = this, args = $A(arguments);
+    var __method = this, args = slice.call(arguments, 0);
     return function() {
-      return __method.apply(this, args.concat($A(arguments)));
+      var a = merge(args, arguments);
+      return __method.apply(this, a);
     }
-  },
+  }
 
-  delay: function() {
-    var __method = this, args = $A(arguments), timeout = args.shift() * 1000;
+  function delay(timeout) {
+    var __method = this, args = slice.call(arguments, 1);
+    timeout = timeout * 1000
     return window.setTimeout(function() {
       return __method.apply(__method, args);
     }, timeout);
-  },
+  }
+
+  function defer() {
+    var args = update([0.01], arguments);
+    return this.delay.apply(this, args);
+  }
 
-  wrap: function(wrapper) {
+  function wrap(wrapper) {
     var __method = this;
     return function() {
-      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
+      var a = update([__method.bind(this)], arguments);
+      return wrapper.apply(this, a);
     }
-  },
+  }
 
-  methodize: function() {
+  function methodize() {
     if (this._methodized) return this._methodized;
     var __method = this;
     return this._methodized = function() {
-      return __method.apply(null, [this].concat($A(arguments)));
+      var a = update([this], arguments);
+      return __method.apply(null, a);
     };
   }
-});
 
-Function.prototype.defer = Function.prototype.delay.curry(0.01);
+  return {
+    argumentNames:       argumentNames,
+    bind:                bind,
+    bindAsEventListener: bindAsEventListener,
+    curry:               curry,
+    delay:               delay,
+    defer:               defer,
+    wrap:                wrap,
+    methodize:           methodize
+  }
+})());
+
 
 Date.prototype.toJSON = function() {
   return '&quot;' + this.getUTCFullYear() + '-' +
@@ -259,30 +360,12 @@ Date.prototype.toJSON = function() {
     this.getUTCSeconds().toPaddedString(2) + 'Z&quot;';
 };
 
-var Try = {
-  these: function() {
-    var returnValue;
-
-    for (var i = 0, length = arguments.length; i &lt; length; i++) {
-      var lambda = arguments[i];
-      try {
-        returnValue = lambda();
-        break;
-      } catch (e) { }
-    }
-
-    return returnValue;
-  }
-};
 
 RegExp.prototype.match = RegExp.prototype.test;
 
 RegExp.escape = function(str) {
   return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
 };
-
-/*--------------------------------------------------------------------------*/
-
 var PeriodicalExecuter = Class.create({
   initialize: function(callback, frequency) {
     this.callback = callback;
@@ -331,10 +414,25 @@ Object.extend(String, {
   }
 });
 
-Object.extend(String.prototype, {
-  gsub: function(pattern, replacement) {
+Object.extend(String.prototype, (function() {
+
+  function prepareReplacement(replacement) {
+    if (Object.isFunction(replacement)) return replacement;
+    var template = new Template(replacement);
+    return function(match) { return template.evaluate(match) };
+  }
+
+  function gsub(pattern, replacement) {
     var result = '', source = this, match;
-    replacement = arguments.callee.prepareReplacement(replacement);
+    replacement = prepareReplacement(replacement);
+
+    if (Object.isString(pattern))
+      pattern = RegExp.escape(pattern);
+
+    if (!(pattern.length || pattern.source)) {
+      replacement = replacement('');
+      return replacement + source.split('').join(replacement) + replacement;
+    }
 
     while (source.length &gt; 0) {
       if (match = source.match(pattern)) {
@@ -346,69 +444,68 @@ Object.extend(String.prototype, {
       }
     }
     return result;
-  },
+  }
 
-  sub: function(pattern, replacement, count) {
-    replacement = this.gsub.prepareReplacement(replacement);
+  function sub(pattern, replacement, count) {
+    replacement = prepareReplacement(replacement);
     count = Object.isUndefined(count) ? 1 : count;
 
     return this.gsub(pattern, function(match) {
       if (--count &lt; 0) return match[0];
       return replacement(match);
     });
-  },
+  }
 
-  scan: function(pattern, iterator) {
+  function scan(pattern, iterator) {
     this.gsub(pattern, iterator);
     return String(this);
-  },
+  }
 
-  truncate: function(length, truncation) {
+  function truncate(length, truncation) {
     length = length || 30;
     truncation = Object.isUndefined(truncation) ? '...' : truncation;
     return this.length &gt; length ?
       this.slice(0, length - truncation.length) + truncation : String(this);
-  },
+  }
 
-  strip: function() {
+  function strip() {
     return this.replace(/^\s+/, '').replace(/\s+$/, '');
-  },
+  }
 
-  stripTags: function() {
+  function stripTags() {
     return this.replace(/&lt;\/?[^&gt;]+&gt;/gi, '');
-  },
+  }
 
-  stripScripts: function() {
+  function stripScripts() {
     return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
-  },
+  }
 
-  extractScripts: function() {
+  function extractScripts() {
     var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
     var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
     return (this.match(matchAll) || []).map(function(scriptTag) {
       return (scriptTag.match(matchOne) || ['', ''])[1];
     });
-  },
+  }
 
-  evalScripts: function() {
+  function evalScripts() {
     return this.extractScripts().map(function(script) { return eval(script) });
-  },
+  }
 
-  escapeHTML: function() {
-    var self = arguments.callee;
-    self.text.data = this;
-    return self.div.innerHTML;
-  },
+  function escapeHTML() {
+    escapeHTML.text.data = this;
+    return escapeHTML.div.innerHTML;
+  }
 
-  unescapeHTML: function() {
+  function unescapeHTML() {
     var div = new Element('div');
     div.innerHTML = this.stripTags();
     return div.childNodes[0] ? (div.childNodes.length &gt; 1 ?
       $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) :
       div.childNodes[0].nodeValue) : '';
-  },
+  }
 
-  toQueryParams: function(separator) {
+  function toQueryParams(separator) {
     var match = this.strip().match(/([^?#]*)(#.*)?$/);
     if (!match) return { };
 
@@ -426,22 +523,22 @@ Object.extend(String.prototype, {
       }
       return hash;
     });
-  },
+  }
 
-  toArray: function() {
+  function toArray() {
     return this.split('');
-  },
+  }
 
-  succ: function() {
+  function succ() {
     return this.slice(0, this.length - 1) +
       String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
-  },
+  }
 
-  times: function(count) {
+  function times(count) {
     return count &lt; 1 ? '' : new Array(count + 1).join(this);
-  },
+  }
 
-  camelize: function() {
+  function camelize() {
     var parts = this.split('-'), len = parts.length;
     if (len == 1) return parts[0];
 
@@ -453,101 +550,127 @@ Object.extend(String.prototype, {
       camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
 
     return camelized;
-  },
+  }
 
-  capitalize: function() {
+  function capitalize() {
     return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
-  },
+  }
 
-  underscore: function() {
+  function underscore() {
     return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
-  },
+  }
 
-  dasherize: function() {
+  function dasherize() {
     return this.gsub(/_/,'-');
-  },
+  }
 
-  inspect: function(useDoubleQuotes) {
+  function inspect(useDoubleQuotes) {
     var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) {
       var character = String.specialChar[match[0]];
       return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
     });
     if (useDoubleQuotes) return '&quot;' + escapedString.replace(/&quot;/g, '\\&quot;') + '&quot;';
     return &quot;'&quot; + escapedString.replace(/'/g, '\\\'') + &quot;'&quot;;
-  },
+  }
 
-  toJSON: function() {
+  function toJSON() {
     return this.inspect(true);
-  },
+  }
 
-  unfilterJSON: function(filter) {
+  function unfilterJSON(filter) {
     return this.sub(filter || Prototype.JSONFilter, '#{1}');
-  },
+  }
 
-  isJSON: function() {
+  function isJSON() {
     var str = this;
     if (str.blank()) return false;
     str = this.replace(/\\./g, '@').replace(/&quot;[^&quot;\\\n\r]*&quot;/g, '');
     return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str);
-  },
+  }
 
-  evalJSON: function(sanitize) {
+  function evalJSON(sanitize) {
     var json = this.unfilterJSON();
     try {
       if (!sanitize || json.isJSON()) return eval('(' + json + ')');
     } catch (e) { }
     throw new SyntaxError('Badly formed JSON string: ' + this.inspect());
-  },
+  }
 
-  include: function(pattern) {
+  function include(pattern) {
     return this.indexOf(pattern) &gt; -1;
-  },
+  }
 
-  startsWith: function(pattern) {
+  function startsWith(pattern) {
     return this.indexOf(pattern) === 0;
-  },
+  }
 
-  endsWith: function(pattern) {
+  function endsWith(pattern) {
     var d = this.length - pattern.length;
     return d &gt;= 0 &amp;&amp; this.lastIndexOf(pattern) === d;
-  },
+  }
 
-  empty: function() {
+  function empty() {
     return this == '';
-  },
+  }
 
-  blank: function() {
+  function blank() {
     return /^\s*$/.test(this);
-  },
+  }
 
-  interpolate: function(object, pattern) {
+  function interpolate(object, pattern) {
     return new Template(this, pattern).evaluate(object);
   }
-});
+
+  return {
+    gsub:           gsub,
+    sub:            sub,
+    scan:           scan,
+    truncate:       truncate,
+    strip:          strip,
+    stripTags:      stripTags,
+    stripScripts:   stripScripts,
+    extractScripts: extractScripts,
+    evalScripts:    evalScripts,
+    escapeHTML:     escapeHTML,
+    unescapeHTML:   unescapeHTML,
+    toQueryParams:  toQueryParams,
+    parseQuery:     toQueryParams,
+    toArray:        toArray,
+    succ:           succ,
+    times:          times,
+    camelize:       camelize,
+    capitalize:     capitalize,
+    underscore:     underscore,
+    dasherize:      dasherize,
+    inspect:        inspect,
+    toJSON:         toJSON,
+    unfilterJSON:   unfilterJSON,
+    isJSON:         isJSON,
+    evalJSON:       evalJSON,
+    include:        include,
+    startsWith:     startsWith,
+    endsWith:       endsWith,
+    empty:          empty,
+    blank:          blank,
+    interpolate:    interpolate
+  };
+})());
 
 if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, {
   escapeHTML: function() {
     return this.replace(/&amp;/g,'&amp;amp;').replace(/&lt;/g,'&amp;lt;').replace(/&gt;/g,'&amp;gt;');
   },
   unescapeHTML: function() {
-    return this.replace(/&amp;amp;/g,'&amp;').replace(/&amp;lt;/g,'&lt;').replace(/&amp;gt;/g,'&gt;');
+    return this.stripTags().replace(/&amp;lt;/g,'&lt;').replace(/&amp;gt;/g,'&gt;').replace(/&amp;amp;/g,'&amp;');
   }
 });
 
-String.prototype.gsub.prepareReplacement = function(replacement) {
-  if (Object.isFunction(replacement)) return replacement;
-  var template = new Template(replacement);
-  return function(match) { return template.evaluate(match) };
-};
-
-String.prototype.parseQuery = String.prototype.toQueryParams;
-
 Object.extend(String.prototype.escapeHTML, {
   div:  document.createElement('div'),
   text: document.createTextNode('')
 });
 
-with (String.prototype.escapeHTML) div.appendChild(text);
+String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
 
 var Template = Class.create({
   initialize: function(template, pattern) {
@@ -586,94 +709,91 @@ Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
 
 var $break = { };
 
-var Enumerable = {
-  each: function(iterator, context) {
+var Enumerable = (function() {
+  function each(iterator, context) {
     var index = 0;
-    iterator = iterator.bind(context);
     try {
       this._each(function(value) {
-        iterator(value, index++);
+        iterator.call(context, value, index++);
       });
     } catch (e) {
       if (e != $break) throw e;
     }
     return this;
-  },
+  }
 
-  eachSlice: function(number, iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+  function eachSlice(number, iterator, context) {
     var index = -number, slices = [], array = this.toArray();
+    if (number &lt; 1) return array;
     while ((index += number) &lt; array.length)
       slices.push(array.slice(index, index+number));
     return slices.collect(iterator, context);
-  },
+  }
 
-  all: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+  function all(iterator, context) {
+    iterator = iterator || Prototype.K;
     var result = true;
     this.each(function(value, index) {
-      result = result &amp;&amp; !!iterator(value, index);
+      result = result &amp;&amp; !!iterator.call(context, value, index);
       if (!result) throw $break;
     });
     return result;
-  },
+  }
 
-  any: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+  function any(iterator, context) {
+    iterator = iterator || Prototype.K;
     var result = false;
     this.each(function(value, index) {
-      if (result = !!iterator(value, index))
+      if (result = !!iterator.call(context, value, index))
         throw $break;
     });
     return result;
-  },
+  }
 
-  collect: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+  function collect(iterator, context) {
+    iterator = iterator || Prototype.K;
     var results = [];
     this.each(function(value, index) {
-      results.push(iterator(value, index));
+      results.push(iterator.call(context, value, index));
     });
     return results;
-  },
+  }
 
-  detect: function(iterator, context) {
-    iterator = iterator.bind(context);
+  function detect(iterator, context) {
     var result;
     this.each(function(value, index) {
-      if (iterator(value, index)) {
+      if (iterator.call(context, value, index)) {
         result = value;
         throw $break;
       }
     });
     return result;
-  },
+  }
 
-  findAll: function(iterator, context) {
-    iterator = iterator.bind(context);
+  function findAll(iterator, context) {
     var results = [];
     this.each(function(value, index) {
-      if (iterator(value, index))
+      if (iterator.call(context, value, index))
         results.push(value);
     });
     return results;
-  },
+  }
 
-  grep: function(filter, iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+  function grep(filter, iterator, context) {
+    iterator = iterator || Prototype.K;
     var results = [];
 
     if (Object.isString(filter))
-      filter = new RegExp(filter);
+      filter = new RegExp(RegExp.escape(filter));
 
     this.each(function(value, index) {
       if (filter.match(value))
-        results.push(iterator(value, index));
+        results.push(iterator.call(context, value, index));
     });
     return results;
-  },
+  }
 
-  include: function(object) {
+  function include(object) {
     if (Object.isFunction(this.indexOf))
       if (this.indexOf(object) != -1) return true;
 
@@ -685,96 +805,96 @@ var Enumerable = {
       }
     });
     return found;
-  },
+  }
 
-  inGroupsOf: function(number, fillWith) {
+  function inGroupsOf(number, fillWith) {
     fillWith = Object.isUndefined(fillWith) ? null : fillWith;
     return this.eachSlice(number, function(slice) {
       while(slice.length &lt; number) slice.push(fillWith);
       return slice;
     });
-  },
+  }
 
-  inject: function(memo, iterator, context) {
-    iterator = iterator.bind(context);
+  function inject(memo, iterator, context) {
     this.each(function(value, index) {
-      memo = iterator(memo, value, index);
+      memo = iterator.call(context, memo, value, index);
     });
     return memo;
-  },
+  }
 
-  invoke: function(method) {
+  function invoke(method) {
     var args = $A(arguments).slice(1);
     return this.map(function(value) {
       return value[method].apply(value, args);
     });
-  },
+  }
 
-  max: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+  function max(iterator, context) {
+    iterator = iterator || Prototype.K;
     var result;
     this.each(function(value, index) {
-      value = iterator(value, index);
+      value = iterator.call(context, value, index);
       if (result == null || value &gt;= result)
         result = value;
     });
     return result;
-  },
+  }
 
-  min: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+  function min(iterator, context) {
+    iterator = iterator || Prototype.K;
     var result;
     this.each(function(value, index) {
-      value = iterator(value, index);
+      value = iterator.call(context, value, index);
       if (result == null || value &lt; result)
         result = value;
     });
     return result;
-  },
+  }
 
-  partition: function(iterator, context) {
-    iterator = iterator ? iterator.bind(context) : Prototype.K;
+  function partition(iterator, context) {
+    iterator = iterator || Prototype.K;
     var trues = [], falses = [];
     this.each(function(value, index) {
-      (iterator(value, index) ?
+      (iterator.call(context, value, index) ?
         trues : falses).push(value);
     });
     return [trues, falses];
-  },
+  }
 
-  pluck: function(property) {
+  function pluck(property) {
     var results = [];
     this.each(function(value) {
       results.push(value[property]);
     });
     return results;
-  },
+  }
 
-  reject: function(iterator, context) {
-    iterator = iterator.bind(context);
+  function reject(iterator, context) {
     var results = [];
     this.each(function(value, index) {
-      if (!iterator(value, index))
+      if (!iterator.call(context, value, index))
         results.push(value);
     });
     return results;
-  },
+  }
 
-  sortBy: function(iterator, context) {
-    iterator = iterator.bind(context);
+  function sortBy(iterator, context) {
     return this.map(function(value, index) {
-      return {value: value, criteria: iterator(value, index)};
+      return {
+        value: value,
+        criteria: iterator.call(context, value, index)
+      };
     }).sort(function(left, right) {
       var a = left.criteria, b = right.criteria;
       return a &lt; b ? -1 : a &gt; b ? 1 : 0;
     }).pluck('value');
-  },
+  }
 
-  toArray: function() {
+  function toArray() {
     return this.map();
-  },
+  }
 
-  zip: function() {
+  function zip() {
     var iterator = Prototype.K, args = $A(arguments);
     if (Object.isFunction(args.last()))
       iterator = args.pop();
@@ -783,27 +903,49 @@ var Enumerable = {
     return this.map(function(value, index) {
       return iterator(collections.pluck(index));
     });
-  },
+  }
 
-  size: function() {
+  function size() {
     return this.toArray().length;
-  },
+  }
 
-  inspect: function() {
+  function inspect() {
     return '#&lt;Enumerable:' + this.toArray().inspect() + '&gt;';
   }
-};
 
-Object.extend(Enumerable, {
-  map:     Enumerable.collect,
-  find:    Enumerable.detect,
-  select:  Enumerable.findAll,
-  filter:  Enumerable.findAll,
-  member:  Enumerable.include,
-  entries: Enumerable.toArray,
-  every:   Enumerable.all,
-  some:    Enumerable.any
-});
+  return {
+    each:       each,
+    eachSlice:  eachSlice,
+    all:        all,
+    every:      all,
+    any:        any,
+    some:       any,
+    collect:    collect,
+    map:        collect,
+    detect:     detect,
+    findAll:    findAll,
+    select:     findAll,
+    filter:     findAll,
+    grep:       grep,
+    include:    include,
+    member:     include,
+    inGroupsOf: inGroupsOf,
+    inject:     inject,
+    invoke:     invoke,
+    max:        max,
+    min:        min,
+    partition:  partition,
+    pluck:      pluck,
+    reject:     reject,
+    sortBy:     sortBy,
+    toArray:    toArray,
+    entries:    toArray,
+    zip:        zip,
+    size:       size,
+    inspect:    inspect,
+    find:       detect
+  };
+})();
 function $A(iterable) {
   if (!iterable) return [];
   if (iterable.toArray) return iterable.toArray();
@@ -815,94 +957,104 @@ function $A(iterable) {
 if (Prototype.Browser.WebKit) {
   $A = function(iterable) {
     if (!iterable) return [];
-    if (!(Object.isFunction(iterable) &amp;&amp; iterable == '[object NodeList]') &amp;&amp;
-        iterable.toArray) return iterable.toArray();
+    if (!(typeof iterable === 'function' &amp;&amp; typeof iterable.length ===
+        'number' &amp;&amp; typeof iterable.item === 'function') &amp;&amp; iterable.toArray)
+      return iterable.toArray();
     var length = iterable.length || 0, results = new Array(length);
     while (length--) results[length] = iterable[length];
     return results;
   };
 }
 
-Array.from = $A;
+function $w(string) {
+  if (!Object.isString(string)) return [];
+  string = string.strip();
+  return string ? string.split(/\s+/) : [];
+}
 
-Object.extend(Array.prototype, Enumerable);
+Array.from = $A;
 
-if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse;
+(function() {
+  var arrayProto = Array.prototype,
+      slice = arrayProto.slice,
+      _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available
 
-Object.extend(Array.prototype, {
-  _each: function(iterator) {
+  function each(iterator) {
     for (var i = 0, length = this.length; i &lt; length; i++)
       iterator(this[i]);
-  },
+  }
+  if (!_each) _each = each;
 
-  clear: function() {
+  function clear() {
     this.length = 0;
     return this;
-  },
+  }
 
-  first: function() {
+  function first() {
     return this[0];
-  },
+  }
 
-  last: function() {
+  function last() {
     return this[this.length - 1];
-  },
+  }
 
-  compact: function() {
+  function compact() {
     return this.select(function(value) {
       return value != null;
     });
-  },
+  }
 
-  flatten: function() {
+  function flatten() {
     return this.inject([], function(array, value) {
-      return array.concat(Object.isArray(value) ?
-        value.flatten() : [value]);
+      if (Object.isArray(value))
+        return array.concat(value.flatten());
+      array.push(value);
+      return array;
     });
-  },
+  }
 
-  without: function() {
-    var values = $A(arguments);
+  function without() {
+    var values = slice.call(arguments, 0);
     return this.select(function(value) {
       return !values.include(value);
     });
-  },
+  }
 
-  reverse: function(inline) {
+  function reverse(inline) {
     return (inline !== false ? this : this.toArray())._reverse();
-  },
+  }
 
-  reduce: function() {
+  function reduce() {
     return this.length &gt; 1 ? this : this[0];
-  },
+  }
 
-  uniq: function(sorted) {
+  function uniq(sorted) {
     return this.inject([], function(array, value, index) {
       if (0 == index || (sorted ? array.last() != value : !array.include(value)))
         array.push(value);
       return array;
     });
-  },
+  }
 
-  intersect: function(array) {
+  function intersect(array) {
     return this.uniq().findAll(function(item) {
       return array.detect(function(value) { return item === value });
     });
-  },
+  }
 
-  clone: function() {
-    return [].concat(this);
-  },
+  function clone() {
+    return slice.call(this, 0);
+  }
 
-  size: function() {
+  function size() {
     return this.length;
-  },
+  }
 
-  inspect: function() {
+  function inspect() {
     return '[' + this.map(Object.inspect).join(', ') + ']';
-  },
+  }
 
-  toJSON: function() {
+  function toJSON() {
     var results = [];
     this.each(function(object) {
       var value = Object.toJSON(object);
@@ -910,203 +1062,269 @@ Object.extend(Array.prototype, {
     });
     return '[' + results.join(', ') + ']';
   }
-});
-
-// use native browser JS 1.6 implementation if available
-if (Object.isFunction(Array.prototype.forEach))
-  Array.prototype._each = Array.prototype.forEach;
-
-if (!Array.prototype.indexOf) Array.prototype.indexOf = function(item, i) {
-  i || (i = 0);
-  var length = this.length;
-  if (i &lt; 0) i = length + i;
-  for (; i &lt; length; i++)
-    if (this[i] === item) return i;
-  return -1;
-};
-
-if (!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(item, i) {
-  i = isNaN(i) ? this.length : (i &lt; 0 ? this.length + i : i) + 1;
-  var n = this.slice(0, i).reverse().indexOf(item);
-  return (n &lt; 0) ? n : i - n - 1;
-};
 
-Array.prototype.toArray = Array.prototype.clone;
+  function indexOf(item, i) {
+    i || (i = 0);
+    var length = this.length;
+    if (i &lt; 0) i = length + i;
+    for (; i &lt; length; i++)
+      if (this[i] === item) return i;
+    return -1;
+  }
 
-function $w(string) {
-  if (!Object.isString(string)) return [];
-  string = string.strip();
-  return string ? string.split(/\s+/) : [];
-}
+  function lastIndexOf(item, i) {
+    i = isNaN(i) ? this.length : (i &lt; 0 ? this.length + i : i) + 1;
+    var n = this.slice(0, i).reverse().indexOf(item);
+    return (n &lt; 0) ? n : i - n - 1;
+  }
 
-if (Prototype.Browser.Opera){
-  Array.prototype.concat = function() {
-    var array = [];
-    for (var i = 0, length = this.length; i &lt; length; i++) array.push(this[i]);
+  function concat() {
+    var array = slice.call(this, 0), item;
     for (var i = 0, length = arguments.length; i &lt; length; i++) {
-      if (Object.isArray(arguments[i])) {
-        for (var j = 0, arrayLength = arguments[i].length; j &lt; arrayLength; j++)
-          array.push(arguments[i][j]);
+      item = arguments[i];
+      if (Object.isArray(item) &amp;&amp; !('callee' in item)) {
+        for (var j = 0, arrayLength = item.length; j &lt; arrayLength; j++)
+          array.push(item[j]);
       } else {
-        array.push(arguments[i]);
+        array.push(item);
       }
     }
     return array;
-  };
-}
-Object.extend(Number.prototype, {
-  toColorPart: function() {
-    return this.toPaddedString(2, 16);
-  },
+  }
 
-  succ: function() {
-    return this + 1;
-  },
+  Object.extend(arrayProto, Enumerable);
+
+  if (!arrayProto._reverse)
+    arrayProto._reverse = arrayProto.reverse;
+
+  Object.extend(arrayProto, {
+    _each:     _each,
+    clear:     clear,
+    first:     first,
+    last:      last,
+    compact:   compact,
+    flatten:   flatten,
+    without:   without,
+    reverse:   reverse,
+    reduce:    reduce,
+    uniq:      uniq,
+    intersect: intersect,
+    clone:     clone,
+    toArray:   clone,
+    size:      size,
+    inspect:   inspect,
+    toJSON:    toJSON
+  });
 
-  times: function(iterator) {
-    $R(0, this, true).each(iterator);
-    return this;
-  },
+  var CONCAT_ARGUMENTS_BUGGY = (function() {
+    return [].concat(arguments)[0][0] !== 1;
+  })(1,2)
 
-  toPaddedString: function(length, radix) {
-    var string = this.toString(radix || 10);
-    return '0'.times(length - string.length) + string;
-  },
+  if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
 
-  toJSON: function() {
-    return isFinite(this) ? this.toString() : 'null';
-  }
-});
-
-$w('abs round ceil floor').each(function(method){
-  Number.prototype[method] = Math[method].methodize();
-});
+  if (!arrayProto.indexOf) arrayProto.indexOf = indexOf;
+  if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf;
+})();
 function $H(object) {
   return new Hash(object);
 };
 
 var Hash = Class.create(Enumerable, (function() {
+  function initialize(object) {
+    this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
+  }
+
+  function _each(iterator) {
+    for (var key in this._object) {
+      var value = this._object[key], pair = [key, value];
+      pair.key = key;
+      pair.value = value;
+      iterator(pair);
+    }
+  }
+
+  function set(key, value) {
+    return this._object[key] = value;
+  }
+
+  function get(key) {
+    if (this._object[key] !== Object.prototype[key])
+      return this._object[key];
+  }
+
+  function unset(key) {
+    var value = this._object[key];
+    delete this._object[key];
+    return value;
+  }
+
+  function toObject() {
+    return Object.clone(this._object);
+  }
+
+  function keys() {
+    return this.pluck('key');
+  }
+
+  function values() {
+    return this.pluck('value');
+  }
+
+  function index(value) {
+    var match = this.detect(function(pair) {
+      return pair.value === value;
+    });
+    return match &amp;&amp; match.key;
+  }
+
+  function merge(object) {
+    return this.clone().update(object);
+  }
+
+  function update(object) {
+    return new Hash(object).inject(this, function(result, pair) {
+      result.set(pair.key, pair.value);
+      return result;
+    });
+  }
 
   function toQueryPair(key, value) {
     if (Object.isUndefined(value)) return key;
     return key + '=' + encodeURIComponent(String.interpret(value));
   }
 
-  return {
-    initialize: function(object) {
-      this._object = Object.isHash(object) ? object.toObject() : Object.clone(object);
-    },
+  function toQueryString() {
+    return this.inject([], function(results, pair) {
+      var key = encodeURIComponent(pair.key), values = pair.value;
 
-    _each: function(iterator) {
-      for (var key in this._object) {
-        var value = this._object[key], pair = [key, value];
-        pair.key = key;
-        pair.value = value;
-        iterator(pair);
-      }
-    },
-
-    set: function(key, value) {
-      return this._object[key] = value;
-    },
+      if (values &amp;&amp; typeof values == 'object') {
+        if (Object.isArray(values))
+          return results.concat(values.map(toQueryPair.curry(key)));
+      } else results.push(toQueryPair(key, values));
+      return results;
+    }).join('&amp;');
+  }
 
-    get: function(key) {
-      return this._object[key];
-    },
+  function inspect() {
+    return '#&lt;Hash:{' + this.map(function(pair) {
+      return pair.map(Object.inspect).join(': ');
+    }).join(', ') + '}&gt;';
+  }
 
-    unset: function(key) {
-      var value = this._object[key];
-      delete this._object[key];
-      return value;
-    },
+  function toJSON() {
+    return Object.toJSON(this.toObject());
+  }
 
-    toObject: function() {
-      return Object.clone(this._object);
-    },
+  function clone() {
+    return new Hash(this);
+  }
 
-    keys: function() {
-      return this.pluck('key');
-    },
+  return {
+    initialize:             initialize,
+    _each:                  _each,
+    set:                    set,
+    get:                    get,
+    unset:                  unset,
+    toObject:               toObject,
+    toTemplateReplacements: toObject,
+    keys:                   keys,
+    values:                 values,
+    index:                  index,
+    merge:                  merge,
+    update:                 update,
+    toQueryString:          toQueryString,
+    inspect:                inspect,
+    toJSON:                 toJSON,
+    clone:                  clone
+  };
+})());
 
-    values: function() {
-      return this.pluck('value');
-    },
+Hash.from = $H;
+Object.extend(Number.prototype, (function() {
+  function toColorPart() {
+    return this.toPaddedString(2, 16);
+  }
 
-    index: function(value) {
-      var match = this.detect(function(pair) {
-        return pair.value === value;
-      });
-      return match &amp;&amp; match.key;
-    },
+  function succ() {
+    return this + 1;
+  }
 
-    merge: function(object) {
-      return this.clone().update(object);
-    },
+  function times(iterator, context) {
+    $R(0, this, true).each(iterator, context);
+    return this;
+  }
 
-    update: function(object) {
-      return new Hash(object).inject(this, function(result, pair) {
-        result.set(pair.key, pair.value);
-        return result;
-      });
-    },
+  function toPaddedString(length, radix) {
+    var string = this.toString(radix || 10);
+    return '0'.times(length - string.length) + string;
+  }
 
-    toQueryString: function() {
-      return this.map(function(pair) {
-        var key = encodeURIComponent(pair.key), values = pair.value;
+  function toJSON() {
+    return isFinite(this) ? this.toString() : 'null';
+  }
 
-        if (values &amp;&amp; typeof values == 'object') {
-          if (Object.isArray(values))
-            return values.map(toQueryPair.curry(key)).join('&amp;');
-        }
-        return toQueryPair(key, values);
-      }).join('&amp;');
-    },
+  function abs() {
+    return Math.abs(this);
+  }
 
-    inspect: function() {
-      return '#&lt;Hash:{' + this.map(function(pair) {
-        return pair.map(Object.inspect).join(': ');
-      }).join(', ') + '}&gt;';
-    },
+  function round() {
+    return Math.round(this);
+  }
 
-    toJSON: function() {
-      return Object.toJSON(this.toObject());
-    },
+  function ceil() {
+    return Math.ceil(this);
+  }
 
-    clone: function() {
-      return new Hash(this);
-    }
+  function floor() {
+    return Math.floor(this);
   }
+
+  return {
+    toColorPart:    toColorPart,
+    succ:           succ,
+    times:          times,
+    toPaddedString: toPaddedString,
+    toJSON:         toJSON,
+    abs:            abs,
+    round:          round,
+    ceil:           ceil,
+    floor:          floor
+  };
 })());
 
-Hash.prototype.toTemplateReplacements = Hash.prototype.toObject;
-Hash.from = $H;
-var ObjectRange = Class.create(Enumerable, {
-  initialize: function(start, end, exclusive) {
+function $R(start, end, exclusive) {
+  return new ObjectRange(start, end, exclusive);
+}
+
+var ObjectRange = Class.create(Enumerable, (function() {
+  function initialize(start, end, exclusive) {
     this.start = start;
     this.end = end;
     this.exclusive = exclusive;
-  },
+  }
 
-  _each: function(iterator) {
+  function _each(iterator) {
     var value = this.start;
     while (this.include(value)) {
       iterator(value);
       value = value.succ();
     }
-  },
+  }
 
-  include: function(value) {
+  function include(value) {
     if (value &lt; this.start)
       return false;
     if (this.exclusive)
       return value &lt; this.end;
     return value &lt;= this.end;
   }
-});
 
-var $R = function(start, end, exclusive) {
-  return new ObjectRange(start, end, exclusive);
-};
+  return {
+    initialize: initialize,
+    _each:      _each,
+    include:    include
+  };
+})());
 
 var Ajax = {
   getTransport: function() {
@@ -1119,7 +1337,6 @@ var Ajax = {
 
   activeRequestCount: 0
 };
-
 Ajax.Responders = {
   responders: [],
 
@@ -1153,7 +1370,6 @@ Ajax.Responders.register({
   onCreate:   function() { Ajax.activeRequestCount++ },
   onComplete: function() { Ajax.activeRequestCount-- }
 });
-
 Ajax.Base = Class.create({
   initialize: function(options) {
     this.options = {
@@ -1175,7 +1391,6 @@ Ajax.Base = Class.create({
       this.options.parameters = this.options.parameters.toObject();
   }
 });
-
 Ajax.Request = Class.create(Ajax.Base, {
   _complete: false,
 
@@ -1191,7 +1406,6 @@ Ajax.Request = Class.create(Ajax.Base, {
     var params = Object.clone(this.options.parameters);
 
     if (!['get', 'post'].include(this.method)) {
-      // simulate other verbs over post
       params['_method'] = this.method;
       this.method = 'post';
     }
@@ -1199,7 +1413,6 @@ Ajax.Request = Class.create(Ajax.Base, {
     this.parameters = params;
 
     if (params = Object.toQueryString(params)) {
-      // when GET, append parameters to URL
       if (this.method == 'get')
         this.url += (this.url.include('?') ? '&amp;' : '?') + params;
       else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent))
@@ -1258,7 +1471,6 @@ Ajax.Request = Class.create(Ajax.Base, {
             headers['Connection'] = 'close';
     }
 
-    // user-defined headers
     if (typeof this.options.requestHeaders == 'object') {
       var extras = this.options.requestHeaders;
 
@@ -1312,7 +1524,6 @@ Ajax.Request = Class.create(Ajax.Base, {
     }
 
     if (state == 'Complete') {
-      // avoid memory leak in MSIE: clean up
       this.transport.onreadystatechange = Prototype.emptyFunction;
     }
   },
@@ -1348,7 +1559,6 @@ Ajax.Request = Class.create(Ajax.Base, {
 
 Ajax.Request.Events =
   ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
-
 Ajax.Response = Class.create({
   initialize: function(request){
     this.request = request;
@@ -1422,7 +1632,6 @@ Ajax.Response = Class.create({
     }
   }
 });
-
 Ajax.Updater = Class.create(Ajax.Request, {
   initialize: function($super, container, url, options) {
     this.container = {
@@ -1458,7 +1667,6 @@ Ajax.Updater = Class.create(Ajax.Request, {
     }
   }
 });
-
 Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
   initialize: function($super, container, url, options) {
     $super(options);
@@ -1499,6 +1707,9 @@ Ajax.PeriodicalUpdater = Class.create(Ajax.Base, {
     this.updater = new Ajax.Updater(this.container, this.url, this.options);
   }
 });
+
+
+
 function $(element) {
   if (arguments.length &gt; 1) {
     for (var i = 0, elements = [], length = arguments.length; i &lt; length; i++)
@@ -1526,7 +1737,6 @@ if (Prototype.BrowserFeatures.XPath) {
 if (!window.Node) var Node = { };
 
 if (!Node.ELEMENT_NODE) {
-  // DOM level 2 ECMAScript Language Binding
   Object.extend(Node, {
     ELEMENT_NODE: 1,
     ATTRIBUTE_NODE: 2,
@@ -1543,9 +1753,10 @@ if (!Node.ELEMENT_NODE) {
   });
 }
 
-(function() {
-  var element = this.Element;
-  this.Element = function(tagName, attributes) {
+
+(function(global) {
+  var element = global.Element;
+  global.Element = function(tagName, attributes) {
     attributes = attributes || { };
     tagName = tagName.toLowerCase();
     var cache = Element.cache;
@@ -1557,10 +1768,12 @@ if (!Node.ELEMENT_NODE) {
     if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
     return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
   };
-  Object.extend(this.Element, element || { });
-}).call(window);
+  Object.extend(global.Element, element || { });
+  if (element) global.Element.prototype = element.prototype;
+})(this);
 
 Element.cache = { };
+Element.idCounter = 1;
 
 Element.Methods = {
   visible: function(element) {
@@ -1573,13 +1786,16 @@ Element.Methods = {
     return element;
   },
 
+
   hide: function(element) {
-    $(element).style.display = 'none';
+    element = $(element);
+    element.style.display = 'none';
     return element;
   },
 
   show: function(element) {
-    $(element).style.display = '';
+    element = $(element);
+    element.style.display = '';
     return element;
   },
 
@@ -1686,7 +1902,7 @@ Element.Methods = {
   },
 
   descendants: function(element) {
-    return $(element).select(&quot;*&quot;);
+    return Element.select(element, &quot;*&quot;);
   },
 
   firstDescendant: function(element) {
@@ -1733,7 +1949,7 @@ Element.Methods = {
     element = $(element);
     if (arguments.length == 1) return element.firstDescendant();
     return Object.isNumber(expression) ? element.descendants()[expression] :
-      element.select(expression)[index || 0];
+      Element.select(element, expression)[index || 0];
   },
 
   previous: function(element, expression, index) {
@@ -1752,6 +1968,7 @@ Element.Methods = {
       Selector.findElement(nextSiblings, expression, index);
   },
 
+
   select: function() {
     var args = $A(arguments), element = $(args.shift());
     return Selector.findChildElements(element, args);
@@ -1764,26 +1981,49 @@ Element.Methods = {
 
   identify: function(element) {
     element = $(element);
-    var id = element.readAttribute('id'), self = arguments.callee;
+    var id = element.readAttribute('id');
     if (id) return id;
-    do { id = 'anonymous_element_' + self.counter++ } while ($(id));
+    do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
     element.writeAttribute('id', id);
     return id;
   },
 
-  readAttribute: function(element, name) {
-    element = $(element);
-    if (Prototype.Browser.IE) {
-      var t = Element._attributeTranslations.read;
-      if (t.values[name]) return t.values[name](element, name);
-      if (t.names[name]) name = t.names[name];
-      if (name.include(':')) {
-        return (!element.attributes || !element.attributes[name]) ? null :
-         element.attributes[name].value;
+  readAttribute: (function(){
+
+    var iframeGetAttributeThrowsError = (function(){
+      var el = document.createElement('iframe'),
+          isBuggy = false;
+
+      document.documentElement.appendChild(el);
+      try {
+        el.getAttribute('type', 2);
+      } catch(e) {
+        isBuggy = true;
+      }
+      document.documentElement.removeChild(el);
+      el = null;
+      return isBuggy;
+    })();
+
+    return function(element, name) {
+      element = $(element);
+      if (iframeGetAttributeThrowsError &amp;&amp;
+          name === 'type' &amp;&amp;
+          element.tagName.toUpperCase() == 'IFRAME') {
+        return element.getAttribute('type');
+      }
+      if (Prototype.Browser.IE) {
+        var t = Element._attributeTranslations.read;
+        if (t.values[name]) return t.values[name](element, name);
+        if (t.names[name]) name = t.names[name];
+        if (name.include(':')) {
+          return (!element.attributes || !element.attributes[name]) ? null :
+           element.attributes[name].value;
+        }
       }
+      return element.getAttribute(name);
     }
-    return element.getAttribute(name);
-  },
+  })(),
 
   writeAttribute: function(element, name, value) {
     element = $(element);
@@ -1844,7 +2084,6 @@ Element.Methods = {
       'removeClassName' : 'addClassName'](className);
   },
 
-  // removes whitespace-only text node children
   cleanWhitespace: function(element) {
     element = $(element);
     var node = element.firstChild;
@@ -1863,29 +2102,16 @@ Element.Methods = {
 
   descendantOf: function(element, ancestor) {
     element = $(element), ancestor = $(ancestor);
-    var originalAncestor = ancestor;
 
-    if (element.compareDocumentPosition) {
-      try {
-        return (element.compareDocumentPosition(ancestor) &amp; 8) === 8;        
-      } catch(e) {
-        if (!e.startsWith('Permission denied')) throw e;
-      }
-    }
+    if (element.compareDocumentPosition)
+      return (element.compareDocumentPosition(ancestor) &amp; 8) === 8;
 
-    if (element.sourceIndex &amp;&amp; !Prototype.Browser.Opera) {
-      var e = element.sourceIndex, a = ancestor.sourceIndex,
-       nextAncestor = ancestor.nextSibling;
-      if (!nextAncestor) {
-        do { ancestor = ancestor.parentNode; }
-        while (!(nextAncestor = ancestor.nextSibling) &amp;&amp; ancestor.parentNode);
-      }
-      if (nextAncestor &amp;&amp; nextAncestor.sourceIndex)
-       return (e &gt; a &amp;&amp; e &lt; nextAncestor.sourceIndex);
-    }
+    if (ancestor.contains)
+      return ancestor.contains(element) &amp;&amp; ancestor !== element;
 
     while (element = element.parentNode)
-      if (element == originalAncestor) return true;
+      if (element == ancestor) return true;
+
     return false;
   },
 
@@ -1900,7 +2126,7 @@ Element.Methods = {
     element = $(element);
     style = style == 'float' ? 'cssFloat' : style.camelize();
     var value = element.style[style];
-    if (!value) {
+    if (!value || value == 'auto') {
       var css = document.defaultView.getComputedStyle(element, null);
       value = css ? css[style] : null;
     }
@@ -1939,18 +2165,17 @@ Element.Methods = {
 
   getDimensions: function(element) {
     element = $(element);
-    var display = $(element).getStyle('display');
+    var display = element.getStyle('display');
     if (display != 'none' &amp;&amp; display != null) // Safari bug
       return {width: element.offsetWidth, height: element.offsetHeight};
 
-    // All *Width and *Height properties give 0 on elements with display none,
-    // so enable the element temporarily
     var els = element.style;
     var originalVisibility = els.visibility;
     var originalPosition = els.position;
     var originalDisplay = els.display;
     els.visibility = 'hidden';
-    els.position = 'absolute';
+    if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari
+      els.position = 'absolute';
     els.display = 'block';
     var originalWidth = element.clientWidth;
     var originalHeight = element.clientHeight;
@@ -1966,9 +2191,7 @@ Element.Methods = {
     if (pos == 'static' || !pos) {
       element._madePositioned = true;
       element.style.position = 'relative';
-      // Opera returns the offset relative to the positioning context, when an
-      // element is position relative but top and left have not been defined
-      if (window.opera) {
+      if (Prototype.Browser.Opera) {
         element.style.top = 0;
         element.style.left = 0;
       }
@@ -2023,7 +2246,7 @@ Element.Methods = {
       valueL += element.offsetLeft || 0;
       element = element.offsetParent;
       if (element) {
-        if (element.tagName == 'BODY') break;
+        if (element.tagName.toUpperCase() == 'BODY') break;
         var p = Element.getStyle(element, 'position');
         if (p !== 'static') break;
       }
@@ -2033,8 +2256,7 @@ Element.Methods = {
 
   absolutize: function(element) {
     element = $(element);
-    if (element.getStyle('position') == 'absolute') return;
-    // Position.prepare(); // To be done manually by Scripty when it needs it.
+    if (element.getStyle('position') == 'absolute') return element;
 
     var offsets = element.positionedOffset();
     var top     = offsets[1];
@@ -2057,8 +2279,7 @@ Element.Methods = {
 
   relativize: function(element) {
     element = $(element);
-    if (element.getStyle('position') == 'relative') return;
-    // Position.prepare(); // To be done manually by Scripty when it needs it.
+    if (element.getStyle('position') == 'relative') return element;
 
     element.style.position = 'relative';
     var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
@@ -2100,7 +2321,6 @@ Element.Methods = {
       valueT += element.offsetTop  || 0;
       valueL += element.offsetLeft || 0;
 
-      // Safari fix
       if (element.offsetParent == document.body &amp;&amp;
         Element.getStyle(element, 'position') == 'absolute') break;
 
@@ -2108,7 +2328,7 @@ Element.Methods = {
 
     element = forElement;
     do {
-      if (!Prototype.Browser.Opera || element.tagName == 'BODY') {
+      if (!Prototype.Browser.Opera || (element.tagName &amp;&amp; (element.tagName.toUpperCase() == 'BODY'))) {
         valueT -= element.scrollTop  || 0;
         valueL -= element.scrollLeft || 0;
       }
@@ -2127,28 +2347,22 @@ Element.Methods = {
       offsetLeft: 0
     }, arguments[2] || { });
 
-    // find page position of source
     source = $(source);
     var p = source.viewportOffset();
 
-    // find coordinate system to use
     element = $(element);
     var delta = [0, 0];
     var parent = null;
-    // delta [0,0] will do fine with position: fixed elements,
-    // position:absolute needs offsetParent deltas
     if (Element.getStyle(element, 'position') == 'absolute') {
       parent = element.getOffsetParent();
       delta = parent.viewportOffset();
     }
 
-    // correct by body offsets (fixes Safari)
     if (parent == document.body) {
       delta[0] -= document.body.offsetLeft;
       delta[1] -= document.body.offsetTop;
     }
 
-    // set position
     if (options.setLeft)   element.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
     if (options.setTop)    element.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
     if (options.setWidth)  element.style.width = source.offsetWidth + 'px';
@@ -2157,10 +2371,9 @@ Element.Methods = {
   }
 };
 
-Element.Methods.identify.counter = 1;
-
 Object.extend(Element.Methods, {
   getElementsBySelector: Element.Methods.select,
+
   childElements: Element.Methods.immediateDescendants
 });
 
@@ -2181,11 +2394,8 @@ if (Prototype.Browser.Opera) {
         case 'left': case 'top': case 'right': case 'bottom':
           if (proceed(element, 'position') === 'static') return null;
         case 'height': case 'width':
-          // returns '0px' for hidden elements; we want it to return null
           if (!Element.visible(element)) return null;
 
-          // returns the border-box dimensions rather than the content-box
-          // dimensions, so we subtract padding and borders from the value
           var dim = parseInt(proceed(element, style), 10);
 
           if (dim !== element['offset' + style.capitalize()])
@@ -2218,11 +2428,11 @@ if (Prototype.Browser.Opera) {
 }
 
 else if (Prototype.Browser.IE) {
-  // IE doesn't report offsets correctly for static elements, so we change them
-  // to &quot;relative&quot; to get the values, then change them back.
   Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
     function(proceed, element) {
       element = $(element);
+      try { element.offsetParent }
+      catch(e) { return $(document.body) }
       var position = element.getStyle('position');
       if (position !== 'static') return proceed(element);
       element.setStyle({ position: 'relative' });
@@ -2236,10 +2446,10 @@ else if (Prototype.Browser.IE) {
     Element.Methods[method] = Element.Methods[method].wrap(
       function(proceed, element) {
         element = $(element);
+        try { element.offsetParent }
+        catch(e) { return Element._returnOffset(0,0) }
         var position = element.getStyle('position');
         if (position !== 'static') return proceed(element);
-        // Trigger hasLayout on the offset parent so that IE6 reports
-        // accurate offsetTop and offsetLeft values for position: fixed.
         var offsetParent = element.getOffsetParent();
         if (offsetParent &amp;&amp; offsetParent.getStyle('position') === 'fixed')
           offsetParent.setStyle({ zoom: 1 });
@@ -2251,6 +2461,14 @@ else if (Prototype.Browser.IE) {
     );
   });
 
+  Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
+    function(proceed, element) {
+      try { element.offsetParent }
+      catch(e) { return Element._returnOffset(0,0) }
+      return proceed(element);
+    }
+  );
+
   Element.Methods.getStyle = function(element, style) {
     element = $(element);
     style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
@@ -2308,7 +2526,12 @@ else if (Prototype.Browser.IE) {
         },
         _getEv: function(element, attribute) {
           attribute = element.getAttribute(attribute);
-          return attribute ? attribute.toString().slice(23, -2) : null;
+
+          if (!attribute) return null;
+          attribute = attribute.toString();
+          attribute = attribute.split('{')[1];
+          attribute = attribute.split('}')[0];
+          return attribute.strip();
         },
         _flag: function(element, attribute) {
           return $(element).hasAttribute(attribute) ? attribute : null;
@@ -2342,7 +2565,7 @@ else if (Prototype.Browser.IE) {
   Element._attributeTranslations.has = {};
 
   $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
-      'encType maxLength readOnly longDesc').each(function(attr) {
+      'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
     Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
     Element._attributeTranslations.has[attr.toLowerCase()] = attr;
   });
@@ -2377,6 +2600,26 @@ else if (Prototype.Browser.IE) {
       onchange:    v._getEv
     });
   })(Element._attributeTranslations.read.values);
+
+  if (Prototype.BrowserFeatures.ElementExtensions) {
+    (function() {
+      function _descendants(element) {
+        var nodes = element.getElementsByTagName('*'), results = [];
+        for (var i = 0, node; node = nodes[i]; i++)
+          if (node.tagName !== &quot;!&quot;) // Filter out comment nodes.
+            results.push(node);
+        return results;
+      }
+
+      Element.Methods.down = function(element, expression, index) {
+        element = $(element);
+        if (arguments.length == 1) return element.firstDescendant();
+        return Object.isNumber(expression) ? _descendants(element)[expression] :
+          Element.select(element, expression)[index || 0];
+      }
+    })();
+  }
+
 }
 
 else if (Prototype.Browser.Gecko &amp;&amp; /rv:1\.8\.0/.test(navigator.userAgent)) {
@@ -2395,7 +2638,7 @@ else if (Prototype.Browser.WebKit) {
       (value &lt; 0.00001) ? 0 : value;
 
     if (value == 1)
-      if(element.tagName == 'IMG' &amp;&amp; element.width) {
+      if(element.tagName.toUpperCase() == 'IMG' &amp;&amp; element.width) {
         element.width++; element.width--;
       } else try {
         var n = document.createTextNode(' ');
@@ -2406,9 +2649,6 @@ else if (Prototype.Browser.WebKit) {
     return element;
   };
 
-  // Safari returns margins on body which is incorrect if the child is absolutely
-  // positioned.  For performance reasons, redefine Element#cumulativeOffset for
-  // KHTML/WebKit only.
   Element.Methods.cumulativeOffset = function(element) {
     var valueT = 0, valueL = 0;
     do {
@@ -2425,7 +2665,6 @@ else if (Prototype.Browser.WebKit) {
 }
 
 if (Prototype.Browser.IE || Prototype.Browser.Opera) {
-  // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements
   Element.Methods.update = function(element, content) {
     element = $(element);
 
@@ -2526,7 +2765,7 @@ Element.Methods.Simulated = {
   hasAttribute: function(element, attribute) {
     attribute = Element._attributeTranslations.has[attribute] || attribute;
     var node = $(element).getAttributeNode(attribute);
-    return node &amp;&amp; node.specified;
+    return !!(node &amp;&amp; node.specified);
   }
 };
 
@@ -2534,12 +2773,17 @@ Element.Methods.ByTag = { };
 
 Object.extend(Element, Element.Methods);
 
-if (!Prototype.BrowserFeatures.ElementExtensions &amp;&amp;
-    document.createElement('div').__proto__) {
-  window.HTMLElement = { };
-  window.HTMLElement.prototype = document.createElement('div').__proto__;
-  Prototype.BrowserFeatures.ElementExtensions = true;
-}
+(function(div) {
+
+  if (!Prototype.BrowserFeatures.ElementExtensions &amp;&amp; div['__proto__']) {
+    window.HTMLElement = { };
+    window.HTMLElement.prototype = div['__proto__'];
+    Prototype.BrowserFeatures.ElementExtensions = true;
+  }
+
+  div = null;
+
+})(document.createElement('div'))
 
 Element.extend = (function() {
   if (Prototype.BrowserFeatures.SpecificElementExtensions)
@@ -2548,13 +2792,12 @@ Element.extend = (function() {
   var Methods = { }, ByTag = Element.Methods.ByTag;
 
   var extend = Object.extend(function(element) {
-    if (!element || element._extendedByPrototype ||
+    if (!element || typeof element._extendedByPrototype != 'undefined' ||
         element.nodeType != 1 || element == window) return element;
 
     var methods = Object.clone(Methods),
-      tagName = element.tagName, property, value;
+      tagName = element.tagName.toUpperCase(), property, value;
 
-    // extend methods for specific tags
     if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
 
     for (property in methods) {
@@ -2568,7 +2811,6 @@ Element.extend = (function() {
 
   }, {
     refresh: function() {
-      // extend methods for all tags (Safari doesn't need this)
       if (!Prototype.BrowserFeatures.ElementExtensions) {
         Object.extend(Methods, Element.Methods);
         Object.extend(Methods, Element.Methods.Simulated);
@@ -2647,14 +2889,18 @@ Element.addMethods = function(methods) {
     klass = 'HTML' + tagName.capitalize() + 'Element';
     if (window[klass]) return window[klass];
 
-    window[klass] = { };
-    window[klass].prototype = document.createElement(tagName).__proto__;
-    return window[klass];
+    var element = document.createElement(tagName);
+    var proto = element['__proto__'] || element.constructor.prototype;
+    element = null;
+    return proto;
   }
 
+  var elementPrototype = window.HTMLElement ? HTMLElement.prototype :
+   Element.prototype;
+
   if (F.ElementExtensions) {
-    copy(Element.Methods, HTMLElement.prototype);
-    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+    copy(Element.Methods, elementPrototype);
+    copy(Element.Methods.Simulated, elementPrototype, true);
   }
 
   if (F.SpecificElementExtensions) {
@@ -2672,66 +2918,173 @@ Element.addMethods = function(methods) {
   Element.cache = { };
 };
 
-document.viewport = {
-  getDimensions: function() {
-    var dimensions = { };
-    var B = Prototype.Browser;
-    $w('width height').each(function(d) {
-      var D = d.capitalize();
-      dimensions[d] = (B.WebKit &amp;&amp; !document.evaluate) ? self['inner' + D] :
-        (B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
-    });
-    return dimensions;
-  },
 
-  getWidth: function() {
-    return this.getDimensions().width;
-  },
+document.viewport = {
 
-  getHeight: function() {
-    return this.getDimensions().height;
+  getDimensions: function() {
+    return { width: this.getWidth(), height: this.getHeight() };
   },
 
   getScrollOffsets: function() {
     return Element._returnOffset(
       window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft,
-      window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
+      window.pageYOffset || document.documentElement.scrollTop  || document.body.scrollTop);
+  }
+};
+
+(function(viewport) {
+  var B = Prototype.Browser, doc = document, element, property = {};
+
+  function getRootElement() {
+    if (B.WebKit &amp;&amp; !doc.evaluate)
+      return document;
+
+    if (B.Opera &amp;&amp; window.parseFloat(window.opera.version()) &lt; 9.5)
+      return document.body;
+
+    return document.documentElement;
+  }
+
+  function define(D) {
+    if (!element) element = getRootElement();
+
+    property[D] = 'client' + D;
+
+    viewport['get' + D] = function() { return element[property[D]] };
+    return viewport['get' + D]();
   }
+
+  viewport.getWidth  = define.curry('Width');
+
+  viewport.getHeight = define.curry('Height');
+})(document.viewport);
+
+
+Element.Storage = {
+  UID: 1
 };
-/* Portions of the Selector class are derived from Jack Slocum&#8217;s DomQuery,
+
+Element.addMethods({
+  getStorage: function(element) {
+    if (!(element = $(element))) return;
+
+    var uid;
+    if (element === window) {
+      uid = 0;
+    } else {
+      if (typeof element._prototypeUID === &quot;undefined&quot;)
+        element._prototypeUID = [Element.Storage.UID++];
+      uid = element._prototypeUID[0];
+    }
+
+    if (!Element.Storage[uid])
+      Element.Storage[uid] = $H();
+
+    return Element.Storage[uid];
+  },
+
+  store: function(element, key, value) {
+    if (!(element = $(element))) return;
+
+    if (arguments.length === 2) {
+      element.getStorage().update(key);
+    } else {
+      element.getStorage().set(key, value);
+    }
+
+    return element;
+  },
+
+  retrieve: function(element, key, defaultValue) {
+    if (!(element = $(element))) return;
+    var hash = Element.getStorage(element), value = hash.get(key);
+
+    if (Object.isUndefined(value)) {
+      hash.set(key, defaultValue);
+      value = defaultValue;
+    }
+
+    return value;
+  }
+});
+/* Portions of the Selector class are derived from Jack Slocum's DomQuery,
  * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
  * license.  Please see http://www.yui-ext.com/ for more information. */
 
 var Selector = Class.create({
   initialize: function(expression) {
     this.expression = expression.strip();
-    this.compileMatcher();
+
+    if (this.shouldUseSelectorsAPI()) {
+      this.mode = 'selectorsAPI';
+    } else if (this.shouldUseXPath()) {
+      this.mode = 'xpath';
+      this.compileXPathMatcher();
+    } else {
+      this.mode = &quot;normal&quot;;
+      this.compileMatcher();
+    }
+
   },
 
-  shouldUseXPath: function() {
-    if (!Prototype.BrowserFeatures.XPath) return false;
+  shouldUseXPath: (function() {
 
-    var e = this.expression;
+    var IS_DESCENDANT_SELECTOR_BUGGY = (function(){
+      var isBuggy = false;
+      if (document.evaluate &amp;&amp; window.XPathResult) {
+        var el = document.createElement('div');
+        el.innerHTML = '&lt;ul&gt;&lt;li&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;';
 
-    // Safari 3 chokes on :*-of-type and :empty
-    if (Prototype.Browser.WebKit &amp;&amp;
-     (e.include(&quot;-of-type&quot;) || e.include(&quot;:empty&quot;)))
-      return false;
+        var xpath = &quot;.//*[local-name()='ul' or local-name()='UL']&quot; +
+          &quot;//*[local-name()='li' or local-name()='LI']&quot;;
+
+        var result = document.evaluate(xpath, el, null,
+          XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+
+        isBuggy = (result.snapshotLength !== 2);
+        el = null;
+      }
+      return isBuggy;
+    })();
+
+    return function() {
+      if (!Prototype.BrowserFeatures.XPath) return false;
+
+      var e = this.expression;
+
+      if (Prototype.Browser.WebKit &amp;&amp;
+       (e.include(&quot;-of-type&quot;) || e.include(&quot;:empty&quot;)))
+        return false;
 
-    // XPath can't do namespaced attributes, nor can it read
-    // the &quot;checked&quot; property from DOM nodes
-    if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
+      if ((/(\[[\w-]*?:|:checked)/).test(e))
+        return false;
+
+      if (IS_DESCENDANT_SELECTOR_BUGGY) return false;
+
+      return true;
+    }
+
+  })(),
+
+  shouldUseSelectorsAPI: function() {
+    if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
+
+    if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false;
+
+    if (!Selector._div) Selector._div = new Element('div');
+
+    try {
+      Selector._div.querySelector(this.expression);
+    } catch(e) {
       return false;
+    }
 
     return true;
   },
 
   compileMatcher: function() {
-    if (this.shouldUseXPath())
-      return this.compileXPathMatcher();
-
     var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
-        c = Selector.criteria, le, p, m;
+        c = Selector.criteria, le, p, m, len = ps.length, name;
 
     if (Selector._cache[e]) {
       this.matcher = Selector._cache[e];
@@ -2743,11 +3096,12 @@ var Selector = Class.create({
 
     while (e &amp;&amp; le != e &amp;&amp; (/\S/).test(e)) {
       le = e;
-      for (var i in ps) {
-        p = ps[i];
+      for (var i = 0; i&lt;len; i++) {
+        p = ps[i].re;
+        name = ps[i].name;
         if (m = e.match(p)) {
-          this.matcher.push(Object.isFunction(c[i]) ? c[i](m) :
-    	      new Template(c[i]).evaluate(m));
+          this.matcher.push(Object.isFunction(c[name]) ? c[name](m) :
+            new Template(c[name]).evaluate(m));
           e = e.replace(m[0], '');
           break;
         }
@@ -2761,7 +3115,7 @@ var Selector = Class.create({
 
   compileXPathMatcher: function() {
     var e = this.expression, ps = Selector.patterns,
-        x = Selector.xpath, le, m;
+        x = Selector.xpath, le, m, len = ps.length, name;
 
     if (Selector._cache[e]) {
       this.xpath = Selector._cache[e]; return;
@@ -2770,10 +3124,11 @@ var Selector = Class.create({
     this.matcher = ['.//*'];
     while (e &amp;&amp; le != e &amp;&amp; (/\S/).test(e)) {
       le = e;
-      for (var i in ps) {
-        if (m = e.match(ps[i])) {
-          this.matcher.push(Object.isFunction(x[i]) ? x[i](m) :
-            new Template(x[i]).evaluate(m));
+      for (var i = 0; i&lt;len; i++) {
+        name = ps[i].name;
+        if (m = e.match(ps[i].re)) {
+          this.matcher.push(Object.isFunction(x[name]) ? x[name](m) :
+            new Template(x[name]).evaluate(m));
           e = e.replace(m[0], '');
           break;
         }
@@ -2786,29 +3141,43 @@ var Selector = Class.create({
 
   findElements: function(root) {
     root = root || document;
-    if (this.xpath) return document._getElementsByXPath(this.xpath, root);
-    return this.matcher(root);
+    var e = this.expression, results;
+
+    switch (this.mode) {
+      case 'selectorsAPI':
+        if (root !== document) {
+          var oldId = root.id, id = $(root).identify();
+          id = id.replace(/[\.:]/g, &quot;\\$0&quot;);
+          e = &quot;#&quot; + id + &quot; &quot; + e;
+        }
+
+        results = $A(root.querySelectorAll(e)).map(Element.extend);
+        root.id = oldId;
+
+        return results;
+      case 'xpath':
+        return document._getElementsByXPath(this.xpath, root);
+      default:
+       return this.matcher(root);
+    }
   },
 
   match: function(element) {
     this.tokens = [];
 
     var e = this.expression, ps = Selector.patterns, as = Selector.assertions;
-    var le, p, m;
+    var le, p, m, len = ps.length, name;
 
     while (e &amp;&amp; le !== e &amp;&amp; (/\S/).test(e)) {
       le = e;
-      for (var i in ps) {
-        p = ps[i];
+      for (var i = 0; i&lt;len; i++) {
+        p = ps[i].re;
+        name = ps[i].name;
         if (m = e.match(p)) {
-          // use the Selector.assertions methods unless the selector
-          // is too complex.
-          if (as[i]) {
-            this.tokens.push([i, Object.clone(m)]);
+          if (as[name]) {
+            this.tokens.push([name, Object.clone(m)]);
             e = e.replace(m[0], '');
           } else {
-            // reluctantly do a document-wide search
-            // and look for a match in the array
             return this.findElements(document).include(element);
           }
         }
@@ -2835,6 +3204,21 @@ var Selector = Class.create({
   }
 });
 
+if (Prototype.BrowserFeatures.SelectorsAPI &amp;&amp;
+ document.compatMode === 'BackCompat') {
+  Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){
+    var div = document.createElement('div'),
+     span = document.createElement('span');
+
+    div.id = &quot;prototype_test_id&quot;;
+    span.className = 'Test';
+    div.appendChild(span);
+    var isIgnored = (div.querySelector('#prototype_test_id .test') !== null);
+    div = span = null;
+    return isIgnored;
+  })();
+}
+
 Object.extend(Selector, {
   _cache: { },
 
@@ -2878,20 +3262,21 @@ Object.extend(Selector, {
       'first-child': '[not(preceding-sibling::*)]',
       'last-child':  '[not(following-sibling::*)]',
       'only-child':  '[not(preceding-sibling::* or following-sibling::*)]',
-      'empty':       &quot;[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]&quot;,
+      'empty':       &quot;[count(*) = 0 and (count(text()) = 0)]&quot;,
       'checked':     &quot;[@checked]&quot;,
-      'disabled':    &quot;[@disabled]&quot;,
-      'enabled':     &quot;[not(@disabled)]&quot;,
+      'disabled':    &quot;[(@disabled) and (@type!='hidden')]&quot;,
+      'enabled':     &quot;[not(@disabled) and (@type!='hidden')]&quot;,
       'not': function(m) {
         var e = m[6], p = Selector.patterns,
-            x = Selector.xpath, le, v;
+            x = Selector.xpath, le, v, len = p.length, name;
 
         var exclusion = [];
         while (e &amp;&amp; le != e &amp;&amp; (/\S/).test(e)) {
           le = e;
-          for (var i in p) {
-            if (m = e.match(p[i])) {
-              v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m);
+          for (var i = 0; i&lt;len; i++) {
+            name = p[i].name
+            if (m = e.match(p[i].re)) {
+              v = Object.isFunction(x[name]) ? x[name](m) : new Template(x[name]).evaluate(m);
               exclusion.push(&quot;(&quot; + v.substring(1, v.length - 1) + &quot;)&quot;);
               e = e.replace(m[0], '');
               break;
@@ -2959,25 +3344,20 @@ Object.extend(Selector, {
     laterSibling: 'c = &quot;laterSibling&quot;;'
   },
 
-  patterns: {
-    // combinators must be listed first
-    // (and descendant needs to be last combinator)
-    laterSibling: /^\s*~\s*/,
-    child:        /^\s*&gt;\s*/,
-    adjacent:     /^\s*\+\s*/,
-    descendant:   /^\s/,
+  patterns: [
+    { name: 'laterSibling', re: /^\s*~\s*/ },
+    { name: 'child',        re: /^\s*&gt;\s*/ },
+    { name: 'adjacent',     re: /^\s*\+\s*/ },
+    { name: 'descendant',   re: /^\s/ },
 
-    // selectors follow
-    tagName:      /^\s*(\*|[\w\-]+)(\b|$)?/,
-    id:           /^#([\w\-\*]+)(\b|$)/,
-    className:    /^\.([\w\-\*]+)(\b|$)/,
-    pseudo:
-/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~&gt;]))/,
-    attrPresence: /^\[([\w]+)\]/,
-    attr:         /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['&quot;])([^\4]*?)\4|([^'&quot;][^\]]*?)))?\]/
-  },
+    { name: 'tagName',      re: /^\s*(\*|[\w\-]+)(\b|$)?/ },
+    { name: 'id',           re: /^#([\w\-\*]+)(\b|$)/ },
+    { name: 'className',    re: /^\.([\w\-\*]+)(\b|$)/ },
+    { name: 'pseudo',       re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~&gt;]))/ },
+    { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ },
+    { name: 'attr',         re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['&quot;])([^\4]*?)\4|([^'&quot;][^\]]*?)))?\]/ }
+  ],
 
-  // for Selector.match and Element#match
   assertions: {
     tagName: function(element, matches) {
       return matches[1].toUpperCase() == element.tagName.toUpperCase();
@@ -3002,15 +3382,12 @@ Object.extend(Selector, {
   },
 
   handlers: {
-    // UTILITY FUNCTIONS
-    // joins two collections
     concat: function(a, b) {
       for (var i = 0, node; node = b[i]; i++)
         a.push(node);
       return a;
     },
 
-    // marks an array of nodes for counting
     mark: function(nodes) {
       var _true = Prototype.emptyFunction;
       for (var i = 0, node; node = nodes[i]; i++)
@@ -3024,9 +3401,6 @@ Object.extend(Selector, {
       return nodes;
     },
 
-    // mark each child node with its position (for nth calls)
-    // &quot;ofType&quot; flag indicates whether we're indexing for nth-of-type
-    // rather than nth-child
     index: function(parentNode, reverse, ofType) {
       parentNode._countedByPrototype = Prototype.emptyFunction;
       if (reverse) {
@@ -3040,19 +3414,17 @@ Object.extend(Selector, {
       }
     },
 
-    // filters out duplicates and extends all nodes
     unique: function(nodes) {
       if (nodes.length == 0) return nodes;
       var results = [], n;
       for (var i = 0, l = nodes.length; i &lt; l; i++)
-        if (!(n = nodes[i])._countedByPrototype) {
+        if (typeof (n = nodes[i])._countedByPrototype == 'undefined') {
           n._countedByPrototype = Prototype.emptyFunction;
           results.push(Element.extend(n));
         }
       return Selector.handlers.unmark(results);
     },
 
-    // COMBINATOR FUNCTIONS
     descendant: function(nodes) {
       var h = Selector.handlers;
       for (var i = 0, results = [], node; node = nodes[i]; i++)
@@ -3086,7 +3458,7 @@ Object.extend(Selector, {
 
     nextElementSibling: function(node) {
       while (node = node.nextSibling)
-	      if (node.nodeType == 1) return node;
+        if (node.nodeType == 1) return node;
       return null;
     },
 
@@ -3096,13 +3468,11 @@ Object.extend(Selector, {
       return null;
     },
 
-    // TOKEN FUNCTIONS
     tagName: function(nodes, root, tagName, combinator) {
       var uTagName = tagName.toUpperCase();
       var results = [], h = Selector.handlers;
       if (nodes) {
         if (combinator) {
-          // fastlane for ordinary descendant combinators
           if (combinator == &quot;descendant&quot;) {
             for (var i = 0, node; node = nodes[i]; i++)
               h.concat(results, node.getElementsByTagName(tagName));
@@ -3118,8 +3488,19 @@ Object.extend(Selector, {
 
     id: function(nodes, root, id, combinator) {
       var targetNode = $(id), h = Selector.handlers;
-      if (!targetNode) return [];
-      if (!nodes &amp;&amp; root == document) return [targetNode];
+
+      if (root == document) {
+        if (!targetNode) return [];
+        if (!nodes) return [targetNode];
+      } else {
+        if (!root.sourceIndex || root.sourceIndex &lt; 1) {
+          var nodes = root.getElementsByTagName('*');
+          for (var j = 0, node; node = nodes[j]; j++) {
+            if (node.id === id) return [node];
+          }
+        }
+      }
+
       if (nodes) {
         if (combinator) {
           if (combinator == 'child') {
@@ -3231,7 +3612,6 @@ Object.extend(Selector, {
       return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root);
     },
 
-    // handles the an+b logic
     getIndices: function(a, b, total) {
       if (a == 0) return b &gt; 0 ? [b] : [];
       return $R(1, total).inject([], function(memo, i) {
@@ -3240,7 +3620,6 @@ Object.extend(Selector, {
       });
     },
 
-    // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type
     nth: function(nodes, formula, root, reverse, ofType) {
       if (nodes.length == 0) return [];
       if (formula == 'even') formula = '2n+0';
@@ -3274,8 +3653,7 @@ Object.extend(Selector, {
 
     'empty': function(nodes, value, root) {
       for (var i = 0, results = [], node; node = nodes[i]; i++) {
-        // IE treats comments as element nodes
-        if (node.tagName == '!' || (node.firstChild &amp;&amp; !node.innerHTML.match(/^\s*$/))) continue;
+        if (node.tagName == '!' || node.firstChild) continue;
         results.push(node);
       }
       return results;
@@ -3293,7 +3671,8 @@ Object.extend(Selector, {
 
     'enabled': function(nodes, value, root) {
       for (var i = 0, results = [], node; node = nodes[i]; i++)
-        if (!node.disabled) results.push(node);
+        if (!node.disabled &amp;&amp; (!node.type || node.type !== 'hidden'))
+          results.push(node);
       return results;
     },
 
@@ -3313,11 +3692,12 @@ Object.extend(Selector, {
   operators: {
     '=':  function(nv, v) { return nv == v; },
     '!=': function(nv, v) { return nv != v; },
-    '^=': function(nv, v) { return nv.startsWith(v); },
-    '$=': function(nv, v) { return nv.endsWith(v); },
-    '*=': function(nv, v) { return nv.include(v); },
+    '^=': function(nv, v) { return nv == v || nv &amp;&amp; nv.startsWith(v); },
+    '$=': function(nv, v) { return nv == v || nv &amp;&amp; nv.endsWith(v); },
+    '*=': function(nv, v) { return nv == v || nv &amp;&amp; nv.include(v); },
     '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
-    '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
+    '|=': function(nv, v) { return ('-' + (nv || &quot;&quot;).toUpperCase() +
+     '-').include('-' + (v || &quot;&quot;).toUpperCase() + '-'); }
   },
 
   split: function(expression) {
@@ -3357,15 +3737,12 @@ Object.extend(Selector, {
 
 if (Prototype.Browser.IE) {
   Object.extend(Selector.handlers, {
-    // IE returns comment nodes on getElementsByTagName(&quot;*&quot;).
-    // Filter them out.
     concat: function(a, b) {
       for (var i = 0, node; node = b[i]; i++)
         if (node.tagName !== &quot;!&quot;) a.push(node);
       return a;
     },
 
-    // IE improperly serializes _countedByPrototype in (inner|outer)HTML.
     unmark: function(nodes) {
       for (var i = 0, node; node = nodes[i]; i++)
         node.removeAttribute('_countedByPrototype');
@@ -3377,9 +3754,11 @@ if (Prototype.Browser.IE) {
 function $$() {
   return Selector.findChildElements(document, $A(arguments));
 }
+
 var Form = {
   reset: function(form) {
-    $(form).reset();
+    form = $(form);
+    form.reset();
     return form;
   },
 
@@ -3391,10 +3770,9 @@ var Form = {
     var data = elements.inject({ }, function(result, element) {
       if (!element.disabled &amp;&amp; element.name) {
         key = element.name; value = $(element).getValue();
-        if (value != null &amp;&amp; (element.type != 'submit' || (!submitted &amp;&amp;
+        if (value != null &amp;&amp; element.type != 'file' &amp;&amp; (element.type != 'submit' || (!submitted &amp;&amp;
             submit !== false &amp;&amp; (!submit || key == submit) &amp;&amp; (submitted = true)))) {
           if (key in result) {
-            // a key is already present; construct an array of values
             if (!Object.isArray(result[key])) result[key] = [result[key]];
             result[key].push(value);
           }
@@ -3491,6 +3869,7 @@ Form.Methods = {
 
 /*--------------------------------------------------------------------------*/
 
+
 Form.Element = {
   focus: function(element) {
     $(element).focus();
@@ -3504,6 +3883,7 @@ Form.Element = {
 };
 
 Form.Element.Methods = {
+
   serialize: function(element) {
     element = $(element);
     if (!element.disabled &amp;&amp; element.name) {
@@ -3552,7 +3932,6 @@ Form.Element.Methods = {
 
   disable: function(element) {
     element = $(element);
-    element.blur();
     element.disabled = true;
     return element;
   },
@@ -3567,6 +3946,7 @@ Form.Element.Methods = {
 /*--------------------------------------------------------------------------*/
 
 var Field = Form.Element;
+
 var $F = Form.Element.Methods.getValue;
 
 /*--------------------------------------------------------------------------*/
@@ -3592,22 +3972,22 @@ Form.Element.Serializers = {
     else element.value = value;
   },
 
-  select: function(element, index) {
-    if (Object.isUndefined(index))
+  select: function(element, value) {
+    if (Object.isUndefined(value))
       return this[element.type == 'select-one' ?
         'selectOne' : 'selectMany'](element);
     else {
-      var opt, value, single = !Object.isArray(index);
+      var opt, currentValue, single = !Object.isArray(value);
       for (var i = 0, length = element.length; i &lt; length; i++) {
         opt = element.options[i];
-        value = this.optionValue(opt);
+        currentValue = this.optionValue(opt);
         if (single) {
-          if (value == index) {
+          if (currentValue == value) {
             opt.selected = true;
             return;
           }
         }
-        else opt.selected = index.include(value);
+        else opt.selected = value.include(currentValue);
       }
     }
   },
@@ -3629,13 +4009,13 @@ Form.Element.Serializers = {
   },
 
   optionValue: function(opt) {
-    // extend element because hasAttribute may not be native
     return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
   }
 };
 
 /*--------------------------------------------------------------------------*/
 
+
 Abstract.TimedObserver = Class.create(PeriodicalExecuter, {
   initialize: function($super, element, frequency, callback) {
     $super(callback, frequency);
@@ -3717,325 +4097,437 @@ Form.EventObserver = Class.create(Abstract.EventObserver, {
     return Form.serialize(this.element);
   }
 });
-if (!window.Event) var Event = { };
-
-Object.extend(Event, {
-  KEY_BACKSPACE: 8,
-  KEY_TAB:       9,
-  KEY_RETURN:   13,
-  KEY_ESC:      27,
-  KEY_LEFT:     37,
-  KEY_UP:       38,
-  KEY_RIGHT:    39,
-  KEY_DOWN:     40,
-  KEY_DELETE:   46,
-  KEY_HOME:     36,
-  KEY_END:      35,
-  KEY_PAGEUP:   33,
-  KEY_PAGEDOWN: 34,
-  KEY_INSERT:   45,
-
-  cache: { },
-
-  relatedTarget: function(event) {
-    var element;
-    switch(event.type) {
-      case 'mouseover': element = event.fromElement; break;
-      case 'mouseout':  element = event.toElement;   break;
-      default: return null;
-    }
-    return Element.extend(element);
-  }
-});
+(function() {
 
-Event.Methods = (function() {
-  var isButton;
+  var Event = {
+    KEY_BACKSPACE: 8,
+    KEY_TAB:       9,
+    KEY_RETURN:   13,
+    KEY_ESC:      27,
+    KEY_LEFT:     37,
+    KEY_UP:       38,
+    KEY_RIGHT:    39,
+    KEY_DOWN:     40,
+    KEY_DELETE:   46,
+    KEY_HOME:     36,
+    KEY_END:      35,
+    KEY_PAGEUP:   33,
+    KEY_PAGEDOWN: 34,
+    KEY_INSERT:   45,
+
+    cache: {}
+  };
 
+  var _isButton;
   if (Prototype.Browser.IE) {
     var buttonMap = { 0: 1, 1: 4, 2: 2 };
-    isButton = function(event, code) {
-      return event.button == buttonMap[code];
+    _isButton = function(event, code) {
+      return event.button === buttonMap[code];
     };
-
   } else if (Prototype.Browser.WebKit) {
-    isButton = function(event, code) {
+    _isButton = function(event, code) {
       switch (code) {
         case 0: return event.which == 1 &amp;&amp; !event.metaKey;
         case 1: return event.which == 1 &amp;&amp; event.metaKey;
         default: return false;
       }
     };
-
   } else {
-    isButton = function(event, code) {
+    _isButton = function(event, code) {
       return event.which ? (event.which === code + 1) : (event.button === code);
     };
   }
 
-  return {
-    isLeftClick:   function(event) { return isButton(event, 0) },
-    isMiddleClick: function(event) { return isButton(event, 1) },
-    isRightClick:  function(event) { return isButton(event, 2) },
+  function isLeftClick(event)   { return _isButton(event, 0) }
 
-    element: function(event) {
-      var node = Event.extend(event).target;
-      return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
-    },
+  function isMiddleClick(event) { return _isButton(event, 1) }
 
-    findElement: function(event, expression) {
-      var element = Event.element(event);
-      if (!expression) return element;
-      var elements = [element].concat(element.ancestors());
-      return Selector.findElement(elements, expression, 0);
-    },
+  function isRightClick(event)  { return _isButton(event, 2) }
 
-    pointer: function(event) {
-      return {
-        x: event.pageX || (event.clientX +
-          (document.documentElement.scrollLeft || document.body.scrollLeft)),
-        y: event.pageY || (event.clientY +
-          (document.documentElement.scrollTop || document.body.scrollTop))
-      };
-    },
+  function element(event) {
+    event = Event.extend(event);
 
-    pointerX: function(event) { return Event.pointer(event).x },
-    pointerY: function(event) { return Event.pointer(event).y },
+    var node = event.target, type = event.type,
+     currentTarget = event.currentTarget;
 
-    stop: function(event) {
-      Event.extend(event);
-      event.preventDefault();
-      event.stopPropagation();
-      event.stopped = true;
+    if (currentTarget &amp;&amp; currentTarget.tagName) {
+      if (type === 'load' || type === 'error' ||
+        (type === 'click' &amp;&amp; currentTarget.tagName.toLowerCase() === 'input'
+          &amp;&amp; currentTarget.type === 'radio'))
+            node = currentTarget;
     }
+
+    if (node.nodeType == Node.TEXT_NODE)
+      node = node.parentNode;
+
+    return Element.extend(node);
+  }
+
+  function findElement(event, expression) {
+    var element = Event.element(event);
+    if (!expression) return element;
+    var elements = [element].concat(element.ancestors());
+    return Selector.findElement(elements, expression, 0);
+  }
+
+  function pointer(event) {
+    return { x: pointerX(event), y: pointerY(event) };
+  }
+
+  function pointerX(event) {
+    var docElement = document.documentElement,
+     body = document.body || { scrollLeft: 0 };
+
+    return event.pageX || (event.clientX +
+      (docElement.scrollLeft || body.scrollLeft) -
+      (docElement.clientLeft || 0));
+  }
+
+  function pointerY(event) {
+    var docElement = document.documentElement,
+     body = document.body || { scrollTop: 0 };
+
+    return  event.pageY || (event.clientY +
+       (docElement.scrollTop || body.scrollTop) -
+       (docElement.clientTop || 0));
+  }
+
+
+  function stop(event) {
+    Event.extend(event);
+    event.preventDefault();
+    event.stopPropagation();
+
+    event.stopped = true;
+  }
+
+  Event.Methods = {
+    isLeftClick: isLeftClick,
+    isMiddleClick: isMiddleClick,
+    isRightClick: isRightClick,
+
+    element: element,
+    findElement: findElement,
+
+    pointer: pointer,
+    pointerX: pointerX,
+    pointerY: pointerY,
+
+    stop: stop
   };
-})();
 
-Event.extend = (function() {
+
   var methods = Object.keys(Event.Methods).inject({ }, function(m, name) {
     m[name] = Event.Methods[name].methodize();
     return m;
   });
 
   if (Prototype.Browser.IE) {
+    function _relatedTarget(event) {
+      var element;
+      switch (event.type) {
+        case 'mouseover': element = event.fromElement; break;
+        case 'mouseout':  element = event.toElement;   break;
+        default: return null;
+      }
+      return Element.extend(element);
+    }
+
     Object.extend(methods, {
       stopPropagation: function() { this.cancelBubble = true },
       preventDefault:  function() { this.returnValue = false },
-      inspect: function() { return &quot;[object Event]&quot; }
+      inspect: function() { return '[object Event]' }
     });
 
-    return function(event) {
+    Event.extend = function(event, element) {
       if (!event) return false;
       if (event._extendedByPrototype) return event;
 
       event._extendedByPrototype = Prototype.emptyFunction;
       var pointer = Event.pointer(event);
+
       Object.extend(event, {
-        target: event.srcElement,
-        relatedTarget: Event.relatedTarget(event),
+        target: event.srcElement || element,
+        relatedTarget: _relatedTarget(event),
         pageX:  pointer.x,
         pageY:  pointer.y
       });
+
       return Object.extend(event, methods);
     };
-
   } else {
-    Event.prototype = Event.prototype || document.createEvent(&quot;HTMLEvents&quot;).__proto__;
+    Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__;
     Object.extend(Event.prototype, methods);
-    return Prototype.K;
+    Event.extend = Prototype.K;
   }
-})();
 
-Object.extend(Event, (function() {
-  var cache = Event.cache;
+  function _createResponder(element, eventName, handler) {
+    var registry = Element.retrieve(element, 'prototype_event_registry');
 
-  function getEventID(element) {
-    if (element._prototypeEventID) return element._prototypeEventID[0];
-    arguments.callee.id = arguments.callee.id || 1;
-    return element._prototypeEventID = [++arguments.callee.id];
-  }
-
-  function getDOMEventName(eventName) {
-    if (eventName &amp;&amp; eventName.include(':')) return &quot;dataavailable&quot;;
-    return eventName;
-  }
+    if (Object.isUndefined(registry)) {
+      CACHE.push(element);
+      registry = Element.retrieve(element, 'prototype_event_registry', $H());
+    }
 
-  function getCacheForID(id) {
-    return cache[id] = cache[id] || { };
-  }
+    var respondersForEvent = registry.get(eventName);
+    if (Object.isUndefined()) {
+      respondersForEvent = [];
+      registry.set(eventName, respondersForEvent);
+    }
 
-  function getWrappersForEventName(id, eventName) {
-    var c = getCacheForID(id);
-    return c[eventName] = c[eventName] || [];
-  }
+    if (respondersForEvent.pluck('handler').include(handler)) return false;
 
-  function createWrapper(element, eventName, handler) {
-    var id = getEventID(element);
-    var c = getWrappersForEventName(id, eventName);
-    if (c.pluck(&quot;handler&quot;).include(handler)) return false;
+    var responder;
+    if (eventName.include(&quot;:&quot;)) {
+      responder = function(event) {
+        if (Object.isUndefined(event.eventName))
+          return false;
 
-    var wrapper = function(event) {
-      if (!Event || !Event.extend ||
-        (event.eventName &amp;&amp; event.eventName != eventName))
+        if (event.eventName !== eventName)
           return false;
 
-      Event.extend(event);
-      handler.call(element, event);
-    };
+        Event.extend(event, element);
+        handler.call(element, event);
+      };
+    } else {
+      if (!Prototype.Browser.IE &amp;&amp;
+       (eventName === &quot;mouseenter&quot; || eventName === &quot;mouseleave&quot;)) {
+        if (eventName === &quot;mouseenter&quot; || eventName === &quot;mouseleave&quot;) {
+          responder = function(event) {
+            Event.extend(event, element);
+
+            var parent = event.relatedTarget;
+            while (parent &amp;&amp; parent !== element) {
+              try { parent = parent.parentNode; }
+              catch(e) { parent = element; }
+            }
 
-    wrapper.handler = handler;
-    c.push(wrapper);
-    return wrapper;
-  }
+            if (parent === element) return;
 
-  function findWrapper(id, eventName, handler) {
-    var c = getWrappersForEventName(id, eventName);
-    return c.find(function(wrapper) { return wrapper.handler == handler });
-  }
+            handler.call(element, event);
+          };
+        }
+      } else {
+        responder = function(event) {
+          Event.extend(event, element);
+          handler.call(element, event);
+        };
+      }
+    }
 
-  function destroyWrapper(id, eventName, handler) {
-    var c = getCacheForID(id);
-    if (!c[eventName]) return false;
-    c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
+    responder.handler = handler;
+    respondersForEvent.push(responder);
+    return responder;
   }
 
-  function destroyCache() {
-    for (var id in cache)
-      for (var eventName in cache[id])
-        cache[id][eventName] = null;
+  function _destroyCache() {
+    for (var i = 0, length = CACHE.length; i &lt; length; i++) {
+      Event.stopObserving(CACHE[i]);
+      CACHE[i] = null;
+    }
   }
 
-  if (window.attachEvent) {
-    window.attachEvent(&quot;onunload&quot;, destroyCache);
+  var CACHE = [];
+
+  if (Prototype.Browser.IE)
+    window.attachEvent('onunload', _destroyCache);
+
+  if (Prototype.Browser.WebKit)
+    window.addEventListener('unload', Prototype.emptyFunction, false);
+
+
+  var _getDOMEventName = Prototype.K;
+
+  if (!Prototype.Browser.IE) {
+    _getDOMEventName = function(eventName) {
+      var translations = { mouseenter: &quot;mouseover&quot;, mouseleave: &quot;mouseout&quot; };
+      return eventName in translations ? translations[eventName] : eventName;
+    };
   }
 
-  return {
-    observe: function(element, eventName, handler) {
-      element = $(element);
-      var name = getDOMEventName(eventName);
+  function observe(element, eventName, handler) {
+    element = $(element);
 
-      var wrapper = createWrapper(element, eventName, handler);
-      if (!wrapper) return element;
+    var responder = _createResponder(element, eventName, handler);
 
-      if (element.addEventListener) {
-        element.addEventListener(name, wrapper, false);
-      } else {
-        element.attachEvent(&quot;on&quot; + name, wrapper);
+    if (!responder) return element;
+
+    if (eventName.include(':')) {
+      if (element.addEventListener)
+        element.addEventListener(&quot;dataavailable&quot;, responder, false);
+      else {
+        element.attachEvent(&quot;ondataavailable&quot;, responder);
+        element.attachEvent(&quot;onfilterchange&quot;, responder);
       }
+    } else {
+      var actualEventName = _getDOMEventName(eventName);
 
-      return element;
-    },
+      if (element.addEventListener)
+        element.addEventListener(actualEventName, responder, false);
+      else
+        element.attachEvent(&quot;on&quot; + actualEventName, responder);
+    }
 
-    stopObserving: function(element, eventName, handler) {
-      element = $(element);
-      var id = getEventID(element), name = getDOMEventName(eventName);
+    return element;
+  }
 
-      if (!handler &amp;&amp; eventName) {
-        getWrappersForEventName(id, eventName).each(function(wrapper) {
-          element.stopObserving(eventName, wrapper.handler);
-        });
-        return element;
+  function stopObserving(element, eventName, handler) {
+    element = $(element);
 
-      } else if (!eventName) {
-        Object.keys(getCacheForID(id)).each(function(eventName) {
-          element.stopObserving(eventName);
-        });
-        return element;
-      }
+    var registry = Element.retrieve(element, 'prototype_event_registry');
 
-      var wrapper = findWrapper(id, eventName, handler);
-      if (!wrapper) return element;
+    if (Object.isUndefined(registry)) return element;
 
-      if (element.removeEventListener) {
-        element.removeEventListener(name, wrapper, false);
-      } else {
-        element.detachEvent(&quot;on&quot; + name, wrapper);
-      }
+    if (eventName &amp;&amp; !handler) {
+      var responders = registry.get(eventName);
 
-      destroyWrapper(id, eventName, handler);
+      if (Object.isUndefined(responders)) return element;
 
+      responders.each( function(r) {
+        Element.stopObserving(element, eventName, r.handler);
+      });
       return element;
-    },
+    } else if (!eventName) {
+      registry.each( function(pair) {
+        var eventName = pair.key, responders = pair.value;
 
-    fire: function(element, eventName, memo) {
-      element = $(element);
-      if (element == document &amp;&amp; document.createEvent &amp;&amp; !element.dispatchEvent)
-        element = document.documentElement;
+        responders.each( function(r) {
+          Element.stopObserving(element, eventName, r.handler);
+        });
+      });
+      return element;
+    }
 
-      var event;
-      if (document.createEvent) {
-        event = document.createEvent(&quot;HTMLEvents&quot;);
-        event.initEvent(&quot;dataavailable&quot;, true, true);
-      } else {
-        event = document.createEventObject();
-        event.eventType = &quot;ondataavailable&quot;;
-      }
+    var responders = registry.get(eventName);
 
-      event.eventName = eventName;
-      event.memo = memo || { };
+    if (!responders) return;
 
-      if (document.createEvent) {
-        element.dispatchEvent(event);
-      } else {
-        element.fireEvent(event.eventType, event);
+    var responder = responders.find( function(r) { return r.handler === handler; });
+    if (!responder) return element;
+
+    var actualEventName = _getDOMEventName(eventName);
+
+    if (eventName.include(':')) {
+      if (element.removeEventListener)
+        element.removeEventListener(&quot;dataavailable&quot;, responder, false);
+      else {
+        element.detachEvent(&quot;ondataavailable&quot;, responder);
+        element.detachEvent(&quot;onfilterchange&quot;,  responder);
       }
+    } else {
+      if (element.removeEventListener)
+        element.removeEventListener(actualEventName, responder, false);
+      else
+        element.detachEvent('on' + actualEventName, responder);
+    }
 
-      return Event.extend(event);
+    registry.set(eventName, responders.without(responder));
+
+    return element;
+  }
+
+  function fire(element, eventName, memo, bubble) {
+    element = $(element);
+
+    if (Object.isUndefined(bubble))
+      bubble = true;
+
+    if (element == document &amp;&amp; document.createEvent &amp;&amp; !element.dispatchEvent)
+      element = document.documentElement;
+
+    var event;
+    if (document.createEvent) {
+      event = document.createEvent('HTMLEvents');
+      event.initEvent('dataavailable', true, true);
+    } else {
+      event = document.createEventObject();
+      event.eventType = bubble ? 'ondataavailable' : 'onfilterchange';
     }
-  };
-})());
 
-Object.extend(Event, Event.Methods);
+    event.eventName = eventName;
+    event.memo = memo || { };
 
-Element.addMethods({
-  fire:          Event.fire,
-  observe:       Event.observe,
-  stopObserving: Event.stopObserving
-});
+    if (document.createEvent)
+      element.dispatchEvent(event);
+    else
+      element.fireEvent(event.eventType, event);
 
-Object.extend(document, {
-  fire:          Element.Methods.fire.methodize(),
-  observe:       Element.Methods.observe.methodize(),
-  stopObserving: Element.Methods.stopObserving.methodize(),
-  loaded:        false
-});
+    return Event.extend(event);
+  }
+
+
+  Object.extend(Event, Event.Methods);
+
+  Object.extend(Event, {
+    fire:          fire,
+    observe:       observe,
+    stopObserving: stopObserving
+  });
+
+  Element.addMethods({
+    fire:          fire,
+
+    observe:       observe,
+
+    stopObserving: stopObserving
+  });
+
+  Object.extend(document, {
+    fire:          fire.methodize(),
+
+    observe:       observe.methodize(),
+
+    stopObserving: stopObserving.methodize(),
+
+    loaded:        false
+  });
+
+  if (window.Event) Object.extend(window.Event, Event);
+  else window.Event = Event;
+})();
 
 (function() {
   /* Support for the DOMContentLoaded event is based on work by Dan Webb,
-     Matthias Miller, Dean Edwards and John Resig. */
+     Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */
 
   var timer;
 
   function fireContentLoadedEvent() {
     if (document.loaded) return;
-    if (timer) window.clearInterval(timer);
-    document.fire(&quot;dom:loaded&quot;);
+    if (timer) window.clearTimeout(timer);
     document.loaded = true;
+    document.fire('dom:loaded');
   }
 
-  if (document.addEventListener) {
-    if (Prototype.Browser.WebKit) {
-      timer = window.setInterval(function() {
-        if (/loaded|complete/.test(document.readyState))
-          fireContentLoadedEvent();
-      }, 0);
-
-      Event.observe(window, &quot;load&quot;, fireContentLoadedEvent);
+  function checkReadyState() {
+    if (document.readyState === 'complete') {
+      document.stopObserving('readystatechange', checkReadyState);
+      fireContentLoadedEvent();
+    }
+  }
 
-    } else {
-      document.addEventListener(&quot;DOMContentLoaded&quot;,
-        fireContentLoadedEvent, false);
+  function pollDoScroll() {
+    try { document.documentElement.doScroll('left'); }
+    catch(e) {
+      timer = pollDoScroll.defer();
+      return;
     }
+    fireContentLoadedEvent();
+  }
 
+  if (document.addEventListener) {
+    document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false);
   } else {
-    document.write(&quot;&lt;script id=__onDOMContentLoaded defer src=//:&gt;&lt;\/script&gt;&quot;);
-    $(&quot;__onDOMContentLoaded&quot;).onreadystatechange = function() {
-      if (this.readyState == &quot;complete&quot;) {
-        this.onreadystatechange = null;
-        fireContentLoadedEvent();
-      }
-    };
+    document.observe('readystatechange', checkReadyState);
+    if (window == top)
+      timer = pollDoScroll.defer();
   }
+
+  Event.observe(window, 'load', fireContentLoadedEvent);
 })();
+
+Element.addMethods();
+
 /*------------------------------- DEPRECATED -------------------------------*/
 
 Hash.toQueryString = Object.toQueryString;
@@ -4064,16 +4556,9 @@ var Insertion = {
 
 var $continue = new Error('&quot;throw $continue&quot; is deprecated, use &quot;return&quot; instead');
 
-// This should be moved to script.aculo.us; notice the deprecated methods
-// further below, that map to the newer Element methods.
 var Position = {
-  // set to true if needed, warning: firefox performance problems
-  // NOT neeeded for page scrolling, only if draggable contained in
-  // scrollable elements
   includeScrollOffsets: false,
 
-  // must be called before calling withinIncludingScrolloffset, every time the
-  // page is scrolled
   prepare: function() {
     this.deltaX =  window.pageXOffset
                 || document.documentElement.scrollLeft
@@ -4085,7 +4570,6 @@ var Position = {
                 || 0;
   },
 
-  // caches x/y coordinate pair to use with overlap
   within: function(element, x, y) {
     if (this.includeScrollOffsets)
       return this.withinIncludingScrolloffsets(element, x, y);
@@ -4112,7 +4596,6 @@ var Position = {
             this.xcomp &lt;  this.offset[0] + element.offsetWidth);
   },
 
-  // within must be called directly before
   overlap: function(mode, element) {
     if (!mode) return 0;
     if (mode == 'vertical')
@@ -4123,7 +4606,6 @@ var Position = {
         element.offsetWidth;
   },
 
-  // Deprecation layer -- use newer Element methods now (1.5.2).
 
   cumulativeOffset: Element.Methods.cumulativeOffset,
 
@@ -4222,5 +4704,3 @@ Element.ClassNames.prototype = {
 Object.extend(Element.ClassNames.prototype, Enumerable);
 
 /*--------------------------------------------------------------------------*/
-
-Element.addMethods();
\ No newline at end of file</diff>
      <filename>templates/html/assets/javascripts/prototype.js</filename>
    </modified>
    <modified>
      <diff>@@ -4,22 +4,15 @@
 
 
 /* tag styles */
-h1, h2, h3, h4, h5, h6 {
-  font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif;
-  margin: 0;
-  padding: 0;
-}
-
 pre {
   padding: 0;
 }
 
 code {
   font-family: Monaco, &quot;Bitstream Vera Sans Mono&quot;, &quot;Lucida Console&quot;, monospace;
-  font-size: 13px;
+  font-size: 12px;
 }
 
-
 /* masthead */
 div#masthead {
   background: url(../images/header-stripe-small.png) repeat-x top left;
@@ -39,78 +32,456 @@ div#masthead {
     position: relative;
     left: 60px;
   }
+  
+/* footer */
+div#footer {
+  width: 960px;
+  margin: 0 auto;
+}
 
+  div.about {
+    margin-top: 20px;
+    padding-top: 20px;
+    width: 835px;
+    margin-left: 120px;
+    border-top: 1px solid #aaa;
+    color: #aaa;
+  }
 
+    div.about a,
+    div.about a:link {
+      color: #aaa;
+      text-decoration: underline;
+      border: 0;
+    }
+    
+  div.copyright,
+  div.credits {
+    width: 360px;
+    float: left;
+  }
+  
+    div.copyright .cc {
+      width: 115px;
+      margin-right: 5px;
+      text-align: center;
+      float: left;
+    }
+  
+    div.copyright .copyright-about {
+      width: 235px;
+      float: left;
+    }
+    
+  div.credits {
+    margin-left: 115px;
+  }
 
-#api {
-  width: 840px;
-  margin: 20px auto;
-  position: relative;
+
+.page-title span.type {
+  display: block;
+  text-transform: uppercase;
+  font-size: 14px;
+  color: #aaa;
+  letter-spacing: 0;
+}
+
+h2.page-title {
+  margin-top: 0;
+  line-height: 100%;
+}
+
+ul.breadcrumbs {
+  margin-left: 120px;
 }
 
-  #api h2 {
-    font-size: 22px;
-    padding-left: 65px;
+  ul.breadcrumbs li {
+    float: left;
+    list-style-type: none;
+    margin-right: 10px;
+    margin-left: 0;
   }
 
-    #api h3, h4, h5, h6 {
-      padding-left: 5px;
+
+
+ul.method-list {
+  margin-top: 0;
+}
+  
+  ul.method-list li {
+    margin-top: 0;
+    float: left;
+    margin-right: 5px;
+    margin-left: 0;
+    list-style-type: none;
+  }
+
+    ul.method-list li a,
+    ul.method-list li a:link {
+      text-decoration: none;
+      border: 0;
     }
 
+ul.method-details-list {
+  margin-top: 0;
+}
+  
+  ul.method-details-list li.method-description {
+    margin-top: 0;
+    margin-bottom: 3.0em;
+    margin-left: 0;
+    list-style-type: none;
+  }
 
-    #api .section {
-      overflow: hidden;
-      padding-left: 65px;
-      padding-bottom: 0;
-      margin: 5px 0 0;
+    ul.method-details-list li h4 {
+      margin: 0 0 0.6em;
+      line-height: 90%;
     }
   
-    #api .section h3 {
-      position: absolute;
-      left: -60px;
-      width: 110px;
-      text-align: right;
+    ul.method-details-list li pre {
+      margin-top: 0;
+    }
+      
+      ul.method-details-list li pre code {
+        font-size: 13px;
+      }
+    
+    ul.method-details-list li code {
+      font-size: 12px;
+    }
+
+    h4.inherited {
+      padding-top: 5px;
+      clear: left;
+      font-style: italic;
+      font-weight: bold;
       font-size: 14px;
-      color: #999;
     }
+    
+.method-description h4 .method-permalink a {
+  color: #aaa;
+  text-decoration: none;
+  border: 0;
+  font-size: 14px;
+}
+
+ul.argument-list {
+  margin-top: -5px;
+  list-style-type: disc;
+  margin-left: 20px;
+}
+
+  ul.argument-list li {
+    list-style-type: disc;
+    font-size: 90%;
+    margin-bottom: 0;
+  }
   
-    #api .section h4 {
-      font-size: 15px;
-      color: #444;
-      margin: 0.4em 0 0.3em;
+    ul.argument-list li code {
+      font-size: 11px;
     }
     
-  #api p, #api pre {
-    margin: 0 0 1.1em;
+ul.section-list {
+  margin-top: 0;
+} 
+
+   ul.section-list li {
+     margin-top: 0;
+     margin-left: 0;
+     list-style-type: none;
+   }
+   
+    ul.section-list li h4 {
+      margin-top: 0;
+    }
+
+    
+/* Aliases */
+
+.alias,
+.related-to {
+  font-style: italic;
+}
+
+  .alias code,
+  .related-to code {
+    font-style: normal;
   }
   
-  #api pre {
-    background-color: #000;
-    color: #fff;
+/* Section icons */
+
+.page-content .section .section-title h3 {
+  padding-right: 24px;
+  background-position: right 0;
+  background-repeat: no-repeat;
+}
+
+.section-constructor .section-title h3 {
+  background-image: url(../images/constructor.png);
+}
+
+.section-method-list .section-title h3 {
+  background-image: url(../images/method.png);
+}
+
+.section-klass_methods .section-title h3 {
+  background-image: url(../images/class_method.png);  
+}
+
+.section-klass_properties .section-title h3 {
+  background-image: url(../images/class_property.png);  
+}
+
+.section-instance_methods .section-title h3 {
+  background-image: url(../images/instance_method.png);
+}
+
+.section-instance_properties .section-title h3 {
+  background-image: url(../images/instance_property.png);  
+}
+
+.section-mixins .section-title h3 {
+  background-image: url(../images/mixin.png);
+}
+
+.section-classes .section-title h3 {
+  background-image: url(../images/class.png);
+}
+
+.section-namespaces .section-title h3 {
+  background-image: url(../images/namespace.png);
+}
+
+.section-sections .section-title h3 {
+  background-image: url(../images/section.png);
+}
+
+.section-utilities .section-title h3 {
+  background-image: url(../images/utility.png);
+}
+
+.section-description .section-title h3 {
+  background-image: url(../images/description.png);
+}
+
+.section-subclasses .section-title h3 {
+  background-image: url(../images/subclass.png);
+}
+
+.section-superclass .section-title h3 {
+  background-image: url(../images/superclass.png);
+}
+
+/* search box */
+
+.search-results {
+  position: absolute;
+  background-color: #fff;
+  height: 200px;
+  width: 233px;
+  overflow: auto;
+  overflow-y: scroll;
+  overflow-x: hidden;
+  margin: 7px -11px 0;
+  border: 1px solid #999;
+  top: 28px;
+}
+
+  * html .search-results {
+    left: 486px;
+    top: 30px;
+  }
+  
+    
+/* search result types */
+
+.menu-item a,
+.menu-item a:link {
+  display: block;
+  padding: 3px 10px 3px 28px;
+  background-position: 6px 50%;
+  background-repeat: no-repeat;
+  text-align: left;
+  text-decoration: none;
+  color: #333;
+  border-top: 1px solid #fff;
+  border-bottom: 1px solid #fff;
+  white-space: nowrap;
+  
+}
+
+  .menu-item a:hover,
+  .menu-item a.highlighted,
+  #menu .highlighted a {
+    border-top: 1px solid #69f;
+    border-bottom: 1px solid #69f;
+    background-color: #f0f0ff;      
+  }
+
+
+.menu-item a.section {
+  font-weight: bold;
+  background-image: url(../images/section.png);
+}
+
+.menu-item a.class_method,
+.menu-item a.instance_method {
+  background-image: url(../images/method.png);  
+}
+
+.menu-item a.class {
+  background-image: url(../images/class.png);  
+}
+
+.menu-item a.constructor {
+  background-image: url(../images/constructor.png);  
+}
+
+.menu-item a.class_property {
+  background-image: url(../images/class_property.png);  
+}
+
+.menu-item a.instance_property {
+  background-image: url(../images/instance_property.png);  
+}
+
+.menu-item a.namespace {
+  background-image: url(../images/namespace.png);  
+}
+
+.menu-item a.utility {
+  background-image: url(../images/utility.png);    
+}
+
+
+/* halo around selected method */
+
+.highlighter {
+  border: 3px solid #69f;
+  z-index: -1;
+  -webkit-border-radius: 15px;
+  -moz-border-radius: 15px;
+  border-radius: 15px;
+}
+
+/* MENU */
+ 
+div#menu {
+  width: 960px;
+  margin: 0 auto;
+  position: relative;
+}
+
+  #menu .api-box h2 a,
+  #menu .search-box {
+    width: 213px;
+    height: 25px;
+    line-height: 25px;
     padding: 5px 10px;
+    margin-right: 5px;
+    text-align: center;
+    float: right;
+  }
+  
+    * html #menu .api-box h2 a,
+    * html #menu .search-box {
+      height: 30px;
+      line-height: 30px;
+    }
+  
+  #menu .api-box {
   }
   
-  #api pre.syntax {
-    background-color: #CEE8C3;
-    color: #000;
-    padding: 3px 5px;
+    #menu .api-box h2 a {
+      font-size: 14px;
+      font-weight: normal;
+      font-family: Verdana, sans-serif;
+      display: block;
+      background-color: #cde0fb;
+      border: 1px solid #669;
+      border-top: 0;
+      text-decoration: none;
+      color: #222;
+    }
+    
+    #menu .api-box .menu-items {
+      position: absolute;
+      background-color: #fff;
+      height: 200px;
+      width: 233px;
+      overflow: auto;
+      overflow-y: scroll;
+      overflow-x: hidden;
+      top: 35px;
+      border: 1px solid #999;
+      right: 5px;
+    }
+    
+      * html #menu .api-box .menu-items {
+        right: 10px;
+        top: 37px;
+      }
+    
+      #menu .api-box ul,
+      #menu .api-box li {
+        margin: 0;
+        padding: 0;
+      }
+    
+      #menu .api-box .menu-item a {
+      }
+  
+  #menu .search-box {
+    background-color: #cee8c3;
+    border: 1px solid #696;
+    border-top: 0;
   }
   
-#api .section p.purpose {
-  background-color: #CDE0FB;
-  padding: 3px 5px;
+    #menu .search-box input {
+      width: 150px;
+      padding: 3px 10px;
+      margin-top: 2px;
+      border: 1px solid #999;
+      border-radius: 10px;
+      -webkit-border-radius: 10px;
+      -moz-border-radius: 10px;
+    }
+    
+#menu #search.ghosted {
+  color: #aaa;
+  text-align: left;
+}
+    
+
+/* notes */
+
+p.note,
+p.alias,
+p.related-to {
+  font-size: 11px;
+  line-height: 14px;
+  padding: 5px 5px 5px 60px;
+  background-repeat: no-repeat;
+  background-position: 20px 50%;
+  border: 1px solid #000;
 }
 
-#api .section p {
-  padding: 0 5px;
+p.note {
+  background-color: #f0f0f4;
+  background-image: url(../images/information.png);
+  border-color: #69c;
 }
 
-#api ul, #api ol {
-  padding-left: 5px;
-  margin: 10px 0;
+p.alias {
+  background-color: #fff6de;
+  background-image: url(../images/alias.png);
+  border-color: #cc9;
 }
 
-#api ul, #api ul li {
-  list-style-type: disc;
+p.related-to {
+  background-color: #f4f0f4;
+  background-image: url(../images/related_to.png);
+  border-color: #c9c;
 }
 
+</diff>
      <filename>templates/html/assets/stylesheets/api.css</filename>
    </modified>
    <modified>
      <diff>@@ -5,7 +5,7 @@ body.grid {
 
 body.grid div#page {
   overflow: hidden;
-  background: url(http://prototype.conio.net/new/images/grid-55-5.png);
+  background: url(../images/grid.png);
 }
 
 body.grid div#page * {</diff>
      <filename>templates/html/assets/stylesheets/grid.css</filename>
    </modified>
    <modified>
      <diff>@@ -1,75 +1,3 @@
-body {
-  background: #fff;
-  margin: 0;
-  padding: 0;
-  color: #333;
-}
-
-ul, li, p, h1, h2, h3, h4 {
-  margin: 0;
-  padding: 0;
-  font-family: Verdana, sans-serif;
-  font-size: 13px;
-  line-height: 150%;
-}
-
-li {
-  list-style-type: none;
-}
-
-
-/* Link bar */
-
-div#links {
-  margin: 0 auto;
-  width: 835px;
-  padding: 16px 0;
-  height: 16px;
-  overflow: hidden;
-}
-
-div#links_wrapper {
-  background: #fff;
-}
-
-div#links li {
-  display: inline;
-}
-
-div#links li a {
-  color: #666;
-}
-
-div#links li.selected a {
-  color: #000;
-  font-weight: bold;
-  text-decoration: none;
-}
-
-ul#internal_links {
-  float: left;
-}
-
-ul#internal_links li {
-  margin-right: 25px;
-}
-
-ul#external_links {
-  float: right;
-}
-
-ul#external_links li {
-  margin-left: 25px;
-  padding-left: 21px;
-}
-
-li#scripty_link {
-  background: url(http://prototype.conio.net/new/images/link-logo-scripty.png) no-repeat center left;
-}
-
-li#rails_link {
-  background: url(http://prototype.conio.net/new/images/link-logo-rails.png) no-repeat center left;
-}
 
 
 /* Masthead */</diff>
      <filename>templates/html/assets/stylesheets/screen.css</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,24 @@
 &lt;% @title = &quot;Home&quot; %&gt;
 
-&lt;h2&gt;Prototype API&lt;/h2&gt;
+&lt;div class=&quot;page-introduction&quot;&gt;
+  &lt;%= @index_page_content %&gt;
+&lt;/div&gt; &lt;!-- .section --&gt;
 
-&lt;div class=&quot;section&quot;&gt;
-  &lt;p&gt;Welcome to the Prototype API Documentation.&lt;/p&gt;
-&lt;/div&gt; &lt;!-- .section --&gt;
\ No newline at end of file
+&lt;div class=&quot;section section-sections&quot;&gt;
+  &lt;div class=&quot;section-title&quot;&gt;
+    &lt;h3&gt;Sections&lt;/h3&gt;
+  &lt;/div&gt; &lt;!-- .section-title --&gt;
+  
+  &lt;div class=&quot;section-content&quot;&gt;
+    &lt;ul class=&quot;section-list&quot;&gt;
+      &lt;% @root.sections.each do |section| %&gt;
+      &lt;li&gt;
+        &lt;h4&gt;
+          &lt;a href=&quot;&lt;%= path_to_section(section) %&gt;&quot;&gt;&lt;%= section.name %&gt;&lt;/a&gt;
+        &lt;/h4&gt;
+        &lt;p&gt;&lt;%= htmlize(section.short_description) %&gt;&lt;/p&gt;
+      &lt;/li&gt;      
+      &lt;% end %&gt;
+    &lt;/ul&gt;
+  &lt;/div&gt; &lt;!-- .section-content --&gt;
+&lt;/div&gt; &lt;!-- .section clearfix --&gt;
\ No newline at end of file</diff>
      <filename>templates/html/index.erb</filename>
    </modified>
    <modified>
      <diff>@@ -9,71 +9,23 @@
 	  &lt;%= javascript_include_tag &quot;application&quot;, &quot;code_highlighter&quot; %&gt;
 
 	  &lt;%= javascript_include_tag &quot;item_index&quot; %&gt;
+	  	  
+	  &lt;%= stylesheet_link_tag &quot;core&quot;, &quot;api&quot; %&gt;
 	  
-	  
-	  &lt;%= stylesheet_link_tag &quot;screen&quot;, &quot;grid&quot;, &quot;highlighter&quot;, &quot;main&quot; %&gt;
-	  
-	  &lt;script type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;
-	    function menuButtonMouseOver(event) {
-	      var menuButton = $('api_menu_button');
-	      var target = event.element();
-	      if (target === menuButton || target.descendantOf(menuButton)) {
-	        $('api_menu').show();
-	        $('search').focus();
-	      }
-	    }
-	    
-	    function menuButtonMouseOut(event) {
-	      var menuButton = $('api_menu_button');
-	      var menu = $('api_menu');
-	      var target = event.element(), related = event.relatedTarget;
-	      
-	      if (related === menu || related.descendantOf(menu)) return;
-	      menu.hide();
-	    }
-	    
-	    function menuMouseOut(event) {
-	      var menu = $('api_menu'), related = event.relatedTarget;
-	      if (related &amp;&amp; !related.descendantOf(menu)) {
-	        arguments.callee.timer = Element.hide.delay(0.5, menu);
-	      } else {
-	        window.clearTimeout(arguments.callee.timer)
-	      }
-	    }
-	    
-	    document.observe('dom:loaded', function() {
-   	    $('api_menu_button').observe('mouseover', menuButtonMouseOver);
-   	    $('api_menu_button').observe('mouseout',  menuButtonMouseOut);
-   	    
-   	    $('api_menu').observe('mouseout', menuMouseOut);
-	    });
-	  &lt;/script&gt;
-	  
-	  &lt;script type=&quot;text/javascript&quot; charset=&quot;utf-8&quot;&gt;PDoc.pathPrefix = '&lt;%= path_prefix %&gt;';&lt;/script&gt;
+	  &lt;script type=&quot;text/javascript&quot;&gt;PDoc.pathPrefix = '&lt;%= path_prefix %&gt;';&lt;/script&gt;
   &lt;/head&gt;
   &lt;body class=&quot;&quot;&gt;
     &lt;div id=&quot;page&quot;&gt;
-      &lt;div id=&quot;links_wrapper&quot;&gt;
-        &lt;div id=&quot;links&quot;&gt;
-          &lt;ul id=&quot;internal_links&quot;&gt;
-            &lt;li class=&quot;selected&quot;&gt;&lt;a href=&quot;#&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
-            &lt;li&gt;&lt;a href=&quot;#&quot;&gt;Documentation&lt;/a&gt;&lt;/li&gt;
-            &lt;li&gt;&lt;a href=&quot;#&quot;&gt;Weblog&lt;/a&gt;&lt;/li&gt;
-          &lt;/ul&gt;
-          &lt;ul id=&quot;external_links&quot;&gt;
-            &lt;li id=&quot;scripty_link&quot;&gt;&lt;a href=&quot;http://script.aculo.us/&quot;&gt;script.aculo.us&lt;/a&gt;&lt;/li&gt;
-            &lt;li id=&quot;rails_link&quot;&gt;&lt;a href=&quot;http://www.rubyonrails.org/&quot;&gt;Ruby on Rails&lt;/a&gt;&lt;/li&gt;
-          &lt;/ul&gt;
-        &lt;/div&gt; &lt;!-- #links --&gt;
-      &lt;/div&gt; &lt;!-- #links_wrapper --&gt;
       
       &lt;div id=&quot;masthead&quot;&gt;
         &lt;div id=&quot;masthead_content&quot;&gt;
-          &lt;h1 onclick=&quot;with (document.body) className = className ? '' : 'grid'&quot; id=&quot;logo&quot;&gt;&lt;span&gt;Prototype JavaScript framework&lt;/span&gt;&lt;/h1&gt;
+          &lt;a href=&quot;http://prototypejs.org&quot;&gt;
+            &lt;h1 id=&quot;logo&quot;&gt;&lt;span class=&quot;replaced&quot;&gt;Prototype JavaScript framework&lt;/span&gt;&lt;/h1&gt;
+          &lt;/a&gt;
         &lt;/div&gt; &lt;!-- #masthead_content --&gt;
       &lt;/div&gt; &lt;!-- #masthead --&gt;
       
-      &lt;div id=&quot;menu&quot;&gt;
+      &lt;div id=&quot;menu&quot; class=&quot;clearfix&quot;&gt;
         &lt;div class=&quot;api-box&quot;&gt;
           &lt;h2&gt;&lt;a href=&quot;#&quot; id=&quot;api_menu_button&quot;&gt;Menu &amp;darr;&lt;/a&gt;&lt;/h2&gt;
           
@@ -86,18 +38,40 @@
 
         &lt;div class=&quot;search-box&quot;&gt;
   			  &lt;form&gt;
-    			  &lt;label&gt;Search &lt;input type=&quot;text&quot; id=&quot;search&quot; size=&quot;20&quot; /&gt;&lt;/label&gt;
+    			  &lt;label&gt;&lt;span class=&quot;hidden&quot;&gt;Search &lt;/span&gt;&lt;input type=&quot;text&quot; id=&quot;search&quot; size=&quot;20&quot; /&gt;&lt;/label&gt;
   			  &lt;/form&gt;
   			  &lt;ul id=&quot;search_results&quot; class=&quot;search-results menu-items&quot; style=&quot;display:none&quot;&gt;&lt;/ul&gt;
         &lt;/div&gt; &lt;!-- .search-box --&gt;
 
       &lt;/div&gt; &lt;!-- #menu --&gt;
       
-      &lt;div id=&quot;main&quot;&gt;
+      &lt;div id=&quot;main&quot; class=&quot;page-content&quot;&gt;
         
         &lt;%= @content_for_layout %&gt;
 
       &lt;/div&gt; &lt;!-- #main --&gt;
+      
+      &lt;div id=&quot;footer&quot;&gt;
+        
+        &lt;div class=&quot;about clearfix&quot;&gt;
+          &lt;div class=&quot;copyright clearfix&quot;&gt;
+            &lt;div class=&quot;cc&quot;&gt;
+              &lt;a rel=&quot;license&quot; href=&quot;http://creativecommons.org/licenses/by-sa/3.0/&quot;&gt;&lt;img alt=&quot;Creative Commons License&quot; style=&quot;border-width:0&quot; src=&quot;http://creativecommons.org/images/public/somerights20.png&quot; /&gt;&lt;/a&gt;
+            &lt;/div&gt; &lt;!-- .cc --&gt;
+            &lt;div class=&quot;copyright-about&quot;&gt;
+              This work is licensed under a &lt;a rel=&quot;license&quot; href=&quot;http://creativecommons.org/licenses/by-sa/3.0/&quot;&gt;Creative Commons Attribution-Share Alike 3.0 Unported License&lt;/a&gt;.
+            &lt;/div&gt; &lt;!-- .copyright-about --&gt;
+          &lt;/div&gt; &lt;!-- .copyright --&gt;
+          
+          &lt;div class=&quot;credits&quot;&gt;
+            &lt;p&gt;Generated by &lt;a href=&quot;http://pdoc.org&quot;&gt;PDoc&lt;/a&gt;. Uses &lt;a href=&quot;http://famfamfam.com/lab/icons/silk/&quot; title=&quot;famfamfam.com: Silk Icons&quot;&gt;Silk Icons&lt;/a&gt;.&lt;/p&gt;
+            
+          &lt;/div&gt; &lt;!-- .credits --&gt;
+          
+        &lt;/div&gt; &lt;!-- .about --&gt;
+        
+        
+      &lt;/div&gt; &lt;!-- #footer --&gt;
             
     &lt;/div&gt; &lt;!-- #page --&gt;
 </diff>
      <filename>templates/html/layout.erb</filename>
    </modified>
    <modified>
      <diff>@@ -1,97 +1,153 @@
 &lt;% d = @doc_instance %&gt;
 
-&lt;% @title = &quot;#{d.full_name} (#{d.type})&quot; %&gt;
+&lt;% @title = &quot;#{d.full_name} #{d.type}&quot; %&gt;
 
-&lt;h2 class=&quot;&lt;%= class_names_for(d) %&gt;&quot;&gt;
-  &lt;span&gt;&lt;%= d.type %&gt;&lt;/span&gt;
-  &lt;%= d.full_name %&gt;
+&lt;%= include &quot;partials/breadcrumbs&quot;, :object =&gt; d %&gt;
+
+&lt;h2 class=&quot;page-title &lt;%= class_names_for(d) %&gt;&quot;&gt;
+  &lt;span class=&quot;type&quot;&gt;&lt;%= d.type %&gt; &lt;/span&gt;&lt;%= d.full_name %&gt;
 &lt;/h2&gt;
 
+&lt;% # Does it have a description? %&gt;
+
+&lt;% if d.description &amp;&amp; !d.description.empty? %&gt;
+&lt;div class=&quot;section section-description&quot;&gt;
+  
+  &lt;div class=&quot;section-title&quot;&gt;
+    &lt;h3&gt;Description&lt;/h3&gt;
+  &lt;/div&gt; &lt;!-- .section-title --&gt;
+  
+  &lt;div class=&quot;section-content&quot;&gt;
+    &lt;%= htmlize(d.description) %&gt;
+  &lt;/div&gt; &lt;!-- .section-content --&gt;
+  
+&lt;/div&gt; &lt;!--.section --&gt;
+&lt;% end %&gt;
 
 &lt;% # Is it a CLASS?  %&gt;
-&lt;% if @doc_instance.is_a?(Documentation::Klass) %&gt;
-
-	&lt;% if @doc_instance.superklass %&gt;
-	&lt;div class=&quot;section section-superclass&quot;&gt;
-	  &lt;h3&gt;Superclass&lt;/h3&gt;
-	  &lt;p&gt;&lt;%= auto_link(d.superklass, false) %&gt;&lt;/p&gt;
-	&lt;/div&gt; &lt;!-- .section --&gt;		
-	&lt;% end %&gt;
-
-	&lt;% unless @doc_instance.subklasses.empty? %&gt;
-	&lt;div class=&quot;section section-subclasses&quot;&gt;
-	  &lt;h3&gt;Subclasses&lt;/h3&gt;
-	  &lt;p&gt;&lt;%= d.subklasses.map { |s| auto_link(s, false) }.join(', ') %&gt;&lt;/p&gt;
-	&lt;/div&gt; &lt;!-- .section --&gt;		
-	&lt;% end %&gt;
+&lt;% if d.is_a?(Documentation::Klass) %&gt;
+
+  &lt;% if d.superklass %&gt;
+  &lt;div class=&quot;section section-superclass&quot;&gt;
+    &lt;div class=&quot;section-title&quot;&gt;
+      &lt;h3&gt;Superclass&lt;/h3&gt;
+    &lt;/div&gt; &lt;!-- .section-title --&gt;
+    
+    &lt;div class=&quot;section-content&quot;&gt;
+      &lt;p&gt;&lt;%= auto_link_code(d.superklass, false) %&gt;&lt;/p&gt;     
+    &lt;/div&gt; &lt;!-- .section-content --&gt;
+  &lt;/div&gt; &lt;!-- .section --&gt;    
+  &lt;% end %&gt;
+
+  &lt;% unless d.subklasses.empty? %&gt;
+  &lt;div class=&quot;section section-subclasses&quot;&gt;
+    &lt;div class=&quot;section-title&quot;&gt;
+      &lt;h3&gt;Subclasses&lt;/h3&gt;     
+    &lt;/div&gt; &lt;!-- .section-title --&gt;
+    
+    &lt;div class=&quot;section-content&quot;&gt;
+      &lt;p&gt;&lt;%= d.subklasses.map { |s| auto_link_code(s, false) }.join(', ') %&gt;&lt;/p&gt;     
+    &lt;/div&gt; &lt;!-- .section-content --&gt;
+  &lt;/div&gt; &lt;!-- .section --&gt;    
+  &lt;% end %&gt;
 
 &lt;% end %&gt;
 
 &lt;% # Does it have MIXINS? %&gt;
-&lt;% unless @doc_instance.mixins.empty? %&gt;
+&lt;% unless d.mixins.compact.empty? %&gt;
   &lt;div class=&quot;section section-mixins&quot;&gt;
-    &lt;h3&gt;Includes&lt;/h3&gt;
-    &lt;p&gt;&lt;%= d.mixins.map { |m| auto_link(m, false) }.join(', ') %&gt;&lt;/p&gt;
+    &lt;div class=&quot;section-title&quot;&gt;
+      &lt;h3&gt;Includes&lt;/h3&gt;      
+    &lt;/div&gt; &lt;!-- .section-title --&gt;
+    
+    &lt;div class=&quot;section-content&quot;&gt;
+      &lt;p&gt;&lt;%= d.mixins.map { |m| auto_link_code(m, false) }.join(', ') %&gt;&lt;/p&gt;      
+    &lt;/div&gt; &lt;!-- .section-content --&gt;
   &lt;/div&gt; &lt;!-- .section --&gt;
 &lt;% end %&gt;
 
 &lt;% # Are there related utilities? %&gt;
-&lt;% unless @doc_instance.related_utilities.empty? %&gt;
+&lt;% unless d.related_utilities.empty? %&gt;
   &lt;div class=&quot;section section-utilities&quot;&gt;
-    &lt;h3&gt;Related utilities&lt;/h3&gt;
-    &lt;p&gt;&lt;%= d.related_utilities.map { |u| auto_link(u, false) }.join(', ') %&gt;&lt;/p&gt;
+    &lt;div class=&quot;section-title&quot;&gt;
+      &lt;h3&gt;Related utilities&lt;/h3&gt;      
+    &lt;/div&gt; &lt;!-- .section-title --&gt;
+    
+    &lt;div class=&quot;section-content&quot;&gt;
+      &lt;p&gt;&lt;%= d.related_utilities.map { |u| auto_link_code(u, false) }.join(', ') %&gt;&lt;/p&gt;      
+    &lt;/div&gt; &lt;!-- .section-content --&gt;
   &lt;/div&gt; &lt;!-- .section --&gt;
 &lt;% end %&gt;
 
-&lt;% unless @doc_instance.description.strip == '' %&gt;
-&lt;div class=&quot;section section-description&quot;&gt;
-  &lt;h3&gt;Description&lt;/h3&gt;
-  &lt;%= htmlize(@doc_instance.description) %&gt;
-&lt;/div&gt; &lt;!-- .section --&gt;
-&lt;% end %&gt;
-
+&lt;% # List its methods. %&gt;
+&lt;% unless d.all_methods.empty? &amp;&amp; d.mixins.empty? %&gt;
 &lt;div class=&quot;section section-method-list&quot;&gt;
-  &lt;% unless d.all_methods.empty? &amp;&amp; d.mixins.empty? %&gt;
+  &lt;div class=&quot;section-title&quot;&gt;
     &lt;h3&gt;Methods&lt;/h3&gt;
+  &lt;/div&gt; &lt;!-- .section-title --&gt;
   
+  &lt;div class=&quot;section-content&quot;&gt;
     &lt;ul class=&quot;method-list&quot;&gt;
       &lt;% d.all_methods.each do |method| %&gt;
-        &lt;li&gt;&lt;%= auto_link(method, true, :class =&gt; class_names_for(method)) %&gt;&lt;/li&gt;
+        &lt;li&gt;&lt;%= auto_link_code(method, true, :class =&gt; class_names_for(method)) %&gt;&lt;/li&gt;
       &lt;% end %&gt;
     &lt;/ul&gt;
-  
-    &lt;% unless @doc_instance.mixins.empty? %&gt;
+    
+    &lt;% unless d.mixins.compact.empty? %&gt;
       &lt;% d.mixins.each do |mixin| %&gt;
-      &lt;h4 class=&quot;inherited&quot;&gt;Inherited from &lt;%= auto_link(mixin, false) %&gt;&lt;/h4&gt;
+      &lt;h4 class=&quot;inherited&quot;&gt;Inherited from &lt;%= auto_link(mixin) %&gt;&lt;/h4&gt;
       &lt;ul class=&quot;method-list&quot;&gt;
-  			&lt;% mixin.all_methods.each do |method| %&gt;
-  				&lt;li&gt;&lt;%= auto_link(method, true, :class =&gt; class_names_for(method)) %&gt;&lt;/li&gt;
-  			&lt;% end %&gt;
+        &lt;% mixin.all_methods.each do |method| %&gt;
+          &lt;li&gt;&lt;%= auto_link_code(method, true, :class =&gt; class_names_for(method)) %&gt;&lt;/li&gt;
+        &lt;% end %&gt;
       &lt;/ul&gt;
       &lt;% end %&gt;
     &lt;% end %&gt;
-  &lt;% end %&gt;
+    
+    
+  &lt;/div&gt; &lt;!-- .section-content --&gt;
+    
 &lt;/div&gt; &lt;!-- .section --&gt;
+&lt;% end %&gt;
 
 &lt;% if d.is_a?(Documentation::Klass) &amp;&amp; d.constructor %&gt;
 &lt;div class=&quot;section section-constructor&quot;&gt;
-  &lt;h3&gt;Constructor&lt;/h3&gt;
-  &lt;p&gt;
-    &lt;pre id=&quot;&lt;%= dom_id(d.constructor) %&gt;&quot; class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;%= d.constructor.ebnf_expressions %&gt;&lt;/code&gt;&lt;/pre&gt;
-  &lt;/p&gt;
+  &lt;div class=&quot;section-title&quot;&gt;
+    &lt;h3&gt;Constructor&lt;/h3&gt;
+  &lt;/div&gt; &lt;!-- .section-title --&gt;
+
+  &lt;div class=&quot;section-content&quot;&gt;
+    &lt;pre id=&quot;&lt;%= dom_id(d.constructor) %&gt;&quot; class=&quot;syntax&quot;&gt;&lt;code&gt;&lt;%= d.constructor.ebnf_expressions.join(&quot;\n&quot;).strip %&gt;&lt;/code&gt;&lt;/pre&gt;
+    &lt;% unless d.constructor.arguments.empty? %&gt;
+      &lt;ul class=&quot;argument-list&quot;&gt;
+        &lt;% d.constructor.arguments.each do |arg| %&gt;
+          &lt;li&gt;
+            &lt;code&gt;&lt;%= arg.name %&gt;&lt;/code&gt;
+            &lt;% unless arg.types.empty? %&gt;
+              (&lt;%= arg.types.map { |t| auto_link_code(t, false) }.join(' | ') %&gt;)
+            &lt;% end %&gt;
+            &lt;%= ' &amp;ndash; ' + inline_htmlize(arg.description) unless arg.description.empty? %&gt;
+          &lt;/li&gt;
+        &lt;% end %&gt;
+      &lt;/ul&gt; &lt;!-- .argument-list --&gt;
+    &lt;% end %&gt;
+    
+
+    &lt;p&gt;&lt;%= htmlize(d.constructor.description) %&gt;&lt;/p&gt;
+    
+  &lt;/div&gt; &lt;!-- .section-content --&gt;
   
-  &lt;p&gt;&lt;%= htmlize(d.constructor.description) %&gt;&lt;/p&gt;
 &lt;/div&gt; &lt;!-- .section --&gt;
 &lt;% end %&gt;
 
 
 &lt;%
 types = {
-	:constants           =&gt; &quot;Constants&quot;,
-	:klass_methods       =&gt; &quot;Class methods&quot;,
-	:klass_properties    =&gt; &quot;Class properties&quot;,
-	:instance_methods    =&gt; &quot;Instance methods&quot;,
-	:instance_properties =&gt; &quot;Instance properties&quot;  
+  :constants           =&gt; &quot;Constants&quot;,
+  :klass_methods       =&gt; &quot;Class methods&quot;,
+  :klass_properties    =&gt; &quot;Class properties&quot;,
+  :instance_methods    =&gt; &quot;Instance methods&quot;,
+  :instance_properties =&gt; &quot;Instance properties&quot;  
 }
 %&gt;
 
@@ -99,11 +155,17 @@ types = {
   &lt;% methods = d.send(method) %&gt;
   &lt;% unless methods.empty? %&gt;
     &lt;div class=&quot;section section-&lt;%= method.to_s %&gt;&quot;&gt;
-      &lt;h3&gt;&lt;%= title %&gt;&lt;/h3&gt;
-      &lt;ul class=&quot;method-details-list&quot;&gt;
-        &lt;%= include &quot;partials/short_description&quot;, :collection =&gt; methods %&gt;
-      &lt;/ul&gt;    
+      
+      &lt;div class=&quot;section-title&quot;&gt;
+        &lt;h3&gt;&lt;%= title %&gt;&lt;/h3&gt;        
+      &lt;/div&gt; &lt;!-- .section-title --&gt;
+      
+      &lt;div class=&quot;section-content&quot;&gt;
+        &lt;ul class=&quot;method-details-list&quot;&gt;
+          &lt;%= include &quot;partials/short_description&quot;, :collection =&gt; methods %&gt;
+        &lt;/ul&gt;    
+        
+      &lt;/div&gt; &lt;!-- .section-content --&gt;
     &lt;/div&gt; &lt;!-- .section --&gt;
   &lt;% end %&gt;
-&lt;% end %&gt;
-
+&lt;% end %&gt;
\ No newline at end of file</diff>
      <filename>templates/html/namespace.erb</filename>
    </modified>
    <modified>
      <diff>@@ -1,28 +1,48 @@
-&lt;li&gt;&lt;h4 id=&quot;&lt;%= dom_id(object) %&gt;&quot;&gt;&lt;%= object.name %&gt;&lt;/h4&gt;
+&lt;li class=&quot;method-description&quot;&gt;
+  &lt;h4 id=&quot;&lt;%= dom_id(object) %&gt;&quot;&gt;&lt;%= object.name %&gt;
+    &lt;span class=&quot;method-permalink&quot;&gt;&lt;a href=&quot;&lt;%= path_to(object) %&gt;&quot;&gt;#&lt;/a&gt;&lt;/span&gt;&lt;/h4&gt;
+
+  &lt;% if object.signature %&gt;
+    &lt;%= method_synopsis(object) %&gt;
+  &lt;% end %&gt;
   
   &lt;% if object.is_a?(Documentation::Method) %&gt;
-    &lt;%= method_synopsis(object) %&gt;
     &lt;% unless object.arguments.empty? %&gt;
       &lt;ul class=&quot;argument-list&quot;&gt;
         &lt;% object.arguments.each do |arg| %&gt;
           &lt;li&gt;
             &lt;code&gt;&lt;%= arg.name %&gt;&lt;/code&gt;
             &lt;% unless arg.types.empty? %&gt;
-              (&lt;%= arg.types.map { |t| auto_link(t, false) }.join(' | ') %&gt;)
+              (&lt;%= arg.types.map { |t| auto_link_code(t, false) }.join(' | ') %&gt;)
             &lt;% end %&gt;
-            &lt;%= ' &amp;ndash; ' + arg.description unless arg.description.empty? %&gt;
+            &lt;%= ' &amp;ndash; ' + inline_htmlize(arg.description) unless arg.description.empty? %&gt;
           &lt;/li&gt;
         &lt;% end %&gt;
-      &lt;/ul&gt;
+      &lt;/ul&gt; &lt;!-- .argument-list --&gt;
     &lt;% end %&gt;
   &lt;% end %&gt;
   
+	&lt;%= htmlize(object.description) %&gt;
+  
+  &lt;% # Does it have an alias? %&gt;
   &lt;% unless object.aliases.empty? %&gt;
-    &lt;p class=&quot;alias aliases&quot;&gt;Aliased as: &lt;%= object.aliases.map { |a| auto_link(a, false) }.join(', ') %&gt;&lt;/p&gt;
+    &lt;p class=&quot;alias aliases&quot;&gt;Aliased as: &lt;%= object.aliases.map { |a| auto_link_code(a, false) }.join(', ') %&gt;&lt;/p&gt;
   &lt;% end %&gt;
+  
+  &lt;% # Is it an alias of something else? %&gt;
   &lt;% if object.alias? %&gt;
-    &lt;p class=&quot;alias alias-of&quot;&gt;Alias for &lt;%= auto_link(object.alias_of, false) %&gt;&lt;/p&gt;
+    &lt;p class=&quot;alias alias-of&quot;&gt;Alias of: &lt;%= auto_link_code(object.alias_of, false) %&gt;&lt;/p&gt;
+  &lt;% end %&gt;
+  
+  &lt;% # Is it related to something? %&gt;
+  &lt;% if object.is_a?(Documentation::Utility) &amp;&amp; object.related_to %&gt;
+    &lt;p class=&quot;related-to&quot;&gt;Related to: 
+      &lt;%= auto_link_code(object.related_to, false) %&gt;&lt;/p&gt;      
+  &lt;% end %&gt;
+    
+  &lt;% # Is it methodized? %&gt;
+  &lt;% if object.is_a?(Documentation::Method) &amp;&amp; object.methodized? %&gt;
+    &lt;p class=&quot;note&quot;&gt;This method can be called &lt;em&gt;either&lt;/em&gt; as an instance method &lt;em&gt;or&lt;/em&gt; as a generic method. If calling as a generic, pass the instance in as the first argument.&lt;/p&gt;
   &lt;% end %&gt;
   
-	&lt;%= htmlize(object.description) %&gt;
 &lt;/li&gt;</diff>
      <filename>templates/html/partials/short_description.erb</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,99 @@
-&lt;% @title = &quot;#{@doc_instance.full_name} section&quot; %&gt;
+&lt;% @title = &quot;#{@doc_instance.full_name}&quot; %&gt;
+&lt;% section = @doc_instance %&gt;
 
-&lt;h2&gt;&lt;%= @doc_instance.name %&gt;&lt;/h2&gt;
+&lt;%= include &quot;partials/breadcrumbs&quot;, :object =&gt; section %&gt;
 
+&lt;h2 class=&quot;page-title&quot;&gt;
+  &lt;span class=&quot;type&quot;&gt;Section &lt;/span&gt;&lt;%= section.name %&gt;
+&lt;/h2&gt;
+
+&lt;div class=&quot;section section-description&quot;&gt;
+  
+  &lt;div class=&quot;section-title&quot;&gt;
+    &lt;h3&gt;Description&lt;/h3&gt;
+  &lt;/div&gt; &lt;!-- .section-title --&gt;
+  
+  &lt;div class=&quot;section-content&quot;&gt;
+    &lt;%= htmlize(section.description) %&gt;
+  &lt;/div&gt; &lt;!-- .section-content --&gt;
+  
+&lt;/div&gt; &lt;!--.section --&gt;
+
+&lt;% # Iterate over the items in this section. %&gt;
+
+&lt;% utilities = section.utilities %&gt;
+&lt;% unless utilities.empty? %&gt;
+
+  &lt;div class=&quot;section section-utilities&quot;&gt;
+    &lt;div class=&quot;section-title&quot;&gt;
+      &lt;h3&gt;Utilities&lt;/h3&gt;
+    &lt;/div&gt; &lt;!-- .section-title --&gt;
+    
+    &lt;div class=&quot;section-content&quot;&gt;
+      &lt;ul class=&quot;method-list&quot;&gt;
+      &lt;% utilities.each do |utility| %&gt;  
+        &lt;li&gt;&lt;%= auto_link_code(utility) %&gt;&lt;/li&gt;
+      &lt;% end %&gt;
+      &lt;/ul&gt;
+    &lt;/div&gt; &lt;!-- .section-content --&gt;
+  &lt;/div&gt; &lt;!-- .section --&gt;
+
+&lt;% end %&gt;
+
+&lt;% namespaces = section.namespaces %&gt;
+&lt;% unless namespaces.empty? %&gt;
+  
+  &lt;div class=&quot;section section-namespaces&quot;&gt;
+    &lt;div class=&quot;section-title&quot;&gt;
+      &lt;h3&gt;Namespaces&lt;/h3&gt;
+    &lt;/div&gt; &lt;!-- .section-title --&gt;
+    
+    &lt;div class=&quot;section-content&quot;&gt;
+      &lt;ul class=&quot;method-details-list&quot;&gt;
+      &lt;% namespaces.each do |namespace| %&gt;
+        &lt;li class=&quot;method-description&quot;&gt;
+          &lt;h4&gt;
+            &lt;a href=&quot;&lt;%= path_to(namespace) %&gt;&quot;&gt;&lt;%= namespace.full_name %&gt;&lt;/a&gt;
+          &lt;/h4&gt;
+          
+          &lt;% unless namespace.short_description.nil? %&gt;
+            &lt;p&gt;&lt;%= htmlize(namespace.short_description) %&gt;&lt;/p&gt;
+          &lt;% end %&gt;
+          
+        &lt;/li&gt;
+      &lt;% end %&gt;
+      &lt;/ul&gt;
+    &lt;/div&gt; &lt;!-- .section-content --&gt;
+  &lt;/div&gt; &lt;!-- .section --&gt;
+  
+&lt;% end %&gt;
+
+&lt;% klasses = section.klasses %&gt;
+&lt;% unless klasses.empty? %&gt;
+
+  &lt;div class=&quot;section section-classes&quot;&gt;
+    
+    &lt;div class=&quot;section-title&quot;&gt;
+      &lt;h3&gt;Classes&lt;/h3&gt;
+    &lt;/div&gt; &lt;!-- .section-title --&gt;
+    
+    &lt;div class=&quot;section-content&quot;&gt;
+      &lt;ul class=&quot;method-details-list&quot;&gt;
+      &lt;% klasses.each do |klass| %&gt;
+        &lt;li class=&quot;method-description&quot;&gt;
+          &lt;h4&gt;
+            &lt;a href=&quot;&lt;%= path_to(klass) %&gt;&quot;&gt;&lt;%= klass.full_name %&gt;&lt;/a&gt;
+          &lt;/h4&gt;
+          
+          &lt;% unless klass.short_description.nil? %&gt;
+            &lt;p&gt;&lt;%= htmlize(klass.short_description) %&gt;&lt;/p&gt;
+          &lt;% end %&gt;
+          
+        &lt;/li&gt;
+      &lt;% end %&gt;
+      &lt;/ul&gt;
+    &lt;/div&gt; &lt;!-- .section-content --&gt;
+    
+  &lt;/div&gt; &lt;!--.section --&gt;
+  
+&lt;% end %&gt;
\ No newline at end of file</diff>
      <filename>templates/html/section.erb</filename>
    </modified>
    <modified>
      <diff>@@ -2,12 +2,20 @@
 
 &lt;% @title = &quot;#{@doc_instance.full_name} utility&quot; %&gt;
 
-&lt;h2&gt;&lt;span&gt;utility&lt;/span&gt; &lt;%= @doc_instance.name %&gt;&lt;/h2&gt;
-
-&lt;% # What's it related to? %&gt;
-&lt;% unless @doc_instance.related_to.nil? %&gt;
-  &lt;div class=&quot;section section-related&quot;&gt;
-    &lt;h3&gt;Related to&lt;/h3&gt;
-    &lt;p&gt;&lt;%= auto_link(d.related_to, false) %&gt;&lt;/p&gt;
-  &lt;/div&gt; &lt;!-- .section --&gt;
-&lt;% end %&gt;
\ No newline at end of file
+&lt;%= include &quot;partials/breadcrumbs&quot;, :object =&gt; d %&gt;
+
+&lt;h2 class=&quot;page-title&quot;&gt;
+  &lt;span class=&quot;type&quot;&gt;utility &lt;/span&gt;&lt;%= @doc_instance.name %&gt;
+&lt;/h2&gt;
+
+&lt;div class=&quot;section&quot;&gt;
+  &lt;div class=&quot;section-title&quot;&gt;
+    &lt;h3&gt;Description&lt;/h3&gt;
+  &lt;/div&gt; &lt;!-- .section-title --&gt;
+  
+  &lt;div class=&quot;section-content&quot;&gt;
+    &lt;ul class=&quot;method-details-list&quot;&gt;
+      &lt;%= include &quot;partials/short_description&quot;, :collection =&gt; [@doc_instance] %&gt;            
+    &lt;/ul&gt;    
+  &lt;/div&gt; &lt;!-- .section-content --&gt;
+&lt;/div&gt; &lt;!-- .section --&gt;
\ No newline at end of file</diff>
      <filename>templates/html/utility.erb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>templates/html/assets/javascripts/mouse_enter_leave.js</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>6f51d1031aaa8a22c425df56cce8128f4de7b6a4</id>
    </parent>
  </parents>
  <author>
    <name>Tobie Langel</name>
    <email>tobie.langel@gmail.com</email>
  </author>
  <url>http://github.com/tobie/pdoc/commit/914a9ea769e1c211184bd2a15d38097d11046bd2</url>
  <id>914a9ea769e1c211184bd2a15d38097d11046bd2</id>
  <committed-date>2009-08-25T11:47:14-07:00</committed-date>
  <authored-date>2009-08-25T11:47:14-07:00</authored-date>
  <message>Update defautl templates.</message>
  <tree>7bb5aef0f68f83418637b34156b8d09e87e71784</tree>
  <committer>
    <name>Tobie Langel</name>
    <email>tobie.langel@gmail.com</email>
  </committer>
</commit>
