<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>src/resizable.js</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -10,175 +10,176 @@
 /*global window, document, Prototype, Class, Event, $, $A, $R, Control, $value */
 
 if(typeof(Prototype) == &quot;undefined&quot;) {
-	throw &quot;Control.ContextMenu requires Prototype to be loaded.&quot;; }
+    throw &quot;Control.ContextMenu requires Prototype to be loaded.&quot;; }
 if(typeof(Object.Event) == &quot;undefined&quot;) {
-	throw &quot;Control.ContextMenu requires Object.Event to be loaded.&quot;; }
+    throw &quot;Control.ContextMenu requires Object.Event to be loaded.&quot;; }
 
 Control.ContextMenu = Class.create({
-	initialize: function(container,options){
-		Control.ContextMenu.load();
-		this.options = Object.extend({
-			leftClick: false,
-			disableOnShiftKey: true,
-			disableOnAltKey: true,
-			selectedClassName: 'selected',
-			activatedClassName: 'activated',
-			animation: true,
-			animationCycles: 2,
-			animationLength: 300,
-			delayCallback: true
-		},options || {});
-		this.activated = false;
-		this.items = this.options.items || [];
-		this.container = $(container);
-		this.container.observe(this.options.leftClick ? 'click' : (Prototype.Browser.Opera ? 'click' : 'contextmenu'),function(event){
-			if(!Control.ContextMenu.enabled || Prototype.Browser.Opera &amp;&amp; !event.ctrlKey) {
-				return; }
-			this.open(event);
-		}.bindAsEventListener(this));
-	},
-	open: function(event){
-		if(Control.ContextMenu.current &amp;&amp; !Control.ContextMenu.current.close()) {
-			return; }
-		if(this.notify('beforeOpen',event) === false) {
-			return false; }
-		this.buildMenu();
-		if(this.items.length === 0){
-			this.close(event);
-			return false;
-		}
-		Control.ContextMenu.current = this;
-		Control.ContextMenu.positionContainer(event);
-		Control.ContextMenu.container.show();
-		if(this.notify('afterOpen',event) === false) {
-			return false; }
-		event.stop();
-		return true;
-	},
-	close: function(event){
-		if(event) {
-			event.stop(); }
-		if(this.notify('beforeClose') === false) {
-			return false; }
-		Control.ContextMenu.current = false;
-		this.activated = false;
-		Control.ContextMenu.container.removeClassName(this.options.activatedClassName);
-		Control.ContextMenu.container.select('li').invoke('stopObserving');
-		Control.ContextMenu.container.hide();
-		Control.ContextMenu.container.update('');
-		if(this.notify('afterClose') === false) {
-			return false; }
-		return true;
-	},
-	buildMenu: function(){
-		var list = document.createElement('ul');
-		Control.ContextMenu.container.appendChild(list);
-		this.items.each(function(item){
-			if(!(!item.condition || item.condition &amp;&amp; item.condition() !== false)) {
-				return; }
-			var item_container = $(document.createElement('li'));
-			item_container.update($value(item.label));
-			list.appendChild(item_container);
-			item_container[$value(item.enabled) ? 'removeClassName' : 'addClassName']('disabled');
-			item_container.observe('mousedown',function(event,item){
-				if(!$value(item.enabled)) {
-					return event.stop(); }
-				this.activated = $value(item.label);
-			}.bindAsEventListener(this,item));
-			item_container.observe('click',this.selectMenuItem.bindAsEventListener(this,item,item_container));
-			item_container.observe('contextmenu',this.selectMenuItem.bindAsEventListener(this,item,item_container));
-		}.bind(this));
-	},
-	addItem: function(params){
+    initialize: function(container,options){
+        Control.ContextMenu.load();
+        this.options = Object.extend({
+            leftClick: false,
+            disableOnShiftKey: true,
+            disableOnAltKey: true,
+            selectedClassName: 'selected',
+            activatedClassName: 'activated',
+            animation: true,
+            animationCycles: 2,
+            animationLength: 300,
+            delayCallback: true
+        },options || {});
+        this.activated = false;
+        this.items = this.options.items || [];
+        this.container = $(container);
+        this.container.observe(this.options.leftClick ? 'click' : (Prototype.Browser.Opera ? 'click' : 'contextmenu'),function(event){
+            if(!Control.ContextMenu.enabled || Prototype.Browser.Opera &amp;&amp; !event.ctrlKey) {
+                return; }
+            this.open(event);
+        }.bindAsEventListener(this));
+    },
+    open: function(event){
+        if(Control.ContextMenu.current &amp;&amp; !Control.ContextMenu.current.close()) {
+            return; }
+        if(this.notify('beforeOpen',event) === false) {
+            return false; }
+        this.buildMenu();
+        if(this.items.length === 0){
+            this.close(event);
+            return false;
+        }
+        this.clicked = Event.element(event);
+        Control.ContextMenu.current = this;
+        Control.ContextMenu.positionContainer(event);
+        Control.ContextMenu.container.show();
+        if(this.notify('afterOpen',event) === false) {
+            return false; }
+        event.stop();
+        return true;
+    },
+    close: function(event){
+        if(event) {
+            event.stop(); }
+        if(this.notify('beforeClose') === false) {
+            return false; }
+        Control.ContextMenu.current = false;
+        this.activated = false;
+        Control.ContextMenu.container.removeClassName(this.options.activatedClassName);
+        Control.ContextMenu.container.select('li').invoke('stopObserving');
+        Control.ContextMenu.container.hide();
+        Control.ContextMenu.container.update('');
+        if(this.notify('afterClose') === false) {
+            return false; }
+        return true;
+    },
+    buildMenu: function(){
+        var list = document.createElement('ul');
+        Control.ContextMenu.container.appendChild(list);
+        this.items.each(function(item){
+            if(!(!item.condition || item.condition &amp;&amp; item.condition() !== false)) {
+                return; }
+            var item_container = $(document.createElement('li'));
+            item_container.update($value(item.label));
+            list.appendChild(item_container);
+            item_container[$value(item.enabled) ? 'removeClassName' : 'addClassName']('disabled');
+            item_container.observe('mousedown',function(event,item){
+                if(!$value(item.enabled)) {
+                    return event.stop(); }
+                this.activated = $value(item.label);
+            }.bindAsEventListener(this,item));
+            item_container.observe('click',this.selectMenuItem.bindAsEventListener(this,item,item_container));
+            item_container.observe('contextmenu',this.selectMenuItem.bindAsEventListener(this,item,item_container));
+        }.bind(this));
+    },
+    addItem: function(params){
         if (!('enabled' in params)) { params.enabled = true; }
-		this.items.push(params);
-		return this;
-	},
-	destroy: function(){
-		this.container.stopObserving(Prototype.Browser.Opera || this.options.leftClick ? 'click' : 'contextmenu');
-		this.items = [];
-	},
-	selectMenuItem: function(event,item,item_container){
-		if(!$value(item.enabled)) {
-			return event.stop(); }
-		if(!this.activated || this.activated == $value(item.label)){
-			if(this.options.animation){
-				Control.ContextMenu.container.addClassName(this.options.activatedClassName);
-				$A($R(0,this.options.animationCycles * 2)).each(function(i){
-					window.setTimeout(function(){
-						item_container.toggleClassName(this.options.selectedClassName);
-					}.bind(this),i * parseInt(this.options.animationLength / (this.options.animationCycles * 2), 10));
-				}.bind(this));
-				window.setTimeout(function(){
-					if(this.close() &amp;&amp; this.options.delayCallback) {
-						item.callback(); }
-				}.bind(this),this.options.animationLength);
-				if(!this.options.delayCallback) {
-					item.callback(); }
-			}else if(this.close()) {
-				item.callback(); }
-		}
-		event.stop();
-		return false;
-	}
+        this.items.push(params);
+        return this;
+    },
+    destroy: function(){
+        this.container.stopObserving(Prototype.Browser.Opera || this.options.leftClick ? 'click' : 'contextmenu');
+        this.items = [];
+    },
+    selectMenuItem: function(event,item,item_container){
+        if(!$value(item.enabled)) {
+            return event.stop(); }
+        if(!this.activated || this.activated == $value(item.label)){
+            if(this.options.animation){
+                Control.ContextMenu.container.addClassName(this.options.activatedClassName);
+                $A($R(0,this.options.animationCycles * 2)).each(function(i){
+                    window.setTimeout(function(){
+                        item_container.toggleClassName(this.options.selectedClassName);
+                    }.bind(this),i * parseInt(this.options.animationLength / (this.options.animationCycles * 2), 10));
+                }.bind(this));
+                window.setTimeout(function(){
+                    if(this.close() &amp;&amp; this.options.delayCallback) {
+                        item.callback(this.clicked); }
+                }.bind(this),this.options.animationLength);
+                if(!this.options.delayCallback) {
+                    item.callback(this.clicked); }
+            }else if(this.close()) {
+                item.callback(this.clicked); }
+        }
+        event.stop();
+        return false;
+    }
 });
 Object.extend(Control.ContextMenu,{
-	loaded: false,
-	capture_all: false,
-	menus: [],
-	current: false,
-	enabled: false,
-	offset: 4,
-	load: function(capture_all){
-		if(Control.ContextMenu.loaded) {
-			return; }
-		Control.ContextMenu.loaded = true;
-		if(typeof(capture_all) == 'undefined') {
-			capture_all = false; }
-		Control.ContextMenu.capture_all = capture_all;
-		Control.ContextMenu.container = $(document.createElement('div'));
-		Control.ContextMenu.container.id = 'control_contextmenu';
-		Control.ContextMenu.container.style.position = 'absolute';
-		Control.ContextMenu.container.style.zIndex = 99999;
-		Control.ContextMenu.container.hide();
-		document.body.appendChild(Control.ContextMenu.container);
-		Control.ContextMenu.enable();
-	},
-	enable: function(){
-		Control.ContextMenu.enabled = true;
-		Event.observe(document.body,'click',Control.ContextMenu.onClick);
-		if(Control.ContextMenu.capture_all) {
-			Event.observe(document.body,'contextmenu',Control.ContextMenu.onContextMenu); }
-	},
-	disable: function(){
-		Event.stopObserving(document.body,'click',Control.ContextMenu.onClick);
-		if(Control.ContextMenu.capture_all) {
-			Event.stopObserving(document.body,'contextmenu',Control.ContextMenu.onContextMenu);	}
-	},
-	onContextMenu: function(event){
-		event.stop();
-		return false;
-	},
-	onClick: function(){
-		if(Control.ContextMenu.current) {
-			Control.ContextMenu.current.close(); }
-	},
-	positionContainer: function(event){
-		var dimensions = Control.ContextMenu.container.getDimensions();
-		var top = Event.pointerY(event);
-		var left = Event.pointerX(event);
-		var bottom = dimensions.height + top;
-		var right = dimensions.width + left;
-		var viewport_dimensions = document.viewport.getDimensions();
-		var viewport_scroll_offsets = document.viewport.getScrollOffsets();
-		if(bottom &gt; viewport_dimensions.height + viewport_scroll_offsets.top) {
-			top -= bottom - ((viewport_dimensions.height  + viewport_scroll_offsets.top) - Control.ContextMenu.offset); }
-		if(right &gt; viewport_dimensions.width + viewport_scroll_offsets.left) {
-			left -= right - ((viewport_dimensions.width + viewport_scroll_offsets.left) - Control.ContextMenu.offset); }
-		Control.ContextMenu.container.setStyle({
-			top: top + 'px',
-			left: left + 'px'
-		});
-	}
+    loaded: false,
+    capture_all: false,
+    menus: [],
+    current: false,
+    enabled: false,
+    offset: 4,
+    load: function(capture_all){
+        if(Control.ContextMenu.loaded) {
+            return; }
+        Control.ContextMenu.loaded = true;
+        if(typeof(capture_all) == 'undefined') {
+            capture_all = false; }
+        Control.ContextMenu.capture_all = capture_all;
+        Control.ContextMenu.container = $(document.createElement('div'));
+        Control.ContextMenu.container.id = 'control_contextmenu';
+        Control.ContextMenu.container.style.position = 'absolute';
+        Control.ContextMenu.container.style.zIndex = 99999;
+        Control.ContextMenu.container.hide();
+        document.body.appendChild(Control.ContextMenu.container);
+        Control.ContextMenu.enable();
+    },
+    enable: function(){
+        Control.ContextMenu.enabled = true;
+        Event.observe(document.body,'click',Control.ContextMenu.onClick);
+        if(Control.ContextMenu.capture_all) {
+            Event.observe(document.body,'contextmenu',Control.ContextMenu.onContextMenu); }
+    },
+    disable: function(){
+        Event.stopObserving(document.body,'click',Control.ContextMenu.onClick);
+        if(Control.ContextMenu.capture_all) {
+            Event.stopObserving(document.body,'contextmenu',Control.ContextMenu.onContextMenu);    }
+    },
+    onContextMenu: function(event){
+        event.stop();
+        return false;
+    },
+    onClick: function(){
+        if(Control.ContextMenu.current) {
+            Control.ContextMenu.current.close(); }
+    },
+    positionContainer: function(event){
+        var dimensions = Control.ContextMenu.container.getDimensions();
+        var top = Event.pointerY(event);
+        var left = Event.pointerX(event);
+        var bottom = dimensions.height + top;
+        var right = dimensions.width + left;
+        var viewport_dimensions = document.viewport.getDimensions();
+        var viewport_scroll_offsets = document.viewport.getScrollOffsets();
+        if(bottom &gt; viewport_dimensions.height + viewport_scroll_offsets.top) {
+            top -= bottom - ((viewport_dimensions.height  + viewport_scroll_offsets.top) - Control.ContextMenu.offset); }
+        if(right &gt; viewport_dimensions.width + viewport_scroll_offsets.left) {
+            left -= right - ((viewport_dimensions.width + viewport_scroll_offsets.left) - Control.ContextMenu.offset); }
+        Control.ContextMenu.container.setStyle({
+            top: top + 'px',
+            left: left + 'px'
+        });
+    }
 });
 Object.Event.extend(Control.ContextMenu);</diff>
      <filename>public/javascripts/contextmenu.js</filename>
    </modified>
    <modified>
      <diff>@@ -7,10 +7,12 @@
  * @attribution http://www.quirksmode.org/js/cookies.html
  */
 
-if(typeof(Prototype) == &quot;undefined&quot;)
-  throw &quot;Cookie requires Prototype to be loaded.&quot;
-if(typeof(Object.Event) == &quot;undefined&quot;)
-  throw &quot;Cookie requires Object.Event to be loaded.&quot;;
+/*global document, Prototype, $A */
+
+if(typeof(Prototype) == &quot;undefined&quot;) {
+  throw &quot;Cookie requires Prototype to be loaded.&quot;; }
+if(typeof(Object.Event) == &quot;undefined&quot;) {
+  throw &quot;Cookie requires Object.Event to be loaded.&quot;; }
 
 var Cookie = {
   build: function() {
@@ -36,4 +38,4 @@ var Cookie = {
     Cookie.set(name,'',-1);
   }
 };
-Object.Event.extend(Cookie);
\ No newline at end of file
+Object.Event.extend(Cookie);</diff>
      <filename>public/javascripts/cookie.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,6 @@
-// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-//           (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
+// script.aculo.us dragdrop.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
 //
 // script.aculo.us is freely distributable under the terms of an MIT-style license.
 // For details, see the script.aculo.us web site: http://script.aculo.us/
@@ -311,7 +312,7 @@ var Draggable = Class.create({
         tag_name=='TEXTAREA')) return;
 
       var pointer = [Event.pointerX(event), Event.pointerY(event)];
-      var pos     = Position.cumulativeOffset(this.element);
+      var pos     = this.element.cumulativeOffset();
       this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
 
       Draggables.activate(this);
@@ -454,7 +455,7 @@ var Draggable = Class.create({
   },
 
   draw: function(point) {
-    var pos = Position.cumulativeOffset(this.element);
+    var pos = this.element.cumulativeOffset();
     if(this.options.ghosting) {
       var r   = Position.realOffset(this.element);
       pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
@@ -730,7 +731,7 @@ var Sortable = {
     }
 
     // keep reference
-    this.sortables[element.id] = options;
+    this.sortables[element.identify()] = options;
 
     // for onupdate
     Draggables.addObserver(new SortableObserver(element, options.onUpdate));
@@ -825,7 +826,7 @@ var Sortable = {
           hide().addClassName('dropmarker').setStyle({position:'absolute'});
       document.getElementsByTagName(&quot;body&quot;).item(0).appendChild(Sortable._marker);
     }
-    var offsets = Position.cumulativeOffset(dropon);
+    var offsets = dropon.cumulativeOffset();
     Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'});
 
     if(position=='after')</diff>
      <filename>public/javascripts/dragdrop.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,4 +1,6 @@
-// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+// script.aculo.us effects.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
+
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
 // Contributors:
 //  Justin Palmer (http://encytemedia.com/)
 //  Mark Pilgrim (http://diveintomark.org/)
@@ -145,14 +147,13 @@ var Effect = {
     'blind':  ['BlindDown','BlindUp'],
     'appear': ['Appear','Fade']
   },
-  toggle: function(element, effect) {
+  toggle: function(element, effect, options) {
     element = $(element);
-    effect = (effect || 'appear').toLowerCase();
-    var options = Object.extend({
+    effect  = (effect || 'appear').toLowerCase();
+    
+    return Effect[ Effect.PAIRS[ effect ][ element.visible() ? 1 : 0 ] ](element, Object.extend({
       queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
-    }, arguments[2] || { });
-    Effect[element.visible() ?
-      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
+    }, options || {}));
   }
 };
 
@@ -228,12 +229,6 @@ Effect.Queue = Effect.Queues.get('global');
 Effect.Base = Class.create({
   position: null,
   start: function(options) {
-    function codeForEvent(options,eventName){
-      return (
-        (options[eventName+'Internal'] ? 'this.options.'+eventName+'Internal(this);' : '') +
-        (options[eventName] ? 'this.options.'+eventName+'(this);' : '')
-      );
-    }
     if (options &amp;&amp; options.transition === false) options.transition = Effect.Transitions.linear;
     this.options      = Object.extend(Object.extend({ },Effect.DefaultOptions), options || { });
     this.currentFrame = 0;</diff>
      <filename>public/javascripts/effects.js</filename>
    </modified>
    <modified>
      <diff>@@ -8,112 +8,112 @@
  * @attribution http://www.adamlogic.com/2007/03/20/3_metaprogramming-javascript-presentation
  */
 
-if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Event.Behavior requires Prototype to be loaded.&quot;;
-if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Event.Behavior requires Object.Event to be loaded.&quot;;
-	
+/*global Prototype, Class, Event, Try, $, $A, $H */
+
+if(typeof(Prototype) == &quot;undefined&quot;) {
+    throw &quot;Event.Behavior requires Prototype to be loaded.&quot;; }
+if(typeof(Object.Event) == &quot;undefined&quot;) {
+    throw &quot;Event.Behavior requires Object.Event to be loaded.&quot;; }
+    
 Event.Behavior = {
-	addVerbs: function(verbs){
-		for(name in verbs){
-			v = new Event.Behavior.Verb(verbs[name]);
-			Event.Behavior.Verbs[name] = v;
-			Event.Behavior[name.underscore()] = Event.Behavior[name] = v.getCallbackForStack.bind(v);
-		}
-	},
-	addEvents: function(events){
-		$H(events).each(function(event_type){
-			Event.Behavior.Adjective.prototype[event_type.key.underscore()] = Event.Behavior.Adjective.prototype[event_type.key] = function(){
-				this.nextConditionType = 'and';
-				this.events.push(event_type.value);
-				this.attachObserver(false);
-				return this;
-			};
-		});
-	},
-	invokeElementMethod: function(element,action,args){
-		if(typeof(element) == 'function'){
-			return $A(element()).each(function(e){
-				if(typeof(args[0]) == 'function'){
-					return $A(args[0]).each(function(a){
-						return $(e)[action].apply($(e),(a ? [a] : []));
-					});
-				}else
-					return $(e)[action].apply($(e),args || []);
-			});
-		}else
-			return $(element)[action].apply($(element),args || []);
-	}
+    addVerbs: function(verbs){
+        var v;
+        for (var name in verbs) { if (verbs.hasOwnProperty(name)) {
+            v = new Event.Behavior.Verb(verbs[name]);
+            Event.Behavior.Verbs[name] = v;
+            Event.Behavior[name.underscore()] = Event.Behavior[name] = v.getCallbackForStack.bind(v);
+        }}
+    },
+    addEvents: function(events){
+        $H(events).each(function(event_type){
+            Event.Behavior.Adjective.prototype[event_type.key.underscore()] = Event.Behavior.Adjective.prototype[event_type.key] = function(){
+                this.nextConditionType = 'and';
+                this.events.push(event_type.value);
+                this.attachObserver(false);
+                return this;
+            };
+        });
+    },
+    invokeElementMethod: function(element,action,args){
+        if(typeof(element) == 'function'){
+            return $A(element()).each(function(e){
+                if(typeof(args[0]) == 'function'){
+                    return $A(args[0]).each(function(a){
+                        return $(e)[action].apply($(e),(a ? [a] : []));
+                    });
+                }else {
+                    return $(e)[action].apply($(e),args || []); }
+            });
+        }else {
+            return $(element)[action].apply($(element),args || []); }
+    }
 };
 
 Event.Behavior.Verbs = $H({});
 
 Event.Behavior.Verb = Class.create();
 Object.extend(Event.Behavior.Verb.prototype,{
-	originalAction: false,
-	execute: false,
-	executeOpposite: false,
-	target: false,
-	initialize: function(action){
-		this.originalAction = action;
-		this.execute = function(action,target,argument){
-			return (argument)
-				? action(target,argument)
-				: action(target)
-			;
-		}.bind(this,action);
-	},
-	setOpposite: function(opposite_verb){
-		opposite_action = opposite_verb.originalAction;
-		this.executeOpposite = function(opposite_action,target,argument){
-			return (argument)
-				? opposite_action(target,argument)
-				: opposite_action(target)
-			;
-		}.bind(this,opposite_action);
-	},
-	getCallbackForStack: function(argument){
-		return new Event.Behavior.Noun(this,argument);
-	}
+    originalAction: false,
+    execute: false,
+    executeOpposite: false,
+    target: false,
+    initialize: function(action){
+        this.originalAction = action;
+        this.execute = function(action,target,argument){
+            return (argument) ? action(target,argument) : action(target);
+        }.bind(this,action);
+    },
+    setOpposite: function(opposite_verb){
+        var opposite_action = opposite_verb.originalAction;
+        this.executeOpposite = function(opposite_action,target,argument){
+            return (argument) ? opposite_action(target,argument) : 
+                opposite_action(target);
+        }.bind(this,opposite_action);
+    },
+    getCallbackForStack: function(argument){
+        return new Event.Behavior.Noun(this,argument);
+    }
 });
 
 Event.Behavior.addVerbs({
-	call: function(callback){
-		callback();
-	},
-	show: function(element){
-		return Event.Behavior.invokeElementMethod(element,'show');
-	},
-	hide: function(element){
-		return Event.Behavior.invokeElementMethod(element,'hide');
-	},
-	remove: function(element){
-		return Event.Behavior.invokeElementMethod(element,'remove');
-	},
-	setStyle: function(element,styles){
-		return Event.Behavior.invokeElementMethod(element,'setStyle',[(typeof(styles) == 'function' ? styles() : styles)]);
-	},
-	addClassName: function(element,class_name){
-		return Event.Behavior.invokeElementMethod(element,'addClassName',[(typeof(class_name) == 'function' ? class_name() : class_name)]);
-	},
-	removeClassName: function(element,class_name){
-		return Event.Behavior.invokeElementMethod(element,'removeClassName',[(typeof(class_name) == 'function' ? class_name() : class_name)]);
-	},
-	setClassName: function(element,class_name){
-		c = (typeof(class_name) == 'function') ? class_name() : class_name;
-		if(typeof(element) == 'function'){
-			return $A(element()).each(function(e){
-				$(e).className = c;
-			});
-		}else
-			return $(element).className = c;
-	},
-	update: function(content,element){
-		return Event.Behavior.invokeElementMethod(element,'update',[(typeof(content) == 'function' ? content() : content)]);
-	},
-	replace: function(content,element){
-		return Event.Behavior.invokeElementMethod(element,'replace',[(typeof(content) == 'function' ? content() : content)]);
-	}
+    call: function(callback){
+        callback();
+    },
+    show: function(element){
+        return Event.Behavior.invokeElementMethod(element,'show');
+    },
+    hide: function(element){
+        return Event.Behavior.invokeElementMethod(element,'hide');
+    },
+    remove: function(element){
+        return Event.Behavior.invokeElementMethod(element,'remove');
+    },
+    setStyle: function(element,styles){
+        return Event.Behavior.invokeElementMethod(element,'setStyle',[(typeof(styles) == 'function' ? styles() : styles)]);
+    },
+    addClassName: function(element,class_name){
+        return Event.Behavior.invokeElementMethod(element,'addClassName',[(typeof(class_name) == 'function' ? class_name() : class_name)]);
+    },
+    removeClassName: function(element,class_name){
+        return Event.Behavior.invokeElementMethod(element,'removeClassName',[(typeof(class_name) == 'function' ? class_name() : class_name)]);
+    },
+    setClassName: function(element,class_name){
+        var c = (typeof(class_name) == 'function') ? class_name() : class_name;
+        if(typeof(element) == 'function'){
+            return $A(element()).each(function(e){
+                $(e).className = c;
+            });
+        }else {
+            c = $(element).className;
+            return c;
+        }
+    },
+    update: function(content,element){
+        return Event.Behavior.invokeElementMethod(element,'update',[(typeof(content) == 'function' ? content() : content)]);
+    },
+    replace: function(content,element){
+        return Event.Behavior.invokeElementMethod(element,'replace',[(typeof(content) == 'function' ? content() : content)]);
+    }
 });
 Event.Behavior.Verbs.show.setOpposite(Event.Behavior.Verbs.hide);
 Event.Behavior.Verbs.hide.setOpposite(Event.Behavior.Verbs.show);
@@ -122,54 +122,51 @@ Event.Behavior.Verbs.removeClassName.setOpposite(Event.Behavior.Verbs.addClassNa
 
 Event.Behavior.Noun = Class.create();
 Object.extend(Event.Behavior.Noun.prototype,{
-	verbs: false,
-	verb: false,
-	argument: false,
-	subject: false,
-	target: false,
-	initialize: function(verb,argument){
-		//this.verbs = $A([]);
-		this.verb = verb;
-		this.argument = argument;
-	},
-	execute: function(){
-		return (this.target)
-			? this.verb.execute(this.target,this.argument)
-			: this.verb.execute(this.argument)
-		;
-	},
-	executeOpposite: function(){
-		return (this.target)
-			? this.verb.executeOpposite(this.target,this.argument)
-			: this.verb.executeOpposite(this.argument)
-		;
-	},
-	when: function(subject){
-		this.subject = subject;
-		return new Event.Behavior.Adjective(this);
-	},
-	getValue: function(){
-		return Try.these(
-			function(){return $(this.subject).getValue();}.bind(this),
-			function(){return $(this.subject).options[$(this.subject).options.selectedIndex].value;}.bind(this),
-			function(){return $(this.subject).value;}.bind(this),
-			function(){return $(this.subject).innerHTML;}.bind(this)
-		);
-	},
-	containsValue: function(match){
-		value = this.getValue();
-		if(typeof(match) == 'function'){
-			return $A(match()).include(value);
-		}else
-			return value.match(match);
-	},
-	setTarget: function(target){
-		this.target = target;
-		return this;
-	},
-	and: function(){
+    verbs: false,
+    verb: false,
+    argument: false,
+    subject: false,
+    target: false,
+    initialize: function(verb,argument){
+        //this.verbs = $A([]);
+        this.verb = verb;
+        this.argument = argument;
+    },
+    execute: function(){
+        return (this.target) ? this.verb.execute(this.target,this.argument) : 
+            this.verb.execute(this.argument);
+    },
+    executeOpposite: function(){
+        return (this.target) ? 
+            this.verb.executeOpposite(this.target,this.argument) : 
+            this.verb.executeOpposite(this.argument);
+    },
+    when: function(subject){
+        this.subject = subject;
+        return new Event.Behavior.Adjective(this);
+    },
+    getValue: function(){
+        return Try.these(
+            function(){return $(this.subject).getValue();}.bind(this),
+            function(){return $(this.subject).options[$(this.subject).options.selectedIndex].value;}.bind(this),
+            function(){return $(this.subject).value;}.bind(this),
+            function(){return $(this.subject).innerHTML;}.bind(this)
+        );
+    },
+    containsValue: function(match){
+        var value = this.getValue();
+        if(typeof(match) == 'function'){
+            return $A(match()).include(value);
+        }else {
+            return value.match(match); }
+    },
+    setTarget: function(target){
+        this.target = target;
+        return this;
+    },
+    and: function(){
 
-	}
+    }
 });
 Event.Behavior.Noun.prototype._with = Event.Behavior.Noun.prototype.setTarget;
 Event.Behavior.Noun.prototype.on = Event.Behavior.Noun.prototype.setTarget;
@@ -179,122 +176,117 @@ Event.Behavior.Noun.prototype.from = Event.Behavior.Noun.prototype.setTarget;
 
 Event.Behavior.Adjective = Class.create();
 Object.extend(Event.Behavior.Adjective.prototype,{
-	noun: false,
-	lastConditionName: '',
-	nextConditionType: 'and',
-	conditions: $A([]),
-	events: $A([]),
-	attached: false,
-	initialize: function(noun){
-		this.conditions = $A([]);
-		this.events = $A([]);
-		this.noun = noun;
-	},
-	attachObserver: function(execute_on_load){
-		if(this.attached){
-			//this may call things multiple times, but is the only way to gaurentee correct state on startup
-			if(execute_on_load)
-				this.execute();
-			return;
-		}
-		this.attached = true;
-		if(typeof(this.noun.subject) == 'function'){
-			$A(this.noun.subject()).each(function(subject){
-				(this.events.length &gt; 0 ? this.events : $A(['change'])).each(function(event_name){
-					(subject.observe ? subject : $(subject)).observe(event_name,function(){
-						this.execute();
-					}.bind(this));
-				}.bind(this));
-			}.bind(this));
-		}else{
-			(this.events.length &gt; 0 ? this.events : $A(['change'])).each(function(event_name){
-				$(this.noun.subject).observe(event_name,function(){
-					this.execute();
-				}.bind(this));
-			}.bind(this));
-		}
-		if(execute_on_load)
-			this.execute();
-	},
-	execute: function(){
-		if(this.match())
-			return this.noun.execute();
-		else if(this.noun.verb.executeOpposite)
-			this.noun.executeOpposite();
-	},
-	attachCondition: function(callback){
-		this.conditions.push([this.nextConditionType,callback.bind(this)]);
-	},
-	match: function(){
-		if(this.conditions.length == 0)
-			return true;
-		else{
-			return this.conditions.inject(new Boolean(),function(bool,condition){
-				return (condition[0] == 'and') ? (bool &amp;&amp; condition[1]()) : (bool || condition[1]());
-			});
-		}
-	},
-	//conditions
-	is: function(item){
-		this.lastConditionName = 'is';
-		this.attachCondition(function(item){
-			return (typeof(item) == 'function' ? item() : item) == this.noun.getValue();
-		}.bind(this,item));
-		this.attachObserver(true);
-		return this;
-	},
-	isNot: function(item){
-		this.lastConditionName = 'isNot';
-		this.attachCondition(function(item){
-			return (typeof(item) == 'function' ? item() : item) != this.noun.getValue();
-		}.bind(this,item));
-		this.attachObserver(true);
-		return this;
-	},
-	contains: function(item){
-		this.lastConditionName = 'contains';
-		this.attachCondition(function(item){
-			return this.noun.containsValue(item);
-		}.bind(this,item));
-		this.attachObserver(true);
-		return this;
-	},
-	within: function(item){
-		this.lastConditionName = 'within';
-		this.attachCondition(function(item){
-			
-		}.bind(this,item));
-		this.attachObserver(true);
-		return this;
-	},
-	//events
-	change: function(){
-		this.nextConditionType = 'and';
-		this.attachObserver(true);
-		return this;
-	},
-	and: function(condition){
-		this.attached = false;
-		this.nextConditionType = 'and';
-		if(condition)
-			this[this.lastConditionName](condition);
-		return this;
-	},
-	or: function(condition){
-		this.attached = false;
-		this.nextConditionType = 'or';
-		if(condition)
-			this[this.lastConditionName](condition);
-		return this;
-	}
+    noun: false,
+    lastConditionName: '',
+    nextConditionType: 'and',
+    conditions: $A([]),
+    events: $A([]),
+    attached: false,
+    initialize: function(noun){
+        this.conditions = $A([]);
+        this.events = $A([]);
+        this.noun = noun;
+    },
+    attachObserver: function(execute_on_load){
+        if(this.attached){
+            //this may call things multiple times, but is the only way to gaurentee correct state on startup
+            if(execute_on_load) {
+                this.execute(); }
+            return;
+        }
+        this.attached = true;
+        if(typeof(this.noun.subject) == 'function'){
+            $A(this.noun.subject()).each(function(subject){
+                (this.events.length &gt; 0 ? this.events : $A(['change'])).each(function(event_name){
+                    (subject.observe ? subject : $(subject)).observe(event_name,function(){
+                        this.execute();
+                    }.bind(this));
+                }.bind(this));
+            }.bind(this));
+        }else{
+            (this.events.length &gt; 0 ? this.events : $A(['change'])).each(function(event_name){
+                $(this.noun.subject).observe(event_name,function(){
+                    this.execute();
+                }.bind(this));
+            }.bind(this));
+        }
+        if(execute_on_load) { this.execute(); }
+    },
+    execute: function(){
+        if(this.match()) { return this.noun.execute(); }
+        else if(this.noun.verb.executeOpposite) { this.noun.executeOpposite(); }
+    },
+    attachCondition: function(callback){
+        this.conditions.push([this.nextConditionType,callback.bind(this)]);
+    },
+    match: function(){
+        if(this.conditions.length === 0) { return true; }
+        else {
+            return this.conditions.inject(false, function (bool,condition) {
+                return (condition[0] === 'or') ? 
+                       (bool &amp;&amp; condition[1]()) : (bool || condition[1]());
+            });
+        }
+    },
+    //conditions
+    is: function(item){
+        this.lastConditionName = 'is';
+        this.attachCondition(function(item){
+            return (typeof(item) == 'function' ? item() : item) == this.noun.getValue();
+        }.bind(this,item));
+        this.attachObserver(true);
+        return this;
+    },
+    isNot: function(item){
+        this.lastConditionName = 'isNot';
+        this.attachCondition(function(item){
+            return (typeof(item) == 'function' ? item() : item) != this.noun.getValue();
+        }.bind(this,item));
+        this.attachObserver(true);
+        return this;
+    },
+    contains: function(item){
+        this.lastConditionName = 'contains';
+        this.attachCondition(function(item){
+            return this.noun.containsValue(item);
+        }.bind(this,item));
+        this.attachObserver(true);
+        return this;
+    },
+    within: function(item){
+        this.lastConditionName = 'within';
+        this.attachCondition(function(item){
+            
+        }.bind(this,item));
+        this.attachObserver(true);
+        return this;
+    },
+    //events
+    change: function(){
+        this.nextConditionType = 'and';
+        this.attachObserver(true);
+        return this;
+    },
+    and: function(condition){
+        this.attached = false;
+        this.nextConditionType = 'and';
+        if(condition) { this[this.lastConditionName](condition); }
+        return this;
+    },
+    or: function(condition){
+        this.attached = false;
+        this.nextConditionType = 'or';
+        if(condition) { this[this.lastConditionName](condition); }
+        return this;
+    }
 });
 
 Event.Behavior.addEvents({
-	losesFocus: 'blur',
-	gainsFocus: 'focus',
-	isClicked: 'click',
-	isDoubleClicked: 'dblclick',
-	keyPressed: 'keypress'
+    losesFocus: 'blur',
+    gainsFocus: 'focus',
+    isClicked: 'click',
+    isDoubleClicked: 'dblclick',
+    keyPressed: 'keypress'
 });
 
 Event.Behavior.Adjective.prototype.is_not = Event.Behavior.Adjective.prototype.isNot;
@@ -303,4 +295,4 @@ Event.Behavior.Adjective.prototype.includes = Event.Behavior.Adjective.prototype
 Event.Behavior.Adjective.prototype.are = Event.Behavior.Adjective.prototype.is;
 Event.Behavior.Adjective.prototype.areNot = Event.Behavior.Adjective.prototype.isNot;
 Event.Behavior.Adjective.prototype.are_not = Event.Behavior.Adjective.prototype.isNot;
-Event.Behavior.Adjective.prototype.changes = Event.Behavior.Adjective.prototype.change;
\ No newline at end of file
+Event.Behavior.Adjective.prototype.changes = Event.Behavior.Adjective.prototype.change;</diff>
      <filename>public/javascripts/event_behavior.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,54 +10,65 @@
 /*global document, Prototype, Class, Event, $ */
 
 if(typeof(Prototype) == &quot;undefined&quot;) {
-	throw &quot;HotKey requires Prototype to be loaded.&quot;; }
+    throw &quot;HotKey requires Prototype to be loaded.&quot;; }
 if(typeof(Object.Event) == &quot;undefined&quot;) {
-	throw &quot;HotKey requires Object.Event to be loaded.&quot;; }
+    throw &quot;HotKey requires Object.Event to be loaded.&quot;; }
 
 var HotKey = Class.create({
-	initialize: function(letter,callback,options){
-		letter = letter.toUpperCase();
-		HotKey.hotkeys.push(this);
-		this.options = Object.extend({
-			element: false,
-			shiftKey: false,
-			altKey: false,
-			ctrlKey: true
-		},options || {});
-		this.letter = letter;
-		this.callback = callback;
-		this.element = $(this.options.element || document);
-		this.handler = function(event){
-			if(!event || (
-				(Event['KEY_' + this.letter] || this.letter.charCodeAt(0)) == event.keyCode &amp;&amp;
-				((!this.options.shiftKey || (this.options.shiftKey &amp;&amp; event.shiftKey)) &amp;&amp;
-					(!this.options.altKey || (this.options.altKey &amp;&amp; event.altKey)) &amp;&amp;
-					(!this.options.ctrlKey || (this.options.ctrlKey &amp;&amp; event.ctrlKey))
-				)
-			)){
-				if(this.notify('beforeCallback',event) === false) {
-					return; }
-				this.callback(event);
-				this.notify('afterCallback',event);
-			}
-		}.bind(this);
-		this.enable();
-	},
-	trigger: function(){
-		this.handler();
-	},
-	enable: function(){
-		this.element.observe('keydown',this.handler);
-	},
-	disable: function(){
-		this.element.stopObserving('keydown',this.handler);
-	},
-	destroy: function(){
-		this.disable();
-		HotKey.hotkeys = HotKey.hotkeys.without(this);
-	}
+    initialize: function(letter,callback,options){
+        letter = letter.toUpperCase();
+        HotKey.hotkeys.push(this);
+        this.options = Object.extend({
+            element: false,
+            shiftKey: false,
+            altKey: false,
+            ctrlKey: true,
+            bubbleEvent : true,
+            fireOnce : false // Keep repeating event while key is pressed?
+        },options || {});
+        this.letter = letter;
+
+        // All custom hotkey events should stop after their custom actions.
+        this.callback = function (event) {
+            if (!(this.options.fireOnce &amp;&amp; this.fired) &amp;&amp; Object.isFunction(callback)) { 
+                callback(event); 
+            }
+            if (!this.options.bubbleEvent) { event.stop(); }
+            this.fired = true;
+        };
+
+        this.element = $(this.options.element || document);
+        this.handler = function(event){
+            if(!event || (
+                (Event['KEY_' + this.letter] || this.letter.charCodeAt(0)) == event.keyCode &amp;&amp;
+                ((!this.options.shiftKey || (this.options.shiftKey &amp;&amp; event.shiftKey)) &amp;&amp;
+                    (!this.options.altKey || (this.options.altKey &amp;&amp; event.altKey)) &amp;&amp;
+                    (!this.options.ctrlKey || (this.options.ctrlKey &amp;&amp; event.ctrlKey))
+                )
+            )){
+                if(this.notify('beforeCallback',event) === false) {
+                    return; }
+                this.callback(event);
+                this.notify('afterCallback',event);
+            }
+        }.bind(this);
+        this.enable();
+    },
+    trigger: function(){
+        this.handler();
+    },
+    enable: function(){
+        this.element.observe('keydown',this.handler);
+    },
+    disable: function(){
+        this.element.stopObserving('keydown',this.handler);
+    },
+    destroy: function(){
+        this.disable();
+        HotKey.hotkeys = HotKey.hotkeys.without(this);
+    }
 });
 Object.extend(HotKey,{
-	hotkeys: []
+    hotkeys: []
 });
 Object.Event.extend(HotKey);</diff>
      <filename>public/javascripts/hotkey.js</filename>
    </modified>
    <modified>
      <diff>@@ -8,349 +8,173 @@
  */
 
 if(typeof(Control) == 'undefined')
-	Control = {};
-	
+    Control = {};
+    
 var $proc = function(proc){
-	return typeof(proc) == 'function' ? proc : function(){return proc};
+    return typeof(proc) == 'function' ? proc : function(){return proc};
 };
 
 var $value = function(value){
-	return typeof(value) == 'function' ? value() : value;
+    return typeof(value) == 'function' ? value() : value;
 };
 
 Object.Event = {
-	extend: function(object){
-		object._objectEventSetup = function(event_name){
-			this._observers = this._observers || {};
-			this._observers[event_name] = this._observers[event_name] || [];
-		};
-		object.observe = function(event_name,observer){
-			if(typeof(event_name) == 'string' &amp;&amp; typeof(observer) != 'undefined'){
-				this._objectEventSetup(event_name);
-				if(!this._observers[event_name].include(observer))
-					this._observers[event_name].push(observer);
-			}else
-				for(var e in event_name)
-					this.observe(e,event_name[e]);
-		};
-		object.stopObserving = function(event_name,observer){
-			this._objectEventSetup(event_name);
-			if(event_name &amp;&amp; observer)
-				this._observers[event_name] = this._observers[event_name].without(observer);
-			else if(event_name)
-				this._observers[event_name] = [];
-			else
-				this._observers = {};
-		};
-		object.observeOnce = function(event_name,outer_observer){
-			var inner_observer = function(){
-				outer_observer.apply(this,arguments);
-				this.stopObserving(event_name,inner_observer);
-			}.bind(this);
-			this._objectEventSetup(event_name);
-			this._observers[event_name].push(inner_observer);
-		};
-		object.notify = function(event_name){
-			this._objectEventSetup(event_name);
-			var collected_return_values = [];
-			var args = $A(arguments).slice(1);
-			try{
-				for(var i = 0; i &lt; this._observers[event_name].length; ++i)
-					collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
-			}catch(e){
-				if(e == $break)
-					return false;
-				else
-					throw e;
-			}
-			return collected_return_values;
-		};
-		if(object.prototype){
-			object.prototype._objectEventSetup = object._objectEventSetup;
-			object.prototype.observe = object.observe;
-			object.prototype.stopObserving = object.stopObserving;
-			object.prototype.observeOnce = object.observeOnce;
-			object.prototype.notify = function(event_name){
-				if(object.notify){
-					var args = $A(arguments).slice(1);
-					args.unshift(this);
-					args.unshift(event_name);
-					object.notify.apply(object,args);
-				}
-				this._objectEventSetup(event_name);
-				var args = $A(arguments).slice(1);
-				var collected_return_values = [];
-				try{
-					if(this.options &amp;&amp; this.options[event_name] &amp;&amp; typeof(this.options[event_name]) == 'function')
-						collected_return_values.push(this.options[event_name].apply(this,args) || null);
-					for(var i = 0; i &lt; this._observers[event_name].length; ++i)
-						collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
-				}catch(e){
-					if(e == $break)
-						return false;
-					else
-						throw e;
-				}
-				return collected_return_values;
-			};
-		}
-	}
+    extend: function(object){
+        object._objectEventSetup = function(event_name){
+            this._observers = this._observers || {};
+            this._observers[event_name] = this._observers[event_name] || [];
+        };
+        object.observe = function(event_name,observer){
+            if(typeof(event_name) == 'string' &amp;&amp; typeof(observer) != 'undefined'){
+                this._objectEventSetup(event_name);
+                if(!this._observers[event_name].include(observer))
+                    this._observers[event_name].push(observer);
+            }else
+                for(var e in event_name)
+                    this.observe(e,event_name[e]);
+        };
+        object.stopObserving = function(event_name,observer){
+            this._objectEventSetup(event_name);
+            if(event_name &amp;&amp; observer)
+                this._observers[event_name] = this._observers[event_name].without(observer);
+            else if(event_name)
+                this._observers[event_name] = [];
+            else
+                this._observers = {};
+        };
+        object.observeOnce = function(event_name,outer_observer){
+            var inner_observer = function(){
+                outer_observer.apply(this,arguments);
+                this.stopObserving(event_name,inner_observer);
+            }.bind(this);
+            this._objectEventSetup(event_name);
+            this._observers[event_name].push(inner_observer);
+        };
+        object.notify = function(event_name){
+            this._objectEventSetup(event_name);
+            var collected_return_values = [];
+            var args = $A(arguments).slice(1);
+            try{
+                for(var i = 0; i &lt; this._observers[event_name].length; ++i)
+                    collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
+            }catch(e){
+                if(e == $break)
+                    return false;
+                else
+                    throw e;
+            }
+            return collected_return_values;
+        };
+        if(object.prototype){
+            object.prototype._objectEventSetup = object._objectEventSetup;
+            object.prototype.observe = object.observe;
+            object.prototype.stopObserving = object.stopObserving;
+            object.prototype.observeOnce = object.observeOnce;
+            object.prototype.notify = function(event_name){
+                if(object.notify){
+                    var args = $A(arguments).slice(1);
+                    args.unshift(this);
+                    args.unshift(event_name);
+                    object.notify.apply(object,args);
+                }
+                this._objectEventSetup(event_name);
+                var args = $A(arguments).slice(1);
+                var collected_return_values = [];
+                try{
+                    if(this.options &amp;&amp; this.options[event_name] &amp;&amp; typeof(this.options[event_name]) == 'function')
+                        collected_return_values.push(this.options[event_name].apply(this,args) || null);
+                    for(var i = 0; i &lt; this._observers[event_name].length; ++i)
+                        collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
+                }catch(e){
+                    if(e == $break)
+                        return false;
+                    else
+                        throw e;
+                }
+                return collected_return_values;
+            };
+        }
+    }
 };
 
 /* Begin Core Extensions */
 
 //Element.observeOnce
 Element.addMethods({
-	observeOnce: function(element,event_name,outer_callback){
-		var inner_callback = function(){
-			outer_callback.apply(this,arguments);
-			Element.stopObserving(element,event_name,inner_callback);
-		};
-		Element.observe(element,event_name,inner_callback);
-	}
-});
-
-//mouseenter, mouseleave
-//from http://dev.rubyonrails.org/attachment/ticket/8354/event_mouseenter_106rc1.patch
-Object.extend(Event, (function() {
-	var cache = Event.cache;
-
-	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;;
-		//begin extension
-		if(!Prototype.Browser.IE){
-			eventName = {
-				mouseenter: 'mouseover',
-				mouseleave: 'mouseout'
-			}[eventName] || eventName;
-		}
-		//end extension
-		return eventName;
-	}
-
-	function getCacheForID(id) {
-		return cache[id] = cache[id] || { };
-	}
-
-	function getWrappersForEventName(id, eventName) {
-		var c = getCacheForID(id);
-		return c[eventName] = c[eventName] || [];
-	}
-
-	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 wrapper = function(event) {
-			if (!Event || !Event.extend ||
-				(event.eventName &amp;&amp; event.eventName != eventName))
-					return false;
-
-			Event.extend(event);
-			handler.call(element, event);
-		};
-		
-		//begin extension
-		if(!(Prototype.Browser.IE) &amp;&amp; ['mouseenter','mouseleave'].include(eventName)){
-			wrapper = wrapper.wrap(function(proceed,event) {	
-				var rel = event.relatedTarget;
-				var cur = event.currentTarget;			 
-				if(rel &amp;&amp; rel.nodeType == Node.TEXT_NODE)
-					rel = rel.parentNode;	  
-				if(rel &amp;&amp; rel != cur &amp;&amp; !rel.descendantOf(cur))	  
-					return proceed(event);   
-			});	 
-		}
-		//end extension
-
-		wrapper.handler = handler;
-		c.push(wrapper);
-		return wrapper;
-	}
-
-	function findWrapper(id, eventName, handler) {
-		var c = getWrappersForEventName(id, eventName);
-		return c.find(function(wrapper) { return wrapper.handler == handler });
-	}
-
-	function destroyWrapper(id, eventName, handler) {
-		var c = getCacheForID(id);
-		if (!c[eventName]) return false;
-		c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
-	}
-
-	function destroyCache() {
-		for (var id in cache)
-			for (var eventName in cache[id])
-				cache[id][eventName] = null;
-	}
-
-	if (window.attachEvent) {
-		window.attachEvent(&quot;onunload&quot;, destroyCache);
-	}
-
-	return {
-		observe: function(element, eventName, handler) {
-			element = $(element);
-			var name = getDOMEventName(eventName);
-
-			var wrapper = createWrapper(element, eventName, handler);
-			if (!wrapper) return element;
-
-			if (element.addEventListener) {
-				element.addEventListener(name, wrapper, false);
-			} else {
-				element.attachEvent(&quot;on&quot; + name, wrapper);
-			}
-
-			return element;
-		},
-
-		stopObserving: function(element, eventName, handler) {
-			element = $(element);
-			var id = getEventID(element), name = getDOMEventName(eventName);
-
-			if (!handler &amp;&amp; eventName) {
-				getWrappersForEventName(id, eventName).each(function(wrapper) {
-					element.stopObserving(eventName, wrapper.handler);
-				});
-				return element;
-
-			} else if (!eventName) {
-				Object.keys(getCacheForID(id)).each(function(eventName) {
-					element.stopObserving(eventName);
-				});
-				return element;
-			}
-
-			var wrapper = findWrapper(id, eventName, handler);
-			if (!wrapper) return element;
-
-			if (element.removeEventListener) {
-				element.removeEventListener(name, wrapper, false);
-			} else {
-				element.detachEvent(&quot;on&quot; + name, wrapper);
-			}
-
-			destroyWrapper(id, eventName, handler);
-
-			return element;
-		},
-
-		fire: function(element, eventName, memo) {
-			element = $(element);
-			if (element == document &amp;&amp; document.createEvent &amp;&amp; !element.dispatchEvent)
-				element = document.documentElement;
-
-			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;;
-			}
-
-			event.eventName = eventName;
-			event.memo = memo || { };
-
-			if (document.createEvent) {
-				element.dispatchEvent(event);
-			} else {
-				element.fireEvent(event.eventType, event);
-			}
-
-			return Event.extend(event);
-		}
-	};
-})());
-
-Object.extend(Event, Event.Methods);
-
-Element.addMethods({
-	fire:			Event.fire,
-	observe:		Event.observe,
-	stopObserving:	Event.stopObserving
-});
-
-Object.extend(document, {
-	fire:			Element.Methods.fire.methodize(),
-	observe:		Element.Methods.observe.methodize(),
-	stopObserving:	Element.Methods.stopObserving.methodize()
+    observeOnce: function(element,event_name,outer_callback){
+        var inner_callback = function(){
+            outer_callback.apply(this,arguments);
+            Element.stopObserving(element,event_name,inner_callback);
+        };
+        Element.observe(element,event_name,inner_callback);
+    }
 });
 
 //mouse:wheel
 (function(){
-	function wheel(event){
-		var delta;
-		// normalize the delta
-		if(event.wheelDelta) // IE &amp; Opera
-			delta = event.wheelDelta / 120;
-		else if (event.detail) // W3C
-			delta =- event.detail / 3;
-		if(!delta)
-			return;
-		var custom_event = Event.element(event).fire('mouse:wheel',{
-			delta: delta
-		});
-		if(custom_event.stopped){
-			Event.stop(event);
-			return false;
-		}
-	}
-	document.observe('mousewheel',wheel);
-	document.observe('DOMMouseScroll',wheel);
+    function wheel(event){
+        var delta, element, custom_event;
+        // normalize the delta
+        if (event.wheelDelta) { // IE &amp; Opera
+            delta = event.wheelDelta / 120;
+        } else if (event.detail) { // W3C
+            delta =- event.detail / 3;
+        }
+        if (!delta) { return; }
+        element = Event.extend(event).target;
+        element = Element.extend(element.nodeType === Node.TEXT_NODE ? element.parentNode : element);
+        custom_event = element.fire('mouse:wheel',{ delta: delta });
+        if (custom_event.stopped) {
+            Event.stop(event);
+            return false;
+        }
+    }
+    document.observe('mousewheel',wheel);
+    document.observe('DOMMouseScroll',wheel);
 })();
 
 /* End Core Extensions */
 
 //from PrototypeUI
 var IframeShim = Class.create({
-	initialize: function() {
-		this.element = new Element('iframe',{
-			style: 'position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);display:none',
-			src: 'javascript:void(0);',
-			frameborder: 0 
-		});
-		$(document.body).insert(this.element);
-	},
-	hide: function() {
-		this.element.hide();
-		return this;
-	},
-	show: function() {
-		this.element.show();
-		return this;
-	},
-	positionUnder: function(element) {
-		var element = $(element);
-		var offset = element.cumulativeOffset();
-		var dimensions = element.getDimensions();
-		this.element.setStyle({
-			left: offset[0] + 'px',
-			top: offset[1] + 'px',
-			width: dimensions.width + 'px',
-			height: dimensions.height + 'px',
-			zIndex: element.getStyle('zIndex') - 1
-		}).show();
-		return this;
-	},
-	setBounds: function(bounds) {
-		for(prop in bounds)
-			bounds[prop] += 'px';
-		this.element.setStyle(bounds);
-		return this;
-	},
-	destroy: function() {
-		if(this.element)
-			this.element.remove();
-		return this;
-	}
-});
\ No newline at end of file
+    initialize: function() {
+        this.element = new Element('iframe',{
+            style: 'position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);display:none',
+            src: 'javascript:void(0);',
+            frameborder: 0 
+        });
+        $(document.body).insert(this.element);
+    },
+    hide: function() {
+        this.element.hide();
+        return this;
+    },
+    show: function() {
+        this.element.show();
+        return this;
+    },
+    positionUnder: function(element) {
+        var element = $(element);
+        var offset = element.cumulativeOffset();
+        var dimensions = element.getDimensions();
+        this.element.setStyle({
+            left: offset[0] + 'px',
+            top: offset[1] + 'px',
+            width: dimensions.width + 'px',
+            height: dimensions.height + 'px',
+            zIndex: element.getStyle('zIndex') - 1
+        }).show();
+        return this;
+    },
+    setBounds: function(bounds) {
+        for(prop in bounds)
+            bounds[prop] += 'px';
+        this.element.setStyle(bounds);
+        return this;
+    },
+    destroy: function() {
+        if(this.element)
+            this.element.remove();
+        return this;
+    }
+});</diff>
      <filename>public/javascripts/livepipe.js</filename>
    </modified>
    <modified>
      <diff>@@ -7,91 +7,96 @@
  * @require prototype.js, livepipe.js
  */
 
-if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Control.ProgressBar requires Prototype to be loaded.&quot;;
-if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Control.ProgressBar requires Object.Event to be loaded.&quot;;
+/*global document, Prototype, Ajax, Class, PeriodicalExecuter, $, $A, Control */
+
+if(typeof(Prototype) == &quot;undefined&quot;) {
+    throw &quot;Control.ProgressBar requires Prototype to be loaded.&quot;; }
+if(typeof(Object.Event) == &quot;undefined&quot;) {
+    throw &quot;Control.ProgressBar requires Object.Event to be loaded.&quot;; }
 
 Control.ProgressBar = Class.create({
-	initialize: function(container,options){
-		this.progress = 0;
-		this.executer = false;
-		this.active = false;
-		this.poller = false;
-		this.container = $(container);
-		this.containerWidth = this.container.getDimensions().width - (parseInt(this.container.getStyle('border-right-width').replace(/px/,'')) + parseInt(this.container.getStyle('border-left-width').replace(/px/,'')));
-		this.progressContainer = $(document.createElement('div'));
-		this.progressContainer.setStyle({
-			width: this.containerWidth + 'px',
-			height: '100%',
-			position: 'absolute',
-			top: '0px',
-			right: '0px'
-		});
-		this.container.appendChild(this.progressContainer);
-		this.options = {
-			afterChange: Prototype.emptyFunction,
-			interval: 0.25,
-			step: 1,
-			classNames: {
-				active: 'progress_bar_active',
-				inactive: 'progress_bar_inactive'
-			}
-		};
-		Object.extend(this.options,options || {});
-		this.container.addClassName(this.options.classNames.inactive);
-		this.active = false;
-	},
-	setProgress: function(value){
-		this.progress = value;
-		this.draw();
-		if(this.progress &gt;= 100)
-			this.stop(false);
-		this.notify('afterChange',this.progress,this.active);
-	},
-	poll: function(url,interval){
-		this.active = true;
-		this.poller = new PeriodicalExecuter(function(){
-			new Ajax.Request(url,{
-				onSuccess: function(request){
-					this.setProgress(parseInt(request.responseText));
-					if(!this.active)
-						this.poller.stop();
-				}.bind(this)
-			});
-		}.bind(this),interval || 3);
-	},
-	start: function(){
-		this.active = true;
-		this.container.removeClassName(this.options.classNames.inactive);
-		this.container.addClassName(this.options.classNames.active);
-		this.executer = new PeriodicalExecuter(this.step.bind(this,this.options.step),this.options.interval);
-	},
-	stop: function(reset){
-		this.active = false;
-		if(this.executer)
-			this.executer.stop();
-		this.container.removeClassName(this.options.classNames.active);
-		this.container.addClassName(this.options.classNames.inactive);
-		if(typeof(reset) == 'undefined' || reset == true)
-			this.reset();
-	},
-	step: function(amount){
-		this.active = true;
-		this.setProgress(Math.min(100,this.progress + amount));
-	},
-	reset: function(){
-		this.active = false;
-		this.setProgress(0);
-	},
-	draw: function(){
-		this.progressContainer.setStyle({
-			width: (this.containerWidth - Math.floor((parseInt(this.progress) / 100) * this.containerWidth)) + 'px'
-		});
-	},
-	notify: function(event_name){
-		if(this.options[event_name])
-			return [this.options[event_name].apply(this.options[event_name],$A(arguments).slice(1))];
-	}
+    initialize: function(container,options){
+        this.progress = 0;
+        this.executer = false;
+        this.active = false;
+        this.poller = false;
+        this.container = $(container);
+        this.containerWidth = this.container.getDimensions().width - (parseInt(this.container.getStyle('border-right-width').replace(/px/,''), 10) + parseInt(this.container.getStyle('border-left-width').replace(/px/,''), 10));
+        this.progressContainer = $(document.createElement('div'));
+        this.progressContainer.setStyle({
+            width: this.containerWidth + 'px',
+            height: '100%',
+            position: 'absolute',
+            top: '0px',
+            right: '0px'
+        });
+        this.container.appendChild(this.progressContainer);
+        this.options = {
+            afterChange: Prototype.emptyFunction,
+            interval: 0.25,
+            step: 1,
+            classNames: {
+                active: 'progress_bar_active',
+                inactive: 'progress_bar_inactive'
+            }
+        };
+        Object.extend(this.options,options || {});
+        this.container.addClassName(this.options.classNames.inactive);
+        this.active = false;
+    },
+    setProgress: function(value){
+        this.progress = value;
+        this.draw();
+        if(this.progress &gt;= 100) {
+            this.stop(false); }
+        this.notify('afterChange',this.progress,this.active);
+    },
+    poll: function (url, interval, ajaxOptions){
+        // Extend the passed ajax options and success callback with our own.
+        ajaxOptions = ajaxOptions || {};
+        var success = ajaxOptions.onSuccess || Prototype.emptyFunction;
+        ajaxOptions.onSuccess = success.wrap(function (callOriginal, request) {
+            this.setProgress(parseInt(request.responseText, 10));
+            if(!this.active) { this.poller.stop(); }
+            callOriginal(request);
+        }).bind(this);
+
+        this.active = true;
+        this.poller = new PeriodicalExecuter(function(){
+            var a = new Ajax.Request(url, ajaxOptions);
+        }.bind(this),interval || 3);
+    },
+    start: function(){
+        this.active = true;
+        this.container.removeClassName(this.options.classNames.inactive);
+        this.container.addClassName(this.options.classNames.active);
+        this.executer = new PeriodicalExecuter(this.step.bind(this,this.options.step),this.options.interval);
+    },
+    stop: function(reset){
+        this.active = false;
+        if(this.executer) {
+            this.executer.stop(); }
+        this.container.removeClassName(this.options.classNames.active);
+        this.container.addClassName(this.options.classNames.inactive);
+        if (typeof reset  === 'undefined' || reset === true) {
+            this.reset(); }
+    },
+    step: function(amount){
+        this.active = true;
+        this.setProgress(Math.min(100,this.progress + amount));
+    },
+    reset: function(){
+        this.active = false;
+        this.setProgress(0);
+    },
+    draw: function(){
+        this.progressContainer.setStyle({
+            width: (this.containerWidth - Math.floor((parseInt(this.progress, 10) / 100) * this.containerWidth)) + 'px'
+        });
+    },
+    notify: function(event_name){
+        if(this.options[event_name]) {
+            return [this.options[event_name].apply(this.options[event_name],$A(arguments).slice(1))]; }
+    }
 });
-Object.Event.extend(Control.ProgressBar);
\ No newline at end of file
+Object.Event.extend(Control.ProgressBar);</diff>
      <filename>public/javascripts/progressbar.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
-/*  Prototype JavaScript framework, version 1.6.0.3
- *  (c) 2005-2008 Sam Stephenson
+/*  Prototype JavaScript framework, version 1.6.1
+ *  (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,26 +7,43 @@
  *--------------------------------------------------------------------------*/
 
 var Prototype = {
-  Version: '1.6.0.3',
-
-  Browser: {
-    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,
-    MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
-  },
+  Version: '1.6.1',
+
+  Browser: (function(){
+    var ua = navigator.userAgent;
+    var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
+    return {
+      IE:             !!window.attachEvent &amp;&amp; !isOpera,
+      Opera:          isOpera,
+      WebKit:         ua.indexOf('AppleWebKit/') &gt; -1,
+      Gecko:          ua.indexOf('Gecko') &gt; -1 &amp;&amp; ua.indexOf('KHTML') === -1,
+      MobileSafari:   /Apple.*Mobile.*Safari/.test(ua)
+    }
+  })(),
 
   BrowserFeatures: {
     XPath: !!document.evaluate,
     SelectorsAPI: !!document.querySelector,
-    ElementExtensions: !!window.HTMLElement,
-    SpecificElementExtensions:
-      document.createElement('div')['__proto__'] &amp;&amp;
-      document.createElement('div')['__proto__'] !==
-        document.createElement('form')['__proto__']
+    ElementExtensions: (function() {
+      var constructor = window.Element || window.HTMLElement;
+      return !!(constructor &amp;&amp; constructor.prototype);
+    })(),
+    SpecificElementExtensions: (function() {
+      if (typeof window.HTMLDivElement !== 'undefined')
+        return true;
+
+      var div = document.createElement('div');
+      var form = document.createElement('form');
+      var isSupported = false;
+
+      if (div['__proto__'] &amp;&amp; (div['__proto__'] !== form['__proto__'])) {
+        isSupported = true;
+      }
+
+      div = form = null;
+
+      return isSupported;
+    })()
   },
 
   ScriptFragment: '&lt;script[^&gt;]*&gt;([\\S\\s]*?)&lt;\/script&gt;',
@@ -40,9 +57,30 @@ 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 subclass() {};
+  function create() {
     var parent = null, properties = $A(arguments);
     if (Object.isFunction(properties[0]))
       parent = properties.shift();
@@ -56,7 +94,6 @@ var Class = {
     klass.subclasses = [];
 
     if (parent) {
-      var subclass = function() { };
       subclass.prototype = parent.prototype;
       klass.prototype = new subclass;
       parent.subclasses.push(klass);
@@ -69,18 +106,19 @@ 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];
@@ -88,7 +126,7 @@ Class.Methods = {
           value.argumentNames().first() == &quot;$super&quot;) {
         var method = value;
         value = (function(m) {
-          return function() { return ancestor[m].apply(this, arguments) };
+          return function() { return ancestor[m].apply(this, arguments); };
         })(property).wrap(method);
 
         value.valueOf = method.valueOf.bind(method);
@@ -99,29 +137,36 @@ Class.Methods = {
 
     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;
-};
+  var _toString = Object.prototype.toString;
 
-Object.extend(Object, {
-  inspect: function(object) {
+  function extend(destination, source) {
+    for (var property in source)
+      destination[property] = source[property];
+    return destination;
+  }
+
+  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':
@@ -132,131 +177,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) {
+  function isElement(object) {
     return !!(object &amp;&amp; object.nodeType == 1);
-  },
+  }
+
+  function isArray(object) {
+    return _toString.call(object) == &quot;[object 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 _toString.call(object) == &quot;[object String]&quot;;
+  }
 
-  isNumber: function(object) {
-    return typeof object == &quot;number&quot;;
-  },
+  function isNumber(object) {
+    return _toString.call(object) == &quot;[object Number]&quot;;
+  }
 
-  isUndefined: function(object) {
-    return typeof object == &quot;undefined&quot;;
+  function isUndefined(object) {
+    return typeof object === &quot;undefined&quot;;
   }
-});
 
-Object.extend(Function.prototype, {
-  argumentNames: function() {
-    var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
+  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);
+  }
+
+  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);
-  },
+  }
 
-  defer: function() {
-    var args = [0.01].concat($A(arguments));
+  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);
     };
   }
-});
+
+  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() + '-' +
@@ -267,30 +361,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;
@@ -319,8 +395,10 @@ var PeriodicalExecuter = Class.create({
       try {
         this.currentlyExecuting = true;
         this.execute();
-      } finally {
         this.currentlyExecuting = false;
+      } catch(e) {
+        this.currentlyExecuting = false;
+        throw e;
       }
     }
   }
@@ -339,10 +417,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)) {
@@ -354,69 +447,64 @@ 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() {
-    return this.replace(/&lt;\/?[^&gt;]+&gt;/gi, '');
-  },
+  function stripTags() {
+    return this.replace(/&lt;\w+(\s+(&quot;[^&quot;]*&quot;|'[^']*'|[^&gt;])+)?&gt;|&lt;\/\w+&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() {
+    return this.replace(/&amp;/g,'&amp;amp;').replace(/&lt;/g,'&amp;lt;').replace(/&gt;/g,'&amp;gt;');
+  }
+
+  function unescapeHTML() {
+    return this.stripTags().replace(/&amp;lt;/g,'&lt;').replace(/&amp;gt;/g,'&gt;').replace(/&amp;amp;/g,'&amp;');
+  }
 
-  unescapeHTML: function() {
-    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 { };
 
@@ -434,22 +522,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];
 
@@ -461,101 +549,117 @@ 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() {
-    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
-  },
+  function underscore() {
+    return this.replace(/::/g, '/')
+               .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
+               .replace(/([a-z\d])([A-Z])/g, '$1_$2')
+               .replace(/-/g, '_')
+               .toLowerCase();
+  }
 
-  dasherize: function() {
-    return this.gsub(/_/,'-');
-  },
+  function dasherize() {
+    return this.replace(/_/g, '-');
+  }
 
-  inspect: function(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);
+  function inspect(useDoubleQuotes) {
+    var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) {
+      if (character in String.specialChar) {
+        return String.specialChar[character];
+      }
+      return '\\u00' + character.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) {
-    return this.sub(filter || Prototype.JSONFilter, '#{1}');
-  },
+  function unfilterJSON(filter) {
+    return this.replace(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) {
-    return new Template(this, pattern).evaluate(object);
   }
-});
 
-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.stripTags().replace(/&amp;amp;/g,'&amp;').replace(/&amp;lt;/g,'&lt;').replace(/&amp;gt;/g,'&gt;');
+  function interpolate(object, pattern) {
+    return new Template(this, pattern).evaluate(object);
   }
-});
-
-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('')
-});
 
-String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
+  return {
+    gsub:           gsub,
+    sub:            sub,
+    scan:           scan,
+    truncate:       truncate,
+    strip:          String.prototype.trim ? String.prototype.trim : 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
+  };
+})());
 
 var Template = Class.create({
   initialize: function(template, pattern) {
@@ -564,11 +668,11 @@ var Template = Class.create({
   },
 
   evaluate: function(object) {
-    if (Object.isFunction(object.toTemplateReplacements))
+    if (object &amp;&amp; Object.isFunction(object.toTemplateReplacements))
       object = object.toTemplateReplacements();
 
     return this.template.gsub(this.pattern, function(match) {
-      if (object == null) return '';
+      if (object == null) return (match[1] + '');
 
       var before = match[1] || '';
       if (before == '\\') return match[2];
@@ -579,7 +683,7 @@ var Template = Class.create({
       if (match == null) return before;
 
       while (match != null) {
-        var comp = match[1].startsWith('[') ? match[2].gsub('\\\\]', ']') : match[1];
+        var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1];
         ctx = ctx[comp];
         if (null == ctx || '' == match[3]) break;
         expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
@@ -594,8 +698,8 @@ Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
 
 var $break = { };
 
-var Enumerable = {
-  each: function(iterator, context) {
+var Enumerable = (function() {
+  function each(iterator, context) {
     var index = 0;
     try {
       this._each(function(value) {
@@ -605,17 +709,17 @@ var Enumerable = {
       if (e != $break) throw e;
     }
     return this;
-  },
+  }
 
-  eachSlice: function(number, iterator, context) {
+  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) {
+  function all(iterator, context) {
     iterator = iterator || Prototype.K;
     var result = true;
     this.each(function(value, index) {
@@ -623,9 +727,9 @@ var Enumerable = {
       if (!result) throw $break;
     });
     return result;
-  },
+  }
 
-  any: function(iterator, context) {
+  function any(iterator, context) {
     iterator = iterator || Prototype.K;
     var result = false;
     this.each(function(value, index) {
@@ -633,18 +737,18 @@ var Enumerable = {
         throw $break;
     });
     return result;
-  },
+  }
 
-  collect: function(iterator, context) {
+  function collect(iterator, context) {
     iterator = iterator || Prototype.K;
     var results = [];
     this.each(function(value, index) {
       results.push(iterator.call(context, value, index));
     });
     return results;
-  },
+  }
 
-  detect: function(iterator, context) {
+  function detect(iterator, context) {
     var result;
     this.each(function(value, index) {
       if (iterator.call(context, value, index)) {
@@ -653,32 +757,32 @@ var Enumerable = {
       }
     });
     return result;
-  },
+  }
 
-  findAll: function(iterator, context) {
+  function findAll(iterator, context) {
     var results = [];
     this.each(function(value, index) {
       if (iterator.call(context, value, index))
         results.push(value);
     });
     return results;
-  },
+  }
 
-  grep: function(filter, iterator, context) {
+  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.call(context, value, index));
     });
     return results;
-  },
+  }
 
-  include: function(object) {
+  function include(object) {
     if (Object.isFunction(this.indexOf))
       if (this.indexOf(object) != -1) return true;
 
@@ -690,31 +794,31 @@ 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) {
+  function inject(memo, iterator, context) {
     this.each(function(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) {
+  function max(iterator, context) {
     iterator = iterator || Prototype.K;
     var result;
     this.each(function(value, index) {
@@ -723,9 +827,9 @@ var Enumerable = {
         result = value;
     });
     return result;
-  },
+  }
 
-  min: function(iterator, context) {
+  function min(iterator, context) {
     iterator = iterator || Prototype.K;
     var result;
     this.each(function(value, index) {
@@ -734,9 +838,9 @@ var Enumerable = {
         result = value;
     });
     return result;
-  },
+  }
 
-  partition: function(iterator, context) {
+  function partition(iterator, context) {
     iterator = iterator || Prototype.K;
     var trues = [], falses = [];
     this.each(function(value, index) {
@@ -744,26 +848,26 @@ var Enumerable = {
         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) {
+  function reject(iterator, context) {
     var results = [];
     this.each(function(value, index) {
       if (!iterator.call(context, value, index))
         results.push(value);
     });
     return results;
-  },
+  }
 
-  sortBy: function(iterator, context) {
+  function sortBy(iterator, context) {
     return this.map(function(value, index) {
       return {
         value: value,
@@ -773,13 +877,13 @@ var Enumerable = {
       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();
@@ -788,130 +892,152 @@ 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();
+  if ('toArray' in Object(iterable)) return iterable.toArray();
   var length = iterable.length || 0, results = new Array(length);
   while (length--) results[length] = iterable[length];
   return results;
 }
 
-if (Prototype.Browser.WebKit) {
-  $A = function(iterable) {
-    if (!iterable) return [];
-    // In Safari, only use the `toArray` method if it's not a NodeList.
-    // A NodeList is a function, has an function `item` property, and a numeric
-    // `length` property. Adapted from Google Doctype.
-    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;
-  };
+function $w(string) {
+  if (!Object.isString(string)) return [];
+  string = string.strip();
+  return string ? string.split(/\s+/) : [];
 }
 
 Array.from = $A;
 
-Object.extend(Array.prototype, Enumerable);
 
-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() {
-    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);
-  },
 
-  size: function() {
+  function clone() {
+    return slice.call(this, 0);
+  }
+
+  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);
@@ -919,205 +1045,270 @@ 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;
-  },
+  }
 
-  times: function(iterator, context) {
-    $R(0, this, true).each(iterator, context);
-    return this;
-  },
+  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,
+    uniq:      uniq,
+    intersect: intersect,
+    clone:     clone,
+    toArray:   clone,
+    size:      size,
+    inspect:   inspect,
+    toJSON:    toJSON
+  });
 
-  toPaddedString: function(length, radix) {
-    var string = this.toString(radix || 10);
-    return '0'.times(length - string.length) + string;
-  },
+  var CONCAT_ARGUMENTS_BUGGY = (function() {
+    return [].concat(arguments)[0][0] !== 1;
+  })(1,2)
 
-  toJSON: function() {
-    return isFinite(this) ? this.toString() : 'null';
-  }
-});
+  if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat;
 
-$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) {
-      // simulating poorly supported hasOwnProperty
-      if (this._object[key] !== Object.prototype[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.inject([], function(results, 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 results.concat(values.map(toQueryPair.curry(key)));
-        } else results.push(toQueryPair(key, values));
-        return results;
-      }).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() {
@@ -1164,7 +1355,6 @@ Ajax.Responders.register({
   onCreate:   function() { Ajax.activeRequestCount++ },
   onComplete: function() { Ajax.activeRequestCount-- }
 });
-
 Ajax.Base = Class.create({
   initialize: function(options) {
     this.options = {
@@ -1186,7 +1376,6 @@ Ajax.Base = Class.create({
       this.options.parameters = this.options.parameters.toObject();
   }
 });
-
 Ajax.Request = Class.create(Ajax.Base, {
   _complete: false,
 
@@ -1202,7 +1391,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';
     }
@@ -1210,7 +1398,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))
@@ -1269,7 +1456,6 @@ Ajax.Request = Class.create(Ajax.Base, {
             headers['Connection'] = 'close';
     }
 
-    // user-defined headers
     if (typeof this.options.requestHeaders == 'object') {
       var extras = this.options.requestHeaders;
 
@@ -1323,7 +1509,6 @@ Ajax.Request = Class.create(Ajax.Base, {
     }
 
     if (state == 'Complete') {
-      // avoid memory leak in MSIE: clean up
       this.transport.onreadystatechange = Prototype.emptyFunction;
     }
   },
@@ -1340,7 +1525,7 @@ Ajax.Request = Class.create(Ajax.Base, {
   getHeader: function(name) {
     try {
       return this.transport.getResponseHeader(name) || null;
-    } catch (e) { return null }
+    } catch (e) { return null; }
   },
 
   evalResponse: function() {
@@ -1360,6 +1545,13 @@ Ajax.Request = Class.create(Ajax.Base, {
 Ajax.Request.Events =
   ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
 
+
+
+
+
+
+
+
 Ajax.Response = Class.create({
   initialize: function(request){
     this.request = request;
@@ -1381,6 +1573,7 @@ Ajax.Response = Class.create({
   },
 
   status:      0,
+
   statusText: '',
 
   getStatus: Ajax.Request.prototype.getStatus,
@@ -1510,6 +1703,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++)
@@ -1537,7 +1733,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,
@@ -1554,13 +1749,30 @@ if (!Node.ELEMENT_NODE) {
   });
 }
 
-(function() {
-  var element = this.Element;
-  this.Element = function(tagName, attributes) {
+
+(function(global) {
+
+  var SETATTRIBUTE_IGNORES_NAME = (function(){
+    var elForm = document.createElement(&quot;form&quot;);
+    var elInput = document.createElement(&quot;input&quot;);
+    var root = document.documentElement;
+    elInput.setAttribute(&quot;name&quot;, &quot;test&quot;);
+    elForm.appendChild(elInput);
+    root.appendChild(elForm);
+    var isBuggy = elForm.elements
+      ? (typeof elForm.elements.test == &quot;undefined&quot;)
+      : null;
+    root.removeChild(elForm);
+    elForm = elInput = null;
+    return isBuggy;
+  })();
+
+  var element = global.Element;
+  global.Element = function(tagName, attributes) {
     attributes = attributes || { };
     tagName = tagName.toLowerCase();
     var cache = Element.cache;
-    if (Prototype.Browser.IE &amp;&amp; attributes.name) {
+    if (SETATTRIBUTE_IGNORES_NAME &amp;&amp; attributes.name) {
       tagName = '&lt;' + tagName + ' name=&quot;' + attributes.name + '&quot;&gt;';
       delete attributes.name;
       return Element.writeAttribute(document.createElement(tagName), attributes);
@@ -1568,11 +1780,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 || { });
-  if (element) this.Element.prototype = element.prototype;
-}).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) {
@@ -1585,6 +1798,7 @@ Element.Methods = {
     return element;
   },
 
+
   hide: function(element) {
     element = $(element);
     element.style.display = 'none';
@@ -1603,15 +1817,89 @@ Element.Methods = {
     return element;
   },
 
-  update: function(element, content) {
-    element = $(element);
-    if (content &amp;&amp; content.toElement) content = content.toElement();
-    if (Object.isElement(content)) return element.update().insert(content);
-    content = Object.toHTML(content);
-    element.innerHTML = content.stripScripts();
-    content.evalScripts.bind(content).defer();
-    return element;
-  },
+  update: (function(){
+
+    var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){
+      var el = document.createElement(&quot;select&quot;),
+          isBuggy = true;
+      el.innerHTML = &quot;&lt;option value=\&quot;test\&quot;&gt;test&lt;/option&gt;&quot;;
+      if (el.options &amp;&amp; el.options[0]) {
+        isBuggy = el.options[0].nodeName.toUpperCase() !== &quot;OPTION&quot;;
+      }
+      el = null;
+      return isBuggy;
+    })();
+
+    var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){
+      try {
+        var el = document.createElement(&quot;table&quot;);
+        if (el &amp;&amp; el.tBodies) {
+          el.innerHTML = &quot;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;test&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&quot;;
+          var isBuggy = typeof el.tBodies[0] == &quot;undefined&quot;;
+          el = null;
+          return isBuggy;
+        }
+      } catch (e) {
+        return true;
+      }
+    })();
+
+    var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () {
+      var s = document.createElement(&quot;script&quot;),
+          isBuggy = false;
+      try {
+        s.appendChild(document.createTextNode(&quot;&quot;));
+        isBuggy = !s.firstChild ||
+          s.firstChild &amp;&amp; s.firstChild.nodeType !== 3;
+      } catch (e) {
+        isBuggy = true;
+      }
+      s = null;
+      return isBuggy;
+    })();
+
+    function update(element, content) {
+      element = $(element);
+
+      if (content &amp;&amp; content.toElement)
+        content = content.toElement();
+
+      if (Object.isElement(content))
+        return element.update().insert(content);
+
+      content = Object.toHTML(content);
+
+      var tagName = element.tagName.toUpperCase();
+
+      if (tagName === 'SCRIPT' &amp;&amp; SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) {
+        element.text = content;
+        return element;
+      }
+
+      if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) {
+        if (tagName in Element._insertionTranslations.tags) {
+          while (element.firstChild) {
+            element.removeChild(element.firstChild);
+          }
+          Element._getContentFromAnonymousElement(tagName, content.stripScripts())
+            .each(function(node) {
+              element.appendChild(node)
+            });
+        }
+        else {
+          element.innerHTML = content.stripScripts();
+        }
+      }
+      else {
+        element.innerHTML = content.stripScripts();
+      }
+
+      content.evalScripts.bind(content).defer();
+      return element;
+    }
+
+    return update;
+  })(),
 
   replace: function(element, content) {
     element = $(element);
@@ -1696,11 +1984,11 @@ Element.Methods = {
   },
 
   ancestors: function(element) {
-    return $(element).recursivelyCollect('parentNode');
+    return Element.recursivelyCollect(element, 'parentNode');
   },
 
   descendants: function(element) {
-    return $(element).select(&quot;*&quot;);
+    return Element.select(element, &quot;*&quot;);
   },
 
   firstDescendant: function(element) {
@@ -1717,16 +2005,17 @@ Element.Methods = {
   },
 
   previousSiblings: function(element) {
-    return $(element).recursivelyCollect('previousSibling');
+    return Element.recursivelyCollect(element, 'previousSibling');
   },
 
   nextSiblings: function(element) {
-    return $(element).recursivelyCollect('nextSibling');
+    return Element.recursivelyCollect(element, 'nextSibling');
   },
 
   siblings: function(element) {
     element = $(element);
-    return element.previousSiblings().reverse().concat(element.nextSiblings());
+    return Element.previousSiblings(element).reverse()
+      .concat(Element.nextSiblings(element));
   },
 
   match: function(element, selector) {
@@ -1738,22 +2027,22 @@ Element.Methods = {
   up: function(element, expression, index) {
     element = $(element);
     if (arguments.length == 1) return $(element.parentNode);
-    var ancestors = element.ancestors();
+    var ancestors = Element.ancestors(element);
     return Object.isNumber(expression) ? ancestors[expression] :
       Selector.findElement(ancestors, expression, index);
   },
 
   down: function(element, expression, index) {
     element = $(element);
-    if (arguments.length == 1) return element.firstDescendant();
-    return Object.isNumber(expression) ? element.descendants()[expression] :
+    if (arguments.length == 1) return Element.firstDescendant(element);
+    return Object.isNumber(expression) ? Element.descendants(element)[expression] :
       Element.select(element, expression)[index || 0];
   },
 
   previous: function(element, expression, index) {
     element = $(element);
     if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
-    var previousSiblings = element.previousSiblings();
+    var previousSiblings = Element.previousSiblings(element);
     return Object.isNumber(expression) ? previousSiblings[expression] :
       Selector.findElement(previousSiblings, expression, index);
   },
@@ -1761,27 +2050,28 @@ Element.Methods = {
   next: function(element, expression, index) {
     element = $(element);
     if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
-    var nextSiblings = element.nextSiblings();
+    var nextSiblings = Element.nextSiblings(element);
     return Object.isNumber(expression) ? nextSiblings[expression] :
       Selector.findElement(nextSiblings, expression, index);
   },
 
-  select: function() {
-    var args = $A(arguments), element = $(args.shift());
+
+  select: function(element) {
+    var args = Array.prototype.slice.call(arguments, 1);
     return Selector.findChildElements(element, args);
   },
 
-  adjacent: function() {
-    var args = $A(arguments), element = $(args.shift());
+  adjacent: function(element) {
+    var args = Array.prototype.slice.call(arguments, 1);
     return Selector.findChildElements(element.parentNode, args).without(element);
   },
 
   identify: function(element) {
     element = $(element);
-    var id = element.readAttribute('id'), self = arguments.callee;
+    var id = Element.readAttribute(element, 'id');
     if (id) return id;
-    do { id = 'anonymous_element_' + self.counter++ } while ($(id));
-    element.writeAttribute('id', id);
+    do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id));
+    Element.writeAttribute(element, 'id', id);
     return id;
   },
 
@@ -1820,11 +2110,11 @@ Element.Methods = {
   },
 
   getHeight: function(element) {
-    return $(element).getDimensions().height;
+    return Element.getDimensions(element).height;
   },
 
   getWidth: function(element) {
-    return $(element).getDimensions().width;
+    return Element.getDimensions(element).width;
   },
 
   classNames: function(element) {
@@ -1840,7 +2130,7 @@ Element.Methods = {
 
   addClassName: function(element, className) {
     if (!(element = $(element))) return;
-    if (!element.hasClassName(className))
+    if (!Element.hasClassName(element, className))
       element.className += (element.className ? ' ' : '') + className;
     return element;
   },
@@ -1854,11 +2144,10 @@ Element.Methods = {
 
   toggleClassName: function(element, className) {
     if (!(element = $(element))) return;
-    return element[element.hasClassName(className) ?
-      'removeClassName' : 'addClassName'](className);
+    return Element[Element.hasClassName(element, className) ?
+      'removeClassName' : 'addClassName'](element, className);
   },
 
-  // removes whitespace-only text node children
   cleanWhitespace: function(element) {
     element = $(element);
     var node = element.firstChild;
@@ -1892,7 +2181,7 @@ Element.Methods = {
 
   scrollTo: function(element) {
     element = $(element);
-    var pos = element.cumulativeOffset();
+    var pos = Element.cumulativeOffset(element);
     window.scrollTo(pos[0], pos[1]);
     return element;
   },
@@ -1940,18 +2229,17 @@ Element.Methods = {
 
   getDimensions: function(element) {
     element = $(element);
-    var display = element.getStyle('display');
+    var display = Element.getStyle(element, '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;
@@ -1967,8 +2255,6 @@ 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 (Prototype.Browser.Opera) {
         element.style.top = 0;
         element.style.left = 0;
@@ -2034,10 +2320,9 @@ Element.Methods = {
 
   absolutize: function(element) {
     element = $(element);
-    if (element.getStyle('position') == 'absolute') return element;
-    // Position.prepare(); // To be done manually by Scripty when it needs it.
+    if (Element.getStyle(element, 'position') == 'absolute') return element;
 
-    var offsets = element.positionedOffset();
+    var offsets = Element.positionedOffset(element);
     var top     = offsets[1];
     var left    = offsets[0];
     var width   = element.clientWidth;
@@ -2058,8 +2343,7 @@ Element.Methods = {
 
   relativize: function(element) {
     element = $(element);
-    if (element.getStyle('position') == 'relative') return element;
-    // Position.prepare(); // To be done manually by Scripty when it needs it.
+    if (Element.getStyle(element, 'position') == 'relative') return element;
 
     element.style.position = 'relative';
     var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
@@ -2101,7 +2385,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;
 
@@ -2128,28 +2411,22 @@ Element.Methods = {
       offsetLeft: 0
     }, arguments[2] || { });
 
-    // find page position of source
     source = $(source);
-    var p = source.viewportOffset();
+    var p = Element.viewportOffset(source);
 
-    // 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();
+      parent = Element.getOffsetParent(element);
+      delta = Element.viewportOffset(parent);
     }
 
-    // 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';
@@ -2158,10 +2435,9 @@ Element.Methods = {
   }
 };
 
-Element.Methods.identify.counter = 1;
-
 Object.extend(Element.Methods, {
   getElementsBySelector: Element.Methods.select,
+
   childElements: Element.Methods.immediateDescendants
 });
 
@@ -2182,11 +2458,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()])
@@ -2219,12 +2492,9 @@ 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);
-      // IE throws an error if element is not in document
       try { element.offsetParent }
       catch(e) { return $(document.body) }
       var position = element.getStyle('position');
@@ -2244,8 +2514,6 @@ else if (Prototype.Browser.IE) {
         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 });
@@ -2306,36 +2574,92 @@ else if (Prototype.Browser.IE) {
     return element;
   };
 
-  Element._attributeTranslations = {
-    read: {
-      names: {
-        'class': 'className',
-        'for':   'htmlFor'
-      },
-      values: {
-        _getAttr: function(element, attribute) {
-          return element.getAttribute(attribute, 2);
-        },
-        _getAttrNode: function(element, attribute) {
-          var node = element.getAttributeNode(attribute);
-          return node ? node.value : &quot;&quot;;
-        },
-        _getEv: function(element, attribute) {
-          attribute = element.getAttribute(attribute);
-          return attribute ? attribute.toString().slice(23, -2) : null;
-        },
-        _flag: function(element, attribute) {
-          return $(element).hasAttribute(attribute) ? attribute : null;
-        },
-        style: function(element) {
-          return element.style.cssText.toLowerCase();
+  Element._attributeTranslations = (function(){
+
+    var classProp = 'className';
+    var forProp = 'for';
+
+    var el = document.createElement('div');
+
+    el.setAttribute(classProp, 'x');
+
+    if (el.className !== 'x') {
+      el.setAttribute('class', 'x');
+      if (el.className === 'x') {
+        classProp = 'class';
+      }
+    }
+    el = null;
+
+    el = document.createElement('label');
+    el.setAttribute(forProp, 'x');
+    if (el.htmlFor !== 'x') {
+      el.setAttribute('htmlFor', 'x');
+      if (el.htmlFor === 'x') {
+        forProp = 'htmlFor';
+      }
+    }
+    el = null;
+
+    return {
+      read: {
+        names: {
+          'class':      classProp,
+          'className':  classProp,
+          'for':        forProp,
+          'htmlFor':    forProp
         },
-        title: function(element) {
-          return element.title;
+        values: {
+          _getAttr: function(element, attribute) {
+            return element.getAttribute(attribute);
+          },
+          _getAttr2: function(element, attribute) {
+            return element.getAttribute(attribute, 2);
+          },
+          _getAttrNode: function(element, attribute) {
+            var node = element.getAttributeNode(attribute);
+            return node ? node.value : &quot;&quot;;
+          },
+          _getEv: (function(){
+
+            var el = document.createElement('div');
+            el.onclick = Prototype.emptyFunction;
+            var value = el.getAttribute('onclick');
+            var f;
+
+            if (String(value).indexOf('{') &gt; -1) {
+              f = function(element, attribute) {
+                attribute = element.getAttribute(attribute);
+                if (!attribute) return null;
+                attribute = attribute.toString();
+                attribute = attribute.split('{')[1];
+                attribute = attribute.split('}')[0];
+                return attribute.strip();
+              };
+            }
+            else if (value === '') {
+              f = function(element, attribute) {
+                attribute = element.getAttribute(attribute);
+                if (!attribute) return null;
+                return attribute.strip();
+              };
+            }
+            el = null;
+            return f;
+          })(),
+          _flag: function(element, attribute) {
+            return $(element).hasAttribute(attribute) ? attribute : null;
+          },
+          style: function(element) {
+            return element.style.cssText.toLowerCase();
+          },
+          title: function(element) {
+            return element.title;
+          }
         }
       }
     }
-  };
+  })();
 
   Element._attributeTranslations.write = {
     names: Object.extend({
@@ -2363,8 +2687,8 @@ else if (Prototype.Browser.IE) {
 
   (function(v) {
     Object.extend(v, {
-      href:        v._getAttr,
-      src:         v._getAttr,
+      href:        v._getAttr2,
+      src:         v._getAttr2,
       type:        v._getAttr,
       action:      v._getAttrNode,
       disabled:    v._flag,
@@ -2391,6 +2715,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)) {
@@ -2420,9 +2764,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 {
@@ -2438,30 +2779,7 @@ 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);
-
-    if (content &amp;&amp; content.toElement) content = content.toElement();
-    if (Object.isElement(content)) return element.update().insert(content);
-
-    content = Object.toHTML(content);
-    var tagName = element.tagName.toUpperCase();
-
-    if (tagName in Element._insertionTranslations.tags) {
-      $A(element.childNodes).each(function(node) { element.removeChild(node) });
-      Element._getContentFromAnonymousElement(tagName, content.stripScripts())
-        .each(function(node) { element.appendChild(node) });
-    }
-    else element.innerHTML = content.stripScripts();
-
-    content.evalScripts.bind(content).defer();
-    return element;
-  };
-}
-
-if ('outerHTML' in document.createElement('div')) {
+if ('outerHTML' in document.documentElement) {
   Element.Methods.replace = function(element, content) {
     element = $(element);
 
@@ -2529,12 +2847,13 @@ Element._insertionTranslations = {
 };
 
 (function() {
-  Object.extend(this.tags, {
-    THEAD: this.tags.TBODY,
-    TFOOT: this.tags.TBODY,
-    TH:    this.tags.TD
+  var tags = Element._insertionTranslations.tags;
+  Object.extend(tags, {
+    THEAD: tags.TBODY,
+    TFOOT: tags.TBODY,
+    TH:    tags.TD
   });
-}).call(Element._insertionTranslations);
+})();
 
 Element.Methods.Simulated = {
   hasAttribute: function(element, attribute) {
@@ -2548,41 +2867,81 @@ 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)
+
+  function checkDeficiency(tagName) {
+    if (typeof window.Element != 'undefined') {
+      var proto = window.Element.prototype;
+      if (proto) {
+        var id = '_' + (Math.random()+'').slice(2);
+        var el = document.createElement(tagName);
+        proto[id] = 'x';
+        var isBuggy = (el[id] !== 'x');
+        delete proto[id];
+        el = null;
+        return isBuggy;
+      }
+    }
+    return false;
+  }
+
+  function extendElementWith(element, methods) {
+    for (var property in methods) {
+      var value = methods[property];
+      if (Object.isFunction(value) &amp;&amp; !(property in element))
+        element[property] = value.methodize();
+    }
+  }
+
+  var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object');
+
+  if (Prototype.BrowserFeatures.SpecificElementExtensions) {
+    if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) {
+      return function(element) {
+        if (element &amp;&amp; typeof element._extendedByPrototype == 'undefined') {
+          var t = element.tagName;
+          if (t &amp;&amp; (/^(?:object|applet|embed)$/i.test(t))) {
+            extendElementWith(element, Element.Methods);
+            extendElementWith(element, Element.Methods.Simulated);
+            extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]);
+          }
+        }
+        return element;
+      }
+    }
     return Prototype.K;
+  }
 
   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.toUpperCase(), property, value;
+        tagName = element.tagName.toUpperCase();
 
-    // extend methods for specific tags
     if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
 
-    for (property in methods) {
-      value = methods[property];
-      if (Object.isFunction(value) &amp;&amp; !(property in element))
-        element[property] = value.methodize();
-    }
+    extendElementWith(element, methods);
 
     element._extendedByPrototype = Prototype.emptyFunction;
     return element;
 
   }, {
     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);
@@ -2661,14 +3020,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) {
@@ -2686,38 +3049,109 @@ Element.addMethods = function(methods) {
   Element.cache = { };
 };
 
-document.viewport = {
-  getDimensions: function() {
-    var dimensions = { }, B = Prototype.Browser;
-    $w('width height').each(function(d) {
-      var D = d.capitalize();
-      if (B.WebKit &amp;&amp; !document.evaluate) {
-        // Safari &lt;3.0 needs self.innerWidth/Height
-        dimensions[d] = self['inner' + D];
-      } else if (B.Opera &amp;&amp; parseFloat(window.opera.version()) &lt; 9.5) {
-        // Opera &lt;9.5 needs document.body.clientWidth/Height
-        dimensions[d] = document.body['client' + D]
-      } else {
-        dimensions[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
+};
+
+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(element).update(key);
+    } else {
+      Element.getStorage(element).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;
+  },
+
+  clone: function(element, deep) {
+    if (!(element = $(element))) return;
+    var clone = element.cloneNode(deep);
+    clone._prototypeUID = void 0;
+    if (deep) {
+      var descendants = Element.select(clone, '*'),
+          i = descendants.length;
+      while (i--) {
+        descendants[i]._prototypeUID = void 0;
+      }
+    }
+    return Element.extend(clone);
+  }
+});
 /* 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. */
@@ -2738,31 +3172,52 @@ var Selector = Class.create({
 
   },
 
-  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;;
 
-    // XPath can't do namespaced attributes, nor can it read
-    // the &quot;checked&quot; property from DOM nodes
-    if ((/(\[[\w-]*?:|:checked)/).test(e))
-      return false;
+        var result = document.evaluate(xpath, el, null,
+          XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
 
-    return true;
-  },
+        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;
+
+      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');
 
-    // Make sure the browser treats the selector as valid. Test on an
-    // isolated element to minimize cost of this check.
     try {
       Selector._div.querySelector(this.expression);
     } catch(e) {
@@ -2774,7 +3229,7 @@ var Selector = Class.create({
 
   compileMatcher: function() {
     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];
@@ -2786,11 +3241,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;
         }
@@ -2804,7 +3260,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;
@@ -2813,10 +3269,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;
         }
@@ -2833,11 +3290,9 @@ var Selector = Class.create({
 
     switch (this.mode) {
       case 'selectorsAPI':
-        // querySelectorAll queries document-wide, then filters to descendants
-        // of the context element. That's not what we want.
-        // Add an explicit context to the selector if necessary.
         if (root !== document) {
           var oldId = root.id, id = $(root).identify();
+          id = id.replace(/([\.:])/g, &quot;\\$1&quot;);
           e = &quot;#&quot; + id + &quot; &quot; + e;
         }
 
@@ -2856,21 +3311,18 @@ var Selector = Class.create({
     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);
           }
         }
@@ -2897,6 +3349,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: { },
 
@@ -2946,14 +3413,15 @@ Object.extend(Selector, {
       '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;
@@ -3021,25 +3489,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]+:)?[\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();
@@ -3064,15 +3527,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++)
@@ -3080,15 +3540,32 @@ Object.extend(Selector, {
       return nodes;
     },
 
-    unmark: function(nodes) {
-      for (var i = 0, node; node = nodes[i]; i++)
-        node._countedByPrototype = undefined;
-      return nodes;
-    },
+    unmark: (function(){
+
+      var PROPERTIES_ATTRIBUTES_MAP = (function(){
+        var el = document.createElement('div'),
+            isBuggy = false,
+            propName = '_countedByPrototype',
+            value = 'x'
+        el[propName] = value;
+        isBuggy = (el.getAttribute(propName) === value);
+        el = null;
+        return isBuggy;
+      })();
+
+      return PROPERTIES_ATTRIBUTES_MAP ?
+        function(nodes) {
+          for (var i = 0, node; node = nodes[i]; i++)
+            node.removeAttribute('_countedByPrototype');
+          return nodes;
+        } :
+        function(nodes) {
+          for (var i = 0, node; node = nodes[i]; i++)
+            node._countedByPrototype = void 0;
+          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) {
@@ -3102,19 +3579,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++)
@@ -3158,13 +3633,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));
@@ -3180,8 +3653,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') {
@@ -3293,7 +3777,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) {
@@ -3302,7 +3785,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';
@@ -3336,7 +3818,6 @@ 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) continue;
         results.push(node);
       }
@@ -3379,8 +3860,6 @@ Object.extend(Selector, {
     '^=': 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.endsWith(v); },
-    '*=': function(nv, v) { return nv.include(v); },
     '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
     '|=': function(nv, v) { return ('-' + (nv || &quot;&quot;).toUpperCase() +
      '-').include('-' + (v || &quot;&quot;).toUpperCase() + '-'); }
@@ -3423,19 +3902,10 @@ 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');
-      return nodes;
     }
   });
 }
@@ -3443,9 +3913,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;
   },
 
@@ -3460,7 +3932,6 @@ var Form = {
         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);
           }
@@ -3480,13 +3951,18 @@ Form.Methods = {
   },
 
   getElements: function(form) {
-    return $A($(form).getElementsByTagName('*')).inject([],
-      function(elements, child) {
-        if (Form.Element.Serializers[child.tagName.toLowerCase()])
-          elements.push(Element.extend(child));
-        return elements;
-      }
-    );
+    var elements = $(form).getElementsByTagName('*'),
+        element,
+        arr = [ ],
+        serializers = Form.Element.Serializers;
+    for (var i = 0; element = elements[i]; i++) {
+      arr.push(element);
+    }
+    return arr.inject([], function(elements, child) {
+      if (serializers[child.tagName.toLowerCase()])
+        elements.push(Element.extend(child));
+      return elements;
+    })
   },
 
   getInputs: function(form, typeName, name) {
@@ -3526,7 +4002,7 @@ Form.Methods = {
     }).sortBy(function(element) { return element.tabIndex }).first();
 
     return firstByIndex ? firstByIndex : elements.find(function(element) {
-      return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+      return /^(?:input|select|textarea)$/i.test(element.tagName);
     });
   },
 
@@ -3557,6 +4033,7 @@ Form.Methods = {
 
 /*--------------------------------------------------------------------------*/
 
+
 Form.Element = {
   focus: function(element) {
     $(element).focus();
@@ -3570,6 +4047,7 @@ Form.Element = {
 };
 
 Form.Element.Methods = {
+
   serialize: function(element) {
     element = $(element);
     if (!element.disabled &amp;&amp; element.name) {
@@ -3610,7 +4088,7 @@ Form.Element.Methods = {
     try {
       element.focus();
       if (element.select &amp;&amp; (element.tagName.toLowerCase() != 'input' ||
-          !['button', 'reset', 'submit'].include(element.type)))
+          !(/^(?:button|reset|submit)$/i.test(element.type))))
         element.select();
     } catch (e) { }
     return element;
@@ -3632,6 +4110,7 @@ Form.Element.Methods = {
 /*--------------------------------------------------------------------------*/
 
 var Field = Form.Element;
+
 var $F = Form.Element.Methods.getValue;
 
 /*--------------------------------------------------------------------------*/
@@ -3694,13 +4173,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);
@@ -3782,354 +4261,441 @@ 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() {
+
+  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: {}
+  };
 
-Event.Methods = (function() {
-  var isButton;
+  var docEl = document.documentElement;
+  var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl
+    &amp;&amp; 'onmouseleave' in docEl;
 
+  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) },
-
-    element: function(event) {
-      event = Event.extend(event);
-
-      var node          = event.target,
-          type          = event.type,
-          currentTarget = event.currentTarget;
-
-      if (currentTarget &amp;&amp; currentTarget.tagName) {
-        // Firefox screws up the &quot;click&quot; event when moving between radio buttons
-        // via arrow keys. It also screws up the &quot;load&quot; and &quot;error&quot; events on images,
-        // reporting the document as the target instead of the original image.
-        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 isLeftClick(event)   { return _isButton(event, 0) }
 
-    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 isMiddleClick(event) { return _isButton(event, 1) }
 
-    pointer: function(event) {
-      var docElement = document.documentElement,
-      body = document.body || { scrollLeft: 0, scrollTop: 0 };
-      return {
-        x: event.pageX || (event.clientX +
-          (docElement.scrollLeft || body.scrollLeft) -
-          (docElement.clientLeft || 0)),
-        y: event.pageY || (event.clientY +
-          (docElement.scrollTop || body.scrollTop) -
-          (docElement.clientTop || 0))
-      };
-    },
+  function isRightClick(event)  { return _isButton(event, 2) }
+
+  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 getEventID(element) {
-    if (element._prototypeEventID) return element._prototypeEventID[0];
-    arguments.callee.id = arguments.callee.id || 1;
-    return element._prototypeEventID = [++arguments.callee.id];
-  }
+  function _createResponder(element, eventName, handler) {
+    var registry = Element.retrieve(element, 'prototype_event_registry');
 
-  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)) {
+      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 (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED &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;
+    }
   }
 
+  var CACHE = [];
 
-  // Internet Explorer needs to remove event handlers on page unload
-  // in order to avoid memory leaks.
-  if (window.attachEvent) {
-    window.attachEvent(&quot;onunload&quot;, destroyCache);
-  }
+  if (Prototype.Browser.IE)
+    window.attachEvent('onunload', _destroyCache);
 
-  // Safari has a dummy event handler on page unload so that it won't
-  // use its bfcache. Safari &lt;= 3.1 has an issue with restoring the &quot;document&quot;
-  // object when page is returned to via the back button using its bfcache.
-  if (Prototype.Browser.WebKit) {
+  if (Prototype.Browser.WebKit)
     window.addEventListener('unload', Prototype.emptyFunction, false);
+
+
+  var _getDOMEventName = Prototype.K;
+
+  if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) {
+    _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;
@@ -4158,16 +4724,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
@@ -4179,7 +4738,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);
@@ -4206,7 +4764,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')
@@ -4217,7 +4774,6 @@ var Position = {
         element.offsetWidth;
   },
 
-  // Deprecation layer -- use newer Element methods now (1.5.2).
 
   cumulativeOffset: Element.Methods.cumulativeOffset,
 
@@ -4316,5 +4872,3 @@ Element.ClassNames.prototype = {
 Object.extend(Element.ClassNames.prototype, Enumerable);
 
 /*--------------------------------------------------------------------------*/
-
-Element.addMethods();
\ No newline at end of file</diff>
      <filename>public/javascripts/prototype.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,146 +10,147 @@
 /*global document, Prototype, Ajax, Class, Event, $, $A, $F, $R, $break, Control */
 
 if(typeof(Prototype) == &quot;undefined&quot;) {
-	throw &quot;Control.Rating requires Prototype to be loaded.&quot;; }
+    throw &quot;Control.Rating requires Prototype to be loaded.&quot;; }
 if(typeof(Object.Event) == &quot;undefined&quot;) {
-	throw &quot;Control.Rating requires Object.Event to be loaded.&quot;; }
+    throw &quot;Control.Rating requires Object.Event to be loaded.&quot;; }
 
 Control.Rating = Class.create({
-	initialize: function(container,options){
-		Control.Rating.instances.push(this);
-		this.value = false;
-		this.links = [];
-		this.container = $(container);
-		this.container.update('');
-		this.options = {
-			min: 1,
-			max: 5,
-			rated: false,
-			input: false,
-			reverse: false,
-			capture: true,
-			multiple: false,
-			classNames: {
-				off: 'rating_off',
-				half: 'rating_half',
-				on: 'rating_on',
-				selected: 'rating_selected'
-			},
-			updateUrl: false,
-			updateParameterName: 'value',
-			afterChange: Prototype.emptyFunction
-		};
-		Object.extend(this.options,options || {});
-		if(this.options.value){
-			this.value = this.options.value;
-			delete this.options.value;
-		}
-		if(this.options.input){
-			this.options.input = $(this.options.input);
-			this.options.input.observe('change',function(input){
-				this.setValueFromInput(input);
-			}.bind(this,this.options.input));
-			this.setValueFromInput(this.options.input,true);
-		}
-		var range = $R(this.options.min,this.options.max);
-		(this.options.reverse ? $A(range).reverse() : range).each(function(i){
-			var link = this.buildLink(i);
-			this.container.appendChild(link);
-			this.links.push(link);
-		}.bind(this));
-		this.setValue(this.value || this.options.min - 1,false,true);
-	},
-	buildLink: function(rating){
-		var link = $(document.createElement('a'));
-		link.value = rating;
-		if(this.options.multiple || (!this.options.rated &amp;&amp; !this.options.multiple)){
-			link.href = '';
-			link.onmouseover = this.mouseOver.bind(this,link);
-			link.onmouseout = this.mouseOut.bind(this,link);
-			link.onclick = this.click.bindAsEventListener(this,link);
-		}else{
-			link.style.cursor = 'default';
-			link.observe('click',function(event){
-				Event.stop(event);
-				return false;
-			}.bindAsEventListener(this));
-		}
-		link.addClassName(this.options.classNames.off);
-		return link;
-	},
-	disable: function(){
-		this.links.each(function(link){
-			link.onmouseover = Prototype.emptyFunction;
-			link.onmouseout = Prototype.emptyFunction;
-			link.onclick = Prototype.emptyFunction;
-			link.observe('click',function(event){
-				Event.stop(event);
-				return false;
-			}.bindAsEventListener(this));
-			link.style.cursor = 'default';
-		}.bind(this));
-	},
-	setValueFromInput: function(input,prevent_callbacks){
+    initialize: function(container,options){
+        Control.Rating.instances.push(this);
+        this.value = false;
+        this.links = [];
+        this.container = $(container);
+        this.container.update('');
+        this.options = {
+            min: 1,
+            max: 5,
+            rated: false,
+            input: false,
+            reverse: false,
+            capture: true,
+            multiple: false,
+            classNames: {
+                off: 'rating_off',
+                half: 'rating_half',
+                on: 'rating_on',
+                selected: 'rating_selected'
+            },
+            updateUrl: false,
+            updateParameterName: 'value',
+            updateOptions : {},
+            afterChange: Prototype.emptyFunction
+        };
+        Object.extend(this.options,options || {});
+        if(this.options.value){
+            this.value = this.options.value;
+            delete this.options.value;
+        }
+        if(this.options.input){
+            this.options.input = $(this.options.input);
+            this.options.input.observe('change',function(input){
+                this.setValueFromInput(input);
+            }.bind(this,this.options.input));
+            this.setValueFromInput(this.options.input,true);
+        }
+        var range = $R(this.options.min,this.options.max);
+        (this.options.reverse ? $A(range).reverse() : range).each(function(i){
+            var link = this.buildLink(i);
+            this.container.appendChild(link);
+            this.links.push(link);
+        }.bind(this));
+        this.setValue(this.value || this.options.min - 1,false,true);
+    },
+    buildLink: function(rating){
+        var link = $(document.createElement('a'));
+        link.value = rating;
+        if(this.options.multiple || (!this.options.rated &amp;&amp; !this.options.multiple)){
+            link.href = '';
+            link.onmouseover = this.mouseOver.bind(this,link);
+            link.onmouseout = this.mouseOut.bind(this,link);
+            link.onclick = this.click.bindAsEventListener(this,link);
+        }else{
+            link.style.cursor = 'default';
+            link.observe('click',function(event){
+                Event.stop(event);
+                return false;
+            }.bindAsEventListener(this));
+        }
+        link.addClassName(this.options.classNames.off);
+        return link;
+    },
+    disable: function(){
+        this.links.each(function(link){
+            link.onmouseover = Prototype.emptyFunction;
+            link.onmouseout = Prototype.emptyFunction;
+            link.onclick = Prototype.emptyFunction;
+            link.observe('click',function(event){
+                Event.stop(event);
+                return false;
+            }.bindAsEventListener(this));
+            link.style.cursor = 'default';
+        }.bind(this));
+    },
+    setValueFromInput: function(input,prevent_callbacks){
         this.setValue($F(input),true,prevent_callbacks);
-	},
-	setValue: function(value,force_selected,prevent_callbacks){
-		this.value = value;
-		if(this.options.input){
-			if(this.options.input.options){
-				$A(this.options.input.options).each(function(option,i){
-					if(option.value == this.value){
-						this.options.input.options.selectedIndex = i;
-						throw $break;
-					}
-				}.bind(this));
-			}else {
-				this.options.input.value = this.value; }
-		}
-		this.render(this.value,force_selected);
-		if(!prevent_callbacks){
-			if(this.options.updateUrl){
-				var params = {}, a;
-				params[this.options.updateParameterName] = this.value;
-				a = new Ajax.Request(this.options.updateUrl,{
-					parameters: params
-				});
-			}
-			this.notify('afterChange',this.value);
-		}
-	},
-	render: function(rating,force_selected){
-		(this.options.reverse ? this.links.reverse() : this.links).each(function(link,i){
-			if(link.value &lt;= Math.ceil(rating)){
-				link.className = this.options.classNames[link.value &lt;= rating ? 'on' : 'half'];
-				if(this.options.rated || force_selected) {
-					link.addClassName(this.options.classNames.selected); }
-			}else {
-				link.className = this.options.classNames.off; }
-		}.bind(this));
-	},
-	mouseOver: function(link){
-		this.render(link.value,true);
-	},
-	mouseOut: function(link){
-		this.render(this.value);
-	},
-	click: function(event,link){
-		this.options.rated = true;
-		this.setValue((link.value ? link.value : link),true);
-		if(!this.options.multiple) {
-			this.disable(); }
-		if(this.options.capture){
-			Event.stop(event);
-			return false;
-		}
-	}
+    },
+    setValue: function(value,force_selected,prevent_callbacks){
+        this.value = value;
+        if(this.options.input){
+            if(this.options.input.options){
+                $A(this.options.input.options).each(function(option,i){
+                    if(option.value == this.value){
+                        this.options.input.options.selectedIndex = i;
+                        throw $break;
+                    }
+                }.bind(this));
+            }else {
+                this.options.input.value = this.value; }
+        }
+        this.render(this.value,force_selected);
+        if(!prevent_callbacks){
+            if(this.options.updateUrl){
+                var params = {}, a;
+                params[this.options.updateParameterName] = this.value;
+                a = new Ajax.Request(this.options.updateUrl, Object.extend(
+                    this.options.updateOptions, { parameters : params }
+                ));
+            }
+            this.notify('afterChange',this.value);
+        }
+    },
+    render: function(rating,force_selected){
+        (this.options.reverse ? this.links.reverse() : this.links).each(function(link,i){
+            if(link.value &lt;= Math.ceil(rating)){
+                link.className = this.options.classNames[link.value &lt;= rating ? 'on' : 'half'];
+                if(this.options.rated || force_selected) {
+                    link.addClassName(this.options.classNames.selected); }
+            }else {
+                link.className = this.options.classNames.off; }
+        }.bind(this));
+    },
+    mouseOver: function(link){
+        this.render(link.value,true);
+    },
+    mouseOut: function(link){
+        this.render(this.value);
+    },
+    click: function(event,link){
+        this.options.rated = true;
+        this.setValue((link.value ? link.value : link),true);
+        if(!this.options.multiple) {
+            this.disable(); }
+        if(this.options.capture){
+            Event.stop(event);
+            return false;
+        }
+    }
 });
 Object.extend(Control.Rating,{
-	instances: [],
-	findByElementId: function(id){
-		return Control.Rating.instances.find(function(instance){
-			return (instance.container.id &amp;&amp; instance.container.id == id);
-		});
-	}
+    instances: [],
+    findByElementId: function(id){
+        return Control.Rating.instances.find(function(instance){
+            return (instance.container.id &amp;&amp; instance.container.id == id);
+        });
+    }
 });
 Object.Event.extend(Control.Rating);</diff>
      <filename>public/javascripts/rating.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
-// script.aculo.us scriptaculous.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
+// script.aculo.us scriptaculous.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
 
-// Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
-// 
+// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
+//
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // &quot;Software&quot;), to deal in the Software without restriction, including
@@ -9,7 +9,7 @@
 // distribute, sublicense, and/or sell copies of the Software, and to
 // permit persons to whom the Software is furnished to do so, subject to
 // the following conditions:
-// 
+//
 // The above copyright notice and this permission notice shall be
 // included in all copies or substantial portions of the Software.
 //
@@ -24,35 +24,45 @@
 // For details, see the script.aculo.us web site: http://script.aculo.us/
 
 var Scriptaculous = {
-  Version: '1.8.0',
+  Version: '1.8.3',
   require: function(libraryName) {
-    // inserting via DOM fails in Safari 2.0, so brute force approach
-    document.write('&lt;script type=&quot;text/javascript&quot; src=&quot;'+libraryName+'&quot;&gt;&lt;\/script&gt;');
+    try{
+      // inserting via DOM fails in Safari 2.0, so brute force approach
+      document.write('&lt;script type=&quot;text/javascript&quot; src=&quot;'+libraryName+'&quot;&gt;&lt;\/script&gt;');
+    } catch(e) {
+      // for xhtml+xml served content, fall back to DOM methods
+      var script = document.createElement('script');
+      script.type = 'text/javascript';
+      script.src = libraryName;
+      document.getElementsByTagName('head')[0].appendChild(script);
+    }
   },
-  REQUIRED_PROTOTYPE: '1.6.0',
+  REQUIRED_PROTOTYPE: '1.6.0.3',
   load: function() {
-    function convertVersionString(versionString){
-      var r = versionString.split('.');
-      return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
+    function convertVersionString(versionString) {
+      var v = versionString.replace(/_.*|\./g, '');
+      v = parseInt(v + '0'.times(4-v.length));
+      return versionString.indexOf('_') &gt; -1 ? v-1 : v;
     }
- 
-    if((typeof Prototype=='undefined') || 
-       (typeof Element == 'undefined') || 
+
+    if((typeof Prototype=='undefined') ||
+       (typeof Element == 'undefined') ||
        (typeof Element.Methods=='undefined') ||
-       (convertVersionString(Prototype.Version) &lt; 
+       (convertVersionString(Prototype.Version) &lt;
         convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE)))
        throw(&quot;script.aculo.us requires the Prototype JavaScript framework &gt;= &quot; +
         Scriptaculous.REQUIRED_PROTOTYPE);
-    
-    $A(document.getElementsByTagName(&quot;script&quot;)).findAll( function(s) {
-      return (s.src &amp;&amp; s.src.match(/scriptaculous\.js(\?.*)?$/))
-    }).each( function(s) {
-      var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
-      var includes = s.src.match(/\?.*load=([a-z,]*)/);
+
+    var js = /scriptaculous\.js(\?.*)?$/;
+    $$('head script[src]').findAll(function(s) {
+      return s.src.match(js);
+    }).each(function(s) {
+      var path = s.src.replace(js, ''),
+      includes = s.src.match(/\?.*load=([a-z,]*)/);
       (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each(
        function(include) { Scriptaculous.require(path+include+'.js') });
     });
   }
-}
+};
 
 Scriptaculous.load();
\ No newline at end of file</diff>
      <filename>public/javascripts/scriptaculous.js</filename>
    </modified>
    <modified>
      <diff>@@ -8,140 +8,140 @@
  */
 
 if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Control.ScrollBar requires Prototype to be loaded.&quot;;
+    throw &quot;Control.ScrollBar requires Prototype to be loaded.&quot;;
 if(typeof(Control.Slider) == &quot;undefined&quot;)
-	throw &quot;Control.ScrollBar requires Control.Slider to be loaded.&quot;;
+    throw &quot;Control.ScrollBar requires Control.Slider to be loaded.&quot;;
 if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Control.ScrollBar requires Object.Event to be loaded.&quot;;
+    throw &quot;Control.ScrollBar requires Object.Event to be loaded.&quot;;
 
 Control.ScrollBar = Class.create({
-	initialize: function(container,track,options){
-		this.enabled = false;
-		this.notificationTimeout = false;
-		this.container = $(container);
-		this.boundMouseWheelEvent = this.onMouseWheel.bindAsEventListener(this);
-		this.boundResizeObserver = this.onWindowResize.bind(this);
-		this.track = $(track);
-		this.handle = this.track.firstDescendant();
-		this.options = Object.extend({
-			active_class_name: 'scrolling',
-			apply_active_class_name_to: this.container,
-			notification_timeout_length: 125,
-			handle_minimum_height: 25,
-			scroll_to_smoothing: 0.01,
-			scroll_to_steps: 15,
-			proportional: true,
-			slider_options: {}
-		},options || {});
-		this.slider = new Control.Slider(this.handle,this.track,Object.extend({
-			axis: 'vertical',
-			onSlide: this.onChange.bind(this),
-			onChange: this.onChange.bind(this)
-		},this.options.slider_options));
-		this.recalculateLayout();
-		Event.observe(window,'resize',this.boundResizeObserver);
-		this.handle.observe('mousedown',function(){
-		    if(this.auto_sliding_executer)
-    			this.auto_sliding_executer.stop();
-		}.bind(this));
-	},
-	destroy: function(){
-		Event.stopObserving(window,'resize',this.boundResizeObserver);
-	},
-	enable: function(){
-		this.enabled = true;
-		this.container.observe('mouse:wheel',this.boundMouseWheelEvent);
-		this.slider.setEnabled();
-		this.track.show();
-		if(this.options.active_class_name)
-			$(this.options.apply_active_class_name_to).addClassName(this.options.active_class_name);
-		this.notify('enabled');
-	},
-	disable: function(){
-		this.enabled = false;
-		this.container.stopObserving('mouse:wheel',this.boundMouseWheelEvent);
-		this.slider.setDisabled();
-		this.track.hide();
-		if(this.options.active_class_name)
-			$(this.options.apply_active_class_name_to).removeClassName(this.options.active_class_name);
-		this.notify('disabled');
-		this.reset();
-	},
-	reset: function(){
-		this.slider.setValue(0);
-	},
-	recalculateLayout: function(){
-		if(this.container.scrollHeight &lt;= this.container.offsetHeight)
-			this.disable();
-		else{
-			this.slider.trackLength = this.slider.maximumOffset() - this.slider.minimumOffset();
-			if(this.options.proportional){
-				this.handle.style.height = Math.max(this.container.offsetHeight * (this.container.offsetHeight / this.container.scrollHeight),this.options.handle_minimum_height) + 'px';
-				this.slider.handleLength = this.handle.style.height.replace(/px/,'');
-			}
-			this.enable();
-		}
-	},
-	onWindowResize: function(){
-		this.recalculateLayout();
-		this.scrollBy(0);
-	},
-	onMouseWheel: function(event){
-	    if(this.auto_sliding_executer)
-			this.auto_sliding_executer.stop();
-		this.slider.setValueBy(-(event.memo.delta / 20)); //put in math to account for the window height
-		event.stop();
-		return false;
-	},
-	onChange: function(value){
-		this.container.scrollTop = Math.round(value / this.slider.maximum * (this.container.scrollHeight - this.container.offsetHeight));
-		if(this.notification_timeout)
-			window.clearTimeout(this.notificationTimeout);
-		this.notificationTimeout = window.setTimeout(function(){
-			this.notify('change',value);
-		}.bind(this),this.options.notification_timeout_length);
-	},
-	getCurrentMaximumDelta: function(){
-		return this.slider.maximum * (this.container.scrollHeight - this.container.offsetHeight);
-	},
-	getDeltaToElement: function(element){
-		return this.slider.maximum * ((element.positionedOffset().top + (element.getHeight() / 2)) - (this.container.getHeight() / 2));
-	},
-	scrollTo: function(y,animate){
-		var current_maximum_delta = this.getCurrentMaximumDelta();
-		if(y == 'top')
-			y = 0;
-		else if(y == 'bottom')
-			y = current_maximum_delta;
-		else if(typeof(y) != &quot;number&quot;)
-			y = this.getDeltaToElement($(y));
-		if(this.enabled){
-			y = Math.max(0,Math.min(y,current_maximum_delta));
-			if(this.auto_sliding_executer)
-				this.auto_sliding_executer.stop();
-			var target_value = y / current_maximum_delta;
-			var original_slider_value = this.slider.value;
-			var delta = (target_value - original_slider_value) * current_maximum_delta;
-			if(animate){
-				this.auto_sliding_executer = new PeriodicalExecuter(function(){
-					if(Math.round(this.slider.value * 100) / 100 &lt; Math.round(target_value * 100) / 100 || Math.round(this.slider.value * 100) / 100 &gt; Math.round(target_value * 100) / 100){
-						this.scrollBy(delta / this.options.scroll_to_steps);
-					}else{
-						this.auto_sliding_executer.stop();
-						this.auto_sliding_executer = null;
-						if(typeof(animate) == &quot;function&quot;)
-							animate();
-					}			
-				}.bind(this),this.options.scroll_to_smoothing);
-			}else
-				this.scrollBy(delta);
-		}else if(typeof(animate) == &quot;function&quot;)
-			animate();
-	},
-	scrollBy: function(y){
-		if(!this.enabled)
-			return false;
-		this.slider.setValueBy(y / this.getCurrentMaximumDelta());
-	}
+    initialize: function(container,track,options){
+        this.enabled = false;
+        this.notificationTimeout = false;
+        this.container = $(container);
+        this.boundMouseWheelEvent = this.onMouseWheel.bindAsEventListener(this);
+        this.boundResizeObserver = this.onWindowResize.bind(this);
+        this.track = $(track);
+        this.handle = this.track.firstDescendant();
+        this.options = Object.extend({
+            active_class_name: 'scrolling',
+            apply_active_class_name_to: this.container,
+            notification_timeout_length: 125,
+            handle_minimum_height: 25,
+            scroll_to_smoothing: 0.01,
+            scroll_to_steps: 15,
+            proportional: true,
+            slider_options: {}
+        },options || {});
+        this.slider = new Control.Slider(this.handle,this.track,Object.extend({
+            axis: 'vertical',
+            onSlide: this.onChange.bind(this),
+            onChange: this.onChange.bind(this)
+        },this.options.slider_options));
+        this.recalculateLayout();
+        Event.observe(window,'resize',this.boundResizeObserver);
+        this.handle.observe('mousedown',function(){
+            if(this.auto_sliding_executer)
+                this.auto_sliding_executer.stop();
+        }.bind(this));
+    },
+    destroy: function(){
+        Event.stopObserving(window,'resize',this.boundResizeObserver);
+    },
+    enable: function(){
+        this.enabled = true;
+        this.container.observe('mouse:wheel',this.boundMouseWheelEvent);
+        this.slider.setEnabled();
+        this.track.show();
+        if(this.options.active_class_name)
+            $(this.options.apply_active_class_name_to).addClassName(this.options.active_class_name);
+        this.notify('enabled');
+    },
+    disable: function(){
+        this.enabled = false;
+        this.container.stopObserving('mouse:wheel',this.boundMouseWheelEvent);
+        this.slider.setDisabled();
+        this.track.hide();
+        if(this.options.active_class_name)
+            $(this.options.apply_active_class_name_to).removeClassName(this.options.active_class_name);
+        this.notify('disabled');
+        this.reset();
+    },
+    reset: function(){
+        this.slider.setValue(0);
+    },
+    recalculateLayout: function(){
+        if(this.container.scrollHeight &lt;= this.container.offsetHeight)
+            this.disable();
+        else{
+            this.enable();
+            this.slider.trackLength = this.slider.maximumOffset() - this.slider.minimumOffset();
+            if(this.options.proportional){
+                this.handle.style.height = Math.max(this.container.offsetHeight * (this.container.offsetHeight / this.container.scrollHeight),this.options.handle_minimum_height) + 'px';
+                this.slider.handleLength = this.handle.style.height.replace(/px/,'');
+            }
+        }
+    },
+    onWindowResize: function(){
+        this.recalculateLayout();
+        this.scrollBy(0);
+    },
+    onMouseWheel: function(event){
+        if(this.auto_sliding_executer)
+            this.auto_sliding_executer.stop();
+        this.slider.setValueBy(-(event.memo.delta / 20)); //put in math to account for the window height
+        event.stop();
+        return false;
+    },
+    onChange: function(value){
+        this.container.scrollTop = Math.round(value / this.slider.maximum * (this.container.scrollHeight - this.container.offsetHeight));
+        if(this.notification_timeout)
+            window.clearTimeout(this.notificationTimeout);
+        this.notificationTimeout = window.setTimeout(function(){
+            this.notify('change',value);
+        }.bind(this),this.options.notification_timeout_length);
+    },
+    getCurrentMaximumDelta: function(){
+        return this.slider.maximum * (this.container.scrollHeight - this.container.offsetHeight);
+    },
+    getDeltaToElement: function(element){
+        return this.slider.maximum * ((element.positionedOffset().top + (element.getHeight() / 2)) - (this.container.getHeight() / 2));
+    },
+    scrollTo: function(y,animate){
+        var current_maximum_delta = this.getCurrentMaximumDelta();
+        if(y == 'top')
+            y = 0;
+        else if(y == 'bottom')
+            y = current_maximum_delta;
+        else if(typeof(y) != &quot;number&quot;)
+            y = this.getDeltaToElement($(y));
+        if(this.enabled){
+            y = Math.max(0,Math.min(y,current_maximum_delta));
+            if(this.auto_sliding_executer)
+                this.auto_sliding_executer.stop();
+            var target_value = y / current_maximum_delta;
+            var original_slider_value = this.slider.value;
+            var delta = (target_value - original_slider_value) * current_maximum_delta;
+            if(animate){
+                this.auto_sliding_executer = new PeriodicalExecuter(function(){
+                    if(Math.round(this.slider.value * 100) / 100 &lt; Math.round(target_value * 100) / 100 || Math.round(this.slider.value * 100) / 100 &gt; Math.round(target_value * 100) / 100){
+                        this.scrollBy(delta / this.options.scroll_to_steps);
+                    }else{
+                        this.auto_sliding_executer.stop();
+                        this.auto_sliding_executer = null;
+                        if(typeof(animate) == &quot;function&quot;)
+                            animate();
+                    }            
+                }.bind(this),this.options.scroll_to_smoothing);
+            }else
+                this.scrollBy(delta);
+        }else if(typeof(animate) == &quot;function&quot;)
+            animate();
+    },
+    scrollBy: function(y){
+        if(!this.enabled)
+            return false;
+        this.slider.setValueBy(y / this.getCurrentMaximumDelta());
+    }
 });
-Object.Event.extend(Control.ScrollBar);
\ No newline at end of file
+Object.Event.extend(Control.ScrollBar);</diff>
      <filename>public/javascripts/scrollbar.js</filename>
    </modified>
    <modified>
      <diff>@@ -7,451 +7,453 @@
  * @require prototype.js, effects.js, draggable.js, livepipe.js
  */
 
-if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Control.Selection requires Prototype to be loaded.&quot;;
-if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Control.Selection requires Object.Event to be loaded.&quot;;
+/*global window, document, Prototype, Element, Event, $, $$, $break, Control, Draggable */
+
+if(typeof(Prototype) == &quot;undefined&quot;) {
+    throw &quot;Control.Selection requires Prototype to be loaded.&quot;; }
+if(typeof(Object.Event) == &quot;undefined&quot;) {
+    throw &quot;Control.Selection requires Object.Event to be loaded.&quot;; }
 
 Control.Selection = {
-	options: {
-		resize_layout_timeout: 125,
-		selected: Prototype.emptyFunction,
-		deselected: Prototype.emptyFunction,
-		change: Prototype.emptyFunction,
-		selection_id: 'control_selection',
-		selection_style: {
-			zIndex: 999,
-			cursor: 'default',
-			border: '1px dotted #000'
-		},
-		filter: function(element){
-			return true;
-		},
-		drag_proxy: false,
-		drag_proxy_threshold: 1,
-		drag_proxy_options: {}
-	},
-	selectableElements: [],
-	elements: [],
-	selectableObjects: [],
-	objects: [],
-	active: false,
-	container: false,
-	resizeTimeout: false,
-	load: function(options){
-		Control.Selection.options = Object.extend(Control.Selection.options,options || {});
-		Control.Selection.selection_div = $(document.createElement('div'));
-		Control.Selection.selection_div.id = Control.Selection.options.selection_id;
-		Control.Selection.selection_div.style.display = 'none';
-		Control.Selection.selection_div.setStyle(Control.Selection.options.selection_style);
-		Control.Selection.border_width = parseInt(Control.Selection.selection_div.getStyle('border-top-width')) * 2;
-		Control.Selection.container = Prototype.Browser.IE ? window.container : window;
-		$(document.body).insert(Control.Selection.selection_div);
-		Control.Selection.enable();
-		if(Control.Selection.options.drag_proxy &amp;&amp; typeof(Draggable) != 'undefined')
-			Control.Selection.DragProxy.load();
-		Event.observe(window,'resize',function(){
-			if(Control.Selection.resizeTimeout)
-				window.clearTimeout(Control.Selection.resizeTimeout);
-			Control.Selection.resizeTimeout = window.setTimeout(Control.Selection.recalculateLayout,Control.Selection.options.resize_layout_timeout);
-		});
-		if(Prototype.Browser.IE){
-			var body = $$('body').first();
-			body.observe('mouseleave',Control.Selection.stop);
-			body.observe('mouseup',Control.Selection.stop);
-		}
-	},
-	enable: function(){
-		if(Prototype.Browser.IE){
-			document.onselectstart = function(){
-				return false;
-			}
-		}
-		Event.observe(Control.Selection.container,'mousedown',Control.Selection.start);
-		Event.observe(Control.Selection.container,'mouseup',Control.Selection.stop);
-	},
-	disable: function(){
-		if(Prototype.Browser.IE){
-			document.onselectstart = function(){
-				return true;
-			}
-		}
-		Event.stopObserving(Control.Selection.container,'mousedown',Control.Selection.start);
-		Event.stopObserving(Control.Selection.container,'mouseup',Control.Selection.stop);
-	},
-	recalculateLayout: function(){
-		Control.Selection.selectableElements.each(function(element){
-			var dimensions = element.getDimensions();
-			var offset = element.cumulativeOffset();
-			var scroll_offset = element.cumulativeScrollOffset();
-			if(!element._control_selection)
-				element._control_selection = {};
-			element._control_selection.top = offset[1] - scroll_offset[1];
-			element._control_selection.left = offset[0] - scroll_offset[0];
-			element._control_selection.width = dimensions.width;
-			element._control_selection.height = dimensions.height;
-		});
-	},
-	addSelectable: function(element,object,activation_targets,activation_target_callback){
-		element = $(element);
-		if(activation_targets)
-			activation_targets = activation_targets.each ? activation_targets : [activation_targets];
-		var dimensions = element.getDimensions();
-		var offset = Position.cumulativeOffset(element);
-		element._control_selection = {
-			activation_targets: activation_targets,
-			is_selected: false,
-			top: offset[1],
-			left: offset[0],
-			width: dimensions.width,
-			height: dimensions.height,
-			activationTargetMouseMove: function(){
-				Control.Selection.notify('activationTargetMouseMove',element);
-				if(activation_targets){
-					activation_targets.each(function(activation_target){
-						activation_target.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
-					});
-				}
-				Control.Selection.DragProxy.container.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
-			},
-			activationTargetMouseDown: function(event){
-				if(!Control.Selection.elements.include(element))
-					Control.Selection.select(element);
-				Control.Selection.DragProxy.start(event);
-				Control.Selection.DragProxy.container.hide();
-				if(activation_targets){
-					activation_targets.each(function(activation_target){
-						activation_target.observe('mousemove',element._control_selection.activationTargetMouseMove);
-					});
-				}
-				Control.Selection.DragProxy.container.observe('mousemove',element._control_selection.activationTargetMouseMove);
-			},
-			activationTargetClick: function(){
-				Control.Selection.select(element);
-				if(typeof(activation_target_callback) == &quot;function&quot;)
-					activation_target_callback();
-				if(activation_targets){
-					activation_targets.each(function(activation_target){
-						activation_target.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
-					});
-				}
-				Control.Selection.DragProxy.container.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
-			}
-		};
-		element.onselectstart = function(){
-			return false;
-		};
-		element.unselectable = 'on';
-		element.style.MozUserSelect = 'none';
-		if(activation_targets){
-			activation_targets.each(function(activation_target){
-				activation_target.observe('mousedown',element._control_selection.activationTargetMouseDown);
-				activation_target.observe('click',element._control_selection.activationTargetClick);
-			});
-		}
-		Control.Selection.selectableElements.push(element);
-		Control.Selection.selectableObjects.push(object);
-	},
-	removeSelectable: function(element){
-		element = $(element);
-		if(element._control_selection.activation_targets){
-			element._control_selection.activation_targets.each(function(activation_target){
-				activation_target.stopObserving('mousedown',element._control_selection.activationTargetMouseDown);
-			});
-			element._control_selection.activation_targets.each(function(activation_target){
-				activation_target.stopObserving('click',element._control_selection.activationTargetClick);
-			});
-		}
-		element._control_selection = null;
-		element.onselectstart = function() {
-			return true;
-		};
-		element.unselectable = 'off';
-		element.style.MozUserSelect = '';
-		var position = 0;
-		Control.Selection.selectableElements.each(function(selectable_element,i){
-			if(selectable_element == element){
-				position = i;
-				throw $break;
-			}
-		});
-		Control.Selection.selectableElements = Control.Selection.selectableElements.without(element);
-		Control.Selection.selectableObjects = Control.Selection.selectableObjects.slice(0,position).concat(Control.Selection.selectableObjects.slice(position + 1))
-	},
-	select: function(selected_elements){
-		if(typeof(selected_elements) == &quot;undefined&quot; || !selected_elements)
-			selected_elements = [];
-		if(!selected_elements.each &amp;&amp; !selected_elements._each)
-			selected_elements = [selected_elements];
-		//comparing the arrays directly wouldn't equate to true in safari so we need to compare each item
-		var selected_items_have_changed = !(Control.Selection.elements.length == selected_elements.length &amp;&amp; Control.Selection.elements.all(function(item,i){
-			return selected_elements[i] == item;
-		}));
-		if(!selected_items_have_changed)
-			return;
-		var selected_objects_indexed_by_element = {};
-		var selected_objects = selected_elements.collect(function(selected_element){
-			var selected_object = Control.Selection.selectableObjects[Control.Selection.selectableElements.indexOf(selected_element)];
-			selected_objects_indexed_by_element[selected_element] = selected_object;
-			return selected_object;
-		});
-		if(Control.Selection.elements.length == 0 &amp;&amp; selected_elements.length != 0){
-			selected_elements.each(function(element){
-				Control.Selection.notify('selected',element,selected_objects_indexed_by_element[element]);
-			});
-		}else{
-			Control.Selection.elements.each(function(element){
-				if(!selected_elements.include(element)){
-					Control.Selection.notify('deselected',element,selected_objects_indexed_by_element[element]);
-				}
-			});
-			selected_elements.each(function(element){
-				if(!Control.Selection.elements.include(element)){
-					Control.Selection.notify('selected',element,selected_objects_indexed_by_element[element]);
-				}
-			});
-		}
-		Control.Selection.elements = selected_elements;
-		Control.Selection.objects = selected_objects;
-		Control.Selection.notify('change',Control.Selection.elements,Control.Selection.objects);
-	},
-	deselect: function(){
-		if(Control.Selection.notify('deselect') === false)
-			return false;
-		Control.Selection.elements.each(function(element){
-			Control.Selection.notify('deselected',element,Control.Selection.selectableObjects[Control.Selection.selectableElements.indexOf(element)]);
-		});
-		Control.Selection.objects = [];
-		Control.Selection.elements = [];
-		Control.Selection.notify('change',Control.Selection.objects,Control.Selection.elements);
-		return true;
-	},
-	//private
-	start: function(event){
-		if(!event.isLeftClick() || Control.Selection.notify('start',event) === false)
-			return false;
-		if(!event.shiftKey &amp;&amp; !event.altKey)
-			Control.Selection.deselect();
-		Event.observe(Control.Selection.container,'mousemove',Control.Selection.onMouseMove);
-		Event.stop(event);
-		return false;
-	},
-	stop: function(){
-		Event.stopObserving(Control.Selection.container,'mousemove',Control.Selection.onMouseMove);
-		Control.Selection.active = false;
-		Control.Selection.selection_div.setStyle({
-			display: 'none',
-			top: null,
-			left: null,
-			width: null,
-			height: null
-		});
-		Control.Selection.start_mouse_coordinates = {};
-		Control.Selection.current_mouse_coordinates = {};
-	},
-	mouseCoordinatesFromEvent: function(event){
-		return {
-			x: Event.pointerX(event),
-			y: Event.pointerY(event)
-		};
-	},
-	onClick: function(event,element,source){
-		var selection = [];
-		if(event.shiftKey){
-			selection = Control.Selection.elements.clone();
-			if(!selection.include(element))
-				selection.push(element);
-		}else if(event.altKey){
-			selection = Control.Selection.elements.clone();
-			if(selection.include(element))
-				selection = selection.without(element);
-		}else{
-			selection = [element];
-		}
-		Control.Selection.select(selection);
-		if(source == 'click')
-			Event.stop(event);
-	},
-	onMouseMove: function(event){
-		if(!Control.Selection.active){
-			Control.Selection.active = true;
-			Control.Selection.start_mouse_coordinates = Control.Selection.mouseCoordinatesFromEvent(event);
-		}else{
-			Control.Selection.current_mouse_coordinates = Control.Selection.mouseCoordinatesFromEvent(event);
-			Control.Selection.drawSelectionDiv();
-			var current_selection = Control.Selection.selectableElements.findAll(function(element){
-				return Control.Selection.options.filter(element) &amp;&amp; Control.Selection.elementWithinSelection(element);
-			});
-			if(event.shiftKey &amp;&amp; !event.altKey){
-				Control.Selection.elements.each(function(element){
-					if(!current_selection.include(element))
-						current_selection.push(element);
-				});
-			}else if(event.altKey &amp;&amp; !event.shiftKey){
-				current_selection = Control.Selection.elements.findAll(function(element){
-					return !current_selection.include(element);
-				});
-			}
-			Control.Selection.select(current_selection);
-		}
-	},
-	drawSelectionDiv: function(){
-		if(Control.Selection.start_mouse_coordinates == Control.Selection.current_mouse_coordinates){
-			Control.Selection.selection_div.style.display = 'none';
-		}else{
-			Control.Selection.viewport = document.viewport.getDimensions();
-			Control.Selection.selection_div.style.position = 'absolute';
-			Control.Selection.current_direction = (Control.Selection.start_mouse_coordinates.y &gt; Control.Selection.current_mouse_coordinates.y ? 'N' : 'S') + (Control.Selection.start_mouse_coordinates.x &lt; Control.Selection.current_mouse_coordinates.x ? 'E' : 'W');
-			Control.Selection.selection_div.setStyle(Control.Selection['dimensionsFor' + Control.Selection.current_direction]());
-			Control.Selection.selection_div.style.display = 'block';
-		}
-	},
-	dimensionsForNW: function(){
-		return {
-			top: (Control.Selection.start_mouse_coordinates.y - (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y)) + 'px',
-			left: (Control.Selection.start_mouse_coordinates.x - (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x)) + 'px',
-			width: (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x) + 'px',
-			height: (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y) + 'px'
-		};
-	},
-	dimensionsForNE: function(){
-		return {
-			top: (Control.Selection.start_mouse_coordinates.y - (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y)) + 'px',
-			left: Control.Selection.start_mouse_coordinates.x + 'px',
-			width: Math.min((Control.Selection.viewport.width - Control.Selection.start_mouse_coordinates.x) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.x - Control.Selection.start_mouse_coordinates.x) + 'px',
-			height: (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y) + 'px'
-		};
-	},
-	dimensionsForSE: function(){
-		return {
-			top: Control.Selection.start_mouse_coordinates.y + 'px',
-			left: Control.Selection.start_mouse_coordinates.x + 'px',
-			width: Math.min((Control.Selection.viewport.width - Control.Selection.start_mouse_coordinates.x) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.x - Control.Selection.start_mouse_coordinates.x) + 'px',
-			height: Math.min((Control.Selection.viewport.height - Control.Selection.start_mouse_coordinates.y) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.y - Control.Selection.start_mouse_coordinates.y) + 'px'
-		};
-	},
-	dimensionsForSW: function(){
-		return {
-			top: Control.Selection.start_mouse_coordinates.y + 'px',
-			left: (Control.Selection.start_mouse_coordinates.x - (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x)) + 'px',
-			width: (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x) + 'px',
-			height: Math.min((Control.Selection.viewport.height - Control.Selection.start_mouse_coordinates.y) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.y - Control.Selection.start_mouse_coordinates.y) + 'px'
-		};
-	},
-	inBoundsForNW: function(element,selection){
-		return (
-			((element.left &gt; selection.left || element.right &gt; selection.left) &amp;&amp; selection.right &gt; element.left) &amp;&amp;
-			((element.top &gt; selection.top || element.bottom &gt; selection.top) &amp;&amp; selection.bottom &gt; element.top)
-		);
-	},
-	inBoundsForNE: function(element,selection){
-		return (
-			((element.left &lt; selection.right || element.left &lt; selection.right) &amp;&amp; selection.left &lt; element.right) &amp;&amp;
-			((element.top &gt; selection.top || element.bottom &gt; selection.top) &amp;&amp; selection.bottom &gt; element.top)
-		);
-	},
-	inBoundsForSE: function(element,selection){
-		return (
-			((element.left &lt; selection.right || element.left &lt; selection.right) &amp;&amp; selection.left &lt; element.right) &amp;&amp;
-			((element.bottom &lt; selection.bottom || element.top &lt; selection.bottom) &amp;&amp; selection.top &lt; element.bottom)
-		);
-	},
-	inBoundsForSW: function(element,selection){
-		return (
-			((element.left &gt; selection.left || element.right &gt; selection.left) &amp;&amp; selection.right &gt; element.left) &amp;&amp;
-			((element.bottom &lt; selection.bottom || element.top &lt; selection.bottom) &amp;&amp; selection.top &lt; element.bottom)
-		);
-	},
-	elementWithinSelection: function(element){
-		if(Control.Selection['inBoundsFor' + Control.Selection.current_direction]({
-			top: element._control_selection.top,
-			left: element._control_selection.left,
-			bottom: element._control_selection.top + element._control_selection.height,
-			right: element._control_selection.left + element._control_selection.width
-		},{
-			top: parseInt(Control.Selection.selection_div.style.top),
-			left: parseInt(Control.Selection.selection_div.style.left),
-			bottom: parseInt(Control.Selection.selection_div.style.top) + parseInt(Control.Selection.selection_div.style.height),
-			right: parseInt(Control.Selection.selection_div.style.left) + parseInt(Control.Selection.selection_div.style.width)
-		})){
-			element._control_selection.is_selected = true;
-			return true;
-		}else{
-			element._control_selection.is_selected = false;
-			return false;
-		}
-	},
-	DragProxy: {
-	    active: false,
-		xorigin: 0,
-		yorigin: 0,
-		load: function(){
-			Control.Selection.DragProxy.container = $(document.createElement('div'));
-			Control.Selection.DragProxy.container.id = 'control_selection_drag_proxy';
-			Control.Selection.DragProxy.container.setStyle({
-				position: 'absolute',
-				top: '1px',
-				left: '1px',
-				zIndex: 99999
-			});
-			Control.Selection.DragProxy.container.hide();
-			document.body.appendChild(Control.Selection.DragProxy.container);
-			Control.Selection.observe('selected',Control.Selection.DragProxy.selected);
-			Control.Selection.observe('deselected',Control.Selection.DragProxy.deselected);
-		},
-		start: function(event){            
-			if(event.isRightClick()){
-				Control.Selection.DragProxy.container.hide();
-				return;
-			}		    
-			if(Control.Selection.DragProxy.xorigin == Event.pointerX(event) &amp;&amp; Control.Selection.DragProxy.yorigin == Event.pointerY(event))
-				return;    		
-		    Control.Selection.DragProxy.active = true;
-			Control.Selection.DragProxy.container.setStyle({
-				position: 'absolute',
-				top: Event.pointerY(event) + 'px',
-				left: Event.pointerX(event) + 'px'
-			});			
-			Control.Selection.DragProxy.container.observe('mouseup',Control.Selection.DragProxy.onMouseUp);			
-			Control.Selection.DragProxy.container.show();
-			Control.Selection.DragProxy.container._draggable = new Draggable(Control.Selection.DragProxy.container,Object.extend({
-				onEnd: Control.Selection.DragProxy.stop
-			},Control.Selection.options.drag_proxy_options));
-			Control.Selection.DragProxy.container._draggable.eventMouseDown(event);			
-			Control.Selection.DragProxy.notify('start',Control.Selection.DragProxy.container,Control.Selection.elements);
-		},
-		stop: function(){
-			window.setTimeout(function(){
-				Control.Selection.DragProxy.active = false;
-				Control.Selection.DragProxy.container.hide();
-    			if(Control.Selection.DragProxy.container._draggable){
-					Control.Selection.DragProxy.container._draggable.destroy();
-					Control.Selection.DragProxy.container._draggable = null;
-    			}
-    			Control.Selection.DragProxy.notify('stop');
-		    },1);
-		},
-		onClick: function(event){
-			Control.Selection.DragProxy.xorigin = Event.pointerX(event);
-			Control.Selection.DragProxy.yorigin = Event.pointerY(event);
-			if(event.isRightClick())
-				Control.Selection.DragProxy.container.hide();
-			if(Control.Selection.elements.length &gt;= Control.Selection.options.drag_proxy_threshold &amp;&amp; !(event.shiftKey || event.altKey) &amp;&amp; (Control.Selection.DragProxy.xorigin != Event.pointerX(event) || Control.Selection.DragProxy.yorigin != Event.pointerY(event))){
-				Control.Selection.DragProxy.start(event);
-				Event.stop(event);
-			}
-		},
-		onMouseUp: function(event){
-			Control.Selection.DragProxy.stop();
-			Control.Selection.DragProxy.container.stopObserving('mouseup',Control.Selection.DragProxy.onMouseUp);
-		},
-		selected: function(element){
-			element.observe('mousedown',Control.Selection.DragProxy.onClick);
-		},
-		deselected: function(element){
-			element.stopObserving('mousedown',Control.Selection.DragProxy.onClick);
-		}
-	}
+    options: {
+        resize_layout_timeout: 125,
+        selected: Prototype.emptyFunction,
+        deselected: Prototype.emptyFunction,
+        change: Prototype.emptyFunction,
+        selection_id: 'control_selection',
+        selection_style: {
+            zIndex: 999,
+            cursor: 'default',
+            border: '1px dotted #000'
+        },
+        filter: function(element){
+            return true;
+        },
+        drag_proxy: false,
+        drag_proxy_threshold: 1,
+        drag_proxy_options: {}
+    },
+    selectableElements: [],
+    elements: [],
+    selectableObjects: [],
+    objects: [],
+    active: false,
+    container: false,
+    resizeTimeout: false,
+    load: function(options){
+        Control.Selection.options = Object.extend(Control.Selection.options,options || {});
+        Control.Selection.selection_div = $(document.createElement('div'));
+        Control.Selection.selection_div.id = Control.Selection.options.selection_id;
+        Control.Selection.selection_div.style.display = 'none';
+        Control.Selection.selection_div.setStyle(Control.Selection.options.selection_style);
+        Control.Selection.border_width = parseInt(Control.Selection.selection_div.getStyle('border-top-width'), 10) * 2;
+        Control.Selection.container = Prototype.Browser.IE ? window.container : window;
+        $(document.body).insert(Control.Selection.selection_div);
+        Control.Selection.enable();
+        if(Control.Selection.options.drag_proxy &amp;&amp; typeof(Draggable) != 'undefined') {
+            Control.Selection.DragProxy.load(); }
+        Event.observe(window,'resize',function(){
+            if(Control.Selection.resizeTimeout) {
+                window.clearTimeout(Control.Selection.resizeTimeout); }
+            Control.Selection.resizeTimeout = window.setTimeout(Control.Selection.recalculateLayout,Control.Selection.options.resize_layout_timeout);
+        });
+        if(Prototype.Browser.IE){
+            var body = $$('body').first();
+            body.observe('mouseleave',Control.Selection.stop);
+            body.observe('mouseup',Control.Selection.stop);
+        }
+    },
+    enable: function(){
+        if(Prototype.Browser.IE){
+            document.onselectstart = function(){
+                return false;
+            };
+        }
+        Event.observe(Control.Selection.container,'mousedown',Control.Selection.start);
+        Event.observe(Control.Selection.container,'mouseup',Control.Selection.stop);
+    },
+    disable: function(){
+        if(Prototype.Browser.IE){
+            document.onselectstart = function(){
+                return true;
+            };
+        }
+        Event.stopObserving(Control.Selection.container,'mousedown',Control.Selection.start);
+        Event.stopObserving(Control.Selection.container,'mouseup',Control.Selection.stop);
+    },
+    recalculateLayout: function(){
+        Control.Selection.selectableElements.each(function(element){
+            var dimensions = element.getDimensions();
+            var offset = element.cumulativeOffset();
+            var scroll_offset = element.cumulativeScrollOffset();
+            if(!element._control_selection) {
+                element._control_selection = {}; }
+            element._control_selection.top = offset[1] - scroll_offset[1];
+            element._control_selection.left = offset[0] - scroll_offset[0];
+            element._control_selection.width = dimensions.width;
+            element._control_selection.height = dimensions.height;
+        });
+    },
+    addSelectable: function(element,object,activation_targets,activation_target_callback){
+        element = $(element);
+        if(activation_targets) {
+            activation_targets = activation_targets.each ? activation_targets : [activation_targets]; }
+        var dimensions = element.getDimensions();
+        var offset = Element.cumulativeOffset(element);
+        element._control_selection = {
+            activation_targets: activation_targets,
+            is_selected: false,
+            top: offset[1],
+            left: offset[0],
+            width: dimensions.width,
+            height: dimensions.height,
+            activationTargetMouseMove: function(){
+                Control.Selection.notify('activationTargetMouseMove',element);
+                if(activation_targets){
+                    activation_targets.each(function(activation_target){
+                        activation_target.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
+                    });
+                }
+                Control.Selection.DragProxy.container.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
+            },
+            activationTargetMouseDown: function(event){
+                if(!Control.Selection.elements.include(element)) {
+                    Control.Selection.select(element); }
+                Control.Selection.DragProxy.start(event);
+                Control.Selection.DragProxy.container.hide();
+                if(activation_targets){
+                    activation_targets.each(function(activation_target){
+                        activation_target.observe('mousemove',element._control_selection.activationTargetMouseMove);
+                    });
+                }
+                Control.Selection.DragProxy.container.observe('mousemove',element._control_selection.activationTargetMouseMove);
+            },
+            activationTargetClick: function(){
+                Control.Selection.select(element);
+                if(typeof(activation_target_callback) == &quot;function&quot;) {
+                    activation_target_callback(); }
+                if(activation_targets){
+                    activation_targets.each(function(activation_target){
+                        activation_target.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
+                    });
+                }
+                Control.Selection.DragProxy.container.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
+            }
+        };
+        element.onselectstart = function(){
+            return false;
+        };
+        element.unselectable = 'on';
+        element.style.MozUserSelect = 'none';
+        if(activation_targets){
+            activation_targets.each(function(activation_target){
+                activation_target.observe('mousedown',element._control_selection.activationTargetMouseDown);
+                activation_target.observe('click',element._control_selection.activationTargetClick);
+            });
+        }
+        Control.Selection.selectableElements.push(element);
+        Control.Selection.selectableObjects.push(object);
+    },
+    removeSelectable: function(element){
+        element = $(element);
+        if(element._control_selection.activation_targets){
+            element._control_selection.activation_targets.each(function(activation_target){
+                activation_target.stopObserving('mousedown',element._control_selection.activationTargetMouseDown);
+            });
+            element._control_selection.activation_targets.each(function(activation_target){
+                activation_target.stopObserving('click',element._control_selection.activationTargetClick);
+            });
+        }
+        element._control_selection = null;
+        element.onselectstart = function() {
+            return true;
+        };
+        element.unselectable = 'off';
+        element.style.MozUserSelect = '';
+        var position = 0;
+        Control.Selection.selectableElements.each(function(selectable_element,i){
+            if(selectable_element == element){
+                position = i;
+                throw $break;
+            }
+        });
+        Control.Selection.selectableElements = Control.Selection.selectableElements.without(element);
+        Control.Selection.selectableObjects = Control.Selection.selectableObjects.slice(0,position).concat(Control.Selection.selectableObjects.slice(position + 1));
+    },
+    select: function(selected_elements){
+        if(typeof(selected_elements) == &quot;undefined&quot; || !selected_elements) {
+            selected_elements = []; }
+        if(!selected_elements.each &amp;&amp; !selected_elements._each) {
+            selected_elements = [selected_elements]; }
+        //comparing the arrays directly wouldn't equate to true in safari so we need to compare each item
+        var selected_items_have_changed = !(Control.Selection.elements.length == selected_elements.length &amp;&amp; Control.Selection.elements.all(function(item,i){
+            return selected_elements[i] == item;
+        }));
+        if(!selected_items_have_changed) {
+            return; }
+        var selected_objects_indexed_by_element = {};
+        var selected_objects = selected_elements.collect(function(selected_element){
+            var selected_object = Control.Selection.selectableObjects[Control.Selection.selectableElements.indexOf(selected_element)];
+            selected_objects_indexed_by_element[selected_element] = selected_object;
+            return selected_object;
+        });
+        if(Control.Selection.elements.length === 0 &amp;&amp; selected_elements.length !== 0){
+            selected_elements.each(function(element){
+                Control.Selection.notify('selected',element,selected_objects_indexed_by_element[element]);
+            });
+        }else{
+            Control.Selection.elements.each(function(element){
+                if(!selected_elements.include(element)){
+                    Control.Selection.notify('deselected',element,selected_objects_indexed_by_element[element]);
+                }
+            });
+            selected_elements.each(function(element){
+                if(!Control.Selection.elements.include(element)){
+                    Control.Selection.notify('selected',element,selected_objects_indexed_by_element[element]);
+                }
+            });
+        }
+        Control.Selection.elements = selected_elements;
+        Control.Selection.objects = selected_objects;
+        Control.Selection.notify('change',Control.Selection.elements,Control.Selection.objects);
+    },
+    deselect: function(){
+        if(Control.Selection.notify('deselect') === false) {
+            return false; }
+        Control.Selection.elements.each(function(element){
+            Control.Selection.notify('deselected',element,Control.Selection.selectableObjects[Control.Selection.selectableElements.indexOf(element)]);
+        });
+        Control.Selection.objects = [];
+        Control.Selection.elements = [];
+        Control.Selection.notify('change',Control.Selection.objects,Control.Selection.elements);
+        return true;
+    },
+    //private
+    start: function(event){
+        if(!event.isLeftClick() || Control.Selection.notify('start',event) === false) {
+            return false; }
+        if(!event.shiftKey &amp;&amp; !event.altKey) {
+            Control.Selection.deselect(); }
+        Event.observe(Control.Selection.container,'mousemove',Control.Selection.onMouseMove);
+        Event.stop(event);
+        return false;
+    },
+    stop: function(){
+        Event.stopObserving(Control.Selection.container,'mousemove',Control.Selection.onMouseMove);
+        Control.Selection.active = false;
+        Control.Selection.selection_div.setStyle({
+            display: 'none',
+            top: null,
+            left: null,
+            width: null,
+            height: null
+        });
+        Control.Selection.start_mouse_coordinates = {};
+        Control.Selection.current_mouse_coordinates = {};
+    },
+    mouseCoordinatesFromEvent: function(event){
+        return {
+            x: Event.pointerX(event),
+            y: Event.pointerY(event)
+        };
+    },
+    onClick: function(event,element,source){
+        var selection = [];
+        if(event.shiftKey){
+            selection = Control.Selection.elements.clone();
+            if(!selection.include(element)) {
+                selection.push(element); }
+        }else if(event.altKey){
+            selection = Control.Selection.elements.clone();
+            if(selection.include(element)) {
+                selection = selection.without(element); }
+        }else{
+            selection = [element];
+        }
+        Control.Selection.select(selection);
+        if(source == 'click') {
+            Event.stop(event); }
+    },
+    onMouseMove: function(event){
+        if(!Control.Selection.active){
+            Control.Selection.active = true;
+            Control.Selection.start_mouse_coordinates = Control.Selection.mouseCoordinatesFromEvent(event);
+        }else{
+            Control.Selection.current_mouse_coordinates = Control.Selection.mouseCoordinatesFromEvent(event);
+            Control.Selection.drawSelectionDiv();
+            var current_selection = Control.Selection.selectableElements.findAll(function(element){
+                return Control.Selection.options.filter(element) &amp;&amp; Control.Selection.elementWithinSelection(element);
+            });
+            if(event.shiftKey &amp;&amp; !event.altKey){
+                Control.Selection.elements.each(function(element){
+                    if(!current_selection.include(element)) {
+                        current_selection.push(element); }
+                });
+            }else if(event.altKey &amp;&amp; !event.shiftKey){
+                current_selection = Control.Selection.elements.findAll(function(element){
+                    return !current_selection.include(element);
+                });
+            }
+            Control.Selection.select(current_selection);
+        }
+    },
+    drawSelectionDiv: function(){
+        if(Control.Selection.start_mouse_coordinates == Control.Selection.current_mouse_coordinates){
+            Control.Selection.selection_div.style.display = 'none';
+        }else{
+            Control.Selection.viewport = document.viewport.getDimensions();
+            Control.Selection.selection_div.style.position = 'absolute';
+            Control.Selection.current_direction = (Control.Selection.start_mouse_coordinates.y &gt; Control.Selection.current_mouse_coordinates.y ? 'N' : 'S') + (Control.Selection.start_mouse_coordinates.x &lt; Control.Selection.current_mouse_coordinates.x ? 'E' : 'W');
+            Control.Selection.selection_div.setStyle(Control.Selection['dimensionsFor' + Control.Selection.current_direction]());
+            Control.Selection.selection_div.style.display = 'block';
+        }
+    },
+    dimensionsForNW: function(){
+        return {
+            top: (Control.Selection.start_mouse_coordinates.y - (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y)) + 'px',
+            left: (Control.Selection.start_mouse_coordinates.x - (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x)) + 'px',
+            width: (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x) + 'px',
+            height: (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y) + 'px'
+        };
+    },
+    dimensionsForNE: function(){
+        return {
+            top: (Control.Selection.start_mouse_coordinates.y - (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y)) + 'px',
+            left: Control.Selection.start_mouse_coordinates.x + 'px',
+            width: Math.min((Control.Selection.viewport.width - Control.Selection.start_mouse_coordinates.x) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.x - Control.Selection.start_mouse_coordinates.x) + 'px',
+            height: (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y) + 'px'
+        };
+    },
+    dimensionsForSE: function(){
+        return {
+            top: Control.Selection.start_mouse_coordinates.y + 'px',
+            left: Control.Selection.start_mouse_coordinates.x + 'px',
+            width: Math.min((Control.Selection.viewport.width - Control.Selection.start_mouse_coordinates.x) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.x - Control.Selection.start_mouse_coordinates.x) + 'px',
+            height: Math.min((Control.Selection.viewport.height - Control.Selection.start_mouse_coordinates.y) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.y - Control.Selection.start_mouse_coordinates.y) + 'px'
+        };
+    },
+    dimensionsForSW: function(){
+        return {
+            top: Control.Selection.start_mouse_coordinates.y + 'px',
+            left: (Control.Selection.start_mouse_coordinates.x - (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x)) + 'px',
+            width: (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x) + 'px',
+            height: Math.min((Control.Selection.viewport.height - Control.Selection.start_mouse_coordinates.y) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.y - Control.Selection.start_mouse_coordinates.y) + 'px'
+        };
+    },
+    inBoundsForNW: function(element,selection){
+        return (
+            ((element.left &gt; selection.left || element.right &gt; selection.left) &amp;&amp; selection.right &gt; element.left) &amp;&amp;
+            ((element.top &gt; selection.top || element.bottom &gt; selection.top) &amp;&amp; selection.bottom &gt; element.top)
+        );
+    },
+    inBoundsForNE: function(element,selection){
+        return (
+            ((element.left &lt; selection.right || element.left &lt; selection.right) &amp;&amp; selection.left &lt; element.right) &amp;&amp;
+            ((element.top &gt; selection.top || element.bottom &gt; selection.top) &amp;&amp; selection.bottom &gt; element.top)
+        );
+    },
+    inBoundsForSE: function(element,selection){
+        return (
+            ((element.left &lt; selection.right || element.left &lt; selection.right) &amp;&amp; selection.left &lt; element.right) &amp;&amp;
+            ((element.bottom &lt; selection.bottom || element.top &lt; selection.bottom) &amp;&amp; selection.top &lt; element.bottom)
+        );
+    },
+    inBoundsForSW: function(element,selection){
+        return (
+            ((element.left &gt; selection.left || element.right &gt; selection.left) &amp;&amp; selection.right &gt; element.left) &amp;&amp;
+            ((element.bottom &lt; selection.bottom || element.top &lt; selection.bottom) &amp;&amp; selection.top &lt; element.bottom)
+        );
+    },
+    elementWithinSelection: function(element){
+        if(Control.Selection['inBoundsFor' + Control.Selection.current_direction]({
+            top: element._control_selection.top,
+            left: element._control_selection.left,
+            bottom: element._control_selection.top + element._control_selection.height,
+            right: element._control_selection.left + element._control_selection.width
+        },{
+            top: parseInt(Control.Selection.selection_div.style.top, 10),
+            left: parseInt(Control.Selection.selection_div.style.left, 10),
+            bottom: parseInt(Control.Selection.selection_div.style.top, 10) + parseInt(Control.Selection.selection_div.style.height, 10),
+            right: parseInt(Control.Selection.selection_div.style.left, 10) + parseInt(Control.Selection.selection_div.style.width, 10)
+        })){
+            element._control_selection.is_selected = true;
+            return true;
+        }else{
+            element._control_selection.is_selected = false;
+            return false;
+        }
+    },
+    DragProxy: {
+        active: false,
+        xorigin: 0,
+        yorigin: 0,
+        load: function(){
+            Control.Selection.DragProxy.container = $(document.createElement('div'));
+            Control.Selection.DragProxy.container.id = 'control_selection_drag_proxy';
+            Control.Selection.DragProxy.container.setStyle({
+                position: 'absolute',
+                top: '1px',
+                left: '1px',
+                zIndex: 99999
+            });
+            Control.Selection.DragProxy.container.hide();
+            document.body.appendChild(Control.Selection.DragProxy.container);
+            Control.Selection.observe('selected',Control.Selection.DragProxy.selected);
+            Control.Selection.observe('deselected',Control.Selection.DragProxy.deselected);
+        },
+        start: function(event){            
+            if(event.isRightClick()){
+                Control.Selection.DragProxy.container.hide();
+                return;
+            }            
+            if(Control.Selection.DragProxy.xorigin == Event.pointerX(event) &amp;&amp; Control.Selection.DragProxy.yorigin == Event.pointerY(event)) {
+                return; }
+            Control.Selection.DragProxy.active = true;
+            Control.Selection.DragProxy.container.setStyle({
+                position: 'absolute',
+                top: Event.pointerY(event) + 'px',
+                left: Event.pointerX(event) + 'px'
+            });            
+            Control.Selection.DragProxy.container.observe('mouseup',Control.Selection.DragProxy.onMouseUp);            
+            Control.Selection.DragProxy.container.show();
+            Control.Selection.DragProxy.container._draggable = new Draggable(Control.Selection.DragProxy.container,Object.extend({
+                onEnd: Control.Selection.DragProxy.stop
+            },Control.Selection.options.drag_proxy_options));
+            Control.Selection.DragProxy.container._draggable.eventMouseDown(event);            
+            Control.Selection.DragProxy.notify('start',Control.Selection.DragProxy.container,Control.Selection.elements);
+        },
+        stop: function(){
+            window.setTimeout(function(){
+                Control.Selection.DragProxy.active = false;
+                Control.Selection.DragProxy.container.hide();
+                if(Control.Selection.DragProxy.container._draggable){
+                    Control.Selection.DragProxy.container._draggable.destroy();
+                    Control.Selection.DragProxy.container._draggable = null;
+                }
+                Control.Selection.DragProxy.notify('stop');
+            },1);
+        },
+        onClick: function(event){
+            Control.Selection.DragProxy.xorigin = Event.pointerX(event);
+            Control.Selection.DragProxy.yorigin = Event.pointerY(event);
+            if(event.isRightClick()) {
+                Control.Selection.DragProxy.container.hide(); }
+            if(Control.Selection.elements.length &gt;= Control.Selection.options.drag_proxy_threshold &amp;&amp; !(event.shiftKey || event.altKey) &amp;&amp; (Control.Selection.DragProxy.xorigin != Event.pointerX(event) || Control.Selection.DragProxy.yorigin != Event.pointerY(event))){
+                Control.Selection.DragProxy.start(event);
+                Event.stop(event);
+            }
+        },
+        onMouseUp: function(event){
+            Control.Selection.DragProxy.stop();
+            Control.Selection.DragProxy.container.stopObserving('mouseup',Control.Selection.DragProxy.onMouseUp);
+        },
+        selected: function(element){
+            element.observe('mousedown',Control.Selection.DragProxy.onClick);
+        },
+        deselected: function(element){
+            element.stopObserving('mousedown',Control.Selection.DragProxy.onClick);
+        }
+    }
 };
 Object.Event.extend(Control.Selection);
-Object.Event.extend(Control.Selection.DragProxy);
\ No newline at end of file
+Object.Event.extend(Control.Selection.DragProxy);</diff>
      <filename>public/javascripts/selection.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,146 +10,146 @@
 /*global Prototype, Class, Option, $, $A, Control, $break,  */
 
 if(typeof(Prototype) == &quot;undefined&quot;) {
-	throw &quot;Control.SelectMultiple requires Prototype to be loaded.&quot;; }
+    throw &quot;Control.SelectMultiple requires Prototype to be loaded.&quot;; }
 if(typeof(Object.Event) == &quot;undefined&quot;) {
-	throw &quot;Control.SelectMultiple requires Object.Event to be loaded.&quot;; }
+    throw &quot;Control.SelectMultiple requires Object.Event to be loaded.&quot;; }
 
 Control.SelectMultiple = Class.create({
-	select: false,
-	container: false,
-	numberOfCheckedBoxes: 0,
-	checkboxes: [],
-	hasExtraOption: false,
-	initialize: function(select,container,options){
-		this.options = {
-			checkboxSelector: 'input[type=checkbox]',
-			nameSelector: 'span.name',
-			labelSeparator: ', ',
-			valueSeparator: ',',
-			afterChange: Prototype.emptyFunction,
-			overflowString: function(str){
-				return str.truncate();
-			},
-			overflowLength: 30
-		};
-		Object.extend(this.options,options || {});
-		this.select = $(select);
-		this.container =  $(container);
-		this.checkboxes = (typeof(this.options.checkboxSelector) == 'function') ? 
+    select: false,
+    container: false,
+    numberOfCheckedBoxes: 0,
+    checkboxes: [],
+    hasExtraOption: false,
+    initialize: function(select,container,options){
+        this.options = {
+            checkboxSelector: 'input[type=checkbox]',
+            nameSelector: 'span.name',
+            labelSeparator: ', ',
+            valueSeparator: ',',
+            afterChange: Prototype.emptyFunction,
+            overflowString: function(str){
+                return str.truncate();
+            },
+            overflowLength: 30
+        };
+        Object.extend(this.options,options || {});
+        this.select = $(select);
+        this.container =  $(container);
+        this.checkboxes = (typeof(this.options.checkboxSelector) == 'function') ? 
             this.options.checkboxSelector.bind(this)() : 
             this.container.getElementsBySelector(this.options.checkboxSelector);
-		var value_was_set = false;
-		if(this.options.value){
-			value_was_set = true;
-			this.setValue(this.options.value);
-			delete this.options.value;
-		}
-		this.hasExtraOption = false;
-		this.checkboxes.each(function(checkbox){
-		 checkbox.observe('click',this.checkboxOnClick.bind(this,checkbox));
-		}.bind(this));
-		this.select.observe('change',this.selectOnChange.bind(this));
-		this.countAndCheckCheckBoxes();
-		if(!value_was_set) {
-		 this.scanCheckBoxes(); }
-		this.notify('afterChange',this.select.options[this.select.options.selectedIndex].value);
-	},
-	countAndCheckCheckBoxes: function(){
-		this.numberOfCheckedBoxes = this.checkboxes.inject(0,function(number,checkbox){
-			checkbox.checked = (this.select.options[this.select.options.selectedIndex].value == checkbox.value);
-			var value_string = this.select.options[this.select.options.selectedIndex].value;
+        var value_was_set = false;
+        if(this.options.value){
+            value_was_set = true;
+            this.setValue(this.options.value);
+            delete this.options.value;
+        }
+        this.hasExtraOption = false;
+        this.checkboxes.each(function(checkbox){
+         checkbox.observe('click',this.checkboxOnClick.bind(this,checkbox));
+        }.bind(this));
+        this.select.observe('change',this.selectOnChange.bind(this));
+        this.countAndCheckCheckBoxes();
+        if(!value_was_set) {
+         this.scanCheckBoxes(); }
+        this.notify('afterChange',this.select.options[this.select.options.selectedIndex].value);
+    },
+    countAndCheckCheckBoxes: function(){
+        this.numberOfCheckedBoxes = this.checkboxes.inject(0,function(number,checkbox){
+            checkbox.checked = (this.select.options[this.select.options.selectedIndex].value == checkbox.value);
+            var value_string = this.select.options[this.select.options.selectedIndex].value;
             var value_collection = $A(value_string.split ? value_string.split(this.options.valueSeparator) : value_string);
-			var should_check = value_collection.any(function(value) {
-				if (!should_check &amp;&amp; checkbox.value == value) {
-					return true; }
-			}.bind(this));
-			checkbox.checked = should_check;
-			if(checkbox.checked) {
-				++number; }
-			return number;
-		}.bind(this));
-	},
-	setValue: function(value_string){
-		this.numberOfCheckedBoxes = 0;
+            var should_check = value_collection.any(function(value) {
+                if (!should_check &amp;&amp; checkbox.value == value) {
+                    return true; }
+            }.bind(this));
+            checkbox.checked = should_check;
+            if(checkbox.checked) {
+                ++number; }
+            return number;
+        }.bind(this));
+    },
+    setValue: function(value_string){
+        this.numberOfCheckedBoxes = 0;
         var value_collection = $A(value_string.split ? value_string.split(this.options.valueSeparator) : value_string);
-		this.checkboxes.each(function(checkbox){
-			checkbox.checked = false;
-			value_collection.each(function(value){
-				if(checkbox.value == value){
-					++this.numberOfCheckedBoxes;
-					checkbox.checked = true;
-				}
-			}.bind(this));
-		}.bind(this));
-		this.scanCheckBoxes();
-	},
-	selectOnChange: function(){
-		this.removeExtraOption();
-		this.countAndCheckCheckBoxes();
-		this.notify('afterChange',this.select.options[this.select.options.selectedIndex].value);
-	},
-	checkboxOnClick: function(checkbox){
+        this.checkboxes.each(function(checkbox){
+            checkbox.checked = false;
+            value_collection.each(function(value){
+                if(checkbox.value == value){
+                    ++this.numberOfCheckedBoxes;
+                    checkbox.checked = true;
+                }
+            }.bind(this));
+        }.bind(this));
+        this.scanCheckBoxes();
+    },
+    selectOnChange: function(){
+        this.removeExtraOption();
+        this.countAndCheckCheckBoxes();
+        this.notify('afterChange',this.select.options[this.select.options.selectedIndex].value);
+    },
+    checkboxOnClick: function(checkbox){
         this.numberOfCheckedBoxes = this.checkboxes.findAll(function (c) { 
             return c.checked; 
         }).length;
-		this.scanCheckBoxes();
+        this.scanCheckBoxes();
         this.notify('afterChange', this.numberOfCheckedBoxes === 0 ? &quot;&quot; :
             this.select.options[this.select.options.selectedIndex].value);
-	},
-	scanCheckBoxes: function(){
-		switch(this.numberOfCheckedBoxes){
-			case 1:
-				this.checkboxes.each(function(checkbox){
-					if(checkbox.checked){
-						$A(this.select.options).each(function(option,i){
-							if(option.value == checkbox.value){
-								this.select.options.selectedIndex = i;
-								throw $break;
-							}
-						}.bind(this));
-						throw $break;
-					}
-				}.bind(this));
+    },
+    scanCheckBoxes: function(){
+        switch(this.numberOfCheckedBoxes){
+            case 1:
+                this.checkboxes.each(function(checkbox){
+                    if(checkbox.checked){
+                        $A(this.select.options).each(function(option,i){
+                            if(option.value == checkbox.value){
+                                this.select.options.selectedIndex = i;
+                                throw $break;
+                            }
+                        }.bind(this));
+                        throw $break;
+                    }
+                }.bind(this));
                 break;
-			case 0:
-				this.removeExtraOption();
-				break;
-			default:
-				this.addExtraOption();
-				break;
-		}
-	},
-	getLabelForExtraOption: function(){
-		var label = (typeof(this.options.nameSelector) == 'function' ? 
+            case 0:
+                this.removeExtraOption();
+                break;
+            default:
+                this.addExtraOption();
+                break;
+        }
+    },
+    getLabelForExtraOption: function(){
+        var label = (typeof(this.options.nameSelector) == 'function' ? 
             this.options.nameSelector.bind(this)() : 
             this.container.getElementsBySelector(this.options.nameSelector).inject([],function(labels,name_element,i){
-				if(this.checkboxes[i].checked) {
-					labels.push(name_element.innerHTML); }
-				return labels;
-			}.bind(this))
-		).join(this.options.labelSeparator);
+                if(this.checkboxes[i].checked) {
+                    labels.push(name_element.innerHTML); }
+                return labels;
+            }.bind(this))
+        ).join(this.options.labelSeparator);
         return (label.length &gt;= this.options.overflowLength &amp;&amp; this.options.overflowLength &gt; 0) ? 
             (typeof(this.options.overflowString) == 'function' ? this.options.overflowString(label) : this.options.overflowString) : 
             label;
-	},
-	getValueForExtraOption: function(){
-		return this.checkboxes.inject([],function(values,checkbox){
-			if(checkbox.checked) {
-				values.push(checkbox.value); }
-			return values;
-		}).join(this.options.valueSeparator);
-	},
-	addExtraOption: function(){
-		this.removeExtraOption();
-		this.hasExtraOption = true;
-		this.select.options[this.select.options.length] = new Option(this.getLabelForExtraOption(),this.getValueForExtraOption());
-		this.select.options.selectedIndex = this.select.options.length - 1;
-	},
-	removeExtraOption: function(){
-		if(this.hasExtraOption){
-			this.select.remove(this.select.options.length - 1);
-			this.hasExtraOption = false;
-		}
-	}
+    },
+    getValueForExtraOption: function(){
+        return this.checkboxes.inject([],function(values,checkbox){
+            if(checkbox.checked) {
+                values.push(checkbox.value); }
+            return values;
+        }).join(this.options.valueSeparator);
+    },
+    addExtraOption: function(){
+        this.removeExtraOption();
+        this.hasExtraOption = true;
+        this.select.options[this.select.options.length] = new Option(this.getLabelForExtraOption(),this.getValueForExtraOption());
+        this.select.options.selectedIndex = this.select.options.length - 1;
+    },
+    removeExtraOption: function(){
+        if(this.hasExtraOption){
+            this.select.remove(this.select.options.length - 1);
+            this.hasExtraOption = false;
+        }
+    }
 });
 Object.Event.extend(Control.SelectMultiple);</diff>
      <filename>public/javascripts/selectmultiple.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,6 @@
-// script.aculo.us slider.js v1.8.0, Tue Nov 06 15:01:40 +0300 2007
+// script.aculo.us slider.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009
 
-// Copyright (c) 2005-2007 Marty Haught, Thomas Fuchs 
+// Copyright (c) 2005-2009 Marty Haught, Thomas Fuchs
 //
 // script.aculo.us is freely distributable under the terms of an MIT-style license.
 // For details, see the script.aculo.us web site: http://script.aculo.us/
@@ -16,13 +16,13 @@ if (!Control) var Control = { };
 Control.Slider = Class.create({
   initialize: function(handle, track, options) {
     var slider = this;
-    
+
     if (Object.isArray(handle)) {
       this.handles = handle.collect( function(e) { return $(e) });
     } else {
       this.handles = [$(handle)];
     }
-    
+
     this.track   = $(track);
     this.options = options || { };
 
@@ -30,7 +30,7 @@ Control.Slider = Class.create({
     this.increment = this.options.increment || 1;
     this.step      = parseInt(this.options.step || '1');
     this.range     = this.options.range || $R(0,1);
-    
+
     this.value     = 0; // assure backwards compat
     this.values    = this.handles.map( function() { return 0 });
     this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
@@ -45,13 +45,13 @@ Control.Slider = Class.create({
     // Will be used to align the handle onto the track, if necessary
     this.alignX = parseInt(this.options.alignX || '0');
     this.alignY = parseInt(this.options.alignY || '0');
-    
+
     this.trackLength = this.maximumOffset() - this.minimumOffset();
 
-    this.handleLength = this.isVertical() ? 
-      (this.handles[0].offsetHeight != 0 ? 
-        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,&quot;&quot;)) : 
-      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth : 
+    this.handleLength = this.isVertical() ?
+      (this.handles[0].offsetHeight != 0 ?
+        this.handles[0].offsetHeight : this.handles[0].style.height.replace(/px$/,&quot;&quot;)) :
+      (this.handles[0].offsetWidth != 0 ? this.handles[0].offsetWidth :
         this.handles[0].style.width.replace(/px$/,&quot;&quot;));
 
     this.active   = false;
@@ -75,20 +75,20 @@ Control.Slider = Class.create({
     this.handles.each( function(h,i) {
       i = slider.handles.length-1-i;
       slider.setValue(parseFloat(
-        (Object.isArray(slider.options.sliderValue) ? 
-          slider.options.sliderValue[i] : slider.options.sliderValue) || 
+        (Object.isArray(slider.options.sliderValue) ?
+          slider.options.sliderValue[i] : slider.options.sliderValue) ||
          slider.range.start), i);
       h.makePositioned().observe(&quot;mousedown&quot;, slider.eventMouseDown);
     });
-    
+
     this.track.observe(&quot;mousedown&quot;, this.eventMouseDown);
     document.observe(&quot;mouseup&quot;, this.eventMouseUp);
     document.observe(&quot;mousemove&quot;, this.eventMouseMove);
-    
+
     this.initialized = true;
   },
   dispose: function() {
-    var slider = this;    
+    var slider = this;
     Event.stopObserving(this.track, &quot;mousedown&quot;, this.eventMouseDown);
     Event.stopObserving(document, &quot;mouseup&quot;, this.eventMouseUp);
     Event.stopObserving(document, &quot;mousemove&quot;, this.eventMouseMove);
@@ -101,12 +101,12 @@ Control.Slider = Class.create({
   },
   setEnabled: function(){
     this.disabled = false;
-  },  
+  },
   getNearestValue: function(value){
     if (this.allowedValues){
       if (value &gt;= this.allowedValues.max()) return(this.allowedValues.max());
       if (value &lt;= this.allowedValues.min()) return(this.allowedValues.min());
-      
+
       var offset = Math.abs(this.allowedValues[0] - value);
       var newValue = this.allowedValues[0];
       this.allowedValues.each( function(v) {
@@ -114,7 +114,7 @@ Control.Slider = Class.create({
         if (currentOffset &lt;= offset){
           newValue = v;
           offset = currentOffset;
-        } 
+        }
       });
       return newValue;
     }
@@ -138,28 +138,28 @@ Control.Slider = Class.create({
     sliderValue = this.getNearestValue(sliderValue);
     this.values[handleIdx] = sliderValue;
     this.value = this.values[0]; // assure backwards compat
-    
-    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = 
+
+    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] =
       this.translateToPx(sliderValue);
-    
+
     this.drawSpans();
     if (!this.dragging || !this.event) this.updateFinished();
   },
   setValueBy: function(delta, handleIdx) {
-    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, 
+    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta,
       handleIdx || this.activeHandleIdx || 0);
   },
   translateToPx: function(value) {
     return Math.round(
-      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * 
+      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) *
       (value - this.range.start)) + &quot;px&quot;;
   },
   translateToValue: function(offset) {
-    return ((offset/(this.trackLength-this.handleLength) * 
+    return ((offset/(this.trackLength-this.handleLength) *
       (this.range.end-this.range.start)) + this.range.start);
   },
   getRange: function(range) {
-    var v = this.values.sortBy(Prototype.K); 
+    var v = this.values.sortBy(Prototype.K);
     range = range || 0;
     return $R(v[range],v[range+1]);
   },
@@ -167,12 +167,12 @@ Control.Slider = Class.create({
     return(this.isVertical() ? this.alignY : this.alignX);
   },
   maximumOffset: function(){
-    return(this.isVertical() ? 
+    return(this.isVertical() ?
       (this.track.offsetHeight != 0 ? this.track.offsetHeight :
-        this.track.style.height.replace(/px$/,&quot;&quot;)) - this.alignY : 
-      (this.track.offsetWidth != 0 ? this.track.offsetWidth : 
+        this.track.style.height.replace(/px$/,&quot;&quot;)) - this.alignY :
+      (this.track.offsetWidth != 0 ? this.track.offsetWidth :
         this.track.style.width.replace(/px$/,&quot;&quot;)) - this.alignX);
-  },  
+  },
   isVertical:  function(){
     return (this.axis == 'vertical');
   },
@@ -184,7 +184,7 @@ Control.Slider = Class.create({
       this.setSpan(this.options.startSpan,
         $R(0, this.values.length&gt;1 ? this.getRange(0).min() : this.value ));
     if (this.options.endSpan)
-      this.setSpan(this.options.endSpan, 
+      this.setSpan(this.options.endSpan,
         $R(this.values.length&gt;1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
   },
   setSpan: function(span, range) {
@@ -204,30 +204,30 @@ Control.Slider = Class.create({
     if (Event.isLeftClick(event)) {
       if (!this.disabled){
         this.active = true;
-        
+
         var handle = Event.element(event);
         var pointer  = [Event.pointerX(event), Event.pointerY(event)];
         var track = handle;
         if (track==this.track) {
-          var offsets  = Position.cumulativeOffset(this.track); 
+          var offsets  = this.track.cumulativeOffset();
           this.event = event;
-          this.setValue(this.translateToValue( 
+          this.setValue(this.translateToValue(
            (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
           ));
-          var offsets  = Position.cumulativeOffset(this.activeHandle);
+          var offsets  = this.activeHandle.cumulativeOffset();
           this.offsetX = (pointer[0] - offsets[0]);
           this.offsetY = (pointer[1] - offsets[1]);
         } else {
           // find the handle (prevents issues with Safari)
-          while((this.handles.indexOf(handle) == -1) &amp;&amp; handle.parentNode) 
+          while((this.handles.indexOf(handle) == -1) &amp;&amp; handle.parentNode)
             handle = handle.parentNode;
-            
+
           if (this.handles.indexOf(handle)!=-1) {
             this.activeHandle    = handle;
             this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
             this.updateStyles();
-            
-            var offsets  = Position.cumulativeOffset(this.activeHandle);
+
+            var offsets  = this.activeHandle.cumulativeOffset();
             this.offsetX = (pointer[0] - offsets[0]);
             this.offsetY = (pointer[1] - offsets[1]);
           }
@@ -246,7 +246,7 @@ Control.Slider = Class.create({
   },
   draw: function(event) {
     var pointer = [Event.pointerX(event), Event.pointerY(event)];
-    var offsets = Position.cumulativeOffset(this.track);
+    var offsets = this.track.cumulativeOffset();
     pointer[0] -= this.offsetX + offsets[0];
     pointer[1] -= this.offsetY + offsets[1];
     this.event = event;
@@ -261,15 +261,15 @@ Control.Slider = Class.create({
     }
     this.active = false;
     this.dragging = false;
-  },  
+  },
   finishDrag: function(event, success) {
     this.active = false;
     this.dragging = false;
     this.updateFinished();
   },
   updateFinished: function() {
-    if (this.initialized &amp;&amp; this.options.onChange) 
+    if (this.initialized &amp;&amp; this.options.onChange)
       this.options.onChange(this.values.length&gt;1 ? this.values : this.value, this);
     this.event = null;
   }
-});
+});
\ No newline at end of file</diff>
      <filename>public/javascripts/slider.js</filename>
    </modified>
    <modified>
      <diff>@@ -7,141 +7,143 @@
  * @require prototype.js, livepipe.js
  */
 
-if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Control.Tabs requires Prototype to be loaded.&quot;;
-if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Control.Tabs requires Object.Event to be loaded.&quot;;
+/*global window, document, Prototype, $, $A, $H, $break, Class, Element, Event, Control */
+
+if(typeof(Prototype) == &quot;undefined&quot;) {
+    throw &quot;Control.Tabs requires Prototype to be loaded.&quot;; }
+if(typeof(Object.Event) == &quot;undefined&quot;) {
+    throw &quot;Control.Tabs requires Object.Event to be loaded.&quot;; }
 
 Control.Tabs = Class.create({
-	initialize: function(tab_list_container,options){
-		if(!$(tab_list_container))
-			throw &quot;Control.Tabs could not find the element: &quot; + tab_list_container;
-		this.activeContainer = false;
-		this.activeLink = false;
-		this.containers = $H({});
-		this.links = [];
-		Control.Tabs.instances.push(this);
-		this.options = {
-			beforeChange: Prototype.emptyFunction,
-			afterChange: Prototype.emptyFunction,
-			hover: false,
-			linkSelector: 'li a',
-			setClassOnContainer: false,
-			activeClassName: 'active',
-			defaultTab: 'first',
-			autoLinkExternal: true,
-			targetRegExp: /#(.+)$/,
-			showFunction: Element.show,
-			hideFunction: Element.hide
-		};
-		Object.extend(this.options,options || {});
-		(typeof(this.options.linkSelector == 'string')
-			? $(tab_list_container).select(this.options.linkSelector)
-			: this.options.linkSelector($(tab_list_container))
-		).findAll(function(link){
-			return (/^#/).exec((Prototype.Browser.WebKit ? decodeURIComponent(link.href) : link.href).replace(window.location.href.split('#')[0],''));
-		}).each(function(link){
-			this.addTab(link);
-		}.bind(this));
-		this.containers.values().each(Element.hide);
-		if(this.options.defaultTab == 'first')
-			this.setActiveTab(this.links.first());
-		else if(this.options.defaultTab == 'last')
-			this.setActiveTab(this.links.last());
-		else
-			this.setActiveTab(this.options.defaultTab);
-		var targets = this.options.targetRegExp.exec(window.location);
-		if(targets &amp;&amp; targets[1]){
-			targets[1].split(',').each(function(target){
-				this.setActiveTab(this.links.find(function(link){
-					return link.key == target;
-				}));
-			}.bind(this));
-		}
-		if(this.options.autoLinkExternal){
-			$A(document.getElementsByTagName('a')).each(function(a){
-				if(!this.links.include(a)){
-					var clean_href = a.href.replace(window.location.href.split('#')[0],'');
-					if(clean_href.substring(0,1) == '#'){
-						if(this.containers.keys().include(clean_href.substring(1))){
-							$(a).observe('click',function(event,clean_href){
-								this.setActiveTab(clean_href.substring(1));
-							}.bindAsEventListener(this,clean_href));
-						}
-					}
-				}
-			}.bind(this));
-		}
-	},
-	addTab: function(link){
-		this.links.push(link);
-		link.key = link.getAttribute('href').replace(window.location.href.split('#')[0],'').split('#').last().replace(/#/,'');
-		var container = $(link.key);
-		if(!container)
-			throw &quot;Control.Tabs: #&quot; + link.key + &quot; was not found on the page.&quot;
-		this.containers.set(link.key,container);
-		link[this.options.hover ? 'onmouseover' : 'onclick'] = function(link){
-			if(window.event)
-				Event.stop(window.event);
-			this.setActiveTab(link);
-			return false;
-		}.bind(this,link);
-	},
-	setActiveTab: function(link){
-		if(!link &amp;&amp; typeof(link) == 'undefined')
-			return;
-		if(typeof(link) == 'string'){
-			this.setActiveTab(this.links.find(function(_link){
-				return _link.key == link;
-			}));
-		}else if(typeof(link) == 'number'){
-			this.setActiveTab(this.links[link]);
-		}else{
-			if(this.notify('beforeChange',this.activeContainer,this.containers.get(link.key)) === false)
-				return;
-			if(this.activeContainer)
-				this.options.hideFunction(this.activeContainer);
-			this.links.each(function(item){
-				(this.options.setClassOnContainer ? $(item.parentNode) : item).removeClassName(this.options.activeClassName);
-			}.bind(this));
-			(this.options.setClassOnContainer ? $(link.parentNode) : link).addClassName(this.options.activeClassName);
-			this.activeContainer = this.containers.get(link.key);
-			this.activeLink = link;
-			this.options.showFunction(this.containers.get(link.key));
-			this.notify('afterChange',this.containers.get(link.key));
-		}
-	},
-	next: function(){
-		this.links.each(function(link,i){
-			if(this.activeLink == link &amp;&amp; this.links[i + 1]){
-				this.setActiveTab(this.links[i + 1]);
-				throw $break;
-			}
-		}.bind(this));
-	},
-	previous: function(){
-		this.links.each(function(link,i){
-			if(this.activeLink == link &amp;&amp; this.links[i - 1]){
-				this.setActiveTab(this.links[i - 1]);
-				throw $break;
-			}
-		}.bind(this));
-	},
-	first: function(){
-		this.setActiveTab(this.links.first());
-	},
-	last: function(){
-		this.setActiveTab(this.links.last());
-	}
+    initialize: function(tab_list_container,options){
+        if(!$(tab_list_container)) {
+            throw &quot;Control.Tabs could not find the element: &quot; + tab_list_container; }
+        this.activeContainer = false;
+        this.activeLink = false;
+        this.containers = $H({});
+        this.links = [];
+        Control.Tabs.instances.push(this);
+        this.options = {
+            beforeChange: Prototype.emptyFunction,
+            afterChange: Prototype.emptyFunction,
+            hover: false,
+            linkSelector: 'li a',
+            setClassOnContainer: false,
+            activeClassName: 'active',
+            defaultTab: 'first',
+            autoLinkExternal: true,
+            targetRegExp: /#(.+)$/,
+            showFunction: Element.show,
+            hideFunction: Element.hide
+        };
+        Object.extend(this.options,options || {});
+        (typeof(this.options.linkSelector == 'string') ? 
+            $(tab_list_container).select(this.options.linkSelector) : 
+            this.options.linkSelector($(tab_list_container))
+        ).findAll(function(link){
+            return (/^#/).exec((Prototype.Browser.WebKit ? decodeURIComponent(link.href) : link.href).replace(window.location.href.split('#')[0],''));
+        }).each(function(link){
+            this.addTab(link);
+        }.bind(this));
+        this.containers.values().each(Element.hide);
+        if(this.options.defaultTab == 'first') {
+            this.setActiveTab(this.links.first());
+        } else if(this.options.defaultTab == 'last') {
+            this.setActiveTab(this.links.last());
+        } else {
+            this.setActiveTab(this.options.defaultTab); }
+        var targets = this.options.targetRegExp.exec(window.location);
+        if(targets &amp;&amp; targets[1]){
+            targets[1].split(',').each(function(target){
+                this.setActiveTab(this.links.find(function(link){
+                    return link.key == target;
+                }));
+            }.bind(this));
+        }
+        if(this.options.autoLinkExternal){
+            $A(document.getElementsByTagName('a')).each(function(a){
+                if(!this.links.include(a)){
+                    var clean_href = a.href.replace(window.location.href.split('#')[0],'');
+                    if(clean_href.substring(0,1) == '#'){
+                        if(this.containers.keys().include(clean_href.substring(1))){
+                            $(a).observe('click',function(event,clean_href){
+                                this.setActiveTab(clean_href.substring(1));
+                            }.bindAsEventListener(this,clean_href));
+                        }
+                    }
+                }
+            }.bind(this));
+        }
+    },
+    addTab: function(link){
+        this.links.push(link);
+        link.key = link.getAttribute('href').replace(window.location.href.split('#')[0],'').split('#').last().replace(/#/,'');
+        var container = $(link.key);
+        if(!container) {
+            throw &quot;Control.Tabs: #&quot; + link.key + &quot; was not found on the page.&quot;; }
+        this.containers.set(link.key,container);
+        link[this.options.hover ? 'onmouseover' : 'onclick'] = function(link){
+            if(window.event) {
+                Event.stop(window.event); }
+            this.setActiveTab(link);
+            return false;
+        }.bind(this,link);
+    },
+    setActiveTab: function(link){
+        if(!link &amp;&amp; typeof(link) == 'undefined') {
+            return; }
+        if(typeof(link) == 'string'){
+            this.setActiveTab(this.links.find(function(_link){
+                return _link.key == link;
+            }));
+        }else if(typeof(link) == 'number'){
+            this.setActiveTab(this.links[link]);
+        }else{
+            if(this.notify('beforeChange',this.activeContainer,this.containers.get(link.key)) === false) {
+                return; }
+            if(this.activeContainer) {
+                this.options.hideFunction(this.activeContainer); }
+            this.links.each(function(item){
+                (this.options.setClassOnContainer ? $(item.parentNode) : item).removeClassName(this.options.activeClassName);
+            }.bind(this));
+            (this.options.setClassOnContainer ? $(link.parentNode) : link).addClassName(this.options.activeClassName);
+            this.activeContainer = this.containers.get(link.key);
+            this.activeLink = link;
+            this.options.showFunction(this.containers.get(link.key));
+            this.notify('afterChange',this.containers.get(link.key));
+        }
+    },
+    next: function(){
+        this.links.each(function(link,i){
+            if(this.activeLink == link &amp;&amp; this.links[i + 1]){
+                this.setActiveTab(this.links[i + 1]);
+                throw $break;
+            }
+        }.bind(this));
+    },
+    previous: function(){
+        this.links.each(function(link,i){
+            if(this.activeLink == link &amp;&amp; this.links[i - 1]){
+                this.setActiveTab(this.links[i - 1]);
+                throw $break;
+            }
+        }.bind(this));
+    },
+    first: function(){
+        this.setActiveTab(this.links.first());
+    },
+    last: function(){
+        this.setActiveTab(this.links.last());
+    }
 });
 Object.extend(Control.Tabs,{
-	instances: [],
-	findByTabId: function(id){
-		return Control.Tabs.instances.find(function(tab){
-			return tab.links.find(function(link){
-				return link.key == id;
-			});
-		});
-	}
+    instances: [],
+    findByTabId: function(id){
+        return Control.Tabs.instances.find(function(tab){
+            return tab.links.find(function(link){
+                return link.key == id;
+            });
+        });
+    }
 });
 Object.Event.extend(Control.Tabs);</diff>
      <filename>public/javascripts/tabs.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,60 +10,60 @@
 /*global window, document, Prototype, Class, $, $A, Control */
 
 if(typeof(Prototype) == &quot;undefined&quot;) {
-	throw &quot;Control.TextArea requires Prototype to be loaded.&quot;; }
+    throw &quot;Control.TextArea requires Prototype to be loaded.&quot;; }
 if(typeof(Object.Event) == &quot;undefined&quot;) {
-	throw &quot;Control.TextArea requires Object.Event to be loaded.&quot;; }
+    throw &quot;Control.TextArea requires Object.Event to be loaded.&quot;; }
 
 Control.TextArea = Class.create({
-	initialize: function(textarea){
-		this.onChangeTimeout = false;
-		this.element = $(textarea);
-		$(this.element).observe('keyup',this.doOnChange.bindAsEventListener(this));
-		$(this.element).observe('paste',this.doOnChange.bindAsEventListener(this));
-		$(this.element).observe('input',this.doOnChange.bindAsEventListener(this));
-		if(!!document.selection){
-			$(this.element).observe('mouseup',this.saveRange.bindAsEventListener(this));  
-			$(this.element).observe('keyup',this.saveRange.bindAsEventListener(this));
-		}
-	},
-	doOnChange: function(event){
-		if(this.onChangeTimeout) {
-			window.clearTimeout(this.onChangeTimeout); }
-		this.onChangeTimeout = window.setTimeout(function(){
-			this.notify('change',this.getValue());
-		}.bind(this),Control.TextArea.onChangeTimeoutLength);
-	},
-	saveRange: function(){
-		this.range = document.selection.createRange();  
-	},
-	getValue: function(){
-		return this.element.value;
-	},
-	getSelection: function(){
-		if(!!document.selection) {
-			return document.selection.createRange().text; }
-		else if(!!this.element.setSelectionRange) {
-			return this.element.value.substring(this.element.selectionStart,this.element.selectionEnd); }
-		else {
-			return false; }
-	},
-	replaceSelection: function(text){
-		var scroll_top = this.element.scrollTop;
-		if(!!document.selection){
-			this.element.focus();
-			var range = (this.range) ? this.range : document.selection.createRange();
-			range.text = text;
-			range.select();
-		}else if(!!this.element.setSelectionRange){
-			var selection_start = this.element.selectionStart;
-			this.element.value = this.element.value.substring(0,selection_start) + text + this.element.value.substring(this.element.selectionEnd);
-			this.element.setSelectionRange(selection_start + text.length,selection_start + text.length);
-		}
-		this.doOnChange();
-		this.element.focus();
-		this.element.scrollTop = scroll_top;
-	},
-	wrapSelection: function(before,after){
+    initialize: function(textarea){
+        this.onChangeTimeout = false;
+        this.element = $(textarea);
+        $(this.element).observe('keyup',this.doOnChange.bindAsEventListener(this));
+        $(this.element).observe('paste',this.doOnChange.bindAsEventListener(this));
+        $(this.element).observe('input',this.doOnChange.bindAsEventListener(this));
+        if(!!document.selection){
+            $(this.element).observe('mouseup',this.saveRange.bindAsEventListener(this));  
+            $(this.element).observe('keyup',this.saveRange.bindAsEventListener(this));
+        }
+    },
+    doOnChange: function(event){
+        if(this.onChangeTimeout) {
+            window.clearTimeout(this.onChangeTimeout); }
+        this.onChangeTimeout = window.setTimeout(function(){
+            this.notify('change',this.getValue());
+        }.bind(this),Control.TextArea.onChangeTimeoutLength);
+    },
+    saveRange: function(){
+        this.range = document.selection.createRange();  
+    },
+    getValue: function(){
+        return this.element.value;
+    },
+    getSelection: function(){
+        if(!!document.selection) {
+            return document.selection.createRange().text; }
+        else if(!!this.element.setSelectionRange) {
+            return this.element.value.substring(this.element.selectionStart,this.element.selectionEnd); }
+        else {
+            return false; }
+    },
+    replaceSelection: function(text){
+        var scroll_top = this.element.scrollTop;
+        if(!!document.selection){
+            this.element.focus();
+            var range = (this.range) ? this.range : document.selection.createRange();
+            range.text = text;
+            range.select();
+        }else if(!!this.element.setSelectionRange){
+            var selection_start = this.element.selectionStart;
+            this.element.value = this.element.value.substring(0,selection_start) + text + this.element.value.substring(this.element.selectionEnd);
+            this.element.setSelectionRange(selection_start + text.length,selection_start + text.length);
+        }
+        this.doOnChange();
+        this.element.focus();
+        this.element.scrollTop = scroll_top;
+    },
+    wrapSelection: function(before,after){
         var sel = this.getSelection();
         // Remove the wrapping if the selection has the same before/after
         if (sel.indexOf(before) === 0 &amp;&amp; 
@@ -71,52 +71,52 @@ Control.TextArea = Class.create({
             this.replaceSelection(sel.substring(before.length, 
                 sel.length - after.length));
         } else { this.replaceSelection(before + sel + after); }
-	},
-	insertBeforeSelection: function(text){
-		this.replaceSelection(text + this.getSelection());
-	},
-	insertAfterSelection: function(text){
-		this.replaceSelection(this.getSelection() + text);
-	},
-	collectFromEachSelectedLine: function(callback,before,after){
-		this.replaceSelection((before || '') + $A(this.getSelection().split(&quot;\n&quot;)).collect(callback).join(&quot;\n&quot;) + (after || ''));
-	},
-	insertBeforeEachSelectedLine: function(text,before,after){
-		this.collectFromEachSelectedLine(function(line){
-		},before,after);
-	}
+    },
+    insertBeforeSelection: function(text){
+        this.replaceSelection(text + this.getSelection());
+    },
+    insertAfterSelection: function(text){
+        this.replaceSelection(this.getSelection() + text);
+    },
+    collectFromEachSelectedLine: function(callback,before,after){
+        this.replaceSelection((before || '') + $A(this.getSelection().split(&quot;\n&quot;)).collect(callback).join(&quot;\n&quot;) + (after || ''));
+    },
+    insertBeforeEachSelectedLine: function(text,before,after){
+        this.collectFromEachSelectedLine(function(line){
+        },before,after);
+    }
 });
 Object.extend(Control.TextArea,{
-	onChangeTimeoutLength: 500
+    onChangeTimeoutLength: 500
 });
 Object.Event.extend(Control.TextArea);
 
-Control.TextArea.ToolBar = Class.create(	{
-	initialize: function(textarea,toolbar){
-		this.textarea = textarea;
-		if(toolbar) {
-			this.container = $(toolbar); }
-		else{
-			this.container = $(document.createElement('ul'));
-			this.textarea.element.parentNode.insertBefore(this.container,this.textarea.element);
-		}
-	},
-	attachButton: function(node,callback){
+Control.TextArea.ToolBar = Class.create(    {
+    initialize: function(textarea,toolbar){
+        this.textarea = textarea;
+        if(toolbar) {
+            this.container = $(toolbar); }
+        else{
+            this.container = $(document.createElement('ul'));
+            this.textarea.element.parentNode.insertBefore(this.container,this.textarea.element);
+        }
+    },
+    attachButton: function(node,callback){
         node.onclick = function(){return false;};
-		$(node).observe('click',callback.bindAsEventListener(this.textarea));
-	},
-	addButton: function(link_text,callback,attrs){
-		var li = document.createElement('li');
-		var a = document.createElement('a');
-		a.href = '#';
-		this.attachButton(a,callback);
-		li.appendChild(a);
-		Object.extend(a,attrs || {});
-		if(link_text){
-			var span = document.createElement('span');
-			span.innerHTML = link_text;
-			a.appendChild(span);
-		}
-		this.container.appendChild(li);
-	}
+        $(node).observe('click',callback.bindAsEventListener(this.textarea));
+    },
+    addButton: function(link_text,callback,attrs){
+        var li = document.createElement('li');
+        var a = document.createElement('a');
+        a.href = '#';
+        this.attachButton(a,callback);
+        li.appendChild(a);
+        Object.extend(a,attrs || {});
+        if(link_text){
+            var span = document.createElement('span');
+            span.innerHTML = link_text;
+            a.appendChild(span);
+        }
+        this.container.appendChild(li);
+    }
 });</diff>
      <filename>public/javascripts/textarea.js</filename>
    </modified>
    <modified>
      <diff>@@ -9,921 +9,921 @@
 
 //adds onDraw and constrainToViewport option to draggable
 if(typeof(Draggable) != 'undefined'){
-	//allows the point to be modified with an onDraw callback
-	Draggable.prototype.draw = function(point) {
-		var pos = Position.cumulativeOffset(this.element);
-		if(this.options.ghosting) {
-			var r = Position.realOffset(this.element);
-			pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
-		}
-		
-		var d = this.currentDelta();
-		pos[0] -= d[0]; pos[1] -= d[1];
-		
-		if(this.options.scroll &amp;&amp; (this.options.scroll != window &amp;&amp; this._isScrollChild)) {
-			pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
-			pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
-		}
-		
-		var p = [0,1].map(function(i){ 
-			return (point[i]-pos[i]-this.offset[i]) 
-		}.bind(this));
-		
-		if(this.options.snap) {
-			if(typeof this.options.snap == 'function') {
-				p = this.options.snap(p[0],p[1],this);
-			} else {
-				if(this.options.snap instanceof Array) {
-					p = p.map( function(v, i) {return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
-				} else {
-					p = p.map( function(v) {return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
-	  			}
-			}
-		}
-		
-		if(this.options.onDraw)
-			this.options.onDraw.bind(this)(p);
-		else{
-			var style = this.element.style;
-			if(this.options.constrainToViewport){
-				var viewport_dimensions = document.viewport.getDimensions();
-				var container_dimensions = this.element.getDimensions();
-				var margin_top = parseInt(this.element.getStyle('margin-top'));
-				var margin_left = parseInt(this.element.getStyle('margin-left'));
-				var boundary = [[
-					0 - margin_left,
-					0 - margin_top
-				],[
-					(viewport_dimensions.width - container_dimensions.width) - margin_left,
-					(viewport_dimensions.height - container_dimensions.height) - margin_top
-				]];
-				if((!this.options.constraint) || (this.options.constraint=='horizontal')){ 
-					if((p[0] &gt;= boundary[0][0]) &amp;&amp; (p[0] &lt;= boundary[1][0]))
-						this.element.style.left = p[0] + &quot;px&quot;;
-					else
-						this.element.style.left = ((p[0] &lt; boundary[0][0]) ? boundary[0][0] : boundary[1][0]) + &quot;px&quot;;
-				} 
-				if((!this.options.constraint) || (this.options.constraint=='vertical')){ 
-					if((p[1] &gt;= boundary[0][1] ) &amp;&amp; (p[1] &lt;= boundary[1][1]))
-						this.element.style.top = p[1] + &quot;px&quot;;
-				  else
-						this.element.style.top = ((p[1] &lt;= boundary[0][1]) ? boundary[0][1] : boundary[1][1]) + &quot;px&quot;;			   
-				}
-			}else{
-				if((!this.options.constraint) || (this.options.constraint=='horizontal'))
-				  style.left = p[0] + &quot;px&quot;;
-				if((!this.options.constraint) || (this.options.constraint=='vertical'))
-				  style.top	 = p[1] + &quot;px&quot;;
-			}
-			if(style.visibility==&quot;hidden&quot;)
-				style.visibility = &quot;&quot;; // fix gecko rendering
-		}
-	};
+    //allows the point to be modified with an onDraw callback
+    Draggable.prototype.draw = function(point) {
+        var pos = Position.cumulativeOffset(this.element);
+        if(this.options.ghosting) {
+            var r = Position.realOffset(this.element);
+            pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
+        }
+        
+        var d = this.currentDelta();
+        pos[0] -= d[0]; pos[1] -= d[1];
+        
+        if(this.options.scroll &amp;&amp; (this.options.scroll != window &amp;&amp; this._isScrollChild)) {
+            pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+            pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+        }
+        
+        var p = [0,1].map(function(i){ 
+            return (point[i]-pos[i]-this.offset[i]) 
+        }.bind(this));
+        
+        if(this.options.snap) {
+            if(typeof this.options.snap == 'function') {
+                p = this.options.snap(p[0],p[1],this);
+            } else {
+                if(this.options.snap instanceof Array) {
+                    p = p.map( function(v, i) {return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
+                } else {
+                    p = p.map( function(v) {return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
+                  }
+            }
+        }
+        
+        if(this.options.onDraw)
+            this.options.onDraw.bind(this)(p);
+        else{
+            var style = this.element.style;
+            if(this.options.constrainToViewport){
+                var viewport_dimensions = document.viewport.getDimensions();
+                var container_dimensions = this.element.getDimensions();
+                var margin_top = parseInt(this.element.getStyle('margin-top'));
+                var margin_left = parseInt(this.element.getStyle('margin-left'));
+                var boundary = [[
+                    0 - margin_left,
+                    0 - margin_top
+                ],[
+                    (viewport_dimensions.width - container_dimensions.width) - margin_left,
+                    (viewport_dimensions.height - container_dimensions.height) - margin_top
+                ]];
+                if((!this.options.constraint) || (this.options.constraint=='horizontal')){ 
+                    if((p[0] &gt;= boundary[0][0]) &amp;&amp; (p[0] &lt;= boundary[1][0]))
+                        this.element.style.left = p[0] + &quot;px&quot;;
+                    else
+                        this.element.style.left = ((p[0] &lt; boundary[0][0]) ? boundary[0][0] : boundary[1][0]) + &quot;px&quot;;
+                } 
+                if((!this.options.constraint) || (this.options.constraint=='vertical')){ 
+                    if((p[1] &gt;= boundary[0][1] ) &amp;&amp; (p[1] &lt;= boundary[1][1]))
+                        this.element.style.top = p[1] + &quot;px&quot;;
+                  else
+                        this.element.style.top = ((p[1] &lt;= boundary[0][1]) ? boundary[0][1] : boundary[1][1]) + &quot;px&quot;;               
+                }
+            }else{
+                if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+                  style.left = p[0] + &quot;px&quot;;
+                if((!this.options.constraint) || (this.options.constraint=='vertical'))
+                  style.top     = p[1] + &quot;px&quot;;
+            }
+            if(style.visibility==&quot;hidden&quot;)
+                style.visibility = &quot;&quot;; // fix gecko rendering
+        }
+    };
 }
 
 if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Control.Window requires Prototype to be loaded.&quot;;
+    throw &quot;Control.Window requires Prototype to be loaded.&quot;;
 if(typeof(IframeShim) == &quot;undefined&quot;)
-	throw &quot;Control.Window requires IframeShim to be loaded.&quot;;
+    throw &quot;Control.Window requires IframeShim to be loaded.&quot;;
 if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Control.Window requires Object.Event to be loaded.&quot;;
+    throw &quot;Control.Window requires Object.Event to be loaded.&quot;;
 /*
-	known issues:
-		- when iframe is clicked is does not gain focus
-		- safari can't open multiple iframes properly
-		- constrainToViewport: body must have no margin or padding for this to work properly
-		- iframe will be mis positioned during fade in
-		- document.viewport does not account for scrollbars (this will eventually be fixed in the prototype core)
-	notes
-		- setting constrainToViewport only works when the page is not scrollable
-		- setting draggable: true will negate the effects of position: center
+    known issues:
+        - when iframe is clicked is does not gain focus
+        - safari can't open multiple iframes properly
+        - constrainToViewport: body must have no margin or padding for this to work properly
+        - iframe will be mis positioned during fade in
+        - document.viewport does not account for scrollbars (this will eventually be fixed in the prototype core)
+    notes
+        - setting constrainToViewport only works when the page is not scrollable
+        - setting draggable: true will negate the effects of position: center
 */
 Control.Window = Class.create({
-	initialize: function(container,options){
-		Control.Window.windows.push(this);
-		
-		//attribute initialization
-		this.container = false;
-		this.isOpen = false;
-		this.href = false;
-		this.sourceContainer = false; //this is optionally the container that will open the window
-		this.ajaxRequest = false;
-		this.remoteContentLoaded = false; //this is set when the code to load the remote content is run, onRemoteContentLoaded is fired when the connection is closed
-		this.numberInSequence = Control.Window.windows.length + 1; //only useful for the effect scoping
-		this.indicator = false;
-		this.effects = {
-			fade: false,
-			appear: false
-		};
-		this.indicatorEffects = {
-			fade: false,
-			appear: false
-		};
-		
-		//options
-		this.options = Object.extend({
-			//lifecycle
-			beforeOpen: Prototype.emptyFunction,
-			afterOpen: Prototype.emptyFunction,
-			beforeClose: Prototype.emptyFunction,
-			afterClose: Prototype.emptyFunction,
-			//dimensions and modes
-			height: null,
-			width: null,
-			className: false,
-			position: 'center', //'center', 'relative', [x,y], [function(){return x;},function(){return y;}]
-			offsetLeft: 0, //available only for anchors opening the window, or windows set to position: hover
-			offsetTop: 0, //&quot;&quot;
-			iframe: false, //if the window has an href, this will display the href as an iframe instead of requesting the url as an an Ajax.Request
-			hover: false, //element object to hover over, or if &quot;true&quot; only available for windows with sourceContainer (an anchor or any element already on the page with an href attribute)
-			indicator: false, //element to show or hide when ajax requests, images and iframes are loading
-			closeOnClick: false, //does not work with hover,can be: true (click anywhere), 'container' (will refer to this.container), or element (a specific element)
-			iframeshim: true, //wether or not to position an iFrameShim underneath the window 
-			//effects
-			fade: false,
-			fadeDuration: 0.75,
-			//draggable
-			draggable: false,
-			onDrag: Prototype.emptyFunction,
-			//resizable
-			resizable: false,
-			minHeight: false,
-			minWidth: false,
-			maxHeight: false,
-			maxWidth: false,
-			onResize: Prototype.emptyFunction,
-			//draggable and resizable
-			constrainToViewport: false,
-			//ajax
-			method: 'post',
-			parameters: {},
-			onComplete: Prototype.emptyFunction,
-			onSuccess: Prototype.emptyFunction,
-			onFailure: Prototype.emptyFunction,
-			onException: Prototype.emptyFunction,
-			//any element with an href (image,iframe,ajax) will call this after it is done loading
-			onRemoteContentLoaded: Prototype.emptyFunction,
-			insertRemoteContentAt: false //false will set this to this.container, can be string selector (first returned will be selected), or an Element that must be a child of this.container
-		},options || {});
-		
-		//container setup
-		this.indicator = this.options.indicator ? $(this.options.indicator) : false;
-		if(container){
-			if(typeof(container) == &quot;string&quot; &amp;&amp; container.match(Control.Window.uriRegex))
-				this.href = container;
-			else{
-				this.container = $(container);
-				//need to create the container now for tooltips (or hover: element with no container already on the page)
-				//second call made below will not create the container since the check is done inside createDefaultContainer()
-				this.createDefaultContainer(container);
-				//if an element with an href was passed in we use it to activate the window
-				if(this.container &amp;&amp; ((this.container.readAttribute('href') &amp;&amp; this.container.readAttribute('href') != '') || (this.options.hover &amp;&amp; this.options.hover !== true))){						
-					if(this.options.hover &amp;&amp; this.options.hover !== true)
-						this.sourceContainer = $(this.options.hover);
-					else{
-						this.sourceContainer = this.container;
-						this.href = this.container.readAttribute('href');
-						var rel = this.href.match(/^#(.+)$/);
-						if(rel &amp;&amp; rel[1]){
-							this.container = $(rel[1]);
-							this.href = false;
-						}else
-							this.container = false;
-					}
-					//hover or click handling
-					this.sourceContainerOpenHandler = function(event){
-						this.open(event);
-						event.stop();
-						return false;
-					}.bindAsEventListener(this);
-					this.sourceContainerCloseHandler = function(event){
-						this.close(event);
-					}.bindAsEventListener(this);
-					this.sourceContainerMouseMoveHandler = function(event){
-						this.position(event);
-					}.bindAsEventListener(this);
-					if(this.options.hover){
-						this.sourceContainer.observe('mouseenter',this.sourceContainerOpenHandler);
-						this.sourceContainer.observe('mouseleave',this.sourceContainerCloseHandler);
-						if(this.options.position == 'mouse')
-							this.sourceContainer.observe('mousemove',this.sourceContainerMouseMoveHandler);
-					}else
-						this.sourceContainer.observe('click',this.sourceContainerOpenHandler);
-				}
-			}
-		}
-		this.createDefaultContainer(container);
-		if(this.options.insertRemoteContentAt === false)
-			this.options.insertRemoteContentAt = this.container;
-		var styles = {
-			margin: 0,
-			position: 'absolute',
-			zIndex: Control.Window.initialZIndexForWindow()
-		};
-		if(this.options.width)
-			styles.width = $value(this.options.width) + 'px';
-		if(this.options.height)
-			styles.height = $value(this.options.height) + 'px';
-		this.container.setStyle(styles);
-		if(this.options.className)
-			this.container.addClassName(this.options.className);
-		this.positionHandler = this.position.bindAsEventListener(this);
-		this.outOfBoundsPositionHandler = this.ensureInBounds.bindAsEventListener(this);
-		this.bringToFrontHandler = this.bringToFront.bindAsEventListener(this);
-		this.container.observe('mousedown',this.bringToFrontHandler);
-		this.container.hide();
-		this.closeHandler = this.close.bindAsEventListener(this);
-		//iframeshim setup
-		if(this.options.iframeshim){
-			this.iFrameShim = new IframeShim();
-			this.iFrameShim.hide();
-		}
-		//resizable support
-		this.applyResizable();
-		//draggable support
-		this.applyDraggable();
-		
-		//makes sure the window can't go out of bounds
-		Event.observe(window,'resize',this.outOfBoundsPositionHandler);
-		
-		this.notify('afterInitialize');
-	},
-	open: function(event){
-		if(this.isOpen){
-			this.bringToFront();
-			return false;
-		}
-		if(this.notify('beforeOpen') === false)
-			return false;
-		//closeOnClick
-		if(this.options.closeOnClick){
-			if(this.options.closeOnClick === true)
-				this.closeOnClickContainer = $(document.body);
-			else if(this.options.closeOnClick == 'container')
-				this.closeOnClickContainer = this.container;
-			else if (this.options.closeOnClick == 'overlay'){
-				Control.Overlay.load();
-				this.closeOnClickContainer = Control.Overlay.container;
-			}else
-				this.closeOnClickContainer = $(this.options.closeOnClick);
-			this.closeOnClickContainer.observe('click',this.closeHandler);
-		}
-		if(this.href &amp;&amp; !this.options.iframe &amp;&amp; !this.remoteContentLoaded){
-			//link to image
-			this.remoteContentLoaded = true;
-			if(this.href.match(/\.(jpe?g|gif|png|tiff?)$/i)){
-				var img = new Element('img');
-				img.observe('load',function(img){
-					this.getRemoteContentInsertionTarget().insert(img);
-					this.position();
-					if(this.notify('onRemoteContentLoaded') !== false){
-						if(this.options.indicator)
-							this.hideIndicator();
-						this.finishOpen();
-					}
-				}.bind(this,img));
-				img.writeAttribute('src',this.href);
-			}else{
-				//if this is an ajax window it will only open if the request is successful
-				if(!this.ajaxRequest){
-					if(this.options.indicator)
-						this.showIndicator();
-					this.ajaxRequest = new Ajax.Request(this.href,{
-						method: this.options.method,
-						parameters: this.options.parameters,
-						onComplete: function(request){
-							this.notify('onComplete',request);
-							this.ajaxRequest = false;
-						}.bind(this),
-						onSuccess: function(request){
-							this.getRemoteContentInsertionTarget().insert(request.responseText);
-							this.notify('onSuccess',request);
-							if(this.notify('onRemoteContentLoaded') !== false){
-								if(this.options.indicator)
-									this.hideIndicator();
-								this.finishOpen();
-							}
-						}.bind(this),
-						onFailure: function(request){
-							this.notify('onFailure',request);
-							if(this.options.indicator)
-								this.hideIndicator();
-						}.bind(this),
-						onException: function(request,e){
-							this.notify('onException',request,e);
-							if(this.options.indicator)
-								this.hideIndicator();
-						}.bind(this)
-					});
-				}
-			}
-			return true;
-		}else if(this.options.iframe &amp;&amp; !this.remoteContentLoaded){
-			//iframe
-			this.remoteContentLoaded = true;
-			if(this.options.indicator)
-				this.showIndicator();
-			this.getRemoteContentInsertionTarget().insert(Control.Window.iframeTemplate.evaluate({
-				href: this.href
-			}));
-			var iframe = this.container.down('iframe');
-			iframe.onload = function(){
-				this.notify('onRemoteContentLoaded');
-				if(this.options.indicator)
-					this.hideIndicator();
-				iframe.onload = null;
-			}.bind(this);
-		}
-		this.finishOpen(event);
-		return true
-	},
-	close: function(event){ //event may or may not be present
-		if(!this.isOpen || this.notify('beforeClose',event) === false)
-			return false;
-		if(this.options.closeOnClick)
-			this.closeOnClickContainer.stopObserving('click',this.closeHandler);
-		if(this.options.fade){
-			this.effects.fade = new Effect.Fade(this.container,{
-				queue: {
-					position: 'front',
-					scope: 'Control.Window' + this.numberInSequence
-				},
-				from: 1,
-				to: 0,
-				duration: this.options.fadeDuration / 2,
-				afterFinish: function(){
-					if(this.iFrameShim)
-						this.iFrameShim.hide();
-					this.isOpen = false;
-					this.notify('afterClose');
-				}.bind(this)
-			});
-		}else{
-			this.container.hide();
-			if(this.iFrameShim)
-				this.iFrameShim.hide();
-		}
-		if(this.ajaxRequest)
-			this.ajaxRequest.transport.abort();
-		if(!(this.options.draggable || this.options.resizable) &amp;&amp; this.options.position == 'center')
-			Event.stopObserving(window,'resize',this.positionHandler);
-		if(!this.options.draggable &amp;&amp; this.options.position == 'center')
-			Event.stopObserving(window,'scroll',this.positionHandler);
-		if(this.options.indicator)
-			this.hideIndicator();
-		if(!this.options.fade){
-			this.isOpen = false;
-			this.notify('afterClose');
+    initialize: function(container,options){
+        Control.Window.windows.push(this);
+        
+        //attribute initialization
+        this.container = false;
+        this.isOpen = false;
+        this.href = false;
+        this.sourceContainer = false; //this is optionally the container that will open the window
+        this.ajaxRequest = false;
+        this.remoteContentLoaded = false; //this is set when the code to load the remote content is run, onRemoteContentLoaded is fired when the connection is closed
+        this.numberInSequence = Control.Window.windows.length + 1; //only useful for the effect scoping
+        this.indicator = false;
+        this.effects = {
+            fade: false,
+            appear: false
+        };
+        this.indicatorEffects = {
+            fade: false,
+            appear: false
+        };
+        
+        //options
+        this.options = Object.extend({
+            //lifecycle
+            beforeOpen: Prototype.emptyFunction,
+            afterOpen: Prototype.emptyFunction,
+            beforeClose: Prototype.emptyFunction,
+            afterClose: Prototype.emptyFunction,
+            //dimensions and modes
+            height: null,
+            width: null,
+            className: false,
+            position: 'center', //'center', 'relative', [x,y], [function(){return x;},function(){return y;}]
+            offsetLeft: 0, //available only for anchors opening the window, or windows set to position: hover
+            offsetTop: 0, //&quot;&quot;
+            iframe: false, //if the window has an href, this will display the href as an iframe instead of requesting the url as an an Ajax.Request
+            hover: false, //element object to hover over, or if &quot;true&quot; only available for windows with sourceContainer (an anchor or any element already on the page with an href attribute)
+            indicator: false, //element to show or hide when ajax requests, images and iframes are loading
+            closeOnClick: false, //does not work with hover,can be: true (click anywhere), 'container' (will refer to this.container), or element (a specific element)
+            iframeshim: true, //whether or not to position an iFrameShim underneath the window 
+            //effects
+            fade: false,
+            fadeDuration: 0.75,
+            //draggable
+            draggable: false,
+            onDrag: Prototype.emptyFunction,
+            //resizable
+            resizable: false,
+            minHeight: false,
+            minWidth: false,
+            maxHeight: false,
+            maxWidth: false,
+            onResize: Prototype.emptyFunction,
+            //draggable and resizable
+            constrainToViewport: false,
+            //ajax
+            method: 'post',
+            parameters: {},
+            onComplete: Prototype.emptyFunction,
+            onSuccess: Prototype.emptyFunction,
+            onFailure: Prototype.emptyFunction,
+            onException: Prototype.emptyFunction,
+            //any element with an href (image,iframe,ajax) will call this after it is done loading
+            onRemoteContentLoaded: Prototype.emptyFunction,
+            insertRemoteContentAt: false //false will set this to this.container, can be string selector (first returned will be selected), or an Element that must be a child of this.container
+        },options || {});
+        
+        //container setup
+        this.indicator = this.options.indicator ? $(this.options.indicator) : false;
+        if(container){
+            if(typeof(container) == &quot;string&quot; &amp;&amp; container.match(Control.Window.uriRegex))
+                this.href = container;
+            else{
+                this.container = $(container);
+                //need to create the container now for tooltips (or hover: element with no container already on the page)
+                //second call made below will not create the container since the check is done inside createDefaultContainer()
+                this.createDefaultContainer(container);
+                //if an element with an href was passed in we use it to activate the window
+                if(this.container &amp;&amp; ((this.container.readAttribute('href') &amp;&amp; this.container.readAttribute('href') != '') || (this.options.hover &amp;&amp; this.options.hover !== true))){                        
+                    if(this.options.hover &amp;&amp; this.options.hover !== true)
+                        this.sourceContainer = $(this.options.hover);
+                    else{
+                        this.sourceContainer = this.container;
+                        this.href = this.container.readAttribute('href');
+                        var rel = this.href.match(/^#(.+)$/);
+                        if(rel &amp;&amp; rel[1]){
+                            this.container = $(rel[1]);
+                            this.href = false;
+                        }else
+                            this.container = false;
+                    }
+                    //hover or click handling
+                    this.sourceContainerOpenHandler = function(event){
+                        this.open(event);
+                        event.stop();
+                        return false;
+                    }.bindAsEventListener(this);
+                    this.sourceContainerCloseHandler = function(event){
+                        this.close(event);
+                    }.bindAsEventListener(this);
+                    this.sourceContainerMouseMoveHandler = function(event){
+                        this.position(event);
+                    }.bindAsEventListener(this);
+                    if(this.options.hover){
+                        this.sourceContainer.observe('mouseenter',this.sourceContainerOpenHandler);
+                        this.sourceContainer.observe('mouseleave',this.sourceContainerCloseHandler);
+                        if(this.options.position == 'mouse')
+                            this.sourceContainer.observe('mousemove',this.sourceContainerMouseMoveHandler);
+                    }else
+                        this.sourceContainer.observe('click',this.sourceContainerOpenHandler);
+                }
+            }
+        }
+        this.createDefaultContainer(container);
+        if(this.options.insertRemoteContentAt === false)
+            this.options.insertRemoteContentAt = this.container;
+        var styles = {
+            margin: 0,
+            position: 'absolute',
+            zIndex: Control.Window.initialZIndexForWindow()
+        };
+        if(this.options.width)
+            styles.width = $value(this.options.width) + 'px';
+        if(this.options.height)
+            styles.height = $value(this.options.height) + 'px';
+        this.container.setStyle(styles);
+        if(this.options.className)
+            this.container.addClassName(this.options.className);
+        this.positionHandler = this.position.bindAsEventListener(this);
+        this.outOfBoundsPositionHandler = this.ensureInBounds.bindAsEventListener(this);
+        this.bringToFrontHandler = this.bringToFront.bindAsEventListener(this);
+        this.container.observe('mousedown',this.bringToFrontHandler);
+        this.container.hide();
+        this.closeHandler = this.close.bindAsEventListener(this);
+        //iframeshim setup
+        if(this.options.iframeshim){
+            this.iFrameShim = new IframeShim();
+            this.iFrameShim.hide();
+        }
+        //resizable support
+        this.applyResizable();
+        //draggable support
+        this.applyDraggable();
+        
+        //makes sure the window can't go out of bounds
+        Event.observe(window,'resize',this.outOfBoundsPositionHandler);
+        
+        this.notify('afterInitialize');
+    },
+    open: function(event){
+        if(this.isOpen){
+            this.bringToFront();
+            return false;
+        }
+        if(this.notify('beforeOpen') === false)
+            return false;
+        //closeOnClick
+        if(this.options.closeOnClick){
+            if(this.options.closeOnClick === true)
+                this.closeOnClickContainer = $(document.body);
+            else if(this.options.closeOnClick == 'container')
+                this.closeOnClickContainer = this.container;
+            else if (this.options.closeOnClick == 'overlay'){
+                Control.Overlay.load();
+                this.closeOnClickContainer = Control.Overlay.container;
+            }else
+                this.closeOnClickContainer = $(this.options.closeOnClick);
+            this.closeOnClickContainer.observe('click',this.closeHandler);
+        }
+        if(this.href &amp;&amp; !this.options.iframe &amp;&amp; !this.remoteContentLoaded){
+            //link to image
+            this.remoteContentLoaded = true;
+            if(this.href.match(/\.(jpe?g|gif|png|tiff?)$/i)){
+                var img = new Element('img');
+                img.observe('load',function(img){
+                    this.getRemoteContentInsertionTarget().insert(img);
+                    this.position();
+                    if(this.notify('onRemoteContentLoaded') !== false){
+                        if(this.options.indicator)
+                            this.hideIndicator();
+                        this.finishOpen();
+                    }
+                }.bind(this,img));
+                img.writeAttribute('src',this.href);
+            }else{
+                //if this is an ajax window it will only open if the request is successful
+                if(!this.ajaxRequest){
+                    if(this.options.indicator)
+                        this.showIndicator();
+                    this.ajaxRequest = new Ajax.Request(this.href,{
+                        method: this.options.method,
+                        parameters: this.options.parameters,
+                        onComplete: function(request){
+                            this.notify('onComplete',request);
+                            this.ajaxRequest = false;
+                        }.bind(this),
+                        onSuccess: function(request){
+                            this.getRemoteContentInsertionTarget().insert(request.responseText);
+                            this.notify('onSuccess',request);
+                            if(this.notify('onRemoteContentLoaded') !== false){
+                                if(this.options.indicator)
+                                    this.hideIndicator();
+                                this.finishOpen();
+                            }
+                        }.bind(this),
+                        onFailure: function(request){
+                            this.notify('onFailure',request);
+                            if(this.options.indicator)
+                                this.hideIndicator();
+                        }.bind(this),
+                        onException: function(request,e){
+                            this.notify('onException',request,e);
+                            if(this.options.indicator)
+                                this.hideIndicator();
+                        }.bind(this)
+                    });
+                }
+            }
+            return true;
+        }else if(this.options.iframe &amp;&amp; !this.remoteContentLoaded){
+            //iframe
+            this.remoteContentLoaded = true;
+            if(this.options.indicator)
+                this.showIndicator();
+            this.getRemoteContentInsertionTarget().insert(Control.Window.iframeTemplate.evaluate({
+                href: this.href
+            }));
+            var iframe = this.container.down('iframe');
+            iframe.onload = function(){
+                this.notify('onRemoteContentLoaded');
+                if(this.options.indicator)
+                    this.hideIndicator();
+                iframe.onload = null;
+            }.bind(this);
+        }
+        this.finishOpen(event);
+        return true
+    },
+    close: function(event){ //event may or may not be present
+        if(!this.isOpen || this.notify('beforeClose',event) === false)
+            return false;
+        if(this.options.closeOnClick)
+            this.closeOnClickContainer.stopObserving('click',this.closeHandler);
+        if(this.options.fade){
+            this.effects.fade = new Effect.Fade(this.container,{
+                queue: {
+                    position: 'front',
+                    scope: 'Control.Window' + this.numberInSequence
+                },
+                from: 1,
+                to: 0,
+                duration: this.options.fadeDuration / 2,
+                afterFinish: function(){
+                    if(this.iFrameShim)
+                        this.iFrameShim.hide();
+                    this.isOpen = false;
+                    this.notify('afterClose');
+                }.bind(this)
+            });
+        }else{
+            this.container.hide();
+            if(this.iFrameShim)
+                this.iFrameShim.hide();
+        }
+        if(this.ajaxRequest)
+            this.ajaxRequest.transport.abort();
+        if(!(this.options.draggable || this.options.resizable) &amp;&amp; this.options.position == 'center')
+            Event.stopObserving(window,'resize',this.positionHandler);
+        if(!this.options.draggable &amp;&amp; this.options.position == 'center')
+            Event.stopObserving(window,'scroll',this.positionHandler);
+        if(this.options.indicator)
+            this.hideIndicator();
+        if(!this.options.fade){
+            this.isOpen = false;
+            this.notify('afterClose');
+        }
+        return true;
+    },
+    position: function(event){
+        //this is up top for performance reasons
+        if(this.options.position == 'mouse'){
+            var xy = [Event.pointerX(event),Event.pointerY(event)];
+            this.container.setStyle({
+                top: xy[1] + $value(this.options.offsetTop) + 'px',
+                left: xy[0] + $value(this.options.offsetLeft) + 'px'
+            });
+            return;
+        }
+        var container_dimensions = this.container.getDimensions();
+        var viewport_dimensions = document.viewport.getDimensions();
+        Position.prepare();
+        var offset_left = (Position.deltaX + Math.floor((viewport_dimensions.width - container_dimensions.width) / 2));
+        var offset_top = (Position.deltaY + ((viewport_dimensions.height &gt; container_dimensions.height) ? Math.floor((viewport_dimensions.height - container_dimensions.height) / 2) : 0));
+        if(this.options.position == 'center'){
+            this.container.setStyle({
+                top: (container_dimensions.height &lt;= viewport_dimensions.height) ? ((offset_top != null &amp;&amp; offset_top &gt; 0) ? offset_top : 0) + 'px' : 0,
+                left: (container_dimensions.width &lt;= viewport_dimensions.width) ? ((offset_left != null &amp;&amp; offset_left &gt; 0) ? offset_left : 0) + 'px' : 0
+            });
+        }else if(this.options.position == 'relative'){
+            var xy = this.sourceContainer.cumulativeOffset();
+            var top = xy[1] + $value(this.options.offsetTop);
+            var left = xy[0] + $value(this.options.offsetLeft);
+            this.container.setStyle({
+                top: (container_dimensions.height &lt;= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.height - (container_dimensions.height),top)) : top) + 'px' : 0,
+                left: (container_dimensions.width &lt;= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.width - (container_dimensions.width),left)) : left) + 'px' : 0
+            });
+        }else if(this.options.position.length){
+            var top = $value(this.options.position[1]) + $value(this.options.offsetTop);
+            var left = $value(this.options.position[0]) + $value(this.options.offsetLeft);
+            this.container.setStyle({
+                top: (container_dimensions.height &lt;= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.height - (container_dimensions.height),top)) : top) + 'px' : 0,
+                left: (container_dimensions.width &lt;= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.width - (container_dimensions.width),left)) : left) + 'px' : 0
+            });
+        }
+        if(this.iFrameShim)
+            this.updateIFrameShimZIndex();
+    },
+    ensureInBounds: function(){
+        if(!this.isOpen)
+            return;
+        var viewport_dimensions = document.viewport.getDimensions();
+        var container_offset = this.container.cumulativeOffset();
+        var container_dimensions = this.container.getDimensions();
+        if(container_offset.left + container_dimensions.width &gt; viewport_dimensions.width){
+            this.container.setStyle({
+                left: (Math.max(0,viewport_dimensions.width - container_dimensions.width)) + 'px'
+            });
         }
-		return true;
-	},
-	position: function(event){
-		//this is up top for performance reasons
-		if(this.options.position == 'mouse'){
-			var xy = [Event.pointerX(event),Event.pointerY(event)];
-			this.container.setStyle({
-				top: xy[1] + $value(this.options.offsetTop) + 'px',
-				left: xy[0] + $value(this.options.offsetLeft) + 'px'
-			});
-			return;
-		}
-		var container_dimensions = this.container.getDimensions();
-		var viewport_dimensions = document.viewport.getDimensions();
-		Position.prepare();
-		var offset_left = (Position.deltaX + Math.floor((viewport_dimensions.width - container_dimensions.width) / 2));
-		var offset_top = (Position.deltaY + ((viewport_dimensions.height &gt; container_dimensions.height) ? Math.floor((viewport_dimensions.height - container_dimensions.height) / 2) : 0));
-		if(this.options.position == 'center'){
-			this.container.setStyle({
-				top: (container_dimensions.height &lt;= viewport_dimensions.height) ? ((offset_top != null &amp;&amp; offset_top &gt; 0) ? offset_top : 0) + 'px' : 0,
-				left: (container_dimensions.width &lt;= viewport_dimensions.width) ? ((offset_left != null &amp;&amp; offset_left &gt; 0) ? offset_left : 0) + 'px' : 0
-			});
-		}else if(this.options.position == 'relative'){
-			var xy = this.sourceContainer.cumulativeOffset();
-			var top = xy[1] + $value(this.options.offsetTop);
-			var left = xy[0] + $value(this.options.offsetLeft);
-			this.container.setStyle({
-				top: (container_dimensions.height &lt;= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.height - (container_dimensions.height),top)) : top) + 'px' : 0,
-				left: (container_dimensions.width &lt;= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.width - (container_dimensions.width),left)) : left) + 'px' : 0
-			});
-		}else if(this.options.position.length){
-			var top = $value(this.options.position[1]) + $value(this.options.offsetTop);
-			var left = $value(this.options.position[0]) + $value(this.options.offsetLeft);
-			this.container.setStyle({
-				top: (container_dimensions.height &lt;= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.height - (container_dimensions.height),top)) : top) + 'px' : 0,
-				left: (container_dimensions.width &lt;= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.width - (container_dimensions.width),left)) : left) + 'px' : 0
-			});
-		}
-		if(this.iFrameShim)
-			this.updateIFrameShimZIndex();
-	},
-	ensureInBounds: function(){
-		if(!this.isOpen)
-			return;
-		var viewport_dimensions = document.viewport.getDimensions();
-		var container_offset = this.container.cumulativeOffset();
-		var container_dimensions = this.container.getDimensions();
-		if(container_offset.left + container_dimensions.width &gt; viewport_dimensions.width){
-			this.container.setStyle({
-				left: (Math.max(0,viewport_dimensions.width - container_dimensions.width)) + 'px'
-			});
-		}
-		if(container_offset.top + container_dimensions.height &gt; viewport_dimensions.height){
-			this.container.setStyle({
-				top: (Math.max(0,viewport_dimensions.height - container_dimensions.height)) + 'px'
-			});
-		}
-	},
-	bringToFront: function(){
-		Control.Window.bringToFront(this);
-		this.notify('bringToFront');
-	},
-	destroy: function(){
-		this.container.stopObserving('mousedown',this.bringToFrontHandler);
-		if(this.draggable){
-			Draggables.removeObserver(this.container);
-			this.draggable.handle.stopObserving('mousedown',this.bringToFrontHandler);
-			this.draggable.destroy();
-		}
-		if(this.resizable){
-			Resizables.removeObserver(this.container);
-			this.resizable.handle.stopObserving('mousedown',this.bringToFrontHandler);
-			this.resizable.destroy();
-		}
-		if(this.container &amp;&amp; !this.sourceContainer)
-			this.container.remove();
-		if(this.sourceContainer){
-			if(this.options.hover){
-				this.sourceContainer.stopObserving('mouseenter',this.sourceContainerOpenHandler);
-				this.sourceContainer.stopObserving('mouseleave',this.sourceContainerCloseHandler);
-				if(this.options.position == 'mouse')
-					this.sourceContainer.stopObserving('mousemove',this.sourceContainerMouseMoveHandler);
-			}else
-				this.sourceContainer.stopObserving('click',this.sourceContainerOpenHandler);
-		}
-		if(this.iFrameShim)
-			this.iFrameShim.destroy();
-		Event.stopObserving(window,'resize',this.outOfBoundsPositionHandler);
-		Control.Window.windows = Control.Window.windows.without(this);
-		this.notify('afterDestroy');
-	},
-	//private
-	applyResizable: function(){
-		if(this.options.resizable){
-			if(typeof(Resizable) == &quot;undefined&quot;)
-				throw &quot;Control.Window requires resizable.js to be loaded.&quot;;
-			var resizable_handle = null;
-			if(this.options.resizable === true){
-				resizable_handle = new Element('div',{
-					className: 'resizable_handle'
-				});
-				this.container.insert(resizable_handle);
-			}else
-				resizable_handle = $(this.options.resziable);
-			this.resizable = new Resizable(this.container,{
-				handle: resizable_handle,
-				minHeight: this.options.minHeight,
-				minWidth: this.options.minWidth,
-				maxHeight: this.options.constrainToViewport ? function(element){
-					//viewport height - top - total border height
-					return (document.viewport.getDimensions().height - parseInt(element.style.top || 0)) - (element.getHeight() - parseInt(element.style.height || 0));
-				} : this.options.maxHeight,
-				maxWidth: this.options.constrainToViewport ? function(element){
-					//viewport width - left - total border width
-					return (document.viewport.getDimensions().width - parseInt(element.style.left || 0)) - (element.getWidth() - parseInt(element.style.width || 0));
-				} : this.options.maxWidth
-			});
-			this.resizable.handle.observe('mousedown',this.bringToFrontHandler);
-			Resizables.addObserver(new Control.Window.LayoutUpdateObserver(this,function(){
-				if(this.iFrameShim)
-					this.updateIFrameShimZIndex();
-				this.notify('onResize');
-			}.bind(this)));
-		}
-	},
-	applyDraggable: function(){
-		if(this.options.draggable){
-			if(typeof(Draggables) == &quot;undefined&quot;)
-				throw &quot;Control.Window requires dragdrop.js to be loaded.&quot;;
-			var draggable_handle = null;
-			if(this.options.draggable === true){
-				draggable_handle = new Element('div',{
-					className: 'draggable_handle'
-				});
-				this.container.insert(draggable_handle);
-			}else
-				draggable_handle = $(this.options.draggable);
-			this.draggable = new Draggable(this.container,{
-				handle: draggable_handle,
-				constrainToViewport: this.options.constrainToViewport,
-				zindex: this.container.getStyle('z-index'),
-				starteffect: function(){
-					if(Prototype.Browser.IE){
-						this.old_onselectstart = document.onselectstart;
-						document.onselectstart = function(){
-							return false;
-						};
-					}
-				}.bind(this),
-				endeffect: function(){
-					document.onselectstart = this.old_onselectstart;
-				}.bind(this)
-			});
-			this.draggable.handle.observe('mousedown',this.bringToFrontHandler);
-			Draggables.addObserver(new Control.Window.LayoutUpdateObserver(this,function(){
-				if(this.iFrameShim)
-					this.updateIFrameShimZIndex();
-				this.notify('onDrag');
-			}.bind(this)));
-		}
-	},
-	createDefaultContainer: function(container){
-		if(!this.container){
-			//no container passed or found, create it
-			this.container = new Element('div',{
-				id: 'control_window_' + this.numberInSequence
-			});
-			$(document.body).insert(this.container);
-			if(typeof(container) == &quot;string&quot; &amp;&amp; $(container) == null &amp;&amp; !container.match(/^#(.+)$/) &amp;&amp; !container.match(Control.Window.uriRegex))
-				this.container.update(container);
-		}
-	},
-	finishOpen: function(event){
-		this.bringToFront();
-		if(this.options.fade){
-			if(typeof(Effect) == &quot;undefined&quot;)
-				throw &quot;Control.Window requires effects.js to be loaded.&quot;
-			if(this.effects.fade)
-				this.effects.fade.cancel();
-			this.effects.appear = new Effect.Appear(this.container,{
-				queue: {
-					position: 'end',
-					scope: 'Control.Window.' + this.numberInSequence
-				},
-				from: 0,
-				to: 1,
-				duration: this.options.fadeDuration / 2,
-				afterFinish: function(){
-					if(this.iFrameShim)
-						this.updateIFrameShimZIndex();
-					this.isOpen = true;
-					this.notify('afterOpen');
-				}.bind(this)
-			});
-		}else
-			this.container.show();
-		this.position(event);
-		if(!(this.options.draggable || this.options.resizable) &amp;&amp; this.options.position == 'center')
-			Event.observe(window,'resize',this.positionHandler,false);
-		if(!this.options.draggable &amp;&amp; this.options.position == 'center')
-			Event.observe(window,'scroll',this.positionHandler,false);
-		if(!this.options.fade){
-			this.isOpen = true;
-			this.notify('afterOpen');
-		}
-		return true;
-	},
-	showIndicator: function(){
-		this.showIndicatorTimeout = window.setTimeout(function(){
-			if(this.options.fade){
-				this.indicatorEffects.appear = new Effect.Appear(this.indicator,{
-					queue: {
-						position: 'front',
-						scope: 'Control.Window.indicator.' + this.numberInSequence
-					},
-					from: 0,
-					to: 1,
-					duration: this.options.fadeDuration / 2
-				});
-			}else
-				this.indicator.show();
-		}.bind(this),Control.Window.indicatorTimeout);
-	},
-	hideIndicator: function(){
-		if(this.showIndicatorTimeout)
-			window.clearTimeout(this.showIndicatorTimeout);
-		this.indicator.hide();
-	},
-	getRemoteContentInsertionTarget: function(){
-		return typeof(this.options.insertRemoteContentAt) == &quot;string&quot; ? this.container.down(this.options.insertRemoteContentAt) : $(this.options.insertRemoteContentAt);
-	},
-	updateIFrameShimZIndex: function(){
-		if(this.iFrameShim)
-			this.iFrameShim.positionUnder(this.container);
-	}
+        if(container_offset.top + container_dimensions.height &gt; viewport_dimensions.height){
+            this.container.setStyle({
+                top: (Math.max(0,viewport_dimensions.height - container_dimensions.height)) + 'px'
+            });
+        }
+    },
+    bringToFront: function(){
+        Control.Window.bringToFront(this);
+        this.notify('bringToFront');
+    },
+    destroy: function(){
+        this.container.stopObserving('mousedown',this.bringToFrontHandler);
+        if(this.draggable){
+            Draggables.removeObserver(this.container);
+            this.draggable.handle.stopObserving('mousedown',this.bringToFrontHandler);
+            this.draggable.destroy();
+        }
+        if(this.resizable){
+            Resizables.removeObserver(this.container);
+            this.resizable.handle.stopObserving('mousedown',this.bringToFrontHandler);
+            this.resizable.destroy();
+        }
+        if(this.container &amp;&amp; !this.sourceContainer)
+            this.container.remove();
+        if(this.sourceContainer){
+            if(this.options.hover){
+                this.sourceContainer.stopObserving('mouseenter',this.sourceContainerOpenHandler);
+                this.sourceContainer.stopObserving('mouseleave',this.sourceContainerCloseHandler);
+                if(this.options.position == 'mouse')
+                    this.sourceContainer.stopObserving('mousemove',this.sourceContainerMouseMoveHandler);
+            }else
+                this.sourceContainer.stopObserving('click',this.sourceContainerOpenHandler);
+        }
+        if(this.iFrameShim)
+            this.iFrameShim.destroy();
+        Event.stopObserving(window,'resize',this.outOfBoundsPositionHandler);
+        Control.Window.windows = Control.Window.windows.without(this);
+        this.notify('afterDestroy');
+    },
+    //private
+    applyResizable: function(){
+        if(this.options.resizable){
+            if(typeof(Resizable) == &quot;undefined&quot;)
+                throw &quot;Control.Window requires resizable.js to be loaded.&quot;;
+            var resizable_handle = null;
+            if(this.options.resizable === true){
+                resizable_handle = new Element('div',{
+                    className: 'resizable_handle'
+                });
+                this.container.insert(resizable_handle);
+            }else
+                resizable_handle = $(this.options.resziable);
+            this.resizable = new Resizable(this.container,{
+                handle: resizable_handle,
+                minHeight: this.options.minHeight,
+                minWidth: this.options.minWidth,
+                maxHeight: this.options.constrainToViewport ? function(element){
+                    //viewport height - top - total border height
+                    return (document.viewport.getDimensions().height - parseInt(element.style.top || 0)) - (element.getHeight() - parseInt(element.style.height || 0));
+                } : this.options.maxHeight,
+                maxWidth: this.options.constrainToViewport ? function(element){
+                    //viewport width - left - total border width
+                    return (document.viewport.getDimensions().width - parseInt(element.style.left || 0)) - (element.getWidth() - parseInt(element.style.width || 0));
+                } : this.options.maxWidth
+            });
+            this.resizable.handle.observe('mousedown',this.bringToFrontHandler);
+            Resizables.addObserver(new Control.Window.LayoutUpdateObserver(this,function(){
+                if(this.iFrameShim)
+                    this.updateIFrameShimZIndex();
+                this.notify('onResize');
+            }.bind(this)));
+        }
+    },
+    applyDraggable: function(){
+        if(this.options.draggable){
+            if(typeof(Draggables) == &quot;undefined&quot;)
+                throw &quot;Control.Window requires dragdrop.js to be loaded.&quot;;
+            var draggable_handle = null;
+            if(this.options.draggable === true){
+                draggable_handle = new Element('div',{
+                    className: 'draggable_handle'
+                });
+                this.container.insert(draggable_handle);
+            }else
+                draggable_handle = $(this.options.draggable);
+            this.draggable = new Draggable(this.container,{
+                handle: draggable_handle,
+                constrainToViewport: this.options.constrainToViewport,
+                zindex: this.container.getStyle('z-index'),
+                starteffect: function(){
+                    if(Prototype.Browser.IE){
+                        this.old_onselectstart = document.onselectstart;
+                        document.onselectstart = function(){
+                            return false;
+                        };
+                    }
+                }.bind(this),
+                endeffect: function(){
+                    document.onselectstart = this.old_onselectstart;
+                }.bind(this)
+            });
+            this.draggable.handle.observe('mousedown',this.bringToFrontHandler);
+            Draggables.addObserver(new Control.Window.LayoutUpdateObserver(this,function(){
+                if(this.iFrameShim)
+                    this.updateIFrameShimZIndex();
+                this.notify('onDrag');
+            }.bind(this)));
+        }
+    },
+    createDefaultContainer: function(container){
+        if(!this.container){
+            //no container passed or found, create it
+            this.container = new Element('div',{
+                id: 'control_window_' + this.numberInSequence
+            });
+            $(document.body).insert(this.container);
+            if(typeof(container) == &quot;string&quot; &amp;&amp; $(container) == null &amp;&amp; !container.match(/^#(.+)$/) &amp;&amp; !container.match(Control.Window.uriRegex))
+                this.container.update(container);
+        }
+    },
+    finishOpen: function(event){
+        this.bringToFront();
+        if(this.options.fade){
+            if(typeof(Effect) == &quot;undefined&quot;)
+                throw &quot;Control.Window requires effects.js to be loaded.&quot;
+            if(this.effects.fade)
+                this.effects.fade.cancel();
+            this.effects.appear = new Effect.Appear(this.container,{
+                queue: {
+                    position: 'end',
+                    scope: 'Control.Window.' + this.numberInSequence
+                },
+                from: 0,
+                to: 1,
+                duration: this.options.fadeDuration / 2,
+                afterFinish: function(){
+                    if(this.iFrameShim)
+                        this.updateIFrameShimZIndex();
+                    this.isOpen = true;
+                    this.notify('afterOpen');
+                }.bind(this)
+            });
+        }else
+            this.container.show();
+        this.position(event);
+        if(!(this.options.draggable || this.options.resizable) &amp;&amp; this.options.position == 'center')
+            Event.observe(window,'resize',this.positionHandler,false);
+        if(!this.options.draggable &amp;&amp; this.options.position == 'center')
+            Event.observe(window,'scroll',this.positionHandler,false);
+        if(!this.options.fade){
+            this.isOpen = true;
+            this.notify('afterOpen');
+        }
+        return true;
+    },
+    showIndicator: function(){
+        this.showIndicatorTimeout = window.setTimeout(function(){
+            if(this.options.fade){
+                this.indicatorEffects.appear = new Effect.Appear(this.indicator,{
+                    queue: {
+                        position: 'front',
+                        scope: 'Control.Window.indicator.' + this.numberInSequence
+                    },
+                    from: 0,
+                    to: 1,
+                    duration: this.options.fadeDuration / 2
+                });
+            }else
+                this.indicator.show();
+        }.bind(this),Control.Window.indicatorTimeout);
+    },
+    hideIndicator: function(){
+        if(this.showIndicatorTimeout)
+            window.clearTimeout(this.showIndicatorTimeout);
+        this.indicator.hide();
+    },
+    getRemoteContentInsertionTarget: function(){
+        return typeof(this.options.insertRemoteContentAt) == &quot;string&quot; ? this.container.down(this.options.insertRemoteContentAt) : $(this.options.insertRemoteContentAt);
+    },
+    updateIFrameShimZIndex: function(){
+        if(this.iFrameShim)
+            this.iFrameShim.positionUnder(this.container);
+    }
 });
 //class methods
 Object.extend(Control.Window,{
-	windows: [],
-	baseZIndex: 9999,
-	indicatorTimeout: 250,
-	iframeTemplate: new Template('&lt;iframe src=&quot;#{href}&quot; width=&quot;100%&quot; height=&quot;100%&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;'),
-	uriRegex: /^(\/|\#|https?\:\/\/|[\w]+\/)/,
-	bringToFront: function(w){
-		Control.Window.windows = Control.Window.windows.without(w);
-		Control.Window.windows.push(w);
-		Control.Window.windows.each(function(w,i){
-			var z_index = Control.Window.baseZIndex + i;
-			w.container.setStyle({
-				zIndex: z_index
-			});
-			if(w.isOpen){
-				if(w.iFrameShim)
-				w.updateIFrameShimZIndex();
-			}
-			if(w.options.draggable)
-				w.draggable.options.zindex = z_index;
-		});
-	},
-	open: function(container,options){
-		var w = new Control.Window(container,options);
-		w.open();
-		return w;
-	},
-	//protected
-	initialZIndexForWindow: function(w){
-		return Control.Window.baseZIndex + (Control.Window.windows.length - 1);
-	}
+    windows: [],
+    baseZIndex: 9999,
+    indicatorTimeout: 250,
+    iframeTemplate: new Template('&lt;iframe src=&quot;#{href}&quot; width=&quot;100%&quot; height=&quot;100%&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;'),
+    uriRegex: /^(\/|\#|https?\:\/\/|[\w]+\/)/,
+    bringToFront: function(w){
+        Control.Window.windows = Control.Window.windows.without(w);
+        Control.Window.windows.push(w);
+        Control.Window.windows.each(function(w,i){
+            var z_index = Control.Window.baseZIndex + i;
+            w.container.setStyle({
+                zIndex: z_index
+            });
+            if(w.isOpen){
+                if(w.iFrameShim)
+                w.updateIFrameShimZIndex();
+            }
+            if(w.options.draggable)
+                w.draggable.options.zindex = z_index;
+        });
+    },
+    open: function(container,options){
+        var w = new Control.Window(container,options);
+        w.open();
+        return w;
+    },
+    //protected
+    initialZIndexForWindow: function(w){
+        return Control.Window.baseZIndex + (Control.Window.windows.length - 1);
+    }
 });
 Object.Event.extend(Control.Window);
 
 //this is the observer for both Resizables and Draggables
 Control.Window.LayoutUpdateObserver = Class.create({
-	initialize: function(w,observer){
-		this.w = w;
-		this.element = $(w.container);
-		this.observer = observer;
-	},
-	onStart: Prototype.emptyFunction,
-	onEnd: function(event_name,instance){
-		if(instance.element == this.element &amp;&amp; this.iFrameShim)
-			this.w.updateIFrameShimZIndex();
-	},
-	onResize: function(event_name,instance){
-		if(instance.element == this.element)
-			this.observer(this.element);
-	},
-	onDrag: function(event_name,instance){
-		if(instance.element == this.element)
-			this.observer(this.element);
-	}
+    initialize: function(w,observer){
+        this.w = w;
+        this.element = $(w.container);
+        this.observer = observer;
+    },
+    onStart: Prototype.emptyFunction,
+    onEnd: function(event_name,instance){
+        if(instance.element == this.element &amp;&amp; this.iFrameShim)
+            this.w.updateIFrameShimZIndex();
+    },
+    onResize: function(event_name,instance){
+        if(instance.element == this.element)
+            this.observer(this.element);
+    },
+    onDrag: function(event_name,instance){
+        if(instance.element == this.element)
+            this.observer(this.element);
+    }
 });
 
 //overlay for Control.Modal
 Control.Overlay = {
-	id: 'control_overlay',
-	loaded: false,
-	container: false,
-	lastOpacity: 0,
-	styles: {
-		position: 'fixed',
-		top: 0,
-		left: 0,
-		width: '100%',
-		height: '100%',
-		zIndex: 9998
-	},
-	ieStyles: {
-		position: 'absolute',
-		top: 0,
-		left: 0,
-		zIndex: 9998
-	},
-	effects: {
-		fade: false,
-		appear: false
-	},
-	load: function(){
-		if(Control.Overlay.loaded)
-			return false;
-		Control.Overlay.loaded = true;
-		Control.Overlay.container = new Element('div',{
-			id: Control.Overlay.id
-		});
-		$(document.body).insert(Control.Overlay.container);
-		if(Prototype.Browser.IE){
-			Control.Overlay.container.setStyle(Control.Overlay.ieStyles);
-			Event.observe(window,'scroll',Control.Overlay.positionOverlay);
-			Event.observe(window,'resize',Control.Overlay.positionOverlay);
-			Control.Overlay.observe('beforeShow',Control.Overlay.positionOverlay);
-		}else
-			Control.Overlay.container.setStyle(Control.Overlay.styles);
-		Control.Overlay.iFrameShim = new IframeShim();
-		Control.Overlay.iFrameShim.hide();
-		Event.observe(window,'resize',Control.Overlay.positionIFrameShim);
-		Control.Overlay.container.hide();
-		return true;
-	},
-	unload: function(){
-		if(!Control.Overlay.loaded)
-			return false;
-		Event.stopObserving(window,'resize',Control.Overlay.positionOverlay);
-		Control.Overlay.stopObserving('beforeShow',Control.Overlay.positionOverlay);
-		Event.stopObserving(window,'resize',Control.Overlay.positionIFrameShim);
-		Control.Overlay.iFrameShim.destroy();
-		Control.Overlay.container.remove();
-		Control.Overlay.loaded = false;
-		return true;
-	},
-	show: function(opacity,fade){
-		if(Control.Overlay.notify('beforeShow') === false)
-			return false;
-		Control.Overlay.lastOpacity = opacity;
-		Control.Overlay.positionIFrameShim();
-		Control.Overlay.iFrameShim.show();
-		if(fade){
-			if(typeof(Effect) == &quot;undefined&quot;)
-				throw &quot;Control.Window requires effects.js to be loaded.&quot;
-			if(Control.Overlay.effects.fade)
-				Control.Overlay.effects.fade.cancel();
-			Control.Overlay.effects.appear = new Effect.Appear(Control.Overlay.container,{
-				queue: {
-					position: 'end',
-					scope: 'Control.Overlay'
-				},
-				afterFinish: function(){
-					Control.Overlay.notify('afterShow');
-				},
-				from: 0,
-				to: Control.Overlay.lastOpacity,
-				duration: (fade === true ? 0.75 : fade) / 2
-			});
-		}else{
-			Control.Overlay.container.setStyle({
-				opacity: opacity || 1
-			});
-			Control.Overlay.container.show();
-			Control.Overlay.notify('afterShow');
-		}
-		return true;
-	},
-	hide: function(fade){
-		if(Control.Overlay.notify('beforeHide') === false)
-			return false;
-		if(Control.Overlay.effects.appear)
-			Control.Overlay.effects.appear.cancel();
-		Control.Overlay.iFrameShim.hide();
-		if(fade){
-			Control.Overlay.effects.fade = new Effect.Fade(Control.Overlay.container,{
-				queue: {
-					position: 'front',
-					scope: 'Control.Overlay'
-				},
-				afterFinish: function(){
-					Control.Overlay.notify('afterHide');
-				},
-				from: Control.Overlay.lastOpacity,
-				to: 0,
-				duration: (fade === true ? 0.75 : fade) / 2
-			});
-		}else{
-			Control.Overlay.container.hide();
-			Control.Overlay.notify('afterHide');
-		}
-		return true;
-	},
-	positionIFrameShim: function(){
-		if(Control.Overlay.container.visible())
-			Control.Overlay.iFrameShim.positionUnder(Control.Overlay.container);
-	},
-	//IE only
-	positionOverlay: function(){
-		Control.Overlay.container.setStyle({
-			width: document.body.clientWidth + 'px',
-			height: document.body.clientHeight + 'px'
-		});
-	}
+    id: 'control_overlay',
+    loaded: false,
+    container: false,
+    lastOpacity: 0,
+    styles: {
+        position: 'fixed',
+        top: 0,
+        left: 0,
+        width: '100%',
+        height: '100%',
+        zIndex: 9998
+    },
+    ieStyles: {
+        position: 'absolute',
+        top: 0,
+        left: 0,
+        zIndex: 9998
+    },
+    effects: {
+        fade: false,
+        appear: false
+    },
+    load: function(){
+        if(Control.Overlay.loaded)
+            return false;
+        Control.Overlay.loaded = true;
+        Control.Overlay.container = new Element('div',{
+            id: Control.Overlay.id
+        });
+        $(document.body).insert(Control.Overlay.container);
+        if(Prototype.Browser.IE){
+            Control.Overlay.container.setStyle(Control.Overlay.ieStyles);
+            Event.observe(window,'scroll',Control.Overlay.positionOverlay);
+            Event.observe(window,'resize',Control.Overlay.positionOverlay);
+            Control.Overlay.observe('beforeShow',Control.Overlay.positionOverlay);
+        }else
+            Control.Overlay.container.setStyle(Control.Overlay.styles);
+        Control.Overlay.iFrameShim = new IframeShim();
+        Control.Overlay.iFrameShim.hide();
+        Event.observe(window,'resize',Control.Overlay.positionIFrameShim);
+        Control.Overlay.container.hide();
+        return true;
+    },
+    unload: function(){
+        if(!Control.Overlay.loaded)
+            return false;
+        Event.stopObserving(window,'resize',Control.Overlay.positionOverlay);
+        Control.Overlay.stopObserving('beforeShow',Control.Overlay.positionOverlay);
+        Event.stopObserving(window,'resize',Control.Overlay.positionIFrameShim);
+        Control.Overlay.iFrameShim.destroy();
+        Control.Overlay.container.remove();
+        Control.Overlay.loaded = false;
+        return true;
+    },
+    show: function(opacity,fade){
+        if(Control.Overlay.notify('beforeShow') === false)
+            return false;
+        Control.Overlay.lastOpacity = opacity;
+        Control.Overlay.positionIFrameShim();
+        Control.Overlay.iFrameShim.show();
+        if(fade){
+            if(typeof(Effect) == &quot;undefined&quot;)
+                throw &quot;Control.Window requires effects.js to be loaded.&quot;
+            if(Control.Overlay.effects.fade)
+                Control.Overlay.effects.fade.cancel();
+            Control.Overlay.effects.appear = new Effect.Appear(Control.Overlay.container,{
+                queue: {
+                    position: 'end',
+                    scope: 'Control.Overlay'
+                },
+                afterFinish: function(){
+                    Control.Overlay.notify('afterShow');
+                },
+                from: 0,
+                to: Control.Overlay.lastOpacity,
+                duration: (fade === true ? 0.75 : fade) / 2
+            });
+        }else{
+            Control.Overlay.container.setStyle({
+                opacity: opacity || 1
+            });
+            Control.Overlay.container.show();
+            Control.Overlay.notify('afterShow');
+        }
+        return true;
+    },
+    hide: function(fade){
+        if(Control.Overlay.notify('beforeHide') === false)
+            return false;
+        if(Control.Overlay.effects.appear)
+            Control.Overlay.effects.appear.cancel();
+        Control.Overlay.iFrameShim.hide();
+        if(fade){
+            Control.Overlay.effects.fade = new Effect.Fade(Control.Overlay.container,{
+                queue: {
+                    position: 'front',
+                    scope: 'Control.Overlay'
+                },
+                afterFinish: function(){
+                    Control.Overlay.notify('afterHide');
+                },
+                from: Control.Overlay.lastOpacity,
+                to: 0,
+                duration: (fade === true ? 0.75 : fade) / 2
+            });
+        }else{
+            Control.Overlay.container.hide();
+            Control.Overlay.notify('afterHide');
+        }
+        return true;
+    },
+    positionIFrameShim: function(){
+        if(Control.Overlay.container.visible())
+            Control.Overlay.iFrameShim.positionUnder(Control.Overlay.container);
+    },
+    //IE only
+    positionOverlay: function(){
+        Control.Overlay.container.setStyle({
+            width: document.body.clientWidth + 'px',
+            height: document.body.clientHeight + 'px'
+        });
+    }
 };
 Object.Event.extend(Control.Overlay);
 
 Control.ToolTip = Class.create(Control.Window,{
-	initialize: function($super,container,tooltip,options){
-		$super(tooltip,Object.extend(Object.extend(Object.clone(Control.ToolTip.defaultOptions),options || {}),{
-			position: 'mouse',
-			hover: container
-		}));
-	}
+    initialize: function($super,container,tooltip,options){
+        $super(tooltip,Object.extend(Object.extend(Object.clone(Control.ToolTip.defaultOptions),options || {}),{
+            position: 'mouse',
+            hover: container
+        }));
+    }
 });
 Object.extend(Control.ToolTip,{
-	defaultOptions: {
-		offsetLeft: 10
-	}
+    defaultOptions: {
+        offsetLeft: 10
+    }
 });
 
 Control.Modal = Class.create(Control.Window,{
-	initialize: function($super,container,options){
-		Control.Modal.InstanceMethods.beforeInitialize.bind(this)();
-		$super(container,Object.extend(Object.clone(Control.Modal.defaultOptions),options || {}));
-	}
+    initialize: function($super,container,options){
+        Control.Modal.InstanceMethods.beforeInitialize.bind(this)();
+        $super(container,Object.extend(Object.clone(Control.Modal.defaultOptions),options || {}));
+    }
 });
 Object.extend(Control.Modal,{
-	defaultOptions: {
-		overlayOpacity: 0.5,
-		closeOnClick: 'overlay'
-	},
-	current: false,
-	open: function(container,options){
-		var modal = new Control.Modal(container,options);
-		modal.open();
-		return modal;
-	},
-	close: function(){
-		if(Control.Modal.current)
-			Control.Modal.current.close();
-	},
-	InstanceMethods: {
-		beforeInitialize: function(){
-			Control.Overlay.load();
-			this.overlayFinishedOpening = false;
-			this.observe('beforeOpen',Control.Modal.Observers.beforeOpen.bind(this));
-			this.observe('afterOpen',Control.Modal.Observers.afterOpen.bind(this));
-			this.observe('afterClose',Control.Modal.Observers.afterClose.bind(this));
-		}
-	},
-	Observers: {
-		beforeOpen: function(){
-			if(!this.overlayFinishedOpening){
-				Control.Overlay.observeOnce('afterShow',function(){
-					this.overlayFinishedOpening = true;
-					this.open();
-				}.bind(this));
-				Control.Overlay.show(this.options.overlayOpacity,this.options.fade ? this.options.fadeDuration : false);
-				throw $break;
-			}else
-			Control.Window.windows.without(this).invoke('close');
-		},
-		afterOpen: function(){
-			Control.Modal.current = this;
-		},
-		afterClose: function(){
-			Control.Overlay.hide(this.options.fade ? this.options.fadeDuration : false);
-			Control.Modal.current = false;
-			this.overlayFinishedOpening = false;
-		}
-	}
+    defaultOptions: {
+        overlayOpacity: 0.5,
+        closeOnClick: 'overlay'
+    },
+    current: false,
+    open: function(container,options){
+        var modal = new Control.Modal(container,options);
+        modal.open();
+        return modal;
+    },
+    close: function(){
+        if(Control.Modal.current)
+            Control.Modal.current.close();
+    },
+    InstanceMethods: {
+        beforeInitialize: function(){
+            Control.Overlay.load();
+            this.overlayFinishedOpening = false;
+            this.observe('beforeOpen',Control.Modal.Observers.beforeOpen.bind(this));
+            this.observe('afterOpen',Control.Modal.Observers.afterOpen.bind(this));
+            this.observe('afterClose',Control.Modal.Observers.afterClose.bind(this));
+        }
+    },
+    Observers: {
+        beforeOpen: function(){
+            if(!this.overlayFinishedOpening){
+                Control.Overlay.observeOnce('afterShow',function(){
+                    this.overlayFinishedOpening = true;
+                    this.open();
+                }.bind(this));
+                Control.Overlay.show(this.options.overlayOpacity,this.options.fade ? this.options.fadeDuration : false);
+                throw $break;
+            }else
+            Control.Window.windows.without(this).invoke('close');
+        },
+        afterOpen: function(){
+            Control.Modal.current = this;
+        },
+        afterClose: function(){
+            Control.Overlay.hide(this.options.fade ? this.options.fadeDuration : false);
+            Control.Modal.current = false;
+            this.overlayFinishedOpening = false;
+        }
+    }
 });
 
 Control.LightBox = Class.create(Control.Window,{
-	initialize: function($super,container,options){
-		this.allImagesLoaded = false;
-		if(options.modal){
-			var options = Object.extend(Object.clone(Control.LightBox.defaultOptions),options || {});
-			options = Object.extend(Object.clone(Control.Modal.defaultOptions),options);
-			options = Control.Modal.InstanceMethods.beforeInitialize.bind(this)(options);
-			$super(container,options);
-		}else
-			$super(container,Object.extend(Object.clone(Control.LightBox.defaultOptions),options || {}));
-		this.hasRemoteContent = this.href &amp;&amp; !this.options.iframe;
-		if(this.hasRemoteContent)
-			this.observe('onRemoteContentLoaded',Control.LightBox.Observers.onRemoteContentLoaded.bind(this));
-		else
-			this.applyImageObservers();
-		this.observe('beforeOpen',Control.LightBox.Observers.beforeOpen.bind(this));
-	},
-	applyImageObservers:function(){
-		var images = this.getImages();
-		this.numberImagesToLoad = images.length;
-		this.numberofImagesLoaded = 0;
-		images.each(function(image){
-			image.observe('load',function(image){
-				++this.numberofImagesLoaded;
-				if(this.numberImagesToLoad == this.numberofImagesLoaded){
-					this.allImagesLoaded = true;
-					this.onAllImagesLoaded();
-				}
-			}.bind(this,image));
-			image.hide();
-		}.bind(this));
-	},
-	onAllImagesLoaded: function(){
-		this.getImages().each(function(image){
-			this.showImage(image);
-		}.bind(this));
-		if(this.hasRemoteContent){
-			if(this.options.indicator)
-				this.hideIndicator();
-			this.finishOpen();
-		}else
-			this.open();
-	},
-	getImages: function(){
-		return this.container.select(Control.LightBox.imageSelector);
-	},
-	showImage: function(image){
-		image.show();
-	}
+    initialize: function($super,container,options){
+        this.allImagesLoaded = false;
+        if(options.modal){
+            var options = Object.extend(Object.clone(Control.LightBox.defaultOptions),options || {});
+            options = Object.extend(Object.clone(Control.Modal.defaultOptions),options);
+            options = Control.Modal.InstanceMethods.beforeInitialize.bind(this)(options);
+            $super(container,options);
+        }else
+            $super(container,Object.extend(Object.clone(Control.LightBox.defaultOptions),options || {}));
+        this.hasRemoteContent = this.href &amp;&amp; !this.options.iframe;
+        if(this.hasRemoteContent)
+            this.observe('onRemoteContentLoaded',Control.LightBox.Observers.onRemoteContentLoaded.bind(this));
+        else
+            this.applyImageObservers();
+        this.observe('beforeOpen',Control.LightBox.Observers.beforeOpen.bind(this));
+    },
+    applyImageObservers:function(){
+        var images = this.getImages();
+        this.numberImagesToLoad = images.length;
+        this.numberofImagesLoaded = 0;
+        images.each(function(image){
+            image.observe('load',function(image){
+                ++this.numberofImagesLoaded;
+                if(this.numberImagesToLoad == this.numberofImagesLoaded){
+                    this.allImagesLoaded = true;
+                    this.onAllImagesLoaded();
+                }
+            }.bind(this,image));
+            image.hide();
+        }.bind(this));
+    },
+    onAllImagesLoaded: function(){
+        this.getImages().each(function(image){
+            this.showImage(image);
+        }.bind(this));
+        if(this.hasRemoteContent){
+            if(this.options.indicator)
+                this.hideIndicator();
+            this.finishOpen();
+        }else
+            this.open();
+    },
+    getImages: function(){
+        return this.container.select(Control.LightBox.imageSelector);
+    },
+    showImage: function(image){
+        image.show();
+    }
 });
 Object.extend(Control.LightBox,{
-	imageSelector: 'img',
-	defaultOptions: {},
-	Observers: {
-		beforeOpen: function(){
-			if(!this.hasRemoteContent &amp;&amp; !this.allImagesLoaded)
-				throw $break;
-		},
-		onRemoteContentLoaded: function(){
-			this.applyImageObservers();
-			if(!this.allImagesLoaded)
-				throw $break;
-		}
-	}
+    imageSelector: 'img',
+    defaultOptions: {},
+    Observers: {
+        beforeOpen: function(){
+            if(!this.hasRemoteContent &amp;&amp; !this.allImagesLoaded)
+                throw $break;
+        },
+        onRemoteContentLoaded: function(){
+            this.applyImageObservers();
+            if(!this.allImagesLoaded)
+                throw $break;
+        }
+    }
 });</diff>
      <filename>public/javascripts/window.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,175 +10,176 @@
 /*global window, document, Prototype, Class, Event, $, $A, $R, Control, $value */
 
 if(typeof(Prototype) == &quot;undefined&quot;) {
-	throw &quot;Control.ContextMenu requires Prototype to be loaded.&quot;; }
+    throw &quot;Control.ContextMenu requires Prototype to be loaded.&quot;; }
 if(typeof(Object.Event) == &quot;undefined&quot;) {
-	throw &quot;Control.ContextMenu requires Object.Event to be loaded.&quot;; }
+    throw &quot;Control.ContextMenu requires Object.Event to be loaded.&quot;; }
 
 Control.ContextMenu = Class.create({
-	initialize: function(container,options){
-		Control.ContextMenu.load();
-		this.options = Object.extend({
-			leftClick: false,
-			disableOnShiftKey: true,
-			disableOnAltKey: true,
-			selectedClassName: 'selected',
-			activatedClassName: 'activated',
-			animation: true,
-			animationCycles: 2,
-			animationLength: 300,
-			delayCallback: true
-		},options || {});
-		this.activated = false;
-		this.items = this.options.items || [];
-		this.container = $(container);
-		this.container.observe(this.options.leftClick ? 'click' : (Prototype.Browser.Opera ? 'click' : 'contextmenu'),function(event){
-			if(!Control.ContextMenu.enabled || Prototype.Browser.Opera &amp;&amp; !event.ctrlKey) {
-				return; }
-			this.open(event);
-		}.bindAsEventListener(this));
-	},
-	open: function(event){
-		if(Control.ContextMenu.current &amp;&amp; !Control.ContextMenu.current.close()) {
-			return; }
-		if(this.notify('beforeOpen',event) === false) {
-			return false; }
-		this.buildMenu();
-		if(this.items.length === 0){
-			this.close(event);
-			return false;
-		}
-		Control.ContextMenu.current = this;
-		Control.ContextMenu.positionContainer(event);
-		Control.ContextMenu.container.show();
-		if(this.notify('afterOpen',event) === false) {
-			return false; }
-		event.stop();
-		return true;
-	},
-	close: function(event){
-		if(event) {
-			event.stop(); }
-		if(this.notify('beforeClose') === false) {
-			return false; }
-		Control.ContextMenu.current = false;
-		this.activated = false;
-		Control.ContextMenu.container.removeClassName(this.options.activatedClassName);
-		Control.ContextMenu.container.select('li').invoke('stopObserving');
-		Control.ContextMenu.container.hide();
-		Control.ContextMenu.container.update('');
-		if(this.notify('afterClose') === false) {
-			return false; }
-		return true;
-	},
-	buildMenu: function(){
-		var list = document.createElement('ul');
-		Control.ContextMenu.container.appendChild(list);
-		this.items.each(function(item){
-			if(!(!item.condition || item.condition &amp;&amp; item.condition() !== false)) {
-				return; }
-			var item_container = $(document.createElement('li'));
-			item_container.update($value(item.label));
-			list.appendChild(item_container);
-			item_container[$value(item.enabled) ? 'removeClassName' : 'addClassName']('disabled');
-			item_container.observe('mousedown',function(event,item){
-				if(!$value(item.enabled)) {
-					return event.stop(); }
-				this.activated = $value(item.label);
-			}.bindAsEventListener(this,item));
-			item_container.observe('click',this.selectMenuItem.bindAsEventListener(this,item,item_container));
-			item_container.observe('contextmenu',this.selectMenuItem.bindAsEventListener(this,item,item_container));
-		}.bind(this));
-	},
-	addItem: function(params){
+    initialize: function(container,options){
+        Control.ContextMenu.load();
+        this.options = Object.extend({
+            leftClick: false,
+            disableOnShiftKey: true,
+            disableOnAltKey: true,
+            selectedClassName: 'selected',
+            activatedClassName: 'activated',
+            animation: true,
+            animationCycles: 2,
+            animationLength: 300,
+            delayCallback: true
+        },options || {});
+        this.activated = false;
+        this.items = this.options.items || [];
+        this.container = $(container);
+        this.container.observe(this.options.leftClick ? 'click' : (Prototype.Browser.Opera ? 'click' : 'contextmenu'),function(event){
+            if(!Control.ContextMenu.enabled || Prototype.Browser.Opera &amp;&amp; !event.ctrlKey) {
+                return; }
+            this.open(event);
+        }.bindAsEventListener(this));
+    },
+    open: function(event){
+        if(Control.ContextMenu.current &amp;&amp; !Control.ContextMenu.current.close()) {
+            return; }
+        if(this.notify('beforeOpen',event) === false) {
+            return false; }
+        this.buildMenu();
+        if(this.items.length === 0){
+            this.close(event);
+            return false;
+        }
+        this.clicked = Event.element(event);
+        Control.ContextMenu.current = this;
+        Control.ContextMenu.positionContainer(event);
+        Control.ContextMenu.container.show();
+        if(this.notify('afterOpen',event) === false) {
+            return false; }
+        event.stop();
+        return true;
+    },
+    close: function(event){
+        if(event) {
+            event.stop(); }
+        if(this.notify('beforeClose') === false) {
+            return false; }
+        Control.ContextMenu.current = false;
+        this.activated = false;
+        Control.ContextMenu.container.removeClassName(this.options.activatedClassName);
+        Control.ContextMenu.container.select('li').invoke('stopObserving');
+        Control.ContextMenu.container.hide();
+        Control.ContextMenu.container.update('');
+        if(this.notify('afterClose') === false) {
+            return false; }
+        return true;
+    },
+    buildMenu: function(){
+        var list = document.createElement('ul');
+        Control.ContextMenu.container.appendChild(list);
+        this.items.each(function(item){
+            if(!(!item.condition || item.condition &amp;&amp; item.condition() !== false)) {
+                return; }
+            var item_container = $(document.createElement('li'));
+            item_container.update($value(item.label));
+            list.appendChild(item_container);
+            item_container[$value(item.enabled) ? 'removeClassName' : 'addClassName']('disabled');
+            item_container.observe('mousedown',function(event,item){
+                if(!$value(item.enabled)) {
+                    return event.stop(); }
+                this.activated = $value(item.label);
+            }.bindAsEventListener(this,item));
+            item_container.observe('click',this.selectMenuItem.bindAsEventListener(this,item,item_container));
+            item_container.observe('contextmenu',this.selectMenuItem.bindAsEventListener(this,item,item_container));
+        }.bind(this));
+    },
+    addItem: function(params){
         if (!('enabled' in params)) { params.enabled = true; }
-		this.items.push(params);
-		return this;
-	},
-	destroy: function(){
-		this.container.stopObserving(Prototype.Browser.Opera || this.options.leftClick ? 'click' : 'contextmenu');
-		this.items = [];
-	},
-	selectMenuItem: function(event,item,item_container){
-		if(!$value(item.enabled)) {
-			return event.stop(); }
-		if(!this.activated || this.activated == $value(item.label)){
-			if(this.options.animation){
-				Control.ContextMenu.container.addClassName(this.options.activatedClassName);
-				$A($R(0,this.options.animationCycles * 2)).each(function(i){
-					window.setTimeout(function(){
-						item_container.toggleClassName(this.options.selectedClassName);
-					}.bind(this),i * parseInt(this.options.animationLength / (this.options.animationCycles * 2), 10));
-				}.bind(this));
-				window.setTimeout(function(){
-					if(this.close() &amp;&amp; this.options.delayCallback) {
-						item.callback(); }
-				}.bind(this),this.options.animationLength);
-				if(!this.options.delayCallback) {
-					item.callback(); }
-			}else if(this.close()) {
-				item.callback(); }
-		}
-		event.stop();
-		return false;
-	}
+        this.items.push(params);
+        return this;
+    },
+    destroy: function(){
+        this.container.stopObserving(Prototype.Browser.Opera || this.options.leftClick ? 'click' : 'contextmenu');
+        this.items = [];
+    },
+    selectMenuItem: function(event,item,item_container){
+        if(!$value(item.enabled)) {
+            return event.stop(); }
+        if(!this.activated || this.activated == $value(item.label)){
+            if(this.options.animation){
+                Control.ContextMenu.container.addClassName(this.options.activatedClassName);
+                $A($R(0,this.options.animationCycles * 2)).each(function(i){
+                    window.setTimeout(function(){
+                        item_container.toggleClassName(this.options.selectedClassName);
+                    }.bind(this),i * parseInt(this.options.animationLength / (this.options.animationCycles * 2), 10));
+                }.bind(this));
+                window.setTimeout(function(){
+                    if(this.close() &amp;&amp; this.options.delayCallback) {
+                        item.callback(this.clicked); }
+                }.bind(this),this.options.animationLength);
+                if(!this.options.delayCallback) {
+                    item.callback(this.clicked); }
+            }else if(this.close()) {
+                item.callback(this.clicked); }
+        }
+        event.stop();
+        return false;
+    }
 });
 Object.extend(Control.ContextMenu,{
-	loaded: false,
-	capture_all: false,
-	menus: [],
-	current: false,
-	enabled: false,
-	offset: 4,
-	load: function(capture_all){
-		if(Control.ContextMenu.loaded) {
-			return; }
-		Control.ContextMenu.loaded = true;
-		if(typeof(capture_all) == 'undefined') {
-			capture_all = false; }
-		Control.ContextMenu.capture_all = capture_all;
-		Control.ContextMenu.container = $(document.createElement('div'));
-		Control.ContextMenu.container.id = 'control_contextmenu';
-		Control.ContextMenu.container.style.position = 'absolute';
-		Control.ContextMenu.container.style.zIndex = 99999;
-		Control.ContextMenu.container.hide();
-		document.body.appendChild(Control.ContextMenu.container);
-		Control.ContextMenu.enable();
-	},
-	enable: function(){
-		Control.ContextMenu.enabled = true;
-		Event.observe(document.body,'click',Control.ContextMenu.onClick);
-		if(Control.ContextMenu.capture_all) {
-			Event.observe(document.body,'contextmenu',Control.ContextMenu.onContextMenu); }
-	},
-	disable: function(){
-		Event.stopObserving(document.body,'click',Control.ContextMenu.onClick);
-		if(Control.ContextMenu.capture_all) {
-			Event.stopObserving(document.body,'contextmenu',Control.ContextMenu.onContextMenu);	}
-	},
-	onContextMenu: function(event){
-		event.stop();
-		return false;
-	},
-	onClick: function(){
-		if(Control.ContextMenu.current) {
-			Control.ContextMenu.current.close(); }
-	},
-	positionContainer: function(event){
-		var dimensions = Control.ContextMenu.container.getDimensions();
-		var top = Event.pointerY(event);
-		var left = Event.pointerX(event);
-		var bottom = dimensions.height + top;
-		var right = dimensions.width + left;
-		var viewport_dimensions = document.viewport.getDimensions();
-		var viewport_scroll_offsets = document.viewport.getScrollOffsets();
-		if(bottom &gt; viewport_dimensions.height + viewport_scroll_offsets.top) {
-			top -= bottom - ((viewport_dimensions.height  + viewport_scroll_offsets.top) - Control.ContextMenu.offset); }
-		if(right &gt; viewport_dimensions.width + viewport_scroll_offsets.left) {
-			left -= right - ((viewport_dimensions.width + viewport_scroll_offsets.left) - Control.ContextMenu.offset); }
-		Control.ContextMenu.container.setStyle({
-			top: top + 'px',
-			left: left + 'px'
-		});
-	}
+    loaded: false,
+    capture_all: false,
+    menus: [],
+    current: false,
+    enabled: false,
+    offset: 4,
+    load: function(capture_all){
+        if(Control.ContextMenu.loaded) {
+            return; }
+        Control.ContextMenu.loaded = true;
+        if(typeof(capture_all) == 'undefined') {
+            capture_all = false; }
+        Control.ContextMenu.capture_all = capture_all;
+        Control.ContextMenu.container = $(document.createElement('div'));
+        Control.ContextMenu.container.id = 'control_contextmenu';
+        Control.ContextMenu.container.style.position = 'absolute';
+        Control.ContextMenu.container.style.zIndex = 99999;
+        Control.ContextMenu.container.hide();
+        document.body.appendChild(Control.ContextMenu.container);
+        Control.ContextMenu.enable();
+    },
+    enable: function(){
+        Control.ContextMenu.enabled = true;
+        Event.observe(document.body,'click',Control.ContextMenu.onClick);
+        if(Control.ContextMenu.capture_all) {
+            Event.observe(document.body,'contextmenu',Control.ContextMenu.onContextMenu); }
+    },
+    disable: function(){
+        Event.stopObserving(document.body,'click',Control.ContextMenu.onClick);
+        if(Control.ContextMenu.capture_all) {
+            Event.stopObserving(document.body,'contextmenu',Control.ContextMenu.onContextMenu);    }
+    },
+    onContextMenu: function(event){
+        event.stop();
+        return false;
+    },
+    onClick: function(){
+        if(Control.ContextMenu.current) {
+            Control.ContextMenu.current.close(); }
+    },
+    positionContainer: function(event){
+        var dimensions = Control.ContextMenu.container.getDimensions();
+        var top = Event.pointerY(event);
+        var left = Event.pointerX(event);
+        var bottom = dimensions.height + top;
+        var right = dimensions.width + left;
+        var viewport_dimensions = document.viewport.getDimensions();
+        var viewport_scroll_offsets = document.viewport.getScrollOffsets();
+        if(bottom &gt; viewport_dimensions.height + viewport_scroll_offsets.top) {
+            top -= bottom - ((viewport_dimensions.height  + viewport_scroll_offsets.top) - Control.ContextMenu.offset); }
+        if(right &gt; viewport_dimensions.width + viewport_scroll_offsets.left) {
+            left -= right - ((viewport_dimensions.width + viewport_scroll_offsets.left) - Control.ContextMenu.offset); }
+        Control.ContextMenu.container.setStyle({
+            top: top + 'px',
+            left: left + 'px'
+        });
+    }
 });
 Object.Event.extend(Control.ContextMenu);</diff>
      <filename>src/contextmenu.js</filename>
    </modified>
    <modified>
      <diff>@@ -7,10 +7,12 @@
  * @attribution http://www.quirksmode.org/js/cookies.html
  */
 
-if(typeof(Prototype) == &quot;undefined&quot;)
-  throw &quot;Cookie requires Prototype to be loaded.&quot;
-if(typeof(Object.Event) == &quot;undefined&quot;)
-  throw &quot;Cookie requires Object.Event to be loaded.&quot;;
+/*global document, Prototype, $A */
+
+if(typeof(Prototype) == &quot;undefined&quot;) {
+  throw &quot;Cookie requires Prototype to be loaded.&quot;; }
+if(typeof(Object.Event) == &quot;undefined&quot;) {
+  throw &quot;Cookie requires Object.Event to be loaded.&quot;; }
 
 var Cookie = {
   build: function() {
@@ -36,4 +38,4 @@ var Cookie = {
     Cookie.set(name,'',-1);
   }
 };
-Object.Event.extend(Cookie);
\ No newline at end of file
+Object.Event.extend(Cookie);</diff>
      <filename>src/cookie.js</filename>
    </modified>
    <modified>
      <diff>@@ -8,112 +8,112 @@
  * @attribution http://www.adamlogic.com/2007/03/20/3_metaprogramming-javascript-presentation
  */
 
-if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Event.Behavior requires Prototype to be loaded.&quot;;
-if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Event.Behavior requires Object.Event to be loaded.&quot;;
-	
+/*global Prototype, Class, Event, Try, $, $A, $H */
+
+if(typeof(Prototype) == &quot;undefined&quot;) {
+    throw &quot;Event.Behavior requires Prototype to be loaded.&quot;; }
+if(typeof(Object.Event) == &quot;undefined&quot;) {
+    throw &quot;Event.Behavior requires Object.Event to be loaded.&quot;; }
+    
 Event.Behavior = {
-	addVerbs: function(verbs){
-		for(name in verbs){
-			v = new Event.Behavior.Verb(verbs[name]);
-			Event.Behavior.Verbs[name] = v;
-			Event.Behavior[name.underscore()] = Event.Behavior[name] = v.getCallbackForStack.bind(v);
-		}
-	},
-	addEvents: function(events){
-		$H(events).each(function(event_type){
-			Event.Behavior.Adjective.prototype[event_type.key.underscore()] = Event.Behavior.Adjective.prototype[event_type.key] = function(){
-				this.nextConditionType = 'and';
-				this.events.push(event_type.value);
-				this.attachObserver(false);
-				return this;
-			};
-		});
-	},
-	invokeElementMethod: function(element,action,args){
-		if(typeof(element) == 'function'){
-			return $A(element()).each(function(e){
-				if(typeof(args[0]) == 'function'){
-					return $A(args[0]).each(function(a){
-						return $(e)[action].apply($(e),(a ? [a] : []));
-					});
-				}else
-					return $(e)[action].apply($(e),args || []);
-			});
-		}else
-			return $(element)[action].apply($(element),args || []);
-	}
+    addVerbs: function(verbs){
+        var v;
+        for (var name in verbs) { if (verbs.hasOwnProperty(name)) {
+            v = new Event.Behavior.Verb(verbs[name]);
+            Event.Behavior.Verbs[name] = v;
+            Event.Behavior[name.underscore()] = Event.Behavior[name] = v.getCallbackForStack.bind(v);
+        }}
+    },
+    addEvents: function(events){
+        $H(events).each(function(event_type){
+            Event.Behavior.Adjective.prototype[event_type.key.underscore()] = Event.Behavior.Adjective.prototype[event_type.key] = function(){
+                this.nextConditionType = 'and';
+                this.events.push(event_type.value);
+                this.attachObserver(false);
+                return this;
+            };
+        });
+    },
+    invokeElementMethod: function(element,action,args){
+        if(typeof(element) == 'function'){
+            return $A(element()).each(function(e){
+                if(typeof(args[0]) == 'function'){
+                    return $A(args[0]).each(function(a){
+                        return $(e)[action].apply($(e),(a ? [a] : []));
+                    });
+                }else {
+                    return $(e)[action].apply($(e),args || []); }
+            });
+        }else {
+            return $(element)[action].apply($(element),args || []); }
+    }
 };
 
 Event.Behavior.Verbs = $H({});
 
 Event.Behavior.Verb = Class.create();
 Object.extend(Event.Behavior.Verb.prototype,{
-	originalAction: false,
-	execute: false,
-	executeOpposite: false,
-	target: false,
-	initialize: function(action){
-		this.originalAction = action;
-		this.execute = function(action,target,argument){
-			return (argument)
-				? action(target,argument)
-				: action(target)
-			;
-		}.bind(this,action);
-	},
-	setOpposite: function(opposite_verb){
-		opposite_action = opposite_verb.originalAction;
-		this.executeOpposite = function(opposite_action,target,argument){
-			return (argument)
-				? opposite_action(target,argument)
-				: opposite_action(target)
-			;
-		}.bind(this,opposite_action);
-	},
-	getCallbackForStack: function(argument){
-		return new Event.Behavior.Noun(this,argument);
-	}
+    originalAction: false,
+    execute: false,
+    executeOpposite: false,
+    target: false,
+    initialize: function(action){
+        this.originalAction = action;
+        this.execute = function(action,target,argument){
+            return (argument) ? action(target,argument) : action(target);
+        }.bind(this,action);
+    },
+    setOpposite: function(opposite_verb){
+        var opposite_action = opposite_verb.originalAction;
+        this.executeOpposite = function(opposite_action,target,argument){
+            return (argument) ? opposite_action(target,argument) : 
+                opposite_action(target);
+        }.bind(this,opposite_action);
+    },
+    getCallbackForStack: function(argument){
+        return new Event.Behavior.Noun(this,argument);
+    }
 });
 
 Event.Behavior.addVerbs({
-	call: function(callback){
-		callback();
-	},
-	show: function(element){
-		return Event.Behavior.invokeElementMethod(element,'show');
-	},
-	hide: function(element){
-		return Event.Behavior.invokeElementMethod(element,'hide');
-	},
-	remove: function(element){
-		return Event.Behavior.invokeElementMethod(element,'remove');
-	},
-	setStyle: function(element,styles){
-		return Event.Behavior.invokeElementMethod(element,'setStyle',[(typeof(styles) == 'function' ? styles() : styles)]);
-	},
-	addClassName: function(element,class_name){
-		return Event.Behavior.invokeElementMethod(element,'addClassName',[(typeof(class_name) == 'function' ? class_name() : class_name)]);
-	},
-	removeClassName: function(element,class_name){
-		return Event.Behavior.invokeElementMethod(element,'removeClassName',[(typeof(class_name) == 'function' ? class_name() : class_name)]);
-	},
-	setClassName: function(element,class_name){
-		c = (typeof(class_name) == 'function') ? class_name() : class_name;
-		if(typeof(element) == 'function'){
-			return $A(element()).each(function(e){
-				$(e).className = c;
-			});
-		}else
-			return $(element).className = c;
-	},
-	update: function(content,element){
-		return Event.Behavior.invokeElementMethod(element,'update',[(typeof(content) == 'function' ? content() : content)]);
-	},
-	replace: function(content,element){
-		return Event.Behavior.invokeElementMethod(element,'replace',[(typeof(content) == 'function' ? content() : content)]);
-	}
+    call: function(callback){
+        callback();
+    },
+    show: function(element){
+        return Event.Behavior.invokeElementMethod(element,'show');
+    },
+    hide: function(element){
+        return Event.Behavior.invokeElementMethod(element,'hide');
+    },
+    remove: function(element){
+        return Event.Behavior.invokeElementMethod(element,'remove');
+    },
+    setStyle: function(element,styles){
+        return Event.Behavior.invokeElementMethod(element,'setStyle',[(typeof(styles) == 'function' ? styles() : styles)]);
+    },
+    addClassName: function(element,class_name){
+        return Event.Behavior.invokeElementMethod(element,'addClassName',[(typeof(class_name) == 'function' ? class_name() : class_name)]);
+    },
+    removeClassName: function(element,class_name){
+        return Event.Behavior.invokeElementMethod(element,'removeClassName',[(typeof(class_name) == 'function' ? class_name() : class_name)]);
+    },
+    setClassName: function(element,class_name){
+        var c = (typeof(class_name) == 'function') ? class_name() : class_name;
+        if(typeof(element) == 'function'){
+            return $A(element()).each(function(e){
+                $(e).className = c;
+            });
+        }else {
+            c = $(element).className;
+            return c;
+        }
+    },
+    update: function(content,element){
+        return Event.Behavior.invokeElementMethod(element,'update',[(typeof(content) == 'function' ? content() : content)]);
+    },
+    replace: function(content,element){
+        return Event.Behavior.invokeElementMethod(element,'replace',[(typeof(content) == 'function' ? content() : content)]);
+    }
 });
 Event.Behavior.Verbs.show.setOpposite(Event.Behavior.Verbs.hide);
 Event.Behavior.Verbs.hide.setOpposite(Event.Behavior.Verbs.show);
@@ -122,54 +122,51 @@ Event.Behavior.Verbs.removeClassName.setOpposite(Event.Behavior.Verbs.addClassNa
 
 Event.Behavior.Noun = Class.create();
 Object.extend(Event.Behavior.Noun.prototype,{
-	verbs: false,
-	verb: false,
-	argument: false,
-	subject: false,
-	target: false,
-	initialize: function(verb,argument){
-		//this.verbs = $A([]);
-		this.verb = verb;
-		this.argument = argument;
-	},
-	execute: function(){
-		return (this.target)
-			? this.verb.execute(this.target,this.argument)
-			: this.verb.execute(this.argument)
-		;
-	},
-	executeOpposite: function(){
-		return (this.target)
-			? this.verb.executeOpposite(this.target,this.argument)
-			: this.verb.executeOpposite(this.argument)
-		;
-	},
-	when: function(subject){
-		this.subject = subject;
-		return new Event.Behavior.Adjective(this);
-	},
-	getValue: function(){
-		return Try.these(
-			function(){return $(this.subject).getValue();}.bind(this),
-			function(){return $(this.subject).options[$(this.subject).options.selectedIndex].value;}.bind(this),
-			function(){return $(this.subject).value;}.bind(this),
-			function(){return $(this.subject).innerHTML;}.bind(this)
-		);
-	},
-	containsValue: function(match){
-		value = this.getValue();
-		if(typeof(match) == 'function'){
-			return $A(match()).include(value);
-		}else
-			return value.match(match);
-	},
-	setTarget: function(target){
-		this.target = target;
-		return this;
-	},
-	and: function(){
+    verbs: false,
+    verb: false,
+    argument: false,
+    subject: false,
+    target: false,
+    initialize: function(verb,argument){
+        //this.verbs = $A([]);
+        this.verb = verb;
+        this.argument = argument;
+    },
+    execute: function(){
+        return (this.target) ? this.verb.execute(this.target,this.argument) : 
+            this.verb.execute(this.argument);
+    },
+    executeOpposite: function(){
+        return (this.target) ? 
+            this.verb.executeOpposite(this.target,this.argument) : 
+            this.verb.executeOpposite(this.argument);
+    },
+    when: function(subject){
+        this.subject = subject;
+        return new Event.Behavior.Adjective(this);
+    },
+    getValue: function(){
+        return Try.these(
+            function(){return $(this.subject).getValue();}.bind(this),
+            function(){return $(this.subject).options[$(this.subject).options.selectedIndex].value;}.bind(this),
+            function(){return $(this.subject).value;}.bind(this),
+            function(){return $(this.subject).innerHTML;}.bind(this)
+        );
+    },
+    containsValue: function(match){
+        var value = this.getValue();
+        if(typeof(match) == 'function'){
+            return $A(match()).include(value);
+        }else {
+            return value.match(match); }
+    },
+    setTarget: function(target){
+        this.target = target;
+        return this;
+    },
+    and: function(){
 
-	}
+    }
 });
 Event.Behavior.Noun.prototype._with = Event.Behavior.Noun.prototype.setTarget;
 Event.Behavior.Noun.prototype.on = Event.Behavior.Noun.prototype.setTarget;
@@ -179,122 +176,117 @@ Event.Behavior.Noun.prototype.from = Event.Behavior.Noun.prototype.setTarget;
 
 Event.Behavior.Adjective = Class.create();
 Object.extend(Event.Behavior.Adjective.prototype,{
-	noun: false,
-	lastConditionName: '',
-	nextConditionType: 'and',
-	conditions: $A([]),
-	events: $A([]),
-	attached: false,
-	initialize: function(noun){
-		this.conditions = $A([]);
-		this.events = $A([]);
-		this.noun = noun;
-	},
-	attachObserver: function(execute_on_load){
-		if(this.attached){
-			//this may call things multiple times, but is the only way to gaurentee correct state on startup
-			if(execute_on_load)
-				this.execute();
-			return;
-		}
-		this.attached = true;
-		if(typeof(this.noun.subject) == 'function'){
-			$A(this.noun.subject()).each(function(subject){
-				(this.events.length &gt; 0 ? this.events : $A(['change'])).each(function(event_name){
-					(subject.observe ? subject : $(subject)).observe(event_name,function(){
-						this.execute();
-					}.bind(this));
-				}.bind(this));
-			}.bind(this));
-		}else{
-			(this.events.length &gt; 0 ? this.events : $A(['change'])).each(function(event_name){
-				$(this.noun.subject).observe(event_name,function(){
-					this.execute();
-				}.bind(this));
-			}.bind(this));
-		}
-		if(execute_on_load)
-			this.execute();
-	},
-	execute: function(){
-		if(this.match())
-			return this.noun.execute();
-		else if(this.noun.verb.executeOpposite)
-			this.noun.executeOpposite();
-	},
-	attachCondition: function(callback){
-		this.conditions.push([this.nextConditionType,callback.bind(this)]);
-	},
-	match: function(){
-		if(this.conditions.length == 0)
-			return true;
-		else{
-			return this.conditions.inject(new Boolean(),function(bool,condition){
-				return (condition[0] == 'and') ? (bool &amp;&amp; condition[1]()) : (bool || condition[1]());
-			});
-		}
-	},
-	//conditions
-	is: function(item){
-		this.lastConditionName = 'is';
-		this.attachCondition(function(item){
-			return (typeof(item) == 'function' ? item() : item) == this.noun.getValue();
-		}.bind(this,item));
-		this.attachObserver(true);
-		return this;
-	},
-	isNot: function(item){
-		this.lastConditionName = 'isNot';
-		this.attachCondition(function(item){
-			return (typeof(item) == 'function' ? item() : item) != this.noun.getValue();
-		}.bind(this,item));
-		this.attachObserver(true);
-		return this;
-	},
-	contains: function(item){
-		this.lastConditionName = 'contains';
-		this.attachCondition(function(item){
-			return this.noun.containsValue(item);
-		}.bind(this,item));
-		this.attachObserver(true);
-		return this;
-	},
-	within: function(item){
-		this.lastConditionName = 'within';
-		this.attachCondition(function(item){
-			
-		}.bind(this,item));
-		this.attachObserver(true);
-		return this;
-	},
-	//events
-	change: function(){
-		this.nextConditionType = 'and';
-		this.attachObserver(true);
-		return this;
-	},
-	and: function(condition){
-		this.attached = false;
-		this.nextConditionType = 'and';
-		if(condition)
-			this[this.lastConditionName](condition);
-		return this;
-	},
-	or: function(condition){
-		this.attached = false;
-		this.nextConditionType = 'or';
-		if(condition)
-			this[this.lastConditionName](condition);
-		return this;
-	}
+    noun: false,
+    lastConditionName: '',
+    nextConditionType: 'and',
+    conditions: $A([]),
+    events: $A([]),
+    attached: false,
+    initialize: function(noun){
+        this.conditions = $A([]);
+        this.events = $A([]);
+        this.noun = noun;
+    },
+    attachObserver: function(execute_on_load){
+        if(this.attached){
+            //this may call things multiple times, but is the only way to gaurentee correct state on startup
+            if(execute_on_load) {
+                this.execute(); }
+            return;
+        }
+        this.attached = true;
+        if(typeof(this.noun.subject) == 'function'){
+            $A(this.noun.subject()).each(function(subject){
+                (this.events.length &gt; 0 ? this.events : $A(['change'])).each(function(event_name){
+                    (subject.observe ? subject : $(subject)).observe(event_name,function(){
+                        this.execute();
+                    }.bind(this));
+                }.bind(this));
+            }.bind(this));
+        }else{
+            (this.events.length &gt; 0 ? this.events : $A(['change'])).each(function(event_name){
+                $(this.noun.subject).observe(event_name,function(){
+                    this.execute();
+                }.bind(this));
+            }.bind(this));
+        }
+        if(execute_on_load) { this.execute(); }
+    },
+    execute: function(){
+        if(this.match()) { return this.noun.execute(); }
+        else if(this.noun.verb.executeOpposite) { this.noun.executeOpposite(); }
+    },
+    attachCondition: function(callback){
+        this.conditions.push([this.nextConditionType,callback.bind(this)]);
+    },
+    match: function(){
+        if(this.conditions.length === 0) { return true; }
+        else {
+            return this.conditions.inject(false, function (bool,condition) {
+                return (condition[0] === 'or') ? 
+                       (bool &amp;&amp; condition[1]()) : (bool || condition[1]());
+            });
+        }
+    },
+    //conditions
+    is: function(item){
+        this.lastConditionName = 'is';
+        this.attachCondition(function(item){
+            return (typeof(item) == 'function' ? item() : item) == this.noun.getValue();
+        }.bind(this,item));
+        this.attachObserver(true);
+        return this;
+    },
+    isNot: function(item){
+        this.lastConditionName = 'isNot';
+        this.attachCondition(function(item){
+            return (typeof(item) == 'function' ? item() : item) != this.noun.getValue();
+        }.bind(this,item));
+        this.attachObserver(true);
+        return this;
+    },
+    contains: function(item){
+        this.lastConditionName = 'contains';
+        this.attachCondition(function(item){
+            return this.noun.containsValue(item);
+        }.bind(this,item));
+        this.attachObserver(true);
+        return this;
+    },
+    within: function(item){
+        this.lastConditionName = 'within';
+        this.attachCondition(function(item){
+            
+        }.bind(this,item));
+        this.attachObserver(true);
+        return this;
+    },
+    //events
+    change: function(){
+        this.nextConditionType = 'and';
+        this.attachObserver(true);
+        return this;
+    },
+    and: function(condition){
+        this.attached = false;
+        this.nextConditionType = 'and';
+        if(condition) { this[this.lastConditionName](condition); }
+        return this;
+    },
+    or: function(condition){
+        this.attached = false;
+        this.nextConditionType = 'or';
+        if(condition) { this[this.lastConditionName](condition); }
+        return this;
+    }
 });
 
 Event.Behavior.addEvents({
-	losesFocus: 'blur',
-	gainsFocus: 'focus',
-	isClicked: 'click',
-	isDoubleClicked: 'dblclick',
-	keyPressed: 'keypress'
+    losesFocus: 'blur',
+    gainsFocus: 'focus',
+    isClicked: 'click',
+    isDoubleClicked: 'dblclick',
+    keyPressed: 'keypress'
 });
 
 Event.Behavior.Adjective.prototype.is_not = Event.Behavior.Adjective.prototype.isNot;
@@ -303,4 +295,4 @@ Event.Behavior.Adjective.prototype.includes = Event.Behavior.Adjective.prototype
 Event.Behavior.Adjective.prototype.are = Event.Behavior.Adjective.prototype.is;
 Event.Behavior.Adjective.prototype.areNot = Event.Behavior.Adjective.prototype.isNot;
 Event.Behavior.Adjective.prototype.are_not = Event.Behavior.Adjective.prototype.isNot;
-Event.Behavior.Adjective.prototype.changes = Event.Behavior.Adjective.prototype.change;
\ No newline at end of file
+Event.Behavior.Adjective.prototype.changes = Event.Behavior.Adjective.prototype.change;</diff>
      <filename>src/event_behavior.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,54 +10,65 @@
 /*global document, Prototype, Class, Event, $ */
 
 if(typeof(Prototype) == &quot;undefined&quot;) {
-	throw &quot;HotKey requires Prototype to be loaded.&quot;; }
+    throw &quot;HotKey requires Prototype to be loaded.&quot;; }
 if(typeof(Object.Event) == &quot;undefined&quot;) {
-	throw &quot;HotKey requires Object.Event to be loaded.&quot;; }
+    throw &quot;HotKey requires Object.Event to be loaded.&quot;; }
 
 var HotKey = Class.create({
-	initialize: function(letter,callback,options){
-		letter = letter.toUpperCase();
-		HotKey.hotkeys.push(this);
-		this.options = Object.extend({
-			element: false,
-			shiftKey: false,
-			altKey: false,
-			ctrlKey: true
-		},options || {});
-		this.letter = letter;
-		this.callback = callback;
-		this.element = $(this.options.element || document);
-		this.handler = function(event){
-			if(!event || (
-				(Event['KEY_' + this.letter] || this.letter.charCodeAt(0)) == event.keyCode &amp;&amp;
-				((!this.options.shiftKey || (this.options.shiftKey &amp;&amp; event.shiftKey)) &amp;&amp;
-					(!this.options.altKey || (this.options.altKey &amp;&amp; event.altKey)) &amp;&amp;
-					(!this.options.ctrlKey || (this.options.ctrlKey &amp;&amp; event.ctrlKey))
-				)
-			)){
-				if(this.notify('beforeCallback',event) === false) {
-					return; }
-				this.callback(event);
-				this.notify('afterCallback',event);
-			}
-		}.bind(this);
-		this.enable();
-	},
-	trigger: function(){
-		this.handler();
-	},
-	enable: function(){
-		this.element.observe('keydown',this.handler);
-	},
-	disable: function(){
-		this.element.stopObserving('keydown',this.handler);
-	},
-	destroy: function(){
-		this.disable();
-		HotKey.hotkeys = HotKey.hotkeys.without(this);
-	}
+    initialize: function(letter,callback,options){
+        letter = letter.toUpperCase();
+        HotKey.hotkeys.push(this);
+        this.options = Object.extend({
+            element: false,
+            shiftKey: false,
+            altKey: false,
+            ctrlKey: true,
+            bubbleEvent : true,
+            fireOnce : false // Keep repeating event while key is pressed?
+        },options || {});
+        this.letter = letter;
+
+        // All custom hotkey events should stop after their custom actions.
+        this.callback = function (event) {
+            if (!(this.options.fireOnce &amp;&amp; this.fired) &amp;&amp; Object.isFunction(callback)) { 
+                callback(event); 
+            }
+            if (!this.options.bubbleEvent) { event.stop(); }
+            this.fired = true;
+        };
+
+        this.element = $(this.options.element || document);
+        this.handler = function(event){
+            if(!event || (
+                (Event['KEY_' + this.letter] || this.letter.charCodeAt(0)) == event.keyCode &amp;&amp;
+                ((!this.options.shiftKey || (this.options.shiftKey &amp;&amp; event.shiftKey)) &amp;&amp;
+                    (!this.options.altKey || (this.options.altKey &amp;&amp; event.altKey)) &amp;&amp;
+                    (!this.options.ctrlKey || (this.options.ctrlKey &amp;&amp; event.ctrlKey))
+                )
+            )){
+                if(this.notify('beforeCallback',event) === false) {
+                    return; }
+                this.callback(event);
+                this.notify('afterCallback',event);
+            }
+        }.bind(this);
+        this.enable();
+    },
+    trigger: function(){
+        this.handler();
+    },
+    enable: function(){
+        this.element.observe('keydown',this.handler);
+    },
+    disable: function(){
+        this.element.stopObserving('keydown',this.handler);
+    },
+    destroy: function(){
+        this.disable();
+        HotKey.hotkeys = HotKey.hotkeys.without(this);
+    }
 });
 Object.extend(HotKey,{
-	hotkeys: []
+    hotkeys: []
 });
 Object.Event.extend(HotKey);</diff>
      <filename>src/hotkey.js</filename>
    </modified>
    <modified>
      <diff>@@ -8,349 +8,173 @@
  */
 
 if(typeof(Control) == 'undefined')
-	Control = {};
-	
+    Control = {};
+    
 var $proc = function(proc){
-	return typeof(proc) == 'function' ? proc : function(){return proc};
+    return typeof(proc) == 'function' ? proc : function(){return proc};
 };
 
 var $value = function(value){
-	return typeof(value) == 'function' ? value() : value;
+    return typeof(value) == 'function' ? value() : value;
 };
 
 Object.Event = {
-	extend: function(object){
-		object._objectEventSetup = function(event_name){
-			this._observers = this._observers || {};
-			this._observers[event_name] = this._observers[event_name] || [];
-		};
-		object.observe = function(event_name,observer){
-			if(typeof(event_name) == 'string' &amp;&amp; typeof(observer) != 'undefined'){
-				this._objectEventSetup(event_name);
-				if(!this._observers[event_name].include(observer))
-					this._observers[event_name].push(observer);
-			}else
-				for(var e in event_name)
-					this.observe(e,event_name[e]);
-		};
-		object.stopObserving = function(event_name,observer){
-			this._objectEventSetup(event_name);
-			if(event_name &amp;&amp; observer)
-				this._observers[event_name] = this._observers[event_name].without(observer);
-			else if(event_name)
-				this._observers[event_name] = [];
-			else
-				this._observers = {};
-		};
-		object.observeOnce = function(event_name,outer_observer){
-			var inner_observer = function(){
-				outer_observer.apply(this,arguments);
-				this.stopObserving(event_name,inner_observer);
-			}.bind(this);
-			this._objectEventSetup(event_name);
-			this._observers[event_name].push(inner_observer);
-		};
-		object.notify = function(event_name){
-			this._objectEventSetup(event_name);
-			var collected_return_values = [];
-			var args = $A(arguments).slice(1);
-			try{
-				for(var i = 0; i &lt; this._observers[event_name].length; ++i)
-					collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
-			}catch(e){
-				if(e == $break)
-					return false;
-				else
-					throw e;
-			}
-			return collected_return_values;
-		};
-		if(object.prototype){
-			object.prototype._objectEventSetup = object._objectEventSetup;
-			object.prototype.observe = object.observe;
-			object.prototype.stopObserving = object.stopObserving;
-			object.prototype.observeOnce = object.observeOnce;
-			object.prototype.notify = function(event_name){
-				if(object.notify){
-					var args = $A(arguments).slice(1);
-					args.unshift(this);
-					args.unshift(event_name);
-					object.notify.apply(object,args);
-				}
-				this._objectEventSetup(event_name);
-				var args = $A(arguments).slice(1);
-				var collected_return_values = [];
-				try{
-					if(this.options &amp;&amp; this.options[event_name] &amp;&amp; typeof(this.options[event_name]) == 'function')
-						collected_return_values.push(this.options[event_name].apply(this,args) || null);
-					for(var i = 0; i &lt; this._observers[event_name].length; ++i)
-						collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
-				}catch(e){
-					if(e == $break)
-						return false;
-					else
-						throw e;
-				}
-				return collected_return_values;
-			};
-		}
-	}
+    extend: function(object){
+        object._objectEventSetup = function(event_name){
+            this._observers = this._observers || {};
+            this._observers[event_name] = this._observers[event_name] || [];
+        };
+        object.observe = function(event_name,observer){
+            if(typeof(event_name) == 'string' &amp;&amp; typeof(observer) != 'undefined'){
+                this._objectEventSetup(event_name);
+                if(!this._observers[event_name].include(observer))
+                    this._observers[event_name].push(observer);
+            }else
+                for(var e in event_name)
+                    this.observe(e,event_name[e]);
+        };
+        object.stopObserving = function(event_name,observer){
+            this._objectEventSetup(event_name);
+            if(event_name &amp;&amp; observer)
+                this._observers[event_name] = this._observers[event_name].without(observer);
+            else if(event_name)
+                this._observers[event_name] = [];
+            else
+                this._observers = {};
+        };
+        object.observeOnce = function(event_name,outer_observer){
+            var inner_observer = function(){
+                outer_observer.apply(this,arguments);
+                this.stopObserving(event_name,inner_observer);
+            }.bind(this);
+            this._objectEventSetup(event_name);
+            this._observers[event_name].push(inner_observer);
+        };
+        object.notify = function(event_name){
+            this._objectEventSetup(event_name);
+            var collected_return_values = [];
+            var args = $A(arguments).slice(1);
+            try{
+                for(var i = 0; i &lt; this._observers[event_name].length; ++i)
+                    collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
+            }catch(e){
+                if(e == $break)
+                    return false;
+                else
+                    throw e;
+            }
+            return collected_return_values;
+        };
+        if(object.prototype){
+            object.prototype._objectEventSetup = object._objectEventSetup;
+            object.prototype.observe = object.observe;
+            object.prototype.stopObserving = object.stopObserving;
+            object.prototype.observeOnce = object.observeOnce;
+            object.prototype.notify = function(event_name){
+                if(object.notify){
+                    var args = $A(arguments).slice(1);
+                    args.unshift(this);
+                    args.unshift(event_name);
+                    object.notify.apply(object,args);
+                }
+                this._objectEventSetup(event_name);
+                var args = $A(arguments).slice(1);
+                var collected_return_values = [];
+                try{
+                    if(this.options &amp;&amp; this.options[event_name] &amp;&amp; typeof(this.options[event_name]) == 'function')
+                        collected_return_values.push(this.options[event_name].apply(this,args) || null);
+                    for(var i = 0; i &lt; this._observers[event_name].length; ++i)
+                        collected_return_values.push(this._observers[event_name][i].apply(this._observers[event_name][i],args) || null);
+                }catch(e){
+                    if(e == $break)
+                        return false;
+                    else
+                        throw e;
+                }
+                return collected_return_values;
+            };
+        }
+    }
 };
 
 /* Begin Core Extensions */
 
 //Element.observeOnce
 Element.addMethods({
-	observeOnce: function(element,event_name,outer_callback){
-		var inner_callback = function(){
-			outer_callback.apply(this,arguments);
-			Element.stopObserving(element,event_name,inner_callback);
-		};
-		Element.observe(element,event_name,inner_callback);
-	}
-});
-
-//mouseenter, mouseleave
-//from http://dev.rubyonrails.org/attachment/ticket/8354/event_mouseenter_106rc1.patch
-Object.extend(Event, (function() {
-	var cache = Event.cache;
-
-	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;;
-		//begin extension
-		if(!Prototype.Browser.IE){
-			eventName = {
-				mouseenter: 'mouseover',
-				mouseleave: 'mouseout'
-			}[eventName] || eventName;
-		}
-		//end extension
-		return eventName;
-	}
-
-	function getCacheForID(id) {
-		return cache[id] = cache[id] || { };
-	}
-
-	function getWrappersForEventName(id, eventName) {
-		var c = getCacheForID(id);
-		return c[eventName] = c[eventName] || [];
-	}
-
-	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 wrapper = function(event) {
-			if (!Event || !Event.extend ||
-				(event.eventName &amp;&amp; event.eventName != eventName))
-					return false;
-
-			Event.extend(event);
-			handler.call(element, event);
-		};
-		
-		//begin extension
-		if(!(Prototype.Browser.IE) &amp;&amp; ['mouseenter','mouseleave'].include(eventName)){
-			wrapper = wrapper.wrap(function(proceed,event) {	
-				var rel = event.relatedTarget;
-				var cur = event.currentTarget;			 
-				if(rel &amp;&amp; rel.nodeType == Node.TEXT_NODE)
-					rel = rel.parentNode;	  
-				if(rel &amp;&amp; rel != cur &amp;&amp; !rel.descendantOf(cur))	  
-					return proceed(event);   
-			});	 
-		}
-		//end extension
-
-		wrapper.handler = handler;
-		c.push(wrapper);
-		return wrapper;
-	}
-
-	function findWrapper(id, eventName, handler) {
-		var c = getWrappersForEventName(id, eventName);
-		return c.find(function(wrapper) { return wrapper.handler == handler });
-	}
-
-	function destroyWrapper(id, eventName, handler) {
-		var c = getCacheForID(id);
-		if (!c[eventName]) return false;
-		c[eventName] = c[eventName].without(findWrapper(id, eventName, handler));
-	}
-
-	function destroyCache() {
-		for (var id in cache)
-			for (var eventName in cache[id])
-				cache[id][eventName] = null;
-	}
-
-	if (window.attachEvent) {
-		window.attachEvent(&quot;onunload&quot;, destroyCache);
-	}
-
-	return {
-		observe: function(element, eventName, handler) {
-			element = $(element);
-			var name = getDOMEventName(eventName);
-
-			var wrapper = createWrapper(element, eventName, handler);
-			if (!wrapper) return element;
-
-			if (element.addEventListener) {
-				element.addEventListener(name, wrapper, false);
-			} else {
-				element.attachEvent(&quot;on&quot; + name, wrapper);
-			}
-
-			return element;
-		},
-
-		stopObserving: function(element, eventName, handler) {
-			element = $(element);
-			var id = getEventID(element), name = getDOMEventName(eventName);
-
-			if (!handler &amp;&amp; eventName) {
-				getWrappersForEventName(id, eventName).each(function(wrapper) {
-					element.stopObserving(eventName, wrapper.handler);
-				});
-				return element;
-
-			} else if (!eventName) {
-				Object.keys(getCacheForID(id)).each(function(eventName) {
-					element.stopObserving(eventName);
-				});
-				return element;
-			}
-
-			var wrapper = findWrapper(id, eventName, handler);
-			if (!wrapper) return element;
-
-			if (element.removeEventListener) {
-				element.removeEventListener(name, wrapper, false);
-			} else {
-				element.detachEvent(&quot;on&quot; + name, wrapper);
-			}
-
-			destroyWrapper(id, eventName, handler);
-
-			return element;
-		},
-
-		fire: function(element, eventName, memo) {
-			element = $(element);
-			if (element == document &amp;&amp; document.createEvent &amp;&amp; !element.dispatchEvent)
-				element = document.documentElement;
-
-			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;;
-			}
-
-			event.eventName = eventName;
-			event.memo = memo || { };
-
-			if (document.createEvent) {
-				element.dispatchEvent(event);
-			} else {
-				element.fireEvent(event.eventType, event);
-			}
-
-			return Event.extend(event);
-		}
-	};
-})());
-
-Object.extend(Event, Event.Methods);
-
-Element.addMethods({
-	fire:			Event.fire,
-	observe:		Event.observe,
-	stopObserving:	Event.stopObserving
-});
-
-Object.extend(document, {
-	fire:			Element.Methods.fire.methodize(),
-	observe:		Element.Methods.observe.methodize(),
-	stopObserving:	Element.Methods.stopObserving.methodize()
+    observeOnce: function(element,event_name,outer_callback){
+        var inner_callback = function(){
+            outer_callback.apply(this,arguments);
+            Element.stopObserving(element,event_name,inner_callback);
+        };
+        Element.observe(element,event_name,inner_callback);
+    }
 });
 
 //mouse:wheel
 (function(){
-	function wheel(event){
-		var delta;
-		// normalize the delta
-		if(event.wheelDelta) // IE &amp; Opera
-			delta = event.wheelDelta / 120;
-		else if (event.detail) // W3C
-			delta =- event.detail / 3;
-		if(!delta)
-			return;
-		var custom_event = Event.element(event).fire('mouse:wheel',{
-			delta: delta
-		});
-		if(custom_event.stopped){
-			Event.stop(event);
-			return false;
-		}
-	}
-	document.observe('mousewheel',wheel);
-	document.observe('DOMMouseScroll',wheel);
+    function wheel(event){
+        var delta, element, custom_event;
+        // normalize the delta
+        if (event.wheelDelta) { // IE &amp; Opera
+            delta = event.wheelDelta / 120;
+        } else if (event.detail) { // W3C
+            delta =- event.detail / 3;
+        }
+        if (!delta) { return; }
+        element = Event.extend(event).target;
+        element = Element.extend(element.nodeType === Node.TEXT_NODE ? element.parentNode : element);
+        custom_event = element.fire('mouse:wheel',{ delta: delta });
+        if (custom_event.stopped) {
+            Event.stop(event);
+            return false;
+        }
+    }
+    document.observe('mousewheel',wheel);
+    document.observe('DOMMouseScroll',wheel);
 })();
 
 /* End Core Extensions */
 
 //from PrototypeUI
 var IframeShim = Class.create({
-	initialize: function() {
-		this.element = new Element('iframe',{
-			style: 'position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);display:none',
-			src: 'javascript:void(0);',
-			frameborder: 0 
-		});
-		$(document.body).insert(this.element);
-	},
-	hide: function() {
-		this.element.hide();
-		return this;
-	},
-	show: function() {
-		this.element.show();
-		return this;
-	},
-	positionUnder: function(element) {
-		var element = $(element);
-		var offset = element.cumulativeOffset();
-		var dimensions = element.getDimensions();
-		this.element.setStyle({
-			left: offset[0] + 'px',
-			top: offset[1] + 'px',
-			width: dimensions.width + 'px',
-			height: dimensions.height + 'px',
-			zIndex: element.getStyle('zIndex') - 1
-		}).show();
-		return this;
-	},
-	setBounds: function(bounds) {
-		for(prop in bounds)
-			bounds[prop] += 'px';
-		this.element.setStyle(bounds);
-		return this;
-	},
-	destroy: function() {
-		if(this.element)
-			this.element.remove();
-		return this;
-	}
-});
\ No newline at end of file
+    initialize: function() {
+        this.element = new Element('iframe',{
+            style: 'position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);display:none',
+            src: 'javascript:void(0);',
+            frameborder: 0 
+        });
+        $(document.body).insert(this.element);
+    },
+    hide: function() {
+        this.element.hide();
+        return this;
+    },
+    show: function() {
+        this.element.show();
+        return this;
+    },
+    positionUnder: function(element) {
+        var element = $(element);
+        var offset = element.cumulativeOffset();
+        var dimensions = element.getDimensions();
+        this.element.setStyle({
+            left: offset[0] + 'px',
+            top: offset[1] + 'px',
+            width: dimensions.width + 'px',
+            height: dimensions.height + 'px',
+            zIndex: element.getStyle('zIndex') - 1
+        }).show();
+        return this;
+    },
+    setBounds: function(bounds) {
+        for(prop in bounds)
+            bounds[prop] += 'px';
+        this.element.setStyle(bounds);
+        return this;
+    },
+    destroy: function() {
+        if(this.element)
+            this.element.remove();
+        return this;
+    }
+});</diff>
      <filename>src/livepipe.js</filename>
    </modified>
    <modified>
      <diff>@@ -7,91 +7,96 @@
  * @require prototype.js, livepipe.js
  */
 
-if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Control.ProgressBar requires Prototype to be loaded.&quot;;
-if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Control.ProgressBar requires Object.Event to be loaded.&quot;;
+/*global document, Prototype, Ajax, Class, PeriodicalExecuter, $, $A, Control */
+
+if(typeof(Prototype) == &quot;undefined&quot;) {
+    throw &quot;Control.ProgressBar requires Prototype to be loaded.&quot;; }
+if(typeof(Object.Event) == &quot;undefined&quot;) {
+    throw &quot;Control.ProgressBar requires Object.Event to be loaded.&quot;; }
 
 Control.ProgressBar = Class.create({
-	initialize: function(container,options){
-		this.progress = 0;
-		this.executer = false;
-		this.active = false;
-		this.poller = false;
-		this.container = $(container);
-		this.containerWidth = this.container.getDimensions().width - (parseInt(this.container.getStyle('border-right-width').replace(/px/,'')) + parseInt(this.container.getStyle('border-left-width').replace(/px/,'')));
-		this.progressContainer = $(document.createElement('div'));
-		this.progressContainer.setStyle({
-			width: this.containerWidth + 'px',
-			height: '100%',
-			position: 'absolute',
-			top: '0px',
-			right: '0px'
-		});
-		this.container.appendChild(this.progressContainer);
-		this.options = {
-			afterChange: Prototype.emptyFunction,
-			interval: 0.25,
-			step: 1,
-			classNames: {
-				active: 'progress_bar_active',
-				inactive: 'progress_bar_inactive'
-			}
-		};
-		Object.extend(this.options,options || {});
-		this.container.addClassName(this.options.classNames.inactive);
-		this.active = false;
-	},
-	setProgress: function(value){
-		this.progress = value;
-		this.draw();
-		if(this.progress &gt;= 100)
-			this.stop(false);
-		this.notify('afterChange',this.progress,this.active);
-	},
-	poll: function(url,interval){
-		this.active = true;
-		this.poller = new PeriodicalExecuter(function(){
-			new Ajax.Request(url,{
-				onSuccess: function(request){
-					this.setProgress(parseInt(request.responseText));
-					if(!this.active)
-						this.poller.stop();
-				}.bind(this)
-			});
-		}.bind(this),interval || 3);
-	},
-	start: function(){
-		this.active = true;
-		this.container.removeClassName(this.options.classNames.inactive);
-		this.container.addClassName(this.options.classNames.active);
-		this.executer = new PeriodicalExecuter(this.step.bind(this,this.options.step),this.options.interval);
-	},
-	stop: function(reset){
-		this.active = false;
-		if(this.executer)
-			this.executer.stop();
-		this.container.removeClassName(this.options.classNames.active);
-		this.container.addClassName(this.options.classNames.inactive);
-		if(typeof(reset) == 'undefined' || reset == true)
-			this.reset();
-	},
-	step: function(amount){
-		this.active = true;
-		this.setProgress(Math.min(100,this.progress + amount));
-	},
-	reset: function(){
-		this.active = false;
-		this.setProgress(0);
-	},
-	draw: function(){
-		this.progressContainer.setStyle({
-			width: (this.containerWidth - Math.floor((parseInt(this.progress) / 100) * this.containerWidth)) + 'px'
-		});
-	},
-	notify: function(event_name){
-		if(this.options[event_name])
-			return [this.options[event_name].apply(this.options[event_name],$A(arguments).slice(1))];
-	}
+    initialize: function(container,options){
+        this.progress = 0;
+        this.executer = false;
+        this.active = false;
+        this.poller = false;
+        this.container = $(container);
+        this.containerWidth = this.container.getDimensions().width - (parseInt(this.container.getStyle('border-right-width').replace(/px/,''), 10) + parseInt(this.container.getStyle('border-left-width').replace(/px/,''), 10));
+        this.progressContainer = $(document.createElement('div'));
+        this.progressContainer.setStyle({
+            width: this.containerWidth + 'px',
+            height: '100%',
+            position: 'absolute',
+            top: '0px',
+            right: '0px'
+        });
+        this.container.appendChild(this.progressContainer);
+        this.options = {
+            afterChange: Prototype.emptyFunction,
+            interval: 0.25,
+            step: 1,
+            classNames: {
+                active: 'progress_bar_active',
+                inactive: 'progress_bar_inactive'
+            }
+        };
+        Object.extend(this.options,options || {});
+        this.container.addClassName(this.options.classNames.inactive);
+        this.active = false;
+    },
+    setProgress: function(value){
+        this.progress = value;
+        this.draw();
+        if(this.progress &gt;= 100) {
+            this.stop(false); }
+        this.notify('afterChange',this.progress,this.active);
+    },
+    poll: function (url, interval, ajaxOptions){
+        // Extend the passed ajax options and success callback with our own.
+        ajaxOptions = ajaxOptions || {};
+        var success = ajaxOptions.onSuccess || Prototype.emptyFunction;
+        ajaxOptions.onSuccess = success.wrap(function (callOriginal, request) {
+            this.setProgress(parseInt(request.responseText, 10));
+            if(!this.active) { this.poller.stop(); }
+            callOriginal(request);
+        }).bind(this);
+
+        this.active = true;
+        this.poller = new PeriodicalExecuter(function(){
+            var a = new Ajax.Request(url, ajaxOptions);
+        }.bind(this),interval || 3);
+    },
+    start: function(){
+        this.active = true;
+        this.container.removeClassName(this.options.classNames.inactive);
+        this.container.addClassName(this.options.classNames.active);
+        this.executer = new PeriodicalExecuter(this.step.bind(this,this.options.step),this.options.interval);
+    },
+    stop: function(reset){
+        this.active = false;
+        if(this.executer) {
+            this.executer.stop(); }
+        this.container.removeClassName(this.options.classNames.active);
+        this.container.addClassName(this.options.classNames.inactive);
+        if (typeof reset  === 'undefined' || reset === true) {
+            this.reset(); }
+    },
+    step: function(amount){
+        this.active = true;
+        this.setProgress(Math.min(100,this.progress + amount));
+    },
+    reset: function(){
+        this.active = false;
+        this.setProgress(0);
+    },
+    draw: function(){
+        this.progressContainer.setStyle({
+            width: (this.containerWidth - Math.floor((parseInt(this.progress, 10) / 100) * this.containerWidth)) + 'px'
+        });
+    },
+    notify: function(event_name){
+        if(this.options[event_name]) {
+            return [this.options[event_name].apply(this.options[event_name],$A(arguments).slice(1))]; }
+    }
 });
-Object.Event.extend(Control.ProgressBar);
\ No newline at end of file
+Object.Event.extend(Control.ProgressBar);</diff>
      <filename>src/progressbar.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,146 +10,147 @@
 /*global document, Prototype, Ajax, Class, Event, $, $A, $F, $R, $break, Control */
 
 if(typeof(Prototype) == &quot;undefined&quot;) {
-	throw &quot;Control.Rating requires Prototype to be loaded.&quot;; }
+    throw &quot;Control.Rating requires Prototype to be loaded.&quot;; }
 if(typeof(Object.Event) == &quot;undefined&quot;) {
-	throw &quot;Control.Rating requires Object.Event to be loaded.&quot;; }
+    throw &quot;Control.Rating requires Object.Event to be loaded.&quot;; }
 
 Control.Rating = Class.create({
-	initialize: function(container,options){
-		Control.Rating.instances.push(this);
-		this.value = false;
-		this.links = [];
-		this.container = $(container);
-		this.container.update('');
-		this.options = {
-			min: 1,
-			max: 5,
-			rated: false,
-			input: false,
-			reverse: false,
-			capture: true,
-			multiple: false,
-			classNames: {
-				off: 'rating_off',
-				half: 'rating_half',
-				on: 'rating_on',
-				selected: 'rating_selected'
-			},
-			updateUrl: false,
-			updateParameterName: 'value',
-			afterChange: Prototype.emptyFunction
-		};
-		Object.extend(this.options,options || {});
-		if(this.options.value){
-			this.value = this.options.value;
-			delete this.options.value;
-		}
-		if(this.options.input){
-			this.options.input = $(this.options.input);
-			this.options.input.observe('change',function(input){
-				this.setValueFromInput(input);
-			}.bind(this,this.options.input));
-			this.setValueFromInput(this.options.input,true);
-		}
-		var range = $R(this.options.min,this.options.max);
-		(this.options.reverse ? $A(range).reverse() : range).each(function(i){
-			var link = this.buildLink(i);
-			this.container.appendChild(link);
-			this.links.push(link);
-		}.bind(this));
-		this.setValue(this.value || this.options.min - 1,false,true);
-	},
-	buildLink: function(rating){
-		var link = $(document.createElement('a'));
-		link.value = rating;
-		if(this.options.multiple || (!this.options.rated &amp;&amp; !this.options.multiple)){
-			link.href = '';
-			link.onmouseover = this.mouseOver.bind(this,link);
-			link.onmouseout = this.mouseOut.bind(this,link);
-			link.onclick = this.click.bindAsEventListener(this,link);
-		}else{
-			link.style.cursor = 'default';
-			link.observe('click',function(event){
-				Event.stop(event);
-				return false;
-			}.bindAsEventListener(this));
-		}
-		link.addClassName(this.options.classNames.off);
-		return link;
-	},
-	disable: function(){
-		this.links.each(function(link){
-			link.onmouseover = Prototype.emptyFunction;
-			link.onmouseout = Prototype.emptyFunction;
-			link.onclick = Prototype.emptyFunction;
-			link.observe('click',function(event){
-				Event.stop(event);
-				return false;
-			}.bindAsEventListener(this));
-			link.style.cursor = 'default';
-		}.bind(this));
-	},
-	setValueFromInput: function(input,prevent_callbacks){
+    initialize: function(container,options){
+        Control.Rating.instances.push(this);
+        this.value = false;
+        this.links = [];
+        this.container = $(container);
+        this.container.update('');
+        this.options = {
+            min: 1,
+            max: 5,
+            rated: false,
+            input: false,
+            reverse: false,
+            capture: true,
+            multiple: false,
+            classNames: {
+                off: 'rating_off',
+                half: 'rating_half',
+                on: 'rating_on',
+                selected: 'rating_selected'
+            },
+            updateUrl: false,
+            updateParameterName: 'value',
+            updateOptions : {},
+            afterChange: Prototype.emptyFunction
+        };
+        Object.extend(this.options,options || {});
+        if(this.options.value){
+            this.value = this.options.value;
+            delete this.options.value;
+        }
+        if(this.options.input){
+            this.options.input = $(this.options.input);
+            this.options.input.observe('change',function(input){
+                this.setValueFromInput(input);
+            }.bind(this,this.options.input));
+            this.setValueFromInput(this.options.input,true);
+        }
+        var range = $R(this.options.min,this.options.max);
+        (this.options.reverse ? $A(range).reverse() : range).each(function(i){
+            var link = this.buildLink(i);
+            this.container.appendChild(link);
+            this.links.push(link);
+        }.bind(this));
+        this.setValue(this.value || this.options.min - 1,false,true);
+    },
+    buildLink: function(rating){
+        var link = $(document.createElement('a'));
+        link.value = rating;
+        if(this.options.multiple || (!this.options.rated &amp;&amp; !this.options.multiple)){
+            link.href = '';
+            link.onmouseover = this.mouseOver.bind(this,link);
+            link.onmouseout = this.mouseOut.bind(this,link);
+            link.onclick = this.click.bindAsEventListener(this,link);
+        }else{
+            link.style.cursor = 'default';
+            link.observe('click',function(event){
+                Event.stop(event);
+                return false;
+            }.bindAsEventListener(this));
+        }
+        link.addClassName(this.options.classNames.off);
+        return link;
+    },
+    disable: function(){
+        this.links.each(function(link){
+            link.onmouseover = Prototype.emptyFunction;
+            link.onmouseout = Prototype.emptyFunction;
+            link.onclick = Prototype.emptyFunction;
+            link.observe('click',function(event){
+                Event.stop(event);
+                return false;
+            }.bindAsEventListener(this));
+            link.style.cursor = 'default';
+        }.bind(this));
+    },
+    setValueFromInput: function(input,prevent_callbacks){
         this.setValue($F(input),true,prevent_callbacks);
-	},
-	setValue: function(value,force_selected,prevent_callbacks){
-		this.value = value;
-		if(this.options.input){
-			if(this.options.input.options){
-				$A(this.options.input.options).each(function(option,i){
-					if(option.value == this.value){
-						this.options.input.options.selectedIndex = i;
-						throw $break;
-					}
-				}.bind(this));
-			}else {
-				this.options.input.value = this.value; }
-		}
-		this.render(this.value,force_selected);
-		if(!prevent_callbacks){
-			if(this.options.updateUrl){
-				var params = {}, a;
-				params[this.options.updateParameterName] = this.value;
-				a = new Ajax.Request(this.options.updateUrl,{
-					parameters: params
-				});
-			}
-			this.notify('afterChange',this.value);
-		}
-	},
-	render: function(rating,force_selected){
-		(this.options.reverse ? this.links.reverse() : this.links).each(function(link,i){
-			if(link.value &lt;= Math.ceil(rating)){
-				link.className = this.options.classNames[link.value &lt;= rating ? 'on' : 'half'];
-				if(this.options.rated || force_selected) {
-					link.addClassName(this.options.classNames.selected); }
-			}else {
-				link.className = this.options.classNames.off; }
-		}.bind(this));
-	},
-	mouseOver: function(link){
-		this.render(link.value,true);
-	},
-	mouseOut: function(link){
-		this.render(this.value);
-	},
-	click: function(event,link){
-		this.options.rated = true;
-		this.setValue((link.value ? link.value : link),true);
-		if(!this.options.multiple) {
-			this.disable(); }
-		if(this.options.capture){
-			Event.stop(event);
-			return false;
-		}
-	}
+    },
+    setValue: function(value,force_selected,prevent_callbacks){
+        this.value = value;
+        if(this.options.input){
+            if(this.options.input.options){
+                $A(this.options.input.options).each(function(option,i){
+                    if(option.value == this.value){
+                        this.options.input.options.selectedIndex = i;
+                        throw $break;
+                    }
+                }.bind(this));
+            }else {
+                this.options.input.value = this.value; }
+        }
+        this.render(this.value,force_selected);
+        if(!prevent_callbacks){
+            if(this.options.updateUrl){
+                var params = {}, a;
+                params[this.options.updateParameterName] = this.value;
+                a = new Ajax.Request(this.options.updateUrl, Object.extend(
+                    this.options.updateOptions, { parameters : params }
+                ));
+            }
+            this.notify('afterChange',this.value);
+        }
+    },
+    render: function(rating,force_selected){
+        (this.options.reverse ? this.links.reverse() : this.links).each(function(link,i){
+            if(link.value &lt;= Math.ceil(rating)){
+                link.className = this.options.classNames[link.value &lt;= rating ? 'on' : 'half'];
+                if(this.options.rated || force_selected) {
+                    link.addClassName(this.options.classNames.selected); }
+            }else {
+                link.className = this.options.classNames.off; }
+        }.bind(this));
+    },
+    mouseOver: function(link){
+        this.render(link.value,true);
+    },
+    mouseOut: function(link){
+        this.render(this.value);
+    },
+    click: function(event,link){
+        this.options.rated = true;
+        this.setValue((link.value ? link.value : link),true);
+        if(!this.options.multiple) {
+            this.disable(); }
+        if(this.options.capture){
+            Event.stop(event);
+            return false;
+        }
+    }
 });
 Object.extend(Control.Rating,{
-	instances: [],
-	findByElementId: function(id){
-		return Control.Rating.instances.find(function(instance){
-			return (instance.container.id &amp;&amp; instance.container.id == id);
-		});
-	}
+    instances: [],
+    findByElementId: function(id){
+        return Control.Rating.instances.find(function(instance){
+            return (instance.container.id &amp;&amp; instance.container.id == id);
+        });
+    }
 });
 Object.Event.extend(Control.Rating);</diff>
      <filename>src/rating.js</filename>
    </modified>
    <modified>
      <diff>@@ -8,140 +8,140 @@
  */
 
 if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Control.ScrollBar requires Prototype to be loaded.&quot;;
+    throw &quot;Control.ScrollBar requires Prototype to be loaded.&quot;;
 if(typeof(Control.Slider) == &quot;undefined&quot;)
-	throw &quot;Control.ScrollBar requires Control.Slider to be loaded.&quot;;
+    throw &quot;Control.ScrollBar requires Control.Slider to be loaded.&quot;;
 if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Control.ScrollBar requires Object.Event to be loaded.&quot;;
+    throw &quot;Control.ScrollBar requires Object.Event to be loaded.&quot;;
 
 Control.ScrollBar = Class.create({
-	initialize: function(container,track,options){
-		this.enabled = false;
-		this.notificationTimeout = false;
-		this.container = $(container);
-		this.boundMouseWheelEvent = this.onMouseWheel.bindAsEventListener(this);
-		this.boundResizeObserver = this.onWindowResize.bind(this);
-		this.track = $(track);
-		this.handle = this.track.firstDescendant();
-		this.options = Object.extend({
-			active_class_name: 'scrolling',
-			apply_active_class_name_to: this.container,
-			notification_timeout_length: 125,
-			handle_minimum_height: 25,
-			scroll_to_smoothing: 0.01,
-			scroll_to_steps: 15,
-			proportional: true,
-			slider_options: {}
-		},options || {});
-		this.slider = new Control.Slider(this.handle,this.track,Object.extend({
-			axis: 'vertical',
-			onSlide: this.onChange.bind(this),
-			onChange: this.onChange.bind(this)
-		},this.options.slider_options));
-		this.recalculateLayout();
-		Event.observe(window,'resize',this.boundResizeObserver);
-		this.handle.observe('mousedown',function(){
-		    if(this.auto_sliding_executer)
-    			this.auto_sliding_executer.stop();
-		}.bind(this));
-	},
-	destroy: function(){
-		Event.stopObserving(window,'resize',this.boundResizeObserver);
-	},
-	enable: function(){
-		this.enabled = true;
-		this.container.observe('mouse:wheel',this.boundMouseWheelEvent);
-		this.slider.setEnabled();
-		this.track.show();
-		if(this.options.active_class_name)
-			$(this.options.apply_active_class_name_to).addClassName(this.options.active_class_name);
-		this.notify('enabled');
-	},
-	disable: function(){
-		this.enabled = false;
-		this.container.stopObserving('mouse:wheel',this.boundMouseWheelEvent);
-		this.slider.setDisabled();
-		this.track.hide();
-		if(this.options.active_class_name)
-			$(this.options.apply_active_class_name_to).removeClassName(this.options.active_class_name);
-		this.notify('disabled');
-		this.reset();
-	},
-	reset: function(){
-		this.slider.setValue(0);
-	},
-	recalculateLayout: function(){
-		if(this.container.scrollHeight &lt;= this.container.offsetHeight)
-			this.disable();
-		else{
-			this.slider.trackLength = this.slider.maximumOffset() - this.slider.minimumOffset();
-			if(this.options.proportional){
-				this.handle.style.height = Math.max(this.container.offsetHeight * (this.container.offsetHeight / this.container.scrollHeight),this.options.handle_minimum_height) + 'px';
-				this.slider.handleLength = this.handle.style.height.replace(/px/,'');
-			}
-			this.enable();
-		}
-	},
-	onWindowResize: function(){
-		this.recalculateLayout();
-		this.scrollBy(0);
-	},
-	onMouseWheel: function(event){
-	    if(this.auto_sliding_executer)
-			this.auto_sliding_executer.stop();
-		this.slider.setValueBy(-(event.memo.delta / 20)); //put in math to account for the window height
-		event.stop();
-		return false;
-	},
-	onChange: function(value){
-		this.container.scrollTop = Math.round(value / this.slider.maximum * (this.container.scrollHeight - this.container.offsetHeight));
-		if(this.notification_timeout)
-			window.clearTimeout(this.notificationTimeout);
-		this.notificationTimeout = window.setTimeout(function(){
-			this.notify('change',value);
-		}.bind(this),this.options.notification_timeout_length);
-	},
-	getCurrentMaximumDelta: function(){
-		return this.slider.maximum * (this.container.scrollHeight - this.container.offsetHeight);
-	},
-	getDeltaToElement: function(element){
-		return this.slider.maximum * ((element.positionedOffset().top + (element.getHeight() / 2)) - (this.container.getHeight() / 2));
-	},
-	scrollTo: function(y,animate){
-		var current_maximum_delta = this.getCurrentMaximumDelta();
-		if(y == 'top')
-			y = 0;
-		else if(y == 'bottom')
-			y = current_maximum_delta;
-		else if(typeof(y) != &quot;number&quot;)
-			y = this.getDeltaToElement($(y));
-		if(this.enabled){
-			y = Math.max(0,Math.min(y,current_maximum_delta));
-			if(this.auto_sliding_executer)
-				this.auto_sliding_executer.stop();
-			var target_value = y / current_maximum_delta;
-			var original_slider_value = this.slider.value;
-			var delta = (target_value - original_slider_value) * current_maximum_delta;
-			if(animate){
-				this.auto_sliding_executer = new PeriodicalExecuter(function(){
-					if(Math.round(this.slider.value * 100) / 100 &lt; Math.round(target_value * 100) / 100 || Math.round(this.slider.value * 100) / 100 &gt; Math.round(target_value * 100) / 100){
-						this.scrollBy(delta / this.options.scroll_to_steps);
-					}else{
-						this.auto_sliding_executer.stop();
-						this.auto_sliding_executer = null;
-						if(typeof(animate) == &quot;function&quot;)
-							animate();
-					}			
-				}.bind(this),this.options.scroll_to_smoothing);
-			}else
-				this.scrollBy(delta);
-		}else if(typeof(animate) == &quot;function&quot;)
-			animate();
-	},
-	scrollBy: function(y){
-		if(!this.enabled)
-			return false;
-		this.slider.setValueBy(y / this.getCurrentMaximumDelta());
-	}
+    initialize: function(container,track,options){
+        this.enabled = false;
+        this.notificationTimeout = false;
+        this.container = $(container);
+        this.boundMouseWheelEvent = this.onMouseWheel.bindAsEventListener(this);
+        this.boundResizeObserver = this.onWindowResize.bind(this);
+        this.track = $(track);
+        this.handle = this.track.firstDescendant();
+        this.options = Object.extend({
+            active_class_name: 'scrolling',
+            apply_active_class_name_to: this.container,
+            notification_timeout_length: 125,
+            handle_minimum_height: 25,
+            scroll_to_smoothing: 0.01,
+            scroll_to_steps: 15,
+            proportional: true,
+            slider_options: {}
+        },options || {});
+        this.slider = new Control.Slider(this.handle,this.track,Object.extend({
+            axis: 'vertical',
+            onSlide: this.onChange.bind(this),
+            onChange: this.onChange.bind(this)
+        },this.options.slider_options));
+        this.recalculateLayout();
+        Event.observe(window,'resize',this.boundResizeObserver);
+        this.handle.observe('mousedown',function(){
+            if(this.auto_sliding_executer)
+                this.auto_sliding_executer.stop();
+        }.bind(this));
+    },
+    destroy: function(){
+        Event.stopObserving(window,'resize',this.boundResizeObserver);
+    },
+    enable: function(){
+        this.enabled = true;
+        this.container.observe('mouse:wheel',this.boundMouseWheelEvent);
+        this.slider.setEnabled();
+        this.track.show();
+        if(this.options.active_class_name)
+            $(this.options.apply_active_class_name_to).addClassName(this.options.active_class_name);
+        this.notify('enabled');
+    },
+    disable: function(){
+        this.enabled = false;
+        this.container.stopObserving('mouse:wheel',this.boundMouseWheelEvent);
+        this.slider.setDisabled();
+        this.track.hide();
+        if(this.options.active_class_name)
+            $(this.options.apply_active_class_name_to).removeClassName(this.options.active_class_name);
+        this.notify('disabled');
+        this.reset();
+    },
+    reset: function(){
+        this.slider.setValue(0);
+    },
+    recalculateLayout: function(){
+        if(this.container.scrollHeight &lt;= this.container.offsetHeight)
+            this.disable();
+        else{
+            this.enable();
+            this.slider.trackLength = this.slider.maximumOffset() - this.slider.minimumOffset();
+            if(this.options.proportional){
+                this.handle.style.height = Math.max(this.container.offsetHeight * (this.container.offsetHeight / this.container.scrollHeight),this.options.handle_minimum_height) + 'px';
+                this.slider.handleLength = this.handle.style.height.replace(/px/,'');
+            }
+        }
+    },
+    onWindowResize: function(){
+        this.recalculateLayout();
+        this.scrollBy(0);
+    },
+    onMouseWheel: function(event){
+        if(this.auto_sliding_executer)
+            this.auto_sliding_executer.stop();
+        this.slider.setValueBy(-(event.memo.delta / 20)); //put in math to account for the window height
+        event.stop();
+        return false;
+    },
+    onChange: function(value){
+        this.container.scrollTop = Math.round(value / this.slider.maximum * (this.container.scrollHeight - this.container.offsetHeight));
+        if(this.notification_timeout)
+            window.clearTimeout(this.notificationTimeout);
+        this.notificationTimeout = window.setTimeout(function(){
+            this.notify('change',value);
+        }.bind(this),this.options.notification_timeout_length);
+    },
+    getCurrentMaximumDelta: function(){
+        return this.slider.maximum * (this.container.scrollHeight - this.container.offsetHeight);
+    },
+    getDeltaToElement: function(element){
+        return this.slider.maximum * ((element.positionedOffset().top + (element.getHeight() / 2)) - (this.container.getHeight() / 2));
+    },
+    scrollTo: function(y,animate){
+        var current_maximum_delta = this.getCurrentMaximumDelta();
+        if(y == 'top')
+            y = 0;
+        else if(y == 'bottom')
+            y = current_maximum_delta;
+        else if(typeof(y) != &quot;number&quot;)
+            y = this.getDeltaToElement($(y));
+        if(this.enabled){
+            y = Math.max(0,Math.min(y,current_maximum_delta));
+            if(this.auto_sliding_executer)
+                this.auto_sliding_executer.stop();
+            var target_value = y / current_maximum_delta;
+            var original_slider_value = this.slider.value;
+            var delta = (target_value - original_slider_value) * current_maximum_delta;
+            if(animate){
+                this.auto_sliding_executer = new PeriodicalExecuter(function(){
+                    if(Math.round(this.slider.value * 100) / 100 &lt; Math.round(target_value * 100) / 100 || Math.round(this.slider.value * 100) / 100 &gt; Math.round(target_value * 100) / 100){
+                        this.scrollBy(delta / this.options.scroll_to_steps);
+                    }else{
+                        this.auto_sliding_executer.stop();
+                        this.auto_sliding_executer = null;
+                        if(typeof(animate) == &quot;function&quot;)
+                            animate();
+                    }            
+                }.bind(this),this.options.scroll_to_smoothing);
+            }else
+                this.scrollBy(delta);
+        }else if(typeof(animate) == &quot;function&quot;)
+            animate();
+    },
+    scrollBy: function(y){
+        if(!this.enabled)
+            return false;
+        this.slider.setValueBy(y / this.getCurrentMaximumDelta());
+    }
 });
-Object.Event.extend(Control.ScrollBar);
\ No newline at end of file
+Object.Event.extend(Control.ScrollBar);</diff>
      <filename>src/scrollbar.js</filename>
    </modified>
    <modified>
      <diff>@@ -7,451 +7,453 @@
  * @require prototype.js, effects.js, draggable.js, livepipe.js
  */
 
-if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Control.Selection requires Prototype to be loaded.&quot;;
-if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Control.Selection requires Object.Event to be loaded.&quot;;
+/*global window, document, Prototype, Element, Event, $, $$, $break, Control, Draggable */
+
+if(typeof(Prototype) == &quot;undefined&quot;) {
+    throw &quot;Control.Selection requires Prototype to be loaded.&quot;; }
+if(typeof(Object.Event) == &quot;undefined&quot;) {
+    throw &quot;Control.Selection requires Object.Event to be loaded.&quot;; }
 
 Control.Selection = {
-	options: {
-		resize_layout_timeout: 125,
-		selected: Prototype.emptyFunction,
-		deselected: Prototype.emptyFunction,
-		change: Prototype.emptyFunction,
-		selection_id: 'control_selection',
-		selection_style: {
-			zIndex: 999,
-			cursor: 'default',
-			border: '1px dotted #000'
-		},
-		filter: function(element){
-			return true;
-		},
-		drag_proxy: false,
-		drag_proxy_threshold: 1,
-		drag_proxy_options: {}
-	},
-	selectableElements: [],
-	elements: [],
-	selectableObjects: [],
-	objects: [],
-	active: false,
-	container: false,
-	resizeTimeout: false,
-	load: function(options){
-		Control.Selection.options = Object.extend(Control.Selection.options,options || {});
-		Control.Selection.selection_div = $(document.createElement('div'));
-		Control.Selection.selection_div.id = Control.Selection.options.selection_id;
-		Control.Selection.selection_div.style.display = 'none';
-		Control.Selection.selection_div.setStyle(Control.Selection.options.selection_style);
-		Control.Selection.border_width = parseInt(Control.Selection.selection_div.getStyle('border-top-width')) * 2;
-		Control.Selection.container = Prototype.Browser.IE ? window.container : window;
-		$(document.body).insert(Control.Selection.selection_div);
-		Control.Selection.enable();
-		if(Control.Selection.options.drag_proxy &amp;&amp; typeof(Draggable) != 'undefined')
-			Control.Selection.DragProxy.load();
-		Event.observe(window,'resize',function(){
-			if(Control.Selection.resizeTimeout)
-				window.clearTimeout(Control.Selection.resizeTimeout);
-			Control.Selection.resizeTimeout = window.setTimeout(Control.Selection.recalculateLayout,Control.Selection.options.resize_layout_timeout);
-		});
-		if(Prototype.Browser.IE){
-			var body = $$('body').first();
-			body.observe('mouseleave',Control.Selection.stop);
-			body.observe('mouseup',Control.Selection.stop);
-		}
-	},
-	enable: function(){
-		if(Prototype.Browser.IE){
-			document.onselectstart = function(){
-				return false;
-			}
-		}
-		Event.observe(Control.Selection.container,'mousedown',Control.Selection.start);
-		Event.observe(Control.Selection.container,'mouseup',Control.Selection.stop);
-	},
-	disable: function(){
-		if(Prototype.Browser.IE){
-			document.onselectstart = function(){
-				return true;
-			}
-		}
-		Event.stopObserving(Control.Selection.container,'mousedown',Control.Selection.start);
-		Event.stopObserving(Control.Selection.container,'mouseup',Control.Selection.stop);
-	},
-	recalculateLayout: function(){
-		Control.Selection.selectableElements.each(function(element){
-			var dimensions = element.getDimensions();
-			var offset = element.cumulativeOffset();
-			var scroll_offset = element.cumulativeScrollOffset();
-			if(!element._control_selection)
-				element._control_selection = {};
-			element._control_selection.top = offset[1] - scroll_offset[1];
-			element._control_selection.left = offset[0] - scroll_offset[0];
-			element._control_selection.width = dimensions.width;
-			element._control_selection.height = dimensions.height;
-		});
-	},
-	addSelectable: function(element,object,activation_targets,activation_target_callback){
-		element = $(element);
-		if(activation_targets)
-			activation_targets = activation_targets.each ? activation_targets : [activation_targets];
-		var dimensions = element.getDimensions();
-		var offset = Position.cumulativeOffset(element);
-		element._control_selection = {
-			activation_targets: activation_targets,
-			is_selected: false,
-			top: offset[1],
-			left: offset[0],
-			width: dimensions.width,
-			height: dimensions.height,
-			activationTargetMouseMove: function(){
-				Control.Selection.notify('activationTargetMouseMove',element);
-				if(activation_targets){
-					activation_targets.each(function(activation_target){
-						activation_target.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
-					});
-				}
-				Control.Selection.DragProxy.container.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
-			},
-			activationTargetMouseDown: function(event){
-				if(!Control.Selection.elements.include(element))
-					Control.Selection.select(element);
-				Control.Selection.DragProxy.start(event);
-				Control.Selection.DragProxy.container.hide();
-				if(activation_targets){
-					activation_targets.each(function(activation_target){
-						activation_target.observe('mousemove',element._control_selection.activationTargetMouseMove);
-					});
-				}
-				Control.Selection.DragProxy.container.observe('mousemove',element._control_selection.activationTargetMouseMove);
-			},
-			activationTargetClick: function(){
-				Control.Selection.select(element);
-				if(typeof(activation_target_callback) == &quot;function&quot;)
-					activation_target_callback();
-				if(activation_targets){
-					activation_targets.each(function(activation_target){
-						activation_target.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
-					});
-				}
-				Control.Selection.DragProxy.container.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
-			}
-		};
-		element.onselectstart = function(){
-			return false;
-		};
-		element.unselectable = 'on';
-		element.style.MozUserSelect = 'none';
-		if(activation_targets){
-			activation_targets.each(function(activation_target){
-				activation_target.observe('mousedown',element._control_selection.activationTargetMouseDown);
-				activation_target.observe('click',element._control_selection.activationTargetClick);
-			});
-		}
-		Control.Selection.selectableElements.push(element);
-		Control.Selection.selectableObjects.push(object);
-	},
-	removeSelectable: function(element){
-		element = $(element);
-		if(element._control_selection.activation_targets){
-			element._control_selection.activation_targets.each(function(activation_target){
-				activation_target.stopObserving('mousedown',element._control_selection.activationTargetMouseDown);
-			});
-			element._control_selection.activation_targets.each(function(activation_target){
-				activation_target.stopObserving('click',element._control_selection.activationTargetClick);
-			});
-		}
-		element._control_selection = null;
-		element.onselectstart = function() {
-			return true;
-		};
-		element.unselectable = 'off';
-		element.style.MozUserSelect = '';
-		var position = 0;
-		Control.Selection.selectableElements.each(function(selectable_element,i){
-			if(selectable_element == element){
-				position = i;
-				throw $break;
-			}
-		});
-		Control.Selection.selectableElements = Control.Selection.selectableElements.without(element);
-		Control.Selection.selectableObjects = Control.Selection.selectableObjects.slice(0,position).concat(Control.Selection.selectableObjects.slice(position + 1))
-	},
-	select: function(selected_elements){
-		if(typeof(selected_elements) == &quot;undefined&quot; || !selected_elements)
-			selected_elements = [];
-		if(!selected_elements.each &amp;&amp; !selected_elements._each)
-			selected_elements = [selected_elements];
-		//comparing the arrays directly wouldn't equate to true in safari so we need to compare each item
-		var selected_items_have_changed = !(Control.Selection.elements.length == selected_elements.length &amp;&amp; Control.Selection.elements.all(function(item,i){
-			return selected_elements[i] == item;
-		}));
-		if(!selected_items_have_changed)
-			return;
-		var selected_objects_indexed_by_element = {};
-		var selected_objects = selected_elements.collect(function(selected_element){
-			var selected_object = Control.Selection.selectableObjects[Control.Selection.selectableElements.indexOf(selected_element)];
-			selected_objects_indexed_by_element[selected_element] = selected_object;
-			return selected_object;
-		});
-		if(Control.Selection.elements.length == 0 &amp;&amp; selected_elements.length != 0){
-			selected_elements.each(function(element){
-				Control.Selection.notify('selected',element,selected_objects_indexed_by_element[element]);
-			});
-		}else{
-			Control.Selection.elements.each(function(element){
-				if(!selected_elements.include(element)){
-					Control.Selection.notify('deselected',element,selected_objects_indexed_by_element[element]);
-				}
-			});
-			selected_elements.each(function(element){
-				if(!Control.Selection.elements.include(element)){
-					Control.Selection.notify('selected',element,selected_objects_indexed_by_element[element]);
-				}
-			});
-		}
-		Control.Selection.elements = selected_elements;
-		Control.Selection.objects = selected_objects;
-		Control.Selection.notify('change',Control.Selection.elements,Control.Selection.objects);
-	},
-	deselect: function(){
-		if(Control.Selection.notify('deselect') === false)
-			return false;
-		Control.Selection.elements.each(function(element){
-			Control.Selection.notify('deselected',element,Control.Selection.selectableObjects[Control.Selection.selectableElements.indexOf(element)]);
-		});
-		Control.Selection.objects = [];
-		Control.Selection.elements = [];
-		Control.Selection.notify('change',Control.Selection.objects,Control.Selection.elements);
-		return true;
-	},
-	//private
-	start: function(event){
-		if(!event.isLeftClick() || Control.Selection.notify('start',event) === false)
-			return false;
-		if(!event.shiftKey &amp;&amp; !event.altKey)
-			Control.Selection.deselect();
-		Event.observe(Control.Selection.container,'mousemove',Control.Selection.onMouseMove);
-		Event.stop(event);
-		return false;
-	},
-	stop: function(){
-		Event.stopObserving(Control.Selection.container,'mousemove',Control.Selection.onMouseMove);
-		Control.Selection.active = false;
-		Control.Selection.selection_div.setStyle({
-			display: 'none',
-			top: null,
-			left: null,
-			width: null,
-			height: null
-		});
-		Control.Selection.start_mouse_coordinates = {};
-		Control.Selection.current_mouse_coordinates = {};
-	},
-	mouseCoordinatesFromEvent: function(event){
-		return {
-			x: Event.pointerX(event),
-			y: Event.pointerY(event)
-		};
-	},
-	onClick: function(event,element,source){
-		var selection = [];
-		if(event.shiftKey){
-			selection = Control.Selection.elements.clone();
-			if(!selection.include(element))
-				selection.push(element);
-		}else if(event.altKey){
-			selection = Control.Selection.elements.clone();
-			if(selection.include(element))
-				selection = selection.without(element);
-		}else{
-			selection = [element];
-		}
-		Control.Selection.select(selection);
-		if(source == 'click')
-			Event.stop(event);
-	},
-	onMouseMove: function(event){
-		if(!Control.Selection.active){
-			Control.Selection.active = true;
-			Control.Selection.start_mouse_coordinates = Control.Selection.mouseCoordinatesFromEvent(event);
-		}else{
-			Control.Selection.current_mouse_coordinates = Control.Selection.mouseCoordinatesFromEvent(event);
-			Control.Selection.drawSelectionDiv();
-			var current_selection = Control.Selection.selectableElements.findAll(function(element){
-				return Control.Selection.options.filter(element) &amp;&amp; Control.Selection.elementWithinSelection(element);
-			});
-			if(event.shiftKey &amp;&amp; !event.altKey){
-				Control.Selection.elements.each(function(element){
-					if(!current_selection.include(element))
-						current_selection.push(element);
-				});
-			}else if(event.altKey &amp;&amp; !event.shiftKey){
-				current_selection = Control.Selection.elements.findAll(function(element){
-					return !current_selection.include(element);
-				});
-			}
-			Control.Selection.select(current_selection);
-		}
-	},
-	drawSelectionDiv: function(){
-		if(Control.Selection.start_mouse_coordinates == Control.Selection.current_mouse_coordinates){
-			Control.Selection.selection_div.style.display = 'none';
-		}else{
-			Control.Selection.viewport = document.viewport.getDimensions();
-			Control.Selection.selection_div.style.position = 'absolute';
-			Control.Selection.current_direction = (Control.Selection.start_mouse_coordinates.y &gt; Control.Selection.current_mouse_coordinates.y ? 'N' : 'S') + (Control.Selection.start_mouse_coordinates.x &lt; Control.Selection.current_mouse_coordinates.x ? 'E' : 'W');
-			Control.Selection.selection_div.setStyle(Control.Selection['dimensionsFor' + Control.Selection.current_direction]());
-			Control.Selection.selection_div.style.display = 'block';
-		}
-	},
-	dimensionsForNW: function(){
-		return {
-			top: (Control.Selection.start_mouse_coordinates.y - (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y)) + 'px',
-			left: (Control.Selection.start_mouse_coordinates.x - (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x)) + 'px',
-			width: (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x) + 'px',
-			height: (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y) + 'px'
-		};
-	},
-	dimensionsForNE: function(){
-		return {
-			top: (Control.Selection.start_mouse_coordinates.y - (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y)) + 'px',
-			left: Control.Selection.start_mouse_coordinates.x + 'px',
-			width: Math.min((Control.Selection.viewport.width - Control.Selection.start_mouse_coordinates.x) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.x - Control.Selection.start_mouse_coordinates.x) + 'px',
-			height: (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y) + 'px'
-		};
-	},
-	dimensionsForSE: function(){
-		return {
-			top: Control.Selection.start_mouse_coordinates.y + 'px',
-			left: Control.Selection.start_mouse_coordinates.x + 'px',
-			width: Math.min((Control.Selection.viewport.width - Control.Selection.start_mouse_coordinates.x) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.x - Control.Selection.start_mouse_coordinates.x) + 'px',
-			height: Math.min((Control.Selection.viewport.height - Control.Selection.start_mouse_coordinates.y) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.y - Control.Selection.start_mouse_coordinates.y) + 'px'
-		};
-	},
-	dimensionsForSW: function(){
-		return {
-			top: Control.Selection.start_mouse_coordinates.y + 'px',
-			left: (Control.Selection.start_mouse_coordinates.x - (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x)) + 'px',
-			width: (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x) + 'px',
-			height: Math.min((Control.Selection.viewport.height - Control.Selection.start_mouse_coordinates.y) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.y - Control.Selection.start_mouse_coordinates.y) + 'px'
-		};
-	},
-	inBoundsForNW: function(element,selection){
-		return (
-			((element.left &gt; selection.left || element.right &gt; selection.left) &amp;&amp; selection.right &gt; element.left) &amp;&amp;
-			((element.top &gt; selection.top || element.bottom &gt; selection.top) &amp;&amp; selection.bottom &gt; element.top)
-		);
-	},
-	inBoundsForNE: function(element,selection){
-		return (
-			((element.left &lt; selection.right || element.left &lt; selection.right) &amp;&amp; selection.left &lt; element.right) &amp;&amp;
-			((element.top &gt; selection.top || element.bottom &gt; selection.top) &amp;&amp; selection.bottom &gt; element.top)
-		);
-	},
-	inBoundsForSE: function(element,selection){
-		return (
-			((element.left &lt; selection.right || element.left &lt; selection.right) &amp;&amp; selection.left &lt; element.right) &amp;&amp;
-			((element.bottom &lt; selection.bottom || element.top &lt; selection.bottom) &amp;&amp; selection.top &lt; element.bottom)
-		);
-	},
-	inBoundsForSW: function(element,selection){
-		return (
-			((element.left &gt; selection.left || element.right &gt; selection.left) &amp;&amp; selection.right &gt; element.left) &amp;&amp;
-			((element.bottom &lt; selection.bottom || element.top &lt; selection.bottom) &amp;&amp; selection.top &lt; element.bottom)
-		);
-	},
-	elementWithinSelection: function(element){
-		if(Control.Selection['inBoundsFor' + Control.Selection.current_direction]({
-			top: element._control_selection.top,
-			left: element._control_selection.left,
-			bottom: element._control_selection.top + element._control_selection.height,
-			right: element._control_selection.left + element._control_selection.width
-		},{
-			top: parseInt(Control.Selection.selection_div.style.top),
-			left: parseInt(Control.Selection.selection_div.style.left),
-			bottom: parseInt(Control.Selection.selection_div.style.top) + parseInt(Control.Selection.selection_div.style.height),
-			right: parseInt(Control.Selection.selection_div.style.left) + parseInt(Control.Selection.selection_div.style.width)
-		})){
-			element._control_selection.is_selected = true;
-			return true;
-		}else{
-			element._control_selection.is_selected = false;
-			return false;
-		}
-	},
-	DragProxy: {
-	    active: false,
-		xorigin: 0,
-		yorigin: 0,
-		load: function(){
-			Control.Selection.DragProxy.container = $(document.createElement('div'));
-			Control.Selection.DragProxy.container.id = 'control_selection_drag_proxy';
-			Control.Selection.DragProxy.container.setStyle({
-				position: 'absolute',
-				top: '1px',
-				left: '1px',
-				zIndex: 99999
-			});
-			Control.Selection.DragProxy.container.hide();
-			document.body.appendChild(Control.Selection.DragProxy.container);
-			Control.Selection.observe('selected',Control.Selection.DragProxy.selected);
-			Control.Selection.observe('deselected',Control.Selection.DragProxy.deselected);
-		},
-		start: function(event){            
-			if(event.isRightClick()){
-				Control.Selection.DragProxy.container.hide();
-				return;
-			}		    
-			if(Control.Selection.DragProxy.xorigin == Event.pointerX(event) &amp;&amp; Control.Selection.DragProxy.yorigin == Event.pointerY(event))
-				return;    		
-		    Control.Selection.DragProxy.active = true;
-			Control.Selection.DragProxy.container.setStyle({
-				position: 'absolute',
-				top: Event.pointerY(event) + 'px',
-				left: Event.pointerX(event) + 'px'
-			});			
-			Control.Selection.DragProxy.container.observe('mouseup',Control.Selection.DragProxy.onMouseUp);			
-			Control.Selection.DragProxy.container.show();
-			Control.Selection.DragProxy.container._draggable = new Draggable(Control.Selection.DragProxy.container,Object.extend({
-				onEnd: Control.Selection.DragProxy.stop
-			},Control.Selection.options.drag_proxy_options));
-			Control.Selection.DragProxy.container._draggable.eventMouseDown(event);			
-			Control.Selection.DragProxy.notify('start',Control.Selection.DragProxy.container,Control.Selection.elements);
-		},
-		stop: function(){
-			window.setTimeout(function(){
-				Control.Selection.DragProxy.active = false;
-				Control.Selection.DragProxy.container.hide();
-    			if(Control.Selection.DragProxy.container._draggable){
-					Control.Selection.DragProxy.container._draggable.destroy();
-					Control.Selection.DragProxy.container._draggable = null;
-    			}
-    			Control.Selection.DragProxy.notify('stop');
-		    },1);
-		},
-		onClick: function(event){
-			Control.Selection.DragProxy.xorigin = Event.pointerX(event);
-			Control.Selection.DragProxy.yorigin = Event.pointerY(event);
-			if(event.isRightClick())
-				Control.Selection.DragProxy.container.hide();
-			if(Control.Selection.elements.length &gt;= Control.Selection.options.drag_proxy_threshold &amp;&amp; !(event.shiftKey || event.altKey) &amp;&amp; (Control.Selection.DragProxy.xorigin != Event.pointerX(event) || Control.Selection.DragProxy.yorigin != Event.pointerY(event))){
-				Control.Selection.DragProxy.start(event);
-				Event.stop(event);
-			}
-		},
-		onMouseUp: function(event){
-			Control.Selection.DragProxy.stop();
-			Control.Selection.DragProxy.container.stopObserving('mouseup',Control.Selection.DragProxy.onMouseUp);
-		},
-		selected: function(element){
-			element.observe('mousedown',Control.Selection.DragProxy.onClick);
-		},
-		deselected: function(element){
-			element.stopObserving('mousedown',Control.Selection.DragProxy.onClick);
-		}
-	}
+    options: {
+        resize_layout_timeout: 125,
+        selected: Prototype.emptyFunction,
+        deselected: Prototype.emptyFunction,
+        change: Prototype.emptyFunction,
+        selection_id: 'control_selection',
+        selection_style: {
+            zIndex: 999,
+            cursor: 'default',
+            border: '1px dotted #000'
+        },
+        filter: function(element){
+            return true;
+        },
+        drag_proxy: false,
+        drag_proxy_threshold: 1,
+        drag_proxy_options: {}
+    },
+    selectableElements: [],
+    elements: [],
+    selectableObjects: [],
+    objects: [],
+    active: false,
+    container: false,
+    resizeTimeout: false,
+    load: function(options){
+        Control.Selection.options = Object.extend(Control.Selection.options,options || {});
+        Control.Selection.selection_div = $(document.createElement('div'));
+        Control.Selection.selection_div.id = Control.Selection.options.selection_id;
+        Control.Selection.selection_div.style.display = 'none';
+        Control.Selection.selection_div.setStyle(Control.Selection.options.selection_style);
+        Control.Selection.border_width = parseInt(Control.Selection.selection_div.getStyle('border-top-width'), 10) * 2;
+        Control.Selection.container = Prototype.Browser.IE ? window.container : window;
+        $(document.body).insert(Control.Selection.selection_div);
+        Control.Selection.enable();
+        if(Control.Selection.options.drag_proxy &amp;&amp; typeof(Draggable) != 'undefined') {
+            Control.Selection.DragProxy.load(); }
+        Event.observe(window,'resize',function(){
+            if(Control.Selection.resizeTimeout) {
+                window.clearTimeout(Control.Selection.resizeTimeout); }
+            Control.Selection.resizeTimeout = window.setTimeout(Control.Selection.recalculateLayout,Control.Selection.options.resize_layout_timeout);
+        });
+        if(Prototype.Browser.IE){
+            var body = $$('body').first();
+            body.observe('mouseleave',Control.Selection.stop);
+            body.observe('mouseup',Control.Selection.stop);
+        }
+    },
+    enable: function(){
+        if(Prototype.Browser.IE){
+            document.onselectstart = function(){
+                return false;
+            };
+        }
+        Event.observe(Control.Selection.container,'mousedown',Control.Selection.start);
+        Event.observe(Control.Selection.container,'mouseup',Control.Selection.stop);
+    },
+    disable: function(){
+        if(Prototype.Browser.IE){
+            document.onselectstart = function(){
+                return true;
+            };
+        }
+        Event.stopObserving(Control.Selection.container,'mousedown',Control.Selection.start);
+        Event.stopObserving(Control.Selection.container,'mouseup',Control.Selection.stop);
+    },
+    recalculateLayout: function(){
+        Control.Selection.selectableElements.each(function(element){
+            var dimensions = element.getDimensions();
+            var offset = element.cumulativeOffset();
+            var scroll_offset = element.cumulativeScrollOffset();
+            if(!element._control_selection) {
+                element._control_selection = {}; }
+            element._control_selection.top = offset[1] - scroll_offset[1];
+            element._control_selection.left = offset[0] - scroll_offset[0];
+            element._control_selection.width = dimensions.width;
+            element._control_selection.height = dimensions.height;
+        });
+    },
+    addSelectable: function(element,object,activation_targets,activation_target_callback){
+        element = $(element);
+        if(activation_targets) {
+            activation_targets = activation_targets.each ? activation_targets : [activation_targets]; }
+        var dimensions = element.getDimensions();
+        var offset = Element.cumulativeOffset(element);
+        element._control_selection = {
+            activation_targets: activation_targets,
+            is_selected: false,
+            top: offset[1],
+            left: offset[0],
+            width: dimensions.width,
+            height: dimensions.height,
+            activationTargetMouseMove: function(){
+                Control.Selection.notify('activationTargetMouseMove',element);
+                if(activation_targets){
+                    activation_targets.each(function(activation_target){
+                        activation_target.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
+                    });
+                }
+                Control.Selection.DragProxy.container.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
+            },
+            activationTargetMouseDown: function(event){
+                if(!Control.Selection.elements.include(element)) {
+                    Control.Selection.select(element); }
+                Control.Selection.DragProxy.start(event);
+                Control.Selection.DragProxy.container.hide();
+                if(activation_targets){
+                    activation_targets.each(function(activation_target){
+                        activation_target.observe('mousemove',element._control_selection.activationTargetMouseMove);
+                    });
+                }
+                Control.Selection.DragProxy.container.observe('mousemove',element._control_selection.activationTargetMouseMove);
+            },
+            activationTargetClick: function(){
+                Control.Selection.select(element);
+                if(typeof(activation_target_callback) == &quot;function&quot;) {
+                    activation_target_callback(); }
+                if(activation_targets){
+                    activation_targets.each(function(activation_target){
+                        activation_target.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
+                    });
+                }
+                Control.Selection.DragProxy.container.stopObserving('mousemove',element._control_selection.activationTargetMouseMove);
+            }
+        };
+        element.onselectstart = function(){
+            return false;
+        };
+        element.unselectable = 'on';
+        element.style.MozUserSelect = 'none';
+        if(activation_targets){
+            activation_targets.each(function(activation_target){
+                activation_target.observe('mousedown',element._control_selection.activationTargetMouseDown);
+                activation_target.observe('click',element._control_selection.activationTargetClick);
+            });
+        }
+        Control.Selection.selectableElements.push(element);
+        Control.Selection.selectableObjects.push(object);
+    },
+    removeSelectable: function(element){
+        element = $(element);
+        if(element._control_selection.activation_targets){
+            element._control_selection.activation_targets.each(function(activation_target){
+                activation_target.stopObserving('mousedown',element._control_selection.activationTargetMouseDown);
+            });
+            element._control_selection.activation_targets.each(function(activation_target){
+                activation_target.stopObserving('click',element._control_selection.activationTargetClick);
+            });
+        }
+        element._control_selection = null;
+        element.onselectstart = function() {
+            return true;
+        };
+        element.unselectable = 'off';
+        element.style.MozUserSelect = '';
+        var position = 0;
+        Control.Selection.selectableElements.each(function(selectable_element,i){
+            if(selectable_element == element){
+                position = i;
+                throw $break;
+            }
+        });
+        Control.Selection.selectableElements = Control.Selection.selectableElements.without(element);
+        Control.Selection.selectableObjects = Control.Selection.selectableObjects.slice(0,position).concat(Control.Selection.selectableObjects.slice(position + 1));
+    },
+    select: function(selected_elements){
+        if(typeof(selected_elements) == &quot;undefined&quot; || !selected_elements) {
+            selected_elements = []; }
+        if(!selected_elements.each &amp;&amp; !selected_elements._each) {
+            selected_elements = [selected_elements]; }
+        //comparing the arrays directly wouldn't equate to true in safari so we need to compare each item
+        var selected_items_have_changed = !(Control.Selection.elements.length == selected_elements.length &amp;&amp; Control.Selection.elements.all(function(item,i){
+            return selected_elements[i] == item;
+        }));
+        if(!selected_items_have_changed) {
+            return; }
+        var selected_objects_indexed_by_element = {};
+        var selected_objects = selected_elements.collect(function(selected_element){
+            var selected_object = Control.Selection.selectableObjects[Control.Selection.selectableElements.indexOf(selected_element)];
+            selected_objects_indexed_by_element[selected_element] = selected_object;
+            return selected_object;
+        });
+        if(Control.Selection.elements.length === 0 &amp;&amp; selected_elements.length !== 0){
+            selected_elements.each(function(element){
+                Control.Selection.notify('selected',element,selected_objects_indexed_by_element[element]);
+            });
+        }else{
+            Control.Selection.elements.each(function(element){
+                if(!selected_elements.include(element)){
+                    Control.Selection.notify('deselected',element,selected_objects_indexed_by_element[element]);
+                }
+            });
+            selected_elements.each(function(element){
+                if(!Control.Selection.elements.include(element)){
+                    Control.Selection.notify('selected',element,selected_objects_indexed_by_element[element]);
+                }
+            });
+        }
+        Control.Selection.elements = selected_elements;
+        Control.Selection.objects = selected_objects;
+        Control.Selection.notify('change',Control.Selection.elements,Control.Selection.objects);
+    },
+    deselect: function(){
+        if(Control.Selection.notify('deselect') === false) {
+            return false; }
+        Control.Selection.elements.each(function(element){
+            Control.Selection.notify('deselected',element,Control.Selection.selectableObjects[Control.Selection.selectableElements.indexOf(element)]);
+        });
+        Control.Selection.objects = [];
+        Control.Selection.elements = [];
+        Control.Selection.notify('change',Control.Selection.objects,Control.Selection.elements);
+        return true;
+    },
+    //private
+    start: function(event){
+        if(!event.isLeftClick() || Control.Selection.notify('start',event) === false) {
+            return false; }
+        if(!event.shiftKey &amp;&amp; !event.altKey) {
+            Control.Selection.deselect(); }
+        Event.observe(Control.Selection.container,'mousemove',Control.Selection.onMouseMove);
+        Event.stop(event);
+        return false;
+    },
+    stop: function(){
+        Event.stopObserving(Control.Selection.container,'mousemove',Control.Selection.onMouseMove);
+        Control.Selection.active = false;
+        Control.Selection.selection_div.setStyle({
+            display: 'none',
+            top: null,
+            left: null,
+            width: null,
+            height: null
+        });
+        Control.Selection.start_mouse_coordinates = {};
+        Control.Selection.current_mouse_coordinates = {};
+    },
+    mouseCoordinatesFromEvent: function(event){
+        return {
+            x: Event.pointerX(event),
+            y: Event.pointerY(event)
+        };
+    },
+    onClick: function(event,element,source){
+        var selection = [];
+        if(event.shiftKey){
+            selection = Control.Selection.elements.clone();
+            if(!selection.include(element)) {
+                selection.push(element); }
+        }else if(event.altKey){
+            selection = Control.Selection.elements.clone();
+            if(selection.include(element)) {
+                selection = selection.without(element); }
+        }else{
+            selection = [element];
+        }
+        Control.Selection.select(selection);
+        if(source == 'click') {
+            Event.stop(event); }
+    },
+    onMouseMove: function(event){
+        if(!Control.Selection.active){
+            Control.Selection.active = true;
+            Control.Selection.start_mouse_coordinates = Control.Selection.mouseCoordinatesFromEvent(event);
+        }else{
+            Control.Selection.current_mouse_coordinates = Control.Selection.mouseCoordinatesFromEvent(event);
+            Control.Selection.drawSelectionDiv();
+            var current_selection = Control.Selection.selectableElements.findAll(function(element){
+                return Control.Selection.options.filter(element) &amp;&amp; Control.Selection.elementWithinSelection(element);
+            });
+            if(event.shiftKey &amp;&amp; !event.altKey){
+                Control.Selection.elements.each(function(element){
+                    if(!current_selection.include(element)) {
+                        current_selection.push(element); }
+                });
+            }else if(event.altKey &amp;&amp; !event.shiftKey){
+                current_selection = Control.Selection.elements.findAll(function(element){
+                    return !current_selection.include(element);
+                });
+            }
+            Control.Selection.select(current_selection);
+        }
+    },
+    drawSelectionDiv: function(){
+        if(Control.Selection.start_mouse_coordinates == Control.Selection.current_mouse_coordinates){
+            Control.Selection.selection_div.style.display = 'none';
+        }else{
+            Control.Selection.viewport = document.viewport.getDimensions();
+            Control.Selection.selection_div.style.position = 'absolute';
+            Control.Selection.current_direction = (Control.Selection.start_mouse_coordinates.y &gt; Control.Selection.current_mouse_coordinates.y ? 'N' : 'S') + (Control.Selection.start_mouse_coordinates.x &lt; Control.Selection.current_mouse_coordinates.x ? 'E' : 'W');
+            Control.Selection.selection_div.setStyle(Control.Selection['dimensionsFor' + Control.Selection.current_direction]());
+            Control.Selection.selection_div.style.display = 'block';
+        }
+    },
+    dimensionsForNW: function(){
+        return {
+            top: (Control.Selection.start_mouse_coordinates.y - (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y)) + 'px',
+            left: (Control.Selection.start_mouse_coordinates.x - (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x)) + 'px',
+            width: (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x) + 'px',
+            height: (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y) + 'px'
+        };
+    },
+    dimensionsForNE: function(){
+        return {
+            top: (Control.Selection.start_mouse_coordinates.y - (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y)) + 'px',
+            left: Control.Selection.start_mouse_coordinates.x + 'px',
+            width: Math.min((Control.Selection.viewport.width - Control.Selection.start_mouse_coordinates.x) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.x - Control.Selection.start_mouse_coordinates.x) + 'px',
+            height: (Control.Selection.start_mouse_coordinates.y - Control.Selection.current_mouse_coordinates.y) + 'px'
+        };
+    },
+    dimensionsForSE: function(){
+        return {
+            top: Control.Selection.start_mouse_coordinates.y + 'px',
+            left: Control.Selection.start_mouse_coordinates.x + 'px',
+            width: Math.min((Control.Selection.viewport.width - Control.Selection.start_mouse_coordinates.x) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.x - Control.Selection.start_mouse_coordinates.x) + 'px',
+            height: Math.min((Control.Selection.viewport.height - Control.Selection.start_mouse_coordinates.y) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.y - Control.Selection.start_mouse_coordinates.y) + 'px'
+        };
+    },
+    dimensionsForSW: function(){
+        return {
+            top: Control.Selection.start_mouse_coordinates.y + 'px',
+            left: (Control.Selection.start_mouse_coordinates.x - (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x)) + 'px',
+            width: (Control.Selection.start_mouse_coordinates.x - Control.Selection.current_mouse_coordinates.x) + 'px',
+            height: Math.min((Control.Selection.viewport.height - Control.Selection.start_mouse_coordinates.y) - Control.Selection.border_width,Control.Selection.current_mouse_coordinates.y - Control.Selection.start_mouse_coordinates.y) + 'px'
+        };
+    },
+    inBoundsForNW: function(element,selection){
+        return (
+            ((element.left &gt; selection.left || element.right &gt; selection.left) &amp;&amp; selection.right &gt; element.left) &amp;&amp;
+            ((element.top &gt; selection.top || element.bottom &gt; selection.top) &amp;&amp; selection.bottom &gt; element.top)
+        );
+    },
+    inBoundsForNE: function(element,selection){
+        return (
+            ((element.left &lt; selection.right || element.left &lt; selection.right) &amp;&amp; selection.left &lt; element.right) &amp;&amp;
+            ((element.top &gt; selection.top || element.bottom &gt; selection.top) &amp;&amp; selection.bottom &gt; element.top)
+        );
+    },
+    inBoundsForSE: function(element,selection){
+        return (
+            ((element.left &lt; selection.right || element.left &lt; selection.right) &amp;&amp; selection.left &lt; element.right) &amp;&amp;
+            ((element.bottom &lt; selection.bottom || element.top &lt; selection.bottom) &amp;&amp; selection.top &lt; element.bottom)
+        );
+    },
+    inBoundsForSW: function(element,selection){
+        return (
+            ((element.left &gt; selection.left || element.right &gt; selection.left) &amp;&amp; selection.right &gt; element.left) &amp;&amp;
+            ((element.bottom &lt; selection.bottom || element.top &lt; selection.bottom) &amp;&amp; selection.top &lt; element.bottom)
+        );
+    },
+    elementWithinSelection: function(element){
+        if(Control.Selection['inBoundsFor' + Control.Selection.current_direction]({
+            top: element._control_selection.top,
+            left: element._control_selection.left,
+            bottom: element._control_selection.top + element._control_selection.height,
+            right: element._control_selection.left + element._control_selection.width
+        },{
+            top: parseInt(Control.Selection.selection_div.style.top, 10),
+            left: parseInt(Control.Selection.selection_div.style.left, 10),
+            bottom: parseInt(Control.Selection.selection_div.style.top, 10) + parseInt(Control.Selection.selection_div.style.height, 10),
+            right: parseInt(Control.Selection.selection_div.style.left, 10) + parseInt(Control.Selection.selection_div.style.width, 10)
+        })){
+            element._control_selection.is_selected = true;
+            return true;
+        }else{
+            element._control_selection.is_selected = false;
+            return false;
+        }
+    },
+    DragProxy: {
+        active: false,
+        xorigin: 0,
+        yorigin: 0,
+        load: function(){
+            Control.Selection.DragProxy.container = $(document.createElement('div'));
+            Control.Selection.DragProxy.container.id = 'control_selection_drag_proxy';
+            Control.Selection.DragProxy.container.setStyle({
+                position: 'absolute',
+                top: '1px',
+                left: '1px',
+                zIndex: 99999
+            });
+            Control.Selection.DragProxy.container.hide();
+            document.body.appendChild(Control.Selection.DragProxy.container);
+            Control.Selection.observe('selected',Control.Selection.DragProxy.selected);
+            Control.Selection.observe('deselected',Control.Selection.DragProxy.deselected);
+        },
+        start: function(event){            
+            if(event.isRightClick()){
+                Control.Selection.DragProxy.container.hide();
+                return;
+            }            
+            if(Control.Selection.DragProxy.xorigin == Event.pointerX(event) &amp;&amp; Control.Selection.DragProxy.yorigin == Event.pointerY(event)) {
+                return; }
+            Control.Selection.DragProxy.active = true;
+            Control.Selection.DragProxy.container.setStyle({
+                position: 'absolute',
+                top: Event.pointerY(event) + 'px',
+                left: Event.pointerX(event) + 'px'
+            });            
+            Control.Selection.DragProxy.container.observe('mouseup',Control.Selection.DragProxy.onMouseUp);            
+            Control.Selection.DragProxy.container.show();
+            Control.Selection.DragProxy.container._draggable = new Draggable(Control.Selection.DragProxy.container,Object.extend({
+                onEnd: Control.Selection.DragProxy.stop
+            },Control.Selection.options.drag_proxy_options));
+            Control.Selection.DragProxy.container._draggable.eventMouseDown(event);            
+            Control.Selection.DragProxy.notify('start',Control.Selection.DragProxy.container,Control.Selection.elements);
+        },
+        stop: function(){
+            window.setTimeout(function(){
+                Control.Selection.DragProxy.active = false;
+                Control.Selection.DragProxy.container.hide();
+                if(Control.Selection.DragProxy.container._draggable){
+                    Control.Selection.DragProxy.container._draggable.destroy();
+                    Control.Selection.DragProxy.container._draggable = null;
+                }
+                Control.Selection.DragProxy.notify('stop');
+            },1);
+        },
+        onClick: function(event){
+            Control.Selection.DragProxy.xorigin = Event.pointerX(event);
+            Control.Selection.DragProxy.yorigin = Event.pointerY(event);
+            if(event.isRightClick()) {
+                Control.Selection.DragProxy.container.hide(); }
+            if(Control.Selection.elements.length &gt;= Control.Selection.options.drag_proxy_threshold &amp;&amp; !(event.shiftKey || event.altKey) &amp;&amp; (Control.Selection.DragProxy.xorigin != Event.pointerX(event) || Control.Selection.DragProxy.yorigin != Event.pointerY(event))){
+                Control.Selection.DragProxy.start(event);
+                Event.stop(event);
+            }
+        },
+        onMouseUp: function(event){
+            Control.Selection.DragProxy.stop();
+            Control.Selection.DragProxy.container.stopObserving('mouseup',Control.Selection.DragProxy.onMouseUp);
+        },
+        selected: function(element){
+            element.observe('mousedown',Control.Selection.DragProxy.onClick);
+        },
+        deselected: function(element){
+            element.stopObserving('mousedown',Control.Selection.DragProxy.onClick);
+        }
+    }
 };
 Object.Event.extend(Control.Selection);
-Object.Event.extend(Control.Selection.DragProxy);
\ No newline at end of file
+Object.Event.extend(Control.Selection.DragProxy);</diff>
      <filename>src/selection.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,146 +10,146 @@
 /*global Prototype, Class, Option, $, $A, Control, $break,  */
 
 if(typeof(Prototype) == &quot;undefined&quot;) {
-	throw &quot;Control.SelectMultiple requires Prototype to be loaded.&quot;; }
+    throw &quot;Control.SelectMultiple requires Prototype to be loaded.&quot;; }
 if(typeof(Object.Event) == &quot;undefined&quot;) {
-	throw &quot;Control.SelectMultiple requires Object.Event to be loaded.&quot;; }
+    throw &quot;Control.SelectMultiple requires Object.Event to be loaded.&quot;; }
 
 Control.SelectMultiple = Class.create({
-	select: false,
-	container: false,
-	numberOfCheckedBoxes: 0,
-	checkboxes: [],
-	hasExtraOption: false,
-	initialize: function(select,container,options){
-		this.options = {
-			checkboxSelector: 'input[type=checkbox]',
-			nameSelector: 'span.name',
-			labelSeparator: ', ',
-			valueSeparator: ',',
-			afterChange: Prototype.emptyFunction,
-			overflowString: function(str){
-				return str.truncate();
-			},
-			overflowLength: 30
-		};
-		Object.extend(this.options,options || {});
-		this.select = $(select);
-		this.container =  $(container);
-		this.checkboxes = (typeof(this.options.checkboxSelector) == 'function') ? 
+    select: false,
+    container: false,
+    numberOfCheckedBoxes: 0,
+    checkboxes: [],
+    hasExtraOption: false,
+    initialize: function(select,container,options){
+        this.options = {
+            checkboxSelector: 'input[type=checkbox]',
+            nameSelector: 'span.name',
+            labelSeparator: ', ',
+            valueSeparator: ',',
+            afterChange: Prototype.emptyFunction,
+            overflowString: function(str){
+                return str.truncate();
+            },
+            overflowLength: 30
+        };
+        Object.extend(this.options,options || {});
+        this.select = $(select);
+        this.container =  $(container);
+        this.checkboxes = (typeof(this.options.checkboxSelector) == 'function') ? 
             this.options.checkboxSelector.bind(this)() : 
             this.container.getElementsBySelector(this.options.checkboxSelector);
-		var value_was_set = false;
-		if(this.options.value){
-			value_was_set = true;
-			this.setValue(this.options.value);
-			delete this.options.value;
-		}
-		this.hasExtraOption = false;
-		this.checkboxes.each(function(checkbox){
-		 checkbox.observe('click',this.checkboxOnClick.bind(this,checkbox));
-		}.bind(this));
-		this.select.observe('change',this.selectOnChange.bind(this));
-		this.countAndCheckCheckBoxes();
-		if(!value_was_set) {
-		 this.scanCheckBoxes(); }
-		this.notify('afterChange',this.select.options[this.select.options.selectedIndex].value);
-	},
-	countAndCheckCheckBoxes: function(){
-		this.numberOfCheckedBoxes = this.checkboxes.inject(0,function(number,checkbox){
-			checkbox.checked = (this.select.options[this.select.options.selectedIndex].value == checkbox.value);
-			var value_string = this.select.options[this.select.options.selectedIndex].value;
+        var value_was_set = false;
+        if(this.options.value){
+            value_was_set = true;
+            this.setValue(this.options.value);
+            delete this.options.value;
+        }
+        this.hasExtraOption = false;
+        this.checkboxes.each(function(checkbox){
+         checkbox.observe('click',this.checkboxOnClick.bind(this,checkbox));
+        }.bind(this));
+        this.select.observe('change',this.selectOnChange.bind(this));
+        this.countAndCheckCheckBoxes();
+        if(!value_was_set) {
+         this.scanCheckBoxes(); }
+        this.notify('afterChange',this.select.options[this.select.options.selectedIndex].value);
+    },
+    countAndCheckCheckBoxes: function(){
+        this.numberOfCheckedBoxes = this.checkboxes.inject(0,function(number,checkbox){
+            checkbox.checked = (this.select.options[this.select.options.selectedIndex].value == checkbox.value);
+            var value_string = this.select.options[this.select.options.selectedIndex].value;
             var value_collection = $A(value_string.split ? value_string.split(this.options.valueSeparator) : value_string);
-			var should_check = value_collection.any(function(value) {
-				if (!should_check &amp;&amp; checkbox.value == value) {
-					return true; }
-			}.bind(this));
-			checkbox.checked = should_check;
-			if(checkbox.checked) {
-				++number; }
-			return number;
-		}.bind(this));
-	},
-	setValue: function(value_string){
-		this.numberOfCheckedBoxes = 0;
+            var should_check = value_collection.any(function(value) {
+                if (!should_check &amp;&amp; checkbox.value == value) {
+                    return true; }
+            }.bind(this));
+            checkbox.checked = should_check;
+            if(checkbox.checked) {
+                ++number; }
+            return number;
+        }.bind(this));
+    },
+    setValue: function(value_string){
+        this.numberOfCheckedBoxes = 0;
         var value_collection = $A(value_string.split ? value_string.split(this.options.valueSeparator) : value_string);
-		this.checkboxes.each(function(checkbox){
-			checkbox.checked = false;
-			value_collection.each(function(value){
-				if(checkbox.value == value){
-					++this.numberOfCheckedBoxes;
-					checkbox.checked = true;
-				}
-			}.bind(this));
-		}.bind(this));
-		this.scanCheckBoxes();
-	},
-	selectOnChange: function(){
-		this.removeExtraOption();
-		this.countAndCheckCheckBoxes();
-		this.notify('afterChange',this.select.options[this.select.options.selectedIndex].value);
-	},
-	checkboxOnClick: function(checkbox){
+        this.checkboxes.each(function(checkbox){
+            checkbox.checked = false;
+            value_collection.each(function(value){
+                if(checkbox.value == value){
+                    ++this.numberOfCheckedBoxes;
+                    checkbox.checked = true;
+                }
+            }.bind(this));
+        }.bind(this));
+        this.scanCheckBoxes();
+    },
+    selectOnChange: function(){
+        this.removeExtraOption();
+        this.countAndCheckCheckBoxes();
+        this.notify('afterChange',this.select.options[this.select.options.selectedIndex].value);
+    },
+    checkboxOnClick: function(checkbox){
         this.numberOfCheckedBoxes = this.checkboxes.findAll(function (c) { 
             return c.checked; 
         }).length;
-		this.scanCheckBoxes();
+        this.scanCheckBoxes();
         this.notify('afterChange', this.numberOfCheckedBoxes === 0 ? &quot;&quot; :
             this.select.options[this.select.options.selectedIndex].value);
-	},
-	scanCheckBoxes: function(){
-		switch(this.numberOfCheckedBoxes){
-			case 1:
-				this.checkboxes.each(function(checkbox){
-					if(checkbox.checked){
-						$A(this.select.options).each(function(option,i){
-							if(option.value == checkbox.value){
-								this.select.options.selectedIndex = i;
-								throw $break;
-							}
-						}.bind(this));
-						throw $break;
-					}
-				}.bind(this));
+    },
+    scanCheckBoxes: function(){
+        switch(this.numberOfCheckedBoxes){
+            case 1:
+                this.checkboxes.each(function(checkbox){
+                    if(checkbox.checked){
+                        $A(this.select.options).each(function(option,i){
+                            if(option.value == checkbox.value){
+                                this.select.options.selectedIndex = i;
+                                throw $break;
+                            }
+                        }.bind(this));
+                        throw $break;
+                    }
+                }.bind(this));
                 break;
-			case 0:
-				this.removeExtraOption();
-				break;
-			default:
-				this.addExtraOption();
-				break;
-		}
-	},
-	getLabelForExtraOption: function(){
-		var label = (typeof(this.options.nameSelector) == 'function' ? 
+            case 0:
+                this.removeExtraOption();
+                break;
+            default:
+                this.addExtraOption();
+                break;
+        }
+    },
+    getLabelForExtraOption: function(){
+        var label = (typeof(this.options.nameSelector) == 'function' ? 
             this.options.nameSelector.bind(this)() : 
             this.container.getElementsBySelector(this.options.nameSelector).inject([],function(labels,name_element,i){
-				if(this.checkboxes[i].checked) {
-					labels.push(name_element.innerHTML); }
-				return labels;
-			}.bind(this))
-		).join(this.options.labelSeparator);
+                if(this.checkboxes[i].checked) {
+                    labels.push(name_element.innerHTML); }
+                return labels;
+            }.bind(this))
+        ).join(this.options.labelSeparator);
         return (label.length &gt;= this.options.overflowLength &amp;&amp; this.options.overflowLength &gt; 0) ? 
             (typeof(this.options.overflowString) == 'function' ? this.options.overflowString(label) : this.options.overflowString) : 
             label;
-	},
-	getValueForExtraOption: function(){
-		return this.checkboxes.inject([],function(values,checkbox){
-			if(checkbox.checked) {
-				values.push(checkbox.value); }
-			return values;
-		}).join(this.options.valueSeparator);
-	},
-	addExtraOption: function(){
-		this.removeExtraOption();
-		this.hasExtraOption = true;
-		this.select.options[this.select.options.length] = new Option(this.getLabelForExtraOption(),this.getValueForExtraOption());
-		this.select.options.selectedIndex = this.select.options.length - 1;
-	},
-	removeExtraOption: function(){
-		if(this.hasExtraOption){
-			this.select.remove(this.select.options.length - 1);
-			this.hasExtraOption = false;
-		}
-	}
+    },
+    getValueForExtraOption: function(){
+        return this.checkboxes.inject([],function(values,checkbox){
+            if(checkbox.checked) {
+                values.push(checkbox.value); }
+            return values;
+        }).join(this.options.valueSeparator);
+    },
+    addExtraOption: function(){
+        this.removeExtraOption();
+        this.hasExtraOption = true;
+        this.select.options[this.select.options.length] = new Option(this.getLabelForExtraOption(),this.getValueForExtraOption());
+        this.select.options.selectedIndex = this.select.options.length - 1;
+    },
+    removeExtraOption: function(){
+        if(this.hasExtraOption){
+            this.select.remove(this.select.options.length - 1);
+            this.hasExtraOption = false;
+        }
+    }
 });
 Object.Event.extend(Control.SelectMultiple);</diff>
      <filename>src/selectmultiple.js</filename>
    </modified>
    <modified>
      <diff>@@ -7,141 +7,143 @@
  * @require prototype.js, livepipe.js
  */
 
-if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Control.Tabs requires Prototype to be loaded.&quot;;
-if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Control.Tabs requires Object.Event to be loaded.&quot;;
+/*global window, document, Prototype, $, $A, $H, $break, Class, Element, Event, Control */
+
+if(typeof(Prototype) == &quot;undefined&quot;) {
+    throw &quot;Control.Tabs requires Prototype to be loaded.&quot;; }
+if(typeof(Object.Event) == &quot;undefined&quot;) {
+    throw &quot;Control.Tabs requires Object.Event to be loaded.&quot;; }
 
 Control.Tabs = Class.create({
-	initialize: function(tab_list_container,options){
-		if(!$(tab_list_container))
-			throw &quot;Control.Tabs could not find the element: &quot; + tab_list_container;
-		this.activeContainer = false;
-		this.activeLink = false;
-		this.containers = $H({});
-		this.links = [];
-		Control.Tabs.instances.push(this);
-		this.options = {
-			beforeChange: Prototype.emptyFunction,
-			afterChange: Prototype.emptyFunction,
-			hover: false,
-			linkSelector: 'li a',
-			setClassOnContainer: false,
-			activeClassName: 'active',
-			defaultTab: 'first',
-			autoLinkExternal: true,
-			targetRegExp: /#(.+)$/,
-			showFunction: Element.show,
-			hideFunction: Element.hide
-		};
-		Object.extend(this.options,options || {});
-		(typeof(this.options.linkSelector == 'string')
-			? $(tab_list_container).select(this.options.linkSelector)
-			: this.options.linkSelector($(tab_list_container))
-		).findAll(function(link){
-			return (/^#/).exec((Prototype.Browser.WebKit ? decodeURIComponent(link.href) : link.href).replace(window.location.href.split('#')[0],''));
-		}).each(function(link){
-			this.addTab(link);
-		}.bind(this));
-		this.containers.values().each(Element.hide);
-		if(this.options.defaultTab == 'first')
-			this.setActiveTab(this.links.first());
-		else if(this.options.defaultTab == 'last')
-			this.setActiveTab(this.links.last());
-		else
-			this.setActiveTab(this.options.defaultTab);
-		var targets = this.options.targetRegExp.exec(window.location);
-		if(targets &amp;&amp; targets[1]){
-			targets[1].split(',').each(function(target){
-				this.setActiveTab(this.links.find(function(link){
-					return link.key == target;
-				}));
-			}.bind(this));
-		}
-		if(this.options.autoLinkExternal){
-			$A(document.getElementsByTagName('a')).each(function(a){
-				if(!this.links.include(a)){
-					var clean_href = a.href.replace(window.location.href.split('#')[0],'');
-					if(clean_href.substring(0,1) == '#'){
-						if(this.containers.keys().include(clean_href.substring(1))){
-							$(a).observe('click',function(event,clean_href){
-								this.setActiveTab(clean_href.substring(1));
-							}.bindAsEventListener(this,clean_href));
-						}
-					}
-				}
-			}.bind(this));
-		}
-	},
-	addTab: function(link){
-		this.links.push(link);
-		link.key = link.getAttribute('href').replace(window.location.href.split('#')[0],'').split('#').last().replace(/#/,'');
-		var container = $(link.key);
-		if(!container)
-			throw &quot;Control.Tabs: #&quot; + link.key + &quot; was not found on the page.&quot;
-		this.containers.set(link.key,container);
-		link[this.options.hover ? 'onmouseover' : 'onclick'] = function(link){
-			if(window.event)
-				Event.stop(window.event);
-			this.setActiveTab(link);
-			return false;
-		}.bind(this,link);
-	},
-	setActiveTab: function(link){
-		if(!link &amp;&amp; typeof(link) == 'undefined')
-			return;
-		if(typeof(link) == 'string'){
-			this.setActiveTab(this.links.find(function(_link){
-				return _link.key == link;
-			}));
-		}else if(typeof(link) == 'number'){
-			this.setActiveTab(this.links[link]);
-		}else{
-			if(this.notify('beforeChange',this.activeContainer,this.containers.get(link.key)) === false)
-				return;
-			if(this.activeContainer)
-				this.options.hideFunction(this.activeContainer);
-			this.links.each(function(item){
-				(this.options.setClassOnContainer ? $(item.parentNode) : item).removeClassName(this.options.activeClassName);
-			}.bind(this));
-			(this.options.setClassOnContainer ? $(link.parentNode) : link).addClassName(this.options.activeClassName);
-			this.activeContainer = this.containers.get(link.key);
-			this.activeLink = link;
-			this.options.showFunction(this.containers.get(link.key));
-			this.notify('afterChange',this.containers.get(link.key));
-		}
-	},
-	next: function(){
-		this.links.each(function(link,i){
-			if(this.activeLink == link &amp;&amp; this.links[i + 1]){
-				this.setActiveTab(this.links[i + 1]);
-				throw $break;
-			}
-		}.bind(this));
-	},
-	previous: function(){
-		this.links.each(function(link,i){
-			if(this.activeLink == link &amp;&amp; this.links[i - 1]){
-				this.setActiveTab(this.links[i - 1]);
-				throw $break;
-			}
-		}.bind(this));
-	},
-	first: function(){
-		this.setActiveTab(this.links.first());
-	},
-	last: function(){
-		this.setActiveTab(this.links.last());
-	}
+    initialize: function(tab_list_container,options){
+        if(!$(tab_list_container)) {
+            throw &quot;Control.Tabs could not find the element: &quot; + tab_list_container; }
+        this.activeContainer = false;
+        this.activeLink = false;
+        this.containers = $H({});
+        this.links = [];
+        Control.Tabs.instances.push(this);
+        this.options = {
+            beforeChange: Prototype.emptyFunction,
+            afterChange: Prototype.emptyFunction,
+            hover: false,
+            linkSelector: 'li a',
+            setClassOnContainer: false,
+            activeClassName: 'active',
+            defaultTab: 'first',
+            autoLinkExternal: true,
+            targetRegExp: /#(.+)$/,
+            showFunction: Element.show,
+            hideFunction: Element.hide
+        };
+        Object.extend(this.options,options || {});
+        (typeof(this.options.linkSelector == 'string') ? 
+            $(tab_list_container).select(this.options.linkSelector) : 
+            this.options.linkSelector($(tab_list_container))
+        ).findAll(function(link){
+            return (/^#/).exec((Prototype.Browser.WebKit ? decodeURIComponent(link.href) : link.href).replace(window.location.href.split('#')[0],''));
+        }).each(function(link){
+            this.addTab(link);
+        }.bind(this));
+        this.containers.values().each(Element.hide);
+        if(this.options.defaultTab == 'first') {
+            this.setActiveTab(this.links.first());
+        } else if(this.options.defaultTab == 'last') {
+            this.setActiveTab(this.links.last());
+        } else {
+            this.setActiveTab(this.options.defaultTab); }
+        var targets = this.options.targetRegExp.exec(window.location);
+        if(targets &amp;&amp; targets[1]){
+            targets[1].split(',').each(function(target){
+                this.setActiveTab(this.links.find(function(link){
+                    return link.key == target;
+                }));
+            }.bind(this));
+        }
+        if(this.options.autoLinkExternal){
+            $A(document.getElementsByTagName('a')).each(function(a){
+                if(!this.links.include(a)){
+                    var clean_href = a.href.replace(window.location.href.split('#')[0],'');
+                    if(clean_href.substring(0,1) == '#'){
+                        if(this.containers.keys().include(clean_href.substring(1))){
+                            $(a).observe('click',function(event,clean_href){
+                                this.setActiveTab(clean_href.substring(1));
+                            }.bindAsEventListener(this,clean_href));
+                        }
+                    }
+                }
+            }.bind(this));
+        }
+    },
+    addTab: function(link){
+        this.links.push(link);
+        link.key = link.getAttribute('href').replace(window.location.href.split('#')[0],'').split('#').last().replace(/#/,'');
+        var container = $(link.key);
+        if(!container) {
+            throw &quot;Control.Tabs: #&quot; + link.key + &quot; was not found on the page.&quot;; }
+        this.containers.set(link.key,container);
+        link[this.options.hover ? 'onmouseover' : 'onclick'] = function(link){
+            if(window.event) {
+                Event.stop(window.event); }
+            this.setActiveTab(link);
+            return false;
+        }.bind(this,link);
+    },
+    setActiveTab: function(link){
+        if(!link &amp;&amp; typeof(link) == 'undefined') {
+            return; }
+        if(typeof(link) == 'string'){
+            this.setActiveTab(this.links.find(function(_link){
+                return _link.key == link;
+            }));
+        }else if(typeof(link) == 'number'){
+            this.setActiveTab(this.links[link]);
+        }else{
+            if(this.notify('beforeChange',this.activeContainer,this.containers.get(link.key)) === false) {
+                return; }
+            if(this.activeContainer) {
+                this.options.hideFunction(this.activeContainer); }
+            this.links.each(function(item){
+                (this.options.setClassOnContainer ? $(item.parentNode) : item).removeClassName(this.options.activeClassName);
+            }.bind(this));
+            (this.options.setClassOnContainer ? $(link.parentNode) : link).addClassName(this.options.activeClassName);
+            this.activeContainer = this.containers.get(link.key);
+            this.activeLink = link;
+            this.options.showFunction(this.containers.get(link.key));
+            this.notify('afterChange',this.containers.get(link.key));
+        }
+    },
+    next: function(){
+        this.links.each(function(link,i){
+            if(this.activeLink == link &amp;&amp; this.links[i + 1]){
+                this.setActiveTab(this.links[i + 1]);
+                throw $break;
+            }
+        }.bind(this));
+    },
+    previous: function(){
+        this.links.each(function(link,i){
+            if(this.activeLink == link &amp;&amp; this.links[i - 1]){
+                this.setActiveTab(this.links[i - 1]);
+                throw $break;
+            }
+        }.bind(this));
+    },
+    first: function(){
+        this.setActiveTab(this.links.first());
+    },
+    last: function(){
+        this.setActiveTab(this.links.last());
+    }
 });
 Object.extend(Control.Tabs,{
-	instances: [],
-	findByTabId: function(id){
-		return Control.Tabs.instances.find(function(tab){
-			return tab.links.find(function(link){
-				return link.key == id;
-			});
-		});
-	}
+    instances: [],
+    findByTabId: function(id){
+        return Control.Tabs.instances.find(function(tab){
+            return tab.links.find(function(link){
+                return link.key == id;
+            });
+        });
+    }
 });
 Object.Event.extend(Control.Tabs);</diff>
      <filename>src/tabs.js</filename>
    </modified>
    <modified>
      <diff>@@ -10,60 +10,60 @@
 /*global window, document, Prototype, Class, $, $A, Control */
 
 if(typeof(Prototype) == &quot;undefined&quot;) {
-	throw &quot;Control.TextArea requires Prototype to be loaded.&quot;; }
+    throw &quot;Control.TextArea requires Prototype to be loaded.&quot;; }
 if(typeof(Object.Event) == &quot;undefined&quot;) {
-	throw &quot;Control.TextArea requires Object.Event to be loaded.&quot;; }
+    throw &quot;Control.TextArea requires Object.Event to be loaded.&quot;; }
 
 Control.TextArea = Class.create({
-	initialize: function(textarea){
-		this.onChangeTimeout = false;
-		this.element = $(textarea);
-		$(this.element).observe('keyup',this.doOnChange.bindAsEventListener(this));
-		$(this.element).observe('paste',this.doOnChange.bindAsEventListener(this));
-		$(this.element).observe('input',this.doOnChange.bindAsEventListener(this));
-		if(!!document.selection){
-			$(this.element).observe('mouseup',this.saveRange.bindAsEventListener(this));  
-			$(this.element).observe('keyup',this.saveRange.bindAsEventListener(this));
-		}
-	},
-	doOnChange: function(event){
-		if(this.onChangeTimeout) {
-			window.clearTimeout(this.onChangeTimeout); }
-		this.onChangeTimeout = window.setTimeout(function(){
-			this.notify('change',this.getValue());
-		}.bind(this),Control.TextArea.onChangeTimeoutLength);
-	},
-	saveRange: function(){
-		this.range = document.selection.createRange();  
-	},
-	getValue: function(){
-		return this.element.value;
-	},
-	getSelection: function(){
-		if(!!document.selection) {
-			return document.selection.createRange().text; }
-		else if(!!this.element.setSelectionRange) {
-			return this.element.value.substring(this.element.selectionStart,this.element.selectionEnd); }
-		else {
-			return false; }
-	},
-	replaceSelection: function(text){
-		var scroll_top = this.element.scrollTop;
-		if(!!document.selection){
-			this.element.focus();
-			var range = (this.range) ? this.range : document.selection.createRange();
-			range.text = text;
-			range.select();
-		}else if(!!this.element.setSelectionRange){
-			var selection_start = this.element.selectionStart;
-			this.element.value = this.element.value.substring(0,selection_start) + text + this.element.value.substring(this.element.selectionEnd);
-			this.element.setSelectionRange(selection_start + text.length,selection_start + text.length);
-		}
-		this.doOnChange();
-		this.element.focus();
-		this.element.scrollTop = scroll_top;
-	},
-	wrapSelection: function(before,after){
+    initialize: function(textarea){
+        this.onChangeTimeout = false;
+        this.element = $(textarea);
+        $(this.element).observe('keyup',this.doOnChange.bindAsEventListener(this));
+        $(this.element).observe('paste',this.doOnChange.bindAsEventListener(this));
+        $(this.element).observe('input',this.doOnChange.bindAsEventListener(this));
+        if(!!document.selection){
+            $(this.element).observe('mouseup',this.saveRange.bindAsEventListener(this));  
+            $(this.element).observe('keyup',this.saveRange.bindAsEventListener(this));
+        }
+    },
+    doOnChange: function(event){
+        if(this.onChangeTimeout) {
+            window.clearTimeout(this.onChangeTimeout); }
+        this.onChangeTimeout = window.setTimeout(function(){
+            this.notify('change',this.getValue());
+        }.bind(this),Control.TextArea.onChangeTimeoutLength);
+    },
+    saveRange: function(){
+        this.range = document.selection.createRange();  
+    },
+    getValue: function(){
+        return this.element.value;
+    },
+    getSelection: function(){
+        if(!!document.selection) {
+            return document.selection.createRange().text; }
+        else if(!!this.element.setSelectionRange) {
+            return this.element.value.substring(this.element.selectionStart,this.element.selectionEnd); }
+        else {
+            return false; }
+    },
+    replaceSelection: function(text){
+        var scroll_top = this.element.scrollTop;
+        if(!!document.selection){
+            this.element.focus();
+            var range = (this.range) ? this.range : document.selection.createRange();
+            range.text = text;
+            range.select();
+        }else if(!!this.element.setSelectionRange){
+            var selection_start = this.element.selectionStart;
+            this.element.value = this.element.value.substring(0,selection_start) + text + this.element.value.substring(this.element.selectionEnd);
+            this.element.setSelectionRange(selection_start + text.length,selection_start + text.length);
+        }
+        this.doOnChange();
+        this.element.focus();
+        this.element.scrollTop = scroll_top;
+    },
+    wrapSelection: function(before,after){
         var sel = this.getSelection();
         // Remove the wrapping if the selection has the same before/after
         if (sel.indexOf(before) === 0 &amp;&amp; 
@@ -71,52 +71,52 @@ Control.TextArea = Class.create({
             this.replaceSelection(sel.substring(before.length, 
                 sel.length - after.length));
         } else { this.replaceSelection(before + sel + after); }
-	},
-	insertBeforeSelection: function(text){
-		this.replaceSelection(text + this.getSelection());
-	},
-	insertAfterSelection: function(text){
-		this.replaceSelection(this.getSelection() + text);
-	},
-	collectFromEachSelectedLine: function(callback,before,after){
-		this.replaceSelection((before || '') + $A(this.getSelection().split(&quot;\n&quot;)).collect(callback).join(&quot;\n&quot;) + (after || ''));
-	},
-	insertBeforeEachSelectedLine: function(text,before,after){
-		this.collectFromEachSelectedLine(function(line){
-		},before,after);
-	}
+    },
+    insertBeforeSelection: function(text){
+        this.replaceSelection(text + this.getSelection());
+    },
+    insertAfterSelection: function(text){
+        this.replaceSelection(this.getSelection() + text);
+    },
+    collectFromEachSelectedLine: function(callback,before,after){
+        this.replaceSelection((before || '') + $A(this.getSelection().split(&quot;\n&quot;)).collect(callback).join(&quot;\n&quot;) + (after || ''));
+    },
+    insertBeforeEachSelectedLine: function(text,before,after){
+        this.collectFromEachSelectedLine(function(line){
+        },before,after);
+    }
 });
 Object.extend(Control.TextArea,{
-	onChangeTimeoutLength: 500
+    onChangeTimeoutLength: 500
 });
 Object.Event.extend(Control.TextArea);
 
-Control.TextArea.ToolBar = Class.create(	{
-	initialize: function(textarea,toolbar){
-		this.textarea = textarea;
-		if(toolbar) {
-			this.container = $(toolbar); }
-		else{
-			this.container = $(document.createElement('ul'));
-			this.textarea.element.parentNode.insertBefore(this.container,this.textarea.element);
-		}
-	},
-	attachButton: function(node,callback){
+Control.TextArea.ToolBar = Class.create(    {
+    initialize: function(textarea,toolbar){
+        this.textarea = textarea;
+        if(toolbar) {
+            this.container = $(toolbar); }
+        else{
+            this.container = $(document.createElement('ul'));
+            this.textarea.element.parentNode.insertBefore(this.container,this.textarea.element);
+        }
+    },
+    attachButton: function(node,callback){
         node.onclick = function(){return false;};
-		$(node).observe('click',callback.bindAsEventListener(this.textarea));
-	},
-	addButton: function(link_text,callback,attrs){
-		var li = document.createElement('li');
-		var a = document.createElement('a');
-		a.href = '#';
-		this.attachButton(a,callback);
-		li.appendChild(a);
-		Object.extend(a,attrs || {});
-		if(link_text){
-			var span = document.createElement('span');
-			span.innerHTML = link_text;
-			a.appendChild(span);
-		}
-		this.container.appendChild(li);
-	}
+        $(node).observe('click',callback.bindAsEventListener(this.textarea));
+    },
+    addButton: function(link_text,callback,attrs){
+        var li = document.createElement('li');
+        var a = document.createElement('a');
+        a.href = '#';
+        this.attachButton(a,callback);
+        li.appendChild(a);
+        Object.extend(a,attrs || {});
+        if(link_text){
+            var span = document.createElement('span');
+            span.innerHTML = link_text;
+            a.appendChild(span);
+        }
+        this.container.appendChild(li);
+    }
 });</diff>
      <filename>src/textarea.js</filename>
    </modified>
    <modified>
      <diff>@@ -9,921 +9,921 @@
 
 //adds onDraw and constrainToViewport option to draggable
 if(typeof(Draggable) != 'undefined'){
-	//allows the point to be modified with an onDraw callback
-	Draggable.prototype.draw = function(point) {
-		var pos = Position.cumulativeOffset(this.element);
-		if(this.options.ghosting) {
-			var r = Position.realOffset(this.element);
-			pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
-		}
-		
-		var d = this.currentDelta();
-		pos[0] -= d[0]; pos[1] -= d[1];
-		
-		if(this.options.scroll &amp;&amp; (this.options.scroll != window &amp;&amp; this._isScrollChild)) {
-			pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
-			pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
-		}
-		
-		var p = [0,1].map(function(i){ 
-			return (point[i]-pos[i]-this.offset[i]) 
-		}.bind(this));
-		
-		if(this.options.snap) {
-			if(typeof this.options.snap == 'function') {
-				p = this.options.snap(p[0],p[1],this);
-			} else {
-				if(this.options.snap instanceof Array) {
-					p = p.map( function(v, i) {return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
-				} else {
-					p = p.map( function(v) {return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
-	  			}
-			}
-		}
-		
-		if(this.options.onDraw)
-			this.options.onDraw.bind(this)(p);
-		else{
-			var style = this.element.style;
-			if(this.options.constrainToViewport){
-				var viewport_dimensions = document.viewport.getDimensions();
-				var container_dimensions = this.element.getDimensions();
-				var margin_top = parseInt(this.element.getStyle('margin-top'));
-				var margin_left = parseInt(this.element.getStyle('margin-left'));
-				var boundary = [[
-					0 - margin_left,
-					0 - margin_top
-				],[
-					(viewport_dimensions.width - container_dimensions.width) - margin_left,
-					(viewport_dimensions.height - container_dimensions.height) - margin_top
-				]];
-				if((!this.options.constraint) || (this.options.constraint=='horizontal')){ 
-					if((p[0] &gt;= boundary[0][0]) &amp;&amp; (p[0] &lt;= boundary[1][0]))
-						this.element.style.left = p[0] + &quot;px&quot;;
-					else
-						this.element.style.left = ((p[0] &lt; boundary[0][0]) ? boundary[0][0] : boundary[1][0]) + &quot;px&quot;;
-				} 
-				if((!this.options.constraint) || (this.options.constraint=='vertical')){ 
-					if((p[1] &gt;= boundary[0][1] ) &amp;&amp; (p[1] &lt;= boundary[1][1]))
-						this.element.style.top = p[1] + &quot;px&quot;;
-				  else
-						this.element.style.top = ((p[1] &lt;= boundary[0][1]) ? boundary[0][1] : boundary[1][1]) + &quot;px&quot;;			   
-				}
-			}else{
-				if((!this.options.constraint) || (this.options.constraint=='horizontal'))
-				  style.left = p[0] + &quot;px&quot;;
-				if((!this.options.constraint) || (this.options.constraint=='vertical'))
-				  style.top	 = p[1] + &quot;px&quot;;
-			}
-			if(style.visibility==&quot;hidden&quot;)
-				style.visibility = &quot;&quot;; // fix gecko rendering
-		}
-	};
+    //allows the point to be modified with an onDraw callback
+    Draggable.prototype.draw = function(point) {
+        var pos = Position.cumulativeOffset(this.element);
+        if(this.options.ghosting) {
+            var r = Position.realOffset(this.element);
+            pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
+        }
+        
+        var d = this.currentDelta();
+        pos[0] -= d[0]; pos[1] -= d[1];
+        
+        if(this.options.scroll &amp;&amp; (this.options.scroll != window &amp;&amp; this._isScrollChild)) {
+            pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
+            pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
+        }
+        
+        var p = [0,1].map(function(i){ 
+            return (point[i]-pos[i]-this.offset[i]) 
+        }.bind(this));
+        
+        if(this.options.snap) {
+            if(typeof this.options.snap == 'function') {
+                p = this.options.snap(p[0],p[1],this);
+            } else {
+                if(this.options.snap instanceof Array) {
+                    p = p.map( function(v, i) {return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
+                } else {
+                    p = p.map( function(v) {return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
+                  }
+            }
+        }
+        
+        if(this.options.onDraw)
+            this.options.onDraw.bind(this)(p);
+        else{
+            var style = this.element.style;
+            if(this.options.constrainToViewport){
+                var viewport_dimensions = document.viewport.getDimensions();
+                var container_dimensions = this.element.getDimensions();
+                var margin_top = parseInt(this.element.getStyle('margin-top'));
+                var margin_left = parseInt(this.element.getStyle('margin-left'));
+                var boundary = [[
+                    0 - margin_left,
+                    0 - margin_top
+                ],[
+                    (viewport_dimensions.width - container_dimensions.width) - margin_left,
+                    (viewport_dimensions.height - container_dimensions.height) - margin_top
+                ]];
+                if((!this.options.constraint) || (this.options.constraint=='horizontal')){ 
+                    if((p[0] &gt;= boundary[0][0]) &amp;&amp; (p[0] &lt;= boundary[1][0]))
+                        this.element.style.left = p[0] + &quot;px&quot;;
+                    else
+                        this.element.style.left = ((p[0] &lt; boundary[0][0]) ? boundary[0][0] : boundary[1][0]) + &quot;px&quot;;
+                } 
+                if((!this.options.constraint) || (this.options.constraint=='vertical')){ 
+                    if((p[1] &gt;= boundary[0][1] ) &amp;&amp; (p[1] &lt;= boundary[1][1]))
+                        this.element.style.top = p[1] + &quot;px&quot;;
+                  else
+                        this.element.style.top = ((p[1] &lt;= boundary[0][1]) ? boundary[0][1] : boundary[1][1]) + &quot;px&quot;;               
+                }
+            }else{
+                if((!this.options.constraint) || (this.options.constraint=='horizontal'))
+                  style.left = p[0] + &quot;px&quot;;
+                if((!this.options.constraint) || (this.options.constraint=='vertical'))
+                  style.top     = p[1] + &quot;px&quot;;
+            }
+            if(style.visibility==&quot;hidden&quot;)
+                style.visibility = &quot;&quot;; // fix gecko rendering
+        }
+    };
 }
 
 if(typeof(Prototype) == &quot;undefined&quot;)
-	throw &quot;Control.Window requires Prototype to be loaded.&quot;;
+    throw &quot;Control.Window requires Prototype to be loaded.&quot;;
 if(typeof(IframeShim) == &quot;undefined&quot;)
-	throw &quot;Control.Window requires IframeShim to be loaded.&quot;;
+    throw &quot;Control.Window requires IframeShim to be loaded.&quot;;
 if(typeof(Object.Event) == &quot;undefined&quot;)
-	throw &quot;Control.Window requires Object.Event to be loaded.&quot;;
+    throw &quot;Control.Window requires Object.Event to be loaded.&quot;;
 /*
-	known issues:
-		- when iframe is clicked is does not gain focus
-		- safari can't open multiple iframes properly
-		- constrainToViewport: body must have no margin or padding for this to work properly
-		- iframe will be mis positioned during fade in
-		- document.viewport does not account for scrollbars (this will eventually be fixed in the prototype core)
-	notes
-		- setting constrainToViewport only works when the page is not scrollable
-		- setting draggable: true will negate the effects of position: center
+    known issues:
+        - when iframe is clicked is does not gain focus
+        - safari can't open multiple iframes properly
+        - constrainToViewport: body must have no margin or padding for this to work properly
+        - iframe will be mis positioned during fade in
+        - document.viewport does not account for scrollbars (this will eventually be fixed in the prototype core)
+    notes
+        - setting constrainToViewport only works when the page is not scrollable
+        - setting draggable: true will negate the effects of position: center
 */
 Control.Window = Class.create({
-	initialize: function(container,options){
-		Control.Window.windows.push(this);
-		
-		//attribute initialization
-		this.container = false;
-		this.isOpen = false;
-		this.href = false;
-		this.sourceContainer = false; //this is optionally the container that will open the window
-		this.ajaxRequest = false;
-		this.remoteContentLoaded = false; //this is set when the code to load the remote content is run, onRemoteContentLoaded is fired when the connection is closed
-		this.numberInSequence = Control.Window.windows.length + 1; //only useful for the effect scoping
-		this.indicator = false;
-		this.effects = {
-			fade: false,
-			appear: false
-		};
-		this.indicatorEffects = {
-			fade: false,
-			appear: false
-		};
-		
-		//options
-		this.options = Object.extend({
-			//lifecycle
-			beforeOpen: Prototype.emptyFunction,
-			afterOpen: Prototype.emptyFunction,
-			beforeClose: Prototype.emptyFunction,
-			afterClose: Prototype.emptyFunction,
-			//dimensions and modes
-			height: null,
-			width: null,
-			className: false,
-			position: 'center', //'center', 'relative', [x,y], [function(){return x;},function(){return y;}]
-			offsetLeft: 0, //available only for anchors opening the window, or windows set to position: hover
-			offsetTop: 0, //&quot;&quot;
-			iframe: false, //if the window has an href, this will display the href as an iframe instead of requesting the url as an an Ajax.Request
-			hover: false, //element object to hover over, or if &quot;true&quot; only available for windows with sourceContainer (an anchor or any element already on the page with an href attribute)
-			indicator: false, //element to show or hide when ajax requests, images and iframes are loading
-			closeOnClick: false, //does not work with hover,can be: true (click anywhere), 'container' (will refer to this.container), or element (a specific element)
-			iframeshim: true, //wether or not to position an iFrameShim underneath the window 
-			//effects
-			fade: false,
-			fadeDuration: 0.75,
-			//draggable
-			draggable: false,
-			onDrag: Prototype.emptyFunction,
-			//resizable
-			resizable: false,
-			minHeight: false,
-			minWidth: false,
-			maxHeight: false,
-			maxWidth: false,
-			onResize: Prototype.emptyFunction,
-			//draggable and resizable
-			constrainToViewport: false,
-			//ajax
-			method: 'post',
-			parameters: {},
-			onComplete: Prototype.emptyFunction,
-			onSuccess: Prototype.emptyFunction,
-			onFailure: Prototype.emptyFunction,
-			onException: Prototype.emptyFunction,
-			//any element with an href (image,iframe,ajax) will call this after it is done loading
-			onRemoteContentLoaded: Prototype.emptyFunction,
-			insertRemoteContentAt: false //false will set this to this.container, can be string selector (first returned will be selected), or an Element that must be a child of this.container
-		},options || {});
-		
-		//container setup
-		this.indicator = this.options.indicator ? $(this.options.indicator) : false;
-		if(container){
-			if(typeof(container) == &quot;string&quot; &amp;&amp; container.match(Control.Window.uriRegex))
-				this.href = container;
-			else{
-				this.container = $(container);
-				//need to create the container now for tooltips (or hover: element with no container already on the page)
-				//second call made below will not create the container since the check is done inside createDefaultContainer()
-				this.createDefaultContainer(container);
-				//if an element with an href was passed in we use it to activate the window
-				if(this.container &amp;&amp; ((this.container.readAttribute('href') &amp;&amp; this.container.readAttribute('href') != '') || (this.options.hover &amp;&amp; this.options.hover !== true))){						
-					if(this.options.hover &amp;&amp; this.options.hover !== true)
-						this.sourceContainer = $(this.options.hover);
-					else{
-						this.sourceContainer = this.container;
-						this.href = this.container.readAttribute('href');
-						var rel = this.href.match(/^#(.+)$/);
-						if(rel &amp;&amp; rel[1]){
-							this.container = $(rel[1]);
-							this.href = false;
-						}else
-							this.container = false;
-					}
-					//hover or click handling
-					this.sourceContainerOpenHandler = function(event){
-						this.open(event);
-						event.stop();
-						return false;
-					}.bindAsEventListener(this);
-					this.sourceContainerCloseHandler = function(event){
-						this.close(event);
-					}.bindAsEventListener(this);
-					this.sourceContainerMouseMoveHandler = function(event){
-						this.position(event);
-					}.bindAsEventListener(this);
-					if(this.options.hover){
-						this.sourceContainer.observe('mouseenter',this.sourceContainerOpenHandler);
-						this.sourceContainer.observe('mouseleave',this.sourceContainerCloseHandler);
-						if(this.options.position == 'mouse')
-							this.sourceContainer.observe('mousemove',this.sourceContainerMouseMoveHandler);
-					}else
-						this.sourceContainer.observe('click',this.sourceContainerOpenHandler);
-				}
-			}
-		}
-		this.createDefaultContainer(container);
-		if(this.options.insertRemoteContentAt === false)
-			this.options.insertRemoteContentAt = this.container;
-		var styles = {
-			margin: 0,
-			position: 'absolute',
-			zIndex: Control.Window.initialZIndexForWindow()
-		};
-		if(this.options.width)
-			styles.width = $value(this.options.width) + 'px';
-		if(this.options.height)
-			styles.height = $value(this.options.height) + 'px';
-		this.container.setStyle(styles);
-		if(this.options.className)
-			this.container.addClassName(this.options.className);
-		this.positionHandler = this.position.bindAsEventListener(this);
-		this.outOfBoundsPositionHandler = this.ensureInBounds.bindAsEventListener(this);
-		this.bringToFrontHandler = this.bringToFront.bindAsEventListener(this);
-		this.container.observe('mousedown',this.bringToFrontHandler);
-		this.container.hide();
-		this.closeHandler = this.close.bindAsEventListener(this);
-		//iframeshim setup
-		if(this.options.iframeshim){
-			this.iFrameShim = new IframeShim();
-			this.iFrameShim.hide();
-		}
-		//resizable support
-		this.applyResizable();
-		//draggable support
-		this.applyDraggable();
-		
-		//makes sure the window can't go out of bounds
-		Event.observe(window,'resize',this.outOfBoundsPositionHandler);
-		
-		this.notify('afterInitialize');
-	},
-	open: function(event){
-		if(this.isOpen){
-			this.bringToFront();
-			return false;
-		}
-		if(this.notify('beforeOpen') === false)
-			return false;
-		//closeOnClick
-		if(this.options.closeOnClick){
-			if(this.options.closeOnClick === true)
-				this.closeOnClickContainer = $(document.body);
-			else if(this.options.closeOnClick == 'container')
-				this.closeOnClickContainer = this.container;
-			else if (this.options.closeOnClick == 'overlay'){
-				Control.Overlay.load();
-				this.closeOnClickContainer = Control.Overlay.container;
-			}else
-				this.closeOnClickContainer = $(this.options.closeOnClick);
-			this.closeOnClickContainer.observe('click',this.closeHandler);
-		}
-		if(this.href &amp;&amp; !this.options.iframe &amp;&amp; !this.remoteContentLoaded){
-			//link to image
-			this.remoteContentLoaded = true;
-			if(this.href.match(/\.(jpe?g|gif|png|tiff?)$/i)){
-				var img = new Element('img');
-				img.observe('load',function(img){
-					this.getRemoteContentInsertionTarget().insert(img);
-					this.position();
-					if(this.notify('onRemoteContentLoaded') !== false){
-						if(this.options.indicator)
-							this.hideIndicator();
-						this.finishOpen();
-					}
-				}.bind(this,img));
-				img.writeAttribute('src',this.href);
-			}else{
-				//if this is an ajax window it will only open if the request is successful
-				if(!this.ajaxRequest){
-					if(this.options.indicator)
-						this.showIndicator();
-					this.ajaxRequest = new Ajax.Request(this.href,{
-						method: this.options.method,
-						parameters: this.options.parameters,
-						onComplete: function(request){
-							this.notify('onComplete',request);
-							this.ajaxRequest = false;
-						}.bind(this),
-						onSuccess: function(request){
-							this.getRemoteContentInsertionTarget().insert(request.responseText);
-							this.notify('onSuccess',request);
-							if(this.notify('onRemoteContentLoaded') !== false){
-								if(this.options.indicator)
-									this.hideIndicator();
-								this.finishOpen();
-							}
-						}.bind(this),
-						onFailure: function(request){
-							this.notify('onFailure',request);
-							if(this.options.indicator)
-								this.hideIndicator();
-						}.bind(this),
-						onException: function(request,e){
-							this.notify('onException',request,e);
-							if(this.options.indicator)
-								this.hideIndicator();
-						}.bind(this)
-					});
-				}
-			}
-			return true;
-		}else if(this.options.iframe &amp;&amp; !this.remoteContentLoaded){
-			//iframe
-			this.remoteContentLoaded = true;
-			if(this.options.indicator)
-				this.showIndicator();
-			this.getRemoteContentInsertionTarget().insert(Control.Window.iframeTemplate.evaluate({
-				href: this.href
-			}));
-			var iframe = this.container.down('iframe');
-			iframe.onload = function(){
-				this.notify('onRemoteContentLoaded');
-				if(this.options.indicator)
-					this.hideIndicator();
-				iframe.onload = null;
-			}.bind(this);
-		}
-		this.finishOpen(event);
-		return true
-	},
-	close: function(event){ //event may or may not be present
-		if(!this.isOpen || this.notify('beforeClose',event) === false)
-			return false;
-		if(this.options.closeOnClick)
-			this.closeOnClickContainer.stopObserving('click',this.closeHandler);
-		if(this.options.fade){
-			this.effects.fade = new Effect.Fade(this.container,{
-				queue: {
-					position: 'front',
-					scope: 'Control.Window' + this.numberInSequence
-				},
-				from: 1,
-				to: 0,
-				duration: this.options.fadeDuration / 2,
-				afterFinish: function(){
-					if(this.iFrameShim)
-						this.iFrameShim.hide();
-					this.isOpen = false;
-					this.notify('afterClose');
-				}.bind(this)
-			});
-		}else{
-			this.container.hide();
-			if(this.iFrameShim)
-				this.iFrameShim.hide();
-		}
-		if(this.ajaxRequest)
-			this.ajaxRequest.transport.abort();
-		if(!(this.options.draggable || this.options.resizable) &amp;&amp; this.options.position == 'center')
-			Event.stopObserving(window,'resize',this.positionHandler);
-		if(!this.options.draggable &amp;&amp; this.options.position == 'center')
-			Event.stopObserving(window,'scroll',this.positionHandler);
-		if(this.options.indicator)
-			this.hideIndicator();
-		if(!this.options.fade){
-			this.isOpen = false;
-			this.notify('afterClose');
+    initialize: function(container,options){
+        Control.Window.windows.push(this);
+        
+        //attribute initialization
+        this.container = false;
+        this.isOpen = false;
+        this.href = false;
+        this.sourceContainer = false; //this is optionally the container that will open the window
+        this.ajaxRequest = false;
+        this.remoteContentLoaded = false; //this is set when the code to load the remote content is run, onRemoteContentLoaded is fired when the connection is closed
+        this.numberInSequence = Control.Window.windows.length + 1; //only useful for the effect scoping
+        this.indicator = false;
+        this.effects = {
+            fade: false,
+            appear: false
+        };
+        this.indicatorEffects = {
+            fade: false,
+            appear: false
+        };
+        
+        //options
+        this.options = Object.extend({
+            //lifecycle
+            beforeOpen: Prototype.emptyFunction,
+            afterOpen: Prototype.emptyFunction,
+            beforeClose: Prototype.emptyFunction,
+            afterClose: Prototype.emptyFunction,
+            //dimensions and modes
+            height: null,
+            width: null,
+            className: false,
+            position: 'center', //'center', 'relative', [x,y], [function(){return x;},function(){return y;}]
+            offsetLeft: 0, //available only for anchors opening the window, or windows set to position: hover
+            offsetTop: 0, //&quot;&quot;
+            iframe: false, //if the window has an href, this will display the href as an iframe instead of requesting the url as an an Ajax.Request
+            hover: false, //element object to hover over, or if &quot;true&quot; only available for windows with sourceContainer (an anchor or any element already on the page with an href attribute)
+            indicator: false, //element to show or hide when ajax requests, images and iframes are loading
+            closeOnClick: false, //does not work with hover,can be: true (click anywhere), 'container' (will refer to this.container), or element (a specific element)
+            iframeshim: true, //whether or not to position an iFrameShim underneath the window 
+            //effects
+            fade: false,
+            fadeDuration: 0.75,
+            //draggable
+            draggable: false,
+            onDrag: Prototype.emptyFunction,
+            //resizable
+            resizable: false,
+            minHeight: false,
+            minWidth: false,
+            maxHeight: false,
+            maxWidth: false,
+            onResize: Prototype.emptyFunction,
+            //draggable and resizable
+            constrainToViewport: false,
+            //ajax
+            method: 'post',
+            parameters: {},
+            onComplete: Prototype.emptyFunction,
+            onSuccess: Prototype.emptyFunction,
+            onFailure: Prototype.emptyFunction,
+            onException: Prototype.emptyFunction,
+            //any element with an href (image,iframe,ajax) will call this after it is done loading
+            onRemoteContentLoaded: Prototype.emptyFunction,
+            insertRemoteContentAt: false //false will set this to this.container, can be string selector (first returned will be selected), or an Element that must be a child of this.container
+        },options || {});
+        
+        //container setup
+        this.indicator = this.options.indicator ? $(this.options.indicator) : false;
+        if(container){
+            if(typeof(container) == &quot;string&quot; &amp;&amp; container.match(Control.Window.uriRegex))
+                this.href = container;
+            else{
+                this.container = $(container);
+                //need to create the container now for tooltips (or hover: element with no container already on the page)
+                //second call made below will not create the container since the check is done inside createDefaultContainer()
+                this.createDefaultContainer(container);
+                //if an element with an href was passed in we use it to activate the window
+                if(this.container &amp;&amp; ((this.container.readAttribute('href') &amp;&amp; this.container.readAttribute('href') != '') || (this.options.hover &amp;&amp; this.options.hover !== true))){                        
+                    if(this.options.hover &amp;&amp; this.options.hover !== true)
+                        this.sourceContainer = $(this.options.hover);
+                    else{
+                        this.sourceContainer = this.container;
+                        this.href = this.container.readAttribute('href');
+                        var rel = this.href.match(/^#(.+)$/);
+                        if(rel &amp;&amp; rel[1]){
+                            this.container = $(rel[1]);
+                            this.href = false;
+                        }else
+                            this.container = false;
+                    }
+                    //hover or click handling
+                    this.sourceContainerOpenHandler = function(event){
+                        this.open(event);
+                        event.stop();
+                        return false;
+                    }.bindAsEventListener(this);
+                    this.sourceContainerCloseHandler = function(event){
+                        this.close(event);
+                    }.bindAsEventListener(this);
+                    this.sourceContainerMouseMoveHandler = function(event){
+                        this.position(event);
+                    }.bindAsEventListener(this);
+                    if(this.options.hover){
+                        this.sourceContainer.observe('mouseenter',this.sourceContainerOpenHandler);
+                        this.sourceContainer.observe('mouseleave',this.sourceContainerCloseHandler);
+                        if(this.options.position == 'mouse')
+                            this.sourceContainer.observe('mousemove',this.sourceContainerMouseMoveHandler);
+                    }else
+                        this.sourceContainer.observe('click',this.sourceContainerOpenHandler);
+                }
+            }
+        }
+        this.createDefaultContainer(container);
+        if(this.options.insertRemoteContentAt === false)
+            this.options.insertRemoteContentAt = this.container;
+        var styles = {
+            margin: 0,
+            position: 'absolute',
+            zIndex: Control.Window.initialZIndexForWindow()
+        };
+        if(this.options.width)
+            styles.width = $value(this.options.width) + 'px';
+        if(this.options.height)
+            styles.height = $value(this.options.height) + 'px';
+        this.container.setStyle(styles);
+        if(this.options.className)
+            this.container.addClassName(this.options.className);
+        this.positionHandler = this.position.bindAsEventListener(this);
+        this.outOfBoundsPositionHandler = this.ensureInBounds.bindAsEventListener(this);
+        this.bringToFrontHandler = this.bringToFront.bindAsEventListener(this);
+        this.container.observe('mousedown',this.bringToFrontHandler);
+        this.container.hide();
+        this.closeHandler = this.close.bindAsEventListener(this);
+        //iframeshim setup
+        if(this.options.iframeshim){
+            this.iFrameShim = new IframeShim();
+            this.iFrameShim.hide();
+        }
+        //resizable support
+        this.applyResizable();
+        //draggable support
+        this.applyDraggable();
+        
+        //makes sure the window can't go out of bounds
+        Event.observe(window,'resize',this.outOfBoundsPositionHandler);
+        
+        this.notify('afterInitialize');
+    },
+    open: function(event){
+        if(this.isOpen){
+            this.bringToFront();
+            return false;
+        }
+        if(this.notify('beforeOpen') === false)
+            return false;
+        //closeOnClick
+        if(this.options.closeOnClick){
+            if(this.options.closeOnClick === true)
+                this.closeOnClickContainer = $(document.body);
+            else if(this.options.closeOnClick == 'container')
+                this.closeOnClickContainer = this.container;
+            else if (this.options.closeOnClick == 'overlay'){
+                Control.Overlay.load();
+                this.closeOnClickContainer = Control.Overlay.container;
+            }else
+                this.closeOnClickContainer = $(this.options.closeOnClick);
+            this.closeOnClickContainer.observe('click',this.closeHandler);
+        }
+        if(this.href &amp;&amp; !this.options.iframe &amp;&amp; !this.remoteContentLoaded){
+            //link to image
+            this.remoteContentLoaded = true;
+            if(this.href.match(/\.(jpe?g|gif|png|tiff?)$/i)){
+                var img = new Element('img');
+                img.observe('load',function(img){
+                    this.getRemoteContentInsertionTarget().insert(img);
+                    this.position();
+                    if(this.notify('onRemoteContentLoaded') !== false){
+                        if(this.options.indicator)
+                            this.hideIndicator();
+                        this.finishOpen();
+                    }
+                }.bind(this,img));
+                img.writeAttribute('src',this.href);
+            }else{
+                //if this is an ajax window it will only open if the request is successful
+                if(!this.ajaxRequest){
+                    if(this.options.indicator)
+                        this.showIndicator();
+                    this.ajaxRequest = new Ajax.Request(this.href,{
+                        method: this.options.method,
+                        parameters: this.options.parameters,
+                        onComplete: function(request){
+                            this.notify('onComplete',request);
+                            this.ajaxRequest = false;
+                        }.bind(this),
+                        onSuccess: function(request){
+                            this.getRemoteContentInsertionTarget().insert(request.responseText);
+                            this.notify('onSuccess',request);
+                            if(this.notify('onRemoteContentLoaded') !== false){
+                                if(this.options.indicator)
+                                    this.hideIndicator();
+                                this.finishOpen();
+                            }
+                        }.bind(this),
+                        onFailure: function(request){
+                            this.notify('onFailure',request);
+                            if(this.options.indicator)
+                                this.hideIndicator();
+                        }.bind(this),
+                        onException: function(request,e){
+                            this.notify('onException',request,e);
+                            if(this.options.indicator)
+                                this.hideIndicator();
+                        }.bind(this)
+                    });
+                }
+            }
+            return true;
+        }else if(this.options.iframe &amp;&amp; !this.remoteContentLoaded){
+            //iframe
+            this.remoteContentLoaded = true;
+            if(this.options.indicator)
+                this.showIndicator();
+            this.getRemoteContentInsertionTarget().insert(Control.Window.iframeTemplate.evaluate({
+                href: this.href
+            }));
+            var iframe = this.container.down('iframe');
+            iframe.onload = function(){
+                this.notify('onRemoteContentLoaded');
+                if(this.options.indicator)
+                    this.hideIndicator();
+                iframe.onload = null;
+            }.bind(this);
+        }
+        this.finishOpen(event);
+        return true
+    },
+    close: function(event){ //event may or may not be present
+        if(!this.isOpen || this.notify('beforeClose',event) === false)
+            return false;
+        if(this.options.closeOnClick)
+            this.closeOnClickContainer.stopObserving('click',this.closeHandler);
+        if(this.options.fade){
+            this.effects.fade = new Effect.Fade(this.container,{
+                queue: {
+                    position: 'front',
+                    scope: 'Control.Window' + this.numberInSequence
+                },
+                from: 1,
+                to: 0,
+                duration: this.options.fadeDuration / 2,
+                afterFinish: function(){
+                    if(this.iFrameShim)
+                        this.iFrameShim.hide();
+                    this.isOpen = false;
+                    this.notify('afterClose');
+                }.bind(this)
+            });
+        }else{
+            this.container.hide();
+            if(this.iFrameShim)
+                this.iFrameShim.hide();
+        }
+        if(this.ajaxRequest)
+            this.ajaxRequest.transport.abort();
+        if(!(this.options.draggable || this.options.resizable) &amp;&amp; this.options.position == 'center')
+            Event.stopObserving(window,'resize',this.positionHandler);
+        if(!this.options.draggable &amp;&amp; this.options.position == 'center')
+            Event.stopObserving(window,'scroll',this.positionHandler);
+        if(this.options.indicator)
+            this.hideIndicator();
+        if(!this.options.fade){
+            this.isOpen = false;
+            this.notify('afterClose');
+        }
+        return true;
+    },
+    position: function(event){
+        //this is up top for performance reasons
+        if(this.options.position == 'mouse'){
+            var xy = [Event.pointerX(event),Event.pointerY(event)];
+            this.container.setStyle({
+                top: xy[1] + $value(this.options.offsetTop) + 'px',
+                left: xy[0] + $value(this.options.offsetLeft) + 'px'
+            });
+            return;
+        }
+        var container_dimensions = this.container.getDimensions();
+        var viewport_dimensions = document.viewport.getDimensions();
+        Position.prepare();
+        var offset_left = (Position.deltaX + Math.floor((viewport_dimensions.width - container_dimensions.width) / 2));
+        var offset_top = (Position.deltaY + ((viewport_dimensions.height &gt; container_dimensions.height) ? Math.floor((viewport_dimensions.height - container_dimensions.height) / 2) : 0));
+        if(this.options.position == 'center'){
+            this.container.setStyle({
+                top: (container_dimensions.height &lt;= viewport_dimensions.height) ? ((offset_top != null &amp;&amp; offset_top &gt; 0) ? offset_top : 0) + 'px' : 0,
+                left: (container_dimensions.width &lt;= viewport_dimensions.width) ? ((offset_left != null &amp;&amp; offset_left &gt; 0) ? offset_left : 0) + 'px' : 0
+            });
+        }else if(this.options.position == 'relative'){
+            var xy = this.sourceContainer.cumulativeOffset();
+            var top = xy[1] + $value(this.options.offsetTop);
+            var left = xy[0] + $value(this.options.offsetLeft);
+            this.container.setStyle({
+                top: (container_dimensions.height &lt;= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.height - (container_dimensions.height),top)) : top) + 'px' : 0,
+                left: (container_dimensions.width &lt;= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.width - (container_dimensions.width),left)) : left) + 'px' : 0
+            });
+        }else if(this.options.position.length){
+            var top = $value(this.options.position[1]) + $value(this.options.offsetTop);
+            var left = $value(this.options.position[0]) + $value(this.options.offsetLeft);
+            this.container.setStyle({
+                top: (container_dimensions.height &lt;= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.height - (container_dimensions.height),top)) : top) + 'px' : 0,
+                left: (container_dimensions.width &lt;= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.width - (container_dimensions.width),left)) : left) + 'px' : 0
+            });
+        }
+        if(this.iFrameShim)
+            this.updateIFrameShimZIndex();
+    },
+    ensureInBounds: function(){
+        if(!this.isOpen)
+            return;
+        var viewport_dimensions = document.viewport.getDimensions();
+        var container_offset = this.container.cumulativeOffset();
+        var container_dimensions = this.container.getDimensions();
+        if(container_offset.left + container_dimensions.width &gt; viewport_dimensions.width){
+            this.container.setStyle({
+                left: (Math.max(0,viewport_dimensions.width - container_dimensions.width)) + 'px'
+            });
         }
-		return true;
-	},
-	position: function(event){
-		//this is up top for performance reasons
-		if(this.options.position == 'mouse'){
-			var xy = [Event.pointerX(event),Event.pointerY(event)];
-			this.container.setStyle({
-				top: xy[1] + $value(this.options.offsetTop) + 'px',
-				left: xy[0] + $value(this.options.offsetLeft) + 'px'
-			});
-			return;
-		}
-		var container_dimensions = this.container.getDimensions();
-		var viewport_dimensions = document.viewport.getDimensions();
-		Position.prepare();
-		var offset_left = (Position.deltaX + Math.floor((viewport_dimensions.width - container_dimensions.width) / 2));
-		var offset_top = (Position.deltaY + ((viewport_dimensions.height &gt; container_dimensions.height) ? Math.floor((viewport_dimensions.height - container_dimensions.height) / 2) : 0));
-		if(this.options.position == 'center'){
-			this.container.setStyle({
-				top: (container_dimensions.height &lt;= viewport_dimensions.height) ? ((offset_top != null &amp;&amp; offset_top &gt; 0) ? offset_top : 0) + 'px' : 0,
-				left: (container_dimensions.width &lt;= viewport_dimensions.width) ? ((offset_left != null &amp;&amp; offset_left &gt; 0) ? offset_left : 0) + 'px' : 0
-			});
-		}else if(this.options.position == 'relative'){
-			var xy = this.sourceContainer.cumulativeOffset();
-			var top = xy[1] + $value(this.options.offsetTop);
-			var left = xy[0] + $value(this.options.offsetLeft);
-			this.container.setStyle({
-				top: (container_dimensions.height &lt;= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.height - (container_dimensions.height),top)) : top) + 'px' : 0,
-				left: (container_dimensions.width &lt;= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.width - (container_dimensions.width),left)) : left) + 'px' : 0
-			});
-		}else if(this.options.position.length){
-			var top = $value(this.options.position[1]) + $value(this.options.offsetTop);
-			var left = $value(this.options.position[0]) + $value(this.options.offsetLeft);
-			this.container.setStyle({
-				top: (container_dimensions.height &lt;= viewport_dimensions.height) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.height - (container_dimensions.height),top)) : top) + 'px' : 0,
-				left: (container_dimensions.width &lt;= viewport_dimensions.width) ? (this.options.constrainToViewport ? Math.max(0,Math.min(viewport_dimensions.width - (container_dimensions.width),left)) : left) + 'px' : 0
-			});
-		}
-		if(this.iFrameShim)
-			this.updateIFrameShimZIndex();
-	},
-	ensureInBounds: function(){
-		if(!this.isOpen)
-			return;
-		var viewport_dimensions = document.viewport.getDimensions();
-		var container_offset = this.container.cumulativeOffset();
-		var container_dimensions = this.container.getDimensions();
-		if(container_offset.left + container_dimensions.width &gt; viewport_dimensions.width){
-			this.container.setStyle({
-				left: (Math.max(0,viewport_dimensions.width - container_dimensions.width)) + 'px'
-			});
-		}
-		if(container_offset.top + container_dimensions.height &gt; viewport_dimensions.height){
-			this.container.setStyle({
-				top: (Math.max(0,viewport_dimensions.height - container_dimensions.height)) + 'px'
-			});
-		}
-	},
-	bringToFront: function(){
-		Control.Window.bringToFront(this);
-		this.notify('bringToFront');
-	},
-	destroy: function(){
-		this.container.stopObserving('mousedown',this.bringToFrontHandler);
-		if(this.draggable){
-			Draggables.removeObserver(this.container);
-			this.draggable.handle.stopObserving('mousedown',this.bringToFrontHandler);
-			this.draggable.destroy();
-		}
-		if(this.resizable){
-			Resizables.removeObserver(this.container);
-			this.resizable.handle.stopObserving('mousedown',this.bringToFrontHandler);
-			this.resizable.destroy();
-		}
-		if(this.container &amp;&amp; !this.sourceContainer)
-			this.container.remove();
-		if(this.sourceContainer){
-			if(this.options.hover){
-				this.sourceContainer.stopObserving('mouseenter',this.sourceContainerOpenHandler);
-				this.sourceContainer.stopObserving('mouseleave',this.sourceContainerCloseHandler);
-				if(this.options.position == 'mouse')
-					this.sourceContainer.stopObserving('mousemove',this.sourceContainerMouseMoveHandler);
-			}else
-				this.sourceContainer.stopObserving('click',this.sourceContainerOpenHandler);
-		}
-		if(this.iFrameShim)
-			this.iFrameShim.destroy();
-		Event.stopObserving(window,'resize',this.outOfBoundsPositionHandler);
-		Control.Window.windows = Control.Window.windows.without(this);
-		this.notify('afterDestroy');
-	},
-	//private
-	applyResizable: function(){
-		if(this.options.resizable){
-			if(typeof(Resizable) == &quot;undefined&quot;)
-				throw &quot;Control.Window requires resizable.js to be loaded.&quot;;
-			var resizable_handle = null;
-			if(this.options.resizable === true){
-				resizable_handle = new Element('div',{
-					className: 'resizable_handle'
-				});
-				this.container.insert(resizable_handle);
-			}else
-				resizable_handle = $(this.options.resziable);
-			this.resizable = new Resizable(this.container,{
-				handle: resizable_handle,
-				minHeight: this.options.minHeight,
-				minWidth: this.options.minWidth,
-				maxHeight: this.options.constrainToViewport ? function(element){
-					//viewport height - top - total border height
-					return (document.viewport.getDimensions().height - parseInt(element.style.top || 0)) - (element.getHeight() - parseInt(element.style.height || 0));
-				} : this.options.maxHeight,
-				maxWidth: this.options.constrainToViewport ? function(element){
-					//viewport width - left - total border width
-					return (document.viewport.getDimensions().width - parseInt(element.style.left || 0)) - (element.getWidth() - parseInt(element.style.width || 0));
-				} : this.options.maxWidth
-			});
-			this.resizable.handle.observe('mousedown',this.bringToFrontHandler);
-			Resizables.addObserver(new Control.Window.LayoutUpdateObserver(this,function(){
-				if(this.iFrameShim)
-					this.updateIFrameShimZIndex();
-				this.notify('onResize');
-			}.bind(this)));
-		}
-	},
-	applyDraggable: function(){
-		if(this.options.draggable){
-			if(typeof(Draggables) == &quot;undefined&quot;)
-				throw &quot;Control.Window requires dragdrop.js to be loaded.&quot;;
-			var draggable_handle = null;
-			if(this.options.draggable === true){
-				draggable_handle = new Element('div',{
-					className: 'draggable_handle'
-				});
-				this.container.insert(draggable_handle);
-			}else
-				draggable_handle = $(this.options.draggable);
-			this.draggable = new Draggable(this.container,{
-				handle: draggable_handle,
-				constrainToViewport: this.options.constrainToViewport,
-				zindex: this.container.getStyle('z-index'),
-				starteffect: function(){
-					if(Prototype.Browser.IE){
-						this.old_onselectstart = document.onselectstart;
-						document.onselectstart = function(){
-							return false;
-						};
-					}
-				}.bind(this),
-				endeffect: function(){
-					document.onselectstart = this.old_onselectstart;
-				}.bind(this)
-			});
-			this.draggable.handle.observe('mousedown',this.bringToFrontHandler);
-			Draggables.addObserver(new Control.Window.LayoutUpdateObserver(this,function(){
-				if(this.iFrameShim)
-					this.updateIFrameShimZIndex();
-				this.notify('onDrag');
-			}.bind(this)));
-		}
-	},
-	createDefaultContainer: function(container){
-		if(!this.container){
-			//no container passed or found, create it
-			this.container = new Element('div',{
-				id: 'control_window_' + this.numberInSequence
-			});
-			$(document.body).insert(this.container);
-			if(typeof(container) == &quot;string&quot; &amp;&amp; $(container) == null &amp;&amp; !container.match(/^#(.+)$/) &amp;&amp; !container.match(Control.Window.uriRegex))
-				this.container.update(container);
-		}
-	},
-	finishOpen: function(event){
-		this.bringToFront();
-		if(this.options.fade){
-			if(typeof(Effect) == &quot;undefined&quot;)
-				throw &quot;Control.Window requires effects.js to be loaded.&quot;
-			if(this.effects.fade)
-				this.effects.fade.cancel();
-			this.effects.appear = new Effect.Appear(this.container,{
-				queue: {
-					position: 'end',
-					scope: 'Control.Window.' + this.numberInSequence
-				},
-				from: 0,
-				to: 1,
-				duration: this.options.fadeDuration / 2,
-				afterFinish: function(){
-					if(this.iFrameShim)
-						this.updateIFrameShimZIndex();
-					this.isOpen = true;
-					this.notify('afterOpen');
-				}.bind(this)
-			});
-		}else
-			this.container.show();
-		this.position(event);
-		if(!(this.options.draggable || this.options.resizable) &amp;&amp; this.options.position == 'center')
-			Event.observe(window,'resize',this.positionHandler,false);
-		if(!this.options.draggable &amp;&amp; this.options.position == 'center')
-			Event.observe(window,'scroll',this.positionHandler,false);
-		if(!this.options.fade){
-			this.isOpen = true;
-			this.notify('afterOpen');
-		}
-		return true;
-	},
-	showIndicator: function(){
-		this.showIndicatorTimeout = window.setTimeout(function(){
-			if(this.options.fade){
-				this.indicatorEffects.appear = new Effect.Appear(this.indicator,{
-					queue: {
-						position: 'front',
-						scope: 'Control.Window.indicator.' + this.numberInSequence
-					},
-					from: 0,
-					to: 1,
-					duration: this.options.fadeDuration / 2
-				});
-			}else
-				this.indicator.show();
-		}.bind(this),Control.Window.indicatorTimeout);
-	},
-	hideIndicator: function(){
-		if(this.showIndicatorTimeout)
-			window.clearTimeout(this.showIndicatorTimeout);
-		this.indicator.hide();
-	},
-	getRemoteContentInsertionTarget: function(){
-		return typeof(this.options.insertRemoteContentAt) == &quot;string&quot; ? this.container.down(this.options.insertRemoteContentAt) : $(this.options.insertRemoteContentAt);
-	},
-	updateIFrameShimZIndex: function(){
-		if(this.iFrameShim)
-			this.iFrameShim.positionUnder(this.container);
-	}
+        if(container_offset.top + container_dimensions.height &gt; viewport_dimensions.height){
+            this.container.setStyle({
+                top: (Math.max(0,viewport_dimensions.height - container_dimensions.height)) + 'px'
+            });
+        }
+    },
+    bringToFront: function(){
+        Control.Window.bringToFront(this);
+        this.notify('bringToFront');
+    },
+    destroy: function(){
+        this.container.stopObserving('mousedown',this.bringToFrontHandler);
+        if(this.draggable){
+            Draggables.removeObserver(this.container);
+            this.draggable.handle.stopObserving('mousedown',this.bringToFrontHandler);
+            this.draggable.destroy();
+        }
+        if(this.resizable){
+            Resizables.removeObserver(this.container);
+            this.resizable.handle.stopObserving('mousedown',this.bringToFrontHandler);
+            this.resizable.destroy();
+        }
+        if(this.container &amp;&amp; !this.sourceContainer)
+            this.container.remove();
+        if(this.sourceContainer){
+            if(this.options.hover){
+                this.sourceContainer.stopObserving('mouseenter',this.sourceContainerOpenHandler);
+                this.sourceContainer.stopObserving('mouseleave',this.sourceContainerCloseHandler);
+                if(this.options.position == 'mouse')
+                    this.sourceContainer.stopObserving('mousemove',this.sourceContainerMouseMoveHandler);
+            }else
+                this.sourceContainer.stopObserving('click',this.sourceContainerOpenHandler);
+        }
+        if(this.iFrameShim)
+            this.iFrameShim.destroy();
+        Event.stopObserving(window,'resize',this.outOfBoundsPositionHandler);
+        Control.Window.windows = Control.Window.windows.without(this);
+        this.notify('afterDestroy');
+    },
+    //private
+    applyResizable: function(){
+        if(this.options.resizable){
+            if(typeof(Resizable) == &quot;undefined&quot;)
+                throw &quot;Control.Window requires resizable.js to be loaded.&quot;;
+            var resizable_handle = null;
+            if(this.options.resizable === true){
+                resizable_handle = new Element('div',{
+                    className: 'resizable_handle'
+                });
+                this.container.insert(resizable_handle);
+            }else
+                resizable_handle = $(this.options.resziable);
+            this.resizable = new Resizable(this.container,{
+                handle: resizable_handle,
+                minHeight: this.options.minHeight,
+                minWidth: this.options.minWidth,
+                maxHeight: this.options.constrainToViewport ? function(element){
+                    //viewport height - top - total border height
+                    return (document.viewport.getDimensions().height - parseInt(element.style.top || 0)) - (element.getHeight() - parseInt(element.style.height || 0));
+                } : this.options.maxHeight,
+                maxWidth: this.options.constrainToViewport ? function(element){
+                    //viewport width - left - total border width
+                    return (document.viewport.getDimensions().width - parseInt(element.style.left || 0)) - (element.getWidth() - parseInt(element.style.width || 0));
+                } : this.options.maxWidth
+            });
+            this.resizable.handle.observe('mousedown',this.bringToFrontHandler);
+            Resizables.addObserver(new Control.Window.LayoutUpdateObserver(this,function(){
+                if(this.iFrameShim)
+                    this.updateIFrameShimZIndex();
+                this.notify('onResize');
+            }.bind(this)));
+        }
+    },
+    applyDraggable: function(){
+        if(this.options.draggable){
+            if(typeof(Draggables) == &quot;undefined&quot;)
+                throw &quot;Control.Window requires dragdrop.js to be loaded.&quot;;
+            var draggable_handle = null;
+            if(this.options.draggable === true){
+                draggable_handle = new Element('div',{
+                    className: 'draggable_handle'
+                });
+                this.container.insert(draggable_handle);
+            }else
+                draggable_handle = $(this.options.draggable);
+            this.draggable = new Draggable(this.container,{
+                handle: draggable_handle,
+                constrainToViewport: this.options.constrainToViewport,
+                zindex: this.container.getStyle('z-index'),
+                starteffect: function(){
+                    if(Prototype.Browser.IE){
+                        this.old_onselectstart = document.onselectstart;
+                        document.onselectstart = function(){
+                            return false;
+                        };
+                    }
+                }.bind(this),
+                endeffect: function(){
+                    document.onselectstart = this.old_onselectstart;
+                }.bind(this)
+            });
+            this.draggable.handle.observe('mousedown',this.bringToFrontHandler);
+            Draggables.addObserver(new Control.Window.LayoutUpdateObserver(this,function(){
+                if(this.iFrameShim)
+                    this.updateIFrameShimZIndex();
+                this.notify('onDrag');
+            }.bind(this)));
+        }
+    },
+    createDefaultContainer: function(container){
+        if(!this.container){
+            //no container passed or found, create it
+            this.container = new Element('div',{
+                id: 'control_window_' + this.numberInSequence
+            });
+            $(document.body).insert(this.container);
+            if(typeof(container) == &quot;string&quot; &amp;&amp; $(container) == null &amp;&amp; !container.match(/^#(.+)$/) &amp;&amp; !container.match(Control.Window.uriRegex))
+                this.container.update(container);
+        }
+    },
+    finishOpen: function(event){
+        this.bringToFront();
+        if(this.options.fade){
+            if(typeof(Effect) == &quot;undefined&quot;)
+                throw &quot;Control.Window requires effects.js to be loaded.&quot;
+            if(this.effects.fade)
+                this.effects.fade.cancel();
+            this.effects.appear = new Effect.Appear(this.container,{
+                queue: {
+                    position: 'end',
+                    scope: 'Control.Window.' + this.numberInSequence
+                },
+                from: 0,
+                to: 1,
+                duration: this.options.fadeDuration / 2,
+                afterFinish: function(){
+                    if(this.iFrameShim)
+                        this.updateIFrameShimZIndex();
+                    this.isOpen = true;
+                    this.notify('afterOpen');
+                }.bind(this)
+            });
+        }else
+            this.container.show();
+        this.position(event);
+        if(!(this.options.draggable || this.options.resizable) &amp;&amp; this.options.position == 'center')
+            Event.observe(window,'resize',this.positionHandler,false);
+        if(!this.options.draggable &amp;&amp; this.options.position == 'center')
+            Event.observe(window,'scroll',this.positionHandler,false);
+        if(!this.options.fade){
+            this.isOpen = true;
+            this.notify('afterOpen');
+        }
+        return true;
+    },
+    showIndicator: function(){
+        this.showIndicatorTimeout = window.setTimeout(function(){
+            if(this.options.fade){
+                this.indicatorEffects.appear = new Effect.Appear(this.indicator,{
+                    queue: {
+                        position: 'front',
+                        scope: 'Control.Window.indicator.' + this.numberInSequence
+                    },
+                    from: 0,
+                    to: 1,
+                    duration: this.options.fadeDuration / 2
+                });
+            }else
+                this.indicator.show();
+        }.bind(this),Control.Window.indicatorTimeout);
+    },
+    hideIndicator: function(){
+        if(this.showIndicatorTimeout)
+            window.clearTimeout(this.showIndicatorTimeout);
+        this.indicator.hide();
+    },
+    getRemoteContentInsertionTarget: function(){
+        return typeof(this.options.insertRemoteContentAt) == &quot;string&quot; ? this.container.down(this.options.insertRemoteContentAt) : $(this.options.insertRemoteContentAt);
+    },
+    updateIFrameShimZIndex: function(){
+        if(this.iFrameShim)
+            this.iFrameShim.positionUnder(this.container);
+    }
 });
 //class methods
 Object.extend(Control.Window,{
-	windows: [],
-	baseZIndex: 9999,
-	indicatorTimeout: 250,
-	iframeTemplate: new Template('&lt;iframe src=&quot;#{href}&quot; width=&quot;100%&quot; height=&quot;100%&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;'),
-	uriRegex: /^(\/|\#|https?\:\/\/|[\w]+\/)/,
-	bringToFront: function(w){
-		Control.Window.windows = Control.Window.windows.without(w);
-		Control.Window.windows.push(w);
-		Control.Window.windows.each(function(w,i){
-			var z_index = Control.Window.baseZIndex + i;
-			w.container.setStyle({
-				zIndex: z_index
-			});
-			if(w.isOpen){
-				if(w.iFrameShim)
-				w.updateIFrameShimZIndex();
-			}
-			if(w.options.draggable)
-				w.draggable.options.zindex = z_index;
-		});
-	},
-	open: function(container,options){
-		var w = new Control.Window(container,options);
-		w.open();
-		return w;
-	},
-	//protected
-	initialZIndexForWindow: function(w){
-		return Control.Window.baseZIndex + (Control.Window.windows.length - 1);
-	}
+    windows: [],
+    baseZIndex: 9999,
+    indicatorTimeout: 250,
+    iframeTemplate: new Template('&lt;iframe src=&quot;#{href}&quot; width=&quot;100%&quot; height=&quot;100%&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;'),
+    uriRegex: /^(\/|\#|https?\:\/\/|[\w]+\/)/,
+    bringToFront: function(w){
+        Control.Window.windows = Control.Window.windows.without(w);
+        Control.Window.windows.push(w);
+        Control.Window.windows.each(function(w,i){
+            var z_index = Control.Window.baseZIndex + i;
+            w.container.setStyle({
+                zIndex: z_index
+            });
+            if(w.isOpen){
+                if(w.iFrameShim)
+                w.updateIFrameShimZIndex();
+            }
+            if(w.options.draggable)
+                w.draggable.options.zindex = z_index;
+        });
+    },
+    open: function(container,options){
+        var w = new Control.Window(container,options);
+        w.open();
+        return w;
+    },
+    //protected
+    initialZIndexForWindow: function(w){
+        return Control.Window.baseZIndex + (Control.Window.windows.length - 1);
+    }
 });
 Object.Event.extend(Control.Window);
 
 //this is the observer for both Resizables and Draggables
 Control.Window.LayoutUpdateObserver = Class.create({
-	initialize: function(w,observer){
-		this.w = w;
-		this.element = $(w.container);
-		this.observer = observer;
-	},
-	onStart: Prototype.emptyFunction,
-	onEnd: function(event_name,instance){
-		if(instance.element == this.element &amp;&amp; this.iFrameShim)
-			this.w.updateIFrameShimZIndex();
-	},
-	onResize: function(event_name,instance){
-		if(instance.element == this.element)
-			this.observer(this.element);
-	},
-	onDrag: function(event_name,instance){
-		if(instance.element == this.element)
-			this.observer(this.element);
-	}
+    initialize: function(w,observer){
+        this.w = w;
+        this.element = $(w.container);
+        this.observer = observer;
+    },
+    onStart: Prototype.emptyFunction,
+    onEnd: function(event_name,instance){
+        if(instance.element == this.element &amp;&amp; this.iFrameShim)
+            this.w.updateIFrameShimZIndex();
+    },
+    onResize: function(event_name,instance){
+        if(instance.element == this.element)
+            this.observer(this.element);
+    },
+    onDrag: function(event_name,instance){
+        if(instance.element == this.element)
+            this.observer(this.element);
+    }
 });
 
 //overlay for Control.Modal
 Control.Overlay = {
-	id: 'control_overlay',
-	loaded: false,
-	container: false,
-	lastOpacity: 0,
-	styles: {
-		position: 'fixed',
-		top: 0,
-		left: 0,
-		width: '100%',
-		height: '100%',
-		zIndex: 9998
-	},
-	ieStyles: {
-		position: 'absolute',
-		top: 0,
-		left: 0,
-		zIndex: 9998
-	},
-	effects: {
-		fade: false,
-		appear: false
-	},
-	load: function(){
-		if(Control.Overlay.loaded)
-			return false;
-		Control.Overlay.loaded = true;
-		Control.Overlay.container = new Element('div',{
-			id: Control.Overlay.id
-		});
-		$(document.body).insert(Control.Overlay.container);
-		if(Prototype.Browser.IE){
-			Control.Overlay.container.setStyle(Control.Overlay.ieStyles);
-			Event.observe(window,'scroll',Control.Overlay.positionOverlay);
-			Event.observe(window,'resize',Control.Overlay.positionOverlay);
-			Control.Overlay.observe('beforeShow',Control.Overlay.positionOverlay);
-		}else
-			Control.Overlay.container.setStyle(Control.Overlay.styles);
-		Control.Overlay.iFrameShim = new IframeShim();
-		Control.Overlay.iFrameShim.hide();
-		Event.observe(window,'resize',Control.Overlay.positionIFrameShim);
-		Control.Overlay.container.hide();
-		return true;
-	},
-	unload: function(){
-		if(!Control.Overlay.loaded)
-			return false;
-		Event.stopObserving(window,'resize',Control.Overlay.positionOverlay);
-		Control.Overlay.stopObserving('beforeShow',Control.Overlay.positionOverlay);
-		Event.stopObserving(window,'resize',Control.Overlay.positionIFrameShim);
-		Control.Overlay.iFrameShim.destroy();
-		Control.Overlay.container.remove();
-		Control.Overlay.loaded = false;
-		return true;
-	},
-	show: function(opacity,fade){
-		if(Control.Overlay.notify('beforeShow') === false)
-			return false;
-		Control.Overlay.lastOpacity = opacity;
-		Control.Overlay.positionIFrameShim();
-		Control.Overlay.iFrameShim.show();
-		if(fade){
-			if(typeof(Effect) == &quot;undefined&quot;)
-				throw &quot;Control.Window requires effects.js to be loaded.&quot;
-			if(Control.Overlay.effects.fade)
-				Control.Overlay.effects.fade.cancel();
-			Control.Overlay.effects.appear = new Effect.Appear(Control.Overlay.container,{
-				queue: {
-					position: 'end',
-					scope: 'Control.Overlay'
-				},
-				afterFinish: function(){
-					Control.Overlay.notify('afterShow');
-				},
-				from: 0,
-				to: Control.Overlay.lastOpacity,
-				duration: (fade === true ? 0.75 : fade) / 2
-			});
-		}else{
-			Control.Overlay.container.setStyle({
-				opacity: opacity || 1
-			});
-			Control.Overlay.container.show();
-			Control.Overlay.notify('afterShow');
-		}
-		return true;
-	},
-	hide: function(fade){
-		if(Control.Overlay.notify('beforeHide') === false)
-			return false;
-		if(Control.Overlay.effects.appear)
-			Control.Overlay.effects.appear.cancel();
-		Control.Overlay.iFrameShim.hide();
-		if(fade){
-			Control.Overlay.effects.fade = new Effect.Fade(Control.Overlay.container,{
-				queue: {
-					position: 'front',
-					scope: 'Control.Overlay'
-				},
-				afterFinish: function(){
-					Control.Overlay.notify('afterHide');
-				},
-				from: Control.Overlay.lastOpacity,
-				to: 0,
-				duration: (fade === true ? 0.75 : fade) / 2
-			});
-		}else{
-			Control.Overlay.container.hide();
-			Control.Overlay.notify('afterHide');
-		}
-		return true;
-	},
-	positionIFrameShim: function(){
-		if(Control.Overlay.container.visible())
-			Control.Overlay.iFrameShim.positionUnder(Control.Overlay.container);
-	},
-	//IE only
-	positionOverlay: function(){
-		Control.Overlay.container.setStyle({
-			width: document.body.clientWidth + 'px',
-			height: document.body.clientHeight + 'px'
-		});
-	}
+    id: 'control_overlay',
+    loaded: false,
+    container: false,
+    lastOpacity: 0,
+    styles: {
+        position: 'fixed',
+        top: 0,
+        left: 0,
+        width: '100%',
+        height: '100%',
+        zIndex: 9998
+    },
+    ieStyles: {
+        position: 'absolute',
+        top: 0,
+        left: 0,
+        zIndex: 9998
+    },
+    effects: {
+        fade: false,
+        appear: false
+    },
+    load: function(){
+        if(Control.Overlay.loaded)
+            return false;
+        Control.Overlay.loaded = true;
+        Control.Overlay.container = new Element('div',{
+            id: Control.Overlay.id
+        });
+        $(document.body).insert(Control.Overlay.container);
+        if(Prototype.Browser.IE){
+            Control.Overlay.container.setStyle(Control.Overlay.ieStyles);
+            Event.observe(window,'scroll',Control.Overlay.positionOverlay);
+            Event.observe(window,'resize',Control.Overlay.positionOverlay);
+            Control.Overlay.observe('beforeShow',Control.Overlay.positionOverlay);
+        }else
+            Control.Overlay.container.setStyle(Control.Overlay.styles);
+        Control.Overlay.iFrameShim = new IframeShim();
+        Control.Overlay.iFrameShim.hide();
+        Event.observe(window,'resize',Control.Overlay.positionIFrameShim);
+        Control.Overlay.container.hide();
+        return true;
+    },
+    unload: function(){
+        if(!Control.Overlay.loaded)
+            return false;
+        Event.stopObserving(window,'resize',Control.Overlay.positionOverlay);
+        Control.Overlay.stopObserving('beforeShow',Control.Overlay.positionOverlay);
+        Event.stopObserving(window,'resize',Control.Overlay.positionIFrameShim);
+        Control.Overlay.iFrameShim.destroy();
+        Control.Overlay.container.remove();
+        Control.Overlay.loaded = false;
+        return true;
+    },
+    show: function(opacity,fade){
+        if(Control.Overlay.notify('beforeShow') === false)
+            return false;
+        Control.Overlay.lastOpacity = opacity;
+        Control.Overlay.positionIFrameShim();
+        Control.Overlay.iFrameShim.show();
+        if(fade){
+            if(typeof(Effect) == &quot;undefined&quot;)
+                throw &quot;Control.Window requires effects.js to be loaded.&quot;
+            if(Control.Overlay.effects.fade)
+                Control.Overlay.effects.fade.cancel();
+            Control.Overlay.effects.appear = new Effect.Appear(Control.Overlay.container,{
+                queue: {
+                    position: 'end',
+                    scope: 'Control.Overlay'
+                },
+                afterFinish: function(){
+                    Control.Overlay.notify('afterShow');
+                },
+                from: 0,
+                to: Control.Overlay.lastOpacity,
+                duration: (fade === true ? 0.75 : fade) / 2
+            });
+        }else{
+            Control.Overlay.container.setStyle({
+                opacity: opacity || 1
+            });
+            Control.Overlay.container.show();
+            Control.Overlay.notify('afterShow');
+        }
+        return true;
+    },
+    hide: function(fade){
+        if(Control.Overlay.notify('beforeHide') === false)
+            return false;
+        if(Control.Overlay.effects.appear)
+            Control.Overlay.effects.appear.cancel();
+        Control.Overlay.iFrameShim.hide();
+        if(fade){
+            Control.Overlay.effects.fade = new Effect.Fade(Control.Overlay.container,{
+                queue: {
+                    position: 'front',
+                    scope: 'Control.Overlay'
+                },
+                afterFinish: function(){
+                    Control.Overlay.notify('afterHide');
+                },
+                from: Control.Overlay.lastOpacity,
+                to: 0,
+                duration: (fade === true ? 0.75 : fade) / 2
+            });
+        }else{
+            Control.Overlay.container.hide();
+            Control.Overlay.notify('afterHide');
+        }
+        return true;
+    },
+    positionIFrameShim: function(){
+        if(Control.Overlay.container.visible())
+            Control.Overlay.iFrameShim.positionUnder(Control.Overlay.container);
+    },
+    //IE only
+    positionOverlay: function(){
+        Control.Overlay.container.setStyle({
+            width: document.body.clientWidth + 'px',
+            height: document.body.clientHeight + 'px'
+        });
+    }
 };
 Object.Event.extend(Control.Overlay);
 
 Control.ToolTip = Class.create(Control.Window,{
-	initialize: function($super,container,tooltip,options){
-		$super(tooltip,Object.extend(Object.extend(Object.clone(Control.ToolTip.defaultOptions),options || {}),{
-			position: 'mouse',
-			hover: container
-		}));
-	}
+    initialize: function($super,container,tooltip,options){
+        $super(tooltip,Object.extend(Object.extend(Object.clone(Control.ToolTip.defaultOptions),options || {}),{
+            position: 'mouse',
+            hover: container
+        }));
+    }
 });
 Object.extend(Control.ToolTip,{
-	defaultOptions: {
-		offsetLeft: 10
-	}
+    defaultOptions: {
+        offsetLeft: 10
+    }
 });
 
 Control.Modal = Class.create(Control.Window,{
-	initialize: function($super,container,options){
-		Control.Modal.InstanceMethods.beforeInitialize.bind(this)();
-		$super(container,Object.extend(Object.clone(Control.Modal.defaultOptions),options || {}));
-	}
+    initialize: function($super,container,options){
+        Control.Modal.InstanceMethods.beforeInitialize.bind(this)();
+        $super(container,Object.extend(Object.clone(Control.Modal.defaultOptions),options || {}));
+    }
 });
 Object.extend(Control.Modal,{
-	defaultOptions: {
-		overlayOpacity: 0.5,
-		closeOnClick: 'overlay'
-	},
-	current: false,
-	open: function(container,options){
-		var modal = new Control.Modal(container,options);
-		modal.open();
-		return modal;
-	},
-	close: function(){
-		if(Control.Modal.current)
-			Control.Modal.current.close();
-	},
-	InstanceMethods: {
-		beforeInitialize: function(){
-			Control.Overlay.load();
-			this.overlayFinishedOpening = false;
-			this.observe('beforeOpen',Control.Modal.Observers.beforeOpen.bind(this));
-			this.observe('afterOpen',Control.Modal.Observers.afterOpen.bind(this));
-			this.observe('afterClose',Control.Modal.Observers.afterClose.bind(this));
-		}
-	},
-	Observers: {
-		beforeOpen: function(){
-			if(!this.overlayFinishedOpening){
-				Control.Overlay.observeOnce('afterShow',function(){
-					this.overlayFinishedOpening = true;
-					this.open();
-				}.bind(this));
-				Control.Overlay.show(this.options.overlayOpacity,this.options.fade ? this.options.fadeDuration : false);
-				throw $break;
-			}else
-			Control.Window.windows.without(this).invoke('close');
-		},
-		afterOpen: function(){
-			Control.Modal.current = this;
-		},
-		afterClose: function(){
-			Control.Overlay.hide(this.options.fade ? this.options.fadeDuration : false);
-			Control.Modal.current = false;
-			this.overlayFinishedOpening = false;
-		}
-	}
+    defaultOptions: {
+        overlayOpacity: 0.5,
+        closeOnClick: 'overlay'
+    },
+    current: false,
+    open: function(container,options){
+        var modal = new Control.Modal(container,options);
+        modal.open();
+        return modal;
+    },
+    close: function(){
+        if(Control.Modal.current)
+            Control.Modal.current.close();
+    },
+    InstanceMethods: {
+        beforeInitialize: function(){
+            Control.Overlay.load();
+            this.overlayFinishedOpening = false;
+            this.observe('beforeOpen',Control.Modal.Observers.beforeOpen.bind(this));
+            this.observe('afterOpen',Control.Modal.Observers.afterOpen.bind(this));
+            this.observe('afterClose',Control.Modal.Observers.afterClose.bind(this));
+        }
+    },
+    Observers: {
+        beforeOpen: function(){
+            if(!this.overlayFinishedOpening){
+                Control.Overlay.observeOnce('afterShow',function(){
+                    this.overlayFinishedOpening = true;
+                    this.open();
+                }.bind(this));
+                Control.Overlay.show(this.options.overlayOpacity,this.options.fade ? this.options.fadeDuration : false);
+                throw $break;
+            }else
+            Control.Window.windows.without(this).invoke('close');
+        },
+        afterOpen: function(){
+            Control.Modal.current = this;
+        },
+        afterClose: function(){
+            Control.Overlay.hide(this.options.fade ? this.options.fadeDuration : false);
+            Control.Modal.current = false;
+            this.overlayFinishedOpening = false;
+        }
+    }
 });
 
 Control.LightBox = Class.create(Control.Window,{
-	initialize: function($super,container,options){
-		this.allImagesLoaded = false;
-		if(options.modal){
-			var options = Object.extend(Object.clone(Control.LightBox.defaultOptions),options || {});
-			options = Object.extend(Object.clone(Control.Modal.defaultOptions),options);
-			options = Control.Modal.InstanceMethods.beforeInitialize.bind(this)(options);
-			$super(container,options);
-		}else
-			$super(container,Object.extend(Object.clone(Control.LightBox.defaultOptions),options || {}));
-		this.hasRemoteContent = this.href &amp;&amp; !this.options.iframe;
-		if(this.hasRemoteContent)
-			this.observe('onRemoteContentLoaded',Control.LightBox.Observers.onRemoteContentLoaded.bind(this));
-		else
-			this.applyImageObservers();
-		this.observe('beforeOpen',Control.LightBox.Observers.beforeOpen.bind(this));
-	},
-	applyImageObservers:function(){
-		var images = this.getImages();
-		this.numberImagesToLoad = images.length;
-		this.numberofImagesLoaded = 0;
-		images.each(function(image){
-			image.observe('load',function(image){
-				++this.numberofImagesLoaded;
-				if(this.numberImagesToLoad == this.numberofImagesLoaded){
-					this.allImagesLoaded = true;
-					this.onAllImagesLoaded();
-				}
-			}.bind(this,image));
-			image.hide();
-		}.bind(this));
-	},
-	onAllImagesLoaded: function(){
-		this.getImages().each(function(image){
-			this.showImage(image);
-		}.bind(this));
-		if(this.hasRemoteContent){
-			if(this.options.indicator)
-				this.hideIndicator();
-			this.finishOpen();
-		}else
-			this.open();
-	},
-	getImages: function(){
-		return this.container.select(Control.LightBox.imageSelector);
-	},
-	showImage: function(image){
-		image.show();
-	}
+    initialize: function($super,container,options){
+        this.allImagesLoaded = false;
+        if(options.modal){
+            var options = Object.extend(Object.clone(Control.LightBox.defaultOptions),options || {});
+            options = Object.extend(Object.clone(Control.Modal.defaultOptions),options);
+            options = Control.Modal.InstanceMethods.beforeInitialize.bind(this)(options);
+            $super(container,options);
+        }else
+            $super(container,Object.extend(Object.clone(Control.LightBox.defaultOptions),options || {}));
+        this.hasRemoteContent = this.href &amp;&amp; !this.options.iframe;
+        if(this.hasRemoteContent)
+            this.observe('onRemoteContentLoaded',Control.LightBox.Observers.onRemoteContentLoaded.bind(this));
+        else
+            this.applyImageObservers();
+        this.observe('beforeOpen',Control.LightBox.Observers.beforeOpen.bind(this));
+    },
+    applyImageObservers:function(){
+        var images = this.getImages();
+        this.numberImagesToLoad = images.length;
+        this.numberofImagesLoaded = 0;
+        images.each(function(image){
+            image.observe('load',function(image){
+                ++this.numberofImagesLoaded;
+                if(this.numberImagesToLoad == this.numberofImagesLoaded){
+                    this.allImagesLoaded = true;
+                    this.onAllImagesLoaded();
+                }
+            }.bind(this,image));
+            image.hide();
+        }.bind(this));
+    },
+    onAllImagesLoaded: function(){
+        this.getImages().each(function(image){
+            this.showImage(image);
+        }.bind(this));
+        if(this.hasRemoteContent){
+            if(this.options.indicator)
+                this.hideIndicator();
+            this.finishOpen();
+        }else
+            this.open();
+    },
+    getImages: function(){
+        return this.container.select(Control.LightBox.imageSelector);
+    },
+    showImage: function(image){
+        image.show();
+    }
 });
 Object.extend(Control.LightBox,{
-	imageSelector: 'img',
-	defaultOptions: {},
-	Observers: {
-		beforeOpen: function(){
-			if(!this.hasRemoteContent &amp;&amp; !this.allImagesLoaded)
-				throw $break;
-		},
-		onRemoteContentLoaded: function(){
-			this.applyImageObservers();
-			if(!this.allImagesLoaded)
-				throw $break;
-		}
-	}
+    imageSelector: 'img',
+    defaultOptions: {},
+    Observers: {
+        beforeOpen: function(){
+            if(!this.hasRemoteContent &amp;&amp; !this.allImagesLoaded)
+                throw $break;
+        },
+        onRemoteContentLoaded: function(){
+            this.applyImageObservers();
+            if(!this.allImagesLoaded)
+                throw $break;
+        }
+    }
 });</diff>
      <filename>src/window.js</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>199e7ff8436e74828f9cb96ab7556e8d44e2d290</id>
    </parent>
  </parents>
  <author>
    <name>smith</name>
    <email>nlloyds@gmail.com</email>
  </author>
  <url>http://github.com/syntacticx/livepipe.net-documentation/commit/f4bfdc89b2e8f7296cb66c56a6328b3bb97c8a4e</url>
  <id>f4bfdc89b2e8f7296cb66c56a6328b3bb97c8a4e</id>
  <committed-date>2009-10-24T11:51:13-07:00</committed-date>
  <authored-date>2009-10-24T11:51:13-07:00</authored-date>
  <message>updated livepipe</message>
  <tree>1add429bf96f8ff3342edebd65927f1776911d9b</tree>
  <committer>
    <name>smith</name>
    <email>nlloyds@gmail.com</email>
  </committer>
</commit>
