function trace_autocomplete(){
	console.log('auto complete library file has been properly loaded');
}

/*!
 * Auto Complete 5.0
 * November 22, 2009
 * Corey Hart @ http://www.codenothing.com
 */
(function($, undefined){
    // Expose autoComplete to the jQuery chain
    $.fn.autoComplete = function(){
        // Force array of arguments
        var args = Slice.call(arguments), self = this, first = args.shift(), isMethod = (typeof first === 'string');
        
        // Deep namespacing is not supported in jQuery, a mistake I made in v4.1
        if (isMethod) 
            first = first.replace('.', '-');
        
        // Allow for passing array of arguments, or multiple arguments
        // Eg: .autoComplete('trigger', [arg1, arg2, arg3...]) or .autoComplete('trigger', arg1, arg2, arg3...)
        // Mainly to allow for .autoComplete('trigger', arguments) to work
        // Note*: button.supply passes an array as the first param, so check against that first
        args = first === 'button-supply' || first === 'direct-supply' ? $.isArray(args[0]) && $.isArray(args[0][0]) ? args[0] : args : args[1] === undefined && $.isArray(args[0]) ? args[0] : args;
        
        // Autocomplete special triggers
        return isMethod ? // The only chain breaking operation is option, which gets passed back the
        // settings/value it requested, otherwise trigger the event and don't break the chain!
        $(self)[first === 'option' && args.length < 2 ? 'triggerHandler' : 'trigger']('autoComplete.' + first, args) : // Allow passing a jquery event special object {from $.Event()}
 first && first[$.expando] ? $(self).trigger(first, args) : // Initiate the autocomplete (Only takes a single argument, the options object)
 AutoCompleteFunction.call(self, first);
    };
    
    // bgiframe is needed to fix z-index problem for IE6 users.
    $.fn.bgiframe = $.fn.bgiframe ? $.fn.bgiframe : $.fn.bgIframe ? $.fn.bgIframe : function(){
        // For applications that don't have bgiframe plugin installed, create a useless 
        // function that doesn't break the chain
        return this;
    };
    
    // The expando won't get attached to the jQuery object until 1.4 release(or so it seems in the nightlies)
    // To get the expando, we must create an event through jQuery, and filter it out.
    $.expando = $.expando !== undefined ? $.expando : (function(){
        var event = $.Event('keyup'), i;
        for (i in event) 
            if (i.indexOf('jQuery') === 0) 
                return i;
        // Use the event's timestamp on instances where 
        // expando isn't attached to the event object
        // (is it ever not?)
        return 'jQuery' + event.timeStamp;
    })();
    
    // Current timestamp
    function now(){
        return (new Date).getTime();
    }
    
    
    
    // Internals
    var // Munging
 TRUE = true, FALSE = false, // Copy of the slice prototype
 Slice = Array.prototype.slice, // Attach global aspects to jQuery itself
 AutoComplete = $.autoComplete = {
        // Index Counter
        counter: 0,
        
        // Attach length of stack to object
        length: 0,
        
        // Storage of elements
        stack: {},
        
        // Storage order of uid's
        order: [],
        
        // Global access to elements in use
        hasFocus: FALSE,
        
        // Callback methods for getting focus element
        getFocus: function(){
            return this.order[0] ? this.stack[this.order[0]] : undefined;
        },
        getPrevious: function(){
            // Removing elements cause some indexs on the order stack
            // to become undefined, so loop until one is found
            for (var i = 1, l = this.order.length; i < l; i++) 
                if (this.order[i]) 
                    return this.stack[this.order[i]];
            // If none are found, return undefined
            return undefined;
        },
        
        // Attempts to remove element from the stack
        remove: function(i){
            for (var k = 0, l = this.order.length; k < l; k++) 
                if (this.order[k] === i) 
                    this.order[k] = undefined;
            this.stack[i] = undefined;
            this.length--;
            delete this.stack[i];
        },
        
        // Returns full stack in jQuery form
        getAll: function(){
            for (var i = 0, l = this.counter, stack = []; i < l; i++) 
                if (this.stack[i]) 
                    stack.push(this.stack[i]);
            return $(stack);
        },
        
        defaults: {
            // To smooth upgrade process to 5.0, set backwardsCompatible to true
            backwardsCompatible: FALSE,
            // Server Script Path
            ajax: 'ajax.php',
            ajaxCache: $.ajaxSettings.cache,
            // Data Configuration
            dataSupply: [],
            dataFn: undefined,
            dataName: 'ac-data',
            // Drop List CSS
            list: 'auto-complete-list',
            rollover: 'auto-complete-list-rollover',
            width: undefined, // Defined as inputs width when extended (can be overridden with this global/options/meta)
            striped: undefined,
            maxHeight: undefined,
            newList: FALSE,
            // Post Data
            postVar: 'value',
            postData: {},
            // Limitations
            minChars: 1,
            maxItems: -1,
            maxRequests: 0,
            requestType: 'POST',
            // Input
            inputControl: undefined,
            autoFill: FALSE,
            nonInput: undefined,
            multiple: FALSE,
            multipleSeparator: ' ',
            // Events
            onBlur: undefined,
            onFocus: undefined,
            onHide: undefined,
            onLoad: undefined,
            onMaxRequest: function(){
            },
            onRollover: undefined,
            onSelect: undefined,
            onShow: undefined,
            onSubmit: function(){
                return TRUE;
            },
            spinner: undefined,
            preventEnterSubmit: TRUE,
            delay: 0,
            // Caching Options
            useCache: TRUE,
            cacheLimit: 50
        }
    }, // Autocomplete function
 AutoCompleteFunction = function(options){
        return this.each(function(){
            var // Cache a copy of the input element
 self = this, // Cache Input Object
 $input = $(self).attr('autocomplete', 'off'), // autoComplete enabled/disabled
 Active = TRUE, // Track every event triggered
 LastEvent = {}, // String of current input value
 inputval = '', // Place holder for all list elements
 $elems = {
                length: 0
            }, // Place holder for the list element in focus
 $li, // View and heights for scrolling
 view, ulHeight, liHeight, liPerView, // Harcoded value for ul visiblity
 ulOpen = FALSE, // Timer for delay
 timeid, // Ajax requests holder
 xhr, // li element in focus during key up/down, and its data
 liFocus = -1, liData, // For multiple selections
 separator, // Index of current input
 inputIndex = (function(){
                AutoComplete.length++;
                return ++AutoComplete.counter;
            })(), // Number of requests made
 requests = 0, // Internal Per Input Cache
 cache = {
                length: 0,
                val: undefined,
                list: {}
            }, // Merge defaults with passed options and metadata options
 settings = $.extend({
                width: $input.outerWidth()
            }, AutoComplete.defaults, options || {}, $.metadata ? $input.metadata() : {}), // Create the drop list (Use an existing one if possible)
 $ul = !settings.newList && $('ul.' + settings.list)[0] ? $('ul.' + settings.list).eq(0).bgiframe().data('autoComplete', TRUE) : $('<ul/>').appendTo('body').addClass(settings.list).bgiframe().hide().data('ac-selfmade', TRUE).data('autoComplete', TRUE), // Attach document click to force blur event
 $doc = $(document).bind('click.autoComplete-' + inputIndex, function(event){
                var $elem;
                // Make sure input is active and list is open
                if (Active && ulOpen &&
                // Double check the event timestamps to ensure there isn't
                // a delayed reaction from a button
                (!LastEvent || event.timeStamp - LastEvent.timeStamp > 200) &&
                // Check the target after all other checks are passed (less processing)
                ($elem = $(event.target)).closest('ul').data('ac-input-index') !== inputIndex &&
                // Also ensure that the input it's being clicked on either
                $elem.data('ac-input-index') !== inputIndex) {
                    $ul.hide(event);
                    // We want to trigger all blur events, so don't
                    // pass special autoComplete flags here through the
                    // trigger function
                    $input.blur();
                }
                LastEvent = event;
            });
            
            // Attach special fn's to ul
            newUl();
            // Upper case requestType now instead of on every call
            settings.requestType = settings.requestType.toUpperCase();
            // Set separator to local variable for munging
            separator = settings.multiple ? settings.multipleSeparator : undefined;
            // Add input to stack
            AutoComplete.stack[inputIndex] = self;
            
            /**
             * Input Central
             */
            // Show autocomplete has been initialized on this element
            $input.data('autoComplete', TRUE) // Attach input index and initial settings
.data('ac-input-index', inputIndex) // autoComplete Activity
.data('ac-active', Active) // Attach settings to initail and current states
.data('ac-initial-settings', $.extend(TRUE, {}, settings)).data('ac-settings', settings) // Central autoComplete specific function
            // Opera uses keypress as it has problems with keydown
            .bind(window.opera ? 'keypress.autoComplete' : 'keydown.autoComplete', function(event){
                // If autoComplete has been disabled, prevent input events
                if (!Active) 
                    return TRUE;
                // Track last event and store code for munging
                var key = (LastEvent = event).keyCode, enter = FALSE;
                
                // Tab Key
                if (key == 9 && ulOpen) {
                    select(event);
                } // Enter Key
 else if (key == 13 && $li) {
                    // IE needs keydown to return false on 'enter' so the element doesn't
                    // lose focus. The problem with returning false is that it prevents bubbling,
                    // and most importantly, form submission. To allow for most flexibility,
                    // preventEnterSubmit is used along with activity of drop down UL list to
                    // determine whether focus is on the drop list or is just on the input.
                    //
                    // Furthermore, preventEnterSubmit will now be defaulted to true, so as
                    // to affect as few implementations as possible, and the ones that need
                    // form submission on 'enter' can just set this flag to false for it to
                    // work as needed.
                    enter = settings.preventEnterSubmit && ulOpen ? FALSE : TRUE;
                    select(event);
                } // Up Arrow
 else if (key == 38) {
                    if (liFocus > 0) {
                        liFocus--;
                        up(event);
                    } else {
                        liFocus = -1;
                        $input.val(inputval);
                        $ul.hide(event);
                    }
                } // Down Arrow
 else if (key == 40) {
                    if (liFocus < $elems.length - 1) {
                        liFocus++;
                        down(event);
                    }
                } // Page Up
 else if (key == 33) {
                    if (liFocus > 0) {
                        liFocus -= liPerView;
                        if (liFocus < 0) 
                            liFocus = 0;
                        up(event);
                    }
                } // Page Down
 else if (key == 34) {
                    if (liFocus < $elems.length - 1) {
                        liFocus += liPerView;
                        if (liFocus > $elems.length - 1) 
                            liFocus = $elems.length - 1;
                        down(event);
                    }
                } // Check for non input values defined by user
 else if (settings.nonInput && $.inArray(key, settings.nonInput)) {
                    $ul.html('').hide(event);
                } // Everything else is considered possible input, so
                // return before keyup prevention flag is set
                else {
                    return TRUE;
                }
                
                // Prevent autoComplete keyup event's from triggering by
                // attaching a flag to the last event
                LastEvent[$.expando + '_autoComplete_keydown'] = TRUE;
                return enter;
            }) // Run a keydown event to specifically catch the tab key
.bind('keyup.autoComplete', function(event){
                // If autoComplete has been disabled or keyup prevention 
                // flag has be set, prevent input events
                if (!Active || LastEvent[$.expando + '_autoComplete_keydown']) 
                    return TRUE;
                
                /**
                 * If no special operations were run on keydown,
                 * allow for regular text searching
                 */
                inputval = $input.val();
                var key = (LastEvent = event).keyCode, val = separator ? inputval.split(separator).pop() : inputval;
                // Still check to make sure 'enter' wasn't pressed
                if (key != 13) {
                    // Caching key value
                    cache.val = settings.inputControl === undefined ? val : settings.inputControl.apply(self, settings.backwardsCompatible ? [val, key, $ul, event] : [event, {
                        val: val,
                        key: key,
                        ul: $ul
                    }]);
                    // Only send request if character length passes
                    if (cache.val.length >= settings.minChars) 
                        sendRequest(event, settings, cache, (key == 8 || key == 32));
                    // Remove list on backspace of small string
                    else if (key == 8) 
                        $ul.html('').hide(event);
                }
            }) // Bind specific Blur Actions
.bind('blur.autoComplete', function(event){
                // If autoComplete has been disabled or the drop list
                // is still open, prevent input events
                if (!Active || ulOpen) 
                    return TRUE;
                // Store event
                LastEvent = event;
                $input.data('ac-hasFocus', FALSE);
                liFocus = -1;
                // Only push undefined index onto order stack
                // if not already there (incase multiple blur events occur)
                if (AutoComplete.order[0] !== undefined) 
                    AutoComplete.order.unshift(undefined);
                // Expose focus
                AutoComplete.hasFocus = FALSE;
                $ul.hide(event);
                // Trigger blur callback last
                if (settings.onBlur) 
                    settings.onBlur.apply(self, settings.backwardsCompatible ? [inputval, $ul, event] : [event, {
                        val: inputval,
                        ul: $ul
                    }]);
            }) // Bind specific focus actions
.bind('focus.autoComplete', function(event, flag){
                // If autoComplete has been disabled but not destoyed, just return true 
                if (!Active ||
                // Prevent inner focus events if caused by autoComplete inner functionality
                (AutoComplete.focus === inputIndex && flag === $.expando + '_autoComplete') ||
                // Because IE triggers focus AND closes the drop list before form submission,
                // prevent inner function focus functionality & pass on the select flag
                LastEvent[$.expando + '_autoComplete_enter']) 
                    return TRUE;
                // Store event
                LastEvent = event;
                // If ul is not associated with current input, clear it
                if (inputIndex != $ul.data('ac-input-index')) 
                    $ul.html('').hide(event);
                // Store focus into input
                $input.data('ac-hasFocus', TRUE);
                // Overwrite undefined index pushed on by the blur event
                if (AutoComplete.order[0] === undefined) {
                    if (AutoComplete.order[1] === inputIndex) 
                        AutoComplete.order.shift();
                    else 
                        AutoComplete.order[0] = inputIndex;
                } // Only push another uid if it's not the current one
 else if (AutoComplete.order[0] != inputIndex && AutoComplete.order[1] != inputIndex) 
                    AutoComplete.order.unshift(inputIndex);
                // Keep the order array to within the global cacheLimit size
                if (AutoComplete.order.length > AutoComplete.defaults.cacheLimit) 
                    AutoComplete.order.pop();
                // Expose focus
                AutoComplete.hasFocus = TRUE;
                // Trigger focus callback last
                if (settings.onFocus) 
                    settings.onFocus.apply(self, settings.backwardsCompatible ? [$ul, event] : [event, {
                        ul: $ul
                    }]);
            })            /**
             * Autocomplete Methods
             * -Extensions off autoComplete event
             */
            // Allows for change of settings at any point
            .bind('autoComplete.settings', function(event, newSettings){
                // If autoComplete has been disabled, prevent input events
                if (!Active) 
                    return TRUE;
                // Give access to current settings and cache
                if ($.isFunction(newSettings)) {
                    var ret = newSettings.apply(self, settings.backwardsCompatible ? [settings, cache, $ul, event] : [event, {
                        settings: settings,
                        cache: cache,
                        ul: $ul
                    }]);
                    // Allow for extending of settings/cache based off function return values
                    if ($.isArray(ret) && ret[0] !== undefined) {
                        settings = $.extend(TRUE, {}, settings, ret[0] || settings);
                        cache = $.extend(TRUE, {}, cache, ret[1] || cache);
                    }
                } else {
                    // Extend deep so settings are kept
                    settings = $.extend(TRUE, {}, settings, newSettings || {});
                }
                // Upper case requestType now instead of on every call
                settings.requestType = settings.requestType.toUpperCase();
                // Reassign local separator
                separator = settings.multiple ? settings.multipleSeparator : undefined;
                // Restablish current settings onto the inputs data
                $input.data('ac-settings', settings);
                // Change the drop down if user want's a differen't class attached
                $ul = !settings.newList && $ul.hasClass(settings.list) ? $ul : !settings.newList && $('ul.' + settings.list)[0] ? $('ul.' + settings.list).bgiframe().data('autoComplete', TRUE) : $('<ul/>').appendTo('body').addClass(settings.list).bgiframe().hide().data('ac-selfmade', TRUE).data('autoComplete', TRUE);
                // Attach special ul fn's
                newUl();
                // Return & Store event
                return LastEvent = event;
            }) // Clears the Cache & requests (requests can be blocked on request)
.bind('autoComplete.flush', function(event, cacheOnly){
                // If autoComplete has been disabled, prevent input events
                if (!Active) 
                    return TRUE;
                cache = {
                    length: 0,
                    val: undefined,
                    list: {}
                };
                if (!cacheOnly) 
                    requests = 0;
                // Store & return event
                return LastEvent = event;
            }) // External button trigger for ajax requests
.bind('autoComplete.button-ajax', function(event, postData, cacheName){
                // If autoComplete has been disabled, prevent input events
                if (!Active) 
                    return TRUE;
                // Store event
                LastEvent = event;
                // Refocus the input box and pass flag to prevent inner focus events
                $input.trigger('focus', [$.expando + '_autoComplete']);
                // Allow for just passing the cache name
                if (typeof postData === 'string') {
                    cacheName = postData;
                    postData = {};
                }
                // If no cache name is given, supply a non-common word
                cache.val = cacheName || 'NON_404_<>!@$^&';
                // Timer is done within sendRequest
                return sendRequest(event, $.extend(TRUE, {}, settings, {
                    maxItems: -1,
                    postData: postData || {}
                }), cache);
            }) // External button trigger for supplied data
.bind('autoComplete.button-supply', function(event, data, cacheName){
                // If autoComplete has been disabled, prevent input events
                if (!Active) 
                    return TRUE;
                // Store event
                LastEvent = event;
                // Refocus the input box and pass flag to prevent inner focus events
                $input.trigger('focus', [$.expando + '_autoComplete']);
                // Allow for just passing of cacheName
                if (typeof data === 'string') {
                    cacheName = data;
                    data = undefined;
                }
                // If no cache name is given, supply a non-common word
                cache.val = cacheName || 'NON_404_SUPPLY_<>!@$^&';
                // If no data is supplied, use data in settings
                data = $.isArray(data) && data.length ? data : settings.dataSupply;
                // Timer done within sendRequest
                return sendRequest(event, $.extend(TRUE, {}, settings, {
                    maxItems: -1,
                    dataSupply: data,
                    dataFn: function(){
                        return TRUE;
                    }
                }), cache);
            }) // Supply list directly into the result function
.bind('autoComplete.direct-supply', function(event, data, cacheName){
                // If autoComplete has been disabled, prevent input events
                if (!Active) 
                    return TRUE;
                // Store event
                LastEvent = event;
                // Refocus the input box and pass flag to prevent inner focus events
                $input.trigger('focus', [$.expando + '_autoComplete']);
                // Allow for just passing of cacheName
                if (typeof data === 'string') {
                    cacheName = data;
                    data = undefined;
                }
                // If no cache name is given, supply a non-common word
                cache.val = cacheName || 'NON_404_SUPPLY_<>!@$^&';
                // If no data is supplied, use data in settings
                data = $.isArray(data) && data.length ? data : settings.dataSupply;
                // Load the results directly into the results function
                // bypassing error checks (Only do)
                return loadResults(event, data, $.extend(TRUE, {}, settings, {
                    maxItems: -1,
                    dataSupply: data,
                    dataFn: function(){
                        return TRUE;
                    }
                }), cache);
            }) // Triggering autocomplete programatically
.bind('autoComplete.search', function(event, value){
                // If autoComplete has been disabled, prevent input events
                if (!Active) 
                    return TRUE;
                cache.val = value || '';
                // Timer done within sendRequest
                return sendRequest(LastEvent = event, settings, cache);
            }) // Add jquery-ui like option access
.bind('autoComplete.option', function(event){
                // If autoComplete has been disabled, prevent input events
                if (!Active) 
                    return TRUE;
                // Store event
                LastEvent = event;
                var args = Slice.call(arguments), length = args.length;
                return length == 3 ? (function(){
                    settings[args[1]] = args[2];
                    $input.data('ac-settings', settings);
                    return args[2];
                })() : length == 2 ? (function(){
                    switch (args[1]) {
                        case 'ul':
                            return $ul;
                        case 'cache':
                            return cache;
                        case 'xhr':
                            return xhr;
                        case 'input':
                            return $input;
                        default:
                            return settings[args[1]] || undefined;
                    }
                })() : settings;
            }) // Add enabling event (only applicable after disable)
.bind('autoComplete.enable', function(event){
                $input.data('ac-active', Active = TRUE);
                // Store & return event
                return LastEvent = event;
            }) // Add disable event
.bind('autoComplete.disable', function(event){
                // Store event
                $input.data('ac-active', Active = FALSE);
                $ul.html('').hide(event);
                // Store & return event
                return LastEvent = event;
            }) // Add a destruction function
.bind('autoComplete.destroy', function(event){
                // Break down the input
                $input // Remove all autoComplete Specific Data
.removeData('autoComplete').removeData('ac-input-index').removeData('ac-initial-settings').removeData('ac-settings').removeData('ac-active') // Remove all autoComplete specific events
.unbind('.autoComplete') // jQuery requires every namespace attached to
                // a made up event to be removed separately
                .unbind('autoComplete.' +
                ['settings', 'flush', 'button-ajax', 'button-supply', 'direct-supply', 'search', 'option', 'enable', 'disable', 'destroy'].join(' autoComplete.')) // Unbind the form submission event
.parents('form').eq(0).unbind('submit.autoComplete-' + inputIndex);
                // Remove document click event
                $doc.unbind('click.autoComplete-' + inputIndex);
                // Remove from stack
                AutoComplete.remove(inputIndex);
                // Disable Activity
                Active = FALSE;
                // Clean the UL
                var list = $ul.html('').hide(event).data('ac-inputs'), i;
                list[inputIndex] = undefined;
                for (i in list) 
                    if (list[i] === TRUE) 
                        return LastEvent = event;
                // Remove the element from the DOM if self created no other input is using it
                if ($ul.data('ac-selfmade') === TRUE) 
                    $ul.remove();
                // Store & return event
                return LastEvent = event;
            }) // Back to normal events
            // Prevent form submission if defined in settings
            .parents('form').eq(0).bind('submit.autoComplete-' + inputIndex, function(event){
                // If autoComplete has been disabled, prevent input events
                if (!Active) 
                    return TRUE;
                // Because IE triggers focus AND closes the drop list before form submission, store the flag if any
                var flag = LastEvent[$.expando + '_autoComplete_enter'] || FALSE;
                // Store event
                LastEvent = event;
                return settings.preventEnterSubmit ? (ulOpen || flag) ? FALSE : settings.onSubmit.call(self, event, {
                    form: this,
                    ul: $ul
                }) : settings.onSubmit.call(self, event, {
                    form: this,
                    ul: $ul
                });
            });
            
            // Ajax/Cache Request
            function sendRequest(event, settings, cache, backSpace, timeout){
                // Pass spinner enabler
                if (settings.spinner) 
                    settings.spinner.call(self, event, {
                        active: TRUE,
                        ul: $ul
                    });
                // Centralize the timer request
                if (timeid) 
                    timeid = clearTimeout(timeid);
                // Call send request again with timeout flag if on delay
                if (settings.delay > 0 && timeout === undefined) 
                    return timeid = setTimeout(function(){
                        sendRequest(event, settings, cache, backSpace, TRUE);
                        timeid = clearTimeout(timeid);
                    }, settings.delay);
                
                // Abort previous request incase it's still running
                if (xhr) 
                    xhr.abort();
                
                // Load from cache if possible
                if (settings.useCache && cache.list[cache.val]) 
                    return loadResults(event, cache.list[cache.val], settings, cache, backSpace);
                
                // Use user supplied data when defined
                if (settings.dataSupply.length) 
                    return userSuppliedData(event, settings, cache, backSpace);
                
                // Check Max requests first before sending request
                if (settings.maxRequests && ++requests >= settings.maxRequests) {
                    $ul.html('').hide(event);
                    if (settings.spinner) 
                        settings.spinner.call(self, event, {
                            active: FALSE,
                            ul: $ul
                        });
                    return requests > settings.maxRequests ? FALSE : settings.onMaxRequest.apply(self, settings.backwardsCompatible ? [cache.val, $ul, event, inputval] : [event, {
                        search: cache.val,
                        val: inputval,
                        ul: $ul
                    }]);
                }
                
                // Send request server side
                settings.postData[settings.postVar] = cache.val;
                // Switched to base ajax request to remove list on errors
                return xhr = $.ajax({
                    type: settings.requestType,
                    url: settings.ajax,
                    data: settings.postData,
                    dataType: 'json',
                    cache: settings.ajaxCache,
                    success: function(list, status){
                        loadResults(event, list, settings, cache, backSpace);
                    },
                    error: function(){
                        $ul.html('').hide(event);
                        if (settings.spinner) 
                            settings.spinner.call(self, event, {
                                active: FALSE,
                                ul: $ul
                            });
                    }
                });
            }
            
            // Parse User Supplied Data
            function userSuppliedData(event, settings, cache, backSpace){
                var list = [], // Result list
 args = [], // Backwards Compatibility
 fn = $.isFunction(settings.dataFn), // User supplied function
 regex = fn ? undefined : new RegExp('^' + cache.val, 'i'), // Only compile regex if needed
 k = 0, entry, i = 0, l = settings.dataSupply.length; // Looping vars
                // Loop through each entry and find matches
                for (; i < l; i++) {
                    entry = settings.dataSupply[i];
                    // Force object
                    entry = typeof entry === 'object' && entry.value ? entry : {
                        value: entry
                    };
                    // Setup arguments for dataFn in a backwards compatible way if needed
                    args = settings.backwardsCompatible ? [cache.val, entry.value, list, i, settings.dataSupply, $ul, event] : [event, {
                        val: cache.val,
                        entry: entry.value,
                        list: list,
                        i: i,
                        supply: settings.dataSupply,
                        ul: $ul
                    }];
                    // If user supplied function, use that, otherwise test with default regex
                    if ((fn && settings.dataFn.apply(self, args)) || (!fn && entry.value.match(regex))) {
                        // Reduce browser load by breaking on limit if it exists
                        if (settings.maxItems > -1 && ++k > settings.maxItems) 
                            break;
                        list.push(entry);
                    }
                }
                // Use normal load functionality
                return loadResults(event, list, settings, cache, backSpace);
            }
            
            // Key element Selection
            function select(event){
                // Ensure the select function only gets fired when list of open
                if (ulOpen) {
                    if (settings.onSelect) 
                        settings.onSelect.apply(self, settings.backwardsCompatible ? [liData, $li, $ul, event] : [event, {
                            data: liData,
                            li: $li,
                            ul: $ul
                        }]);
                    autoFill(undefined);
                    inputval = $input.val();
                    // Because IE triggers focus AND closes the drop list before form submission
                    // attach a flag on 'enter' selection
                    if (LastEvent.type == 'keydown') 
                        LastEvent[$.expando + '_autoComplete_enter'] = TRUE;
                }
                $ul.hide(event);
                return $li;
            }
            
            // Key direction up
            function up(event){
                if ($li) 
                    $li.removeClass(settings.rollover);
                $ul.show(event);
                $li = $elems.eq(liFocus).addClass(settings.rollover);
                liData = $li.data(settings.dataName);
                if (!$li.length || !liData) 
                    return FALSE;
                autoFill(liData.value || '');
                if (settings.onRollover) 
                    settings.onRollover.apply(self, settings.backwardsCompatible ? [liData, $li, $ul, event] : [event, {
                        data: liData,
                        li: $li,
                        ul: $ul
                    }]);
                // Scrolling
                var v = liFocus * liHeight;
                if (v < view - ulHeight) {
                    view = v + ulHeight;
                    $ul.scrollTop(v);
                }
                return $li;
            }
            
            // Key direction down
            function down(event){
                if ($li) 
                    $li.removeClass(settings.rollover);
                $ul.show(event);
                $li = $elems.eq(liFocus).addClass(settings.rollover);
                liData = $li.data(settings.dataName);
                if (!$li.length || !liData) 
                    return FALSE;
                autoFill(liData.value || '');
                // Scrolling
                var v = (liFocus + 1) * liHeight;
                if (v > view) 
                    $ul.scrollTop((view = v) - ulHeight);
                // Callback
                if (settings.onRollover) 
                    settings.onRollover.apply(self, settings.backwardsCompatible ? [liData, $li, $ul, event] : [event, {
                        data: liData,
                        li: $li,
                        ul: $ul
                    }]);
                return $li;
            }
            
            // Attach new show/hide functionality to only the
            // ul object (so not to infect all of jQuery)
            function newUl(){
                if (!$ul[$.expando + '_autoComplete']) {
                    // Make a copy of the old show/hide
                    var hide = $ul.hide, show = $ul.show;
                    $ul.hide = function(event, speed, callback){
                        if (settings.onHide && ulOpen) {
                            settings.onHide.call(self, event, {
                                ul: $ul
                            });
                            LastEvent[$.expando + '_autoComplete_hide'] = TRUE;
                        }
                        ulOpen = FALSE;
                        return hide.call($ul, speed, callback);
                    };
                    $ul.show = function(event, speed, callback){
                        if (settings.onShow && !ulOpen) 
                            settings.onShow.call(self, event, {
                                ul: $ul
                            });
                        ulOpen = TRUE;
                        return show.call($ul, speed, callback);
                    };
                    // A flag must be attached to the $ul cached object
                    $ul[$.expando + '_autoComplete'] = TRUE;
                }
                var list = $ul.data('ac-inputs') || {};
                list[inputIndex] = TRUE;
                return $ul.data('ac-inputs', list);
            }
            
            // Auto-fill the input
            // Credit to Jörn Zaefferer @ http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/
            // and http://www.pengoworks.com/workshop/jquery/autocomplete.htm for this functionality
            function autoFill(val){
                // Set starting and ending points based on values
                if (val === undefined) {
                    var start, end;
                    start = end = $input.val().length;
                } else {
                    if (separator) 
                        val = inputval.substr(0, inputval.length - inputval.split(separator).pop().length) + val + separator;
                    var start = inputval.length, end = val.length;
                    $input.val(val);
                }
                
                // Create selection if allowed
                if (!settings.autoFill || start > end) {
                    return FALSE;
                } else if (self.createTextRange) {
                    var range = self.createTextRange();
                    if (val === undefined) {
                        range.move('character', start);
                        range.select();
                    } else {
                        range.collapse(TRUE);
                        range.moveStart("character", start);
                        range.moveEnd("character", end);
                        range.select();
                    }
                } else if (self.setSelectionRange) {
                    self.setSelectionRange(start, end);
                } else if (self.selectionStart) {
                    self.selectionStart = start;
                    self.selectionEnd = end;
                }
                return TRUE;
            }
            
            // List Functionality
            function loadResults(event, list, settings, cache, backSpace){
                // Allow another level of result handling
                if (settings.onLoad) 
                    list = settings.onLoad.call(self, event, {
                        list: list,
                        settings: settings,
                        cache: cache,
                        ul: $ul
                    });
                // Pass spinner killer as wait time is done in javascript processing
                if (settings.spinner) 
                    settings.spinner.call(self, event, {
                        active: FALSE,
                        ul: $ul
                    });
                // Store results into the cache if allowed
                if (settings.useCache && cache.list[cache.val] === undefined) {
                    cache.length++;
                    cache.list[cache.val] = list;
                    // Clear cache if necessary
                    if (cache.length > settings.cacheLimit) {
                        cache.list = {};
                        cache.length = 0;
                    }
                }
                
                // Ensure there is a list
                if (!list || list.length < 1) 
                    return $ul.html('').hide(event);
                
                // Refocus list element
                liFocus = -1;
                
                // Initialize Vars together (save bytes)
                var offset = $input.offset(), // Input position
 container = [], // Container for list elements
 aci = 0, k = 0, i = 0, even = FALSE, length = list.length; // Loop Items
                // Push items onto container
                for (; i < length; i++) {
                    if (list[i].value) {
                        if (settings.maxItems > -1 && ++aci > settings.maxItems) 
                            break;
                        container.push(settings.striped && even ? '<li class="' + settings.striped + '">' : '<li>', list[i].display || list[i].value, '</li>');
                        even = !even;
                    }
                }
                
                // Load items into list
                $elems = $ul.html(container.join('')).children('li');
                for (length = $elems.length; k < length; k++) {
                    $.data($elems[k], settings.dataName, list[k]);
                    $.data($elems[k], 'ac-index', k);
                }
                
                
                // Autofill input with first entry
                if (settings.autoFill && !backSpace) {
                    liFocus = 0;
                    liData = list[0];
                    autoFill(liData.value || '');
                    $li = $elems.eq(0).addClass(settings.rollover);
                }
                
                // Clear off old events and attach new ones
                $ul.unbind('.autoComplete') // Attach input index in focus
.data('ac-input-index', inputIndex) // Remove focus elements hover class
.bind('mouseout.autoComplete', function(){
                    $li.removeClass(settings.rollover);
                }) // Mouseover using event delegation
.bind('mouseover.autoComplete', function(event){
                    $li = $(event.target).closest('li');
                    // Ensure 'li' mouseover
                    if ($li.length < 1) 
                        return FALSE;
                    // Remove hover class from last rollover
                    $elems.filter('.' + settings.rollover).removeClass(settings.rollover);
                    liFocus = $li.addClass(settings.rollover).data('ac-index');
                    liData = $li.data(settings.dataName);
                    if (settings.onRollover) 
                        settings.onRollover.apply(self, settings.backwardsCompatible ? [liData, $li, $ul, event] : [event, {
                            data: liData,
                            li: $li,
                            ul: $ul
                        }]);
                }) // Click event using target from mouseover
.bind('click.autoComplete', function(event){
                    // reordered this before trigger
                    liData = $li.data(settings.dataName);
                    // Refocus the input box and pass flag to prevent inner focus events
                    $input.trigger('focus', [$.expando + '_autoComplete']);
                    // Check against separator for input value
                    $input.val(inputval = separator ? inputval.substr(0, inputval.length - inputval.split(separator).pop().length) + liData.value + separator : liData.value);
                    $ul.hide(event);
                    autoFill(undefined);
                    if (settings.onSelect) 
                        settings.onSelect.apply(self, settings.backwardsCompatible ? [liData, $li, $ul, event] : [event, {
                            data: liData,
                            li: $li,
                            ul: $ul
                        }]);
                }) // Reposition list
.css({
                    top: offset.top + $input.outerHeight(),
                    left: offset.left,
                    width: settings.width
                }) // Scroll to the top
.scrollTop(0);
                
                // If Max Height specified, control it
                if (settings.maxHeight) 
                    $ul.css({
                        height: liHeight * $elems.length > settings.maxHeight ? settings.maxHeight : 'auto',
                        overflow: 'auto'
                    });
                
                // Apply list height to view for inital value,
                // and show the list now so no jerkiness from css
                // changes are shown to the user
                ulHeight = $ul.show(event).outerHeight();
                view = ulHeight;
                // Log li height for less computation
                liHeight = $elems.eq(0).outerHeight();
                // Number of elements per viewport
                liPerView = Math.floor(view / liHeight);
                
                // Include amount of time it took
                // to load the list
                LastEvent.timeStamp = now();
                
                // Every function needs to return something
                return $ul;
            }
        });
    };
})(jQuery);

