Index: admin/js/jquery/jquery.autocomplete.js
===================================================================
--- admin/js/jquery/jquery.autocomplete.js	(revision 1035)
+++ admin/js/jquery/jquery.autocomplete.js	(revision 2114)
@@ -1,4 +1,4 @@
 /*
- * jQuery Autocomplete plugin 1.1
+ * jQuery Autocomplete plugin 1.2.3
  *
  * Copyright (c) 2009 Jörn Zaefferer
@@ -8,9 +8,11 @@
  *   http://www.gnu.org/licenses/gpl.html
  *
- * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
+ * With small modifications by Alfonso Gómez-Arzola.
+ * See changelog for details.
+ *
  */
 
 ;(function($) {
-	
+
 $.fn.extend({
 	autocomplete: function(urlOrData, options) {
@@ -20,13 +22,14 @@
 			data: isUrl ? null : urlOrData,
 			delay: isUrl ? $.Autocompleter.defaults.delay : 10,
-			max: options && !options.scroll ? 10 : 150
+			max: options && !options.scroll ? 10 : 150,
+			noRecord: "No Records."
 		}, options);
-		
+
 		// if highlight is set to false, replace it with a do-nothing function
 		options.highlight = options.highlight || function(value) { return value; };
-		
+
 		// if the formatMatch option is not specified, then use formatItem for backwards compatibility
 		options.formatMatch = options.formatMatch || options.formatItem;
-		
+
 		return this.each(function() {
 			new $.Autocompleter(this, options);
@@ -65,4 +68,9 @@
 	};
 
+	var globalFailure = null;
+	if(options.failure != null && typeof options.failure == "function") {
+	  globalFailure = options.failure;
+	}
+
 	// Create $ object for input element
 	var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
@@ -77,9 +85,9 @@
 	};
 	var select = $.Autocompleter.Select(options, input, selectCurrent, config);
-	
+
 	var blockSubmit;
-	
+
 	// prevent form submit in opera when selecting with return key
-	$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
+  navigator.userAgent.indexOf("Opera") != -1 && $(input.form).bind("submit.autocomplete", function() {
 		if (blockSubmit) {
 			blockSubmit = false;
@@ -87,7 +95,7 @@
 		}
 	});
-	
-	// 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) {
+
+	// older versions of opera don't trigger keydown multiple times while pressed, others don't work with keypress at all
+	$input.bind((navigator.userAgent.indexOf("Opera") != -1 && !'KeyboardEvent' in window ? "keypress" : "keydown") + ".autocomplete", function(event) {
 		// a keypress means the input has focus
 		// avoids issue where input had focus before the autocomplete was applied
@@ -96,8 +104,8 @@
 		lastKeyPressCode = event.keyCode;
 		switch(event.keyCode) {
-		
+
 			case KEY.UP:
-				event.preventDefault();
 				if ( select.visible() ) {
+					event.preventDefault();
 					select.prev();
 				} else {
@@ -105,8 +113,8 @@
 				}
 				break;
-				
+
 			case KEY.DOWN:
-				event.preventDefault();
 				if ( select.visible() ) {
+					event.preventDefault();
 					select.next();
 				} else {
@@ -114,8 +122,8 @@
 				}
 				break;
-				
+
 			case KEY.PAGEUP:
-				event.preventDefault();
 				if ( select.visible() ) {
+  				event.preventDefault();
 					select.pageUp();
 				} else {
@@ -123,8 +131,8 @@
 				}
 				break;
-				
+
 			case KEY.PAGEDOWN:
-				event.preventDefault();
 				if ( select.visible() ) {
+  				event.preventDefault();
 					select.pageDown();
 				} else {
@@ -132,5 +140,5 @@
 				}
 				break;
-			
+
 			// matches also semicolon
 			case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
@@ -144,9 +152,9 @@
 				}
 				break;
-				
+
 			case KEY.ESC:
 				select.hide();
 				break;
-				
+
 			default:
 				clearTimeout(timeout);
@@ -159,5 +167,5 @@
 		hasFocus++;
 	}).blur(function() {
-		hasFocus = 0;
+	  hasFocus = 0;
 		if (!config.mouseDownOnSelect) {
 			hideResults();
@@ -165,6 +173,14 @@
 	}).click(function() {
 		// show select when clicking in a focused field
-		if ( hasFocus++ > 1 && !select.visible() ) {
-			onChange(0, true);
+		// but if clickFire is true, don't require field
+		// to be focused to begin with; just show select
+		if( options.clickFire ) {
+		  if ( !select.visible() ) {
+  			onChange(0, true);
+  		}
+		} else {
+		  if ( hasFocus++ > 1 && !select.visible() ) {
+  			onChange(0, true);
+  		}
 		}
 	}).bind("search", function() {
@@ -190,5 +206,5 @@
 		cache.flush();
 	}).bind("setOptions", function() {
-		$.extend(options, arguments[1]);
+		$.extend(true, options, arguments[1]);
 		// if we've updated the data, repopulate
 		if ( "data" in arguments[1] )
@@ -199,14 +215,14 @@
 		$(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());
@@ -230,5 +246,5 @@
 			v += options.multipleSeparator;
 		}
-		
+
 		$input.val(v);
 		hideResultsNow();
@@ -236,5 +252,5 @@
 		return true;
 	}
-	
+
 	function onChange(crap, skipPrevCheck) {
 		if( lastKeyPressCode == KEY.DEL ) {
@@ -242,12 +258,12 @@
 			return;
 		}
-		
+
 		var currentValue = $input.val();
-		
+
 		if ( !skipPrevCheck && currentValue == previousValue )
 			return;
-		
+
 		previousValue = currentValue;
-		
+
 		currentValue = lastWord(currentValue);
 		if ( currentValue.length >= options.minChars) {
@@ -261,5 +277,5 @@
 		}
 	};
-	
+
 	function trimWords(value) {
 		if (!value)
@@ -271,10 +287,10 @@
 		});
 	}
-	
+
 	function lastWord(value) {
 		if ( !options.multiple )
 			return value;
 		var words = trimWords(value);
-		if (words.length == 1) 
+		if (words.length == 1)
 			return words[0];
 		var cursorAt = $(input).selection().start;
@@ -286,5 +302,5 @@
 		return words[words.length - 1];
 	}
-	
+
 	// fills in the input box w/the first match (assumed to be the best match)
 	// q: the term entered
@@ -347,9 +363,15 @@
 		var data = cache.load(term);
 		// recieve the cached data
-		if (data && data.length) {
-			success(term, data);
+		if (data) {
+			if(data.length)	{
+				success(term, data);
+			}
+			else{
+				var parsed = options.parse && options.parse(options.noRecord) || parse(options.noRecord);	
+				success(term,parsed);
+			}
 		// 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()
@@ -358,5 +380,5 @@
 				extraParams[key] = typeof param == "function" ? param() : param;
 			});
-			
+
 			$.ajax({
 				// try to leverage ajaxQueue plugin to abort previous requests
@@ -379,8 +401,13 @@
 			// 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);
-		}
-	};
-	
+			if(globalFailure != null) {
+        globalFailure();
+      }
+      else {
+        failure(term);
+			}
+		}
+	};
+
 	function parse(data) {
 		var parsed = [];
@@ -415,6 +442,6 @@
 	matchSubset: true,
 	matchContains: false,
-	cacheLength: 10,
-	max: 100,
+	cacheLength: 100,
+	max: 1000,
 	mustMatch: false,
 	extraParams: {},
@@ -425,10 +452,13 @@
 	width: 0,
 	multiple: false,
-	multipleSeparator: ", ",
+	multipleSeparator: " ",
+	inputFocus: true,
+	clickFire: false,
 	highlight: function(value, term) {
 		return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
 	},
     scroll: true,
-    scrollHeight: 180
+    scrollHeight: 180,
+    scrollJumpPosition: true
 };
 
@@ -437,7 +467,7 @@
 	var data = {};
 	var length = 0;
-	
+
 	function matchSubset(s, sub) {
-		if (!options.matchCase) 
+		if (!options.matchCase)
 			s = s.toLowerCase();
 		var i = s.indexOf(sub);
@@ -448,15 +478,15 @@
 		return i == 0 || options.matchContains;
 	};
-	
+
 	function add(q, value) {
 		if (length > options.cacheLength){
 			flush();
 		}
-		if (!data[q]){ 
+		if (!data[q]){
 			length++;
 		}
 		data[q] = value;
 	}
-	
+
 	function populate(){
 		if( !options.data ) return false;
@@ -467,8 +497,8 @@
 		// 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++ ) {
@@ -476,12 +506,12 @@
 			// 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 )
+			if ( typeof(value) === 'undefined' || value === false )
 				continue;
-				
+
 			var firstChar = value.charAt(0).toLowerCase();
 			// if no lookup array for this character exists, look it up now
-			if( !stMatchSets[firstChar] ) 
+			if( !stMatchSets[firstChar] )
 				stMatchSets[firstChar] = [];
 
@@ -492,5 +522,5 @@
 				result: options.formatResult && options.formatResult(rawValue) || value
 			};
-			
+
 			// push the current match into the set list
 			stMatchSets[firstChar].push(row);
@@ -510,13 +540,13 @@
 		});
 	}
-	
+
 	// populate any existing data
 	setTimeout(populate, 25);
-	
+
 	function flush(){
 		data = {};
 		length = 0;
 	}
-	
+
 	return {
 		flush: flush,
@@ -526,5 +556,5 @@
 			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
@@ -546,7 +576,7 @@
 						});
 					}
-				}				
+				}
 				return csub;
-			} else 
+			} else
 			// if the exact item exists, use it
 			if (data[q]){
@@ -576,5 +606,5 @@
 		ACTIVE: "ac_over"
 	};
-	
+
 	var listItems,
 		active = -1,
@@ -584,5 +614,5 @@
 		element,
 		list;
-	
+
 	// Create results
 	function init() {
@@ -593,16 +623,23 @@
 		.addClass(options.resultsClass)
 		.css("position", "absolute")
-		.appendTo(document.body);
-	
+		.appendTo(document.body)
+		.hover(function(event) {
+		  // Browsers except FF do not fire mouseup event on scrollbars, resulting in mouseDownOnSelect remaining true, and results list not always hiding.
+		  if($(this).is(":visible")) {
+		    input.focus();
+		  }
+		  config.mouseDownOnSelect = false;
+		});
+
 		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);            
+			    $(target(event)).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();
+			if( options.inputFocus )
+			  input.focus();
 			return false;
 		}).mousedown(function() {
@@ -611,11 +648,11 @@
 			config.mouseDownOnSelect = false;
 		});
-		
+
 		if( options.width > 0 )
 			element.css("width", options.width);
-			
+
 		needsInit = false;
-	} 
-	
+	}
+
 	function target(event) {
 		var element = event.target;
@@ -644,14 +681,17 @@
         }
 	};
-	
+
 	function movePosition(step) {
-		active += step;
-		if (active < 0) {
-			active = listItems.size() - 1;
-		} else if (active >= listItems.size()) {
-			active = 0;
-		}
-	}
-	
+		if (options.scrollJumpPosition || (!options.scrollJumpPosition && !((step < 0 && active == 0) || (step > 0 && active == listItems.size() - 1)) )) {
+			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
@@ -659,5 +699,5 @@
 			: available;
 	}
-	
+
 	function fillList() {
 		list.empty();
@@ -681,5 +721,5 @@
 			list.bgiframe();
 	}
-	
+
 	return {
 		display: function(d, q) {
@@ -733,6 +773,6 @@
 					overflow: 'auto'
 				});
-				
-                if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
+
+                if(navigator.userAgent.indexOf("MSIE") != -1 && typeof document.body.style.maxHeight === "undefined") {
 					var listHeight = 0;
 					listItems.each(function() {
@@ -746,5 +786,5 @@
 					}
                 }
-                
+
             }
 		},
Index: plugins/tags/js/jquery.autocomplete.js
===================================================================
--- plugins/tags/js/jquery.autocomplete.js	(revision 738)
+++ plugins/tags/js/jquery.autocomplete.js	(revision 2114)
@@ -1,4 +1,4 @@
 /*
- * jQuery Autocomplete plugin 1.1
+ * jQuery Autocomplete plugin 1.2.3
  *
  * Copyright (c) 2009 Jörn Zaefferer
@@ -8,9 +8,11 @@
  *   http://www.gnu.org/licenses/gpl.html
  *
- * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
+ * With small modifications by Alfonso Gómez-Arzola.
+ * See changelog for details.
+ *
  */
 
 ;(function($) {
-	
+
 $.fn.extend({
 	autocomplete: function(urlOrData, options) {
@@ -20,13 +22,14 @@
 			data: isUrl ? null : urlOrData,
 			delay: isUrl ? $.Autocompleter.defaults.delay : 10,
-			max: options && !options.scroll ? 10 : 150
+			max: options && !options.scroll ? 10 : 150,
+			noRecord: "No Records."
 		}, options);
-		
+
 		// if highlight is set to false, replace it with a do-nothing function
 		options.highlight = options.highlight || function(value) { return value; };
-		
+
 		// if the formatMatch option is not specified, then use formatItem for backwards compatibility
 		options.formatMatch = options.formatMatch || options.formatItem;
-		
+
 		return this.each(function() {
 			new $.Autocompleter(this, options);
@@ -65,4 +68,9 @@
 	};
 
+	var globalFailure = null;
+	if(options.failure != null && typeof options.failure == "function") {
+	  globalFailure = options.failure;
+	}
+
 	// Create $ object for input element
 	var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
@@ -77,9 +85,9 @@
 	};
 	var select = $.Autocompleter.Select(options, input, selectCurrent, config);
-	
+
 	var blockSubmit;
-	
+
 	// prevent form submit in opera when selecting with return key
-	$.browser.opera && $(input.form).bind("submit.autocomplete", function() {
+  navigator.userAgent.indexOf("Opera") != -1 && $(input.form).bind("submit.autocomplete", function() {
 		if (blockSubmit) {
 			blockSubmit = false;
@@ -87,7 +95,7 @@
 		}
 	});
-	
-	// 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) {
+
+	// older versions of opera don't trigger keydown multiple times while pressed, others don't work with keypress at all
+	$input.bind((navigator.userAgent.indexOf("Opera") != -1 && !'KeyboardEvent' in window ? "keypress" : "keydown") + ".autocomplete", function(event) {
 		// a keypress means the input has focus
 		// avoids issue where input had focus before the autocomplete was applied
@@ -96,8 +104,8 @@
 		lastKeyPressCode = event.keyCode;
 		switch(event.keyCode) {
-		
+
 			case KEY.UP:
-				event.preventDefault();
 				if ( select.visible() ) {
+					event.preventDefault();
 					select.prev();
 				} else {
@@ -105,8 +113,8 @@
 				}
 				break;
-				
+
 			case KEY.DOWN:
-				event.preventDefault();
 				if ( select.visible() ) {
+					event.preventDefault();
 					select.next();
 				} else {
@@ -114,8 +122,8 @@
 				}
 				break;
-				
+
 			case KEY.PAGEUP:
-				event.preventDefault();
 				if ( select.visible() ) {
+  				event.preventDefault();
 					select.pageUp();
 				} else {
@@ -123,8 +131,8 @@
 				}
 				break;
-				
+
 			case KEY.PAGEDOWN:
-				event.preventDefault();
 				if ( select.visible() ) {
+  				event.preventDefault();
 					select.pageDown();
 				} else {
@@ -132,5 +140,5 @@
 				}
 				break;
-			
+
 			// matches also semicolon
 			case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
@@ -144,9 +152,9 @@
 				}
 				break;
-				
+
 			case KEY.ESC:
 				select.hide();
 				break;
-				
+
 			default:
 				clearTimeout(timeout);
@@ -159,5 +167,5 @@
 		hasFocus++;
 	}).blur(function() {
-		hasFocus = 0;
+	  hasFocus = 0;
 		if (!config.mouseDownOnSelect) {
 			hideResults();
@@ -165,6 +173,14 @@
 	}).click(function() {
 		// show select when clicking in a focused field
-		if ( hasFocus++ > 1 && !select.visible() ) {
-			onChange(0, true);
+		// but if clickFire is true, don't require field
+		// to be focused to begin with; just show select
+		if( options.clickFire ) {
+		  if ( !select.visible() ) {
+  			onChange(0, true);
+  		}
+		} else {
+		  if ( hasFocus++ > 1 && !select.visible() ) {
+  			onChange(0, true);
+  		}
 		}
 	}).bind("search", function() {
@@ -190,5 +206,5 @@
 		cache.flush();
 	}).bind("setOptions", function() {
-		$.extend(options, arguments[1]);
+		$.extend(true, options, arguments[1]);
 		// if we've updated the data, repopulate
 		if ( "data" in arguments[1] )
@@ -199,14 +215,14 @@
 		$(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());
@@ -230,5 +246,5 @@
 			v += options.multipleSeparator;
 		}
-		
+
 		$input.val(v);
 		hideResultsNow();
@@ -236,5 +252,5 @@
 		return true;
 	}
-	
+
 	function onChange(crap, skipPrevCheck) {
 		if( lastKeyPressCode == KEY.DEL ) {
@@ -242,12 +258,12 @@
 			return;
 		}
-		
+
 		var currentValue = $input.val();
-		
+
 		if ( !skipPrevCheck && currentValue == previousValue )
 			return;
-		
+
 		previousValue = currentValue;
-		
+
 		currentValue = lastWord(currentValue);
 		if ( currentValue.length >= options.minChars) {
@@ -261,5 +277,5 @@
 		}
 	};
-	
+
 	function trimWords(value) {
 		if (!value)
@@ -271,10 +287,10 @@
 		});
 	}
-	
+
 	function lastWord(value) {
 		if ( !options.multiple )
 			return value;
 		var words = trimWords(value);
-		if (words.length == 1) 
+		if (words.length == 1)
 			return words[0];
 		var cursorAt = $(input).selection().start;
@@ -286,5 +302,5 @@
 		return words[words.length - 1];
 	}
-	
+
 	// fills in the input box w/the first match (assumed to be the best match)
 	// q: the term entered
@@ -347,9 +363,15 @@
 		var data = cache.load(term);
 		// recieve the cached data
-		if (data && data.length) {
-			success(term, data);
+		if (data) {
+			if(data.length)	{
+				success(term, data);
+			}
+			else{
+				var parsed = options.parse && options.parse(options.noRecord) || parse(options.noRecord);	
+				success(term,parsed);
+			}
 		// 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()
@@ -358,5 +380,5 @@
 				extraParams[key] = typeof param == "function" ? param() : param;
 			});
-			
+
 			$.ajax({
 				// try to leverage ajaxQueue plugin to abort previous requests
@@ -379,8 +401,13 @@
 			// 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);
-		}
-	};
-	
+			if(globalFailure != null) {
+        globalFailure();
+      }
+      else {
+        failure(term);
+			}
+		}
+	};
+
 	function parse(data) {
 		var parsed = [];
@@ -415,6 +442,6 @@
 	matchSubset: true,
 	matchContains: false,
-	cacheLength: 10,
-	max: 100,
+	cacheLength: 100,
+	max: 1000,
 	mustMatch: false,
 	extraParams: {},
@@ -425,10 +452,13 @@
 	width: 0,
 	multiple: false,
-	multipleSeparator: ", ",
+	multipleSeparator: " ",
+	inputFocus: true,
+	clickFire: false,
 	highlight: function(value, term) {
 		return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
 	},
     scroll: true,
-    scrollHeight: 180
+    scrollHeight: 180,
+    scrollJumpPosition: true
 };
 
@@ -437,7 +467,7 @@
 	var data = {};
 	var length = 0;
-	
+
 	function matchSubset(s, sub) {
-		if (!options.matchCase) 
+		if (!options.matchCase)
 			s = s.toLowerCase();
 		var i = s.indexOf(sub);
@@ -448,15 +478,15 @@
 		return i == 0 || options.matchContains;
 	};
-	
+
 	function add(q, value) {
 		if (length > options.cacheLength){
 			flush();
 		}
-		if (!data[q]){ 
+		if (!data[q]){
 			length++;
 		}
 		data[q] = value;
 	}
-	
+
 	function populate(){
 		if( !options.data ) return false;
@@ -467,8 +497,8 @@
 		// 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++ ) {
@@ -476,12 +506,12 @@
 			// 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 )
+			if ( typeof(value) === 'undefined' || value === false )
 				continue;
-				
+
 			var firstChar = value.charAt(0).toLowerCase();
 			// if no lookup array for this character exists, look it up now
-			if( !stMatchSets[firstChar] ) 
+			if( !stMatchSets[firstChar] )
 				stMatchSets[firstChar] = [];
 
@@ -492,5 +522,5 @@
 				result: options.formatResult && options.formatResult(rawValue) || value
 			};
-			
+
 			// push the current match into the set list
 			stMatchSets[firstChar].push(row);
@@ -510,13 +540,13 @@
 		});
 	}
-	
+
 	// populate any existing data
 	setTimeout(populate, 25);
-	
+
 	function flush(){
 		data = {};
 		length = 0;
 	}
-	
+
 	return {
 		flush: flush,
@@ -526,5 +556,5 @@
 			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
@@ -546,7 +576,7 @@
 						});
 					}
-				}				
+				}
 				return csub;
-			} else 
+			} else
 			// if the exact item exists, use it
 			if (data[q]){
@@ -576,5 +606,5 @@
 		ACTIVE: "ac_over"
 	};
-	
+
 	var listItems,
 		active = -1,
@@ -584,5 +614,5 @@
 		element,
 		list;
-	
+
 	// Create results
 	function init() {
@@ -593,16 +623,23 @@
 		.addClass(options.resultsClass)
 		.css("position", "absolute")
-		.appendTo(document.body);
-	
+		.appendTo(document.body)
+		.hover(function(event) {
+		  // Browsers except FF do not fire mouseup event on scrollbars, resulting in mouseDownOnSelect remaining true, and results list not always hiding.
+		  if($(this).is(":visible")) {
+		    input.focus();
+		  }
+		  config.mouseDownOnSelect = false;
+		});
+
 		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);            
+			    $(target(event)).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();
+			if( options.inputFocus )
+			  input.focus();
 			return false;
 		}).mousedown(function() {
@@ -611,11 +648,11 @@
 			config.mouseDownOnSelect = false;
 		});
-		
+
 		if( options.width > 0 )
 			element.css("width", options.width);
-			
+
 		needsInit = false;
-	} 
-	
+	}
+
 	function target(event) {
 		var element = event.target;
@@ -644,14 +681,17 @@
         }
 	};
-	
+
 	function movePosition(step) {
-		active += step;
-		if (active < 0) {
-			active = listItems.size() - 1;
-		} else if (active >= listItems.size()) {
-			active = 0;
-		}
-	}
-	
+		if (options.scrollJumpPosition || (!options.scrollJumpPosition && !((step < 0 && active == 0) || (step > 0 && active == listItems.size() - 1)) )) {
+			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
@@ -659,5 +699,5 @@
 			: available;
 	}
-	
+
 	function fillList() {
 		list.empty();
@@ -681,5 +721,5 @@
 			list.bgiframe();
 	}
-	
+
 	return {
 		display: function(d, q) {
@@ -733,6 +773,6 @@
 					overflow: 'auto'
 				});
-				
-                if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
+
+                if(navigator.userAgent.indexOf("MSIE") != -1 && typeof document.body.style.maxHeight === "undefined") {
 					var listHeight = 0;
 					listItems.each(function() {
@@ -746,5 +786,5 @@
 					}
                 }
-                
+
             }
 		},
