PageSourceSearch

https://lankersreisen.de/assets/p/cdn/quadra/resources/typeahead.bundle.js?ver=7.1

js lankersreisen.de collected 2026-10-07 04:03:33 UTC 105,732 bytes, 2,641 lines download raw bytes

vendor: 5,858 bytes, lines 1-162
1/*!
2 * typeahead.js 1.3.1
3 * https://github.com/corejavascript/typeahead.js
4 * Copyright 2013-2020 Twitter, Inc. and other contributors; Licensed MIT
5 */
6
7
8(function(root, factory) {
9    if (typeof define === "function" && define.amd) {
10        define([ "jquery" ], function(a0) {
11            return root["Bloodhound"] = factory(a0);
12        });
13    } else if (typeof module === "object" && module.exports) {
14        module.exports = factory(require("jquery"));
15    } else {
16        root["Bloodhound"] = factory(root["jQuery"]);
17    }
18})(this, function($) {
19    var _ = function() {
20        "use strict";
21        return {
22            isMsie: function() {
23                return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
24            },
25            isBlankString: function(str) {
26                return !str || /^\s*$/.test(str);
27            },
28            escapeRegExChars: function(str) {
29                return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
30            },
31            isString: function(obj) {
32                return typeof obj === "string";
33            },
34            isNumber: function(obj) {
35                return typeof obj === "number";
36            },
37            isArray: $.isArray,
38            isFunction: $.isFunction,
39            isObject: $.isPlainObject,
40            isUndefined: function(obj) {
41                return typeof obj === "undefined";
42            },
43            isElement: function(obj) {
44                return !!(obj && obj.nodeType === 1);
45            },
46            isJQuery: function(obj) {
47                return obj instanceof $;
48            },
49            toStr: function toStr(s) {
50                return _.isUndefined(s) || s === null ? "" : s + "";
51            },
52            bind: $.proxy,
53            each: function(collection, cb) {
54                $.each(collection, reverseArgs);
55                function reverseArgs(index, value) {
56                    return cb(value, index);
57                }
58            },
59            map: $.map,
60            filter: $.grep,
61            every: function(obj, test) {
62                var result = true;
63                if (!obj) {
64                    return result;
65                }
66                $.each(obj, function(key, val) {
67                    if (!(result = test.call(null, val, key, obj))) {
68                        return false;
69                    }
70                });
71                return !!result;
72            },
73            some: function(obj, test) {
74                var result = false;
75                if (!obj) {
76                    return result;
77                }
78                $.each(obj, function(key, val) {
79                    if (result = test.call(null, val, key, obj)) {
80                        return false;
81                    }
82                });
83                return !!result;
84            },
85            mixin: $.extend,
86            identity: function(x) {
87                return x;
88            },
89            clone: function(obj) {
90                return $.extend(true, {}, obj);
91            },
92            getIdGenerator: function() {
93                var counter = 0;
94                return function() {
95                    return counter++;
96                };
97            },
98            templatify: function templatify(obj) {
99                return $.isFunction(obj) ? obj : template;
100                function template() {
101                    return String(obj);
102                }
103            },
104            defer: function(fn) {
105                setTimeout(fn, 0);
106            },
107            debounce: function(func, wait, immediate) {
108                var timeout, result;
109                return function() {
110                    var context = this, args = arguments, later, callNow;
111                    later = function() {
112                        timeout = null;
113                        if (!immediate) {
114                            result = func.apply(context, args);
115                        }
116                    };
117                    callNow = immediate && !timeout;
118                    clearTimeout(timeout);
119                    timeout = setTimeout(later, wait);
120                    if (callNow) {
121                        result = func.apply(context, args);
122                    }
123                    return result;
124                };
125            },
126            throttle: function(func, wait) {
127                var context, args, timeout, result, previous, later;
128                previous = 0;
129                later = function() {
130                    previous = new Date();
131                    timeout = null;
132                    result = func.apply(context, args);
133                };
134                return function() {
135                    var now = new Date(), remaining = wait - (now - previous);
136                    context = this;
137                    args = arguments;
138                    if (remaining <= 0) {
139                        clearTimeout(timeout);
140                        timeout = null;
141                        previous = now;
142                        result = func.apply(context, args);
143                    } else if (!timeout) {
144                        timeout = setTimeout(later, remaining);
145                    }
146                    return result;
147                };
148            },
149            stringify: function(val) {
150                return _.isString(val) ? val : JSON.stringify(val);
151            },
152            guid: function() {
153                function _p8(s) {
154                    var p = (Math.random().toString(16) + "000000000").substr(2, 8);
155                    return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p;
156                }
157                return "tt-" + _p8() + _p8(true) + _p8(true) + _p8();
158            },
159            noop: function() {}
160        };
161    }();
162    var VERSION = "1.3.1
vendor: 27,633 bytes, lines 162-920
162";
163    var tokenizers = function() {
164        "use strict";
165        return {
166            nonword: nonword,
167            whitespace: whitespace,
168            ngram: ngram,
169            obj: {
170                nonword: getObjTokenizer(nonword),
171                whitespace: getObjTokenizer(whitespace),
172                ngram: getObjTokenizer(ngram)
173            }
174        };
175        function whitespace(str) {
176            str = _.toStr(str);
177            return str ? str.split(/\s+/) : [];
178        }
179        function nonword(str) {
180            str = _.toStr(str);
181            return str ? str.split(/\W+/) : [];
182        }
183        function ngram(str) {
184            str = _.toStr(str);
185            var tokens = [], word = "";
186            _.each(str.split(""), function(char) {
187                if (char.match(/\s+/)) {
188                    word = "";
189                } else {
190                    tokens.push(word + char);
191                    word += char;
192                }
193            });
194            return tokens;
195        }
196        function getObjTokenizer(tokenizer) {
197            return function setKey(keys) {
198                keys = _.isArray(keys) ? keys : [].slice.call(arguments, 0);
199                return function tokenize(o) {
200                    var tokens = [];
201                    _.each(keys, function(k) {
202                        tokens = tokens.concat(tokenizer(_.toStr(o[k])));
203                    });
204                    return tokens;
205                };
206            };
207        }
208    }();
209    var LruCache = function() {
210        "use strict";
211        function LruCache(maxSize) {
212            this.maxSize = _.isNumber(maxSize) ? maxSize : 100;
213            this.reset();
214            if (this.maxSize <= 0) {
215                this.set = this.get = $.noop;
216            }
217        }
218        _.mixin(LruCache.prototype, {
219            set: function set(key, val) {
220                var tailItem = this.list.tail, node;
221                if (this.size >= this.maxSize) {
222                    this.list.remove(tailItem);
223                    delete this.hash[tailItem.key];
224                    this.size--;
225                }
226                if (node = this.hash[key]) {
227                    node.val = val;
228                    this.list.moveToFront(node);
229                } else {
230                    node = new Node(key, val);
231                    this.list.add(node);
232                    this.hash[key] = node;
233                    this.size++;
234                }
235            },
236            get: function get(key) {
237                var node = this.hash[key];
238                if (node) {
239                    this.list.moveToFront(node);
240                    return node.val;
241                }
242            },
243            reset: function reset() {
244                this.size = 0;
245                this.hash = {};
246                this.list = new List();
247            }
248        });
249        function List() {
250            this.head = this.tail = null;
251        }
252        _.mixin(List.prototype, {
253            add: function add(node) {
254                if (this.head) {
255                    node.next = this.head;
256                    this.head.prev = node;
257                }
258                this.head = node;
259                this.tail = this.tail || node;
260            },
261            remove: function remove(node) {
262                node.prev ? node.prev.next = node.next : this.head = node.next;
263                node.next ? node.next.prev = node.prev : this.tail = node.prev;
264            },
265            moveToFront: function(node) {
266                this.remove(node);
267                this.add(node);
268            }
269        });
270        function Node(key, val) {
271            this.key = key;
272            this.val = val;
273            this.prev = this.next = null;
274        }
275        return LruCache;
276    }();
277    var PersistentStorage = function() {
278        "use strict";
279        var LOCAL_STORAGE;
280        try {
281            LOCAL_STORAGE = window.localStorage;
282            LOCAL_STORAGE.setItem("~~~", "!");
283            LOCAL_STORAGE.removeItem("~~~");
284        } catch (err) {
285            LOCAL_STORAGE = null;
286        }
287        function PersistentStorage(namespace, override) {
288            this.prefix = [ "__", namespace, "__" ].join("");
289            this.ttlKey = "__ttl__";
290            this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
291            this.ls = override || LOCAL_STORAGE;
292            !this.ls && this._noop();
293        }
294        _.mixin(PersistentStorage.prototype, {
295            _prefix: function(key) {
296                return this.prefix + key;
297            },
298            _ttlKey: function(key) {
299                return this._prefix(key) + this.ttlKey;
300            },
301            _noop: function() {
302                this.get = this.set = this.remove = this.clear = this.isExpired = _.noop;
303            },
304            _safeSet: function(key, val) {
305                try {
306                    this.ls.setItem(key, val);
307                } catch (err) {
308                    if (err.name === "QuotaExceededError") {
309                        this.clear();
310                        this._noop();
311                    }
312                }
313            },
314            get: function(key) {
315                if (this.isExpired(key)) {
316                    this.remove(key);
317                }
318                return decode(this.ls.getItem(this._prefix(key)));
319            },
320            set: function(key, val, ttl) {
321                if (_.isNumber(ttl)) {
322                    this._safeSet(this._ttlKey(key), encode(now() + ttl));
323                } else {
324                    this.ls.removeItem(this._ttlKey(key));
325                }
326                return this._safeSet(this._prefix(key), encode(val));
327            },
328            remove: function(key) {
329                this.ls.removeItem(this._ttlKey(key));
330                this.ls.removeItem(this._prefix(key));
331                return this;
332            },
333            clear: function() {
334                var i, keys = gatherMatchingKeys(this.keyMatcher);
335                for (i = keys.length; i--; ) {
336                    this.remove(keys[i]);
337                }
338                return this;
339            },
340            isExpired: function(key) {
341                var ttl = decode(this.ls.getItem(this._ttlKey(key)));
342                return _.isNumber(ttl) && now() > ttl ? true : false;
343            }
344        });
345        return PersistentStorage;
346        function now() {
347            return new Date().getTime();
348        }
349        function encode(val) {
350            return JSON.stringify(_.isUndefined(val) ? null : val);
351        }
352        function decode(val) {
353            return $.parseJSON(val);
354        }
355        function gatherMatchingKeys(keyMatcher) {
356            var i, key, keys = [], len = LOCAL_STORAGE.length;
357            for (i = 0; i < len; i++) {
358                if ((key = LOCAL_STORAGE.key(i)).match(keyMatcher)) {
359                    keys.push(key.replace(keyMatcher, ""));
360                }
361            }
362            return keys;
363        }
364    }();
365    var Transport = function() {
366        "use strict";
367        var pendingRequestsCount = 0, pendingRequests = {}, sharedCache = new LruCache(10);
368        function Transport(o) {
369            o = o || {};
370            this.maxPendingRequests = o.maxPendingRequests || 6;
371            this.cancelled = false;
372            this.lastReq = null;
373            this._send = o.transport;
374            this._get = o.limiter ? o.limiter(this._get) : this._get;
375            this._cache = o.cache === false ? new LruCache(0) : sharedCache;
376        }
377        Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
378            this.maxPendingRequests = num;
379        };
380        Transport.resetCache = function resetCache() {
381            sharedCache.reset();
382        };
383        _.mixin(Transport.prototype, {
384            _fingerprint: function fingerprint(o) {
385                o = o || {};
386                return o.url + o.type + $.param(o.data || {});
387            },
388            _get: function(o, cb) {
389                var that = this, fingerprint, jqXhr;
390                fingerprint = this._fingerprint(o);
391                if (this.cancelled || fingerprint !== this.lastReq) {
392                    return;
393                }
394                if (jqXhr = pendingRequests[fingerprint]) {
395                    jqXhr.done(done).fail(fail);
396                } else if (pendingRequestsCount < this.maxPendingRequests) {
397                    pendingRequestsCount++;
398                    pendingRequests[fingerprint] = this._send(o).done(done).fail(fail).always(always);
399                } else {
400                    this.onDeckRequestArgs = [].slice.call(arguments, 0);
401                }
402                function done(resp) {
403                    cb(null, resp);
404                    that._cache.set(fingerprint, resp);
405                }
406                function fail() {
407                    cb(true);
408                }
409                function always() {
410                    pendingRequestsCount--;
411                    delete pendingRequests[fingerprint];
412                    if (that.onDeckRequestArgs) {
413                        that._get.apply(that, that.onDeckRequestArgs);
414                        that.onDeckRequestArgs = null;
415                    }
416                }
417            },
418            get: function(o, cb) {
419                var resp, fingerprint;
420                cb = cb || $.noop;
421                o = _.isString(o) ? {
422                    url: o
423                } : o || {};
424                fingerprint = this._fingerprint(o);
425                this.cancelled = false;
426                this.lastReq = fingerprint;
427                if (resp = this._cache.get(fingerprint)) {
428                    cb(null, resp);
429                } else {
430                    this._get(o, cb);
431                }
432            },
433            cancel: function() {
434                this.cancelled = true;
435            }
436        });
437        return Transport;
438    }();
439    var SearchIndex = window.SearchIndex = function() {
440        "use strict";
441        var CHILDREN = "c", IDS = "i";
442        function SearchIndex(o) {
443            o = o || {};
444            if (!o.datumTokenizer || !o.queryTokenizer) {
445                $.error("datumTokenizer and queryTokenizer are both required");
446            }
447            this.identify = o.identify || _.stringify;
448            this.datumTokenizer = o.datumTokenizer;
449            this.queryTokenizer = o.queryTokenizer;
450            this.matchAnyQueryToken = o.matchAnyQueryToken;
451            this.reset();
452        }
453        _.mixin(SearchIndex.prototype, {
454            bootstrap: function bootstrap(o) {
455                this.datums = o.datums;
456                this.trie = o.trie;
457            },
458            add: function(data) {
459                var that = this;
460                data = _.isArray(data) ? data : [ data ];
461                _.each(data, function(datum) {
462                    var id, tokens;
463                    that.datums[id = that.identify(datum)] = datum;
464                    tokens = normalizeTokens(that.datumTokenizer(datum));
465                    _.each(tokens, function(token) {
466                        var node, chars, ch;
467                        node = that.trie;
468                        chars = token.split("");
469                        while (ch = chars.shift()) {
470                            node = node[CHILDREN][ch] || (node[CHILDREN][ch] = newNode());
471                            node[IDS].push(id);
472                        }
473                    });
474                });
475            },
476            get: function get(ids) {
477                var that = this;
478                return _.map(ids, function(id) {
479                    return that.datums[id];
480                });
481            },
482            search: function search(query) {
483                var that = this, tokens, matches;
484                tokens = normalizeTokens(this.queryTokenizer(query));
485                _.each(tokens, function(token) {
486                    var node, chars, ch, ids;
487                    if (matches && matches.length === 0 && !that.matchAnyQueryToken) {
488                        return false;
489                    }
490                    node = that.trie;
491                    chars = token.split("");
492                    while (node && (ch = chars.shift())) {
493                        node = node[CHILDREN][ch];
494                    }
495                    if (node && chars.length === 0) {
496                        ids = node[IDS].slice(0);
497                        matches = matches ? getIntersection(matches, ids) : ids;
498                    } else {
499                        if (!that.matchAnyQueryToken) {
500                            matches = [];
501                            return false;
502                        }
503                    }
504                });
505                return matches ? _.map(unique(matches), function(id) {
506                    return that.datums[id];
507                }) : [];
508            },
509            all: function all() {
510                var values = [];
511                for (var key in this.datums) {
512                    values.push(this.datums[key]);
513                }
514                return values;
515            },
516            reset: function reset() {
517                this.datums = {};
518                this.trie = newNode();
519            },
520            serialize: function serialize() {
521                return {
522                    datums: this.datums,
523                    trie: this.trie
524                };
525            }
526        });
527        return SearchIndex;
528        function normalizeTokens(tokens) {
529            tokens = _.filter(tokens, function(token) {
530                return !!token;
531            });
532            tokens = _.map(tokens, function(token) {
533                return token.toLowerCase();
534            });
535            return tokens;
536        }
537        function newNode() {
538            var node = {};
539            node[IDS] = [];
540            node[CHILDREN] = {};
541            return node;
542        }
543        function unique(array) {
544            var seen = {}, uniques = [];
545            for (var i = 0, len = array.length; i < len; i++) {
546                if (!seen[array[i]]) {
547                    seen[array[i]] = true;
548                    uniques.push(array[i]);
549                }
550            }
551            return uniques;
552        }
553        function getIntersection(arrayA, arrayB) {
554            var ai = 0, bi = 0, intersection = [];
555            arrayA = arrayA.sort();
556            arrayB = arrayB.sort();
557            var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
558            while (ai < lenArrayA && bi < lenArrayB) {
559                if (arrayA[ai] < arrayB[bi]) {
560                    ai++;
561                } else if (arrayA[ai] > arrayB[bi]) {
562                    bi++;
563                } else {
564                    intersection.push(arrayA[ai]);
565                    ai++;
566                    bi++;
567                }
568            }
569            return intersection;
570        }
571    }();
572    var Prefetch = function() {
573        "use strict";
574        var keys;
575        keys = {
576            data: "data",
577            protocol: "protocol",
578            thumbprint: "thumbprint"
579        };
580        function Prefetch(o) {
581            this.url = o.url;
582            this.ttl = o.ttl;
583            this.cache = o.cache;
584            this.prepare = o.prepare;
585            this.transform = o.transform;
586            this.transport = o.transport;
587            this.thumbprint = o.thumbprint;
588            this.storage = new PersistentStorage(o.cacheKey);
589        }
590        _.mixin(Prefetch.prototype, {
591            _settings: function settings() {
592                return {
593                    url: this.url,
594                    type: "GET",
595                    dataType: "json"
596                };
597            },
598            store: function store(data) {
599                if (!this.cache) {
600                    return;
601                }
602                this.storage.set(keys.data, data, this.ttl);
603                this.storage.set(keys.protocol, location.protocol, this.ttl);
604                this.storage.set(keys.thumbprint, this.thumbprint, this.ttl);
605            },
606            fromCache: function fromCache() {
607                var stored = {}, isExpired;
608                if (!this.cache) {
609                    return null;
610                }
611                stored.data = this.storage.get(keys.data);
612                stored.protocol = this.storage.get(keys.protocol);
613                stored.thumbprint = this.storage.get(keys.thumbprint);
614                isExpired = stored.thumbprint !== this.thumbprint || stored.protocol !== location.protocol;
615                return stored.data && !isExpired ? stored.data : null;
616            },
617            fromNetwork: function(cb) {
618                var that = this, settings;
619                if (!cb) {
620                    return;
621                }
622                settings = this.prepare(this._settings());
623                this.transport(settings).fail(onError).done(onResponse);
624                function onError() {
625                    cb(true);
626                }
627                function onResponse(resp) {
628                    cb(null, that.transform(resp));
629                }
630            },
631            clear: function clear() {
632                this.storage.clear();
633                return this;
634            }
635        });
636        return Prefetch;
637    }();
638    var Remote = function() {
639        "use strict";
640        function Remote(o) {
641            this.url = o.url;
642            this.prepare = o.prepare;
643            this.transform = o.transform;
644            this.indexResponse = o.indexResponse;
645            this.transport = new Transport({
646                cache: o.cache,
647                limiter: o.limiter,
648                transport: o.transport,
649                maxPendingRequests: o.maxPendingRequests
650            });
651        }
652        _.mixin(Remote.prototype, {
653            _settings: function settings() {
654                return {
655                    url: this.url,
656                    type: "GET",
657                    dataType: "json"
658                };
659            },
660            get: function get(query, cb) {
661                var that = this, settings;
662                if (!cb) {
663                    return;
664                }
665                query = query || "";
666                settings = this.prepare(query, this._settings());
667                return this.transport.get(settings, onResponse);
668                function onResponse(err, resp) {
669                    err ? cb([]) : cb(that.transform(resp));
670                }
671            },
672            cancelLastRequest: function cancelLastRequest() {
673                this.transport.cancel();
674            }
675        });
676        return Remote;
677    }();
678    var oParser = function() {
679        "use strict";
680        return function parse(o) {
681            var defaults, sorter;
682            defaults = {
683                initialize: true,
684                identify: _.stringify,
685                datumTokenizer: null,
686                queryTokenizer: null,
687                matchAnyQueryToken: false,
688                sufficient: 5,
689                indexRemote: false,
690                sorter: null,
691                local: [],
692                prefetch: null,
693                remote: null
694            };
695            o = _.mixin(defaults, o || {});
696            !o.datumTokenizer && $.error("datumTokenizer is required");
697            !o.queryTokenizer && $.error("queryTokenizer is required");
698            sorter = o.sorter;
699            o.sorter = sorter ? function(x) {
700                return x.sort(sorter);
701            } : _.identity;
702            o.local = _.isFunction(o.local) ? o.local() : o.local;
703            o.prefetch = parsePrefetch(o.prefetch);
704            o.remote = parseRemote(o.remote);
705            return o;
706        };
707        function parsePrefetch(o) {
708            var defaults;
709            if (!o) {
710                return null;
711            }
712            defaults = {
713                url: null,
714                ttl: 24 * 60 * 60 * 1e3,
715                cache: true,
716                cacheKey: null,
717                thumbprint: "",
718                prepare: _.identity,
719                transform: _.identity,
720                transport: null
721            };
722            o = _.isString(o) ? {
723                url: o
724            } : o;
725            o = _.mixin(defaults, o);
726            !o.url && $.error("prefetch requires url to be set");
727            o.transform = o.filter || o.transform;
728            o.cacheKey = o.cacheKey || o.url;
729            o.thumbprint = VERSION + o.thumbprint;
730            o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
731            return o;
732        }
733        function parseRemote(o) {
734            var defaults;
735            if (!o) {
736                return;
737            }
738            defaults = {
739                url: null,
740                cache: true,
741                prepare: null,
742                replace: null,
743                wildcard: null,
744                limiter: null,
745                rateLimitBy: "debounce",
746                rateLimitWait: 300,
747                transform: _.identity,
748                transport: null
749            };
750            o = _.isString(o) ? {
751                url: o
752            } : o;
753            o = _.mixin(defaults, o);
754            !o.url && $.error("remote requires url to be set");
755            o.transform = o.filter || o.transform;
756            o.prepare = toRemotePrepare(o);
757            o.limiter = toLimiter(o);
758            o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
759            delete o.replace;
760            delete o.wildcard;
761            delete o.rateLimitBy;
762            delete o.rateLimitWait;
763            return o;
764        }
765        function toRemotePrepare(o) {
766            var prepare, replace, wildcard;
767            prepare = o.prepare;
768            replace = o.replace;
769            wildcard = o.wildcard;
770            if (prepare) {
771                return prepare;
772            }
773            if (replace) {
774                prepare = prepareByReplace;
775            } else if (o.wildcard) {
776                prepare = prepareByWildcard;
777            } else {
778                prepare = identityPrepare;
779            }
780            return prepare;
781            function prepareByReplace(query, settings) {
782                settings.url = replace(settings.url, query);
783                return settings;
784            }
785            function prepareByWildcard(query, settings) {
786                settings.url = settings.url.replace(wildcard, encodeURIComponent(query));
787                return settings;
788            }
789            function identityPrepare(query, settings) {
790                return settings;
791            }
792        }
793        function toLimiter(o) {
794            var limiter, method, wait;
795            limiter = o.limiter;
796            method = o.rateLimitBy;
797            wait = o.rateLimitWait;
798            if (!limiter) {
799                limiter = /^throttle$/i.test(method) ? throttle(wait) : debounce(wait);
800            }
801            return limiter;
802            function debounce(wait) {
803                return function debounce(fn) {
804                    return _.debounce(fn, wait);
805                };
806            }
807            function throttle(wait) {
808                return function throttle(fn) {
809                    return _.throttle(fn, wait);
810                };
811            }
812        }
813        function callbackToDeferred(fn) {
814            return function wrapper(o) {
815                var deferred = $.Deferred();
816                fn(o, onSuccess, onError);
817                return deferred;
818                function onSuccess(resp) {
819                    _.defer(function() {
820                        deferred.resolve(resp);
821                    });
822                }
823                function onError(err) {
824                    _.defer(function() {
825                        deferred.reject(err);
826                    });
827                }
828            };
829        }
830    }();
831    var Bloodhound = function() {
832        "use strict";
833        var old;
834        old = window && window.Bloodhound;
835        function Bloodhound(o) {
836            o = oParser(o);
837            this.sorter = o.sorter;
838            this.identify = o.identify;
839            this.sufficient = o.sufficient;
840            this.indexRemote = o.indexRemote;
841            this.local = o.local;
842            this.remote = o.remote ? new Remote(o.remote) : null;
843            this.prefetch = o.prefetch ? new Prefetch(o.prefetch) : null;
844            this.index = new SearchIndex({
845                identify: this.identify,
846                datumTokenizer: o.datumTokenizer,
847                queryTokenizer: o.queryTokenizer
848            });
849            o.initialize !== false && this.initialize();
850        }
851        Bloodhound.noConflict = function noConflict() {
852            window && (window.Bloodhound = old);
853            return Bloodhound;
854        };
855        Bloodhound.tokenizers = tokenizers;
856        _.mixin(Bloodhound.prototype, {
857            __ttAdapter: function ttAdapter() {
858                var that = this;
859                return this.remote ? withAsync : withoutAsync;
860                function withAsync(query, sync, async) {
861                    return that.search(query, sync, async);
862                }
863                function withoutAsync(query, sync) {
864                    return that.search(query, sync);
865                }
866            },
867            _loadPrefetch: function loadPrefetch() {
868                var that = this, deferred, serialized;
869                deferred = $.Deferred();
870                if (!this.prefetch) {
871                    deferred.resolve();
872                } else if (serialized = this.prefetch.fromCache()) {
873                    this.index.bootstrap(serialized);
874                    deferred.resolve();
875                } else {
876                    this.prefetch.fromNetwork(done);
877                }
878                return deferred.promise();
879                function done(err, data) {
880                    if (err) {
881                        return deferred.reject();
882                    }
883                    that.add(data);
884                    that.prefetch.store(that.index.serialize());
885                    deferred.resolve();
886                }
887            },
888            _initialize: function initialize() {
889                var that = this, deferred;
890                this.clear();
891                (this.initPromise = this._loadPrefetch()).done(addLocalToIndex);
892                return this.initPromise;
893                function addLocalToIndex() {
894                    that.add(that.local);
895                }
896            },
897            initialize: function initialize(force) {
898                return !this.initPromise || force ? this._initialize() : this.initPromise;
899            },
900            add: function add(data) {
901                this.index.add(data);
902                return this;
903            },
904            get: function get(ids) {
905                ids = _.isArray(ids) ? ids : [].slice.call(arguments);
906                return this.index.get(ids);
907            },
908            search: function search(query, sync, async) {
909                var that = this, local;
910                sync = sync || _.noop;
911                async = async || _.noop;
912                local = this.sorter(this.index.search(query));
913                sync(this.remote ? local.slice() : local);
914                if (this.remote && local.length < this.sufficient) {
915                    this.remote.get(query, processRemote);
916                } else if (this.remote) {
917                    this.remote.cancelLastRequest();
918                }
919                return this;
920                function processRemote(remote) {
vendor: 3,518 bytes, lines 921-1021
921                    var nonDuplicates = [];
922                    _.each(remote, function(r) {
923                        !_.some(local, function(l) {
924                            return that.identify(r) === that.identify(l);
925                        }) && nonDuplicates.push(r);
926                    });
927                    that.indexRemote && that.add(nonDuplicates);
928                    async(nonDuplicates);
929                }
930            },
931            all: function all() {
932                return this.index.all();
933            },
934            clear: function clear() {
935                this.index.reset();
936                return this;
937            },
938            clearPrefetchCache: function clearPrefetchCache() {
939                this.prefetch && this.prefetch.clear();
940                return this;
941            },
942            clearRemoteCache: function clearRemoteCache() {
943                Transport.resetCache();
944                return this;
945            },
946            ttAdapter: function ttAdapter() {
947                return this.__ttAdapter();
948            }
949        });
950        return Bloodhound;
951    }();
952    return Bloodhound;
953});
954
955(function(root, factory) {
956    if (typeof define === "function" && define.amd) {
957        define([ "jquery" ], function(a0) {
958            return factory(a0);
959        });
960    } else if (typeof module === "object" && module.exports) {
961        module.exports = factory(require("jquery"));
962    } else {
963        factory(root["jQuery"]);
964    }
965})(this, function($) {
966    var _ = function() {
967        "use strict";
968        return {
969            isMsie: function() {
970                return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
971            },
972            isBlankString: function(str) {
973                return !str || /^\s*$/.test(str);
974            },
975            escapeRegExChars: function(str) {
976                return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
977            },
978            isString: function(obj) {
979                return typeof obj === "string";
980            },
981            isNumber: function(obj) {
982                return typeof obj === "number";
983            },
984            isArray: $.isArray,
985            isFunction: $.isFunction,
986            isObject: $.isPlainObject,
987            isUndefined: function(obj) {
988                return typeof obj === "undefined";
989            },
990            isElement: function(obj) {
991                return !!(obj && obj.nodeType === 1);
992            },
993            isJQuery: function(obj) {
994                return obj instanceof $;
995            },
996            toStr: function toStr(s) {
997                return _.isUndefined(s) || s === null ? "" : s + "";
998            },
999            bind: $.proxy,
1000            each: function(collection, cb) {
1001                $.each(collection, reverseArgs);
1002                function reverseArgs(index, value) {
1003                    return cb(value, index);
1004                }
1005            },
1006            map: $.map,
1007            filter: $.grep,
1008            every: function(obj, test) {
1009                var result = true;
1010                if (!obj) {
1011                    return result;
1012                }
1013                $.each(obj, function(key, val) {
1014                    if (!(result = test.call(null, val, key, obj))) {
1015                        return false;
1016                    }
1017                });
1018                return !!result;
1019            },
1020            some: function(obj, test) {
1021                var result = false;
vendor: 68,723 bytes, lines 1022-2641
1022                if (!obj) {
1023                    return result;
1024                }
1025                $.each(obj, function(key, val) {
1026                    if (result = test.call(null, val, key, obj)) {
1027                        return false;
1028                    }
1029                });
1030                return !!result;
1031            },
1032            mixin: $.extend,
1033            identity: function(x) {
1034                return x;
1035            },
1036            clone: function(obj) {
1037                return $.extend(true, {}, obj);
1038            },
1039            getIdGenerator: function() {
1040                var counter = 0;
1041                return function() {
1042                    return counter++;
1043                };
1044            },
1045            templatify: function templatify(obj) {
1046                return $.isFunction(obj) ? obj : template;
1047                function template() {
1048                    return String(obj);
1049                }
1050            },
1051            defer: function(fn) {
1052                setTimeout(fn, 0);
1053            },
1054            debounce: function(func, wait, immediate) {
1055                var timeout, result;
1056                return function() {
1057                    var context = this, args = arguments, later, callNow;
1058                    later = function() {
1059                        timeout = null;
1060                        if (!immediate) {
1061                            result = func.apply(context, args);
1062                        }
1063                    };
1064                    callNow = immediate && !timeout;
1065                    clearTimeout(timeout);
1066                    timeout = setTimeout(later, wait);
1067                    if (callNow) {
1068                        result = func.apply(context, args);
1069                    }
1070                    return result;
1071                };
1072            },
1073            throttle: function(func, wait) {
1074                var context, args, timeout, result, previous, later;
1075                previous = 0;
1076                later = function() {
1077                    previous = new Date();
1078                    timeout = null;
1079                    result = func.apply(context, args);
1080                };
1081                return function() {
1082                    var now = new Date(), remaining = wait - (now - previous);
1083                    context = this;
1084                    args = arguments;
1085                    if (remaining <= 0) {
1086                        clearTimeout(timeout);
1087                        timeout = null;
1088                        previous = now;
1089                        result = func.apply(context, args);
1090                    } else if (!timeout) {
1091                        timeout = setTimeout(later, remaining);
1092                    }
1093                    return result;
1094                };
1095            },
1096            stringify: function(val) {
1097                return _.isString(val) ? val : JSON.stringify(val);
1098            },
1099            guid: function() {
1100                function _p8(s) {
1101                    var p = (Math.random().toString(16) + "000000000").substr(2, 8);
1102                    return s ? "-" + p.substr(0, 4) + "-" + p.substr(4, 4) : p;
1103                }
1104                return "tt-" + _p8() + _p8(true) + _p8(true) + _p8();
1105            },
1106            noop: function() {}
1107        };
1108    }();
1109    var WWW = function() {
1110        "use strict";
1111        var defaultClassNames = {
1112            wrapper: "twitter-typeahead",
1113            input: "tt-input",
1114            hint: "tt-hint",
1115            menu: "tt-menu",
1116            dataset: "tt-dataset",
1117            suggestion: "tt-suggestion",
1118            selectable: "tt-selectable",
1119            empty: "tt-empty",
1120            open: "tt-open",
1121            cursor: "tt-cursor",
1122            highlight: "tt-highlight"
1123        };
1124        return build;
1125        function build(o) {
1126            var www, classes;
1127            classes = _.mixin({}, defaultClassNames, o);
1128            www = {
1129                css: buildCss(),
1130                classes: classes,
1131                html: buildHtml(classes),
1132                selectors: buildSelectors(classes)
1133            };
1134            return {
1135                css: www.css,
1136                html: www.html,
1137                classes: www.classes,
1138                selectors: www.selectors,
1139                mixin: function(o) {
1140                    _.mixin(o, www);
1141                }
1142            };
1143        }
1144        function buildHtml(c) {
1145            return {
1146                wrapper: '<span class="' + c.wrapper + '"></span>',
1147                menu: '<div role="listbox" class="' + c.menu + '"></div>'
1148            };
1149        }
1150        function buildSelectors(classes) {
1151            var selectors = {};
1152            _.each(classes, function(v, k) {
1153                selectors[k] = "." + v;
1154            });
1155            return selectors;
1156        }
1157        function buildCss() {
1158            var css = {
1159                wrapper: {
1160                    position: "relative",
1161                    display: "inline-block"
1162                },
1163                hint: {
1164                    position: "absolute",
1165                    top: "0",
1166                    left: "0",
1167                    borderColor: "transparent",
1168                    boxShadow: "none",
1169                    opacity: "1"
1170                },
1171                input: {
1172                    position: "relative",
1173                    verticalAlign: "top",
1174                    backgroundColor: "transparent"
1175                },
1176                inputWithNoHint: {
1177                    position: "relative",
1178                    verticalAlign: "top"
1179                },
1180                menu: {
1181                    position: "absolute",
1182                    top: "100%",
1183                    left: "0",
1184                    zIndex: "100",
1185                    display: "none"
1186                },
1187                ltr: {
1188                    left: "0",
1189                    right: "auto"
1190                },
1191                rtl: {
1192                    left: "auto",
1193                    right: " 0"
1194                }
1195            };
1196            if (_.isMsie()) {
1197                _.mixin(css.input, {
1198                    backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
1199                });
1200            }
1201            return css;
1202        }
1203    }();
1204    var EventBus = function() {
1205        "use strict";
1206        var namespace, deprecationMap;
1207        namespace = "typeahead:";
1208        deprecationMap = {
1209            render: "rendered",
1210            cursorchange: "cursorchanged",
1211            select: "selected",
1212            autocomplete: "autocompleted"
1213        };
1214        function EventBus(o) {
1215            if (!o || !o.el) {
1216                $.error("EventBus initialized without el");
1217            }
1218            this.$el = $(o.el);
1219        }
1220        _.mixin(EventBus.prototype, {
1221            _trigger: function(type, args) {
1222                var $e = $.Event(namespace + type);
1223                this.$el.trigger.call(this.$el, $e, args || []);
1224                return $e;
1225            },
1226            before: function(type) {
1227                var args, $e;
1228                args = [].slice.call(arguments, 1);
1229                $e = this._trigger("before" + type, args);
1230                return $e.isDefaultPrevented();
1231            },
1232            trigger: function(type) {
1233                var deprecatedType;
1234                this._trigger(type, [].slice.call(arguments, 1));
1235                if (deprecatedType = deprecationMap[type]) {
1236                    this._trigger(deprecatedType, [].slice.call(arguments, 1));
1237                }
1238            }
1239        });
1240        return EventBus;
1241    }();
1242    var EventEmitter = function() {
1243        "use strict";
1244        var splitter = /\s+/, nextTick = getNextTick();
1245        return {
1246            onSync: onSync,
1247            onAsync: onAsync,
1248            off: off,
1249            trigger: trigger
1250        };
1251        function on(method, types, cb, context) {
1252            var type;
1253            if (!cb) {
1254                return this;
1255            }
1256            types = types.split(splitter);
1257            cb = context ? bindContext(cb, context) : cb;
1258            this._callbacks = this._callbacks || {};
1259            while (type = types.shift()) {
1260                this._callbacks[type] = this._callbacks[type] || {
1261                    sync: [],
1262                    async: []
1263                };
1264                this._callbacks[type][method].push(cb);
1265            }
1266            return this;
1267        }
1268        function onAsync(types, cb, context) {
1269            return on.call(this, "async", types, cb, context);
1270        }
1271        function onSync(types, cb, context) {
1272            return on.call(this, "sync", types, cb, context);
1273        }
1274        function off(types) {
1275            var type;
1276            if (!this._callbacks) {
1277                return this;
1278            }
1279            types = types.split(splitter);
1280            while (type = types.shift()) {
1281                delete this._callbacks[type];
1282            }
1283            return this;
1284        }
1285        function trigger(types) {
1286            var type, callbacks, args, syncFlush, asyncFlush;
1287            if (!this._callbacks) {
1288                return this;
1289            }
1290            types = types.split(splitter);
1291            args = [].slice.call(arguments, 1);
1292            while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
1293                syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args));
1294                asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args));
1295                syncFlush() && nextTick(asyncFlush);
1296            }
1297            return this;
1298        }
1299        function getFlush(callbacks, context, args) {
1300            return flush;
1301            function flush() {
1302                var cancelled;
1303                for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
1304                    cancelled = callbacks[i].apply(context, args) === false;
1305                }
1306                return !cancelled;
1307            }
1308        }
1309        function getNextTick() {
1310            var nextTickFn;
1311            if (window.setImmediate) {
1312                nextTickFn = function nextTickSetImmediate(fn) {
1313                    setImmediate(function() {
1314                        fn();
1315                    });
1316                };
1317            } else {
1318                nextTickFn = function nextTickSetTimeout(fn) {
1319                    setTimeout(function() {
1320                        fn();
1321                    }, 0);
1322                };
1323            }
1324            return nextTickFn;
1325        }
1326        function bindContext(fn, context) {
1327            return fn.bind ? fn.bind(context) : function() {
1328                fn.apply(context, [].slice.call(arguments, 0));
1329            };
1330        }
1331    }();
1332    var highlight = function(doc) {
1333        "use strict";
1334        var defaults = {
1335            node: null,
1336            pattern: null,
1337            tagName: "strong",
1338            className: null,
1339            wordsOnly: false,
1340            caseSensitive: false,
1341            diacriticInsensitive: false
1342        };
1343        var accented = {
1344            A: "[AaªÀ-Åà-åĀ-ąǍǎȀ-ȃȦȧᴬᵃḀḁẚẠ-ảₐ℀℁℻⒜Ⓐⓐ㍱-㍴㎀-㎄㎈㎉㎩-㎯㏂㏊㏟㏿Aa]",
1345            B: "[BbᴮᵇḂ-ḇℬ⒝Ⓑⓑ㍴㎅-㎇㏃㏈㏔㏝Bb]",
1346            C: "[CcÇçĆ-čᶜ℀ℂ℃℅℆ℭⅭⅽ⒞Ⓒⓒ㍶㎈㎉㎝㎠㎤㏄-㏇Cc]",
1347            D: "[DdĎďDŽ-džDZ-dzᴰᵈḊ-ḓⅅⅆⅮⅾ⒟Ⓓⓓ㋏㍲㍷-㍹㎗㎭-㎯㏅㏈Dd]",
1348            E: "[EeÈ-Ëè-ëĒ-ěȄ-ȇȨȩᴱᵉḘ-ḛẸ-ẽₑ℡ℯℰⅇ⒠Ⓔⓔ㉐㋍㋎Ee]",
1349            F: "[FfᶠḞḟ℉ℱ℻⒡Ⓕⓕ㎊-㎌㎙ff-fflFf]",
1350            G: "[GgĜ-ģǦǧǴǵᴳᵍḠḡℊ⒢Ⓖⓖ㋌㋍㎇㎍-㎏㎓㎬㏆㏉㏒㏿Gg]",
1351            H: "[HhĤĥȞȟʰᴴḢ-ḫẖℋ-ℎ⒣Ⓗⓗ㋌㍱㎐-㎔㏊㏋㏗Hh]",
1352            I: "[IiÌ-Ïì-ïĨ-İIJijǏǐȈ-ȋᴵᵢḬḭỈ-ịⁱℐℑℹⅈⅠ-ⅣⅥ-ⅨⅪⅫⅰ-ⅳⅵ-ⅸⅺⅻ⒤Ⓘⓘ㍺㏌㏕fiffiIi]",
1353            J: "[JjIJ-ĵLJ-njǰʲᴶⅉ⒥ⒿⓙⱼJj]",
1354            K: "[KkĶķǨǩᴷᵏḰ-ḵK⒦Ⓚⓚ㎄㎅㎉㎏㎑㎘㎞㎢㎦㎪㎸㎾㏀㏆㏍-㏏Kk]",
1355            L: "[LlĹ-ŀLJ-ljˡᴸḶḷḺ-ḽℒℓ℡Ⅼⅼ⒧Ⓛⓛ㋏㎈㎉㏐-㏓㏕㏖㏿flfflLl]",
1356            M: "[MmᴹᵐḾ-ṃ℠™ℳⅯⅿ⒨Ⓜⓜ㍷-㍹㎃㎆㎎㎒㎖㎙-㎨㎫㎳㎷㎹㎽㎿㏁㏂㏎㏐㏔-㏖㏘㏙㏞㏟Mm]",
1357            N: "[NnÑñŃ-ʼnNJ-njǸǹᴺṄ-ṋⁿℕ№⒩Ⓝⓝ㎁㎋㎚㎱㎵㎻㏌㏑Nn]",
1358            O: "[OoºÒ-Öò-öŌ-őƠơǑǒǪǫȌ-ȏȮȯᴼᵒỌ-ỏₒ℅№ℴ⒪Ⓞⓞ㍵㏇㏒㏖Oo]",
1359            P: "[PpᴾᵖṔ-ṗℙ⒫Ⓟⓟ㉐㍱㍶㎀㎊㎩-㎬㎰㎴㎺㏋㏗-㏚Pp]",
1360            Q: "[Qqℚ⒬Ⓠⓠ㏃Qq]",
1361            R: "[RrŔ-řȐ-ȓʳᴿᵣṘ-ṛṞṟ₨ℛ-ℝ⒭Ⓡⓡ㋍㍴㎭-㎯㏚㏛Rr]",
1362            S: "[SsŚ-šſȘșˢṠ-ṣ₨℁℠⒮Ⓢⓢ㎧㎨㎮-㎳㏛㏜stSs]",
1363            T: "[TtŢ-ťȚțᵀᵗṪ-ṱẗ℡™⒯Ⓣⓣ㉐㋏㎔㏏ſtstTt]",
1364            U: "[UuÙ-Üù-üŨ-ųƯưǓǔȔ-ȗᵁᵘᵤṲ-ṷỤ-ủ℆⒰Ⓤⓤ㍳㍺Uu]",
1365            V: "[VvᵛᵥṼ-ṿⅣ-Ⅷⅳ-ⅷ⒱Ⓥⓥⱽ㋎㍵㎴-㎹㏜㏞Vv]",
1366            W: "[WwŴŵʷᵂẀ-ẉẘ⒲Ⓦⓦ㎺-㎿㏝Ww]",
1367            X: "[XxˣẊ-ẍₓ℻Ⅸ-Ⅻⅸ-ⅻ⒳Ⓧⓧ㏓Xx]",
1368            Y: "[YyÝýÿŶ-ŸȲȳʸẎẏẙỲ-ỹ⒴Ⓨⓨ㏉Yy]",
1369            Z: "[ZzŹ-žDZ-dzᶻẐ-ẕℤℨ⒵Ⓩⓩ㎐-㎔Zz]"
1370        };
1371        return function hightlight(o) {
1372            var regex;
1373            o = _.mixin({}, defaults, o);
1374            if (!o.node || !o.pattern) {
1375                return;
1376            }
1377            o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ];
1378            regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly, o.diacriticInsensitive);
1379            traverse(o.node, hightlightTextNode);
1380            function hightlightTextNode(textNode) {
1381                var match, patternNode, wrapperNode;
1382                if (match = regex.exec(textNode.data)) {
1383                    wrapperNode = doc.createElement(o.tagName);
1384                    o.className && (wrapperNode.className = o.className);
1385                    patternNode = textNode.splitText(match.index);
1386                    patternNode.splitText(match[0].length);
1387                    wrapperNode.appendChild(patternNode.cloneNode(true));
1388                    textNode.parentNode.replaceChild(wrapperNode, patternNode);
1389                }
1390                return !!match;
1391            }
1392            function traverse(el, hightlightTextNode) {
1393                var childNode, TEXT_NODE_TYPE = 3;
1394                for (var i = 0; i < el.childNodes.length; i++) {
1395                    childNode = el.childNodes[i];
1396                    if (childNode.nodeType === TEXT_NODE_TYPE) {
1397                        i += hightlightTextNode(childNode) ? 1 : 0;
1398                    } else {
1399                        traverse(childNode, hightlightTextNode);
1400                    }
1401                }
1402            }
1403        };
1404        function accent_replacer(chr) {
1405            return accented[chr.toUpperCase()] || chr;
1406        }
1407        function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) {
1408            var escapedPatterns = [], regexStr;
1409            for (var i = 0, len = patterns.length; i < len; i++) {
1410                var escapedWord = _.escapeRegExChars(patterns[i]);
1411                if (diacriticInsensitive) {
1412                    escapedWord = escapedWord.replace(/\S/g, accent_replacer);
1413                }
1414                escapedPatterns.push(escapedWord);
1415            }
1416            regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")";
1417            return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i");
1418        }
1419    }(window.document);
1420    var Input = function() {
1421        "use strict";
1422        var specialKeyCodeMap;
1423        specialKeyCodeMap = {
1424            9: "tab",
1425            27: "esc",
1426            37: "left",
1427            39: "right",
1428            13: "enter",
1429            38: "up",
1430            40: "down"
1431        };
1432        function Input(o, www) {
1433            var id;
1434            o = o || {};
1435            if (!o.input) {
1436                $.error("input is missing");
1437            }
1438            www.mixin(this);
1439            this.$hint = $(o.hint);
1440            this.$input = $(o.input);
1441            this.$menu = $(o.menu);
1442            id = this.$input.attr("id") || _.guid();
1443            this.$menu.attr("id", id + "_listbox");
1444            this.$hint.attr({
1445                "aria-hidden": true
1446            });
1447            this.$input.attr({
1448                "aria-owns": id + "_listbox",
1449                role: "combobox",
1450                "aria-autocomplete": "list",
1451                "aria-expanded": false
1452            });
1453            this.query = this.$input.val();
1454            this.queryWhenFocused = this.hasFocus() ? this.query : null;
1455            this.$overflowHelper = buildOverflowHelper(this.$input);
1456            this._checkLanguageDirection();
1457            if (this.$hint.length === 0) {
1458                this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;
1459            }
1460            this.onSync("cursorchange", this._updateDescendent);
1461        }
1462        Input.normalizeQuery = function(str) {
1463            return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
1464        };
1465        _.mixin(Input.prototype, EventEmitter, {
1466            _onBlur: function onBlur() {
1467                this.resetInputValue();
1468                this.trigger("blurred");
1469            },
1470            _onFocus: function onFocus() {
1471                this.queryWhenFocused = this.query;
1472                this.trigger("focused");
1473            },
1474            _onKeydown: function onKeydown($e) {
1475                var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
1476                this._managePreventDefault(keyName, $e);
1477                if (keyName && this._shouldTrigger(keyName, $e)) {
1478                    this.trigger(keyName + "Keyed", $e);
1479                }
1480            },
1481            _onInput: function onInput() {
1482                this._setQuery(this.getInputValue());
1483                this.clearHintIfInvalid();
1484                this._checkLanguageDirection();
1485            },
1486            _managePreventDefault: function managePreventDefault(keyName, $e) {
1487                var preventDefault;
1488                switch (keyName) {
1489                  case "up":
1490                  case "down":
1491                    preventDefault = !withModifier($e);
1492                    break;
1493
1494                  default:
1495                    preventDefault = false;
1496                }
1497                preventDefault && $e.preventDefault();
1498            },
1499            _shouldTrigger: function shouldTrigger(keyName, $e) {
1500                var trigger;
1501                switch (keyName) {
1502                  case "tab":
1503                    trigger = !withModifier($e);
1504                    break;
1505
1506                  default:
1507                    trigger = true;
1508                }
1509                return trigger;
1510            },
1511            _checkLanguageDirection: function checkLanguageDirection() {
1512                var dir = (this.$input.css("direction") || "ltr").toLowerCase();
1513                if (this.dir !== dir) {
1514                    this.dir = dir;
1515                    this.$hint.attr("dir", dir);
1516                    this.trigger("langDirChanged", dir);
1517                }
1518            },
1519            _setQuery: function setQuery(val, silent) {
1520                var areEquivalent, hasDifferentWhitespace;
1521                areEquivalent = areQueriesEquivalent(val, this.query);
1522                hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false;
1523                this.query = val;
1524                if (!silent && !areEquivalent) {
1525                    this.trigger("queryChanged", this.query);
1526                } else if (!silent && hasDifferentWhitespace) {
1527                    this.trigger("whitespaceChanged", this.query);
1528                }
1529            },
1530            _updateDescendent: function updateDescendent(event, id) {
1531                this.$input.attr("aria-activedescendant", id);
1532            },
1533            bind: function() {
1534                var that = this, onBlur, onFocus, onKeydown, onInput;
1535                onBlur = _.bind(this._onBlur, this);
1536                onFocus = _.bind(this._onFocus, this);
1537                onKeydown = _.bind(this._onKeydown, this);
1538                onInput = _.bind(this._onInput, this);
1539                this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
1540                if (!_.isMsie() || _.isMsie() > 9) {
1541                    this.$input.on("input.tt", onInput);
1542                } else {
1543                    this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) {
1544                        if (specialKeyCodeMap[$e.which || $e.keyCode]) {
1545                            return;
1546                        }
1547                        _.defer(_.bind(that._onInput, that, $e));
1548                    });
1549                }
1550                return this;
1551            },
1552            focus: function focus() {
1553                this.$input.focus();
1554            },
1555            blur: function blur() {
1556                this.$input.blur();
1557            },
1558            getLangDir: function getLangDir() {
1559                return this.dir;
1560            },
1561            getQuery: function getQuery() {
1562                return this.query || "";
1563            },
1564            setQuery: function setQuery(val, silent) {
1565                this.setInputValue(val);
1566                this._setQuery(val, silent);
1567            },
1568            hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {
1569                return this.query !== this.queryWhenFocused;
1570            },
1571            getInputValue: function getInputValue() {
1572                return this.$input.val();
1573            },
1574            setInputValue: function setInputValue(value) {
1575                this.$input.val(value);
1576                this.clearHintIfInvalid();
1577                this._checkLanguageDirection();
1578            },
1579            resetInputValue: function resetInputValue() {
1580                this.setInputValue(this.query);
1581            },
1582            getHint: function getHint() {
1583                return this.$hint.val();
1584            },
1585            setHint: function setHint(value) {
1586                this.$hint.val(value);
1587            },
1588            clearHint: function clearHint() {
1589                this.setHint("");
1590            },
1591            clearHintIfInvalid: function clearHintIfInvalid() {
1592                var val, hint, valIsPrefixOfHint, isValid;
1593                val = this.getInputValue();
1594                hint = this.getHint();
1595                valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
1596                isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow();
1597                !isValid && this.clearHint();
1598            },
1599            hasFocus: function hasFocus() {
1600                return this.$input.is(":focus");
1601            },
1602            hasOverflow: function hasOverflow() {
1603                var constraint = this.$input.width() - 2;
1604                this.$overflowHelper.text(this.getInputValue());
1605                return this.$overflowHelper.width() >= constraint;
1606            },
1607            isCursorAtEnd: function() {
1608                var valueLength, selectionStart, range;
1609                valueLength = this.$input.val().length;
1610                selectionStart = this.$input[0].selectionStart;
1611                if (_.isNumber(selectionStart)) {
1612                    return selectionStart === valueLength;
1613                } else if (document.selection) {
1614                    range = document.selection.createRange();
1615                    range.moveStart("character", -valueLength);
1616                    return valueLength === range.text.length;
1617                }
1618                return true;
1619            },
1620            destroy: function destroy() {
1621                this.$hint.off(".tt");
1622                this.$input.off(".tt");
1623                this.$overflowHelper.remove();
1624                this.$hint = this.$input = this.$overflowHelper = $("<div>");
1625            },
1626            setAriaExpanded: function setAriaExpanded(value) {
1627                this.$input.attr("aria-expanded", value);
1628            }
1629        });
1630        return Input;
1631        function buildOverflowHelper($input) {
1632            return $('<pre aria-hidden="true"></pre>').css({
1633                position: "absolute",
1634                visibility: "hidden",
1635                whiteSpace: "pre",
1636                fontFamily: $input.css("font-family"),
1637                fontSize: $input.css("font-size"),
1638                fontStyle: $input.css("font-style"),
1639                fontVariant: $input.css("font-variant"),
1640                fontWeight: $input.css("font-weight"),
1641                wordSpacing: $input.css("word-spacing"),
1642                letterSpacing: $input.css("letter-spacing"),
1643                textIndent: $input.css("text-indent"),
1644                textRendering: $input.css("text-rendering"),
1645                textTransform: $input.css("text-transform")
1646            }).insertAfter($input);
1647        }
1648        function areQueriesEquivalent(a, b) {
1649            return Input.normalizeQuery(a) === Input.normalizeQuery(b);
1650        }
1651        function withModifier($e) {
1652            return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
1653        }
1654    }();
1655    var Dataset = function() {
1656        "use strict";
1657        var keys, nameGenerator;
1658        keys = {
1659            dataset: "tt-selectable-dataset",
1660            val: "tt-selectable-display",
1661            obj: "tt-selectable-object"
1662        };
1663        nameGenerator = _.getIdGenerator();
1664        function Dataset(o, www) {
1665            o = o || {};
1666            o.templates = o.templates || {};
1667            o.templates.notFound = o.templates.notFound || o.templates.empty;
1668            if (!o.source) {
1669                $.error("missing source");
1670            }
1671            if (!o.node) {
1672                $.error("missing node");
1673            }
1674            if (o.name && !isValidName(o.name)) {
1675                $.error("invalid dataset name: " + o.name);
1676            }
1677            www.mixin(this);
1678            this.highlight = !!o.highlight;
1679            this.name = _.toStr(o.name || nameGenerator());
1680            this.limit = o.limit || 5;
1681            this.displayFn = getDisplayFn(o.display || o.displayKey);
1682            this.templates = getTemplates(o.templates, this.displayFn);
1683            this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source;
1684            this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;
1685            this._resetLastSuggestion();
1686            this.$el = $(o.node).attr("role", "presentation").addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name);
1687        }
1688        Dataset.extractData = function extractData(el) {
1689            var $el = $(el);
1690            if ($el.data(keys.obj)) {
1691                return {
1692                    dataset: $el.data(keys.dataset) || "",
1693                    val: $el.data(keys.val) || "",
1694                    obj: $el.data(keys.obj) || null
1695                };
1696            }
1697            return null;
1698        };
1699        _.mixin(Dataset.prototype, EventEmitter, {
1700            _overwrite: function overwrite(query, suggestions) {
1701                suggestions = suggestions || [];
1702                if (suggestions.length) {
1703                    this._renderSuggestions(query, suggestions);
1704                } else if (this.async && this.templates.pending) {
1705                    this._renderPending(query);
1706                } else if (!this.async && this.templates.notFound) {
1707                    this._renderNotFound(query);
1708                } else {
1709                    this._empty();
1710                }
1711                this.trigger("rendered", suggestions, false, this.name);
1712            },
1713            _append: function append(query, suggestions) {
1714                suggestions = suggestions || [];
1715                if (suggestions.length && this.$lastSuggestion.length) {
1716                    this._appendSuggestions(query, suggestions);
1717                } else if (suggestions.length) {
1718                    this._renderSuggestions(query, suggestions);
1719                } else if (!this.$lastSuggestion.length && this.templates.notFound) {
1720                    this._renderNotFound(query);
1721                }
1722                this.trigger("rendered", suggestions, true, this.name);
1723            },
1724            _renderSuggestions: function renderSuggestions(query, suggestions) {
1725                var $fragment;
1726                $fragment = this._getSuggestionsFragment(query, suggestions);
1727                this.$lastSuggestion = $fragment.children().last();
1728                this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions));
1729            },
1730            _appendSuggestions: function appendSuggestions(query, suggestions) {
1731                var $fragment, $lastSuggestion;
1732                $fragment = this._getSuggestionsFragment(query, suggestions);
1733                $lastSuggestion = $fragment.children().last();
1734                this.$lastSuggestion.after($fragment);
1735                this.$lastSuggestion = $lastSuggestion;
1736            },
1737            _renderPending: function renderPending(query) {
1738                var template = this.templates.pending;
1739                this._resetLastSuggestion();
1740                template && this.$el.html(template({
1741                    query: query,
1742                    dataset: this.name
1743                }));
1744            },
1745            _renderNotFound: function renderNotFound(query) {
1746                var template = this.templates.notFound;
1747                this._resetLastSuggestion();
1748                template && this.$el.html(template({
1749                    query: query,
1750                    dataset: this.name
1751                }));
1752            },
1753            _empty: function empty() {
1754                this.$el.empty();
1755                this._resetLastSuggestion();
1756            },
1757            _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {
1758                var that = this, fragment;
1759                fragment = document.createDocumentFragment();
1760                _.each(suggestions, function getSuggestionNode(suggestion) {
1761                    var $el, context;
1762                    context = that._injectQuery(query, suggestion);
1763                    $el = $(that.templates.suggestion(context)).data(keys.dataset, that.name).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable);
1764                    fragment.appendChild($el[0]);
1765                });
1766                this.highlight && highlight({
1767                    className: this.classes.highlight,
1768                    node: fragment,
1769                    pattern: query
1770                });
1771                return $(fragment);
1772            },
1773            _getFooter: function getFooter(query, suggestions) {
1774                return this.templates.footer ? this.templates.footer({
1775                    query: query,
1776                    suggestions: suggestions,
1777                    dataset: this.name
1778                }) : null;
1779            },
1780            _getHeader: function getHeader(query, suggestions) {
1781                return this.templates.header ? this.templates.header({
1782                    query: query,
1783                    suggestions: suggestions,
1784                    dataset: this.name
1785                }) : null;
1786            },
1787            _resetLastSuggestion: function resetLastSuggestion() {
1788                this.$lastSuggestion = $();
1789            },
1790            _injectQuery: function injectQuery(query, obj) {
1791                return _.isObject(obj) ? _.mixin({
1792                    _query: query
1793                }, obj) : obj;
1794            },
1795            update: function update(query) {
1796                var that = this, canceled = false, syncCalled = false, rendered = 0;
1797                this.cancel();
1798                this.cancel = function cancel() {
1799                    canceled = true;
1800                    that.cancel = $.noop;
1801                    that.async && that.trigger("asyncCanceled", query, that.name);
1802                };
1803                this.source(query, sync, async);
1804                !syncCalled && sync([]);
1805                function sync(suggestions) {
1806                    if (syncCalled) {
1807                        return;
1808                    }
1809                    syncCalled = true;
1810                    suggestions = (suggestions || []).slice(0, that.limit);
1811                    rendered = suggestions.length;
1812                    that._overwrite(query, suggestions);
1813                    if (rendered < that.limit && that.async) {
1814                        that.trigger("asyncRequested", query, that.name);
1815                    }
1816                }
1817                function async(suggestions) {
1818                    suggestions = suggestions || [];
1819                    if (!canceled && rendered < that.limit) {
1820                        that.cancel = $.noop;
1821                        var idx = Math.abs(rendered - that.limit);
1822                        rendered += idx;
1823                        that._append(query, suggestions.slice(0, idx));
1824                        that.async && that.trigger("asyncReceived", query, that.name);
1825                    }
1826                }
1827            },
1828            cancel: $.noop,
1829            clear: function clear() {
1830                this._empty();
1831                this.cancel();
1832                this.trigger("cleared");
1833            },
1834            isEmpty: function isEmpty() {
1835                return this.$el.is(":empty");
1836            },
1837            destroy: function destroy() {
1838                this.$el = $("<div>");
1839            }
1840        });
1841        return Dataset;
1842        function getDisplayFn(display) {
1843            display = display || _.stringify;
1844            return _.isFunction(display) ? display : displayFn;
1845            function displayFn(obj) {
1846                return obj[display];
1847            }
1848        }
1849        function getTemplates(templates, displayFn) {
1850            return {
1851                notFound: templates.notFound && _.templatify(templates.notFound),
1852                pending: templates.pending && _.templatify(templates.pending),
1853                header: templates.header && _.templatify(templates.header),
1854                footer: templates.footer && _.templatify(templates.footer),
1855                suggestion: templates.suggestion ? userSuggestionTemplate : suggestionTemplate
1856            };
1857            function userSuggestionTemplate(context) {
1858                var template = templates.suggestion;
1859                return $(template(context)).attr("id", _.guid());
1860            }
1861            function suggestionTemplate(context) {
1862                return $('<div role="option">').attr("id", _.guid()).text(displayFn(context));
1863            }
1864        }
1865        function isValidName(str) {
1866            return /^[_a-zA-Z0-9-]+$/.test(str);
1867        }
1868    }();
1869    var Menu = function() {
1870        "use strict";
1871        function Menu(o, www) {
1872            var that = this;
1873            o = o || {};
1874            if (!o.node) {
1875                $.error("node is required");
1876            }
1877            www.mixin(this);
1878            this.$node = $(o.node);
1879            this.query = null;
1880            this.datasets = _.map(o.datasets, initializeDataset);
1881            function initializeDataset(oDataset) {
1882                var node = that.$node.find(oDataset.node).first();
1883                oDataset.node = node.length ? node : $("<div>").appendTo(that.$node);
1884                return new Dataset(oDataset, www);
1885            }
1886        }
1887        _.mixin(Menu.prototype, EventEmitter, {
1888            _onSelectableClick: function onSelectableClick($e) {
1889                this.trigger("selectableClicked", $($e.currentTarget));
1890            },
1891            _onRendered: function onRendered(type, dataset, suggestions, async) {
1892                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
1893                this.trigger("datasetRendered", dataset, suggestions, async);
1894            },
1895            _onCleared: function onCleared() {
1896                this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
1897                this.trigger("datasetCleared");
1898            },
1899            _propagate: function propagate() {
1900                this.trigger.apply(this, arguments);
1901            },
1902            _allDatasetsEmpty: function allDatasetsEmpty() {
1903                return _.every(this.datasets, _.bind(function isDatasetEmpty(dataset) {
1904                    var isEmpty = dataset.isEmpty();
1905                    this.$node.attr("aria-expanded", !isEmpty);
1906                    return isEmpty;
1907                }, this));
1908            },
1909            _getSelectables: function getSelectables() {
1910                return this.$node.find(this.selectors.selectable);
1911            },
1912            _removeCursor: function _removeCursor() {
1913                var $selectable = this.getActiveSelectable();
1914                $selectable && $selectable.removeClass(this.classes.cursor);
1915            },
1916            _ensureVisible: function ensureVisible($el) {
1917                var elTop, elBottom, nodeScrollTop, nodeHeight;
1918                elTop = $el.position().top;
1919                elBottom = elTop + $el.outerHeight(true);
1920                nodeScrollTop = this.$node.scrollTop();
1921                nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10);
1922                if (elTop < 0) {
1923                    this.$node.scrollTop(nodeScrollTop + elTop);
1924                } else if (nodeHeight < elBottom) {
1925                    this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));
1926                }
1927            },
1928            bind: function() {
1929                var that = this, onSelectableClick;
1930                onSelectableClick = _.bind(this._onSelectableClick, this);
1931                this.$node.on("click.tt", this.selectors.selectable, onSelectableClick);
1932                this.$node.on("mouseover", this.selectors.selectable, function() {
1933                    that.setCursor($(this));
1934                });
1935                this.$node.on("mouseleave", function() {
1936                    that._removeCursor();
1937                });
1938                _.each(this.datasets, function(dataset) {
1939                    dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that);
1940                });
1941                return this;
1942            },
1943            isOpen: function isOpen() {
1944                return this.$node.hasClass(this.classes.open);
1945            },
1946            open: function open() {
1947                this.$node.scrollTop(0);
1948                this.$node.addClass(this.classes.open);
1949            },
1950            close: function close() {
1951                this.$node.attr("aria-expanded", false);
1952                this.$node.removeClass(this.classes.open);
1953                this._removeCursor();
1954            },
1955            setLanguageDirection: function setLanguageDirection(dir) {
1956                this.$node.attr("dir", dir);
1957            },
1958            selectableRelativeToCursor: function selectableRelativeToCursor(delta) {
1959                var $selectables, $oldCursor, oldIndex, newIndex;
1960                $oldCursor = this.getActiveSelectable();
1961                $selectables = this._getSelectables();
1962                oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1;
1963                newIndex = oldIndex + delta;
1964                newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;
1965                newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;
1966                return newIndex === -1 ? null : $selectables.eq(newIndex);
1967            },
1968            setCursor: function setCursor($selectable) {
1969                this._removeCursor();
1970                if ($selectable = $selectable && $selectable.first()) {
1971                    $selectable.addClass(this.classes.cursor);
1972                    this._ensureVisible($selectable);
1973                }
1974            },
1975            getSelectableData: function getSelectableData($el) {
1976                return $el && $el.length ? Dataset.extractData($el) : null;
1977            },
1978            getActiveSelectable: function getActiveSelectable() {
1979                var $selectable = this._getSelectables().filter(this.selectors.cursor).first();
1980                return $selectable.length ? $selectable : null;
1981            },
1982            getTopSelectable: function getTopSelectable() {
1983                var $selectable = this._getSelectables().first();
1984                return $selectable.length ? $selectable : null;
1985            },
1986            update: function update(query) {
1987                var isValidUpdate = query !== this.query;
1988                if (isValidUpdate) {
1989                    this.query = query;
1990                    _.each(this.datasets, updateDataset);
1991                }
1992                return isValidUpdate;
1993                function updateDataset(dataset) {
1994                    dataset.update(query);
1995                }
1996            },
1997            empty: function empty() {
1998                _.each(this.datasets, clearDataset);
1999                this.query = null;
2000                this.$node.addClass(this.classes.empty);
2001                function clearDataset(dataset) {
2002                    dataset.clear();
2003                }
2004            },
2005            destroy: function destroy() {
2006                this.$node.off(".tt");
2007                this.$node = $("<div>");
2008                _.each(this.datasets, destroyDataset);
2009                function destroyDataset(dataset) {
2010                    dataset.destroy();
2011                }
2012            }
2013        });
2014        return Menu;
2015    }();
2016    var Status = function() {
2017        "use strict";
2018        function Status(options) {
2019            this.$el = $("<span></span>", {
2020                role: "status",
2021                "aria-live": "polite"
2022            }).css({
2023                position: "absolute",
2024                padding: "0",
2025                border: "0",
2026                height: "1px",
2027                width: "1px",
2028                "margin-bottom": "-1px",
2029                "margin-right": "-1px",
2030                overflow: "hidden",
2031                clip: "rect(0 0 0 0)",
2032                "white-space": "nowrap"
2033            });
2034            options.$input.after(this.$el);
2035            _.each(options.menu.datasets, _.bind(function(dataset) {
2036                if (dataset.onSync) {
2037                    dataset.onSync("rendered", _.bind(this.update, this));
2038                    dataset.onSync("cleared", _.bind(this.cleared, this));
2039                }
2040            }, this));
2041        }
2042        _.mixin(Status.prototype, {
2043            update: function update(event, suggestions) {
2044                var length = suggestions.length;
2045                var words;
2046                if (length === 1) {
2047                    words = {
2048                        result: "result",
2049                        is: "is"
2050                    };
2051                } else {
2052                    words = {
2053                        result: "results",
2054                        is: "are"
2055                    };
2056                }
2057                this.$el.text(length + " " + words.result + " " + words.is + " available, use up and down arrow keys to navigate.");
2058            },
2059            cleared: function() {
2060                this.$el.text("");
2061            }
2062        });
2063        return Status;
2064    }();
2065    var DefaultMenu = function() {
2066        "use strict";
2067        var s = Menu.prototype;
2068        function DefaultMenu() {
2069            Menu.apply(this, [].slice.call(arguments, 0));
2070        }
2071        _.mixin(DefaultMenu.prototype, Menu.prototype, {
2072            open: function open() {
2073                !this._allDatasetsEmpty() && this._show();
2074                return s.open.apply(this, [].slice.call(arguments, 0));
2075            },
2076            close: function close() {
2077                this._hide();
2078                return s.close.apply(this, [].slice.call(arguments, 0));
2079            },
2080            _onRendered: function onRendered() {
2081                if (this._allDatasetsEmpty()) {
2082                    this._hide();
2083                } else {
2084                    this.isOpen() && this._show();
2085                }
2086                return s._onRendered.apply(this, [].slice.call(arguments, 0));
2087            },
2088            _onCleared: function onCleared() {
2089                if (this._allDatasetsEmpty()) {
2090                    this._hide();
2091                } else {
2092                    this.isOpen() && this._show();
2093                }
2094                return s._onCleared.apply(this, [].slice.call(arguments, 0));
2095            },
2096            setLanguageDirection: function setLanguageDirection(dir) {
2097                this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl);
2098                return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));
2099            },
2100            _hide: function hide() {
2101                this.$node.hide();
2102            },
2103            _show: function show() {
2104                this.$node.css("display", "block");
2105            }
2106        });
2107        return DefaultMenu;
2108    }();
2109    var Typeahead = function() {
2110        "use strict";
2111        function Typeahead(o, www) {
2112            var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged;
2113            o = o || {};
2114            if (!o.input) {
2115                $.error("missing input");
2116            }
2117            if (!o.menu) {
2118                $.error("missing menu");
2119            }
2120            if (!o.eventBus) {
2121                $.error("missing event bus");
2122            }
2123            www.mixin(this);
2124            this.eventBus = o.eventBus;
2125            this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
2126            this.input = o.input;
2127            this.menu = o.menu;
2128            this.enabled = true;
2129            this.autoselect = !!o.autoselect;
2130            this.active = false;
2131            this.input.hasFocus() && this.activate();
2132            this.dir = this.input.getLangDir();
2133            this._hacks();
2134            this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this);
2135            onFocused = c(this, "activate", "open", "_onFocused");
2136            onBlurred = c(this, "deactivate", "_onBlurred");
2137            onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed");
2138            onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed");
2139            onEscKeyed = c(this, "isActive", "_onEscKeyed");
2140            onUpKeyed = c(this, "isActive", "open", "_onUpKeyed");
2141            onDownKeyed = c(this, "isActive", "open", "_onDownKeyed");
2142            onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed");
2143            onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed");
2144            onQueryChanged = c(this, "_openIfActive", "_onQueryChanged");
2145            onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged");
2146            this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this);
2147        }
2148        _.mixin(Typeahead.prototype, {
2149            _hacks: function hacks() {
2150                var $input, $menu;
2151                $input = this.input.$input || $("<div>");
2152                $menu = this.menu.$node || $("<div>");
2153                $input.on("blur.tt", function($e) {
2154                    var active, isActive, hasActive;
2155                    active = document.activeElement;
2156                    isActive = $menu.is(active);
2157                    hasActive = $menu.has(active).length > 0;
2158                    if (_.isMsie() && (isActive || hasActive)) {
2159                        $e.preventDefault();
2160                        $e.stopImmediatePropagation();
2161                        _.defer(function() {
2162                            $input.focus();
2163                        });
2164                    }
2165                });
2166                $menu.on("mousedown.tt", function($e) {
2167                    $e.preventDefault();
2168                });
2169            },
2170            _onSelectableClicked: function onSelectableClicked(type, $el) {
2171                this.select($el);
2172            },
2173            _onDatasetCleared: function onDatasetCleared() {
2174                this._updateHint();
2175            },
2176            _onDatasetRendered: function onDatasetRendered(type, suggestions, async, dataset) {
2177                this._updateHint();
2178                if (this.autoselect) {
2179                    var cursorClass = this.selectors.cursor.substr(1);
2180                    this.menu.$node.find(this.selectors.suggestion).first().addClass(cursorClass);
2181                }
2182                this.eventBus.trigger("render", suggestions, async, dataset);
2183            },
2184            _onAsyncRequested: function onAsyncRequested(type, dataset, query) {
2185                this.eventBus.trigger("asyncrequest", query, dataset);
2186            },
2187            _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {
2188                this.eventBus.trigger("asynccancel", query, dataset);
2189            },
2190            _onAsyncReceived: function onAsyncReceived(type, dataset, query) {
2191                this.eventBus.trigger("asyncreceive", query, dataset);
2192            },
2193            _onFocused: function onFocused() {
2194                this._minLengthMet() && this.menu.update(this.input.getQuery());
2195            },
2196            _onBlurred: function onBlurred() {
2197                if (this.input.hasQueryChangedSinceLastFocus()) {
2198                    this.eventBus.trigger("change", this.input.getQuery());
2199                }
2200            },
2201            _onEnterKeyed: function onEnterKeyed(type, $e) {
2202                var $selectable;
2203                if ($selectable = this.menu.getActiveSelectable()) {
2204                    if (this.select($selectable)) {
2205                        $e.preventDefault();
2206                        $e.stopPropagation();
2207                    }
2208                } else if (this.autoselect) {
2209                    if (this.select(this.menu.getTopSelectable())) {
2210                        $e.preventDefault();
2211                        $e.stopPropagation();
2212                    }
2213                }
2214            },
2215            _onTabKeyed: function onTabKeyed(type, $e) {
2216                var $selectable;
2217                if ($selectable = this.menu.getActiveSelectable()) {
2218                    this.select($selectable) && $e.preventDefault();
2219                } else if (this.autoselect) {
2220                    if ($selectable = this.menu.getTopSelectable()) {
2221                        this.autocomplete($selectable) && $e.preventDefault();
2222                    }
2223                }
2224            },
2225            _onEscKeyed: function onEscKeyed() {
2226                this.close();
2227            },
2228            _onUpKeyed: function onUpKeyed() {
2229                this.moveCursor(-1);
2230            },
2231            _onDownKeyed: function onDownKeyed() {
2232                this.moveCursor(+1);
2233            },
2234            _onLeftKeyed: function onLeftKeyed() {
2235                if (this.dir === "rtl" && this.input.isCursorAtEnd()) {
2236                    this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable());
2237                }
2238            },
2239            _onRightKeyed: function onRightKeyed() {
2240                if (this.dir === "ltr" && this.input.isCursorAtEnd()) {
2241                    this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable());
2242                }
2243            },
2244            _onQueryChanged: function onQueryChanged(e, query) {
2245                this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();
2246            },
2247            _onWhitespaceChanged: function onWhitespaceChanged() {
2248                this._updateHint();
2249            },
2250            _onLangDirChanged: function onLangDirChanged(e, dir) {
2251                if (this.dir !== dir) {
2252                    this.dir = dir;
2253                    this.menu.setLanguageDirection(dir);
2254                }
2255            },
2256            _openIfActive: function openIfActive() {
2257                this.isActive() && this.open();
2258            },
2259            _minLengthMet: function minLengthMet(query) {
2260                query = _.isString(query) ? query : this.input.getQuery() || "";
2261                return query.length >= this.minLength;
2262            },
2263            _updateHint: function updateHint() {
2264                var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;
2265                $selectable = this.menu.getTopSelectable();
2266                data = this.menu.getSelectableData($selectable);
2267                val = this.input.getInputValue();
2268                if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {
2269                    query = Input.normalizeQuery(val);
2270                    escapedQuery = _.escapeRegExChars(query);
2271                    frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i");
2272                    match = frontMatchRegEx.exec(data.val);
2273                    match && this.input.setHint(val + match[1]);
2274                } else {
2275                    this.input.clearHint();
2276                }
2277            },
2278            isEnabled: function isEnabled() {
2279                return this.enabled;
2280            },
2281            enable: function enable() {
2282                this.enabled = true;
2283            },
2284            disable: function disable() {
2285                this.enabled = false;
2286            },
2287            isActive: function isActive() {
2288                return this.active;
2289            },
2290            activate: function activate() {
2291                if (this.isActive()) {
2292                    return true;
2293                } else if (!this.isEnabled() || this.eventBus.before("active")) {
2294                    return false;
2295                } else {
2296                    this.active = true;
2297                    this.eventBus.trigger("active");
2298                    return true;
2299                }
2300            },
2301            deactivate: function deactivate() {
2302                if (!this.isActive()) {
2303                    return true;
2304                } else if (this.eventBus.before("idle")) {
2305                    return false;
2306                } else {
2307                    this.active = false;
2308                    this.close();
2309                    this.eventBus.trigger("idle");
2310                    return true;
2311                }
2312            },
2313            isOpen: function isOpen() {
2314                return this.menu.isOpen();
2315            },
2316            open: function open() {
2317                if (!this.isOpen() && !this.eventBus.before("open")) {
2318                    this.input.setAriaExpanded(true);
2319                    this.menu.open();
2320                    this._updateHint();
2321                    this.eventBus.trigger("open");
2322                }
2323                return this.isOpen();
2324            },
2325            close: function close() {
2326                if (this.isOpen() && !this.eventBus.before("close")) {
2327                    this.input.setAriaExpanded(false);
2328                    this.menu.close();
2329                    this.input.clearHint();
2330                    this.input.resetInputValue();
2331                    this.eventBus.trigger("close");
2332                }
2333                return !this.isOpen();
2334            },
2335            setVal: function setVal(val) {
2336                this.input.setQuery(_.toStr(val));
2337            },
2338            getVal: function getVal() {
2339                return this.input.getQuery();
2340            },
2341            select: function select($selectable) {
2342                var data = this.menu.getSelectableData($selectable);
2343                if (data && !this.eventBus.before("select", data.obj, data.dataset)) {
2344                    this.input.setQuery(data.val, true);
2345                    this.eventBus.trigger("select", data.obj, data.dataset);
2346                    this.close();
2347                    return true;
2348                }
2349                return false;
2350            },
2351            autocomplete: function autocomplete($selectable) {
2352                var query, data, isValid;
2353                query = this.input.getQuery();
2354                data = this.menu.getSelectableData($selectable);
2355                isValid = data && query !== data.val;
2356                if (isValid && !this.eventBus.before("autocomplete", data.obj, data.dataset)) {
2357                    this.input.setQuery(data.val);
2358                    this.eventBus.trigger("autocomplete", data.obj, data.dataset);
2359                    return true;
2360                }
2361                return false;
2362            },
2363            moveCursor: function moveCursor(delta) {
2364                var query, $candidate, data, suggestion, datasetName, cancelMove, id;
2365                query = this.input.getQuery();
2366                $candidate = this.menu.selectableRelativeToCursor(delta);
2367                data = this.menu.getSelectableData($candidate);
2368                suggestion = data ? data.obj : null;
2369                datasetName = data ? data.dataset : null;
2370                id = $candidate ? $candidate.attr("id") : null;
2371                this.input.trigger("cursorchange", id);
2372                cancelMove = this._minLengthMet() && this.menu.update(query);
2373                if (!cancelMove && !this.eventBus.before("cursorchange", suggestion, datasetName)) {
2374                    this.menu.setCursor($candidate);
2375                    if (data) {
2376                        if (typeof data.val === "string") {
2377                            this.input.setInputValue(data.val);
2378                        }
2379                    } else {
2380                        this.input.resetInputValue();
2381                        this._updateHint();
2382                    }
2383                    this.eventBus.trigger("cursorchange", suggestion, datasetName);
2384                    return true;
2385                }
2386                return false;
2387            },
2388            destroy: function destroy() {
2389                this.input.destroy();
2390                this.menu.destroy();
2391            }
2392        });
2393        return Typeahead;
2394        function c(ctx) {
2395            var methods = [].slice.call(arguments, 1);
2396            return function() {
2397                var args = [].slice.call(arguments);
2398                _.each(methods, function(method) {
2399                    return ctx[method].apply(ctx, args);
2400                });
2401            };
2402        }
2403    }();
2404    (function() {
2405        "use strict";
2406        var old, keys, methods;
2407        old = $.fn.typeahead;
2408        keys = {
2409            www: "tt-www",
2410            attrs: "tt-attrs",
2411            typeahead: "tt-typeahead"
2412        };
2413        methods = {
2414            initialize: function initialize(o, datasets) {
2415                var www;
2416                datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);
2417                o = o || {};
2418                www = WWW(o.classNames);
2419                return this.each(attach);
2420                function attach() {
2421                    var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, status, typeahead, MenuConstructor;
2422                    _.each(datasets, function(d) {
2423                        d.highlight = !!o.highlight;
2424                    });
2425                    $input = $(this);
2426                    $wrapper = $(www.html.wrapper);
2427                    $hint = $elOrNull(o.hint);
2428                    $menu = $elOrNull(o.menu);
2429                    defaultHint = o.hint !== false && !$hint;
2430                    defaultMenu = o.menu !== false && !$menu;
2431                    defaultHint && ($hint = buildHintFromInput($input, www));
2432                    defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));
2433                    $hint && $hint.val("");
2434                    $input = prepInput($input, www);
2435                    if (defaultHint || defaultMenu) {
2436                        $wrapper.css(www.css.wrapper);
2437                        $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);
2438                        $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null);
2439                    }
2440                    MenuConstructor = defaultMenu ? DefaultMenu : Menu;
2441                    eventBus = new EventBus({
2442                        el: $input
2443                    });
2444                    input = new Input({
2445                        hint: $hint,
2446                        input: $input,
2447                        menu: $menu
2448                    }, www);
2449                    menu = new MenuConstructor({
2450                        node: $menu,
2451                        datasets: datasets
2452                    }, www);
2453                    status = new Status({
2454                        $input: $input,
2455                        menu: menu
2456                    });
2457                    typeahead = new Typeahead({
2458                        input: input,
2459                        menu: menu,
2460                        eventBus: eventBus,
2461                        minLength: o.minLength,
2462                        autoselect: o.autoselect
2463                    }, www);
2464                    $input.data(keys.www, www);
2465                    $input.data(keys.typeahead, typeahead);
2466                }
2467            },
2468            isEnabled: function isEnabled() {
2469                var enabled;
2470                ttEach(this.first(), function(t) {
2471                    enabled = t.isEnabled();
2472                });
2473                return enabled;
2474            },
2475            enable: function enable() {
2476                ttEach(this, function(t) {
2477                    t.enable();
2478                });
2479                return this;
2480            },
2481            disable: function disable() {
2482                ttEach(this, function(t) {
2483                    t.disable();
2484                });
2485                return this;
2486            },
2487            isActive: function isActive() {
2488                var active;
2489                ttEach(this.first(), function(t) {
2490                    active = t.isActive();
2491                });
2492                return active;
2493            },
2494            activate: function activate() {
2495                ttEach(this, function(t) {
2496                    t.activate();
2497                });
2498                return this;
2499            },
2500            deactivate: function deactivate() {
2501                ttEach(this, function(t) {
2502                    t.deactivate();
2503                });
2504                return this;
2505            },
2506            isOpen: function isOpen() {
2507                var open;
2508                ttEach(this.first(), function(t) {
2509                    open = t.isOpen();
2510                });
2511                return open;
2512            },
2513            open: function open() {
2514                ttEach(this, function(t) {
2515                    t.open();
2516                });
2517                return this;
2518            },
2519            close: function close() {
2520                ttEach(this, function(t) {
2521                    t.close();
2522                });
2523                return this;
2524            },
2525            select: function select(el) {
2526                var success = false, $el = $(el);
2527                ttEach(this.first(), function(t) {
2528                    success = t.select($el);
2529                });
2530                return success;
2531            },
2532            autocomplete: function autocomplete(el) {
2533                var success = false, $el = $(el);
2534                ttEach(this.first(), function(t) {
2535                    success = t.autocomplete($el);
2536                });
2537                return success;
2538            },
2539            moveCursor: function moveCursoe(delta) {
2540                var success = false;
2541                ttEach(this.first(), function(t) {
2542                    success = t.moveCursor(delta);
2543                });
2544                return success;
2545            },
2546            val: function val(newVal) {
2547                var query;
2548                if (!arguments.length) {
2549                    ttEach(this.first(), function(t) {
2550                        query = t.getVal();
2551                    });
2552                    return query;
2553                } else {
2554                    ttEach(this, function(t) {
2555                        t.setVal(_.toStr(newVal));
2556                    });
2557                    return this;
2558                }
2559            },
2560            destroy: function destroy() {
2561                ttEach(this, function(typeahead, $input) {
2562                    revert($input);
2563                    typeahead.destroy();
2564                });
2565                return this;
2566            }
2567        };
2568        $.fn.typeahead = function(method) {
2569            if (methods[method]) {
2570                return methods[method].apply(this, [].slice.call(arguments, 1));
2571            } else {
2572                return methods.initialize.apply(this, arguments);
2573            }
2574        };
2575        $.fn.typeahead.noConflict = function noConflict() {
2576            $.fn.typeahead = old;
2577            return this;
2578        };
2579        function ttEach($els, fn) {
2580            $els.each(function() {
2581                var $input = $(this), typeahead;
2582                (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);
2583            });
2584        }
2585        function buildHintFromInput($input, www) {
2586            return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop({
2587                readonly: true,
2588                required: false
2589            }).removeAttr("id name placeholder").removeClass("required").attr({
2590                spellcheck: "false",
2591                tabindex: -1
2592            });
2593        }
2594        function prepInput($input, www) {
2595            $input.data(keys.attrs, {
2596                dir: $input.attr("dir"),
2597                autocomplete: $input.attr("autocomplete"),
2598                spellcheck: $input.attr("spellcheck"),
2599                style: $input.attr("style")
2600            });
2601            $input.addClass(www.classes.input).attr({
2602                spellcheck: false
2603            });
2604            try {
2605                !$input.attr("dir") && $input.attr("dir", "auto");
2606            } catch (e) {}
2607            return $input;
2608        }
2609        function getBackgroundStyles($el) {
2610            return {
2611                backgroundAttachment: $el.css("background-attachment"),
2612                backgroundClip: $el.css("background-clip"),
2613                backgroundColor: $el.css("background-color"),
2614                backgroundImage: $el.css("background-image"),
2615                backgroundOrigin: $el.css("background-origin"),
2616                backgroundPosition: $el.css("background-position"),
2617                backgroundRepeat: $el.css("background-repeat"),
2618                backgroundSize: $el.css("background-size")
2619            };
2620        }
2621        function revert($input) {
2622            var www, $wrapper;
2623            www = $input.data(keys.www);
2624            $wrapper = $input.parent().filter(www.selectors.wrapper);
2625            _.each($input.data(keys.attrs), function(val, key) {
2626                _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);
2627            });
2628            $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input);
2629            if ($wrapper.length) {
2630                $input.detach().insertAfter($wrapper);
2631                $wrapper.remove();
2632            }
2633        }
2634        function $elOrNull(obj) {
2635            var isValid, $el;
2636            isValid = _.isJQuery(obj) || _.isElement(obj);
2637            $el = isValid ? $(obj).first() : [];
2638            return $el.length ? $el : null;
2639        }
2640    })();
2641});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.