<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -2,8 +2,8 @@
 // Returns whether or not a result set has results in it
 jQuery.fn.onPage = function() { 
   return this.size() &gt; 0;
-} 
+};
 
 jQuery.fn.notOnPage = function() { 
   return this.size() == 0;
-} 
+};</diff>
      <filename>public/javascripts/jquery.ext/jquery.onPage.js</filename>
    </modified>
    <modified>
      <diff>@@ -7,39 +7,6 @@
     jobber_admin_url: &quot;&quot;,
     job_id: &quot;&quot;,
     
-    FixPng: function()
-    {
-      var arVersion = navigator.appVersion.split(&quot;MSIE&quot;);
-      var version = parseFloat(arVersion[1]);
-
-      if ((version &gt;= 5.5) &amp;&amp; (document.body.filters)) 
-      {
-         for(var i=0; i&lt;document.images.length; i++)
-         {
-            var img = document.images[i];
-            var imgName = img.src.toUpperCase();
-
-            if (imgName == this.jobber_url.toUpperCase() + &quot;IMG/BT-RSS.PNG&quot;)
-            {
-               var imgID = (img.id) ? &quot;id='&quot; + img.id + &quot;' &quot; : &quot;&quot;;
-               var imgClass = (img.className) ? &quot;class='&quot; + img.className + &quot;' &quot; : &quot;&quot;;
-               var imgTitle = (img.title) ? &quot;title='&quot; + img.title + &quot;' &quot; : &quot;title='&quot; + img.alt + &quot;' &quot;;
-               var imgStyle = &quot;display:inline-block;&quot; + img.style.cssText;
-               if (img.align == &quot;left&quot;) imgStyle = &quot;float:left;&quot; + imgStyle;
-               if (img.align == &quot;right&quot;) imgStyle = &quot;float:right;&quot; + imgStyle;
-               if (img.parentElement.href) imgStyle = &quot;cursor:hand;&quot; + imgStyle;
-               var strNewHTML = &quot;&lt;span &quot; + imgID + imgClass + imgTitle;
-               strNewHTML += &quot; style=\&quot;&quot; + &quot;width:&quot; + img.width + &quot;px; height:&quot; + img.height + &quot;px;&quot; + imgStyle + &quot;;&quot;;
-               strNewHTML += &quot;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader&quot;;
-               strNewHTML += &quot;(src=\'&quot; + img.src + &quot;\', sizingMethod='scale');\&quot;&gt;&lt;/span&gt;&quot;;
-               img.outerHTML = strNewHTML;
-               i = i - 1;
-            }
-         }
-      }
-
-    },
-    
     HandleLocationOutside: function()
     {
       if($(&quot;#outside_location&quot;).is(&quot;:visible&quot;))</diff>
      <filename>public/javascripts/min/common.js</filename>
    </modified>
    <modified>
      <diff>@@ -22,6 +22,37 @@ $j(document).ready(function() {
   
 });
 
+/* ---- Compressing ./public/javascripts/components/categories.js ----- */
+$j(document).ready(function() {
+    $j(&quot;div.categoryHandle&quot;).mousedown(function() {
+        $j(this).fadeTo(500, 0.4).addClass('draggingItem').get(0);
+    });
+    $j(&quot;div.categoryHandle&quot;).mouseup(function() {
+        $j(this).fadeTo(500,1).removeClass('draggingItem');
+    });
+});
+
+function showOverlay(element) {
+    var el = document.getElementById('overlay');
+    var elTo = document.getElementById(element);
+    if (!elTo) {
+        return;
+    }
+    var sz = elTo.positionedOffset(elTo);
+    
+    if (element != &quot;categoriesContainer&quot;) {
+        var tt = document.getElementById(&quot;categoriesContainer&quot;).positionedOffset(elTo);    
+        el.style.top = tt.top + sz.top + 'px';
+        el.style.left = tt.left + sz.left + 'px';
+    } else {
+        el.style.top = sz.top + 'px';
+        el.style.left = sz.left + 'px';
+    }
+    el.style.width = elTo.offsetWidth + 'px';
+    el.style.height = elTo.offsetHeight + 'px';
+    el.style.display = 'block';
+}
+
 /* ---- Compressing ./public/javascripts/components/flash.js ----- */
 $j(document).ready(function() {
   $j(&quot;.flash a.close-text&quot;).click(function() {</diff>
      <filename>public/javascripts/min/components.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,1151 +1,161 @@
-/* ---- Compressing ./public/javascripts/jquery.ext/dimensions.js ----- */
-/*
- * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
- * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
- *
- * $LastChangedDate: 2007-03-27 23:29:43 +0200 (Di, 27 Mrz 2007) $
- * $Rev: 1601 $
- */
-
-jQuery.fn._height = jQuery.fn.height;
-jQuery.fn._width  = jQuery.fn.width;
-
-/**
- * If used on document, returns the document's height (innerHeight)
- * If used on window, returns the viewport's (window) height
- * See core docs on height() to see what happens when used on an element.
- *
- * @example $(&quot;#testdiv&quot;).height()
- * @result 200
- *
- * @example $(document).height()
- * @result 800
- *
- * @example $(window).height()
- * @result 400
- *
- * @name height
- * @type Object
- * @cat Plugins/Dimensions
- */
-jQuery.fn.height = function() {
-	if ( this[0] == window )
-		return self.innerHeight ||
-			jQuery.boxModel &amp;&amp; document.documentElement.clientHeight ||
-			document.body.clientHeight;
-
-	if ( this[0] == document )
-		return Math.max( document.body.scrollHeight, document.body.offsetHeight );
-
-	return this._height(arguments[0]);
-};
-
-/**
- * If used on document, returns the document's width (innerWidth)
- * If used on window, returns the viewport's (window) width
- * See core docs on height() to see what happens when used on an element.
- *
- * @example $(&quot;#testdiv&quot;).width()
- * @result 200
- *
- * @example $(document).width()
- * @result 800
- *
- * @example $(window).width()
- * @result 400
- *
- * @name width
- * @type Object
- * @cat Plugins/Dimensions
- */
-jQuery.fn.width = function() {
-	if ( this[0] == window )
-		return self.innerWidth ||
-			jQuery.boxModel &amp;&amp; document.documentElement.clientWidth ||
-			document.body.clientWidth;
-
-	if ( this[0] == document )
-		return Math.max( document.body.scrollWidth, document.body.offsetWidth );
-
-	return this._width(arguments[0]);
-};
-
-/**
- * Returns the inner height value (without border) for the first matched element.
- * If used on document, returns the document's height (innerHeight)
- * If used on window, returns the viewport's (window) height
- *
- * @example $(&quot;#testdiv&quot;).innerHeight()
- * @result 800
- *
- * @name innerHeight
- * @type Number
- * @cat Plugins/Dimensions
- */
-jQuery.fn.innerHeight = function() {
-	return this[0] == window || this[0] == document ?
-		this.height() :
-		this.css('display') != 'none' ?
-		 	this[0].offsetHeight - (parseInt(this.css(&quot;borderTopWidth&quot;)) || 0) - (parseInt(this.css(&quot;borderBottomWidth&quot;)) || 0) :
-			this.height() + (parseInt(this.css(&quot;paddingTop&quot;)) || 0) + (parseInt(this.css(&quot;paddingBottom&quot;)) || 0);
-};
-
-/**
- * Returns the inner width value (without border) for the first matched element.
- * If used on document, returns the document's Width (innerWidth)
- * If used on window, returns the viewport's (window) width
- *
- * @example $(&quot;#testdiv&quot;).innerWidth()
- * @result 1000
- *
- * @name innerWidth
- * @type Number
- * @cat Plugins/Dimensions
- */
-jQuery.fn.innerWidth = function() {
-	return this[0] == window || this[0] == document ?
-		this.width() :
-		this.css('display') != 'none' ?
-			this[0].offsetWidth - (parseInt(this.css(&quot;borderLeftWidth&quot;)) || 0) - (parseInt(this.css(&quot;borderRightWidth&quot;)) || 0) :
-			this.height() + (parseInt(this.css(&quot;paddingLeft&quot;)) || 0) + (parseInt(this.css(&quot;paddingRight&quot;)) || 0);
-};
-
-/**
- * Returns the outer height value (including border) for the first matched element.
- * Cannot be used on document or window.
- *
- * @example $(&quot;#testdiv&quot;).outerHeight()
- * @result 1000
- *
- * @name outerHeight
- * @type Number
- * @cat Plugins/Dimensions
- */
-jQuery.fn.outerHeight = function() {
-	return this[0] == window || this[0] == document ?
-		this.height() :
-		this.css('display') != 'none' ?
-			this[0].offsetHeight :
-			this.height() + (parseInt(this.css(&quot;borderTopWidth&quot;)) || 0) + (parseInt(this.css(&quot;borderBottomWidth&quot;)) || 0)
-				+ (parseInt(this.css(&quot;paddingTop&quot;)) || 0) + (parseInt(this.css(&quot;paddingBottom&quot;)) || 0);
-};
-
-/**
- * Returns the outer width value (including border) for the first matched element.
- * Cannot be used on document or window.
- *
- * @example $(&quot;#testdiv&quot;).outerWidth()
- * @result 1000
- *
- * @name outerWidth
- * @type Number
- * @cat Plugins/Dimensions
- */
-jQuery.fn.outerWidth = function() {
-	return this[0] == window || this[0] == document ?
-		this.width() :
-		this.css('display') != 'none' ?
-			this[0].offsetWidth :
-			this.height() + (parseInt(this.css(&quot;borderLeftWidth&quot;)) || 0) + (parseInt(this.css(&quot;borderRightWidth&quot;)) || 0)
-				+ (parseInt(this.css(&quot;paddingLeft&quot;)) || 0) + (parseInt(this.css(&quot;paddingRight&quot;)) || 0);
-};
-
-/**
- * Returns how many pixels the user has scrolled to the right (scrollLeft).
- * Works on containers with overflow: auto and window/document.
- *
- * @example $(&quot;#testdiv&quot;).scrollLeft()
- * @result 100
- *
- * @name scrollLeft
- * @type Number
- * @cat Plugins/Dimensions
- */
-jQuery.fn.scrollLeft = function() {
-	if ( this[0] == window || this[0] == document )
-		return self.pageXOffset ||
-			jQuery.boxModel &amp;&amp; document.documentElement.scrollLeft ||
-			document.body.scrollLeft;
-
-	return this[0].scrollLeft;
-};
-
-/**
- * Returns how many pixels the user has scrolled to the bottom (scrollTop).
- * Works on containers with overflow: auto and window/document.
- *
- * @example $(&quot;#testdiv&quot;).scrollTop()
- * @result 100
- *
- * @name scrollTop
- * @type Number
- * @cat Plugins/Dimensions
- */
-jQuery.fn.scrollTop = function() {
-	if ( this[0] == window || this[0] == document )
-		return self.pageYOffset ||
-			jQuery.boxModel &amp;&amp; document.documentElement.scrollTop ||
-			document.body.scrollTop;
-
-	return this[0].scrollTop;
-};
-
-/**
- * Returns the location of the element in pixels from the top left corner of the viewport.
- *
- * For accurate readings make sure to use pixel values for margins, borders and padding.
- *
- * @example $(&quot;#testdiv&quot;).offset()
- * @result { top: 100, left: 100, scrollTop: 10, scrollLeft: 10 }
- *
- * @example $(&quot;#testdiv&quot;).offset({ scroll: false })
- * @result { top: 90, left: 90 }
- *
- * @example var offset = {}
- * $(&quot;#testdiv&quot;).offset({ scroll: false }, offset)
- * @result offset = { top: 90, left: 90 }
- *
- * @name offset
- * @param Object options A hash of options describing what should be included in the final calculations of the offset.
- *                       The options include:
- *                           margin: Should the margin of the element be included in the calculations? True by default.
- *                                   If set to false the margin of the element is subtracted from the total offset.
- *                           border: Should the border of the element be included in the calculations? True by default.
- *                                   If set to false the border of the element is subtracted from the total offset.
- *                           padding: Should the padding of the element be included in the calculations? False by default.
- *                                    If set to true the padding of the element is added to the total offset.
- *                           scroll: Should the scroll offsets of the parent elements be included in the calculations?
- *                                   True by default. When true, it adds the total scroll offsets of all parents to the
- *                                   total offset and also adds two properties to the returned object, scrollTop and
- *                                   scrollLeft. If set to false the scroll offsets of parent elements are ignored.
- *                                   If scroll offsets are not needed, set to false to get a performance boost.
- * @param Object returnObject An object to store the return value in, so as not to break the chain. If passed in the
- *                            chain will not be broken and the result will be assigned to this object.
- * @type Object
- * @cat Plugins/Dimensions
- * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
- */
-jQuery.fn.offset = function(options, returnObject) {
-	var x = 0, y = 0, elem = this[0], parent = this[0], absparent=false, relparent=false, op, sl = 0, st = 0, options = jQuery.extend({ margin: true, border: true, padding: false, scroll: true }, options || {});
-	do {
-		x += parent.offsetLeft || 0;
-		y += parent.offsetTop  || 0;
-
-		// Mozilla and IE do not add the border
-		if (jQuery.browser.mozilla || jQuery.browser.msie) {
-			// get borders
-			var bt = parseInt(jQuery.css(parent, 'borderTopWidth')) || 0;
-			var bl = parseInt(jQuery.css(parent, 'borderLeftWidth')) || 0;
-
-			// add borders to offset
-			x += bl;
-			y += bt;
-
-			// Mozilla removes the border if the parent has overflow property other than visible
-			if (jQuery.browser.mozilla &amp;&amp; parent != elem &amp;&amp; jQuery.css(parent, 'overflow') != 'visible') {
-				x += bl;
-				y += bt;
-			}
-			
-			// Mozilla does not include the border on body if an element isn't positioned absolute and is without an absolute parent
-			if (jQuery.css(parent, 'position') == 'absolute') absparent = true;
-			// IE does not include the border on the body if an element is position static and without an absolute or relative parent
-			if (jQuery.css(parent, 'position') == 'relative') relparent = true;
-		}
-
-		if (options.scroll) {
-			// Need to get scroll offsets in-between offsetParents
-			op = parent.offsetParent;
-			do {
-				sl += parent.scrollLeft || 0;
-				st += parent.scrollTop  || 0;
-
-				parent = parent.parentNode;
-
-				// Mozilla removes the border if the parent has overflow property other than visible
-				if (jQuery.browser.mozilla &amp;&amp; parent != elem &amp;&amp; parent != op &amp;&amp; jQuery.css(parent, 'overflow') != 'visible') {
-					x += parseInt(jQuery.css(parent, 'borderLeftWidth')) || 0;
-					y += parseInt(jQuery.css(parent, 'borderTopWidth')) || 0;
-				}
-			} while (op &amp;&amp; parent != op);
-		} else
-			parent = parent.offsetParent;
-
-		if (parent &amp;&amp; (parent.tagName.toLowerCase() == 'body' || parent.tagName.toLowerCase() == 'html')) {
-			// Safari and IE Standards Mode doesn't add the body margin for elments positioned with static or relative
-			if ((jQuery.browser.safari || (jQuery.browser.msie &amp;&amp; jQuery.boxModel)) &amp;&amp; jQuery.css(elem, 'position') != 'absolute') {
-				x += parseInt(jQuery.css(parent, 'marginLeft')) || 0;
-				y += parseInt(jQuery.css(parent, 'marginTop'))  || 0;
-			}
-			// Mozilla does not include the border on body if an element isn't positioned absolute and is without an absolute parent
-			// IE does not include the border on the body if an element is positioned static and without an absolute or relative parent
-			if ( (jQuery.browser.mozilla &amp;&amp; !absparent) || 
-			     (jQuery.browser.msie &amp;&amp; jQuery.css(elem, 'position') == 'static' &amp;&amp; (!relparent || !absparent)) ) {
-				x += parseInt(jQuery.css(parent, 'borderLeftWidth')) || 0;
-				y += parseInt(jQuery.css(parent, 'borderTopWidth'))  || 0;
-			}
-			break; // Exit the loop
-		}
-	} while (parent);
-
-	if ( !options.margin) {
-		x -= parseInt(jQuery.css(elem, 'marginLeft')) || 0;
-		y -= parseInt(jQuery.css(elem, 'marginTop'))  || 0;
-	}
-
-	// Safari and Opera do not add the border for the element
-	if ( options.border &amp;&amp; (jQuery.browser.safari || jQuery.browser.opera) ) {
-		x += parseInt(jQuery.css(elem, 'borderLeftWidth')) || 0;
-		y += parseInt(jQuery.css(elem, 'borderTopWidth'))  || 0;
-	} else if ( !options.border &amp;&amp; !(jQuery.browser.safari || jQuery.browser.opera) ) {
-		x -= parseInt(jQuery.css(elem, 'borderLeftWidth')) || 0;
-		y -= parseInt(jQuery.css(elem, 'borderTopWidth'))  || 0;
-	}
-
-	if ( options.padding ) {
-		x += parseInt(jQuery.css(elem, 'paddingLeft')) || 0;
-		y += parseInt(jQuery.css(elem, 'paddingTop'))  || 0;
-	}
-
-	// Opera thinks offset is scroll offset for display: inline elements
-	if (options.scroll &amp;&amp; jQuery.browser.opera &amp;&amp; jQuery.css(elem, 'display') == 'inline') {
-		sl -= elem.scrollLeft || 0;
-		st -= elem.scrollTop  || 0;
-	}
-
-	var returnValue = options.scroll ? { top: y - st, left: x - sl, scrollTop:  st, scrollLeft: sl }
-	                                 : { top: y, left: x };
-
-	if (returnObject) { jQuery.extend(returnObject, returnValue); return this; }
-	else              { return returnValue; }
-};
-
-/* ---- Compressing ./public/javascripts/jquery.ext/jquery.autocomplete.js ----- */
-/*
- * Autocomplete - jQuery plugin 1.0 Alpha
- *
- * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, J&#246;rn Zaefferer
- *
- * Dual licensed under the MIT and GPL licenses:
- *   http://www.opensource.org/licenses/mit-license.php
- *   http://www.gnu.org/licenses/gpl.html
- *
- * Revision: $Id: jquery.autocomplete.js 1729 2007-04-17 20:04:10Z joern $
- *
- */
-
-/*
-TODO
-- add a callback to allow decoding the response
-- fix mustMatch
-- add scrollbars and page down/up, option for height or number of items to be visible without scrolling
-- allow modification of not-last value in multiple-fields
-@option TODO Number size Limit the number of items to show at once. Default: 
-*/
-
-/**
- * Provide autocomplete for text-inputs or textareas.
- *
- * Depends on dimensions plugin's offset method for correct positioning of the select box and bgiframe plugin
- * to fix IE's problem with selects.
- *
- * @example $j(&quot;#input_box&quot;).autocomplete(&quot;my_autocomplete_backend.php&quot;);
- * @before &lt;input id=&quot;input_box&quot; /&gt;
- * @desc Autocomplete a text-input with remote data. For small to giant datasets.
- *
- * When the user starts typing, a request is send to the specified backend (&quot;my_autocomplete_backend.php&quot;),
- * with a GET parameter named q that contains the current value of the input box and a paremeter &quot;limit&quot; with
- * the value specified for the max option.
- *
- * A value of &quot;foo&quot; would result in this request url: my_autocomplete_backend.php?q=foo&amp;limit=10
- *
- * The result must return with one value on each line. The result is presented in the order
- * the backend sends it.
- *
- * @example $j(&quot;#input_box&quot;).autocomplete([&quot;Cologne&quot;, &quot;Berlin&quot;, &quot;Munich&quot;]);
- * @before &lt;input id=&quot;input_box&quot; /&gt;
- * @desc Autcomplete a text-input with local data. For small datasets.
- *
- * @example $.getJSON(&quot;my_backend.php&quot;, function(data) {
- *   $j(&quot;#input_box&quot;).autocomplete(data);
- * });
- * @before &lt;input id=&quot;input_box&quot; /&gt;
- * @desc Autcomplete a text-input with data received via AJAX. For small to medium sized datasets.
- *
- * @example $j(&quot;#mytextarea&quot;).autocomplete([&quot;Cologne&quot;, &quot;Berlin&quot;, &quot;Munich&quot;], {
- *  multiple: true
- * });
- * @before &lt;textarea id=&quot;mytextarea&quot; /&gt;
- * @desc Autcomplete a textarea with local data (for small datasets). Once the user chooses one
- * value, a separator is appended (by default a comma, see multipleSeparator option) and more values
- * are autocompleted.
- *
- * @name autocomplete
- * @cat Plugins/Autocomplete
- * @type jQuery
- * @param String|Array urlOrData Pass either an URL for remote-autocompletion or an array of data for local auto-completion
- * @param Map options Optional settings
- * @option String inputClass This class will be added to the input box. Default: &quot;ac_input&quot;
- * @option String resultsClass The class for the UL that will contain the result items (result items are LI elements). Default: &quot;ac_results&quot;
- * @option String loadingClass The class for the input box while results are being fetched from the server. Default: &quot;ac_loading&quot;
- * @option Number minChars The minimum number of characters a user has to type before the autocompleter activates. Default: 1
- * @option Number delay The delay in milliseconds the autocompleter waits after a keystroke to activate itself. Default: 400 for remote, 10 for local
- * @option Number cacheLength The number of backend query results to store in cache. If set to 1 (the current result), no caching will happen. Do not set below 1. Default: 10
- * @option Boolean matchSubset Whether or not the autocompleter can use a cache for more specific queries. This means that all matches of &quot;foot&quot; are a subset of all matches for &quot;foo&quot;. Usually this is true, and using this options decreases server load and increases performance. Only useful with cacheLength settings bigger then one, like 10. Default: true
- * @option Boolean matchCase Whether or not the comparison is case sensitive. Only important only if you use caching. Default: false
- * @option Boolean matchContains Whether or not the comparison looks inside (i.e. does &quot;ba&quot; match &quot;foo bar&quot;) the search results. Only important if you use caching. Don't mix with autofill. Default: false
- * @option Booolean mustMatch If set to true, the autocompleter will only allow results that are presented by the backend. Note that illegal values result in an empty input box. Default: false
- * @option Object extraParams Extra parameters for the backend. If you were to specify { bar:4 }, the autocompleter would call my_autocomplete_backend.php?q=foo&amp;bar=4 (assuming the input box contains &quot;foo&quot;). Default: {}
- * @option Boolean selectFirst If this is set to true, the first autocomplete value will be automatically selected on tab/return, even if it has not been handpicked by keyboard or mouse action. If there is a handpicked (highlighted) result, that result will take precedence. Default: true
- * @option Function formatItem Provides advanced markup for an item. For each row of results, this function will be called. The returned value will be displayed inside an LI element in the results list. Autocompleter will provide 3 parameters: the results row, the position of the row in the list of results (starting at 1), and the number of items in the list of results. Default: none, assumes that a single row contains a single value.
- * @option Function formatResult Similar to formatResult, but provides the formatting for the value to be put into the input field. Again three arguments: Data, position (starting with one) and total number of data. Default: none, assumes either plain data to use as result or uses the same value as provided by formatItem.
- * @option Boolean multiple Whether to allow more then one autocomplted-value to enter. Default: false
- * @option String multipleSeparator Seperator to put between values when using multiple option. Default: &quot;, &quot;
- * @option Number width Specify a custom width for the select box. Default: width of the input element
- * @option Boolean autoFill Fill the textinput while still selecting a value, replacing the value if more is type or something else is selected. Default: false
- * @option Number max Limit the number of items in the select box. Is also send as a &quot;limit&quot; parameter with a remote request. Default: 10
- */
-
-/**
- * Handle the result of a search event. Is executed when the user selects a value or a
- * programmatic search event is triggered (see search()).
- *
- * You can add and remove (using unbind(&quot;result&quot;)) this event at any time.
- *
- * @example jQuery('input#suggest').result(function(event, data, formatted) {
- *   jQuery(&quot;#result&quot;).html( !data ? &quot;No match!&quot; : &quot;Selected: &quot; + formatted);
- * });
- * @desc Bind a handler to the result event to display the selected value in a #result element.
- *    The first argument is a generic event object, in this case with type &quot;result&quot;.
- *    The second argument refers to the selected data, which can be a plain string value or an array or object.
- *    The third argument is the formatted value that is inserted into the input field.
- *
- * @param Function handler The event handler, gets a default event object as first and
- * 		the selected list item as second argument.
- * @name result
- * @cat Plugins/Autocomplete
- * @type jQuery
- */
-
-/**
- * Trigger a search event. See result(Function) for binding to that event.
- *
- * A search event mimics the same behaviour as when the user selects a value from
- * the list of autocomplete items. You can use it to execute anything that does something
- * with the selected value, beyond simply putting the value into the input and submitting it.
- *
- * @example jQuery('input#suggest').search();
- * @desc Triggers a search event.
- *
- * @name search
- * @cat Plugins/Autocomplete
- * @type jQuery
- */
-
-// * @option Function onSelectItem Called when an item is selected. The autocompleter will specify a single argument, being the LI element selected. This LI element will have an attribute &quot;extra&quot; that contains an array of all cells that the backend specified. Default: none
-
-jQuery.fn.extend({
-	autocomplete: function(urlOrData, options) {
-		var isUrl = typeof urlOrData == &quot;string&quot;;
-		options = jQuery.extend({}, jQuery.Autocompleter.defaults, {
-			url: isUrl ? urlOrData : null,
-			data: isUrl ? null : urlOrData,
-			delay: isUrl ? jQuery.Autocompleter.defaults.delay : 10
-		}, options);
-		return this.each(function() {
-			new jQuery.Autocompleter(this, options);
-		});
-	},
-	result: function(handler) {
-		return this.bind(&quot;result&quot;, handler);
-	},
-	search: function() {
-		return this.trigger(&quot;search&quot;);
-	}
-});
-
-jQuery.Autocompleter = function(input, options) {
-
-	var KEY = {
-		UP: 38,
-		DOWN: 40,
-		DEL: 46,
-		TAB: 9,
-		RETURN: 13,
-		ESC: 27,
-		COMMA: 188
-	};
-
-	// Create jQuery object for input element
-	var $input = $j(input).attr(&quot;autocomplete&quot;, &quot;off&quot;).addClass(options.inputClass);
-
-	var timeout;
-	var previousValue = &quot;&quot;;
-	var cache = jQuery.Autocompleter.Cache(options);
-	var hasFocus = 0;
-	var lastKeyPressCode;
-	var select = jQuery.Autocompleter.Select(options, input, selectCurrent);
-	
-	$input.keydown(function(event) {
-		// track last key pressed
-		lastKeyPressCode = event.keyCode;
-		switch(event.keyCode) {
-		
-			case KEY.UP:
-				event.preventDefault();
-				if ( select.visible() ) {
-					select.prev();
-				} else {
-					onChange(0, true);
-				}
-				break;
-				
-			case KEY.DOWN:
-				event.preventDefault();
-				if ( select.visible() ) {
-					select.next();
-				} else {
-					onChange(0, true);
-				}
-				break;
-			
-			// matches also semicolon
-			case options.multiple &amp;&amp; jQuery.trim(options.multipleSeparator) == &quot;,&quot; &amp;&amp; KEY.COMMA:
-			case KEY.TAB:
-			case KEY.RETURN:
-				if( selectCurrent() ){
-					// make sure to blur off the current field
-					if( !options.multiple )
-						$input.blur();
-					event.preventDefault();
-				}
-				break;
-				
-			case KEY.ESC:
-				select.hide();
-				break;
-				
-			default:
-				clearTimeout(timeout);
-				timeout = setTimeout(onChange, options.delay);
-				break;
-		}
-	}).keypress(function() {
-		// having fun with opera - remove this binding and Opera submits the form when we select an entry via return
-	}).focus(function(){
-		// track whether the field has focus, we shouldn't process any
-		// results if the field no longer has focus
-		hasFocus++;
-	}).blur(function() {
-		hasFocus = 0;
-		hideResults();
-	}).click(function() {
-		// show select when clicking in a focused field
-		if ( hasFocus++ &gt; 1 &amp;&amp; !select.visible() ) {
-			onChange(0, true);
-		}
-	}).bind(&quot;search&quot;, function() {
-		function findValueCallback(q, data) {
-			var result;
-			if( data &amp;&amp; data.length ) {
-				for (var i=0; i &lt; data.length; i++) {
-					if( data[i].result.toLowerCase() == q.toLowerCase() ) {
-						result = data[i];
-						break;
-					}
-				}
-			}
-			$input.trigger(&quot;result&quot;, result &amp;&amp; [result.data, result.value]);
-		}
-		jQuery.each(trimWords($input.val()), function(i, value) {
-			request(value, findValueCallback, findValueCallback);
-		});
-	});
-	
-	hideResultsNow();
-	
-	function selectCurrent() {
-		var selected = select.selected();
-		if( !selected )
-			return false;
-		
-		var v = selected.result;
-		previousValue = v;
-		
-		if ( options.multiple ) {
-			var words = trimWords($input.val());
-			if ( words.length &gt; 1 ) {
-				v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
-			}
-			v += options.multipleSeparator;
-		}
-		
-		$input.val(v);
-		hideResultsNow();
-		$input.trigger(&quot;result&quot;, [selected.data, selected.value]);
-		return true;
-	}
-	
-	function onChange(crap, skipPrevCheck) {
-		if( lastKeyPressCode == KEY.DEL ) {
-			select.hide();
-			return;
-		}
-		
-		var currentValue = $input.val();
-		
-		if ( !skipPrevCheck &amp;&amp; currentValue == previousValue )
-			return;
-		
-		previousValue = currentValue;
-		
-		currentValue = lastWord(currentValue);
-		if ( currentValue.length &gt;= options.minChars) {
-			$input.addClass(options.loadingClass);
-			if (!options.matchCase)
-				currentValue = currentValue.toLowerCase();
-			request(currentValue, receiveData, stopLoading);
-		} else {
-			stopLoading();
-			select.hide();
-		}
-	};
-	
-	function trimWords(value) {
-		if ( !value ) {
-			return [&quot;&quot;];
-		}
-		var words = value.split( jQuery.trim( options.multipleSeparator ) );
-		var result = [];
-		jQuery.each(words, function(i, value) {
-			if ( jQuery.trim(value) )
-				result[i] = jQuery.trim(value);
-		});
-		return result;
-	}
-	
-	function lastWord(value) {
-		if ( !options.multiple )
-			return value;
-		var words = trimWords(value);
-		return words[words.length - 1];
-	}
-	
-	// fills in the input box w/the first match (assumed to be the best match)
-	function autoFill(q, sValue){
-		// autofill in the complete box w/the first match as long as the user hasn't entered in more data
-		// if the last user key pressed was backspace, don't autofill
-		if( options.autoFill &amp;&amp; (lastWord($input.val()).toLowerCase() == q.toLowerCase()) &amp;&amp; lastKeyPressCode != 8 ) {
-			// fill in the value (keep the case the user has typed)
-			$input.val($input.val() + sValue.substring(lastWord(previousValue).length));
-			// select the portion of the value not typed by the user (so the next character will erase)
-			jQuery.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
-		}
-	};
-
-	function hideResults() {
-		clearTimeout(timeout);
-		timeout = setTimeout(hideResultsNow, 200);
-	};
-
-	function hideResultsNow() {
-		select.hide();
-		clearTimeout(timeout);
-		stopLoading();
-		// TODO fix mustMatch...
-		if (options.mustMatch) {
-			if ($input.val() != previousValue) {
-				//selectCurrent();
-			}
-		}
-	};
-
-	function receiveData(q, data) {
-		if ( data &amp;&amp; data.length &amp;&amp; hasFocus ) {
-			stopLoading();
-			select.display(data, q);
-			autoFill(q, data[0].value);
-			select.show();
-		} else {
-			hideResultsNow();
-		}
-	};
-
-	function request(term, success, failure) {
-		if (!options.matchCase)
-			term = term.toLowerCase();
-		var data = cache.load(term);
-		// recieve the cached data
-		if (data &amp;&amp; data.length) {
-			success(term, data);
-		// if an AJAX url has been supplied, try loading the data now
-		} else if( (typeof options.url == &quot;string&quot;) &amp;&amp; (options.url.length &gt; 0) ){
-			jQuery.ajax({
-				url: options.url,
-				data: jQuery.extend({
-					q: lastWord(term),
-					limit: options.max
-				}, options.extraParams),
-				success: function(data) {
-					var parsed = options.parse &amp;&amp; options.parse(data) || parse(data);
-					cache.add(term, parsed);
-					success(term, parsed);
-				}
-			});
-		} else {
-			failure(term);
-		}
-	}
-	
-	function parse(data) {
-		var parsed = [];
-		var rows = data.split(&quot;\n&quot;);
-		for (var i=0; i &lt; rows.length; i++) {
-			var row = jQuery.trim(rows[i]);
-			if (row) {
-				row = row.split(&quot;|&quot;);
-				parsed[parsed.length] = {
-					data: row,
-					value: row[0],
-					result: options.formatResult &amp;&amp; options.formatResult(row) || row[0]
-				};
-			}
-		}
-		return parsed;
-	}
-
-	function stopLoading() {
-		$input.removeClass(options.loadingClass);
-	}
-
-}
-
-jQuery.Autocompleter.defaults = {
-	inputClass: &quot;ac_input&quot;,
-	resultsClass: &quot;ac_results&quot;,
-	loadingClass: &quot;ac_loading&quot;,
-	minChars: 1,
-	delay: 400,
-	matchCase: false,
-	matchSubset: true,
-	matchContains: false,
-	cacheLength: 10,
-	mustMatch: false,
-	extraParams: {},
-	selectFirst: true,
-	max: 10,
-	//size: 10,
-	autoFill: false,
-	width: 0,
-	multiple: false,
-	multipleSeparator: &quot;, &quot;
-};
-
-jQuery.Autocompleter.Cache = function(options) {
-
-	var data = {};
-	var length = 0;
-	
-	function matchSubset(s, sub) {
-		if (!options.matchCase) 
-			s = s.toLowerCase();
-		var i = s.indexOf(sub);
-		if (i == -1) return false;
-		return i == 0 || options.matchContains;
-	};
-	
-	function add(q, value) {
-			if (length &gt; options.cacheLength) {
-				this.flush();
-			}
-			if (!data[q]) {
-				length++;
-			}
-			data[q] = value;
-		}
-	
-	// if there is a data array supplied
-	if( options.data ){
-		var stMatchSets = {},
-			nullData = 0;
-
-		// no url was specified, we need to adjust the cache length to make sure it fits the local data store
-		if( !options.url ) options.cacheLength = 1;
-		
-		stMatchSets[&quot;&quot;] = [];
-
-		// loop through the array and create a lookup structure
-		jQuery.each(options.data, function(i, rawValue) {
-			// if row is a string, make an array otherwise just reference the array
-			
-			
-			value = options.formatItem
-				? options.formatItem(rawValue, i+1, options.data.length)
-				: rawValue;
-			var firstChar = value.charAt(0).toLowerCase();
-			// if no lookup array for this character exists, look it up now
-			if( !stMatchSets[firstChar] )
-				stMatchSets[firstChar] = [];
-			// if the match is a string
-			var row = {
-				value: value,
-				data: rawValue,
-				result: options.formatResult &amp;&amp; options.formatResult(rawValue) || value
-			}
-			
-			stMatchSets[firstChar].push(row);
-			
-			if ( nullData++ &lt; options.max ) {
-				stMatchSets[&quot;&quot;].push(row);
-			}
-			
-		});
-
-		// add the data items to the cache
-		jQuery.each(stMatchSets, function(i, value) {
-			// increase the cache size
-			options.cacheLength++;
-			// add to the cache
-			add(i, value);
-		});
-	}
-	
-	return {
-		flush: function() {
-			data = {};
-			length = 0;
-		},
-		add: add,
-		load: function(q) {
-			if (!options.cacheLength || !length)
-				return null;
-			if (data[q])
-				return data[q];
-			if (options.matchSubset) {
-				for (var i = q.length - 1; i &gt;= options.minChars; i--) {
-					var c = data[q.substr(0, i)];
-					if (c) {
-						var csub = [];
-						jQuery.each(c, function(i, x) {
-							if (matchSubset(x.value, q)) {
-								csub[csub.length] = x;
-							}
-						});
-						return csub;
-					}
-				}
-			}
-			return null;
-		}
-	};
-};
-
-jQuery.Autocompleter.Select = function (options, input, select) {
-	var CLASSES = {
-		ACTIVE: &quot;ac_over&quot;
-	};
-	
-	// Create results
-	var element = jQuery(&quot;&lt;div&gt;&quot;)
-		.hide()
-		.addClass(options.resultsClass)
-		.css(&quot;position&quot;, &quot;absolute&quot;)
-		.appendTo(&quot;body&quot;);
-
-	var list = jQuery(&quot;&lt;ul&gt;&quot;).appendTo(element).mouseover( function(event) {
-		active = jQuery(&quot;li&quot;, list).removeClass(CLASSES.ACTIVE).index(target(event));
-		jQuery(target(event)).addClass(CLASSES.ACTIVE);
-	}).mouseout( function(event) {
-		jQuery(target(event)).removeClass(CLASSES.ACTIVE);
-	}).click(function(event) {
-		jQuery(target(event)).addClass(CLASSES.ACTIVE);
-		select();
-		input.focus();
-		return false;
-	});
-	var listItems,
-		active = -1,
-		data,
-		term = &quot;&quot;;
-		
-	if( options.width &gt; 0 )
-		element.css(&quot;width&quot;, options.width);
-		
-	function target(event) {
-		var element = event.target;
-		while(element.tagName != &quot;LI&quot;)
-			element = element.parentNode;
-		return element;
-	}
-
-	function moveSelect(step) {
-		active += step;
-		wrapSelection();
-		listItems.removeClass(CLASSES.ACTIVE).eq(active).addClass(CLASSES.ACTIVE);
-	};
-	
-	function wrapSelection() {
-		if (active &lt; 0) {
-			active = listItems.size() - 1;
-		} else if (active &gt;= listItems.size()) {
-			active = 0;
-		}
-	}
-	
-	function limitNumberOfItems(available) {
-		return (options.max &gt; 0) &amp;&amp; (options.max &lt; available)
-			? options.max
-			: available;
-	}
-	
-	function dataToDom() {
-		var num = limitNumberOfItems(data.length);
-		for (var i=0; i &lt; num; i++) {
-			if (!data[i])
-				continue;
-			function highlight(value) {
-				return value.replace(new RegExp(&quot;(&quot; + term + &quot;)&quot;, &quot;gi&quot;), &quot;&lt;strong&gt;$1&lt;/strong&gt;&quot;);
-			}
-			jQuery(&quot;&lt;li&gt;&quot;).html( options.formatItem 
-					? highlight(options.formatItem(data[i].data, i+1, num))
-					: highlight(data[i].value) ).appendTo(list);
-		}
-		listItems = list.find(&quot;li&quot;);
-		if ( options.selectFirst ) {
-			listItems.eq(0).addClass(CLASSES.ACTIVE);
-			active = 0;
-		}
-	}
-	
-	return {
-		display: function(d, q) {
-			data = d;
-			term = q;
-			list.empty();
-			dataToDom();
-			list.bgiframe();
-		},
-		next: function() {
-			moveSelect(1);
-		},
-		prev: function() {
-			moveSelect(-1);
-		},
-		hide: function() {
-			element.hide();
-			active = -1;
-		},
-		visible : function() {
-			return element.is(&quot;:visible&quot;);
-		},
-		current: function() {
-			return this.visible() &amp;&amp; (listItems.filter(&quot;.&quot; + CLASSES.ACTIVE)[0] || options.selectFirst &amp;&amp; listItems[0]);
-		},
-		show: function() {
-			// get the position of the input field right now (in case the DOM is shifted)
-			var offset = jQuery(input).offset({scroll: false, border: false});
-			// either use the specified width, or autocalculate based on form element
-			element.css({
-				width: options.width &gt; 0 ? options.width : jQuery(input).width(),
-				//height: jQuery(listItems[0]).height() * options.size,
-				top: offset.top + input.offsetHeight,
-				left: offset.left
-			}).show();
-			//active = -1;
-			//listItems.removeClass(CLASSES.ACTIVE);
-		},
-		selected: function() {
-			return data &amp;&amp; data[active];
-		}
-	};
-}
-
-jQuery.Autocompleter.Selection = function(field, start, end) {
-	if( field.createTextRange ){
-		var selRange = field.createTextRange();
-		selRange.collapse(true);
-		selRange.moveStart(&quot;character&quot;, start);
-		selRange.moveEnd(&quot;character&quot;, end);
-		selRange.select();
-	} else if( field.setSelectionRange ){
-		field.setSelectionRange(start, end);
-	} else {
-		if( field.selectionStart ){
-			field.selectionStart = start;
-			field.selectionEnd = end;
-		}
-	}
-	field.focus();
-};
-
-/* ---- Compressing ./public/javascripts/jquery.ext/jquery.bgiframe.js ----- */
-/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
- * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
- * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
- *
- * $LastChangedDate: 2007-03-19 16:02:41 +0100 (Mo, 19 Mrz 2007) $
- * $Rev: 1546 $
- */
-(function($){$.fn.bgIframe=jQuery.fn.bgiframe=function(s){if(!($.browser.msie&amp;&amp;typeof XMLHttpRequest=='function'))return this;s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&amp;&amp;n.constructor==Number?n+'px':n;},html='&lt;iframe class=&quot;bgiframe&quot;frameborder=&quot;0&quot;tabindex=&quot;-1&quot;src=&quot;'+s.src+'&quot;style=&quot;display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';&quot;/&gt;';return this.each(function(){if(!$('iframe.bgiframe',this)[0])this.insertBefore(document.createElement(html),this.firstChild);});};})(jQuery);
-
-/* ---- Compressing ./public/javascripts/jquery.ext/jquery.example.js ----- */
-/*
- * jQuery Example Plugin 1.3.2
- * Populate form inputs with example text that disappears on focus.
- *
- * e.g.
- *  $('input#name').example('Bob Smith');
- *  $('input[@title]').example(function() {
- *    return $(this).attr('title');
- *  });
- *  $('textarea#message').example('Type your message here', {
- *    class_name: 'example_text',
- *    hide_label: true
- *  });
- *
- * Copyright (c) Paul Mucur (http://mucur.name), 2007-2008.
- * Dual-licensed under the BSD (BSD-LICENSE.txt) and GPL (GPL-LICENSE.txt)
- * licenses.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-(function($) {
-      
-  $.fn.example = function(text, args) {
-    
-    /* Merge the default options with the given arguments. */
-    var options = $.extend({}, $.fn.example.defaults, args);
-    
-    /* Only calculate once whether a callback has been used. */
-    var callback = $.isFunction(text);
-    
-    /* The following event handlers only need to be bound once
-     * per class name. In order to do this, an array of used
-     * class names is stored and checked on each use of the plugin. 
-     * If the class name is in the array then this whole section 
-     * is skipped. If not, the events are bound and the class name 
-     * added to the array.
-     *
-     * As of 1.3.2, the class names are stored as keys in the
-     * array, rather than as elements. This removes the need for
-     * $.inArray().
-     */
-    if (!$.fn.example.bound_class_names[options.class_name]) {
-      
-      /* Because Gecko-based browsers &quot;helpfully&quot; cache form values
-       * but ignore all other attributes such as class, all example
-       * values must be cleared on page unload to prevent them from
-       * being saved.
-       */
-      $(window).unload(function() {
-        $('.' + options.class_name).val('');
-      });
-      
-      /* Clear fields that are still examples before any form is submitted
-       * otherwise those examples will be sent along as well.
-       * 
-       * Prior to 1.3, this would only be bound to forms that were
-       * parents of example fields but this meant that a page with
-       * multiple forms would not work correctly.
-       */
-      $('form').submit(function() {
-        
-        /* Clear only the fields inside this particular form. */
-        $(this).find('.' + options.class_name).val('');
-      });
-      
-      /* Add the class name to the array. */
-      $.fn.example.bound_class_names[options.class_name] = true;      
-    }
-    
-    return this.each(function() {
-      
-      /* Reduce method calls by saving the current jQuery object. */
-      var $this = $(this);
-      
-      /* Initially place the example text in the field if it is empty. */
-      if ($this.val() == '') {
-        $this.addClass(options.class_name);
-        
-        /* The text argument can now be a function; if this is the case,
-         * call it, passing the current element as `this`.
-         */
-        $this.val(callback ? text.call(this) : text);
-      }
-    
-      /* DEPRECATION WARNING: I am considering removing this option.
-       *
-       * If the option is set, hide the associated label (and its line-break
-       * if it has one).
-       */
-      if (options.hide_label) {
-        var label = $('label[@for=' + $this.attr('id') + ']');
-        
-        /* The label and its line break must be hidden separately as
-         * jQuery 1.1 does not support andSelf().
-         */
-        label.next('br').hide();
-        label.hide();
-      }
-    
-      /* Make the example text disappear when someone focuses.
-       *
-       * To determine whether the value of the field is an example or not,
-       * check for the example class name only; comparing the actual value
-       * seems wasteful and can stop people from using example values as real 
-       * input.
-       */
-      $this.focus(function() {
-        
-        /* jQuery 1.1 has no hasClass(), so is() must be used instead. */
-        if ($(this).is('.' + options.class_name)) {
-          $(this).val('');
-          $(this).removeClass(options.class_name);
-        }
-      });
-    
-      /* Make the example text reappear if the input is blank on blurring. */
-      $this.blur(function() {
-        if ($(this).val() == '') {
-          $(this).addClass(options.class_name);
-          
-          /* Re-evaluate the callback function every time the user
-           * blurs the field without entering anything. While this
-           * is not as efficient as caching the value, it allows for
-           * more dynamic applications of the plugin.
-           */
-          $(this).val(callback ? text.call(this) : text);
-        }
-      });
-    });
-  };
-  
-  /* Users can override the defaults for the plugin like so:
-   *
-   *   $.fn.example.defaults.class_name = 'not_example';
-   *   $.fn.example.defaults.hide_label = true;
-   */
-  $.fn.example.defaults = {
-    class_name: 'hint',
-    
-    /* DEPRECATION WARNING: I am considering removing this option. */    
-    hide_label: false
-  };
-  
-  /* All the class names used are stored as keys in the following array. */
-  $.fn.example.bound_class_names = [];
-  
-})(jQuery);
-
-/* ---- Compressing ./public/javascripts/jquery.ext/jquery.form.js ----- */
+/* ---- Compressing ./public/javascripts/jquery.ext/jquery.example.js ----- */
+/*
+ * jQuery Example Plugin 1.3.2
+ * Populate form inputs with example text that disappears on focus.
+ *
+ * e.g.
+ *  $('input#name').example('Bob Smith');
+ *  $('input[@title]').example(function() {
+ *    return $(this).attr('title');
+ *  });
+ *  $('textarea#message').example('Type your message here', {
+ *    class_name: 'example_text',
+ *    hide_label: true
+ *  });
+ *
+ * Copyright (c) Paul Mucur (http://mucur.name), 2007-2008.
+ * Dual-licensed under the BSD (BSD-LICENSE.txt) and GPL (GPL-LICENSE.txt)
+ * licenses.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+(function($) {
+      
+  $.fn.example = function(text, args) {
+    
+    /* Merge the default options with the given arguments. */
+    var options = $.extend({}, $.fn.example.defaults, args);
+    
+    /* Only calculate once whether a callback has been used. */
+    var callback = $.isFunction(text);
+    
+    /* The following event handlers only need to be bound once
+     * per class name. In order to do this, an array of used
+     * class names is stored and checked on each use of the plugin. 
+     * If the class name is in the array then this whole section 
+     * is skipped. If not, the events are bound and the class name 
+     * added to the array.
+     *
+     * As of 1.3.2, the class names are stored as keys in the
+     * array, rather than as elements. This removes the need for
+     * $.inArray().
+     */
+    if (!$.fn.example.bound_class_names[options.class_name]) {
+      
+      /* Because Gecko-based browsers &quot;helpfully&quot; cache form values
+       * but ignore all other attributes such as class, all example
+       * values must be cleared on page unload to prevent them from
+       * being saved.
+       */
+      $(window).unload(function() {
+        $('.' + options.class_name).val('');
+      });
+      
+      /* Clear fields that are still examples before any form is submitted
+       * otherwise those examples will be sent along as well.
+       * 
+       * Prior to 1.3, this would only be bound to forms that were
+       * parents of example fields but this meant that a page with
+       * multiple forms would not work correctly.
+       */
+      $('form').submit(function() {
+        
+        /* Clear only the fields inside this particular form. */
+        $(this).find('.' + options.class_name).val('');
+      });
+      
+      /* Add the class name to the array. */
+      $.fn.example.bound_class_names[options.class_name] = true;      
+    }
+    
+    return this.each(function() {
+      
+      /* Reduce method calls by saving the current jQuery object. */
+      var $this = $(this);
+      
+      /* Initially place the example text in the field if it is empty. */
+      if ($this.val() == '') {
+        $this.addClass(options.class_name);
+        
+        /* The text argument can now be a function; if this is the case,
+         * call it, passing the current element as `this`.
+         */
+        $this.val(callback ? text.call(this) : text);
+      }
+    
+      /* DEPRECATION WARNING: I am considering removing this option.
+       *
+       * If the option is set, hide the associated label (and its line-break
+       * if it has one).
+       */
+      if (options.hide_label) {
+        var label = $('label[@for=' + $this.attr('id') + ']');
+        
+        /* The label and its line break must be hidden separately as
+         * jQuery 1.1 does not support andSelf().
+         */
+        label.next('br').hide();
+        label.hide();
+      }
+    
+      /* Make the example text disappear when someone focuses.
+       *
+       * To determine whether the value of the field is an example or not,
+       * check for the example class name only; comparing the actual value
+       * seems wasteful and can stop people from using example values as real 
+       * input.
+       */
+      $this.focus(function() {
+        
+        /* jQuery 1.1 has no hasClass(), so is() must be used instead. */
+        if ($(this).is('.' + options.class_name)) {
+          $(this).val('');
+          $(this).removeClass(options.class_name);
+        }
+      });
+    
+      /* Make the example text reappear if the input is blank on blurring. */
+      $this.blur(function() {
+        if ($(this).val() == '') {
+          $(this).addClass(options.class_name);
+          
+          /* Re-evaluate the callback function every time the user
+           * blurs the field without entering anything. While this
+           * is not as efficient as caching the value, it allows for
+           * more dynamic applications of the plugin.
+           */
+          $(this).val(callback ? text.call(this) : text);
+        }
+      });
+    });
+  };
+  
+  /* Users can override the defaults for the plugin like so:
+   *
+   *   $.fn.example.defaults.class_name = 'not_example';
+   *   $.fn.example.defaults.hide_label = true;
+   */
+  $.fn.example.defaults = {
+    class_name: 'hint',
+    
+    /* DEPRECATION WARNING: I am considering removing this option. */    
+    hide_label: false
+  };
+  
+  /* All the class names used are stored as keys in the following array. */
+  $.fn.example.bound_class_names = [];
+  
+})(jQuery);
+
+/* ---- Compressing ./public/javascripts/jquery.ext/jquery.form.js ----- */
 /*
  * jQuery Form Plugin
  * version: 2.07 (03/04/2008)
@@ -2015,726 +1025,391 @@ $.fn.select = function(select) {
 };
 
 })(jQuery);
-
-/* ---- Compressing ./public/javascripts/jquery.ext/jquery.history.js ----- */
-/**
- * History/Remote - jQuery plugin for enabling history support and bookmarking
- * @requires jQuery v1.0.3
- *
- * http://stilbuero.de/jquery/history/
- *
- * Copyright (c) 2006 Klaus Hartl (stilbuero.de)
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- *
- * Version: 0.2.3
- */
-
-(function($) { // block scope
-
-/**
- * Initialize the history manager. Subsequent calls will not result in additional history state change 
- * listeners. Should be called soonest when the DOM is ready, because in IE an iframe needs to be added
- * to the body to enable history support.
- *
- * @example $.ajaxHistory.initialize();
- *
- * @param Function callback A single function that will be executed in case there is no fragment
- *                          identifier in the URL, for example after navigating back to the initial
- *                          state. Use to restore such an initial application state.
- *                          Optional. If specified it will overwrite the default action of 
- *                          emptying all containers that are used to load content into.
- * @type undefined
- *
- * @name $.ajaxHistory.initialize()
- * @cat Plugins/History
- * @author Klaus Hartl/klaus.hartl@stilbuero.de
- */
-$.ajaxHistory = new function() {
-
-    var RESET_EVENT = 'historyReset';
-
-    var _currentHash = location.hash;
-    var _intervalId = null;
-    var _observeHistory; // define outside if/else required by Opera
-
-    this.update = function() { }; // empty function body for graceful degradation
-
-    // create custom event for state reset
-    var _defaultReset = function() {
-        $('.remote-output').empty();
-    };
-    $(document).bind(RESET_EVENT, _defaultReset);
-    
-    // TODO fix for Safari 3
-    // if ($.browser.msie)
-    // else if hash != _currentHash
-    // else check history length
-
-    if ($.browser.msie) {
-
-        var _historyIframe, initialized = false; // for IE
-
-        // add hidden iframe
-        $(function() {
-            _historyIframe = $('&lt;iframe style=&quot;display: none;&quot;&gt;&lt;/iframe&gt;').appendTo(document.body).get(0);
-            var iframe = _historyIframe.contentWindow.document;
-            // create initial history entry
-            iframe.open();
-            iframe.close();
-            if (_currentHash &amp;&amp; _currentHash != '#') {
-                iframe.location.hash = _currentHash.replace('#', '');
-            }
-        });
-
-        this.update = function(hash) {
-            _currentHash = hash;
-            var iframe = _historyIframe.contentWindow.document;
-            iframe.open();
-            iframe.close();
-            iframe.location.hash = hash.replace('#', '');
-        };
-
-        _observeHistory = function() {
-            var iframe = _historyIframe.contentWindow.document;
-            var iframeHash = iframe.location.hash;
-            if (iframeHash != _currentHash) {
-                _currentHash = iframeHash;
-                if (iframeHash &amp;&amp; iframeHash != '#') {
-                    // order does matter, set location.hash after triggering the click...
-                    $('a[@href$=&quot;' + iframeHash + '&quot;]').click();
-                    location.hash = iframeHash;
-                } else if (initialized) {
-                    location.hash = '';
-                    $(document).trigger(RESET_EVENT);
-                }
-            }
-            initialized = true;
-        };
-
-    } else if ($.browser.mozilla || $.browser.opera) {
-
-        this.update = function(hash) {
-            _currentHash = hash;
-        };
-
-        _observeHistory = function() {
-            if (location.hash) {
-                if (_currentHash != location.hash) {
-                    _currentHash = location.hash;
-                    $('a[@href$=&quot;' + _currentHash + '&quot;]').click();
-                }
-            } else if (_currentHash) {
-                _currentHash = '';
-                $(document).trigger(RESET_EVENT);
-            }
-        };
-
-    } else if ($.browser.safari) {
-
-        var _backStack, _forwardStack, _addHistory; // for Safari
-
-        // etablish back/forward stacks
-        $(function() {
-            _backStack = [];
-            _backStack.length = history.length;
-            _forwardStack = [];
-
-        });
-        var isFirst = false, initialized = false;
-        _addHistory = function(hash) {
-            _backStack.push(hash);
-            _forwardStack.length = 0; // clear forwardStack (true click occured)
-            isFirst = false;
-        };
-
-        this.update = function(hash) {
-            _currentHash = hash;
-            _addHistory(_currentHash);
-        };
-
-        _observeHistory = function() {
-            var historyDelta = history.length - _backStack.length;
-            if (historyDelta) { // back or forward button has been pushed
-                isFirst = false;
-                if (historyDelta &lt; 0) { // back button has been pushed
-                    // move items to forward stack
-                    for (var i = 0; i &lt; Math.abs(historyDelta); i++) _forwardStack.unshift(_backStack.pop());
-                } else { // forward button has been pushed
-                    // move items to back stack
-                    for (var i = 0; i &lt; historyDelta; i++) _backStack.push(_forwardStack.shift());
-                }
-                var cachedHash = _backStack[_backStack.length - 1];
-                $('a[@href$=&quot;' + cachedHash + '&quot;]').click();
-                _currentHash = location.hash;
-            } else if (_backStack[_backStack.length - 1] == undefined &amp;&amp; !isFirst) {
-                // back button has been pushed to beginning and URL already pointed to hash (e.g. a bookmark)
-                // document.URL doesn't change in Safari
-                if (document.URL.indexOf('#') &gt;= 0) {
-                    $('a[@href$=&quot;' + '#' + document.URL.split('#')[1] + '&quot;]').click();
-                } else if (initialized) {
-                    $(document).trigger(RESET_EVENT);
-                }
-                isFirst = true;
-            }
-            initialized = true;
-        };
-
-    }
-
-    this.initialize = function(callback) {
-        // custom callback to reset app state (no hash in url)
-        if (typeof callback == 'function') {
-            $(document).unbind(RESET_EVENT, _defaultReset).bind(RESET_EVENT, callback);
-        }
-        // look for hash in current URL (not Safari)
-        if (location.hash &amp;&amp; typeof _addHistory == 'undefined') {
-            $('a[@href$=&quot;' + location.hash + '&quot;]').trigger('click');
-        }
-        // start observer
-        if (_observeHistory &amp;&amp; _intervalId == null) {
-            _intervalId = setInterval(_observeHistory, 200); // Safari needs at least 200 ms
-        }
-    };
-
-};
-
-/**
- * Implement Ajax driven links in a completely unobtrusive and accessible manner (also known as &quot;Hijax&quot;)
- * with support for the browser's back/forward navigation buttons and bookmarking.
- *
- * The link's href attribute gets altered to a fragment identifier, such as &quot;#remote-1&quot;, so that the browser's
- * URL gets updated on each click, whereas the former value of that attribute is used to load content via
- * XmlHttpRequest from and update the specified element. If no target element is found, a new div element will be
- * created and appended to the body to load the content into. The link informs the history manager of the 
- * state change on click and adds an entry to the browser's history.
- *
- * jQuery's Ajax implementation adds a custom request header of the form &quot;X-Requested-With: XmlHttpRequest&quot;
- * to any Ajax request so that the called page can distinguish between a standard and an Ajax (XmlHttpRequest)
- * request.
- *
- * @example $('a.remote').remote('#output');
- * @before &lt;a class=&quot;remote&quot; href=&quot;/path/to/content.html&quot;&gt;Update&lt;/a&gt;
- * @result &lt;a class=&quot;remote&quot; href=&quot;#remote-1&quot;&gt;Update&lt;/a&gt;
- * @desc Alter a link of the class &quot;remote&quot; to an Ajax-enhanced link and let it load content from
- *       &quot;/path/to/content.html&quot; via XmlHttpRequest into an element with the id &quot;output&quot;.
- * @example $('a.remote').remote('#output', {hashPrefix: 'chapter'});
- * @before &lt;a class=&quot;remote&quot; href=&quot;/path/to/content.html&quot;&gt;Update&lt;/a&gt;
- * @result &lt;a class=&quot;remote&quot; href=&quot;#chapter-1&quot;&gt;Update&lt;/a&gt;
- * @desc Alter a link of the class &quot;remote&quot; to an Ajax-enhanced link and let it load content from
- *       &quot;/path/to/content.html&quot; via XmlHttpRequest into an element with the id &quot;output&quot;.
- *
- * @param String expr A string containing a CSS selector or basic XPath specifying the element to load
- *                    content into via XmlHttpRequest.
- * @param Object settings An object literal containing key/value pairs to provide optional settings.
- * @option String hashPrefix A String that is used for constructing the hash the link's href attribute
- *                           gets altered to, such as &quot;#remote-1&quot;. Default value: &quot;remote-&quot;.
- * @param Function callback A single function that will be executed when the request is complete. 
- * @type jQuery
- *
- * @name remote
- * @cat Plugins/Remote
- * @author Klaus Hartl/klaus.hartl@stilbuero.de
- */
-
-/**
- * Implement Ajax driven links in a completely unobtrusive and accessible manner (also known as &quot;Hijax&quot;)
- * with support for the browser's back/forward navigation buttons and bookmarking.
- *
- * The link's href attribute gets altered to a fragment identifier, such as &quot;#remote-1&quot;, so that the browser's
- * URL gets updated on each click, whereas the former value of that attribute is used to load content via
- * XmlHttpRequest from and update the specified element. If no target element is found, a new div element will be
- * created and appended to the body to load the content into. The link informs the history manager of the 
- * state change on click and adds an entry to the browser's history.
- *
- * jQuery's Ajax implementation adds a custom request header of the form &quot;X-Requested-With: XmlHttpRequest&quot;
- * to any Ajax request so that the called page can distinguish between a standard and an Ajax (XmlHttpRequest)
- * request.
- *
- * @example $('a.remote').remote( $('#output &gt; div')[0] );
- * @before &lt;a class=&quot;remote&quot; href=&quot;/path/to/content.html&quot;&gt;Update&lt;/a&gt;
- * @result &lt;a class=&quot;remote&quot; href=&quot;#remote-1&quot;&gt;Update&lt;/a&gt;
- * @desc Alter a link of the class &quot;remote&quot; to an Ajax-enhanced link and let it load content from
- *       &quot;/path/to/content.html&quot; via XmlHttpRequest into an element with the id &quot;output&quot;.
- * @example $('a.remote').remote('#output', {hashPrefix: 'chapter'});
- * @before &lt;a class=&quot;remote&quot; href=&quot;/path/to/content.html&quot;&gt;Update&lt;/a&gt;
- * @result &lt;a class=&quot;remote&quot; href=&quot;#chapter-1&quot;&gt;Update&lt;/a&gt;
- * @desc Alter a link of the class &quot;remote&quot; to an Ajax-enhanced link and let it load content from
- *       &quot;/path/to/content.html&quot; via XmlHttpRequest into an element with the id &quot;output&quot;.
- *
- * @param Element elem A DOM element to load content into via XmlHttpRequest.
- * @param Object settings An object literal containing key/value pairs to provide optional settings.
- * @option String hashPrefix A String that is used for constructing the hash the link's href attribute
- *                           gets altered to, such as &quot;#remote-1&quot;. Default value: &quot;remote-&quot;.
- * @param Function callback A single function that will be executed when the request is complete. 
- * @type jQuery
- *
- * @name remote
- * @cat Plugins/Remote
- * @author Klaus Hartl/klaus.hartl@stilbuero.de
- */
-$.fn.remote = function(output, settings, callback) {
-
-    callback = callback || function() {};
-    if (typeof settings == 'function') { // shift arguments
-        callback = settings;
-    }
-    
-    settings = $.extend({
-        hashPrefix: 'remote-'
-    }, settings || {});
-
-    var target = $(output).size() &amp;&amp; $(output) || $('&lt;div&gt;&lt;/div&gt;').appendTo('body');
-    target.addClass('remote-output');
-
-    return this.each(function(i) {
-        var href = this.href, hash = '#' + (this.title &amp;&amp; this.title.replace(/\s/g, '_') || settings.hashPrefix + (i + 1)),
-            a = this;
-        this.href = hash;
-        $(this).click(function(e) {
-            // lock target to prevent double loading in Firefox
-            if (!target['locked']) {
-                // add to history only if true click occured, not a triggered click
-                if (e.clientX) {
-                    $.ajaxHistory.update(hash);
-                }
-                target.load(href, function() {
-                    target['locked'] = null;
-                    callback.apply(a);
-                });
-            }
-        });
-    });
-
-};
-
-/**
- * Provides the ability to use the back/forward navigation buttons in a DHTML application.
- * A change of the application state is reflected by a change of the URL fragment identifier.
- *
- * The link's href attribute needs to point to a fragment identifier within the same resource,
- * although that fragment id does not need to exist. On click the link changes the URL fragment
- * identifier, informs the history manager of the state change and adds an entry to the browser's
- * history.
- *
- * @param Function callback A single function that will be executed as the click handler of the 
- *                          matched element. It will be executed on click (adding an entry to 
- *                          the history) as well as in case the history manager needs to trigger 
- *                          it depending on the value of the URL fragment identifier, e.g. if its 
- *                          current value matches the href attribute of the matched element.
- *                           
- * @type jQuery
- *
- * @name history
- * @cat Plugins/History
- * @author Klaus Hartl/klaus.hartl@stilbuero.de
- */
-$.fn.history = function(callback) {
-    return this.click(function(e) {        
-        // add to history only if true click occured, not a triggered click
-        if (e.clientX) {
-            $.ajaxHistory.update(this.hash);
-        }
-        typeof callback == 'function' &amp;&amp; callback();
-    });
-};
-
-})(jQuery);
-
-/*
-var logger;
-$(function() {
-    logger = $('&lt;div style=&quot;position: fixed; top: 0; overflow: hidden; border: 1px solid; padding: 3px; width: 120px; height: 150px; background: #fff; color: red;&quot;&gt;&lt;/div&gt;').appendTo(document.body);
-});
-function log(m) {    
-    logger.prepend(m + '&lt;br /&gt;');
-};
-*/
-
-
-/* ---- Compressing ./public/javascripts/jquery.ext/jquery.livequery.js ----- */
-/* Copyright (c) 2007 Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
- * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
- * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
- *
- * Version: 1.0.2
- * Requires jQuery 1.1.3+
- * Docs: http://docs.jquery.com/Plugins/livequery
- */
-
-(function($) {
-	
-$.extend($.fn, {
-	livequery: function(type, fn, fn2) {
-		var self = this, q;
-		
-		// Handle different call patterns
-		if ($.isFunction(type))
-			fn2 = fn, fn = type, type = undefined;
-			
-		// See if Live Query already exists
-		$.each( $.livequery.queries, function(i, query) {
-			if ( self.selector == query.selector &amp;&amp; self.context == query.context &amp;&amp;
-				type == query.type &amp;&amp; (!fn || fn.$lqguid == query.fn.$lqguid) &amp;&amp; (!fn2 || fn2.$lqguid == query.fn2.$lqguid) )
-					// Found the query, exit the each loop
-					return (q = query) &amp;&amp; false;
-		});
-		
-		// Create new Live Query if it wasn't found
-		q = q || new $.livequery(this.selector, this.context, type, fn, fn2);
-		
-		// Make sure it is running
-		q.stopped = false;
-		
-		// Run it
-		$.livequery.run( q.id );
-		
-		// Contnue the chain
-		return this;
-	},
-	
-	expire: function(type, fn, fn2) {
-		var self = this;
-		
-		// Handle different call patterns
-		if ($.isFunction(type))
-			fn2 = fn, fn = type, type = undefined;
-			
-		// Find the Live Query based on arguments and stop it
-		$.each( $.livequery.queries, function(i, query) {
-			if ( self.selector == query.selector &amp;&amp; self.context == query.context &amp;&amp; 
-				(!type || type == query.type) &amp;&amp; (!fn || fn.$lqguid == query.fn.$lqguid) &amp;&amp; (!fn2 || fn2.$lqguid == query.fn2.$lqguid) &amp;&amp; !this.stopped )
-					$.livequery.stop(query.id);
-		});
-		
-		// Continue the chain
-		return this;
-	}
-});
-
-$.livequery = function(selector, context, type, fn, fn2) {
-	this.selector = selector;
-	this.context  = context || document;
-	this.type     = type;
-	this.fn       = fn;
-	this.fn2      = fn2;
-	this.elements = [];
-	this.stopped  = false;
-	
-	// The id is the index of the Live Query in $.livequery.queries
-	this.id = $.livequery.queries.push(this)-1;
-	
-	// Mark the functions for matching later on
-	fn.$lqguid = fn.$lqguid || $.livequery.guid++;
-	if (fn2) fn2.$lqguid = fn2.$lqguid || $.livequery.guid++;
-	
-	// Return the Live Query
-	return this;
-};
-
-$.livequery.prototype = {
-	stop: function() {
-		var query = this;
-		
-		if ( this.type )
-			// Unbind all bound events
-			this.elements.unbind(this.type, this.fn);
-		else if (this.fn2)
-			// Call the second function for all matched elements
-			this.elements.each(function(i, el) {
-				query.fn2.apply(el);
-			});
-			
-		// Clear out matched elements
-		this.elements = [];
-		
-		// Stop the Live Query from running until restarted
-		this.stopped = true;
-	},
-	
-	run: function() {
-		// Short-circuit if stopped
-		if ( this.stopped ) return;
-		var query = this;
-		
-		var oEls = this.elements,
-			els  = $(this.selector, this.context),
-			nEls = els.not(oEls);
-		
-		// Set elements to the latest set of matched elements
-		this.elements = els;
-		
-		if (this.type) {
-			// Bind events to newly matched elements
-			nEls.bind(this.type, this.fn);
-			
-			// Unbind events to elements no longer matched
-			if (oEls.length &gt; 0)
-				$.each(oEls, function(i, el) {
-					if ( $.inArray(el, els) &lt; 0 )
-						$.event.remove(el, query.type, query.fn);
-				});
-		}
-		else {
-			// Call the first function for newly matched elements
-			nEls.each(function() {
-				query.fn.apply(this);
-			});
-			
-			// Call the second function for elements no longer matched
-			if ( this.fn2 &amp;&amp; oEls.length &gt; 0 )
-				$.each(oEls, function(i, el) {
-					if ( $.inArray(el, els) &lt; 0 )
-						query.fn2.apply(el);
-				});
-		}
-	}
-};
-
-$.extend($.livequery, {
-	guid: 0,
-	queries: [],
-	queue: [],
-	running: false,
-	timeout: null,
-	
-	checkQueue: function() {
-		if ( $.livequery.running &amp;&amp; $.livequery.queue.length ) {
-			var length = $.livequery.queue.length;
-			// Run each Live Query currently in the queue
-			while ( length-- )
-				$.livequery.queries[ $.livequery.queue.shift() ].run();
-		}
-	},
-	
-	pause: function() {
-		// Don't run anymore Live Queries until restarted
-		$.livequery.running = false;
-	},
-	
-	play: function() {
-		// Restart Live Queries
-		$.livequery.running = true;
-		// Request a run of the Live Queries
-		$.livequery.run();
-	},
-	
-	registerPlugin: function() {
-		$.each( arguments, function(i,n) {
-			// Short-circuit if the method doesn't exist
-			if (!$.fn[n]) return;
-			
-			// Save a reference to the original method
-			var old = $.fn[n];
-			
-			// Create a new method
-			$.fn[n] = function() {
-				// Call the original method
-				var r = old.apply(this, arguments);
-				
-				// Request a run of the Live Queries
-				$.livequery.run();
-				
-				// Return the original methods result
-				return r;
-			}
-		});
-	},
-	
-	run: function(id) {
-		if (id != undefined) {
-			// Put the particular Live Query in the queue if it doesn't already exist
-			if ( $.inArray(id, $.livequery.queue) &lt; 0 )
-				$.livequery.queue.push( id );
-		}
-		else
-			// Put each Live Query in the queue if it doesn't already exist
-			$.each( $.livequery.queries, function(id) {
-				if ( $.inArray(id, $.livequery.queue) &lt; 0 )
-					$.livequery.queue.push( id );
-			});
-		
-		// Clear timeout if it already exists
-		if ($.livequery.timeout) clearTimeout($.livequery.timeout);
-		// Create a timeout to check the queue and actually run the Live Queries
-		$.livequery.timeout = setTimeout($.livequery.checkQueue, 20);
-	},
-	
-	stop: function(id) {
-		if (id != undefined)
-			// Stop are particular Live Query
-			$.livequery.queries[ id ].stop();
-		else
-			// Stop all Live Queries
-			$.each( $.livequery.queries, function(id) {
-				$.livequery.queries[ id ].stop();
-			});
-	}
-});
-
-// Register core DOM manipulation methods
-$.livequery.registerPlugin('append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove');
-
-// Run Live Queries when the Document is ready
-$(function() { $.livequery.play(); });
-
-
-// Save a reference to the original init method
-var init = $.prototype.init;
-
-// Create a new init method that exposes two new properties: selector and context
-$.prototype.init = function(a,c) {
-	// Call the original init and save the result
-	var r = init.apply(this, arguments);
-	
-	// Copy over properties if they exist already
-	if (a &amp;&amp; a.selector)
-		r.context = a.context, r.selector = a.selector;
-		
-	// Set properties
-	if ( typeof a == 'string' )
-		r.context = c || document, r.selector = a;
-	
-	// Return the result
-	return r;
-};
-
-// Give the init function the jQuery prototype for later instantiation (needed after Rev 4091)
-$.prototype.init.prototype = $.prototype;
-	
-})(jQuery);
-
-/* ---- Compressing ./public/javascripts/jquery.ext/jquery.metadata.js ----- */
-/*
- * Metadata - jQuery plugin for parsing metadata from elements
- *
- * Copyright (c) 2006 John Resig, Yehuda Katz, J&#246;rn Zaefferer
- *
- * Dual licensed under the MIT and GPL licenses:
- *   http://www.opensource.org/licenses/mit-license.php
- *   http://www.gnu.org/licenses/gpl.html
- *
- * Revision: $Id: metadata.js 1631 2007-04-05 16:02:19Z joern $
- *
- */
-
-/**
- * Sets the type of metadata to use. Metadata is encoded in JSON, and each property
- * in the JSON will become a property of the element itself.
- *
- * There are three supported types of metadata storage:
- *
- *   attr:  Inside an attribute. The name parameter indicates *which* attribute.
- *          
- *   class: Inside the class attribute, wrapped in curly braces: { }
- *   
- *   elem:  Inside a child element (e.g. a script tag). The
- *          name parameter indicates *which* element.
- *          
- * The metadata for an element is loaded the first time the element is accessed via jQuery.
- *
- * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
- * matched by expr, then redefine the metadata type and run another $(expr) for other elements.
- * 
- * @name $.meta.setType
- *
- * @example &lt;p id=&quot;one&quot; class=&quot;some_class {item_id: 1, item_label: 'Label'}&quot;&gt;This is a p&lt;/p&gt;
- * @before $.meta.setType(&quot;class&quot;)
- * @after $(&quot;#one&quot;).data().item_id == 1; $(&quot;#one&quot;)[0].item_label == &quot;Label&quot;
- * @desc Reads metadata from the class attribute
- * 
- * @example &lt;p id=&quot;one&quot; class=&quot;some_class&quot; data=&quot;{item_id: 1, item_label: 'Label'}&quot;&gt;This is a p&lt;/p&gt;
- * @before $.meta.setType(&quot;attr&quot;, &quot;data&quot;)
- * @after $(&quot;#one&quot;).data().item_id == 1; $(&quot;#one&quot;)[0].item_label == &quot;Label&quot;
- * @desc Reads metadata from a &quot;data&quot; attribute
- * 
- * @example &lt;p id=&quot;one&quot; class=&quot;some_class&quot;&gt;&lt;script&gt;{item_id: 1, item_label: 'Label'}&lt;/script&gt;This is a p&lt;/p&gt;
- * @before $.meta.setType(&quot;elem&quot;, &quot;script&quot;)
- * @after $(&quot;#one&quot;).data().item_id == 1; $(&quot;#one&quot;)[0].item_label == &quot;Label&quot;
- * @desc Reads metadata from a nested script element
- * 
- * @param String type The encoding type
- * @param String name The name of the attribute to be used to get metadata (optional)
- * @cat Plugins/Metadata
- * @descr Sets the type of encoding to be used when loading metadata for the first time
- * @type undefined
- * @see data()
- */
-
-(function($) {
-	// settings
-	$.meta = {
-	  type: &quot;class&quot;,
-	  name: &quot;metadata&quot;,
-	  setType: function(type,name){
-	    this.type = type;
-	    this.name = name;
-	  },
-	  cre: /({.*})/,
-	  single: 'metadata'
-	};
-	
-	// reference to original setArray()
-	var setArray = $.fn.setArray;
-	
-	// define new setArray()
-	$.fn.setArray = function(arr){
-	    return setArray.apply( this, arguments ).each(function(){
-	      if ( this.nodeType == 9 || $.isXMLDoc(this) || this.metaDone ) return;
-	      
-	      var data = &quot;{}&quot;;
-	      
-	      if ( $.meta.type == &quot;class&quot; ) {
-	        var m = $.meta.cre.exec( this.className );
-	        if ( m )
-	          data = m[1];
-	      } else if ( $.meta.type == &quot;elem&quot; ) {
-	      	if( !this.getElementsByTagName ) return;
-	        var e = this.getElementsByTagName($.meta.name);
-	        if ( e.length )
-	          data = $.trim(e[0].innerHTML);
-	      } else if ( this.getAttribute != undefined ) {
-	        var attr = this.getAttribute( $.meta.name );
-	        if ( attr )
-	          data = attr;
-	      }
-	      
-	      if ( !/^{/.test( data ) )
-	        data = &quot;{&quot; + data + &quot;}&quot;;
-	
-	      eval(&quot;data = &quot; + data);
-	
-	      if ( $.meta.single )
-	        this[ $.meta.single ] = data;
-	      else
-	        $.extend( this, data );
-	      
-	      this.metaDone = true;
-	    });
-	};
-	
-	/**
-	 * Returns the metadata object for the first member of the jQuery object.
-	 *
-	 * @name data
-	 * @descr Returns element's metadata object
-	 * @type jQuery
-	 * @cat Plugins/Metadata
-	 */
-	$.fn.data = function() {
-	  return this[0][$.meta.single];
-	};
-})(jQuery);
-
-/* ---- Compressing ./public/javascripts/jquery.ext/jquery.onPage.js ----- */
-
-// Returns whether or not a result set has results in it
-jQuery.fn.onPage = function() { 
-  return this.size() &gt; 0;
-} 
-
-jQuery.fn.notOnPage = function() { 
-  return !this.onPage();
-} 
-
+
+
+/* ---- Compressing ./public/javascripts/jquery.ext/jquery.onPage.js ----- */
+
+// Returns whether or not a result set has results in it
+jQuery.fn.onPage = function() { 
+  return this.size() &gt; 0;
+}
+
+jQuery.fn.notOnPage = function() { 
+  return this.size() == 0;
+}
+
+;
+
+/* ---- Compressing ./public/javascripts/jquery.ext/jquery.livequery.js ----- */
+/* Copyright (c) 2007 Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * Version: 1.0.2
+ * Requires jQuery 1.1.3+
+ * Docs: http://docs.jquery.com/Plugins/livequery
+ */
+
+(function($) {
+	
+$.extend($.fn, {
+	livequery: function(type, fn, fn2) {
+		var self = this, q;
+		
+		// Handle different call patterns
+		if ($.isFunction(type))
+			fn2 = fn, fn = type, type = undefined;
+			
+		// See if Live Query already exists
+		$.each( $.livequery.queries, function(i, query) {
+			if ( self.selector == query.selector &amp;&amp; self.context == query.context &amp;&amp;
+				type == query.type &amp;&amp; (!fn || fn.$lqguid == query.fn.$lqguid) &amp;&amp; (!fn2 || fn2.$lqguid == query.fn2.$lqguid) )
+					// Found the query, exit the each loop
+					return (q = query) &amp;&amp; false;
+		});
+		
+		// Create new Live Query if it wasn't found
+		q = q || new $.livequery(this.selector, this.context, type, fn, fn2);
+		
+		// Make sure it is running
+		q.stopped = false;
+		
+		// Run it
+		$.livequery.run( q.id );
+		
+		// Contnue the chain
+		return this;
+	},
+	
+	expire: function(type, fn, fn2) {
+		var self = this;
+		
+		// Handle different call patterns
+		if ($.isFunction(type))
+			fn2 = fn, fn = type, type = undefined;
+			
+		// Find the Live Query based on arguments and stop it
+		$.each( $.livequery.queries, function(i, query) {
+			if ( self.selector == query.selector &amp;&amp; self.context == query.context &amp;&amp; 
+				(!type || type == query.type) &amp;&amp; (!fn || fn.$lqguid == query.fn.$lqguid) &amp;&amp; (!fn2 || fn2.$lqguid == query.fn2.$lqguid) &amp;&amp; !this.stopped )
+					$.livequery.stop(query.id);
+		});
+		
+		// Continue the chain
+		return this;
+	}
+});
+
+$.livequery = function(selector, context, type, fn, fn2) {
+	this.selector = selector;
+	this.context  = context || document;
+	this.type     = type;
+	this.fn       = fn;
+	this.fn2      = fn2;
+	this.elements = [];
+	this.stopped  = false;
+	
+	// The id is the index of the Live Query in $.livequery.queries
+	this.id = $.livequery.queries.push(this)-1;
+	
+	// Mark the functions for matching later on
+	fn.$lqguid = fn.$lqguid || $.livequery.guid++;
+	if (fn2) fn2.$lqguid = fn2.$lqguid || $.livequery.guid++;
+	
+	// Return the Live Query
+	return this;
+};
+
+$.livequery.prototype = {
+	stop: function() {
+		var query = this;
+		
+		if ( this.type )
+			// Unbind all bound events
+			this.elements.unbind(this.type, this.fn);
+		else if (this.fn2)
+			// Call the second function for all matched elements
+			this.elements.each(function(i, el) {
+				query.fn2.apply(el);
+			});
+			
+		// Clear out matched elements
+		this.elements = [];
+		
+		// Stop the Live Query from running until restarted
+		this.stopped = true;
+	},
+	
+	run: function() {
+		// Short-circuit if stopped
+		if ( this.stopped ) return;
+		var query = this;
+		
+		var oEls = this.elements,
+			els  = $(this.selector, this.context),
+			nEls = els.not(oEls);
+		
+		// Set elements to the latest set of matched elements
+		this.elements = els;
+		
+		if (this.type) {
+			// Bind events to newly matched elements
+			nEls.bind(this.type, this.fn);
+			
+			// Unbind events to elements no longer matched
+			if (oEls.length &gt; 0)
+				$.each(oEls, function(i, el) {
+					if ( $.inArray(el, els) &lt; 0 )
+						$.event.remove(el, query.type, query.fn);
+				});
+		}
+		else {
+			// Call the first function for newly matched elements
+			nEls.each(function() {
+				query.fn.apply(this);
+			});
+			
+			// Call the second function for elements no longer matched
+			if ( this.fn2 &amp;&amp; oEls.length &gt; 0 )
+				$.each(oEls, function(i, el) {
+					if ( $.inArray(el, els) &lt; 0 )
+						query.fn2.apply(el);
+				});
+		}
+	}
+};
+
+$.extend($.livequery, {
+	guid: 0,
+	queries: [],
+	queue: [],
+	running: false,
+	timeout: null,
+	
+	checkQueue: function() {
+		if ( $.livequery.running &amp;&amp; $.livequery.queue.length ) {
+			var length = $.livequery.queue.length;
+			// Run each Live Query currently in the queue
+			while ( length-- )
+				$.livequery.queries[ $.livequery.queue.shift() ].run();
+		}
+	},
+	
+	pause: function() {
+		// Don't run anymore Live Queries until restarted
+		$.livequery.running = false;
+	},
+	
+	play: function() {
+		// Restart Live Queries
+		$.livequery.running = true;
+		// Request a run of the Live Queries
+		$.livequery.run();
+	},
+	
+	registerPlugin: function() {
+		$.each( arguments, function(i,n) {
+			// Short-circuit if the method doesn't exist
+			if (!$.fn[n]) return;
+			
+			// Save a reference to the original method
+			var old = $.fn[n];
+			
+			// Create a new method
+			$.fn[n] = function() {
+				// Call the original method
+				var r = old.apply(this, arguments);
+				
+				// Request a run of the Live Queries
+				$.livequery.run();
+				
+				// Return the original methods result
+				return r;
+			}
+		});
+	},
+	
+	run: function(id) {
+		if (id != undefined) {
+			// Put the particular Live Query in the queue if it doesn't already exist
+			if ( $.inArray(id, $.livequery.queue) &lt; 0 )
+				$.livequery.queue.push( id );
+		}
+		else
+			// Put each Live Query in the queue if it doesn't already exist
+			$.each( $.livequery.queries, function(id) {
+				if ( $.inArray(id, $.livequery.queue) &lt; 0 )
+					$.livequery.queue.push( id );
+			});
+		
+		// Clear timeout if it already exists
+		if ($.livequery.timeout) clearTimeout($.livequery.timeout);
+		// Create a timeout to check the queue and actually run the Live Queries
+		$.livequery.timeout = setTimeout($.livequery.checkQueue, 20);
+	},
+	
+	stop: function(id) {
+		if (id != undefined)
+			// Stop are particular Live Query
+			$.livequery.queries[ id ].stop();
+		else
+			// Stop all Live Queries
+			$.each( $.livequery.queries, function(id) {
+				$.livequery.queries[ id ].stop();
+			});
+	}
+});
+
+// Register core DOM manipulation methods
+$.livequery.registerPlugin('append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove');
+
+// Run Live Queries when the Document is ready
+$(function() { $.livequery.play(); });
+
+
+// Save a reference to the original init method
+var init = $.prototype.init;
+
+// Create a new init method that exposes two new properties: selector and context
+$.prototype.init = function(a,c) {
+	// Call the original init and save the result
+	var r = init.apply(this, arguments);
+	
+	// Copy over properties if they exist already
+	if (a &amp;&amp; a.selector)
+		r.context = a.context, r.selector = a.selector;
+		
+	// Set properties
+	if ( typeof a == 'string' )
+		r.context = c || document, r.selector = a;
+	
+	// Return the result
+	return r;
+};
+
+// Give the init function the jQuery prototype for later instantiation (needed after Rev 4091)
+$.prototype.init.prototype = $.prototype;
+	
+})(jQuery);
+
+/* ---- Compressing ./public/javascripts/jquery.ext/jquery.metadata.js ----- */
+/*
+ * Metadata - jQuery plugin for parsing metadata from elements
+ *
+ * Copyright (c) 2006 John Resig, Yehuda Katz, J&#246;rn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: metadata.js 1631 2007-04-05 16:02:19Z joern $
+ *
+ */
+
+/**
+ * Sets the type of metadata to use. Metadata is encoded in JSON, and each property
+ * in the JSON will become a property of the element itself.
+ *
+ * There are three supported types of metadata storage:
+ *
+ *   attr:  Inside an attribute. The name parameter indicates *which* attribute.
+ *          
+ *   class: Inside the class attribute, wrapped in curly braces: { }
+ *   
+ *   elem:  Inside a child element (e.g. a script tag). The
+ *          name parameter indicates *which* element.
+ *          
+ * The metadata for an element is loaded the first time the element is accessed via jQuery.
+ *
+ * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
+ * matched by expr, then redefine the metadata type and run another $(expr) for other elements.
+ * 
+ * @name $.meta.setType
+ *
+ * @example &lt;p id=&quot;one&quot; class=&quot;some_class {item_id: 1, item_label: 'Label'}&quot;&gt;This is a p&lt;/p&gt;
+ * @before $.meta.setType(&quot;class&quot;)
+ * @after $(&quot;#one&quot;).data().item_id == 1; $(&quot;#one&quot;)[0].item_label == &quot;Label&quot;
+ * @desc Reads metadata from the class attribute
+ * 
+ * @example &lt;p id=&quot;one&quot; class=&quot;some_class&quot; data=&quot;{item_id: 1, item_label: 'Label'}&quot;&gt;This is a p&lt;/p&gt;
+ * @before $.meta.setType(&quot;attr&quot;, &quot;data&quot;)
+ * @after $(&quot;#one&quot;).data().item_id == 1; $(&quot;#one&quot;)[0].item_label == &quot;Label&quot;
+ * @desc Reads metadata from a &quot;data&quot; attribute
+ * 
+ * @example &lt;p id=&quot;one&quot; class=&quot;some_class&quot;&gt;&lt;script&gt;{item_id: 1, item_label: 'Label'}&lt;/script&gt;This is a p&lt;/p&gt;
+ * @before $.meta.setType(&quot;elem&quot;, &quot;script&quot;)
+ * @after $(&quot;#one&quot;).data().item_id == 1; $(&quot;#one&quot;)[0].item_label == &quot;Label&quot;
+ * @desc Reads metadata from a nested script element
+ * 
+ * @param String type The encoding type
+ * @param String name The name of the attribute to be used to get metadata (optional)
+ * @cat Plugins/Metadata
+ * @descr Sets the type of encoding to be used when loading metadata for the first time
+ * @type undefined
+ * @see data()
+ */
+
+(function($) {
+	// settings
+	$.meta = {
+	  type: &quot;class&quot;,
+	  name: &quot;metadata&quot;,
+	  setType: function(type,name){
+	    this.type = type;
+	    this.name = name;
+	  },
+	  cre: /({.*})/,
+	  single: 'metadata'
+	};
+	
+	// reference to original setArray()
+	var setArray = $.fn.setArray;
+	
+	// define new setArray()
+	$.fn.setArray = function(arr){
+	    return setArray.apply( this, arguments ).each(function(){
+	      if ( this.nodeType == 9 || $.isXMLDoc(this) || this.metaDone ) return;
+	      
+	      var data = &quot;{}&quot;;
+	      
+	      if ( $.meta.type == &quot;class&quot; ) {
+	        var m = $.meta.cre.exec( this.className );
+	        if ( m )
+	          data = m[1];
+	      } else if ( $.meta.type == &quot;elem&quot; ) {
+	      	if( !this.getElementsByTagName ) return;
+	        var e = this.getElementsByTagName($.meta.name);
+	        if ( e.length )
+	          data = $.trim(e[0].innerHTML);
+	      } else if ( this.getAttribute != undefined ) {
+	        var attr = this.getAttribute( $.meta.name );
+	        if ( attr )
+	          data = attr;
+	      }
+	      
+	      if ( !/^{/.test( data ) )
+	        data = &quot;{&quot; + data + &quot;}&quot;;
+	
+	      eval(&quot;data = &quot; + data);
+	
+	      if ( $.meta.single )
+	        this[ $.meta.single ] = data;
+	      else
+	        $.extend( this, data );
+	      
+	      this.metaDone = true;
+	    });
+	};
+	
+	/**
+	 * Returns the metadata object for the first member of the jQuery object.
+	 *
+	 * @name data
+	 * @descr Returns element's metadata object
+	 * @type jQuery
+	 * @cat Plugins/Metadata
+	 */
+	$.fn.data = function() {
+	  return this[0][$.meta.single];
+	};
+})(jQuery);</diff>
      <filename>public/javascripts/min/jquery.ext.js</filename>
    </modified>
    <modified>
      <diff>@@ -33,7 +33,7 @@ def package_js(path, min = true)
   # --preserve-semi         Preserve all semicolons
   # --preserve-strings      Do not merge concatenated string literals
   puts &quot;Packaging up #{path.upcase}&quot;
-  concat_path(path, &quot;js&quot;, &quot;javascripts&quot;)
+  concat_path(path, &quot;js&quot;, &quot;javascripts&quot;, &quot;;&quot;)
 
   if min
     puts `java -jar ./script/jar/yuicompressor-2.2.4.jar --nomunge --preserve-semi --preserve-strings ./public/javascripts/min/#{path}.concat.js &gt; ./public/javascripts/min/#{path}.js`
@@ -52,12 +52,12 @@ def package_css(path)
   puts &quot;=========================&quot;
 end
 
-def concat_path(path, extension, output_folder)  
+def concat_path(path, extension, output_folder, end_sep = nil)  
   file = File.open( &quot;./public/#{output_folder}/min/#{path}.concat.#{extension}&quot;, &quot;w+&quot;) do |f|    
     Dir[&quot;./public/#{output_folder}/#{path}/**/*.#{extension}&quot;].each do |file|
       f.puts &quot;/* ---- Compressing #{file} ----- */\n&quot; 
       f.puts File.open(file, &quot;r&quot;).read
-      f.puts &quot;\n&quot;
+      f.puts &quot;\n#{end_sep}\n&quot;
     end
   end
 end</diff>
      <filename>script/merge_assets</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>public/javascripts/jquery.ext/dimensions.js</filename>
    </removed>
    <removed>
      <filename>public/javascripts/jquery.ext/jquery.autocomplete.js</filename>
    </removed>
    <removed>
      <filename>public/javascripts/jquery.ext/jquery.bgiframe.js</filename>
    </removed>
    <removed>
      <filename>public/javascripts/jquery.ext/jquery.history.js</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>ed782015248a0ced209e27f10240274537792b20</id>
    </parent>
  </parents>
  <author>
    <name>Jacques Crocker</name>
    <email>jcnetdev@gmail.com</email>
  </author>
  <url>http://github.com/jcnetdev/jobberrails/commit/00b45fdaa24e3c9dfbd70773b8c7d1ea52c4d753</url>
  <id>00b45fdaa24e3c9dfbd70773b8c7d1ea52c4d753</id>
  <committed-date>2008-08-08T11:57:55-07:00</committed-date>
  <authored-date>2008-08-08T11:57:55-07:00</authored-date>
  <message>Cleaning up Javascripts and adding Merge script</message>
  <tree>cd534b56afcdf046894b94343cb7bbe53eb1a12f</tree>
  <committer>
    <name>Jacques Crocker</name>
    <email>jcnetdev@gmail.com</email>
  </committer>
</commit>
