PageSourceSearch

https://www.siegenia.com/siauv4/bootstrap/dist/lib/bower/typeahead.js/typeahead.bundle.js

js siegenia.com collected 2026-10-02 10:30:32 UTC 78,871 bytes, 2,563 lines download raw bytes

vendor: 26,008 bytes, lines 1-941
1/*!
2 * typeahead.js 0.11.1
3 * https://github.com/twitter/typeahead.js
4 * Copyright 2013-2015 Twitter, Inc. and other contributors; Licensed MIT
5 */
6
7(function (root, factory) {
8  if (typeof define === "function" && define.amd) {
9    define("bloodhound", ["jquery"], function (a0) {
10      return root["Bloodhound"] = factory(a0);
11    });
12  } else if (typeof exports === "object") {
13    module.exports = factory(require("jquery"));
14  } else {
15    root["Bloodhound"] = factory(jQuery);
16  }
17})(this, function ($) {
18  var _ = function () {
19    "use strict";
20    return {
21      isMsie: function () {
22        return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
23      },
24      isBlankString: function (str) {
25        return !str || /^\s*$/.test(str);
26      },
27      escapeRegExChars: function (str) {
28        return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
29      },
30      isString: function (obj) {
31        return typeof obj === "string";
32      },
33      isNumber: function (obj) {
34        return typeof obj === "number";
35      },
36      isArray: $.isArray,
37      isFunction: $.isFunction,
38      isObject: $.isPlainObject,
39      isUndefined: function (obj) {
40        return typeof obj === "undefined";
41      },
42      isElement: function (obj) {
43        return !!(obj && obj.nodeType === 1);
44      },
45      isJQuery: function (obj) {
46        return obj instanceof $;
47      },
48      toStr: function toStr(s) {
49        return _.isUndefined(s) || s === null ? "" : s + "";
50      },
51      bind: $.proxy,
52      each: function (collection, cb) {
53        $.each(collection, reverseArgs);
54
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
101        function template() {
102          return String(obj);
103        }
104      },
105      defer: function (fn) {
106        setTimeout(fn, 0);
107      },
108      debounce: function (func, wait, immediate) {
109        var timeout, result;
110        return function () {
111          var context = this, args = arguments, later, callNow;
112          later = function () {
113            timeout = null;
114            if (!immediate) {
115              result = func.apply(context, args);
116            }
117          };
118          callNow = immediate && !timeout;
119          clearTimeout(timeout);
120          timeout = setTimeout(later, wait);
121          if (callNow) {
122            result = func.apply(context, args);
123          }
124          return result;
125        };
126      },
127      throttle: function (func, wait) {
128        var context, args, timeout, result, previous, later;
129        previous = 0;
130        later = function () {
131          previous = new Date();
132          timeout = null;
133          result = func.apply(context, args);
134        };
135        return function () {
136          var now = new Date(), remaining = wait - (now - previous);
137          context = this;
138          args = arguments;
139          if (remaining <= 0) {
140            clearTimeout(timeout);
141            timeout = null;
142            previous = now;
143            result = func.apply(context, args);
144          } else if (!timeout) {
145            timeout = setTimeout(later, remaining);
146          }
147          return result;
148        };
149      },
150      stringify: function (val) {
151        return _.isString(val) ? val : JSON.stringify(val);
152      },
153      noop: function () {
154      }
155    };
156  }();
157  var VERSION = "0.11.1";
158  var tokenizers = function () {
159    "use strict";
160    return {
161      nonword: nonword,
162      whitespace: whitespace,
163      obj: {
164        nonword: getObjTokenizer(nonword),
165        whitespace: getObjTokenizer(whitespace)
166      }
167    };
168
169    function whitespace(str) {
170      str = _.toStr(str);
171      return str ? str.split(/\s+/) : [];
172    }
173
174    function nonword(str) {
175      str = _.toStr(str);
176      return str ? str.split(/\W+/) : [];
177    }
178
179    function getObjTokenizer(tokenizer) {
180      return function setKey(keys) {
181        keys = _.isArray(keys) ? keys : [].slice.call(arguments, 0);
182        return function tokenize(o) {
183          var tokens = [];
184          _.each(keys, function (k) {
185            tokens = tokens.concat(tokenizer(_.toStr(o[k])));
186          });
187          return tokens;
188        };
189      };
190    }
191  }();
192  var LruCache = function () {
193    "use strict";
194
195    function LruCache(maxSize) {
196      this.maxSize = _.isNumber(maxSize) ? maxSize : 100;
197      this.reset();
198      if (this.maxSize <= 0) {
199        this.set = this.get = $.noop;
200      }
201    }
202
203    _.mixin(LruCache.prototype, {
204      set: function set(key, val) {
205        var tailItem = this.list.tail, node;
206        if (this.size >= this.maxSize) {
207          this.list.remove(tailItem);
208          delete this.hash[tailItem.key];
209          this.size--;
210        }
211        if (node = this.hash[key]) {
212          node.val = val;
213          this.list.moveToFront(node);
214        } else {
215          node = new Node(key, val);
216          this.list.add(node);
217          this.hash[key] = node;
218          this.size++;
219        }
220      },
221      get: function get(key) {
222        var node = this.hash[key];
223        if (node) {
224          this.list.moveToFront(node);
225          return node.val;
226        }
227      },
228      reset: function reset() {
229        this.size = 0;
230        this.hash = {};
231        this.list = new List();
232      }
233    });
234
235    function List() {
236      this.head = this.tail = null;
237    }
238
239    _.mixin(List.prototype, {
240      add: function add(node) {
241        if (this.head) {
242          node.next = this.head;
243          this.head.prev = node;
244        }
245        this.head = node;
246        this.tail = this.tail || node;
247      },
248      remove: function remove(node) {
249        node.prev ? node.prev.next = node.next : this.head = node.next;
250        node.next ? node.next.prev = node.prev : this.tail = node.prev;
251      },
252      moveToFront: function (node) {
253        this.remove(node);
254        this.add(node);
255      }
256    });
257
258    function Node(key, val) {
259      this.key = key;
260      this.val = val;
261      this.prev = this.next = null;
262    }
263
264    return LruCache;
265  }();
266  var PersistentStorage = function () {
267    "use strict";
268    var LOCAL_STORAGE;
269    try {
270      LOCAL_STORAGE = window.localStorage;
271      LOCAL_STORAGE.setItem("~~~", "!");
272      LOCAL_STORAGE.removeItem("~~~");
273    } catch (err) {
274      LOCAL_STORAGE = null;
275    }
276
277    function PersistentStorage(namespace, override) {
278      this.prefix = ["__", namespace, "__"].join("");
279      this.ttlKey = "__ttl__";
280      this.keyMatcher = new RegExp("^" + _.escapeRegExChars(this.prefix));
281      this.ls = override || LOCAL_STORAGE;
282      !this.ls && this._noop();
283    }
284
285    _.mixin(PersistentStorage.prototype, {
286      _prefix: function (key) {
287        return this.prefix + key;
288      },
289      _ttlKey: function (key) {
290        return this._prefix(key) + this.ttlKey;
291      },
292      _noop: function () {
293        this.get = this.set = this.remove = this.clear = this.isExpired = _.noop;
294      },
295      _safeSet: function (key, val) {
296        try {
297          this.ls.setItem(key, val);
298        } catch (err) {
299          if (err.name === "QuotaExceededError") {
300            this.clear();
301            this._noop();
302          }
303        }
304      },
305      get: function (key) {
306        if (this.isExpired(key)) {
307          this.remove(key);
308        }
309        return decode(this.ls.getItem(this._prefix(key)));
310      },
311      set: function (key, val, ttl) {
312        if (_.isNumber(ttl)) {
313          this._safeSet(this._ttlKey(key), encode(now() + ttl));
314        } else {
315          this.ls.removeItem(this._ttlKey(key));
316        }
317        return this._safeSet(this._prefix(key), encode(val));
318      },
319      remove: function (key) {
320        this.ls.removeItem(this._ttlKey(key));
321        this.ls.removeItem(this._prefix(key));
322        return this;
323      },
324      clear: function () {
325        var i, keys = gatherMatchingKeys(this.keyMatcher);
326        for (i = keys.length; i--;) {
327          this.remove(keys[i]);
328        }
329        return this;
330      },
331      isExpired: function (key) {
332        var ttl = decode(this.ls.getItem(this._ttlKey(key)));
333        return _.isNumber(ttl) && now() > ttl ? true : false;
334      }
335    });
336    return PersistentStorage;
337
338    function now() {
339      return new Date().getTime();
340    }
341
342    function encode(val) {
343      return JSON.stringify(_.isUndefined(val) ? null : val);
344    }
345
346    function decode(val) {
347      return $.parseJSON(val);
348    }
349
350    function gatherMatchingKeys(keyMatcher) {
351      var i, key, keys = [], len = LOCAL_STORAGE.length;
352      for (i = 0; i < len; i++) {
353        if ((key = LOCAL_STORAGE.key(i)).match(keyMatcher)) {
354          keys.push(key.replace(keyMatcher, ""));
355        }
356      }
357      return keys;
358    }
359  }();
360  var Transport = function () {
361    "use strict";
362    var pendingRequestsCount = 0, pendingRequests = {}, maxPendingRequests = 6, sharedCache = new LruCache(10);
363
364    function Transport(o) {
365      o = o || {};
366      this.cancelled = false;
367      this.lastReq = null;
368      this._send = o.transport;
369      this._get = o.limiter ? o.limiter(this._get) : this._get;
370      this._cache = o.cache === false ? new LruCache(0) : sharedCache;
371    }
372
373    Transport.setMaxPendingRequests = function setMaxPendingRequests(num) {
374      maxPendingRequests = num;
375    };
376    Transport.resetCache = function resetCache() {
377      sharedCache.reset();
378    };
379    _.mixin(Transport.prototype, {
380      _fingerprint: function fingerprint(o) {
381        o = o || {};
382        return o.url + o.type + $.param(o.data || {});
383      },
384      _get: function (o, cb) {
385        var that = this, fingerprint, jqXhr;
386        fingerprint = this._fingerprint(o);
387        if (this.cancelled || fingerprint !== this.lastReq) {
388          return;
389        }
390        if (jqXhr = pendingRequests[fingerprint]) {
391          jqXhr.done(done).fail(fail);
392        } else if (pendingRequestsCount < maxPendingRequests) {
393          pendingRequestsCount++;
394          pendingRequests[fingerprint] = this._send(o).done(done).fail(fail).always(always);
395        } else {
396          this.onDeckRequestArgs = [].slice.call(arguments, 0);
397        }
398
399        function done(resp) {
400          cb(null, resp);
401          that._cache.set(fingerprint, resp);
402        }
403
404        function fail() {
405          cb(true);
406        }
407
408        function always() {
409          pendingRequestsCount--;
410          delete pendingRequests[fingerprint];
411          if (that.onDeckRequestArgs) {
412            that._get.apply(that, that.onDeckRequestArgs);
413            that.onDeckRequestArgs = null;
414          }
415        }
416      },
417      get: function (o, cb) {
418        var resp, fingerprint;
419        cb = cb || $.noop;
420        o = _.isString(o) ? {
421          url: o
422        } : o || {};
423        fingerprint = this._fingerprint(o);
424        this.cancelled = false;
425        this.lastReq = fingerprint;
426        if (resp = this._cache.get(fingerprint)) {
427          cb(null, resp);
428        } else {
429          this._get(o, cb);
430        }
431      },
432      cancel: function () {
433        this.cancelled = true;
434      }
435    });
436    return Transport;
437  }();
438  var SearchIndex = window.SearchIndex = function () {
439    "use strict";
440    var CHILDREN = "c", IDS = "i";
441
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.reset();
451    }
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) {
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            matches = [];
500            return false;
501          }
502        });
503        return matches ? _.map(unique(matches), function (id) {
504          return that.datums[id];
505        }) : [];
506      },
507      all: function all() {
508        var values = [];
509        for (var key in this.datums) {
510          values.push(this.datums[key]);
511        }
512        return values;
513      },
514      reset: function reset() {
515        this.datums = {};
516        this.trie = newNode();
517      },
518      serialize: function serialize() {
519        return {
520          datums: this.datums,
521          trie: this.trie
522        };
523      }
524    });
525    return SearchIndex;
526
527    function normalizeTokens(tokens) {
528      tokens = _.filter(tokens, function (token) {
529        return !!token;
530      });
531      tokens = _.map(tokens, function (token) {
532        return token.toLowerCase();
533      });
534      return tokens;
535    }
536
537    function newNode() {
538      var node = {};
539      node[IDS] = [];
540      node[CHILDREN] = {};
541      return node;
542    }
543
544    function unique(array) {
545      var seen = {}, uniques = [];
546      for (var i = 0, len = array.length; i < len; i++) {
547        if (!seen[array[i]]) {
548          seen[array[i]] = true;
549          uniques.push(array[i]);
550        }
551      }
552      return uniques;
553    }
554
555    function getIntersection(arrayA, arrayB) {
556      var ai = 0, bi = 0, intersection = [];
557      arrayA = arrayA.sort();
558      arrayB = arrayB.sort();
559      var lenArrayA = arrayA.length, lenArrayB = arrayB.length;
560      while (ai < lenArrayA && bi < lenArrayB) {
561        if (arrayA[ai] < arrayB[bi]) {
562          ai++;
563        } else if (arrayA[ai] > arrayB[bi]) {
564          bi++;
565        } else {
566          intersection.push(arrayA[ai]);
567          ai++;
568          bi++;
569        }
570      }
571      return intersection;
572    }
573  }();
574  var Prefetch = function () {
575    "use strict";
576    var keys;
577    keys = {
578      data: "data",
579      protocol: "protocol",
580      thumbprint: "thumbprint"
581    };
582
583    function Prefetch(o) {
584      this.url = o.url;
585      this.ttl = o.ttl;
586      this.cache = o.cache;
587      this.prepare = o.prepare;
588      this.transform = o.transform;
589      this.transport = o.transport;
590      this.thumbprint = o.thumbprint;
591      this.storage = new PersistentStorage(o.cacheKey);
592    }
593
594    _.mixin(Prefetch.prototype, {
595      _settings: function settings() {
596        return {
597          url: this.url,
598          type: "GET",
599          dataType: "json"
600        };
601      },
602      store: function store(data) {
603        if (!this.cache) {
604          return;
605        }
606        this.storage.set(keys.data, data, this.ttl);
607        this.storage.set(keys.protocol, location.protocol, this.ttl);
608        this.storage.set(keys.thumbprint, this.thumbprint, this.ttl);
609      },
610      fromCache: function fromCache() {
611        var stored = {}, isExpired;
612        if (!this.cache) {
613          return null;
614        }
615        stored.data = this.storage.get(keys.data);
616        stored.protocol = this.storage.get(keys.protocol);
617        stored.thumbprint = this.storage.get(keys.thumbprint);
618        isExpired = stored.thumbprint !== this.thumbprint || stored.protocol !== location.protocol;
619        return stored.data && !isExpired ? stored.data : null;
620      },
621      fromNetwork: function (cb) {
622        var that = this, settings;
623        if (!cb) {
624          return;
625        }
626        settings = this.prepare(this._settings());
627        this.transport(settings).fail(onError).done(onResponse);
628
629        function onError() {
630          cb(true);
631        }
632
633        function onResponse(resp) {
634          cb(null, that.transform(resp));
635        }
636      },
637      clear: function clear() {
638        this.storage.clear();
639        return this;
640      }
641    });
642    return Prefetch;
643  }();
644  var Remote = function () {
645    "use strict";
646
647    function Remote(o) {
648      this.url = o.url;
649      this.prepare = o.prepare;
650      this.transform = o.transform;
651      this.transport = new Transport({
652        cache: o.cache,
653        limiter: o.limiter,
654        transport: o.transport
655      });
656    }
657
658    _.mixin(Remote.prototype, {
659      _settings: function settings() {
660        return {
661          url: this.url,
662          type: "GET",
663          dataType: "json"
664        };
665      },
666      get: function get(query, cb) {
667        var that = this, settings;
668        if (!cb) {
669          return;
670        }
671        query = query || "";
672        settings = this.prepare(query, this._settings());
673        return this.transport.get(settings, onResponse);
674
675        function onResponse(err, resp) {
676          err ? cb([]) : cb(that.transform(resp));
677        }
678      },
679      cancelLastRequest: function cancelLastRequest() {
680        this.transport.cancel();
681      }
682    });
683    return Remote;
684  }();
685  var oParser = function () {
686    "use strict";
687    return function parse(o) {
688      var defaults, sorter;
689      defaults = {
690        initialize: true,
691        identify: _.stringify,
692        datumTokenizer: null,
693        queryTokenizer: null,
694        sufficient: 5,
695        sorter: null,
696        local: [],
697        prefetch: null,
698        remote: null
699      };
700      o = _.mixin(defaults, o || {});
701      !o.datumTokenizer && $.error("datumTokenizer is required");
702      !o.queryTokenizer && $.error("queryTokenizer is required");
703      sorter = o.sorter;
704      o.sorter = sorter ? function (x) {
705        return x.sort(sorter);
706      } : _.identity;
707      o.local = _.isFunction(o.local) ? o.local() : o.local;
708      o.prefetch = parsePrefetch(o.prefetch);
709      o.remote = parseRemote(o.remote);
710      return o;
711    };
712
713    function parsePrefetch(o) {
714      var defaults;
715      if (!o) {
716        return null;
717      }
718      defaults = {
719        url: null,
720        ttl: 24 * 60 * 60 * 1e3,
721        cache: true,
722        cacheKey: null,
723        thumbprint: "",
724        prepare: _.identity,
725        transform: _.identity,
726        transport: null
727      };
728      o = _.isString(o) ? {
729        url: o
730      } : o;
731      o = _.mixin(defaults, o);
732      !o.url && $.error("prefetch requires url to be set");
733      o.transform = o.filter || o.transform;
734      o.cacheKey = o.cacheKey || o.url;
735      o.thumbprint = VERSION + o.thumbprint;
736      o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
737      return o;
738    }
739
740    function parseRemote(o) {
741      var defaults;
742      if (!o) {
743        return;
744      }
745      defaults = {
746        url: null,
747        cache: true,
748        prepare: null,
749        replace: null,
750        wildcard: null,
751        limiter: null,
752        rateLimitBy: "debounce",
753        rateLimitWait: 300,
754        transform: _.identity,
755        transport: null
756      };
757      o = _.isString(o) ? {
758        url: o
759      } : o;
760      o = _.mixin(defaults, o);
761      !o.url && $.error("remote requires url to be set");
762      o.transform = o.filter || o.transform;
763      o.prepare = toRemotePrepare(o);
764      o.limiter = toLimiter(o);
765      o.transport = o.transport ? callbackToDeferred(o.transport) : $.ajax;
766      delete o.replace;
767      delete o.wildcard;
768      delete o.rateLimitBy;
769      delete o.rateLimitWait;
770      return o;
771    }
772
773    function toRemotePrepare(o) {
774      var prepare, replace, wildcard;
775      prepare = o.prepare;
776      replace = o.replace;
777      wildcard = o.wildcard;
778      if (prepare) {
779        return prepare;
780      }
781      if (replace) {
782        prepare = prepareByReplace;
783      } else if (o.wildcard) {
784        prepare = prepareByWildcard;
785      } else {
786        prepare = idenityPrepare;
787      }
788      return prepare;
789
790      function prepareByReplace(query, settings) {
791        settings.url = replace(settings.url, query);
792        return settings;
793      }
794
795      function prepareByWildcard(query, settings) {
796        settings.url = settings.url.replace(wildcard, encodeURIComponent(query));
797        return settings;
798      }
799
800      function idenityPrepare(query, settings) {
801        return settings;
802      }
803    }
804
805    function toLimiter(o) {
806      var limiter, method, wait;
807      limiter = o.limiter;
808      method = o.rateLimitBy;
809      wait = o.rateLimitWait;
810      if (!limiter) {
811        limiter = /^throttle$/i.test(method) ? throttle(wait) : debounce(wait);
812      }
813      return limiter;
814
815      function debounce(wait) {
816        return function debounce(fn) {
817          return _.debounce(fn, wait);
818        };
819      }
820
821      function throttle(wait) {
822        return function throttle(fn) {
823          return _.throttle(fn, wait);
824        };
825      }
826    }
827
828    function callbackToDeferred(fn) {
829      return function wrapper(o) {
830        var deferred = $.Deferred();
831        fn(o, onSuccess, onError);
832        return deferred;
833
834        function onSuccess(resp) {
835          _.defer(function () {
836            deferred.resolve(resp);
837          });
838        }
839
840        function onError(err) {
841          _.defer(function () {
842            deferred.reject(err);
843          });
844        }
845      };
846    }
847  }();
848  var Bloodhound = function () {
849    "use strict";
850    var old;
851    old = window && window.Bloodhound;
852
853    function Bloodhound(o) {
854      o = oParser(o);
855      this.sorter = o.sorter;
856      this.identify = o.identify;
857      this.sufficient = o.sufficient;
858      this.local = o.local;
859      this.remote = o.remote ? new Remote(o.remote) : null;
860      this.prefetch = o.prefetch ? new Prefetch(o.prefetch) : null;
861      this.index = new SearchIndex({
862        identify: this.identify,
863        datumTokenizer: o.datumTokenizer,
864        queryTokenizer: o.queryTokenizer
865      });
866      o.initialize !== false && this.initialize();
867    }
868
869    Bloodhound.noConflict = function noConflict() {
870      window && (window.Bloodhound = old);
871      return Bloodhound;
872    };
873    Bloodhound.tokenizers = tokenizers;
874    _.mixin(Bloodhound.prototype, {
875      __ttAdapter: function ttAdapter() {
876        var that = this;
877        return this.remote ? withAsync : withoutAsync;
878
879        function withAsync(query, sync, async) {
880          return that.search(query, sync, async);
881        }
882
883        function withoutAsync(query, sync) {
884          return that.search(query, sync);
885        }
886      },
887      _loadPrefetch: function loadPrefetch() {
888        var that = this, deferred, serialized;
889        deferred = $.Deferred();
890        if (!this.prefetch) {
891          deferred.resolve();
892        } else if (serialized = this.prefetch.fromCache()) {
893          this.index.bootstrap(serialized);
894          deferred.resolve();
895        } else {
896          this.prefetch.fromNetwork(done);
897        }
898        return deferred.promise();
899
900        function done(err, data) {
901          if (err) {
902            return deferred.reject();
903          }
904          that.add(data);
905          that.prefetch.store(that.index.serialize());
906          deferred.resolve();
907        }
908      },
909      _initialize: function initialize() {
910        var that = this, deferred;
911        this.clear();
912        (this.initPromise = this._loadPrefetch()).done(addLocalToIndex);
913        return this.initPromise;
914
915        function addLocalToIndex() {
916          that.add(that.local);
917        }
918      },
919      initialize: function initialize(force) {
920        return !this.initPromise || force ? this._initialize() : this.initPromise;
921      },
922      add: function add(data) {
923        this.index.add(data);
924        return this;
925      },
926      get: function get(ids) {
927        ids = _.isArray(ids) ? ids : [].slice.call(arguments);
928        return this.index.get(ids);
929      },
930      search: function search(query, sync, async) {
931        var that = this, local;
932        local = this.sorter(this.index.search(query));
933        sync(this.remote ? local.slice() : local);
934        if (this.remote && local.length < this.sufficient) {
935          this.remote.get(query, processRemote);
936        } else if (this.remote) {
937          this.remote.cancelLastRequest();
938        }
939        return this;
940
941        function processRemote(remote) {
vendor: 52,863 bytes, lines 942-2563
942          var nonDuplicates = [];
943          _.each(remote, function (r) {
944            !_.some(local, function (l) {
945              return that.identify(r) === that.identify(l);
946            }) && nonDuplicates.push(r);
947          });
948          async && async(nonDuplicates);
949        }
950      },
951      all: function all() {
952        return this.index.all();
953      },
954      clear: function clear() {
955        this.index.reset();
956        return this;
957      },
958      clearPrefetchCache: function clearPrefetchCache() {
959        this.prefetch && this.prefetch.clear();
960        return this;
961      },
962      clearRemoteCache: function clearRemoteCache() {
963        Transport.resetCache();
964        return this;
965      },
966      ttAdapter: function ttAdapter() {
967        return this.__ttAdapter();
968      }
969    });
970    return Bloodhound;
971  }();
972  return Bloodhound;
973});
974
975(function (root, factory) {
976  if (typeof define === "function" && define.amd) {
977    define("typeahead.js", ["jquery"], function (a0) {
978      return factory(a0);
979    });
980  } else if (typeof exports === "object") {
981    module.exports = factory(require("jquery"));
982  } else {
983    factory(jQuery);
984  }
985})(this, function ($) {
986  var _ = function () {
987    "use strict";
988    return {
989      isMsie: function () {
990        return /(msie|trident)/i.test(navigator.userAgent) ? navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2] : false;
991      },
992      isBlankString: function (str) {
993        return !str || /^\s*$/.test(str);
994      },
995      escapeRegExChars: function (str) {
996        return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
997      },
998      isString: function (obj) {
999        return typeof obj === "string";
1000      },
1001      isNumber: function (obj) {
1002        return typeof obj === "number";
1003      },
1004      isArray: $.isArray,
1005      isFunction: $.isFunction,
1006      isObject: $.isPlainObject,
1007      isUndefined: function (obj) {
1008        return typeof obj === "undefined";
1009      },
1010      isElement: function (obj) {
1011        return !!(obj && obj.nodeType === 1);
1012      },
1013      isJQuery: function (obj) {
1014        return obj instanceof $;
1015      },
1016      toStr: function toStr(s) {
1017        return _.isUndefined(s) || s === null ? "" : s + "";
1018      },
1019      bind: $.proxy,
1020      each: function (collection, cb) {
1021        $.each(collection, reverseArgs);
1022
1023        function reverseArgs(index, value) {
1024          return cb(value, index);
1025        }
1026      },
1027      map: $.map,
1028      filter: $.grep,
1029      every: function (obj, test) {
1030        var result = true;
1031        if (!obj) {
1032          return result;
1033        }
1034        $.each(obj, function (key, val) {
1035          if (!(result = test.call(null, val, key, obj))) {
1036            return false;
1037          }
1038        });
1039        return !!result;
1040      },
1041      some: function (obj, test) {
1042        var result = false;
1043        if (!obj) {
1044          return result;
1045        }
1046        $.each(obj, function (key, val) {
1047          if (result = test.call(null, val, key, obj)) {
1048            return false;
1049          }
1050        });
1051        return !!result;
1052      },
1053      mixin: $.extend,
1054      identity: function (x) {
1055        return x;
1056      },
1057      clone: function (obj) {
1058        return $.extend(true, {}, obj);
1059      },
1060      getIdGenerator: function () {
1061        var counter = 0;
1062        return function () {
1063          return counter++;
1064        };
1065      },
1066      templatify: function templatify(obj) {
1067        return $.isFunction(obj) ? obj : template;
1068
1069        function template() {
1070          return String(obj);
1071        }
1072      },
1073      defer: function (fn) {
1074        setTimeout(fn, 0);
1075      },
1076      debounce: function (func, wait, immediate) {
1077        var timeout, result;
1078        return function () {
1079          var context = this, args = arguments, later, callNow;
1080          later = function () {
1081            timeout = null;
1082            if (!immediate) {
1083              result = func.apply(context, args);
1084            }
1085          };
1086          callNow = immediate && !timeout;
1087          clearTimeout(timeout);
1088          timeout = setTimeout(later, wait);
1089          if (callNow) {
1090            result = func.apply(context, args);
1091          }
1092          return result;
1093        };
1094      },
1095      throttle: function (func, wait) {
1096        var context, args, timeout, result, previous, later;
1097        previous = 0;
1098        later = function () {
1099          previous = new Date();
1100          timeout = null;
1101          result = func.apply(context, args);
1102        };
1103        return function () {
1104          var now = new Date(), remaining = wait - (now - previous);
1105          context = this;
1106          args = arguments;
1107          if (remaining <= 0) {
1108            clearTimeout(timeout);
1109            timeout = null;
1110            previous = now;
1111            result = func.apply(context, args);
1112          } else if (!timeout) {
1113            timeout = setTimeout(later, remaining);
1114          }
1115          return result;
1116        };
1117      },
1118      stringify: function (val) {
1119        return _.isString(val) ? val : JSON.stringify(val);
1120      },
1121      noop: function () {
1122      }
1123    };
1124  }();
1125  var WWW = function () {
1126    "use strict";
1127    var defaultClassNames = {
1128      wrapper: "twitter-typeahead",
1129      input: "tt-input",
1130      hint: "tt-hint",
1131      menu: "tt-menu",
1132      dataset: "tt-dataset",
1133      suggestion: "tt-suggestion",
1134      selectable: "tt-selectable",
1135      empty: "tt-empty",
1136      open: "tt-open",
1137      cursor: "tt-cursor",
1138      highlight: "tt-highlight"
1139    };
1140    return build;
1141
1142    function build(o) {
1143      var www, classes;
1144      classes = _.mixin({}, defaultClassNames, o);
1145      www = {
1146        css: buildCss(),
1147        classes: classes,
1148        html: buildHtml(classes),
1149        selectors: buildSelectors(classes)
1150      };
1151      return {
1152        css: www.css,
1153        html: www.html,
1154        classes: www.classes,
1155        selectors: www.selectors,
1156        mixin: function (o) {
1157          _.mixin(o, www);
1158        }
1159      };
1160    }
1161
1162    function buildHtml(c) {
1163      return {
1164        wrapper: '<span class="' + c.wrapper + '"></span>',
1165        menu: '<div class="' + c.menu + '"></div>'
1166      };
1167    }
1168
1169    function buildSelectors(classes) {
1170      var selectors = {};
1171      _.each(classes, function (v, k) {
1172        selectors[k] = "." + v;
1173      });
1174      return selectors;
1175    }
1176
1177    function buildCss() {
1178      var css = {
1179        wrapper: {
1180          position: "relative",
1181          display: "inline-block"
1182        },
1183        hint: {
1184          position: "absolute",
1185          top: "0",
1186          left: "0",
1187          borderColor: "transparent",
1188          boxShadow: "none",
1189          opacity: "1"
1190        },
1191        input: {
1192          position: "relative",
1193          verticalAlign: "top",
1194          backgroundColor: "transparent"
1195        },
1196        inputWithNoHint: {
1197          position: "relative",
1198          verticalAlign: "top"
1199        },
1200        menu: {
1201          position: "absolute",
1202          top: "100%",
1203          left: "0",
1204          zIndex: "100",
1205          display: "none"
1206        },
1207        ltr: {
1208          left: "0",
1209          right: "auto"
1210        },
1211        rtl: {
1212          left: "auto",
1213          right: " 0"
1214        }
1215      };
1216      if (_.isMsie()) {
1217        _.mixin(css.input, {
1218          backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"
1219        });
1220      }
1221      return css;
1222    }
1223  }();
1224  var EventBus = function () {
1225    "use strict";
1226    var namespace, deprecationMap;
1227    namespace = "typeahead:";
1228    deprecationMap = {
1229      render: "rendered",
1230      cursorchange: "cursorchanged",
1231      select: "selected",
1232      autocomplete: "autocompleted"
1233    };
1234
1235    function EventBus(o) {
1236      if (!o || !o.el) {
1237        $.error("EventBus initialized without el");
1238      }
1239      this.$el = $(o.el);
1240    }
1241
1242    _.mixin(EventBus.prototype, {
1243      _trigger: function (type, args) {
1244        var $e;
1245        $e = $.Event(namespace + type);
1246        (args = args || []).unshift($e);
1247        this.$el.trigger.apply(this.$el, args);
1248        return $e;
1249      },
1250      before: function (type) {
1251        var args, $e;
1252        args = [].slice.call(arguments, 1);
1253        $e = this._trigger("before" + type, args);
1254        return $e.isDefaultPrevented();
1255      },
1256      trigger: function (type) {
1257        var deprecatedType;
1258        this._trigger(type, [].slice.call(arguments, 1));
1259        if (deprecatedType = deprecationMap[type]) {
1260          this._trigger(deprecatedType, [].slice.call(arguments, 1));
1261        }
1262      }
1263    });
1264    return EventBus;
1265  }();
1266  var EventEmitter = function () {
1267    "use strict";
1268    var splitter = /\s+/, nextTick = getNextTick();
1269    return {
1270      onSync: onSync,
1271      onAsync: onAsync,
1272      off: off,
1273      trigger: trigger
1274    };
1275
1276    function on(method, types, cb, context) {
1277      var type;
1278      if (!cb) {
1279        return this;
1280      }
1281      types = types.split(splitter);
1282      cb = context ? bindContext(cb, context) : cb;
1283      this._callbacks = this._callbacks || {};
1284      while (type = types.shift()) {
1285        this._callbacks[type] = this._callbacks[type] || {
1286          sync: [],
1287          async: []
1288        };
1289        this._callbacks[type][method].push(cb);
1290      }
1291      return this;
1292    }
1293
1294    function onAsync(types, cb, context) {
1295      return on.call(this, "async", types, cb, context);
1296    }
1297
1298    function onSync(types, cb, context) {
1299      return on.call(this, "sync", types, cb, context);
1300    }
1301
1302    function off(types) {
1303      var type;
1304      if (!this._callbacks) {
1305        return this;
1306      }
1307      types = types.split(splitter);
1308      while (type = types.shift()) {
1309        delete this._callbacks[type];
1310      }
1311      return this;
1312    }
1313
1314    function trigger(types) {
1315      var type, callbacks, args, syncFlush, asyncFlush;
1316      if (!this._callbacks) {
1317        return this;
1318      }
1319      types = types.split(splitter);
1320      args = [].slice.call(arguments, 1);
1321      while ((type = types.shift()) && (callbacks = this._callbacks[type])) {
1322        syncFlush = getFlush(callbacks.sync, this, [type].concat(args));
1323        asyncFlush = getFlush(callbacks.async, this, [type].concat(args));
1324        syncFlush() && nextTick(asyncFlush);
1325      }
1326      return this;
1327    }
1328
1329    function getFlush(callbacks, context, args) {
1330      return flush;
1331
1332      function flush() {
1333        var cancelled;
1334        for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) {
1335          cancelled = callbacks[i].apply(context, args) === false;
1336        }
1337        return !cancelled;
1338      }
1339    }
1340
1341    function getNextTick() {
1342      var nextTickFn;
1343      if (window.setImmediate) {
1344        nextTickFn = function nextTickSetImmediate(fn) {
1345          setImmediate(function () {
1346            fn();
1347          });
1348        };
1349      } else {
1350        nextTickFn = function nextTickSetTimeout(fn) {
1351          setTimeout(function () {
1352            fn();
1353          }, 0);
1354        };
1355      }
1356      return nextTickFn;
1357    }
1358
1359    function bindContext(fn, context) {
1360      return fn.bind ? fn.bind(context) : function () {
1361        fn.apply(context, [].slice.call(arguments, 0));
1362      };
1363    }
1364  }();
1365  var highlight = function (doc) {
1366    "use strict";
1367    var defaults = {
1368      node: null,
1369      pattern: null,
1370      tagName: "strong",
1371      className: null,
1372      wordsOnly: false,
1373      caseSensitive: false
1374    };
1375    return function hightlight(o) {
1376      var regex;
1377      o = _.mixin({}, defaults, o);
1378      if (!o.node || !o.pattern) {
1379        return;
1380      }
1381      o.pattern = _.isArray(o.pattern) ? o.pattern : [o.pattern];
1382      regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly);
1383      traverse(o.node, hightlightTextNode);
1384
1385      function hightlightTextNode(textNode) {
1386        var match, patternNode, wrapperNode;
1387        if (match = regex.exec(textNode.data)) {
1388          wrapperNode = doc.createElement(o.tagName);
1389          o.className && (wrapperNode.className = o.className);
1390          patternNode = textNode.splitText(match.index);
1391          patternNode.splitText(match[0].length);
1392          wrapperNode.appendChild(patternNode.cloneNode(true));
1393          textNode.parentNode.replaceChild(wrapperNode, patternNode);
1394        }
1395        return !!match;
1396      }
1397
1398      function traverse(el, hightlightTextNode) {
1399        var childNode, TEXT_NODE_TYPE = 3;
1400        for (var i = 0; i < el.childNodes.length; i++) {
1401          childNode = el.childNodes[i];
1402          if (childNode.nodeType === TEXT_NODE_TYPE) {
1403            i += hightlightTextNode(childNode) ? 1 : 0;
1404          } else {
1405            traverse(childNode, hightlightTextNode);
1406          }
1407        }
1408      }
1409    };
1410
1411    function getRegex(patterns, caseSensitive, wordsOnly) {
1412      var escapedPatterns = [], regexStr;
1413      for (var i = 0, len = patterns.length; i < len; i++) {
1414        escapedPatterns.push(_.escapeRegExChars(patterns[i]));
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
1433    function Input(o, www) {
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.query = this.$input.val();
1442      this.queryWhenFocused = this.hasFocus() ? this.query : null;
1443      this.$overflowHelper = buildOverflowHelper(this.$input);
1444      this._checkLanguageDirection();
1445      if (this.$hint.length === 0) {
1446        this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop;
1447      }
1448    }
1449
1450    Input.normalizeQuery = function (str) {
1451      return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " ");
1452    };
1453    _.mixin(Input.prototype, EventEmitter, {
1454      _onBlur: function onBlur() {
1455        this.resetInputValue();
1456        this.trigger("blurred");
1457      },
1458      _onFocus: function onFocus() {
1459        this.queryWhenFocused = this.query;
1460        this.trigger("focused");
1461      },
1462      _onKeydown: function onKeydown($e) {
1463        var keyName = specialKeyCodeMap[$e.which || $e.keyCode];
1464        this._managePreventDefault(keyName, $e);
1465        if (keyName && this._shouldTrigger(keyName, $e)) {
1466          this.trigger(keyName + "Keyed", $e);
1467        }
1468      },
1469      _onInput: function onInput() {
1470        this._setQuery(this.getInputValue());
1471        this.clearHintIfInvalid();
1472        this._checkLanguageDirection();
1473      },
1474      _managePreventDefault: function managePreventDefault(keyName, $e) {
1475        var preventDefault;
1476        switch (keyName) {
1477          case "up":
1478          case "down":
1479            preventDefault = !withModifier($e);
1480            break;
1481
1482          default:
1483            preventDefault = false;
1484        }
1485        preventDefault && $e.preventDefault();
1486      },
1487      _shouldTrigger: function shouldTrigger(keyName, $e) {
1488        var trigger;
1489        switch (keyName) {
1490          case "tab":
1491            trigger = !withModifier($e);
1492            break;
1493
1494          default:
1495            trigger = true;
1496        }
1497        return trigger;
1498      },
1499      _checkLanguageDirection: function checkLanguageDirection() {
1500        var dir = (this.$input.css("direction") || "ltr").toLowerCase();
1501        if (this.dir !== dir) {
1502          this.dir = dir;
1503          this.$hint.attr("dir", dir);
1504          this.trigger("langDirChanged", dir);
1505        }
1506      },
1507      _setQuery: function setQuery(val, silent) {
1508        var areEquivalent, hasDifferentWhitespace;
1509        areEquivalent = areQueriesEquivalent(val, this.query);
1510        hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false;
1511        this.query = val;
1512        if (!silent && !areEquivalent) {
1513          this.trigger("queryChanged", this.query);
1514        } else if (!silent && hasDifferentWhitespace) {
1515          this.trigger("whitespaceChanged", this.query);
1516        }
1517      },
1518      bind: function () {
1519        var that = this, onBlur, onFocus, onKeydown, onInput;
1520        onBlur = _.bind(this._onBlur, this);
1521        onFocus = _.bind(this._onFocus, this);
1522        onKeydown = _.bind(this._onKeydown, this);
1523        onInput = _.bind(this._onInput, this);
1524        this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown);
1525        if (!_.isMsie() || _.isMsie() > 9) {
1526          this.$input.on("input.tt", onInput);
1527        } else {
1528          this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function ($e) {
1529            if (specialKeyCodeMap[$e.which || $e.keyCode]) {
1530              return;
1531            }
1532            _.defer(_.bind(that._onInput, that, $e));
1533          });
1534        }
1535        return this;
1536      },
1537      focus: function focus() {
1538        this.$input.focus();
1539      },
1540      blur: function blur() {
1541        this.$input.blur();
1542      },
1543      getLangDir: function getLangDir() {
1544        return this.dir;
1545      },
1546      getQuery: function getQuery() {
1547        return this.query || "";
1548      },
1549      setQuery: function setQuery(val, silent) {
1550        this.setInputValue(val);
1551        this._setQuery(val, silent);
1552      },
1553      hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() {
1554        return this.query !== this.queryWhenFocused;
1555      },
1556      getInputValue: function getInputValue() {
1557        return this.$input.val();
1558      },
1559      setInputValue: function setInputValue(value) {
1560        this.$input.val(value);
1561        this.clearHintIfInvalid();
1562        this._checkLanguageDirection();
1563      },
1564      resetInputValue: function resetInputValue() {
1565        this.setInputValue(this.query);
1566      },
1567      getHint: function getHint() {
1568        return this.$hint.val();
1569      },
1570      setHint: function setHint(value) {
1571        this.$hint.val(value);
1572      },
1573      clearHint: function clearHint() {
1574        this.setHint("");
1575      },
1576      clearHintIfInvalid: function clearHintIfInvalid() {
1577        var val, hint, valIsPrefixOfHint, isValid;
1578        val = this.getInputValue();
1579        hint = this.getHint();
1580        valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0;
1581        isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow();
1582        !isValid && this.clearHint();
1583      },
1584      hasFocus: function hasFocus() {
1585        return this.$input.is(":focus");
1586      },
1587      hasOverflow: function hasOverflow() {
1588        var constraint = this.$input.width() - 2;
1589        this.$overflowHelper.text(this.getInputValue());
1590        return this.$overflowHelper.width() >= constraint;
1591      },
1592      isCursorAtEnd: function () {
1593        var valueLength, selectionStart, range;
1594        valueLength = this.$input.val().length;
1595        selectionStart = this.$input[0].selectionStart;
1596        if (_.isNumber(selectionStart)) {
1597          return selectionStart === valueLength;
1598        } else if (document.selection) {
1599          range = document.selection.createRange();
1600          range.moveStart("character", -valueLength);
1601          return valueLength === range.text.length;
1602        }
1603        return true;
1604      },
1605      destroy: function destroy() {
1606        this.$hint.off(".tt");
1607        this.$input.off(".tt");
1608        this.$overflowHelper.remove();
1609        this.$hint = this.$input = this.$overflowHelper = $("<div>");
1610      }
1611    });
1612    return Input;
1613
1614    function buildOverflowHelper($input) {
1615      return $('<pre aria-hidden="true"></pre>').css({
1616        position: "absolute",
1617        visibility: "hidden",
1618        whiteSpace: "pre",
1619        fontFamily: $input.css("font-family"),
1620        fontSize: $input.css("font-size"),
1621        fontStyle: $input.css("font-style"),
1622        fontVariant: $input.css("font-variant"),
1623        fontWeight: $input.css("font-weight"),
1624        wordSpacing: $input.css("word-spacing"),
1625        letterSpacing: $input.css("letter-spacing"),
1626        textIndent: $input.css("text-indent"),
1627        textRendering: $input.css("text-rendering"),
1628        textTransform: $input.css("text-transform")
1629      }).insertAfter($input);
1630    }
1631
1632    function areQueriesEquivalent(a, b) {
1633      return Input.normalizeQuery(a) === Input.normalizeQuery(b);
1634    }
1635
1636    function withModifier($e) {
1637      return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey;
1638    }
1639  }();
1640  var Dataset = function () {
1641    "use strict";
1642    var keys, nameGenerator;
1643    keys = {
1644      val: "tt-selectable-display",
1645      obj: "tt-selectable-object"
1646    };
1647    nameGenerator = _.getIdGenerator();
1648
1649    function Dataset(o, www) {
1650      o = o || {};
1651      o.templates = o.templates || {};
1652      o.templates.notFound = o.templates.notFound || o.templates.empty;
1653      if (!o.source) {
1654        $.error("missing source");
1655      }
1656      if (!o.node) {
1657        $.error("missing node");
1658      }
1659      if (o.name && !isValidName(o.name)) {
1660        $.error("invalid dataset name: " + o.name);
1661      }
1662      www.mixin(this);
1663      this.highlight = !!o.highlight;
1664      this.name = o.name || nameGenerator();
1665      this.limit = o.limit || 5;
1666      this.displayFn = getDisplayFn(o.display || o.displayKey);
1667      this.templates = getTemplates(o.templates, this.displayFn);
1668      this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source;
1669      this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async;
1670      this._resetLastSuggestion();
1671      this.$el = $(o.node).addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name);
1672    }
1673
1674    Dataset.extractData = function extractData(el) {
1675      var $el = $(el);
1676      if ($el.data(keys.obj)) {
1677        return {
1678          val: $el.data(keys.val) || "",
1679          obj: $el.data(keys.obj) || null
1680        };
1681      }
1682      return null;
1683    };
1684    _.mixin(Dataset.prototype, EventEmitter, {
1685      _overwrite: function overwrite(query, suggestions) {
1686        suggestions = suggestions || [];
1687        if (suggestions.length) {
1688          this._renderSuggestions(query, suggestions);
1689        } else if (this.async && this.templates.pending) {
1690          this._renderPending(query);
1691        } else if (!this.async && this.templates.notFound) {
1692          this._renderNotFound(query);
1693        } else {
1694          this._empty();
1695        }
1696        this.trigger("rendered", this.name, suggestions, false);
1697      },
1698      _append: function append(query, suggestions) {
1699        suggestions = suggestions || [];
1700        if (suggestions.length && this.$lastSuggestion.length) {
1701          this._appendSuggestions(query, suggestions);
1702        } else if (suggestions.length) {
1703          this._renderSuggestions(query, suggestions);
1704        } else if (!this.$lastSuggestion.length && this.templates.notFound) {
1705          this._renderNotFound(query);
1706        }
1707        this.trigger("rendered", this.name, suggestions, true);
1708      },
1709      _renderSuggestions: function renderSuggestions(query, suggestions) {
1710        var $fragment;
1711        $fragment = this._getSuggestionsFragment(query, suggestions);
1712        this.$lastSuggestion = $fragment.children().last();
1713        this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions));
1714      },
1715      _appendSuggestions: function appendSuggestions(query, suggestions) {
1716        var $fragment, $lastSuggestion;
1717        $fragment = this._getSuggestionsFragment(query, suggestions);
1718        $lastSuggestion = $fragment.children().last();
1719        this.$lastSuggestion.after($fragment);
1720        this.$lastSuggestion = $lastSuggestion;
1721      },
1722      _renderPending: function renderPending(query) {
1723        var template = this.templates.pending;
1724        this._resetLastSuggestion();
1725        template && this.$el.html(template({
1726          query: query,
1727          dataset: this.name
1728        }));
1729      },
1730      _renderNotFound: function renderNotFound(query) {
1731        var template = this.templates.notFound;
1732        this._resetLastSuggestion();
1733        template && this.$el.html(template({
1734          query: query,
1735          dataset: this.name
1736        }));
1737      },
1738      _empty: function empty() {
1739        this.$el.empty();
1740        this._resetLastSuggestion();
1741      },
1742      _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) {
1743        var that = this, fragment;
1744        fragment = document.createDocumentFragment();
1745        _.each(suggestions, function getSuggestionNode(suggestion) {
1746          var $el, context;
1747          context = that._injectQuery(query, suggestion);
1748          $el = $(that.templates.suggestion(context)).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable);
1749          fragment.appendChild($el[0]);
1750        });
1751        this.highlight && highlight({
1752          className: this.classes.highlight,
1753          node: fragment,
1754          pattern: query
1755        });
1756        return $(fragment);
1757      },
1758      _getFooter: function getFooter(query, suggestions) {
1759        return this.templates.footer ? this.templates.footer({
1760          query: query,
1761          suggestions: suggestions,
1762          dataset: this.name
1763        }) : null;
1764      },
1765      _getHeader: function getHeader(query, suggestions) {
1766        return this.templates.header ? this.templates.header({
1767          query: query,
1768          suggestions: suggestions,
1769          dataset: this.name
1770        }) : null;
1771      },
1772      _resetLastSuggestion: function resetLastSuggestion() {
1773        this.$lastSuggestion = $();
1774      },
1775      _injectQuery: function injectQuery(query, obj) {
1776        return _.isObject(obj) ? _.mixin({
1777          _query: query
1778        }, obj) : obj;
1779      },
1780      update: function update(query) {
1781        var that = this, canceled = false, syncCalled = false, rendered = 0;
1782        this.cancel();
1783        this.cancel = function cancel() {
1784          canceled = true;
1785          that.cancel = $.noop;
1786          that.async && that.trigger("asyncCanceled", query);
1787        };
1788        this.source(query, sync, async);
1789        !syncCalled && sync([]);
1790
1791        function sync(suggestions) {
1792          if (syncCalled) {
1793            return;
1794          }
1795          syncCalled = true;
1796          suggestions = (suggestions || []).slice(0, that.limit);
1797          rendered = suggestions.length;
1798          that._overwrite(query, suggestions);
1799          if (rendered < that.limit && that.async) {
1800            that.trigger("asyncRequested", query);
1801          }
1802        }
1803
1804        function async(suggestions) {
1805          suggestions = suggestions || [];
1806          if (!canceled && rendered < that.limit) {
1807            that.cancel = $.noop;
1808            rendered += suggestions.length;
1809            that._append(query, suggestions.slice(0, that.limit - rendered));
1810            that.async && that.trigger("asyncReceived", query);
1811          }
1812        }
1813      },
1814      cancel: $.noop,
1815      clear: function clear() {
1816        this._empty();
1817        this.cancel();
1818        this.trigger("cleared");
1819      },
1820      isEmpty: function isEmpty() {
1821        return this.$el.is(":empty");
1822      },
1823      destroy: function destroy() {
1824        this.$el = $("<div>");
1825      }
1826    });
1827    return Dataset;
1828
1829    function getDisplayFn(display) {
1830      display = display || _.stringify;
1831      return _.isFunction(display) ? display : displayFn;
1832
1833      function displayFn(obj) {
1834        return obj[display];
1835      }
1836    }
1837
1838    function getTemplates(templates, displayFn) {
1839      return {
1840        notFound: templates.notFound && _.templatify(templates.notFound),
1841        pending: templates.pending && _.templatify(templates.pending),
1842        header: templates.header && _.templatify(templates.header),
1843        footer: templates.footer && _.templatify(templates.footer),
1844        suggestion: templates.suggestion || suggestionTemplate
1845      };
1846
1847      function suggestionTemplate(context) {
1848        return $("<div>").text(displayFn(context));
1849      }
1850    }
1851
1852    function isValidName(str) {
1853      return /^[_a-zA-Z0-9-]+$/.test(str);
1854    }
1855  }();
1856  var Menu = function () {
1857    "use strict";
1858
1859    function Menu(o, www) {
1860      var that = this;
1861      o = o || {};
1862      if (!o.node) {
1863        $.error("node is required");
1864      }
1865      www.mixin(this);
1866      this.$node = $(o.node);
1867      this.query = null;
1868      this.datasets = _.map(o.datasets, initializeDataset);
1869
1870      function initializeDataset(oDataset) {
1871        var node = that.$node.find(oDataset.node).first();
1872        oDataset.node = node.length ? node : $("<div>").appendTo(that.$node);
1873        return new Dataset(oDataset, www);
1874      }
1875    }
1876
1877    _.mixin(Menu.prototype, EventEmitter, {
1878      _onSelectableClick: function onSelectableClick($e) {
1879        this.trigger("selectableClicked", $($e.currentTarget));
1880      },
1881      _onRendered: function onRendered(type, dataset, suggestions, async) {
1882        this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
1883        this.trigger("datasetRendered", dataset, suggestions, async);
1884      },
1885      _onCleared: function onCleared() {
1886        this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty());
1887        this.trigger("datasetCleared");
1888      },
1889      _propagate: function propagate() {
1890        this.trigger.apply(this, arguments);
1891      },
1892      _allDatasetsEmpty: function allDatasetsEmpty() {
1893        return _.every(this.datasets, isDatasetEmpty);
1894
1895        function isDatasetEmpty(dataset) {
1896          return dataset.isEmpty();
1897        }
1898      },
1899      _getSelectables: function getSelectables() {
1900        return this.$node.find(this.selectors.selectable);
1901      },
1902      _removeCursor: function _removeCursor() {
1903        var $selectable = this.getActiveSelectable();
1904        $selectable && $selectable.removeClass(this.classes.cursor);
1905      },
1906      _ensureVisible: function ensureVisible($el) {
1907        var elTop, elBottom, nodeScrollTop, nodeHeight;
1908        elTop = $el.position().top;
1909        elBottom = elTop + $el.outerHeight(true);
1910        nodeScrollTop = this.$node.scrollTop();
1911        nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10);
1912        if (elTop < 0) {
1913          this.$node.scrollTop(nodeScrollTop + elTop);
1914        } else if (nodeHeight < elBottom) {
1915          this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight));
1916        }
1917      },
1918      bind: function () {
1919        var that = this, onSelectableClick;
1920        onSelectableClick = _.bind(this._onSelectableClick, this);
1921        this.$node.on("click.tt", this.selectors.selectable, onSelectableClick);
1922        _.each(this.datasets, function (dataset) {
1923          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);
1924        });
1925        return this;
1926      },
1927      isOpen: function isOpen() {
1928        return this.$node.hasClass(this.classes.open);
1929      },
1930      open: function open() {
1931        this.$node.addClass(this.classes.open);
1932      },
1933      close: function close() {
1934        this.$node.removeClass(this.classes.open);
1935        this._removeCursor();
1936      },
1937      setLanguageDirection: function setLanguageDirection(dir) {
1938        this.$node.attr("dir", dir);
1939      },
1940      selectableRelativeToCursor: function selectableRelativeToCursor(delta) {
1941        var $selectables, $oldCursor, oldIndex, newIndex;
1942        $oldCursor = this.getActiveSelectable();
1943        $selectables = this._getSelectables();
1944        oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1;
1945        newIndex = oldIndex + delta;
1946        newIndex = (newIndex + 1) % ($selectables.length + 1) - 1;
1947        newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex;
1948        return newIndex === -1 ? null : $selectables.eq(newIndex);
1949      },
1950      setCursor: function setCursor($selectable) {
1951        this._removeCursor();
1952        if ($selectable = $selectable && $selectable.first()) {
1953          $selectable.addClass(this.classes.cursor);
1954          this._ensureVisible($selectable);
1955        }
1956      },
1957      getSelectableData: function getSelectableData($el) {
1958        return $el && $el.length ? Dataset.extractData($el) : null;
1959      },
1960      getActiveSelectable: function getActiveSelectable() {
1961        var $selectable = this._getSelectables().filter(this.selectors.cursor).first();
1962        return $selectable.length ? $selectable : null;
1963      },
1964      getTopSelectable: function getTopSelectable() {
1965        var $selectable = this._getSelectables().first();
1966        return $selectable.length ? $selectable : null;
1967      },
1968      update: function update(query) {
1969        var isValidUpdate = query !== this.query;
1970        if (isValidUpdate) {
1971          this.query = query;
1972          _.each(this.datasets, updateDataset);
1973        }
1974        return isValidUpdate;
1975
1976        function updateDataset(dataset) {
1977          dataset.update(query);
1978        }
1979      },
1980      empty: function empty() {
1981        _.each(this.datasets, clearDataset);
1982        this.query = null;
1983        this.$node.addClass(this.classes.empty);
1984
1985        function clearDataset(dataset) {
1986          dataset.clear();
1987        }
1988      },
1989      destroy: function destroy() {
1990        this.$node.off(".tt");
1991        this.$node = $("<div>");
1992        _.each(this.datasets, destroyDataset);
1993
1994        function destroyDataset(dataset) {
1995          dataset.destroy();
1996        }
1997      }
1998    });
1999    return Menu;
2000  }();
2001  var DefaultMenu = function () {
2002    "use strict";
2003    var s = Menu.prototype;
2004
2005    function DefaultMenu() {
2006      Menu.apply(this, [].slice.call(arguments, 0));
2007    }
2008
2009    _.mixin(DefaultMenu.prototype, Menu.prototype, {
2010      open: function open() {
2011        !this._allDatasetsEmpty() && this._show();
2012        return s.open.apply(this, [].slice.call(arguments, 0));
2013      },
2014      close: function close() {
2015        this._hide();
2016        return s.close.apply(this, [].slice.call(arguments, 0));
2017      },
2018      _onRendered: function onRendered() {
2019        if (this._allDatasetsEmpty()) {
2020          this._hide();
2021        } else {
2022          this.isOpen() && this._show();
2023        }
2024        return s._onRendered.apply(this, [].slice.call(arguments, 0));
2025      },
2026      _onCleared: function onCleared() {
2027        if (this._allDatasetsEmpty()) {
2028          this._hide();
2029        } else {
2030          this.isOpen() && this._show();
2031        }
2032        return s._onCleared.apply(this, [].slice.call(arguments, 0));
2033      },
2034      setLanguageDirection: function setLanguageDirection(dir) {
2035        this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl);
2036        return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0));
2037      },
2038      _hide: function hide() {
2039        this.$node.hide();
2040      },
2041      _show: function show() {
2042        this.$node.css("display", "block");
2043      }
2044    });
2045    return DefaultMenu;
2046  }();
2047  var Typeahead = function () {
2048    "use strict";
2049
2050    function Typeahead(o, www) {
2051      var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed,
2052        onQueryChanged, onWhitespaceChanged;
2053      o = o || {};
2054      if (!o.input) {
2055        $.error("missing input");
2056      }
2057      if (!o.menu) {
2058        $.error("missing menu");
2059      }
2060      if (!o.eventBus) {
2061        $.error("missing event bus");
2062      }
2063      www.mixin(this);
2064      this.eventBus = o.eventBus;
2065      this.minLength = _.isNumber(o.minLength) ? o.minLength : 1;
2066      this.input = o.input;
2067      this.menu = o.menu;
2068      this.enabled = true;
2069      this.active = false;
2070      this.input.hasFocus() && this.activate();
2071      this.dir = this.input.getLangDir();
2072      this._hacks();
2073      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);
2074      onFocused = c(this, "activate", "open", "_onFocused");
2075      onBlurred = c(this, "deactivate", "_onBlurred");
2076      onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed");
2077      onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed");
2078      onEscKeyed = c(this, "isActive", "_onEscKeyed");
2079      onUpKeyed = c(this, "isActive", "open", "_onUpKeyed");
2080      onDownKeyed = c(this, "isActive", "open", "_onDownKeyed");
2081      onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed");
2082      onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed");
2083      onQueryChanged = c(this, "_openIfActive", "_onQueryChanged");
2084      onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged");
2085      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);
2086    }
2087
2088    _.mixin(Typeahead.prototype, {
2089      _hacks: function hacks() {
2090        var $input, $menu;
2091        $input = this.input.$input || $("<div>");
2092        $menu = this.menu.$node || $("<div>");
2093        $input.on("blur.tt", function ($e) {
2094          var active, isActive, hasActive;
2095          active = document.activeElement;
2096          isActive = $menu.is(active);
2097          hasActive = $menu.has(active).length > 0;
2098          if (_.isMsie() && (isActive || hasActive)) {
2099            $e.preventDefault();
2100            $e.stopImmediatePropagation();
2101            _.defer(function () {
2102              $input.focus();
2103            });
2104          }
2105        });
2106        $menu.on("mousedown.tt", function ($e) {
2107          $e.preventDefault();
2108        });
2109      },
2110      _onSelectableClicked: function onSelectableClicked(type, $el) {
2111        this.select($el);
2112      },
2113      _onDatasetCleared: function onDatasetCleared() {
2114        this._updateHint();
2115      },
2116      _onDatasetRendered: function onDatasetRendered(type, dataset, suggestions, async) {
2117        this._updateHint();
2118        this.eventBus.trigger("render", suggestions, async, dataset);
2119      },
2120      _onAsyncRequested: function onAsyncRequested(type, dataset, query) {
2121        this.eventBus.trigger("asyncrequest", query, dataset);
2122      },
2123      _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) {
2124        this.eventBus.trigger("asynccancel", query, dataset);
2125      },
2126      _onAsyncReceived: function onAsyncReceived(type, dataset, query) {
2127        this.eventBus.trigger("asyncreceive", query, dataset);
2128      },
2129      _onFocused: function onFocused() {
2130        this._minLengthMet() && this.menu.update(this.input.getQuery());
2131      },
2132      _onBlurred: function onBlurred() {
2133        if (this.input.hasQueryChangedSinceLastFocus()) {
2134          this.eventBus.trigger("change", this.input.getQuery());
2135        }
2136      },
2137      _onEnterKeyed: function onEnterKeyed(type, $e) {
2138        var $selectable;
2139        if ($selectable = this.menu.getActiveSelectable()) {
2140          this.select($selectable) && $e.preventDefault();
2141        }
2142      },
2143      _onTabKeyed: function onTabKeyed(type, $e) {
2144        var $selectable;
2145        if ($selectable = this.menu.getActiveSelectable()) {
2146          this.select($selectable) && $e.preventDefault();
2147        } else if ($selectable = this.menu.getTopSelectable()) {
2148          this.autocomplete($selectable) && $e.preventDefault();
2149        }
2150      },
2151      _onEscKeyed: function onEscKeyed() {
2152        this.close();
2153      },
2154      _onUpKeyed: function onUpKeyed() {
2155        this.moveCursor(-1);
2156      },
2157      _onDownKeyed: function onDownKeyed() {
2158        this.moveCursor(+1);
2159      },
2160      _onLeftKeyed: function onLeftKeyed() {
2161        if (this.dir === "rtl" && this.input.isCursorAtEnd()) {
2162          this.autocomplete(this.menu.getTopSelectable());
2163        }
2164      },
2165      _onRightKeyed: function onRightKeyed() {
2166        if (this.dir === "ltr" && this.input.isCursorAtEnd()) {
2167          this.autocomplete(this.menu.getTopSelectable());
2168        }
2169      },
2170      _onQueryChanged: function onQueryChanged(e, query) {
2171        this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty();
2172      },
2173      _onWhitespaceChanged: function onWhitespaceChanged() {
2174        this._updateHint();
2175      },
2176      _onLangDirChanged: function onLangDirChanged(e, dir) {
2177        if (this.dir !== dir) {
2178          this.dir = dir;
2179          this.menu.setLanguageDirection(dir);
2180        }
2181      },
2182      _openIfActive: function openIfActive() {
2183        this.isActive() && this.open();
2184      },
2185      _minLengthMet: function minLengthMet(query) {
2186        query = _.isString(query) ? query : this.input.getQuery() || "";
2187        return query.length >= this.minLength;
2188      },
2189      _updateHint: function updateHint() {
2190        var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match;
2191        $selectable = this.menu.getTopSelectable();
2192        data = this.menu.getSelectableData($selectable);
2193        val = this.input.getInputValue();
2194        if (data && !_.isBlankString(val) && !this.input.hasOverflow()) {
2195          query = Input.normalizeQuery(val);
2196          escapedQuery = _.escapeRegExChars(query);
2197          frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i");
2198          match = frontMatchRegEx.exec(data.val);
2199          match && this.input.setHint(val + match[1]);
2200        } else {
2201          this.input.clearHint();
2202        }
2203      },
2204      isEnabled: function isEnabled() {
2205        return this.enabled;
2206      },
2207      enable: function enable() {
2208        this.enabled = true;
2209      },
2210      disable: function disable() {
2211        this.enabled = false;
2212      },
2213      isActive: function isActive() {
2214        return this.active;
2215      },
2216      activate: function activate() {
2217        if (this.isActive()) {
2218          return true;
2219        } else if (!this.isEnabled() || this.eventBus.before("active")) {
2220          return false;
2221        } else {
2222          this.active = true;
2223          this.eventBus.trigger("active");
2224          return true;
2225        }
2226      },
2227      deactivate: function deactivate() {
2228        if (!this.isActive()) {
2229          return true;
2230        } else if (this.eventBus.before("idle")) {
2231          return false;
2232        } else {
2233          this.active = false;
2234          this.close();
2235          this.eventBus.trigger("idle");
2236          return true;
2237        }
2238      },
2239      isOpen: function isOpen() {
2240        return this.menu.isOpen();
2241      },
2242      open: function open() {
2243        if (!this.isOpen() && !this.eventBus.before("open")) {
2244          this.menu.open();
2245          this._updateHint();
2246          this.eventBus.trigger("open");
2247        }
2248        return this.isOpen();
2249      },
2250      close: function close() {
2251        if (this.isOpen() && !this.eventBus.before("close")) {
2252          this.menu.close();
2253          this.input.clearHint();
2254          this.input.resetInputValue();
2255          this.eventBus.trigger("close");
2256        }
2257        return !this.isOpen();
2258      },
2259      setVal: function setVal(val) {
2260        this.input.setQuery(_.toStr(val));
2261      },
2262      getVal: function getVal() {
2263        return this.input.getQuery();
2264      },
2265      select: function select($selectable) {
2266        var data = this.menu.getSelectableData($selectable);
2267        if (data && !this.eventBus.before("select", data.obj)) {
2268          this.input.setQuery(data.val, true);
2269          this.eventBus.trigger("select", data.obj);
2270          this.close();
2271          return true;
2272        }
2273        return false;
2274      },
2275      autocomplete: function autocomplete($selectable) {
2276        var query, data, isValid;
2277        query = this.input.getQuery();
2278        data = this.menu.getSelectableData($selectable);
2279        isValid = data && query !== data.val;
2280        if (isValid && !this.eventBus.before("autocomplete", data.obj)) {
2281          this.input.setQuery(data.val);
2282          this.eventBus.trigger("autocomplete", data.obj);
2283          return true;
2284        }
2285        return false;
2286      },
2287      moveCursor: function moveCursor(delta) {
2288        var query, $candidate, data, payload, cancelMove;
2289        query = this.input.getQuery();
2290        $candidate = this.menu.selectableRelativeToCursor(delta);
2291        data = this.menu.getSelectableData($candidate);
2292        payload = data ? data.obj : null;
2293        cancelMove = this._minLengthMet() && this.menu.update(query);
2294        if (!cancelMove && !this.eventBus.before("cursorchange", payload)) {
2295          this.menu.setCursor($candidate);
2296          if (data) {
2297            this.input.setInputValue(data.val);
2298          } else {
2299            this.input.resetInputValue();
2300            this._updateHint();
2301          }
2302          this.eventBus.trigger("cursorchange", payload);
2303          return true;
2304        }
2305        return false;
2306      },
2307      destroy: function destroy() {
2308        this.input.destroy();
2309        this.menu.destroy();
2310      }
2311    });
2312    return Typeahead;
2313
2314    function c(ctx) {
2315      var methods = [].slice.call(arguments, 1);
2316      return function () {
2317        var args = [].slice.call(arguments);
2318        _.each(methods, function (method) {
2319          return ctx[method].apply(ctx, args);
2320        });
2321      };
2322    }
2323  }();
2324  (function () {
2325    "use strict";
2326    var old, keys, methods;
2327    old = $.fn.typeahead;
2328    keys = {
2329      www: "tt-www",
2330      attrs: "tt-attrs",
2331      typeahead: "tt-typeahead"
2332    };
2333    methods = {
2334      initialize: function initialize(o, datasets) {
2335        var www;
2336        datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1);
2337        o = o || {};
2338        www = WWW(o.classNames);
2339        return this.each(attach);
2340
2341        function attach() {
2342          var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, typeahead,
2343            MenuConstructor;
2344          _.each(datasets, function (d) {
2345            d.highlight = !!o.highlight;
2346          });
2347          $input = $(this);
2348          $wrapper = $(www.html.wrapper);
2349          $hint = $elOrNull(o.hint);
2350          $menu = $elOrNull(o.menu);
2351          defaultHint = o.hint !== false && !$hint;
2352          defaultMenu = o.menu !== false && !$menu;
2353          defaultHint && ($hint = buildHintFromInput($input, www));
2354          defaultMenu && ($menu = $(www.html.menu).css(www.css.menu));
2355          $hint && $hint.val("");
2356          $input = prepInput($input, www);
2357          if (defaultHint || defaultMenu) {
2358            $wrapper.css(www.css.wrapper);
2359            $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint);
2360            $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null);
2361          }
2362          MenuConstructor = defaultMenu ? DefaultMenu : Menu;
2363          eventBus = new EventBus({
2364            el: $input
2365          });
2366          input = new Input({
2367            hint: $hint,
2368            input: $input
2369          }, www);
2370          menu = new MenuConstructor({
2371            node: $menu,
2372            datasets: datasets
2373          }, www);
2374          typeahead = new Typeahead({
2375            input: input,
2376            menu: menu,
2377            eventBus: eventBus,
2378            minLength: o.minLength
2379          }, www);
2380          $input.data(keys.www, www);
2381          $input.data(keys.typeahead, typeahead);
2382        }
2383      },
2384      isEnabled: function isEnabled() {
2385        var enabled;
2386        ttEach(this.first(), function (t) {
2387          enabled = t.isEnabled();
2388        });
2389        return enabled;
2390      },
2391      enable: function enable() {
2392        ttEach(this, function (t) {
2393          t.enable();
2394        });
2395        return this;
2396      },
2397      disable: function disable() {
2398        ttEach(this, function (t) {
2399          t.disable();
2400        });
2401        return this;
2402      },
2403      isActive: function isActive() {
2404        var active;
2405        ttEach(this.first(), function (t) {
2406          active = t.isActive();
2407        });
2408        return active;
2409      },
2410      activate: function activate() {
2411        ttEach(this, function (t) {
2412          t.activate();
2413        });
2414        return this;
2415      },
2416      deactivate: function deactivate() {
2417        ttEach(this, function (t) {
2418          t.deactivate();
2419        });
2420        return this;
2421      },
2422      isOpen: function isOpen() {
2423        var open;
2424        ttEach(this.first(), function (t) {
2425          open = t.isOpen();
2426        });
2427        return open;
2428      },
2429      open: function open() {
2430        ttEach(this, function (t) {
2431          t.open();
2432        });
2433        return this;
2434      },
2435      close: function close() {
2436        ttEach(this, function (t) {
2437          t.close();
2438        });
2439        return this;
2440      },
2441      select: function select(el) {
2442        var success = false, $el = $(el);
2443        ttEach(this.first(), function (t) {
2444          success = t.select($el);
2445        });
2446        return success;
2447      },
2448      autocomplete: function autocomplete(el) {
2449        var success = false, $el = $(el);
2450        ttEach(this.first(), function (t) {
2451          success = t.autocomplete($el);
2452        });
2453        return success;
2454      },
2455      moveCursor: function moveCursoe(delta) {
2456        var success = false;
2457        ttEach(this.first(), function (t) {
2458          success = t.moveCursor(delta);
2459        });
2460        return success;
2461      },
2462      val: function val(newVal) {
2463        var query;
2464        if (!arguments.length) {
2465          ttEach(this.first(), function (t) {
2466            query = t.getVal();
2467          });
2468          return query;
2469        } else {
2470          ttEach(this, function (t) {
2471            t.setVal(newVal);
2472          });
2473          return this;
2474        }
2475      },
2476      destroy: function destroy() {
2477        ttEach(this, function (typeahead, $input) {
2478          revert($input);
2479          typeahead.destroy();
2480        });
2481        return this;
2482      }
2483    };
2484    $.fn.typeahead = function (method) {
2485      if (methods[method]) {
2486        return methods[method].apply(this, [].slice.call(arguments, 1));
2487      } else {
2488        return methods.initialize.apply(this, arguments);
2489      }
2490    };
2491    $.fn.typeahead.noConflict = function noConflict() {
2492      $.fn.typeahead = old;
2493      return this;
2494    };
2495
2496    function ttEach($els, fn) {
2497      $els.each(function () {
2498        var $input = $(this), typeahead;
2499        (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input);
2500      });
2501    }
2502
2503    function buildHintFromInput($input, www) {
2504      return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop("readonly", true).removeAttr("id name placeholder required").attr({
2505        autocomplete: "off",
2506        spellcheck: "false",
2507        tabindex: -1
2508      });
2509    }
2510
2511    function prepInput($input, www) {
2512      $input.data(keys.attrs, {
2513        dir: $input.attr("dir"),
2514        autocomplete: $input.attr("autocomplete"),
2515        spellcheck: $input.attr("spellcheck"),
2516        style: $input.attr("style")
2517      });
2518      $input.addClass(www.classes.input).attr({
2519        autocomplete: "off",
2520        spellcheck: false
2521      });
2522      try {
2523        !$input.attr("dir") && $input.attr("dir", "auto");
2524      } catch (e) {
2525      }
2526      return $input;
2527    }
2528
2529    function getBackgroundStyles($el) {
2530      return {
2531        backgroundAttachment: $el.css("background-attachment"),
2532        backgroundClip: $el.css("background-clip"),
2533        backgroundColor: $el.css("background-color"),
2534        backgroundImage: $el.css("background-image"),
2535        backgroundOrigin: $el.css("background-origin"),
2536        backgroundPosition: $el.css("background-position"),
2537        backgroundRepeat: $el.css("background-repeat"),
2538        backgroundSize: $el.css("background-size")
2539      };
2540    }
2541
2542    function revert($input) {
2543      var www, $wrapper;
2544      www = $input.data(keys.www);
2545      $wrapper = $input.parent().filter(www.selectors.wrapper);
2546      _.each($input.data(keys.attrs), function (val, key) {
2547        _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val);
2548      });
2549      $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input);
2550      if ($wrapper.length) {
2551        $input.detach().insertAfter($wrapper);
2552        $wrapper.remove();
2553      }
2554    }
2555
2556    function $elOrNull(obj) {
2557      var isValid, $el;
2558      isValid = _.isJQuery(obj) || _.isElement(obj);
2559      $el = isValid ? $(obj).first() : [];
2560      return $el.length ? $el : null;
2561    }
2562  })();
2563});

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.