PageSourceSearch

https://www.theboxery.com/scripts/typeahead.bundle.js

js theboxery.com collected 2026-10-02 08:02:20 UTC 93,764 bytes, 2,451 lines download raw bytes

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

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.