/*
 * Facebox (for jQuery)
 * version: 1.2 (05/05/2008)
 * @requires jQuery v1.2 or later
 *
 * Examples at http://famspam.com/facebox/
 *
 * Licensed under the MIT:
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright 2007, 2008 Chris Wanstrath [ chris@ozmm.org ]
 *
 * Usage:
 *  
 *  jQuery(document).ready(function() {
 *    jQuery('a[rel*=facebox]').facebox() 
 *  })
 *
 *  <a href="#terms" rel="facebox">Terms</a>
 *    Loads the #terms div in the box
 *
 *  <a href="terms.html" rel="facebox">Terms</a>
 *    Loads the terms.html page in the box
 *
 *  <a href="terms.png" rel="facebox">Terms</a>
 *    Loads the terms.png image in the box
 *
 *
 *  You can also use it programmatically:
 * 
 *    jQuery.facebox('some html')
 *    jQuery.facebox('some html', 'my-groovy-style')
 *
 *  The above will open a facebox with "some html" as the content.
 *    
 *    jQuery.facebox(function($) { 
 *      $.get('blah.html', function(data) { $.facebox(data) })
 *    })
 *
 *  The above will show a loading screen before the passed function is called,
 *  allowing for a better ajaxy experience.
 *
 *  The facebox function can also display an ajax page, an image, or the contents of a div:
 *  
 *    jQuery.facebox({ ajax: 'remote.html' })
 *    jQuery.facebox({ ajax: 'remote.html' }, 'my-groovy-style')
 *    jQuery.facebox({ image: 'stairs.jpg' })
 *    jQuery.facebox({ image: 'stairs.jpg' }, 'my-groovy-style')
 *    jQuery.facebox({ div: '#box' })
 *    jQuery.facebox({ div: '#box' }, 'my-groovy-style')
 *
 *  Want to close the facebox?  Trigger the 'close.facebox' document event:
 *
 *    jQuery(document).trigger('close.facebox')
 *
 *  Facebox also has a bunch of other hooks:
 *
 *    loading.facebox
 *    beforeReveal.facebox
 *    reveal.facebox (aliased as 'afterReveal.facebox')
 *    init.facebox
 *
 *  Simply bind a function to any of these hooks:
 *
 *   $(document).bind('reveal.facebox', function() { ...stuff to do after the facebox and contents are revealed... })
 *
 */
(function($) {
  $.facebox = function(data, klass) {
    $.facebox.loading()

    if (data.ajax) fillFaceboxFromAjax(data.ajax, klass)
    else if (data.image) fillFaceboxFromImage(data.image, klass)
    else if (data.div) fillFaceboxFromHref(data.div, klass)
    else if ($.isFunction(data)) data.call($)
    else $.facebox.reveal(data, klass)
  }

  /*
   * Public, $.facebox methods
   */

  $.extend($.facebox, {
    settings: {
      opacity      : 0,
      overlay      : true,
      loadingImage : '/images/loading.gif',
      closeImage   : '/images/facebox/closelabel.gif',
      imageTypes   : [ 'png', 'jpg', 'jpeg', 'gif' ],
      faceboxHtml  : '\
    <div id="facebox" style="display:none;"> \
      <div class="popup"> \
        <table> \
          <tbody> \
            <tr> \
              <td class="tl"/><td class="b"/><td class="tr"/> \
            </tr> \
            <tr> \
              <td class="b"/> \
              <td class="body"> \
                <div class="content"> \
                </div> \
              </td> \
              <td class="b"/> \
            </tr> \
            <tr> \
              <td class="bl"/><td class="b"/><td class="br"/> \
            </tr> \
          </tbody> \
        </table> \
      </div> \
    </div>'
    },

    loading: function() {
      init()
      if ($('#facebox .loading').length == 1) return true
      showOverlay()

      $('#facebox .content').empty()
      $('#facebox .body').children().hide().end().
        append('<div class="loading"><img src="'+$.facebox.settings.loadingImage+'"/></div>')

      $('#facebox').css({
        top:	getPageScroll()[1] + (getPageHeight() / 10),
        left:	$(window).width() / 2 - 205 
      }).show()

      $(document).bind('keydown.facebox', function(e) {
        if (e.keyCode == 27) $.facebox.close()
        return true
      })
      $(document).trigger('loading.facebox')
    },

    reveal: function(data, klass) {
      $(document).trigger('beforeReveal.facebox')
      if (klass) $('#facebox .content').addClass(klass)
      $('#facebox .content').append(data)
      $('#facebox .loading').remove()
      $('#facebox .body').children().fadeIn('normal')
      $('#facebox').css('left', $(window).width() / 2 - ($('#facebox table').width() / 2))
      $(document).trigger('reveal.facebox').trigger('afterReveal.facebox')
    },

    close: function() {
      $(document).trigger('close.facebox')
      return false
    }
  })

  /*
   * Public, $.fn methods
   */

  $.fn.facebox = function(settings) {
    init(settings)

    function clickHandler() {
      $.facebox.loading(true)

      // support for rel="facebox.inline_popup" syntax, to add a class
      // also supports deprecated "facebox[.inline_popup]" syntax
      var klass = this.rel.match(/facebox\[?\.(\w+)\]?/)
      if (klass) klass = klass[1]

      fillFaceboxFromHref(this.href, klass)
      return false
    }

    return this.bind('click.facebox', clickHandler)
  }

  /*
   * Private methods
   */

  // called one time to setup facebox on this page
  function init(settings) {
    if ($.facebox.settings.inited) return true
    else $.facebox.settings.inited = true

    $(document).trigger('init.facebox')
    makeCompatible()

    var imageTypes = $.facebox.settings.imageTypes.join('|')
    $.facebox.settings.imageTypesRegexp = new RegExp('\.(' + imageTypes + ')(\\?\\d+)?', 'i')

    if (settings) $.extend($.facebox.settings, settings)
    $('body').append($.facebox.settings.faceboxHtml)

    var preload = [ new Image(), new Image() ]
    preload[0].src = $.facebox.settings.closeImage
    preload[1].src = $.facebox.settings.loadingImage

    $('#facebox').find('.b:first, .bl, .br, .tl, .tr').each(function() {
      preload.push(new Image())
      preload.slice(-1).src = $(this).css('background-image').replace(/url\((.+)\)/, '$1')
    })

    $('#facebox .close').click($.facebox.close)
    $('#facebox .close_image').attr('src', $.facebox.settings.closeImage)
  }
  
  // getPageScroll() by quirksmode.com
  function getPageScroll() {
    var xScroll, yScroll;
    if (self.pageYOffset) {
      yScroll = self.pageYOffset;
      xScroll = self.pageXOffset;
    } else if (document.documentElement && document.documentElement.scrollTop) {	 // Explorer 6 Strict
      yScroll = document.documentElement.scrollTop;
      xScroll = document.documentElement.scrollLeft;
    } else if (document.body) {// all other Explorers
      yScroll = document.body.scrollTop;
      xScroll = document.body.scrollLeft;	
    }
    return new Array(xScroll,yScroll) 
  }

  // Adapted from getPageSize() by quirksmode.com
  function getPageHeight() {
    var windowHeight
    if (self.innerHeight) {	// all except Explorer
      windowHeight = self.innerHeight;
    } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
      windowHeight = document.documentElement.clientHeight;
    } else if (document.body) { // other Explorers
      windowHeight = document.body.clientHeight;
    }	
    return windowHeight
  }

  // Backwards compatibility
  function makeCompatible() {
    var $s = $.facebox.settings

    $s.loadingImage = $s.loading_image || $s.loadingImage
    $s.closeImage = $s.close_image || $s.closeImage
    $s.imageTypes = $s.image_types || $s.imageTypes
    $s.faceboxHtml = $s.facebox_html || $s.faceboxHtml
  }

  // Figures out what you want to display and displays it
  // formats are:
  //     div: #id
  //   image: blah.extension
  //    ajax: anything else
  function fillFaceboxFromHref(href, klass) {
    // div
    if (href.match(/#/)) {
      var url    = window.location.href.split('#')[0]
      var target = href.replace(url,'')
      $.facebox.reveal($(target).show().replaceWith("<div id='facebox_moved'></div>"), klass)

    // image
    } else if (href.match($.facebox.settings.imageTypesRegexp)) {
      fillFaceboxFromImage(href, klass)
    // ajax
    } else {
      fillFaceboxFromAjax(href, klass)
    }
  }

  function fillFaceboxFromImage(href, klass) {
    var image = new Image()
    image.onload = function() {
      $.facebox.reveal('<div class="image"><img src="' + image.src + '" /></div>', klass)
    }
    image.src = href
  }

  function fillFaceboxFromAjax(href, klass) {
    $.get(href, function(data) { $.facebox.reveal(data, klass) })
  }

  function skipOverlay() {
    return $.facebox.settings.overlay == false || $.facebox.settings.opacity === null 
  }

  function showOverlay() {
    if (skipOverlay()) return

    if ($('#facebox_overlay').length == 0) 
      $("body").append('<div id="facebox_overlay" class="facebox_hide"></div>')

    $('#facebox_overlay').hide().addClass("facebox_overlayBG")
      .css('opacity', $.facebox.settings.opacity)
      .click(function() { $(document).trigger('close.facebox') })
      .fadeIn(200)
    return false
  }

  function hideOverlay() {
    if (skipOverlay()) return

    $('#facebox_overlay').fadeOut(200, function(){
      $("#facebox_overlay").removeClass("facebox_overlayBG")
      $("#facebox_overlay").addClass("facebox_hide") 
      $("#facebox_overlay").remove()
    })
    
    return false
  }

  /*
   * Bindings
   */

  $(document).bind('close.facebox', function() {
    $(document).unbind('keydown.facebox')
    $('#facebox').fadeOut(function() {
      if ($('#facebox_moved').length == 0) $('#facebox .content').removeClass().addClass('content')
      else $('#facebox_moved').replaceWith($('#facebox .content').children().hide())
      hideOverlay()
      $('#facebox .loading').remove()
    })
  })

})(jQuery);


// tipsy, facebook style tooltips for jquery
// version 1.0.0a
// (c) 2008-2010 jason frame [jason@onehackoranother.com]
// released under the MIT license

(function($) {

    function Tipsy(element, options) {
        this.$element = $(element);
        this.options = options;
        this.enabled = true;
        this.fixTitle();
    }

    Tipsy.prototype = {
        show: function() {
            var title = this.getTitle();
            if (title && this.enabled) {
                var $tip = this.tip();

                $tip.find('.tipsy-inner')[this.options.html ? 'html' : 'text'](title);
                $tip[0].className = 'tipsy'; // reset classname in case of dynamic gravity
                $tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).appendTo(document.body);

                var pos = $.extend({}, this.$element.offset(), {
                    width: this.$element[0].offsetWidth,
                    height: this.$element[0].offsetHeight
                });

                var actualWidth = $tip[0].offsetWidth, actualHeight = $tip[0].offsetHeight;
                var gravity = (typeof this.options.gravity == 'function')
                                ? this.options.gravity.call(this.$element[0])
                                : this.options.gravity;

                var tp;
                switch (gravity.charAt(0)) {
                    case 'n':
                        tp = {top: pos.top + pos.height + this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
                        break;
                    case 's':
                        tp = {top: pos.top - actualHeight - this.options.offset, left: pos.left + pos.width / 2 - actualWidth / 2};
                        break;
                    case 'e':
                        tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth - this.options.offset};
                        break;
                    case 'w':
                        tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width + this.options.offset};
                        break;
                }

                if (gravity.length == 2) {
                    if (gravity.charAt(1) == 'w') {
                        tp.left = pos.left + pos.width / 2 - 15;
                    } else {
                        tp.left = pos.left + pos.width / 2 - actualWidth + 15;
                    }
                }

                $tip.css(tp).addClass('tipsy-' + gravity);

                if (this.options.fade) {
                    $tip.stop().css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: this.options.opacity});
                } else {
                    $tip.css({visibility: 'visible', opacity: this.options.opacity});
                }
            }
        },

        hide: function() {
            if (this.options.fade) {
                this.tip().stop().fadeOut(function() { $(this).remove(); });
            } else {
                this.tip().remove();
            }
        },

        fixTitle: function() {
            var $e = this.$element;
            if ($e.attr('title') || typeof($e.attr('original-title')) != 'string') {
                $e.attr('original-title', $e.attr('title') || '').removeAttr('title');
            }
        },

        getTitle: function() {
            var title, $e = this.$element, o = this.options;
            this.fixTitle();
            var title, o = this.options;
            if (typeof o.title == 'string') {
                title = $e.attr(o.title == 'title' ? 'original-title' : o.title);
            } else if (typeof o.title == 'function') {
                title = o.title.call($e[0]);
            }
            title = ('' + title).replace(/(^\s*|\s*$)/, "");
            return title || o.fallback;
        },

        tip: function() {
            if (!this.$tip) {
                this.$tip = $('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>');
            }
            return this.$tip;
        },

        validate: function() {
            if (!this.$element[0].parentNode) {
                this.hide();
                this.$element = null;
                this.options = null;
            }
        },

        enable: function() { this.enabled = true; },
        disable: function() { this.enabled = false; },
        toggleEnabled: function() { this.enabled = !this.enabled; }
    };

    $.fn.tipsy = function(options) {

        if (options === true) {
            return this.data('tipsy');
        } else if (typeof options == 'string') {
            var tipsy = this.data('tipsy');
            if (tipsy) tipsy[options]();
            return this;
        }

        options = $.extend({}, $.fn.tipsy.defaults, options);

        function get(ele) {
            var tipsy = $.data(ele, 'tipsy');
            if (!tipsy) {
                tipsy = new Tipsy(ele, $.fn.tipsy.elementOptions(ele, options));
                $.data(ele, 'tipsy', tipsy);
            }
            return tipsy;
        }

        function enter() {
            var tipsy = get(this);
            tipsy.hoverState = 'in';
            if (options.delayIn == 0) {
                tipsy.show();
            } else {
                tipsy.fixTitle();
                setTimeout(function() { if (tipsy.hoverState == 'in') tipsy.show(); }, options.delayIn);
            }
        };

        function leave() {
            var tipsy = get(this);
            tipsy.hoverState = 'out';
            if (options.delayOut == 0) {
                tipsy.hide();
            } else {
                setTimeout(function() { if (tipsy.hoverState == 'out') tipsy.hide(); }, options.delayOut);
            }
        };

        if (!options.live) this.each(function() { get(this); });

        if (options.trigger != 'manual') {
            var binder   = options.live ? 'live' : 'bind',
                eventIn  = options.trigger == 'hover' ? 'mouseenter' : 'focus',
                eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur';
            this[binder](eventIn, enter)[binder](eventOut, leave);
        }

        return this;

    };

    $.fn.tipsy.defaults = {
        delayIn: 0,
        delayOut: 0,
        fade: false,
        fallback: '',
        gravity: 'n',
        html: false,
        live: false,
        offset: 0,
        opacity: 0.8,
        title: 'title',
        trigger: 'hover'
    };

    // Overwrite this method to provide options on a per-element basis.
    // For example, you could store the gravity in a 'tipsy-gravity' attribute:
    // return $.extend({}, options, {gravity: $(ele).attr('tipsy-gravity') || 'n' });
    // (remember - do not modify 'options' in place!)
    $.fn.tipsy.elementOptions = function(ele, options) {
        return $.metadata ? $.extend({}, options, $(ele).metadata()) : options;
    };

    $.fn.tipsy.autoNS = function() {
        return $(this).offset().top > ($(document).scrollTop() + $(window).height() / 2) ? 's' : 'n';
    };

    $.fn.tipsy.autoWE = function() {
        return $(this).offset().left > ($(document).scrollLeft() + $(window).width() / 2) ? 'e' : 'w';
    };

})(jQuery);



(function($){function toIntegersAtLease(n)
{return n<10?'0'+n:n;}
Date.prototype.toJSON=function(date)
{return this.getUTCFullYear()+'-'+
toIntegersAtLease(this.getUTCMonth())+'-'+
toIntegersAtLease(this.getUTCDate());};var escapeable=/["\\\x00-\x1f\x7f-\x9f]/g;var meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};$.quoteString=function(string)
{if(escapeable.test(string))
{return'"'+string.replace(escapeable,function(a)
{var c=meta[a];if(typeof c==='string'){return c;}
c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
return'"'+string+'"';};$.toJSON=function(o,compact)
{var type=typeof(o);if(type=="undefined")
return"undefined";else if(type=="number"||type=="boolean")
return o+"";else if(o===null)
return"null";if(type=="string")
{return $.quoteString(o);}
if(type=="object"&&typeof o.toJSON=="function")
return o.toJSON(compact);if(type!="function"&&typeof(o.length)=="number")
{var ret=[];for(var i=0;i<o.length;i++){ret.push($.toJSON(o[i],compact));}
if(compact)
return"["+ret.join(",")+"]";else
return"["+ret.join(", ")+"]";}
if(type=="function"){throw new TypeError("Unable to convert object of type 'function' to json.");}
var ret=[];for(var k in o){var name;type=typeof(k);if(type=="number")
name='"'+k+'"';else if(type=="string")
name=$.quoteString(k);else
continue;var val=$.toJSON(o[k],compact);if(typeof(val)!="string"){continue;}
if(compact)
ret.push(name+":"+val);else
ret.push(name+": "+val);}
return"{"+ret.join(", ")+"}";};$.compactJSON=function(o)
{return $.toJSON(o,true);};$.evalJSON=function(src)
{return eval("("+src+")");};$.secureEvalJSON=function(src)
{var filtered=src;filtered=filtered.replace(/\\["\\\/bfnrtu]/g,'@');filtered=filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']');filtered=filtered.replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered))
return eval("("+src+")");else
throw new SyntaxError("Error parsing JSON, source is not valid.");};})(jQuery);

﻿/*
 * jQuery UI Autocomplete @VERSION
 *
 * Copyright (c) 2007, 2008 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 * 
 * http://docs.jquery.com/UI/Autocomplete
 *
 * Depends:
 *	ui.core.js
 */
(function($) {

$.widget("ui.autocomplete", {

	_init: function() {
		// TODO move these to instance properties?
		$.extend(this.options, {
			delay: this.options.delay != undefined ? this.options.delay : (this.options.url? this.options.ajaxDelay : this.options.localDelay),
			max: this.options.max != undefined ? this.options.max : (this.options.scroll? this.options.scrollMax : this.options.noScrollMax),
			highlight: this.options.highlight || function(value) { return value; }, // if highlight is set to false, replace it with a do-nothing function
			formatMatch: this.options.formatMatch || this.options.formatItem // if the formatMatch option is not specified, then use formatItem for backwards compatibility
		});

		
		// this.options['url'] = this.element[0].getAttribute['data-url'];

		var input = this.element[0],
			options = this.options,
			// Create $ object for input element
			$input = $(input).attr("autocomplete", "off").addClass(options.inputClass),
			KEY = $.ui.keyCode,
			previousValue = "",
			cache = $.ui.autocomplete.cache(options),
			hasFocus = 0,
			config = {
				mouseDownOnSelect: false
			},
			timeout,
			blockSubmit,
			lastKeyPressCode,
			select = $.ui.autocomplete.select(options, input, selectCurrent, config);

		options.url = $(input).attr("data-url");
		
		if(options.result) {
			$input.bind('result.autocomplete', options.result);
		}

		// prevent form submit in opera when selecting with return key
		$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
			if (blockSubmit) {
				blockSubmit = false;
				return false;
			}
		});

		// only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
		$input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", 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;

				case KEY.PAGE_UP:
					event.preventDefault();
					if ( select.visible() ) {
						select.pageUp();
					} else {
						onChange(0, true);
					}
					break;

				case KEY.PAGE_DOWN:
					event.preventDefault();
					if ( select.visible() ) {
						select.pageDown();
					} else {
						onChange(0, true);
					}
					break;

				// matches also semicolon
				case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
				case KEY.TAB:
				case KEY.ENTER:
					if( selectCurrent() ) {
						// stop default to prevent a form submit, Opera needs special handling
						event.preventDefault();
						blockSubmit = true;
						return false;
					}
					break;

				case KEY.ESCAPE:
					select.hide();
					break;

				default:
					clearTimeout(timeout);
					timeout = setTimeout(onChange, options.delay);
					break;
			}
		})
		.bind('focus.autocomplete', function(){
			// track whether the field has focus, we shouldn't process any
			// results if the field no longer has focus
			hasFocus++;
		})
		.bind('blur.autocomplete', function() {
			hasFocus = 0;
			if (!config.mouseDownOnSelect) {
				hideResults();
			}
		})
		.bind('click.autocomplete', function() {
			// show select when clicking in a focused field
			if ( hasFocus++ > 1 && !select.visible() ) {
				onChange(0, true);
			}
		}).bind("search.autocomplete", function() {
			// TODO why not just specifying both arguments?
			var fn = (arguments.length > 1) ? arguments[1] : null;
			function findValueCallback(q, data) {
				var result;
				if( data && data.length ) {
					for (var i=0; i < data.length; i++) {
						if( data[i].result.toLowerCase() == q.toLowerCase() ) {
							result = data[i];
							break;
						}
					}
				}
				if( typeof fn == "function" ) fn(result);
				else $input.trigger("result.autocomplete", result && [result.data, result.value]);
			}
			$.each(trimWords($input.val()), function(i, value) {
				request(value, findValueCallback, findValueCallback);
			});
		})
		.bind("flushCache.autocomplete", function() {
			cache.flush();
		})
		.bind("setOptions.autocomplete", function() {
			$.extend(options, arguments[1]);
			// if we've updated the data, repopulate
			if ( "data" in arguments[1] )
				cache.populate();
		})
		.bind("unautocomplete", function() {
			select.unbind();
			//$input.unbind(); << this would unbind all events. Bad news if we've had another plugin applied to this element. AAP 03.12.09
			$(input).unbind(".autocomplete");
			$(input.form).unbind(".autocomplete");
		});

		// Private methods
		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 > 1 ) {
					v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
				}
				v += options.multipleSeparator;
			}

			$input.val(v);
			hideResultsNow();
			$input.trigger("result.autocomplete", [selected.data, selected.value]);
			return true;
		};

		function onChange(crap, skipPrevCheck) {
			if( lastKeyPressCode == KEY.DELETE ) {
				select.hide();
				return;
			}

			var currentValue = $input.val();

			if ( !skipPrevCheck && currentValue == previousValue )
				return;

			previousValue = currentValue;

			currentValue = lastWord(currentValue);
			if ( currentValue.length >= options.minChars) {
				$input.addClass(options.loadingClass);
				if (!options.matchCase)
					currentValue = currentValue.toLowerCase();
				request(currentValue, receiveData, hideResultsNow);
			} else {
				stopLoading();
				select.hide();
			}
		};

		function trimWords(value) {
			if ( !value ) {
				return [""];
			}
			if ( !options.multiple ) {
				return [value];
			}
			var words = value.split( options.multipleSeparator );
			var result = [];
			$.each(words, function(i, value) {
				if ( $.trim(value) )
					result[i] = $.trim(value);
			});
			return result;
		};

		function lastWord(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)
		// q: the term entered
		// sValue: the first matching result
		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 && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != $.ui.keyCode.BACKSPACE ) {
				// 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)
				$.ui.autocomplete.selection(input, previousValue.length, previousValue.length + sValue.length);
			}
		};

		function hideResults() {
			clearTimeout(timeout);
			timeout = setTimeout(hideResultsNow, 200);
		};

		function hideResultsNow() {
			var wasVisible = select.visible();
			select.hide();
			clearTimeout(timeout);
			stopLoading();
			if (options.mustMatch) {
				// call search and run callback
				$input.autocomplete("search", function (result){
						// if no value found, clear the input box
						if( !result ) {
							if (options.multiple) {
								var words = trimWords($input.val()).slice(0, -1);
								$input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
							}
							else
								$input.val( "" );
						}
					}
				);
			}
			if (wasVisible)
				// position cursor at end of input field
				$.ui.autocomplete.selection(input, input.value.length, input.value.length);
		};

		function receiveData(q, data) {
			if ( data && data.length && 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 && data.length) {
				success(term, data);
			} // if an AJAX url has been supplied, try loading the data now
			else if( (typeof options.url == "string") && (options.url.length > 0) ){

				var extraParams = {
					timestamp: +new Date()
				};
				$.each(options.extraParams, function(key, param) {
					extraParams[key] = typeof param == "function" ? param(term) : param;
				});

				$.ajax({
					// try to leverage ajaxQueue plugin to abort previous requests
					mode: "abort",
					// limit abortion to this input
					port: "autocomplete" + input.name,
					dataType: options.dataType,
					url: options.url,
					data: $.extend({
						q: lastWord(term),
						limit: options.max
					}, extraParams),
					success: function(data) {
						var parsed = options.parse && options.parse(data) || parse(data);
						cache.add(term, parsed);
						success(term, parsed);
					}
				});
			}

			else if (options.source && typeof options.source == 'function') {
				var resultData = options.source(term);
				var parsed = (options.parse) ? options.parse(resultData) : resultData;

				cache.add(term, parsed);
				success(term, parsed);
			} else {
				// if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
				select.emptyList();
				failure(term);
			}
		};

		function parse(data) {
			var parsed = [];
			var rows = data.split("\n");
			for (var i=0; i < rows.length; i++) {
				var row = $.trim(rows[i]);
				if (row) {
					row = row.split("|");
					parsed[parsed.length] = {
						data: row,
						value: row[0],
						result: options.formatResult && options.formatResult(row, row[0]) || row[0]
					};
				}
			}
			return parsed;
		};

		function stopLoading() {
			$input.removeClass(options.loadingClass);
		};

	}, //End _init
	
	_propagate: function(n, event) {
		$.ui.plugin.call(this, n, [event, this.ui()]);
		return this.element.triggerHandler(n == 'autocomplete' ? n : 'autocomplete'+n, [event, this.ui()], this.options[n]);
	},

	// Public methods
	ui: function(event) {
		return {
			options: this.options,
			element: this.element
		};
	},
	result: function(handler) {
		return this.element.bind("result.autocomplete", handler);
	},
	search: function(handler) {
		return this.element.trigger("search.autocomplete", [handler]);
	},
	flushCache: function() {
		return this.element.trigger("flushCache.autocomplete");
	},
	setData: function(key, value){
		return this.element.trigger("setOptions.autocomplete", [{ key: value }]);
	},
	destroy: function() {
		this.element
			.removeAttr('disabled')
			.removeClass('ui-autocomplete-input');
		return this.element.trigger("unautocomplete");
	},
	enable: function() {
		this.element
			.removeAttr('disabled')
			.removeClass('ui-autocomplete-disabled');
		this.disabled = false;
	},
	disable: function() {
		this.element
			.attr('disabled', true)
			.addClass('ui-autocomplete-disabled');
		this.disabled = true;
	}
});

$.extend($.ui.autocomplete, {
	defaults: {
		inputClass: "ui-autocomplete-input",
		resultsClass: "ui-widget ui-widget-content ui-autocomplete-results",
		loadingClass: "ui-autocomplete-loading",
		minChars: 1,
		ajaxDelay: 400,
		localDelay: 10,
		matchCase: false,
		matchSubset: true,
		matchContains: false,
		cacheLength: 10,
		scrollMax: 150,
		noScrollMax: 10,
		mustMatch: false,
		extraParams: {},
		selectFirst: true,
		formatItem: function(row) { return row[0]; },
		formatMatch: null,
		autoFill: false,
		width: 0,
		multiple: false,
		multipleSeparator: ", ",
		highlight: function(value, term) {
			return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
		},
		scroll: true,
		scrollHeight: 180
	}
});

$.ui.autocomplete.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 > options.cacheLength){
			flush();
		}
		if (!data[q]){ 
			length++;
		}
		data[q] = value;
	}

	function populate(){
		if( !options.data ) return false;
		// track the matches
		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;

		// track all options for minChars = 0
		stMatchSets[""] = [];

		// loop through the array and create a lookup structure
		for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
			var rawValue = options.data[i];
			// if rawValue is a string, make an array otherwise just reference the array
			rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;

			var value = options.formatMatch(rawValue, i+1, options.data.length);
			if ( value === false )
				continue;

			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 && options.formatResult(rawValue) || value
			};

			// push the current match into the set list
			stMatchSets[firstChar].push(row);

			// keep track of minChars zero items
			if ( nullData++ < options.max ) {
				stMatchSets[""].push(row);
			}
		};

		// add the data items to the cache
		$.each(stMatchSets, function(i, value) {
			// increase the cache size
			options.cacheLength++;
			// add to the cache
			add(i, value);
		});
	}

	// populate any existing data
	setTimeout(populate, 25);

	function flush(){
		data = {};
		length = 0;
	}

	return {
		flush: flush,
		add: add,
		populate: populate,
		load: function(q) {
			if (!options.cacheLength || !length)
				return null;
			/* 
			 * if dealing w/local data and matchContains than we must make sure
			 * to loop through all the data collections looking for matches
			 */
			if( !options.url && options.matchContains ){
				// track all matches
				var csub = [];
				// loop through all the data grids for matches
				for( var k in data ){
					// don't search through the stMatchSets[""] (minChars: 0) cache
					// this prevents duplicates
					if( k.length > 0 ){
						var c = data[k];
						$.each(c, function(i, x) {
							// if we've got a match, add it to the array
							if (matchSubset(x.value, q)) {
								csub.push(x);
							}
						});
					}
				}
				return csub;
			} else 
			// if the exact item exists, use it
			if (data[q]){
				return data[q];
			} else
			if (options.matchSubset) {
				for (var i = q.length - 1; i >= options.minChars; i--) {
					var c = data[q.substr(0, i)];
					if (c) {
						var csub = [];
						$.each(c, function(i, x) {
							if (matchSubset(x.value, q)) {
								csub[csub.length] = x;
							}
						});
						return csub;
					}
				}
			}
			return null;
		}
	};
};

$.ui.autocomplete.select = function (options, input, select, config) {
	var CLASSES = {
		//ACTIVE: "ui-state-active" << From the Css Framework Docs : .ui-state-active: Class to be applied on mousedown to clickable button-like elements.
		//Since this isnt a button element, but a hybrid 'menu item', use a custom class.
		//See: http://jqueryui.pbwiki.com/Menu 2- Visual Design
		DEFAULT: 'ui-autocomplete-state-default',
		ACTIVE: 'ui-autocomplete-state-active'
	};

	var listItems,
		active = -1,
		data,
		term = "",
		needsInit = true,
		element,
		list;

	// Create results
	function init() {
		if (!needsInit) return;
		element = $("<div/>")
		.hide()
		.addClass(options.resultsClass)
		//.css("position", "absolute") set this up in the css in case users want to do something wonky with the positioning.
		.appendTo(document.body);

		list = $("<ul/>").appendTo(element).mouseover( function(event) {
			var e = target(event);
			if(e.nodeName && e.nodeName.toUpperCase() == 'LI') {
				active = $("li", list).removeClass(CLASSES.ACTIVE).index(e);
				$(e).addClass(CLASSES.ACTIVE);
			}
		}).click(function(event) {
			$(target(event)).addClass(CLASSES.ACTIVE);
			select();
			// TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
			input.focus();
			return false;
		}).mousedown(function() {
			config.mouseDownOnSelect = true;
		}).mouseup(function() {
			config.mouseDownOnSelect = false;
		});

		if( options.width > 0 )
			element.css("width", options.width);

		needsInit = false;
	} 

	function target(event) {
		var element = event.target;
		while(element && element.tagName != "LI")
			element = element.parentNode;
		// more fun with IE, sometimes event.target is empty, just ignore it then
		if(!element)
			return [];
		return element;
	}

	function moveSelect(step) {
		listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
		movePosition(step);
		var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
		if(options.scroll) {
			var offset = 0;
			listItems.slice(0, active).each(function() {
				offset += this.offsetHeight;
			});
			if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
				list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
			} else if(offset < list.scrollTop()) {
				list.scrollTop(offset);
			}
		}
	};

	function movePosition(step) {
		active += step;
		if (active < 0) {
			active = listItems.size() - 1;
		} else if (active >= listItems.size()) {
			active = 0;
		}
	}

	function limitNumberOfItems(available) {
		return options.max && options.max < available
			? options.max
			: available;
	}

	function fillList() {
		list.empty();
		var max = limitNumberOfItems(data.length);
		for (var i=0; i < max; i++) {
			if (!data[i])
				continue;
			var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
			if ( formatted === false )
				continue;
			var li = $("<li/>")
				.html( options.highlight(formatted, term) )
				.addClass(i%2 == 0 ? "ui-autocomplete-even" : "ui-autocomplete-odd")
				.addClass(CLASSES.DEFAULT)
				.appendTo(list)[0];
			$.data(li, "ui-autocomplete-data", data[i]);
		}
		listItems = list.find("li");
		if ( options.selectFirst ) {
			listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
			active = 0;
		}
		// apply bgiframe if available
		if ( $.fn.bgiframe )
			list.bgiframe();
	}

	return {
		display: function(d, q) {
			init();
			data = d;
			term = q;
			fillList();
		},
		next: function() {
			moveSelect(1);
		},
		prev: function() {
			moveSelect(-1);
		},
		pageUp: function() {
			if (active != 0 && active - 8 < 0) {
				moveSelect( -active );
			} else {
				moveSelect(-8);
			}
		},
		pageDown: function() {
			if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
				moveSelect( listItems.size() - 1 - active );
			} else {
				moveSelect(8);
			}
		},
		hide: function() {
			element && element.hide();
			listItems && listItems.removeClass(CLASSES.ACTIVE)
			active = -1;
			$(input).triggerHandler("autocompletehide", [{}, { options: options }], options["hide"]);
		},
		visible : function() {
			return element && element.is(":visible");
		},
		current: function() {
			return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
		},
		show: function() {
			var offset = $(input).offset();
			element.css({
				width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
				top: offset.top + input.offsetHeight,
				left: offset.left
			}).show();

			if(options.scroll) {
				list.scrollTop(0);
				list.css({
					maxHeight: options.scrollHeight,
					overflow: 'auto'
				});

				if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
					var listHeight = 0;
					listItems.each(function() {
						listHeight += this.offsetHeight;
					});
					var scrollbarsVisible = listHeight > options.scrollHeight;
					list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
					if (!scrollbarsVisible) {
						// IE doesn't recalculate width when scrollbar disappears
						listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
					}
				}

			}

			$(input).triggerHandler("autocompleteshow", [{}, { options: options }], options["show"]);

		},
		selected: function() {
			var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
			return selected && selected.length && $.data(selected[0], "ui-autocomplete-data");
		},
		emptyList: function (){
			list && list.empty();
		},
		unbind: function() {
			element && element.remove();
		}
	};
};

$.ui.autocomplete.selection = function(field, start, end) {
	if( field.createTextRange ){
		var selRange = field.createTextRange();
		selRange.collapse(true);
		selRange.moveStart("character", start);
		selRange.moveEnd("character", end);
		selRange.select();
	} else if( field.setSelectionRange ){
		field.setSelectionRange(start, end);
	} else {
		if( field.selectionStart ){
			field.selectionStart = start;
			field.selectionEnd = end;
		}
	}
	field.focus();
};

})(jQuery);



jQuery(document).ready(function($) {
  autocomplete_prep_data = function(data){
    tmp = $.evalJSON(data);
    parsed_data = [];
    for (i=0; i < tmp.length; i++) {
      obj = tmp[i];
      // Other internal autocomplete operations expect
      // the data to be split into associative arrays of this sort
      parsed_data[i] = {
        data: obj,
        value: obj.title,
        result: obj.title
      };
    }
    return parsed_data;
  }

  tipsy_gravity = function() {
    return $(this).offset().top > ($(document).scrollTop() + 32) ? 's' : 'n'
  };

  $('.with-tipsy').tipsy({gravity: tipsy_gravity});

  vote_init = function(vote){
    vote.find('.summary').tipsy({
      gravity: tipsy_gravity,
      title: function(){ return $(this).children().text(); }
    });
    var links = vote.find('a');
    links.tipsy({gravity: tipsy_gravity});
    links.click(function(e){
      e.preventDefault();
      $.ajax({
        url: this.href,
        type: 'post',
        success: function(r) {
          new_vote = vote.before(r).prev();
          vote.remove();
          $('.tipsy').remove();
          vote_init($(new_vote));
        }
      });
    });
  };

  $("ul.vote").each(function(){vote_init($(this))});

  format_item = function (item, position, length){
    return item.title;
  }

  $('.bill-entry .delete').live('click', function(event){
    event.preventDefault();
    if (confirm('Are you sure?')) {
      var entry = $(this).parents('.bill-entry');
      $.ajax({
        url: this.href,
        type: 'post',
        data: { '_method': 'delete' },
        success: function(msg){
          entry.remove();
        }
      });
    }
  });

  $('.bill-entry .edit').live('click', function(event){
    event.preventDefault();
    var entry = $(this).parents('.bill-entry');
    $.ajax({
      url: this.href,
      success: function(msg){
        tmp_entry = entry.before(msg).prev();
        entry.remove();
        entry = tmp_entry;
        entry.find('.autocomplete').autocomplete({
          parse: autocomplete_prep_data,
          formatItem: format_item
        });

        function formSubmit(event){
          event.preventDefault();
          $.ajax({
            data: $.param($(this).serializeArray()),
            type: this.method,
            url: this.action,
            success: function(request){
              tmp_entry = entry.before(request).prev();
              entry.remove();
              entry = tmp_entry;
              entry.find('.autocomplete').autocomplete({
                parse: autocomplete_prep_data,
                formatItem: format_item
              });
              entry.find('form').submit(formSubmit);

              /* Update the total as well */
              var total = $('.bill-entry.total')
              $.ajax({
                type: 'get',
                url: total.find('.edit').attr('href').replace('edit_', 'show_'),
                success: function(request){
                  tmp_total = total.before(request).prev();
                  total.remove();
                  total = tmp_total;
                }
              });
            }
          });
        }

        entry.find('form').submit(formSubmit);
      }
    });
  });

  $('.goods .more').live('click', function(e){
    e.preventDefault();
    var that = this;
    $('.goods .more strong').addClass('spinner');
    $.ajax({
      url: this.href,
      success:function(r){
        $(that).before(r).remove();
        $('.goods .more strong').removeClass('spinner');
      }
    });
  });

  $('.goods .reply').live('click', function(e){
    e.preventDefault();
	$(this).addClass('spinner');
    var that = $(this);
    $.ajax({
      url: this.href,
	  success: function(r){
		that.parent().before(r).remove();
      }
    });
  });

  $('.goods #comment_submit').live('click', function(e){
    e.preventDefault();
    var form = $(this).parents('form.new_comment');
    $.ajax({
      data: $.param(form.serializeArray()),
      type: form.attr('method'),
      url: form.attr('action'),
      success:function(r){
        form.find('#comment_kukkerpall').val('');
        form.before(r);
      },
      error:function(r){
        form.before(r.responseText).remove();
      }
    });
  });

  $('.bill-entry .cancel').live('click', function(event){
    event.preventDefault();
    var that = this;
    $.ajax({
      url: this.href,
      success:function(request){
        $(that).parents('.bill-entry').before(request).remove();
      }
    });
  });

  $(".bill-entry").live('mouseover', function(){
    var data_box = $(this).attr("data-box");
    if (data_box != null)
    {
      var match = data_box.match(/(\d+) (\d+)/);
      $("#highlighter").css({
        top: match[1] + "px",
        height: match[2] + "px"
      });
      $("#highlighter").hide().show();
    }
  });

  $('.bill-entry .hint .title a').live('click', function(event){
    event.preventDefault();
    var form = $(this).parents('form.edit_purchase');
    var hints = $(this).parent().parent();

    form.find('#purchase_barcode').val($(this).attr('data-barcode'));
    form.find('.icon').attr('src', hints.find('img').attr('src'));
  });

  $('.jobs .more').click( function(e){
    e.preventDefault();
    $(this).parent().children('pre').toggleClass('hide');
  });

  $(".language select").change(function (){
      $(".language").submit()
  });

  $('div.rating').rating();
  $('a[rel*=facebox]').facebox();

  $("form #good_description").autogrow();

  $("form .manufacturer .autocomplete").autocomplete({
    parse: autocomplete_prep_data,
    formatItem: format_item
  });

  $("form .brand .autocomplete").autocomplete({
    parse: autocomplete_prep_data,
    formatItem: format_item
  });

  $("form .network .autocomplete").autocomplete({
    parse: autocomplete_prep_data,
    formatItem: format_item
  });

  $("form .add_manufacturer").click(function(event){
    var manufacturer = $("form #manufacturers .manufacturer:first").clone().appendTo("#manufacturers");
    var new_id = new Date().getTime();
    var select = manufacturer.find('select');
    var input = manufacturer.find('input');
    $([select, input]).each(function(){
      this.attr('id', this.attr('id').replace(/0/, new_id));
      this.attr('name', this.attr('name').replace(/0/, new_id));
    });
    input.autocomplete({
        parse: autocomplete_prep_data,
        formatItem: format_item
      });;
    manufacturer.show();

    event.preventDefault();
  });

  $("form .manufacturer a").live("click", function(event){
    $(this).siblings('input:checkbox').attr('checked', true);
    $(this).siblings('.autocomplete').remove();
    $(this).siblings('select').remove();
    $(this).remove();
    event.preventDefault();
  });

  $("form #good_category_list").autocomplete({
    multiple: true,
    parse: autocomplete_prep_data,
    formatItem: format_item
  }).autogrow();

  $("form #good_ingredient_list").autocomplete({
    multiple: true,
    parse: autocomplete_prep_data,
    formatItem: format_item
  }).autogrow();
})

$(document).ajaxSend(function(event, request, settings) {
  // if (typeof(window._AUTH_TOKEN) == "undefined") return;
  // IE6 fix for http://dev.jquery.com/ticket/3155
  if (settings.type == 'GET' || settings.type == 'get') return;

  settings.data = settings.data || "";
  settings.data += (settings.data ? "&" : "") + encodeURIComponent($('meta[name=csrf-name]').attr('content')) + "=" + encodeURIComponent($('meta[name=csrf-token]').attr('content'));
});

$(document).bind('reveal.facebox', function() {
  $('#facebox form').unbind('submit');
  $('#facebox form').submit(function() {
    $.ajax({
      data: $.param($(this).serializeArray()),
      dataType:'script',
      type:this.method,
      url: this.action,
      success: function(msg){
        $('#facebox .content').html(msg);
        $(document).trigger('reveal.facebox');
      },
      error: function(msg, status, error) {
        $('#facebox .content').html(msg);
        $(document).trigger('reveal.facebox');
      }
    });
    return false;
  });

  $('#facebox .close').unbind('click');
	$('#facebox .close').click(function() {
		$(document).trigger('close.facebox');
		return false;
	});
});

(function(jQuery) {
  jQuery.fn.rating = function(o) {
    return this.each(function() {
      new jQuery.rating(this, o);
    });
  };

  /**
   * The rating object.
   *
   * @constructor
   * @name jQuery.rating
   * @param Object e The XHTML markup.
   * @param Hash o A set of key/value pairs to set as configuration properties.
   * @cat Plugins/rating
   */
  jQuery.rating = function (e, o)
  {
    this.markup   = jQuery(e);
    this.form     = jQuery(this.markup.find('form')[0]);
    this.average  = jQuery(this.markup.find('.average')[0]);

    var method = this.form.find("input[name='_method']");
    this.options  = o || {
      stars: 5,
      action: this.form.context.action + '.json',
      rateable_type: this.form.find("#rate_rateable_type")[0].value,
      rateable_id: this.form.find("#rate_rateable_id")[0].value,
      method: (method.length > 0 &&  method[0].value == 'put') ? 'put' : 'post'
    };

    this.init();
  };

  jQuery.rating.fn = jQuery.rating.prototype = {
    rating: '1.0.0'
  };

  jQuery.rating.fn.extend = jQuery.rating.extend = jQuery.extend;

  jQuery.rating.fn.extend({
    init: function() {
      var average = this.average.text();
      var percentage = average / this.options.stars * 100;

      this.ul = jQuery('<ul class="jq-rating"/>').insertAfter(this.form);
      var ul = this.ul;

      var login = jQuery(this.markup.find('span.login'));
      login.hide();
      if(login.length > 0) {
        this.ul.append('<li class="login">' + login.html() + '</li>');
        var login = this.ul.find('.login');
        this.ul.hover(
          function() {
            login.css('z-index', '11');
          },
          function() {
            login.css('z-index', '-1');
          }
        );
      }

      ul.append('<li class="loading"/>');
      ul.append('<li class="current" style="width:' + percentage + '%">' + average + '</li>');

      this.markup.find('select option').each(function(){
        if(this.value != ''){
          ul.append('<li class="star r' + this.value +'"><a href="#">' + this.value + '</a></li>');
        }
      });

      var self = this;
      ul.find('.star').bind('click', function(event){self.rate(event)});

      this.form.hide();
    },
    rate: function(event) {
      this.markup.find('.loading').show();

      var self = this;

      jQuery.ajax({
        type: this.options.method, url: this.options.action,
        dataType: "json",
        data: {
          'rate[stars]': jQuery(event.currentTarget).attr('class').replace(/^star.r/,''),
          'rate[rateable_type]': this.options.rateable_type,
          'rate[rateable_id]': this.options.rateable_id
        },
        success:function(request) {
          self.ul.find('li[class="current"]').attr('style', 'width:' + (request.average / self.options.stars * 100) + '%');
          jQuery(self.markup.find('.count')[0]).text('(' + request.count + ')');
          self.average.text(request.average.toFixed(1));

          self.markup.find('.loading').hide();
          self.ul.find('a').blur();
        }
      });

      event.preventDefault();
    }
  });
})(jQuery);

/*
 * Auto Expanding Text Area (1.2.2)
 * by Chrys Bader (www.chrysbader.com)
 * chrysb@gmail.com
 *
 * Special thanks to:
 * Jake Chapa - jake@hybridstudio.com
 * John Resig - jeresig@gmail.com
 *
 * Copyright (c) 2008 Chrys Bader (www.chrysbader.com)
 * Licensed under the GPL (GPL-LICENSE.txt) license.
 *
 *
 * NOTE: This script requires jQuery to work.  Download jQuery at www.jquery.com
 *
 */

(function(jQuery) {

	var self = null;

	jQuery.fn.autogrow = function(o)
	{
		return this.each(function() {
			new jQuery.autogrow(this, o);
		});
	};


    /**
     * The autogrow object.
     *
     * @constructor
     * @name jQuery.autogrow
     * @param Object e The textarea to create the autogrow for.
     * @param Hash o A set of key/value pairs to set as configuration properties.
     * @cat Plugins/autogrow
     */

	jQuery.autogrow = function (e, o)
	{
		this.options		  	= o || {};
		this.dummy			  	= null;
		this.interval	 	  	= null;
		this.line_height	  	= this.options.lineHeight || parseInt(jQuery(e).css('line-height'));
		this.min_height		  	= this.options.minHeight || parseInt(jQuery(e).css('min-height'));
		this.max_height		  	= this.options.maxHeight || parseInt(jQuery(e).css('max-height'));;
		this.textarea		  	= jQuery(e);

		if(this.line_height == NaN)
		  this.line_height = 0;

		// Only one textarea activated at a time, the one being used
		this.init();
	};

	jQuery.autogrow.fn = jQuery.autogrow.prototype = {
    autogrow: '1.2.2'
  };

 	jQuery.autogrow.fn.extend = jQuery.autogrow.extend = jQuery.extend;

	jQuery.autogrow.fn.extend({

		init: function() {
			var self = this;
			this.textarea.css({overflow: 'hidden', display: 'block'});
			this.textarea.bind('focus', function() { self.startExpand() } ).bind('blur', function() { self.stopExpand() });
			this.checkExpand();
		},

		startExpand: function() {
		  var self = this;
			this.interval = window.setInterval(function() {self.checkExpand()}, 400);
		},

		stopExpand: function() {
			clearInterval(this.interval);
		},

		checkExpand: function() {

			if (this.dummy == null)
			{
				this.dummy = jQuery('<div></div>');
        var style = {
											'font-size'  : this.textarea.css('font-size'),
											'font-family': this.textarea.css('font-family'),
											'width'      : this.textarea.css('width'),
											'padding'    : this.textarea.css('padding'),
											'overflow-x' : 'hidden',
											'position'   : 'absolute',
											'top'        : 0,
											'left'		 : -9999
										};
				if (!isNaN(this.line_height)){
				  style['line-height'] = this.line_height + 'px';
				}
				this.dummy.css(style).appendTo('body');
			}

			// Strip HTML tags
			var html = this.textarea.val().replace(/(<|>)/g, '');

			// IE is different, as per usual
			if ($.browser.msie)
			{
				html = html.replace(/\n/g, '<BR>new');
			}
			else
			{
				html = html.replace(/\n/g, '<br>new');
			}

			if (this.dummy.html() != html)
			{
				this.dummy.html(html);

				if (this.max_height > 0 && (this.dummy.height() + this.line_height > this.max_height))
				{
					this.textarea.css('overflow-y', 'auto');
				}
				else
				{
					this.textarea.css('overflow-y', 'hidden');
					if (this.textarea.height() < this.dummy.height() + this.line_height || (this.dummy.height() < this.textarea.height()))
					{
						this.textarea.animate({height: (this.dummy.height() + this.line_height) + 'px'}, 100);
					}
				}
			}
		}

	 });
})(jQuery);
