text: /*
   * jQuery Autocomplete plugin 1.1
   *
   * Copyright (c) 2009 Jö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 15 2009-08-22 10:30:27Z joern.zaefferer $
   */;
  $.browser = navigator.userAgent;
  (function($) {
      $.fn.extend({
          autocomplete: function(urlOrData, options) {
              var isUrl = typeof urlOrData == "string";
              options = $.extend({}, $.Autocompleter.defaults, {
                  url: isUrl ? urlOrData : null,
                  data: isUrl ? null : urlOrData,
                  delay: isUrl ? $.Autocompleter.defaults.delay : 10,
                  max: options && !options.scroll ? 10 : 150
              }, options);
              options.highlight = options.highlight ||
                  function(value) {
                      return value;
                  };
              options.formatMatch = options.formatMatch || options.formatItem;
              return this.each(function() {
                  new $.Autocompleter(this, options);
              });
          },
          result: function(handler) {
              return this.bind("result", handler);
          },
          search: function(handler) {
              return this.trigger("search", [handler]);
          },
          flushCache: function() {
              return this.trigger("flushCache");
          },
          setOptions: function(options) {
              return this.trigger("setOptions", [options]);
          },
          unautocomplete: function() {
              return this.trigger("unautocomplete");
          }
      });
      $.Autocompleter = function(input, options) {
          var KEY = {
              UP: 38,
              DOWN: 40,
              DEL: 46,
              TAB: 9,
              RETURN: 13,
              ESC: 27,
              COMMA: 188,
              PAGEUP: 33,
              PAGEDOWN: 34,
              BACKSPACE: 8
          };
          var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
          var timeout;
          var previousValue = "";
          var cache = $.Autocompleter.Cache(options);
          var hasFocus = 0;
          var lastKeyPressCode;
          var config = {
              mouseDownOnSelect: false
          };
          var select = $.Autocompleter.Select(options, input, selectCurrent, config);
          var blockSubmit;
          $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
              if (blockSubmit) {
                  blockSubmit = false;
                  return false;
              }
          });
          $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
              hasFocus = 1;
              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.PAGEUP:
                      event.preventDefault();
                      if (select.visible()) {
                          select.pageUp();
                      } else {
                          onChange(0, true);
                      }
                      break;
                  case KEY.PAGEDOWN:
                      event.preventDefault();
                      if (select.visible()) {
                          select.pageDown();
                      } else {
                          onChange(0, true);
                      }
                      break;
                  case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
                  
  				case KEY.TAB:
  				    if( selectCurrent() ) {
  				        // stop default to prevent a form submit, Opera needs special handling
  				        event.preventDefault();
  				        blockSubmit = true;
  				        return false;
  				    }
  				    break;				 
  				case KEY.RETURN:
  				    clearTimeout(timeout);
  				    timeout = setTimeout(onChange, options.delay);
  				    break;				
                  case KEY.ESC:
                      select.hide();
                      break;
                  default:
                      clearTimeout(timeout);
                      timeout = setTimeout(onChange, options.delay);
                      break;
              }
          }).focus(function() {
              hasFocus++;
          }).blur(function() {
              hasFocus = 0;
              if (!config.mouseDownOnSelect) {
                  hideResults();
              }
          }).click(function() {
              if (hasFocus++ > 1 && !select.visible()) {
                  onChange(0, true);
              }
          }).bind("search", function() {
              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", result && [result.data, result.value]);
              }
              $.each(trimWords($input.val()), function(i, value) {
                  request(value, findValueCallback, findValueCallback);
              });
          }).bind("flushCache", function() {
              cache.flush();
          }).bind("setOptions", function() {
              $.extend(options, arguments[1]);
              if ("data" in arguments[1]) cache.populate();
          }).bind("unautocomplete", function() {
              select.unbind();
              $input.unbind();
              $(input.form).unbind(".autocomplete");
          });
  
          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) {
                      var seperator = options.multipleSeparator.length;
                      var cursorAt = $(input).selection().start;
                      var wordAt, progress = 0;
                      $.each(words, function(i, word) {
                          progress += word.length;
                          if (cursorAt <= progress) {
                              wordAt = i;
                              return false;
                          }
                          progress += seperator;
                      });
                      words[wordAt] = v;
                      v = words.join(options.multipleSeparator);
                  }
                  v += options.multipleSeparator;
              }
              $input.val(v);
              hideResultsNow();
              $input.trigger("result", [selected.data, selected.value]);
              return true;
          }
          function onChange(crap, skipPrevCheck) {
              if (lastKeyPressCode == KEY.DEL) {
                  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 [$.trim(value)];
              return $.map(value.split(options.multipleSeparator), function(word) {
                  return $.trim(value).length ? $.trim(word) : null;
              });
          }
          function lastWord(value) {
              if (!options.multiple) return value;
              var words = trimWords(value);
              if (words.length == 1) return words[0];
              var cursorAt = $(input).selection().start;
              if (cursorAt == value.length) {
                  words = trimWords(value)
              } else {
                  words = trimWords(value.replace(value.substring(cursorAt), ""));
              }
              return words[words.length - 1];
          }
          function autoFill(q, sValue) {
              if (options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE) {
                  $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
                  $(input).selection(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) {
                  $input.search(function(result) {
                      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("");
                              $input.trigger("result", null);
                          }
                      }
                  });
              }
          };
  
          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);
              if (data && data.length) {
                  success(term, data);
              } 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() : param;
                  });
                  $.ajax({
                      mode: "abort",
                      port: "autocomplete" + input.name,
                      dataType: options.dataType,
                      url: options.url,
                      data: $.extend({
                          wd: 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 {
                  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);
          };
      };
      $.Autocompleter.defaults = {
          inputClass: "ac_input",
          resultsClass: "ac_results",
          loadingClass: "ac_loading",
          minChars: 1,
          delay: 400,
          matchCase: false,
          matchSubset: true,
          matchContains: false,
          cacheLength: 10,
          max: 100,
          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
      };
      $.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 (options.matchContains == "word") {
                  i = s.toLowerCase().search("\\b" + sub.toLowerCase());
              }
              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;
              var stMatchSets = {},
                  nullData = 0;
              if (!options.url) options.cacheLength = 1;
              stMatchSets[""] = [];
              for (var i = 0, ol = options.data.length; i < ol; i++) {
                  var rawValue = options.data[i];
                  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 (!stMatchSets[firstChar]) stMatchSets[firstChar] = [];
                  var row = {
                      value: value,
                      data: rawValue,
                      result: options.formatResult && options.formatResult(rawValue) || value
                  };
                  stMatchSets[firstChar].push(row);
                  if (nullData++ < options.max) {
                      stMatchSets[""].push(row);
                  }
              };
              $.each(stMatchSets, function(i, value) {
                  options.cacheLength++;
                  add(i, value);
              });
          }
          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 (!options.url && options.matchContains) {
                      var csub = [];
                      for (var k in data) {
                          if (k.length > 0) {
                              var c = data[k];
                              $.each(c, function(i, x) {
                                  if (matchSubset(x.value, q)) {
                                      csub.push(x);
                                  }
                              });
                          }
                      }
                      return csub;
                  } else 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;
              }
          };
      };
      $.Autocompleter.Select = function(options, input, select, config) {
          var CLASSES = {
              ACTIVE: "ac_over"
          };
          var listItems, active = -1,
              data, term = "",
              needsInit = true,
              element, list;
  
          function init() {
              if (!needsInit) return;
              element = $("<div/>").hide().addClass(options.resultsClass).css("position", "absolute").appendTo(document.body);
              list = $("<ul/>").appendTo(element).mouseover(function(event) {
                  if (target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
                      active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
                      $(target(event)).addClass(CLASSES.ACTIVE);
                  }
              }).click(function(event) {
                  $(target(event)).addClass(CLASSES.ACTIVE);
                  select();
                  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;
              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 ? "ac_even" : "ac_odd").appendTo(list)[0];
                  $.data(li, "ac_data", data[i]);
              }
              listItems = list.find("li");
              if (options.selectFirst) {
                  listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
                  active = 0;
              }
              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;
              },
              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) {
                              listItems.width(list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")));
                          }
                      }
                  }
              },
              selected: function() {
                  var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
                  return selected && selected.length && $.data(selected[0], "ac_data");
              },
              emptyList: function() {
                  list && list.empty();
              },
              unbind: function() {
                  element && element.remove();
              }
          };
      };
      $.fn.selection = function(start, end) {
          if (start !== undefined) {
              return this.each(function() {
                  if (this.createTextRange) {
                      var selRange = this.createTextRange();
                      if (end === undefined || start == end) {
                          selRange.move("character", start);
                          selRange.select();
                      } else {
                          selRange.collapse(true);
                          selRange.moveStart("character", start);
                          selRange.moveEnd("character", end);
                          selRange.select();
                      }
                  } else if (this.setSelectionRange) {
                      this.setSelectionRange(start, end);
                  } else if (this.selectionStart) {
                      this.selectionStart = start;
                      this.selectionEnd = end;
                  }
              });
          }
          var field = this[0];
          if (field.createTextRange) {
              var range = document.selection.createRange(),
                  orig = field.value,
                  teststring = "<->",
                  textLength = range.text.length;
              range.text = teststring;
              var caretAt = field.value.indexOf(teststring);
              field.value = orig;
              this.selection(caretAt, caretAt + textLength);
              return {
                  start: caretAt,
                  end: caretAt + textLength
              }
          } else if (field.selectionStart !== undefined) {
              return {
                  start: field.selectionStart,
                  end: field.selectionEnd
              }
          }
      };
  })(jQuery);