PageSourceSearch

https://spectrumnews1.com/etc/designs/news/clientlibs/js.min.ACSHASH7b03e7fbfa607f63001bceceaa5ed9cb.js

js spectrumnews1.com collected 2026-09-24 08:28:47 UTC 1,163,689 bytes, 33,143 lines download raw bytes

vendor: 5,009 bytes, lines 1-198
1/*!
2 * @overview es6-promise - a tiny implementation of Promises/A+.
3 * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
4 * @license   Licensed under MIT license
5 *            See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
6 * @version   v4.2.8+1e68dce6
7 */
8
9(function (global, factory) {
10	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11	typeof define === 'function' && define.amd ? define(factory) :
12	(global.ES6Promise = factory());
13}(this, (function () { 'use strict';
14
15function objectOrFunction(x) {
16  var type = typeof x;
17  return x !== null && (type === 'object' || type === 'function');
18}
19
20function isFunction(x) {
21  return typeof x === 'function';
22}
23
24
25
26var _isArray = void 0;
27if (Array.isArray) {
28  _isArray = Array.isArray;
29} else {
30  _isArray = function (x) {
31    return Object.prototype.toString.call(x) === '[object Array]';
32  };
33}
34
35var isArray = _isArray;
36
37var len = 0;
38var vertxNext = void 0;
39var customSchedulerFn = void 0;
40
41var asap = function asap(callback, arg) {
42  queue[len] = callback;
43  queue[len + 1] = arg;
44  len += 2;
45  if (len === 2) {
46    // If len is 2, that means that we need to schedule an async flush.
47    // If additional callbacks are queued before the queue is flushed, they
48    // will be processed by this flush that we are scheduling.
49    if (customSchedulerFn) {
50      customSchedulerFn(flush);
51    } else {
52      scheduleFlush();
53    }
54  }
55};
56
57function setScheduler(scheduleFn) {
58  customSchedulerFn = scheduleFn;
59}
60
61function setAsap(asapFn) {
62  asap = asapFn;
63}
64
65var browserWindow = typeof window !== 'undefined' ? window : undefined;
66var browserGlobal = browserWindow || {};
67var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
68var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
69
70// test for web worker but not in IE10
71var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
72
73// node
74function useNextTick() {
75  // node version 0.10.x displays a deprecation warning when nextTick is used recursively
76  // see https://github.com/cujojs/when/issues/410 for details
77  return function () {
78    return process.nextTick(flush);
79  };
80}
81
82// vertx
83function useVertxTimer() {
84  if (typeof vertxNext !== 'undefined') {
85    return function () {
86      vertxNext(flush);
87    };
88  }
89
90  return useSetTimeout();
91}
92
93function useMutationObserver() {
94  var iterations = 0;
95  var observer = new BrowserMutationObserver(flush);
96  var node = document.createTextNode('');
97  observer.observe(node, { characterData: true });
98
99  return function () {
100    node.data = iterations = ++iterations % 2;
101  };
102}
103
104// web worker
105function useMessageChannel() {
106  var channel = new MessageChannel();
107  channel.port1.onmessage = flush;
108  return function () {
109    return channel.port2.postMessage(0);
110  };
111}
112
113function useSetTimeout() {
114  // Store setTimeout reference so es6-promise will be unaffected by
115  // other code modifying setTimeout (like sinon.useFakeTimers())
116  var globalSetTimeout = setTimeout;
117  return function () {
118    return globalSetTimeout(flush, 1);
119  };
120}
121
122var queue = new Array(1000);
123function flush() {
124  for (var i = 0; i < len; i += 2) {
125    var callback = queue[i];
126    var arg = queue[i + 1];
127
128    callback(arg);
129
130    queue[i] = undefined;
131    queue[i + 1] = undefined;
132  }
133
134  len = 0;
135}
136
137function attemptVertx() {
138  try {
139    var vertx = Function('return this')().require('vertx');
140    vertxNext = vertx.runOnLoop || vertx.runOnContext;
141    return useVertxTimer();
142  } catch (e) {
143    return useSetTimeout();
144  }
145}
146
147var scheduleFlush = void 0;
148// Decide what async method to use to triggering processing of queued callbacks:
149if (isNode) {
150  scheduleFlush = useNextTick();
151} else if (BrowserMutationObserver) {
152  scheduleFlush = useMutationObserver();
153} else if (isWorker) {
154  scheduleFlush = useMessageChannel();
155} else if (browserWindow === undefined && typeof require === 'function') {
156  scheduleFlush = attemptVertx();
157} else {
158  scheduleFlush = useSetTimeout();
159}
160
161function then(onFulfillment, onRejection) {
162  var parent = this;
163
164  var child = new this.constructor(noop);
165
166  if (child[PROMISE_ID] === undefined) {
167    makePromise(child);
168  }
169
170  var _state = parent._state;
171
172
173  if (_state) {
174    var callback = arguments[_state - 1];
175    asap(function () {
176      return invokeCallback(_state, child, callback, parent._result);
177    });
178  } else {
179    subscribe(parent, child, onFulfillment, onRejection);
180  }
181
182  return child;
183}
184
185/**
186  `Promise.resolve` returns a promise that will become resolved with the
187  passed `value`. It is shorthand for the following:
188
189  ```javascript
190  let promise = new Promise(function(resolve, reject){
191    resolve(1);
192  });
193
194  promise.then(function(value){
195    // value === 1
196  });
197  ```
198
vendor: 7,394 bytes, lines 199-519
199  Instead of writing the above, your code now simply becomes the following:
200
201  ```javascript
202  let promise = Promise.resolve(1);
203
204  promise.then(function(value){
205    // value === 1
206  });
207  ```
208
209  @method resolve
210  @static
211  @param {Any} value value that the returned promise will be resolved with
212  Useful for tooling.
213  @return {Promise} a promise that will become fulfilled with the given
214  `value`
215*/
216function resolve$1(object) {
217  /*jshint validthis:true */
218  var Constructor = this;
219
220  if (object && typeof object === 'object' && object.constructor === Constructor) {
221    return object;
222  }
223
224  var promise = new Constructor(noop);
225  resolve(promise, object);
226  return promise;
227}
228
229var PROMISE_ID = Math.random().toString(36).substring(2);
230
231function noop() {}
232
233var PENDING = void 0;
234var FULFILLED = 1;
235var REJECTED = 2;
236
237function selfFulfillment() {
238  return new TypeError("You cannot resolve a promise with itself");
239}
240
241function cannotReturnOwn() {
242  return new TypeError('A promises callback cannot return that same promise.');
243}
244
245function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) {
246  try {
247    then$$1.call(value, fulfillmentHandler, rejectionHandler);
248  } catch (e) {
249    return e;
250  }
251}
252
253function handleForeignThenable(promise, thenable, then$$1) {
254  asap(function (promise) {
255    var sealed = false;
256    var error = tryThen(then$$1, thenable, function (value) {
257      if (sealed) {
258        return;
259      }
260      sealed = true;
261      if (thenable !== value) {
262        resolve(promise, value);
263      } else {
264        fulfill(promise, value);
265      }
266    }, function (reason) {
267      if (sealed) {
268        return;
269      }
270      sealed = true;
271
272      reject(promise, reason);
273    }, 'Settle: ' + (promise._label || ' unknown promise'));
274
275    if (!sealed && error) {
276      sealed = true;
277      reject(promise, error);
278    }
279  }, promise);
280}
281
282function handleOwnThenable(promise, thenable) {
283  if (thenable._state === FULFILLED) {
284    fulfill(promise, thenable._result);
285  } else if (thenable._state === REJECTED) {
286    reject(promise, thenable._result);
287  } else {
288    subscribe(thenable, undefined, function (value) {
289      return resolve(promise, value);
290    }, function (reason) {
291      return reject(promise, reason);
292    });
293  }
294}
295
296function handleMaybeThenable(promise, maybeThenable, then$$1) {
297  if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) {
298    handleOwnThenable(promise, maybeThenable);
299  } else {
300    if (then$$1 === undefined) {
301      fulfill(promise, maybeThenable);
302    } else if (isFunction(then$$1)) {
303      handleForeignThenable(promise, maybeThenable, then$$1);
304    } else {
305      fulfill(promise, maybeThenable);
306    }
307  }
308}
309
310function resolve(promise, value) {
311  if (promise === value) {
312    reject(promise, selfFulfillment());
313  } else if (objectOrFunction(value)) {
314    var then$$1 = void 0;
315    try {
316      then$$1 = value.then;
317    } catch (error) {
318      reject(promise, error);
319      return;
320    }
321    handleMaybeThenable(promise, value, then$$1);
322  } else {
323    fulfill(promise, value);
324  }
325}
326
327function publishRejection(promise) {
328  if (promise._onerror) {
329    promise._onerror(promise._result);
330  }
331
332  publish(promise);
333}
334
335function fulfill(promise, value) {
336  if (promise._state !== PENDING) {
337    return;
338  }
339
340  promise._result = value;
341  promise._state = FULFILLED;
342
343  if (promise._subscribers.length !== 0) {
344    asap(publish, promise);
345  }
346}
347
348function reject(promise, reason) {
349  if (promise._state !== PENDING) {
350    return;
351  }
352  promise._state = REJECTED;
353  promise._result = reason;
354
355  asap(publishRejection, promise);
356}
357
358function subscribe(parent, child, onFulfillment, onRejection) {
359  var _subscribers = parent._subscribers;
360  var length = _subscribers.length;
361
362
363  parent._onerror = null;
364
365  _subscribers[length] = child;
366  _subscribers[length + FULFILLED] = onFulfillment;
367  _subscribers[length + REJECTED] = onRejection;
368
369  if (length === 0 && parent._state) {
370    asap(publish, parent);
371  }
372}
373
374function publish(promise) {
375  var subscribers = promise._subscribers;
376  var settled = promise._state;
377
378  if (subscribers.length === 0) {
379    return;
380  }
381
382  var child = void 0,
383      callback = void 0,
384      detail = promise._result;
385
386  for (var i = 0; i < subscribers.length; i += 3) {
387    child = subscribers[i];
388    callback = subscribers[i + settled];
389
390    if (child) {
391      invokeCallback(settled, child, callback, detail);
392    } else {
393      callback(detail);
394    }
395  }
396
397  promise._subscribers.length = 0;
398}
399
400function invokeCallback(settled, promise, callback, detail) {
401  var hasCallback = isFunction(callback),
402      value = void 0,
403      error = void 0,
404      succeeded = true;
405
406  if (hasCallback) {
407    try {
408      value = callback(detail);
409    } catch (e) {
410      succeeded = false;
411      error = e;
412    }
413
414    if (promise === value) {
415      reject(promise, cannotReturnOwn());
416      return;
417    }
418  } else {
419    value = detail;
420  }
421
422  if (promise._state !== PENDING) {
423    // noop
424  } else if (hasCallback && succeeded) {
425    resolve(promise, value);
426  } else if (succeeded === false) {
427    reject(promise, error);
428  } else if (settled === FULFILLED) {
429    fulfill(promise, value);
430  } else if (settled === REJECTED) {
431    reject(promise, value);
432  }
433}
434
435function initializePromise(promise, resolver) {
436  try {
437    resolver(function resolvePromise(value) {
438      resolve(promise, value);
439    }, function rejectPromise(reason) {
440      reject(promise, reason);
441    });
442  } catch (e) {
443    reject(promise, e);
444  }
445}
446
447var id = 0;
448function nextId() {
449  return id++;
450}
451
452function makePromise(promise) {
453  promise[PROMISE_ID] = id++;
454  promise._state = undefined;
455  promise._result = undefined;
456  promise._subscribers = [];
457}
458
459function validationError() {
460  return new Error('Array Methods must be provided an Array');
461}
462
463var Enumerator = function () {
464  function Enumerator(Constructor, input) {
465    this._instanceConstructor = Constructor;
466    this.promise = new Constructor(noop);
467
468    if (!this.promise[PROMISE_ID]) {
469      makePromise(this.promise);
470    }
471
472    if (isArray(input)) {
473      this.length = input.length;
474      this._remaining = input.length;
475
476      this._result = new Array(this.length);
477
478      if (this.length === 0) {
479        fulfill(this.promise, this._result);
480      } else {
481        this.length = this.length || 0;
482        this._enumerate(input);
483        if (this._remaining === 0) {
484          fulfill(this.promise, this._result);
485        }
486      }
487    } else {
488      reject(this.promise, validationError());
489    }
490  }
491
492  Enumerator.prototype._enumerate = function _enumerate(input) {
493    for (var i = 0; this._state === PENDING && i < input.length; i++) {
494      this._eachEntry(input[i], i);
495    }
496  };
497
498  Enumerator.prototype._eachEntry = function _eachEntry(entry, i) {
499    var c = this._instanceConstructor;
500    var resolve$$1 = c.resolve;
501
502
503    if (resolve$$1 === resolve$1) {
504      var _then = void 0;
505      var error = void 0;
506      var didError = false;
507      try {
508        _then = entry.then;
509      } catch (e) {
510        didError = true;
511        error = e;
512      }
513
514      if (_then === then && entry._state !== PENDING) {
515        this._settledAt(entry._state, i, entry._result);
516      } else if (typeof _then !== 'function') {
517        this._remaining--;
518        this._result[i] = entry;
519      } else if (c === Promise$2
vendor: 9,193 bytes, lines 519-857
519) {
520        var promise = new c(noop);
521        if (didError) {
522          reject(promise, error);
523        } else {
524          handleMaybeThenable(promise, entry, _then);
525        }
526        this._willSettleAt(promise, i);
527      } else {
528        this._willSettleAt(new c(function (resolve$$1) {
529          return resolve$$1(entry);
530        }), i);
531      }
532    } else {
533      this._willSettleAt(resolve$$1(entry), i);
534    }
535  };
536
537  Enumerator.prototype._settledAt = function _settledAt(state, i, value) {
538    var promise = this.promise;
539
540
541    if (promise._state === PENDING) {
542      this._remaining--;
543
544      if (state === REJECTED) {
545        reject(promise, value);
546      } else {
547        this._result[i] = value;
548      }
549    }
550
551    if (this._remaining === 0) {
552      fulfill(promise, this._result);
553    }
554  };
555
556  Enumerator.prototype._willSettleAt = function _willSettleAt(promise, i) {
557    var enumerator = this;
558
559    subscribe(promise, undefined, function (value) {
560      return enumerator._settledAt(FULFILLED, i, value);
561    }, function (reason) {
562      return enumerator._settledAt(REJECTED, i, reason);
563    });
564  };
565
566  return Enumerator;
567}();
568
569/**
570  `Promise.all` accepts an array of promises, and returns a new promise which
571  is fulfilled with an array of fulfillment values for the passed promises, or
572  rejected with the reason of the first passed promise to be rejected. It casts all
573  elements of the passed iterable to promises as it runs this algorithm.
574
575  Example:
576
577  ```javascript
578  let promise1 = resolve(1);
579  let promise2 = resolve(2);
580  let promise3 = resolve(3);
581  let promises = [ promise1, promise2, promise3 ];
582
583  Promise.all(promises).then(function(array){
584    // The array here would be [ 1, 2, 3 ];
585  });
586  ```
587
588  If any of the `promises` given to `all` are rejected, the first promise
589  that is rejected will be given as an argument to the returned promises's
590  rejection handler. For example:
591
592  Example:
593
594  ```javascript
595  let promise1 = resolve(1);
596  let promise2 = reject(new Error("2"));
597  let promise3 = reject(new Error("3"));
598  let promises = [ promise1, promise2, promise3 ];
599
600  Promise.all(promises).then(function(array){
601    // Code here never runs because there are rejected promises!
602  }, function(error) {
603    // error.message === "2"
604  });
605  ```
606
607  @method all
608  @static
609  @param {Array} entries array of promises
610  @param {String} label optional string for labeling the promise.
611  Useful for tooling.
612  @return {Promise} promise that is fulfilled when all `promises` have been
613  fulfilled, or rejected if any of them become rejected.
614  @static
615*/
616function all(entries) {
617  return new Enumerator(this, entries).promise;
618}
619
620/**
621  `Promise.race` returns a new promise which is settled in the same way as the
622  first passed promise to settle.
623
624  Example:
625
626  ```javascript
627  let promise1 = new Promise(function(resolve, reject){
628    setTimeout(function(){
629      resolve('promise 1');
630    }, 200);
631  });
632
633  let promise2 = new Promise(function(resolve, reject){
634    setTimeout(function(){
635      resolve('promise 2');
636    }, 100);
637  });
638
639  Promise.race([promise1, promise2]).then(function(result){
640    // result === 'promise 2' because it was resolved before promise1
641    // was resolved.
642  });
643  ```
644
645  `Promise.race` is deterministic in that only the state of the first
646  settled promise matters. For example, even if other promises given to the
647  `promises` array argument are resolved, but the first settled promise has
648  become rejected before the other promises became fulfilled, the returned
649  promise will become rejected:
650
651  ```javascript
652  let promise1 = new Promise(function(resolve, reject){
653    setTimeout(function(){
654      resolve('promise 1');
655    }, 200);
656  });
657
658  let promise2 = new Promise(function(resolve, reject){
659    setTimeout(function(){
660      reject(new Error('promise 2'));
661    }, 100);
662  });
663
664  Promise.race([promise1, promise2]).then(function(result){
665    // Code here never runs
666  }, function(reason){
667    // reason.message === 'promise 2' because promise 2 became rejected before
668    // promise 1 became fulfilled
669  });
670  ```
671
672  An example real-world use case is implementing timeouts:
673
674  ```javascript
675  Promise.race([ajax('foo.json'), timeout(5000)])
676  ```
677
678  @method race
679  @static
680  @param {Array} promises array of promises to observe
681  Useful for tooling.
682  @return {Promise} a promise which settles in the same way as the first passed
683  promise to settle.
684*/
685function race(entries) {
686  /*jshint validthis:true */
687  var Constructor = this;
688
689  if (!isArray(entries)) {
690    return new Constructor(function (_, reject) {
691      return reject(new TypeError('You must pass an array to race.'));
692    });
693  } else {
694    return new Constructor(function (resolve, reject) {
695      var length = entries.length;
696      for (var i = 0; i < length; i++) {
697        Constructor.resolve(entries[i]).then(resolve, reject);
698      }
699    });
700  }
701}
702
703/**
704  `Promise.reject` returns a promise rejected with the passed `reason`.
705  It is shorthand for the following:
706
707  ```javascript
708  let promise = new Promise(function(resolve, reject){
709    reject(new Error('WHOOPS'));
710  });
711
712  promise.then(function(value){
713    // Code here doesn't run because the promise is rejected!
714  }, function(reason){
715    // reason.message === 'WHOOPS'
716  });
717  ```
718
719  Instead of writing the above, your code now simply becomes the following:
720
721  ```javascript
722  let promise = Promise.reject(new Error('WHOOPS'));
723
724  promise.then(function(value){
725    // Code here doesn't run because the promise is rejected!
726  }, function(reason){
727    // reason.message === 'WHOOPS'
728  });
729  ```
730
731  @method reject
732  @static
733  @param {Any} reason value that the returned promise will be rejected with.
734  Useful for tooling.
735  @return {Promise} a promise rejected with the given `reason`.
736*/
737function reject$1(reason) {
738  /*jshint validthis:true */
739  var Constructor = this;
740  var promise = new Constructor(noop);
741  reject(promise, reason);
742  return promise;
743}
744
745function needsResolver() {
746  throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
747}
748
749function needsNew() {
750  throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
751}
752
753/**
754  Promise objects represent the eventual result of an asynchronous operation. The
755  primary way of interacting with a promise is through its `then` method, which
756  registers callbacks to receive either a promise's eventual value or the reason
757  why the promise cannot be fulfilled.
758
759  Terminology
760  -----------
761
762  - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
763  - `thenable` is an object or function that defines a `then` method.
764  - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
765  - `exception` is a value that is thrown using the throw statement.
766  - `reason` is a value that indicates why a promise was rejected.
767  - `settled` the final resting state of a promise, fulfilled or rejected.
768
769  A promise can be in one of three states: pending, fulfilled, or rejected.
770
771  Promises that are fulfilled have a fulfillment value and are in the fulfilled
772  state.  Promises that are rejected have a rejection reason and are in the
773  rejected state.  A fulfillment value is never a thenable.
774
775  Promises can also be said to *resolve* a value.  If this value is also a
776  promise, then the original promise's settled state will match the value's
777  settled state.  So a promise that *resolves* a promise that rejects will
778  itself reject, and a promise that *resolves* a promise that fulfills will
779  itself fulfill.
780
781
782  Basic Usage:
783  ------------
784
785  ```js
786  let promise = new Promise(function(resolve, reject) {
787    // on success
788    resolve(value);
789
790    // on failure
791    reject(reason);
792  });
793
794  promise.then(function(value) {
795    // on fulfillment
796  }, function(reason) {
797    // on rejection
798  });
799  ```
800
801  Advanced Usage:
802  ---------------
803
804  Promises shine when abstracting away asynchronous interactions such as
805  `XMLHttpRequest`s.
806
807  ```js
808  function getJSON(url) {
809    return new Promise(function(resolve, reject){
810      let xhr = new XMLHttpRequest();
811
812      xhr.open('GET', url);
813      xhr.onreadystatechange = handler;
814      xhr.responseType = 'json';
815      xhr.setRequestHeader('Accept', 'application/json');
816      xhr.send();
817
818      function handler() {
819        if (this.readyState === this.DONE) {
820          if (this.status === 200) {
821            resolve(this.response);
822          } else {
823            reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
824          }
825        }
826      };
827    });
828  }
829
830  getJSON('/posts.json').then(function(json) {
831    // on fulfillment
832  }, function(reason) {
833    // on rejection
834  });
835  ```
836
837  Unlike callbacks, promises are great composable primitives.
838
839  ```js
840  Promise.all([
841    getJSON('/posts'),
842    getJSON('/comments')
843  ]).then(function(values){
844    values[0] // => postsJSON
845    values[1] // => commentsJSON
846
847    return values;
848  });
849  ```
850
851  @class Promise
852  @param {Function} resolver
853  Useful for tooling.
854  @constructor
855*/
856
857var Promise$
8572 = function () {
858  function Promise(resolver) {
859    this[PROMISE_ID] = nextId();
860    this._result = this._state = undefined;
861    this._subscribers = [];
862
863    if (noop !== resolver) {
864      typeof resolver !== 'function' && needsResolver();
865      this instanceof Promise ? initializePromise(this, resolver) : needsNew();
866    }
867  }
868
869  /**
870  The primary way of interacting with a promise is through its `then` method,
871  which registers callbacks to receive either a promise's eventual value or the
872  reason why the promise cannot be fulfilled.
873   ```js
874  findUser().then(function(user){
875    // user is available
876  }, function(reason){
877    // user is unavailable, and you are given the reason why
878  });
879  ```
880   Chaining
881  --------
882   The return value of `then` is itself a promise.  This second, 'downstream'
883  promise is resolved with the return value of the first promise's fulfillment
884  or rejection handler, or rejected if the handler throws an exception.
885   ```js
886  findUser().then(function (user) {
887    return user.name;
888  }, function (reason) {
889    return 'default name';
890  }).then(function (userName) {
891    // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
892    // will be `'default name'`
893  });
894   findUser().then(function (user) {
895    throw new Error('Found user, but still unhappy');
896  }, function (reason) {
897    throw new Error('`findUser` rejected and we're unhappy');
898  }).then(function (value) {
899    // never reached
900  }, function (reason) {
901    // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
902    // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
903  });
904  ```
905  If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
906   ```js
907  findUser().then(function (user) {
908    throw new PedagogicalException('Upstream error');
909  }).then(function (value) {
910    // never reached
911  }).then(function (value) {
912    // never reached
913  }, function (reason) {
914    // The `PedgagocialException` is propagated all the way down to here
915  });
916  ```
917   Assimilation
918  ------------
919   Sometimes the value you want to propagate to a downstream promise can only be
920  retrieved asynchronously. This can be achieved by returning a promise in the
921  fulfillment or rejection handler. The downstream promise will then be pending
922  until the returned promise is settled. This is called *assimilation*.
923   ```js
924  findUser().then(function (user) {
925    return findCommentsByAuthor(user);
926  }).then(function (comments) {
927    // The user's comments are now available
928  });
929  ```
930   If the assimliated promise rejects, then the downstream promise will also reject.
931   ```js
932  findUser().then(function (user) {
933    return findCommentsByAuthor(user);
934  }).then(function (comments) {
935    // If `findCommentsByAuthor` fulfills, we'll have the value here
936  }, function (reason) {
937    // If `findCommentsByAuthor` rejects, we'll have the reason here
938  });
939  ```
940   Simple Example
941  --------------
942   Synchronous Example
943   ```javascript
944  let result;
945   try {
946    result = findResult();
947    // success
948  } catch(reason) {
949    // failure
950  }
951  ```
952   Errback Example
953   ```js
954  findResult(function(result, err){
955    if (err) {
956      // failure
957    } else {
958      // success
959    }
960  });
961  ```
962   Promise Example;
963   ```javascript
964  findResult().then(function(result){
965    // success
966  }, function(reason){
967    // failure
968  });
969  ```
970   Advanced Example
971  --------------
972   Synchronous Example
973   ```javascript
974  let author, books;
975   try {
976    author = findAuthor();
977    books  = findBooksByAuthor(author);
978    // success
979  } catch(reason) {
980    // failure
981  }
982  ```
983   Errback Example
984   ```js
985   function foundBooks(books) {
986   }
987   function failure(reason) {
988   }
989   findAuthor(function(author, err){
990    if (err) {
991      failure(err);
992      // failure
993    } else {
994      try {
995        findBoooksByAuthor(author, function(books, err) {
996          if (err) {
997            failure(err);
998          } else {
999            try {
1000              foundBooks(books);
1001            } catch(reason) {
1002              failure(reason);
1003            }
1004          }
1005        });
1006      } catch(error) {
1007        failure(err);
1008      }
1009      // success
1010    }
1011  });
1012  ```
1013   Promise Example;
1014   ```javascript
1015  findAuthor().
1016    then(findBooksByAuthor).
1017    then(function(books){
1018      // found books
1019  }).catch(function(reason){
1020    // something went wrong
1021  });
1022  ```
1023   @method then
1024  @param {Function} onFulfilled
1025  @param {Function} onRejected
1026  Useful for tooling.
1027  @return {Promise}
1028  */
1029
1030  /**
1031  `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
1032  as the catch block of a try/catch statement.
1033  ```js
1034  function findAuthor(){
1035  throw new Error('couldn't find that author');
1036  }
1037  // synchronous
1038  try {
1039  findAuthor();
1040  } catch(reason) {
1041  // something went wrong
1042  }
1043  // async with promises
1044  findAuthor().catch(function(reason){
1045  // something went wrong
1046  });
1047  ```
1048  @method catch
1049  @param {Function} onRejection
1050  Useful for tooling.
1051  @return {Promise}
1052  */
1053
1054
1055  Promise.prototype.catch = function _catch(onRejection) {
1056    return this.then(null, onRejection);
1057  };
1058
1059  /**
1060    `finally` will be invoked regardless of the promise's fate just as native
1061    try/catch/finally behaves
1062
1063    Synchronous example:
1064
1065    ```js
1066    findAuthor() {
1067      if (Math.random() > 0.5) {
1068        throw new Error();
1069      }
1070      return new Author();
1071    }
1072
1073    try {
1074      return findAuthor(); // succeed or fail
1075    } catch(error) {
1076      return findOtherAuther();
1077    } finally {
1078      // always runs
1079      // doesn't affect the return value
1080    }
1081    ```
1082
1083    Asynchronous example:
1084
1085    ```js
1086    findAuthor().catch(function(reason){
1087      return findOtherAuther();
1088    }).finally(function(){
1089      // author was either found, or not
1090    });
1091    ```
1092
1093    @method finally
1094    @param {Function} callback
1095    @return {Promise}
1096  */
1097
1098
1099  Promise.prototype.finally = function _finally(callback) {
1100    var promise = this;
1101    var constructor = promise.constructor;
1102
1103    if (isFunction(callback)) {
1104      return promise.then(function (value) {
1105        return constructor.resolve(callback()).then(function () {
1106          return value;
1107        });
1108      }, function (reason) {
1109        return constructor.resolve(callback()).then(function () {
1110          throw reason;
1111        });
1112      });
1113    }
1114
1115    return promise.then(callback, callback);
1116  };
1117
1118  return Promise;
1119}();
1120
1121Promise$2.prototype.then = then;
1122Promise$2.all = all;
1123Promise$2.race = race;
1124Promise$2.resolve = resolve$1;
1125Promise$2.reject = reject$1;
1126Promise$2._setScheduler = setScheduler;
1127Promise$2._setAsap = setAsap;
1128Promise$2._asap = asap;
1129
1130/*global self*/
1131function polyfill() {
1132  var local = void 0;
1133
1134  if (typeof global !== 'undefined') {
1135    local = global;
1136  } else if (typeof self !== 'undefined') {
1137    local = self;
1138  } else {
1139    try {
1140      local = Function('return this')();
1141    } catch (e) {
1142      throw new Error('polyfill failed because global object is unavailable in this environment');
1143    }
1144  }
1145
1146  var P = local.Promise;
1147
1148  if (P) {
1149    var promiseToString = null;
1150    try {
1151      promiseToString = Object.prototype.toString.call(P.resolve());
1152    } catch (e) {
1153      // silently ignored
1154    }
1155
1156    if (promiseToString === '[object Promise]' && !P.cast) {
1157      return;
1158    }
1159  }
1160
1161  local.Promise = Promise$2;
1162}
1163
1164// Strange compat..
1165Promise$2.polyfill = polyfill;
1166Promise$2.Promise = Promise$2;
1167
1168Promise$2.polyfill();
1169
1170return Promise$2;
1171
1172})));
1173/* ========================================================================
1174 * Bootstrap: collapse.js v3.3.7
1175 * http://getbootstrap.com/javascript/#collapse
1176 * ========================================================================
1177 * Copyright 2011-2016 Twitter, Inc.
1178 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1179 * ======================================================================== */
1180
vendor: 12,140 bytes, lines 1181-1611
1181/* jshint latedef: false */
1182
1183+function ($) {
1184  'use strict';
1185
1186  // COLLAPSE PUBLIC CLASS DEFINITION
1187  // ================================
1188
1189  var Collapse = function (element, options) {
1190    this.$element      = $(element)
1191    this.options       = $.extend({}, Collapse.DEFAULTS, options)
1192    this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
1193                           '[data-toggle="collapse"][data-target="#' + element.id + '"]')
1194    this.transitioning = null
1195
1196    if (this.options.parent) {
1197      this.$parent = this.getParent()
1198    } else {
1199      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
1200    }
1201
1202    if (this.options.toggle) this.toggle()
1203  }
1204
1205  Collapse.VERSION  = '3.3.7'
1206
1207  Collapse.TRANSITION_DURATION = 350
1208
1209  Collapse.DEFAULTS = {
1210    toggle: true
1211  }
1212
1213  Collapse.prototype.dimension = function () {
1214    var hasWidth = this.$element.hasClass('width')
1215    return hasWidth ? 'width' : 'height'
1216  }
1217
1218  Collapse.prototype.show = function () {
1219    if (this.transitioning || this.$element.hasClass('in')) return
1220
1221    var activesData
1222    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
1223
1224    if (actives && actives.length) {
1225      activesData = actives.data('bs.collapse')
1226      if (activesData && activesData.transitioning) return
1227    }
1228
1229    var startEvent = $.Event('show.bs.collapse')
1230    this.$element.trigger(startEvent)
1231    if (startEvent.isDefaultPrevented()) return
1232
1233    if (actives && actives.length) {
1234      Plugin.call(actives, 'hide')
1235      activesData || actives.data('bs.collapse', null)
1236    }
1237
1238    var dimension = this.dimension()
1239
1240    this.$element
1241      .removeClass('collapse')
1242      .addClass('collapsing')[dimension](0)
1243      .attr('aria-expanded', true)
1244
1245    this.$trigger
1246      .removeClass('collapsed')
1247      .attr('aria-expanded', true)
1248
1249    this.transitioning = 1
1250
1251    var complete = function () {
1252      this.$element
1253        .removeClass('collapsing')
1254        .addClass('collapse in')[dimension]('')
1255      this.transitioning = 0
1256      this.$element
1257        .trigger('shown.bs.collapse')
1258    }
1259
1260    if (!$.support.transition) return complete.call(this)
1261
1262    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
1263
1264    this.$element
1265      .one('bsTransitionEnd', $.proxy(complete, this))
1266      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
1267  }
1268
1269  Collapse.prototype.hide = function () {
1270    if (this.transitioning || !this.$element.hasClass('in')) return
1271
1272    var startEvent = $.Event('hide.bs.collapse')
1273    this.$element.trigger(startEvent)
1274    if (startEvent.isDefaultPrevented()) return
1275
1276    var dimension = this.dimension()
1277
1278    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
1279
1280    this.$element
1281      .addClass('collapsing')
1282      .removeClass('collapse in')
1283      .attr('aria-expanded', false)
1284
1285    this.$trigger
1286      .addClass('collapsed')
1287      .attr('aria-expanded', false)
1288
1289    this.transitioning = 1
1290
1291    var complete = function () {
1292      this.transitioning = 0
1293      this.$element
1294        .removeClass('collapsing')
1295        .addClass('collapse')
1296        .trigger('hidden.bs.collapse')
1297    }
1298
1299    if (!$.support.transition) return complete.call(this)
1300
1301    this.$element
1302      [dimension](0)
1303      .one('bsTransitionEnd', $.proxy(complete, this))
1304      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
1305  }
1306
1307  Collapse.prototype.toggle = function () {
1308    this[this.$element.hasClass('in') ? 'hide' : 'show']()
1309  }
1310
1311  Collapse.prototype.getParent = function () {
1312    return $(this.options.parent)
1313      .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
1314      .each($.proxy(function (i, element) {
1315        var $element = $(element)
1316        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
1317      }, this))
1318      .end()
1319  }
1320
1321  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
1322    var isOpen = $element.hasClass('in')
1323
1324    $element.attr('aria-expanded', isOpen)
1325    $trigger
1326      .toggleClass('collapsed', !isOpen)
1327      .attr('aria-expanded', isOpen)
1328  }
1329
1330  function getTargetFromTrigger($trigger) {
1331    var href
1332    var target = $trigger.attr('data-target')
1333      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
1334
1335    return $(target)
1336  }
1337
1338
1339  // COLLAPSE PLUGIN DEFINITION
1340  // ==========================
1341
1342  function Plugin(option) {
1343    return this.each(function () {
1344      var $this   = $(this)
1345      var data    = $this.data('bs.collapse')
1346      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
1347
1348      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
1349      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
1350      if (typeof option == 'string') data[option]()
1351    })
1352  }
1353
1354  var old = $.fn.collapse
1355
1356  $.fn.collapse             = Plugin
1357  $.fn.collapse.Constructor = Collapse
1358
1359
1360  // COLLAPSE NO CONFLICT
1361  // ====================
1362
1363  $.fn.collapse.noConflict = function () {
1364    $.fn.collapse = old
1365    return this
1366  }
1367
1368
1369  // COLLAPSE DATA-API
1370  // =================
1371
1372  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
1373    var $this   = $(this)
1374
1375    if (!$this.attr('data-target')) e.preventDefault()
1376
1377    var $target = getTargetFromTrigger($this)
1378    var data    = $target.data('bs.collapse')
1379    var option  = data ? 'toggle' : $this.data()
1380
1381    Plugin.call($target, option)
1382  })
1383
1384}(jQuery);
1385
1386/* ========================================================================
1387 * Bootstrap: dropdown.js v3.3.7
1388 * http://getbootstrap.com/javascript/#dropdowns
1389 * ========================================================================
1390 * Copyright 2011-2016 Twitter, Inc.
1391 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1392 * ======================================================================== */
1393
1394
1395+function ($) {
1396  'use strict';
1397
1398  // DROPDOWN CLASS DEFINITION
1399  // =========================
1400
1401  var backdrop = '.dropdown-backdrop'
1402  var toggle   = '[data-toggle="dropdown"]'
1403  var Dropdown = function (element) {
1404    $(element).on('click.bs.dropdown', this.toggle)
1405  }
1406
1407  Dropdown.VERSION = '3.3.7'
1408
1409  function getParent($this) {
1410    var selector = $this.attr('data-target')
1411
1412    if (!selector) {
1413      selector = $this.attr('href')
1414      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
1415    }
1416
1417    var $parent = selector && $(selector)
1418
1419    return $parent && $parent.length ? $parent : $this.parent()
1420  }
1421
1422  function clearMenus(e) {
1423    if (e && e.which === 3) return
1424    $(backdrop).remove()
1425    $(toggle).each(function () {
1426      var $this         = $(this)
1427      var $parent       = getParent($this)
1428      var relatedTarget = { relatedTarget: this }
1429
1430      if (!$parent.hasClass('open')) return
1431
1432      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
1433
1434      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1435
1436      if (e.isDefaultPrevented()) return
1437
1438      $this.attr('aria-expanded', 'false')
1439      $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
1440    })
1441  }
1442
1443  Dropdown.prototype.toggle = function (e) {
1444    var $this = $(this)
1445
1446    if ($this.is('.disabled, :disabled')) return
1447
1448    var $parent  = getParent($this)
1449    var isActive = $parent.hasClass('open')
1450
1451    clearMenus()
1452
1453    if (!isActive) {
1454      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
1455        // if mobile we use a backdrop because click events don't delegate
1456        $(document.createElement('div'))
1457          .addClass('dropdown-backdrop')
1458          .insertAfter($(this))
1459          .on('click', clearMenus)
1460      }
1461
1462      var relatedTarget = { relatedTarget: this }
1463      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
1464
1465      if (e.isDefaultPrevented()) return
1466
1467      $this
1468        .trigger('focus')
1469        .attr('aria-expanded', 'true')
1470
1471      $parent
1472        .toggleClass('open')
1473        .trigger($.Event('shown.bs.dropdown', relatedTarget))
1474    }
1475
1476    return false
1477  }
1478
1479  Dropdown.prototype.keydown = function (e) {
1480    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
1481
1482    var $this = $(this)
1483
1484    e.preventDefault()
1485    e.stopPropagation()
1486
1487    if ($this.is('.disabled, :disabled')) return
1488
1489    var $parent  = getParent($this)
1490    var isActive = $parent.hasClass('open')
1491
1492    if (!isActive && e.which != 27 || isActive && e.which == 27) {
1493      if (e.which == 27) $parent.find(toggle).trigger('focus')
1494      return $this.trigger('click')
1495    }
1496
1497    var desc = ' li:not(.disabled):visible a'
1498    var $items = $parent.find('.dropdown-menu' + desc)
1499
1500    if (!$items.length) return
1501
1502    var index = $items.index(e.target)
1503
1504    if (e.which == 38 && index > 0)                 index--         // up
1505    if (e.which == 40 && index < $items.length - 1) index++         // down
1506    if (!~index)                                    index = 0
1507
1508    $items.eq(index).trigger('focus')
1509  }
1510
1511
1512  // DROPDOWN PLUGIN DEFINITION
1513  // ==========================
1514
1515  function Plugin(option) {
1516    return this.each(function () {
1517      var $this = $(this)
1518      var data  = $this.data('bs.dropdown')
1519
1520      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
1521      if (typeof option == 'string') data[option].call($this)
1522    })
1523  }
1524
1525  var old = $.fn.dropdown
1526
1527  $.fn.dropdown             = Plugin
1528  $.fn.dropdown.Constructor = Dropdown
1529
1530
1531  // DROPDOWN NO CONFLICT
1532  // ====================
1533
1534  $.fn.dropdown.noConflict = function () {
1535    $.fn.dropdown = old
1536    return this
1537  }
1538
1539
1540  // APPLY TO STANDARD DROPDOWN ELEMENTS
1541  // ===================================
1542
1543  $(document)
1544    .on('click.bs.dropdown.data-api', clearMenus)
1545    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
1546    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
1547    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
1548    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
1549
1550}(jQuery);
1551
1552/* ========================================================================
1553 * Bootstrap: transition.js v3.3.7
1554 * http://getbootstrap.com/javascript/#transitions
1555 * ========================================================================
1556 * Copyright 2011-2016 Twitter, Inc.
1557 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
1558 * ======================================================================== */
1559
1560
1561+function ($) {
1562  'use strict';
1563
1564  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
1565  // ============================================================
1566
1567  function transitionEnd() {
1568    var el = document.createElement('bootstrap')
1569
1570    var transEndEventNames = {
1571      WebkitTransition : 'webkitTransitionEnd',
1572      MozTransition    : 'transitionend',
1573      OTransition      : 'oTransitionEnd otransitionend',
1574      transition       : 'transitionend'
1575    }
1576
1577    for (var name in transEndEventNames) {
1578      if (el.style[name] !== undefined) {
1579        return { end: transEndEventNames[name] }
1580      }
1581    }
1582
1583    return false // explicit for ie8 (  ._.)
1584  }
1585
1586  // http://blog.alexmaccaw.com/css-transitions
1587  $.fn.emulateTransitionEnd = function (duration) {
1588    var called = false
1589    var $el = this
1590    $(this).one('bsTransitionEnd', function () { called = true })
1591    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
1592    setTimeout(callback, duration)
1593    return this
1594  }
1595
1596  $(function () {
1597    $.support.transition = transitionEnd()
1598
1599    if (!$.support.transition) return
1600
1601    $.event.special.bsTransitionEnd = {
1602      bindType: $.support.transition.end,
1603      delegateType: $.support.transition.end,
1604      handle: function (e) {
1605        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
1606      }
1607    }
1608  })
1609
1610}(jQuery);
1611
vendor: 12,637 bytes, lines 1612-1926
1612/**
1613 * @license
1614 * Lodash <https://lodash.com/>
1615 * Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
1616 * Released under MIT license <https://lodash.com/license>
1617 * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
1618 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
1619 */
1620;(function() {
1621
1622  /** Used as a safe reference for `undefined` in pre-ES5 environments. */
1623  var undefined;
1624
1625  /** Used as the semantic version number. */
1626  var VERSION = '4.17.21';
1627
1628  /** Used as the size to enable large array optimizations. */
1629  var LARGE_ARRAY_SIZE = 200;
1630
1631  /** Error message constants. */
1632  var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
1633      FUNC_ERROR_TEXT = 'Expected a function',
1634      INVALID_TEMPL_VAR_ERROR_TEXT = 'Invalid `variable` option passed into `_.template`';
1635
1636  /** Used to stand-in for `undefined` hash values. */
1637  var HASH_UNDEFINED = '__lodash_hash_undefined__';
1638
1639  /** Used as the maximum memoize cache size. */
1640  var MAX_MEMOIZE_SIZE = 500;
1641
1642  /** Used as the internal argument placeholder. */
1643  var PLACEHOLDER = '__lodash_placeholder__';
1644
1645  /** Used to compose bitmasks for cloning. */
1646  var CLONE_DEEP_FLAG = 1,
1647      CLONE_FLAT_FLAG = 2,
1648      CLONE_SYMBOLS_FLAG = 4;
1649
1650  /** Used to compose bitmasks for value comparisons. */
1651  var COMPARE_PARTIAL_FLAG = 1,
1652      COMPARE_UNORDERED_FLAG = 2;
1653
1654  /** Used to compose bitmasks for function metadata. */
1655  var WRAP_BIND_FLAG = 1,
1656      WRAP_BIND_KEY_FLAG = 2,
1657      WRAP_CURRY_BOUND_FLAG = 4,
1658      WRAP_CURRY_FLAG = 8,
1659      WRAP_CURRY_RIGHT_FLAG = 16,
1660      WRAP_PARTIAL_FLAG = 32,
1661      WRAP_PARTIAL_RIGHT_FLAG = 64,
1662      WRAP_ARY_FLAG = 128,
1663      WRAP_REARG_FLAG = 256,
1664      WRAP_FLIP_FLAG = 512;
1665
1666  /** Used as default options for `_.truncate`. */
1667  var DEFAULT_TRUNC_LENGTH = 30,
1668      DEFAULT_TRUNC_OMISSION = '...';
1669
1670  /** Used to detect hot functions by number of calls within a span of milliseconds. */
1671  var HOT_COUNT = 800,
1672      HOT_SPAN = 16;
1673
1674  /** Used to indicate the type of lazy iteratees. */
1675  var LAZY_FILTER_FLAG = 1,
1676      LAZY_MAP_FLAG = 2,
1677      LAZY_WHILE_FLAG = 3;
1678
1679  /** Used as references for various `Number` constants. */
1680  var INFINITY = 1 / 0,
1681      MAX_SAFE_INTEGER = 9007199254740991,
1682      MAX_INTEGER = 1.7976931348623157e+308,
1683      NAN = 0 / 0;
1684
1685  /** Used as references for the maximum length and index of an array. */
1686  var MAX_ARRAY_LENGTH = 4294967295,
1687      MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
1688      HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
1689
1690  /** Used to associate wrap methods with their bit flags. */
1691  var wrapFlags = [
1692    ['ary', WRAP_ARY_FLAG],
1693    ['bind', WRAP_BIND_FLAG],
1694    ['bindKey', WRAP_BIND_KEY_FLAG],
1695    ['curry', WRAP_CURRY_FLAG],
1696    ['curryRight', WRAP_CURRY_RIGHT_FLAG],
1697    ['flip', WRAP_FLIP_FLAG],
1698    ['partial', WRAP_PARTIAL_FLAG],
1699    ['partialRight', WRAP_PARTIAL_RIGHT_FLAG],
1700    ['rearg', WRAP_REARG_FLAG]
1701  ];
1702
1703  /** `Object#toString` result references. */
1704  var argsTag = '[object Arguments]',
1705      arrayTag = '[object Array]',
1706      asyncTag = '[object AsyncFunction]',
1707      boolTag = '[object Boolean]',
1708      dateTag = '[object Date]',
1709      domExcTag = '[object DOMException]',
1710      errorTag = '[object Error]',
1711      funcTag = '[object Function]',
1712      genTag = '[object GeneratorFunction]',
1713      mapTag = '[object Map]',
1714      numberTag = '[object Number]',
1715      nullTag = '[object Null]',
1716      objectTag = '[object Object]',
1717      promiseTag = '[object Promise]',
1718      proxyTag = '[object Proxy]',
1719      regexpTag = '[object RegExp]',
1720      setTag = '[object Set]',
1721      stringTag = '[object String]',
1722      symbolTag = '[object Symbol]',
1723      undefinedTag = '[object Undefined]',
1724      weakMapTag = '[object WeakMap]',
1725      weakSetTag = '[object WeakSet]';
1726
1727  var arrayBufferTag = '[object ArrayBuffer]',
1728      dataViewTag = '[object DataView]',
1729      float32Tag = '[object Float32Array]',
1730      float64Tag = '[object Float64Array]',
1731      int8Tag = '[object Int8Array]',
1732      int16Tag = '[object Int16Array]',
1733      int32Tag = '[object Int32Array]',
1734      uint8Tag = '[object Uint8Array]',
1735      uint8ClampedTag = '[object Uint8ClampedArray]',
1736      uint16Tag = '[object Uint16Array]',
1737      uint32Tag = '[object Uint32Array]';
1738
1739  /** Used to match empty string literals in compiled template source. */
1740  var reEmptyStringLeading = /\b__p \+= '';/g,
1741      reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
1742      reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
1743
1744  /** Used to match HTML entities and HTML characters. */
1745  var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g,
1746      reUnescapedHtml = /[&<>"']/g,
1747      reHasEscapedHtml = RegExp(reEscapedHtml.source),
1748      reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
1749
1750  /** Used to match template delimiters. */
1751  var reEscape = /<%-([\s\S]+?)%>/g,
1752      reEvaluate = /<%([\s\S]+?)%>/g,
1753      reInterpolate = /<%=([\s\S]+?)%>/g;
1754
1755  /** Used to match property names within property paths. */
1756  var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
1757      reIsPlainProp = /^\w*$/,
1758      rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
1759
1760  /**
1761   * Used to match `RegExp`
1762   * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
1763   */
1764  var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
1765      reHasRegExpChar = RegExp(reRegExpChar.source);
1766
1767  /** Used to match leading whitespace. */
1768  var reTrimStart = /^\s+/;
1769
1770  /** Used to match a single whitespace character. */
1771  var reWhitespace = /\s/;
1772
1773  /** Used to match wrap detail comments. */
1774  var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
1775      reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
1776      reSplitDetails = /,? & /;
1777
1778  /** Used to match words composed of alphanumeric characters. */
1779  var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
1780
1781  /**
1782   * Used to validate the `validate` option in `_.template` variable.
1783   *
1784   * Forbids characters which could potentially change the meaning of the function argument definition:
1785   * - "()," (modification of function parameters)
1786   * - "=" (default value)
1787   * - "[]{}" (destructuring of function parameters)
1788   * - "/" (beginning of a comment)
1789   * - whitespace
1790   */
1791  var reForbiddenIdentifierChars = /[()=,{}\[\]\/\s]/;
1792
1793  /** Used to match backslashes in property paths. */
1794  var reEscapeChar = /\\(\\)?/g;
1795
1796  /**
1797   * Used to match
1798   * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
1799   */
1800  var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
1801
1802  /** Used to match `RegExp` flags from their coerced string values. */
1803  var reFlags = /\w*$/;
1804
1805  /** Used to detect bad signed hexadecimal string values. */
1806  var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
1807
1808  /** Used to detect binary string values. */
1809  var reIsBinary = /^0b[01]+$/i;
1810
1811  /** Used to detect host constructors (Safari). */
1812  var reIsHostCtor = /^\[object .+?Constructor\]$/;
1813
1814  /** Used to detect octal string values. */
1815  var reIsOctal = /^0o[0-7]+$/i;
1816
1817  /** Used to detect unsigned integer values. */
1818  var reIsUint = /^(?:0|[1-9]\d*)$/;
1819
1820  /** Used to match Latin Unicode letters (excluding mathematical operators). */
1821  var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
1822
1823  /** Used to ensure capturing order of template delimiters. */
1824  var reNoMatch = /($^)/;
1825
1826  /** Used to match unescaped characters in compiled string literals. */
1827  var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
1828
1829  /** Used to compose unicode character classes. */
1830  var rsAstralRange = '\\ud800-\\udfff',
1831      rsComboMarksRange = '\\u0300-\\u036f',
1832      reComboHalfMarksRange = '\\ufe20-\\ufe2f',
1833      rsComboSymbolsRange = '\\u20d0-\\u20ff',
1834      rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
1835      rsDingbatRange = '\\u2700-\\u27bf',
1836      rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
1837      rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
1838      rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
1839      rsPunctuationRange = '\\u2000-\\u206f',
1840      rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
1841      rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
1842      rsVarRange = '\\ufe0e\\ufe0f',
1843      rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
1844
1845  /** Used to compose unicode capture groups. */
1846  var rsApos = "['\u2019]",
1847      rsAstral = '[' + rsAstralRange + ']',
1848      rsBreak = '[' + rsBreakRange + ']',
1849      rsCombo = '[' + rsComboRange + ']',
1850      rsDigits = '\\d+',
1851      rsDingbat = '[' + rsDingbatRange + ']',
1852      rsLower = '[' + rsLowerRange + ']',
1853      rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
1854      rsFitz = '\\ud83c[\\udffb-\\udfff]',
1855      rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
1856      rsNonAstral = '[^' + rsAstralRange + ']',
1857      rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
1858      rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
1859      rsUpper = '[' + rsUpperRange + ']',
1860      rsZWJ = '\\u200d';
1861
1862  /** Used to compose unicode regexes. */
1863  var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
1864      rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
1865      rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
1866      rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
1867      reOptMod = rsModifier + '?',
1868      rsOptVar = '[' + rsVarRange + ']?',
1869      rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
1870      rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])',
1871      rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])',
1872      rsSeq = rsOptVar + reOptMod + rsOptJoin,
1873      rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
1874      rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
1875
1876  /** Used to match apostrophes. */
1877  var reApos = RegExp(rsApos, 'g');
1878
1879  /**
1880   * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
1881   * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
1882   */
1883  var reComboMark = RegExp(rsCombo, 'g');
1884
1885  /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
1886  var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
1887
1888  /** Used to match complex or compound words. */
1889  var reUnicodeWord = RegExp([
1890    rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
1891    rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
1892    rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
1893    rsUpper + '+' + rsOptContrUpper,
1894    rsOrdUpper,
1895    rsOrdLower,
1896    rsDigits,
1897    rsEmoji
1898  ].join('|'), 'g');
1899
1900  /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
1901  var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange  + rsComboRange + rsVarRange + ']');
1902
1903  /** Used to detect strings that need a more robust regexp to match words. */
1904  var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
1905
1906  /** Used to assign default `context` object properties. */
1907  var contextProps = [
1908    'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array',
1909    'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object',
1910    'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array',
1911    'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
1912    '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout'
1913  ];
1914
1915  /** Used to make template sourceURLs easier to identify. */
1916  var templateCounter = -1;
1917
1918  /** Used to identify `toStringTag` values of typed arrays. */
1919  var typedArrayTags = {};
1920  typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
1921  typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
1922  typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
1923  typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
1924  typedArrayTags[uint32Tag] = true;
1925  typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
1926  typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
vendor: 5,923 bytes, lines 1927-2061
1927  typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
1928  typedArrayTags[errorTag] = typedArrayTags[funcTag] =
1929  typedArrayTags[mapTag] = typedArrayTags[numberTag] =
1930  typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
1931  typedArrayTags[setTag] = typedArrayTags[stringTag] =
1932  typedArrayTags[weakMapTag] = false;
1933
1934  /** Used to identify `toStringTag` values supported by `_.clone`. */
1935  var cloneableTags = {};
1936  cloneableTags[argsTag] = cloneableTags[arrayTag] =
1937  cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
1938  cloneableTags[boolTag] = cloneableTags[dateTag] =
1939  cloneableTags[float32Tag] = cloneableTags[float64Tag] =
1940  cloneableTags[int8Tag] = cloneableTags[int16Tag] =
1941  cloneableTags[int32Tag] = cloneableTags[mapTag] =
1942  cloneableTags[numberTag] = cloneableTags[objectTag] =
1943  cloneableTags[regexpTag] = cloneableTags[setTag] =
1944  cloneableTags[stringTag] = cloneableTags[symbolTag] =
1945  cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
1946  cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
1947  cloneableTags[errorTag] = cloneableTags[funcTag] =
1948  cloneableTags[weakMapTag] = false;
1949
1950  /** Used to map Latin Unicode letters to basic Latin letters. */
1951  var deburredLetters = {
1952    // Latin-1 Supplement block.
1953    '\xc0': 'A',  '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
1954    '\xe0': 'a',  '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
1955    '\xc7': 'C',  '\xe7': 'c',
1956    '\xd0': 'D',  '\xf0': 'd',
1957    '\xc8': 'E',  '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
1958    '\xe8': 'e',  '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
1959    '\xcc': 'I',  '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
1960    '\xec': 'i',  '\xed': 'i', '\xee': 'i', '\xef': 'i',
1961    '\xd1': 'N',  '\xf1': 'n',
1962    '\xd2': 'O',  '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
1963    '\xf2': 'o',  '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
1964    '\xd9': 'U',  '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
1965    '\xf9': 'u',  '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
1966    '\xdd': 'Y',  '\xfd': 'y', '\xff': 'y',
1967    '\xc6': 'Ae', '\xe6': 'ae',
1968    '\xde': 'Th', '\xfe': 'th',
1969    '\xdf': 'ss',
1970    // Latin Extended-A block.
1971    '\u0100': 'A',  '\u0102': 'A', '\u0104': 'A',
1972    '\u0101': 'a',  '\u0103': 'a', '\u0105': 'a',
1973    '\u0106': 'C',  '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
1974    '\u0107': 'c',  '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
1975    '\u010e': 'D',  '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
1976    '\u0112': 'E',  '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
1977    '\u0113': 'e',  '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
1978    '\u011c': 'G',  '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
1979    '\u011d': 'g',  '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
1980    '\u0124': 'H',  '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
1981    '\u0128': 'I',  '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
1982    '\u0129': 'i',  '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
1983    '\u0134': 'J',  '\u0135': 'j',
1984    '\u0136': 'K',  '\u0137': 'k', '\u0138': 'k',
1985    '\u0139': 'L',  '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
1986    '\u013a': 'l',  '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
1987    '\u0143': 'N',  '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
1988    '\u0144': 'n',  '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
1989    '\u014c': 'O',  '\u014e': 'O', '\u0150': 'O',
1990    '\u014d': 'o',  '\u014f': 'o', '\u0151': 'o',
1991    '\u0154': 'R',  '\u0156': 'R', '\u0158': 'R',
1992    '\u0155': 'r',  '\u0157': 'r', '\u0159': 'r',
1993    '\u015a': 'S',  '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
1994    '\u015b': 's',  '\u015d': 's', '\u015f': 's', '\u0161': 's',
1995    '\u0162': 'T',  '\u0164': 'T', '\u0166': 'T',
1996    '\u0163': 't',  '\u0165': 't', '\u0167': 't',
1997    '\u0168': 'U',  '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
1998    '\u0169': 'u',  '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
1999    '\u0174': 'W',  '\u0175': 'w',
2000    '\u0176': 'Y',  '\u0177': 'y', '\u0178': 'Y',
2001    '\u0179': 'Z',  '\u017b': 'Z', '\u017d': 'Z',
2002    '\u017a': 'z',  '\u017c': 'z', '\u017e': 'z',
2003    '\u0132': 'IJ', '\u0133': 'ij',
2004    '\u0152': 'Oe', '\u0153': 'oe',
2005    '\u0149': "'n", '\u017f': 's'
2006  };
2007
2008  /** Used to map characters to HTML entities. */
2009  var htmlEscapes = {
2010    '&': '&amp;',
2011    '<': '&lt;',
2012    '>': '&gt;',
2013    '"': '&quot;',
2014    "'": '&#39;'
2015  };
2016
2017  /** Used to map HTML entities to characters. */
2018  var htmlUnescapes = {
2019    '&amp;': '&',
2020    '&lt;': '<',
2021    '&gt;': '>',
2022    '&quot;': '"',
2023    '&#39;': "'"
2024  };
2025
2026  /** Used to escape characters for inclusion in compiled string literals. */
2027  var stringEscapes = {
2028    '\\': '\\',
2029    "'": "'",
2030    '\n': 'n',
2031    '\r': 'r',
2032    '\u2028': 'u2028',
2033    '\u2029': 'u2029'
2034  };
2035
2036  /** Built-in method references without a dependency on `root`. */
2037  var freeParseFloat = parseFloat,
2038      freeParseInt = parseInt;
2039
2040  /** Detect free variable `global` from Node.js. */
2041  var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
2042
2043  /** Detect free variable `self`. */
2044  var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
2045
2046  /** Used as a reference to the global object. */
2047  var root = freeGlobal || freeSelf || Function('return this')();
2048
2049  /** Detect free variable `exports`. */
2050  var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports;
2051
2052  /** Detect free variable `module`. */
2053  var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module;
2054
2055  /** Detect the popular CommonJS extension `module.exports`. */
2056  var moduleExports = freeModule && freeModule.exports === freeExports;
2057
2058  /** Detect free variable `process` from Node.js. */
2059  var freeProcess = moduleExports && freeGlobal.process;
2060
2061  /** Used to access faster Node.js helpers. */
vendor: 8,860 bytes, lines 2062-2355
2062  var nodeUtil = (function() {
2063    try {
2064      // Use `util.types` for Node.js 10+.
2065      var types = freeModule && freeModule.require && freeModule.require('util').types;
2066
2067      if (types) {
2068        return types;
2069      }
2070
2071      // Legacy `process.binding('util')` for Node.js < 10.
2072      return freeProcess && freeProcess.binding && freeProcess.binding('util');
2073    } catch (e) {}
2074  }());
2075
2076  /* Node.js helper references. */
2077  var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer,
2078      nodeIsDate = nodeUtil && nodeUtil.isDate,
2079      nodeIsMap = nodeUtil && nodeUtil.isMap,
2080      nodeIsRegExp = nodeUtil && nodeUtil.isRegExp,
2081      nodeIsSet = nodeUtil && nodeUtil.isSet,
2082      nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
2083
2084  /*--------------------------------------------------------------------------*/
2085
2086  /**
2087   * A faster alternative to `Function#apply`, this function invokes `func`
2088   * with the `this` binding of `thisArg` and the arguments of `args`.
2089   *
2090   * @private
2091   * @param {Function} func The function to invoke.
2092   * @param {*} thisArg The `this` binding of `func`.
2093   * @param {Array} args The arguments to invoke `func` with.
2094   * @returns {*} Returns the result of `func`.
2095   */
2096  function apply(func, thisArg, args) {
2097    switch (args.length) {
2098      case 0: return func.call(thisArg);
2099      case 1: return func.call(thisArg, args[0]);
2100      case 2: return func.call(thisArg, args[0], args[1]);
2101      case 3: return func.call(thisArg, args[0], args[1], args[2]);
2102    }
2103    return func.apply(thisArg, args);
2104  }
2105
2106  /**
2107   * A specialized version of `baseAggregator` for arrays.
2108   *
2109   * @private
2110   * @param {Array} [array] The array to iterate over.
2111   * @param {Function} setter The function to set `accumulator` values.
2112   * @param {Function} iteratee The iteratee to transform keys.
2113   * @param {Object} accumulator The initial aggregated object.
2114   * @returns {Function} Returns `accumulator`.
2115   */
2116  function arrayAggregator(array, setter, iteratee, accumulator) {
2117    var index = -1,
2118        length = array == null ? 0 : array.length;
2119
2120    while (++index < length) {
2121      var value = array[index];
2122      setter(accumulator, value, iteratee(value), array);
2123    }
2124    return accumulator;
2125  }
2126
2127  /**
2128   * A specialized version of `_.forEach` for arrays without support for
2129   * iteratee shorthands.
2130   *
2131   * @private
2132   * @param {Array} [array] The array to iterate over.
2133   * @param {Function} iteratee The function invoked per iteration.
2134   * @returns {Array} Returns `array`.
2135   */
2136  function arrayEach(array, iteratee) {
2137    var index = -1,
2138        length = array == null ? 0 : array.length;
2139
2140    while (++index < length) {
2141      if (iteratee(array[index], index, array) === false) {
2142        break;
2143      }
2144    }
2145    return array;
2146  }
2147
2148  /**
2149   * A specialized version of `_.forEachRight` for arrays without support for
2150   * iteratee shorthands.
2151   *
2152   * @private
2153   * @param {Array} [array] The array to iterate over.
2154   * @param {Function} iteratee The function invoked per iteration.
2155   * @returns {Array} Returns `array`.
2156   */
2157  function arrayEachRight(array, iteratee) {
2158    var length = array == null ? 0 : array.length;
2159
2160    while (length--) {
2161      if (iteratee(array[length], length, array) === false) {
2162        break;
2163      }
2164    }
2165    return array;
2166  }
2167
2168  /**
2169   * A specialized version of `_.every` for arrays without support for
2170   * iteratee shorthands.
2171   *
2172   * @private
2173   * @param {Array} [array] The array to iterate over.
2174   * @param {Function} predicate The function invoked per iteration.
2175   * @returns {boolean} Returns `true` if all elements pass the predicate check,
2176   *  else `false`.
2177   */
2178  function arrayEvery(array, predicate) {
2179    var index = -1,
2180        length = array == null ? 0 : array.length;
2181
2182    while (++index < length) {
2183      if (!predicate(array[index], index, array)) {
2184        return false;
2185      }
2186    }
2187    return true;
2188  }
2189
2190  /**
2191   * A specialized version of `_.filter` for arrays without support for
2192   * iteratee shorthands.
2193   *
2194   * @private
2195   * @param {Array} [array] The array to iterate over.
2196   * @param {Function} predicate The function invoked per iteration.
2197   * @returns {Array} Returns the new filtered array.
2198   */
2199  function arrayFilter(array, predicate) {
2200    var index = -1,
2201        length = array == null ? 0 : array.length,
2202        resIndex = 0,
2203        result = [];
2204
2205    while (++index < length) {
2206      var value = array[index];
2207      if (predicate(value, index, array)) {
2208        result[resIndex++] = value;
2209      }
2210    }
2211    return result;
2212  }
2213
2214  /**
2215   * A specialized version of `_.includes` for arrays without support for
2216   * specifying an index to search from.
2217   *
2218   * @private
2219   * @param {Array} [array] The array to inspect.
2220   * @param {*} target The value to search for.
2221   * @returns {boolean} Returns `true` if `target` is found, else `false`.
2222   */
2223  function arrayIncludes(array, value) {
2224    var length = array == null ? 0 : array.length;
2225    return !!length && baseIndexOf(array, value, 0) > -1;
2226  }
2227
2228  /**
2229   * This function is like `arrayIncludes` except that it accepts a comparator.
2230   *
2231   * @private
2232   * @param {Array} [array] The array to inspect.
2233   * @param {*} target The value to search for.
2234   * @param {Function} comparator The comparator invoked per element.
2235   * @returns {boolean} Returns `true` if `target` is found, else `false`.
2236   */
2237  function arrayIncludesWith(array, value, comparator) {
2238    var index = -1,
2239        length = array == null ? 0 : array.length;
2240
2241    while (++index < length) {
2242      if (comparator(value, array[index])) {
2243        return true;
2244      }
2245    }
2246    return false;
2247  }
2248
2249  /**
2250   * A specialized version of `_.map` for arrays without support for iteratee
2251   * shorthands.
2252   *
2253   * @private
2254   * @param {Array} [array] The array to iterate over.
2255   * @param {Function} iteratee The function invoked per iteration.
2256   * @returns {Array} Returns the new mapped array.
2257   */
2258  function arrayMap(array, iteratee) {
2259    var index = -1,
2260        length = array == null ? 0 : array.length,
2261        result = Array(length);
2262
2263    while (++index < length) {
2264      result[index] = iteratee(array[index], index, array);
2265    }
2266    return result;
2267  }
2268
2269  /**
2270   * Appends the elements of `values` to `array`.
2271   *
2272   * @private
2273   * @param {Array} array The array to modify.
2274   * @param {Array} values The values to append.
2275   * @returns {Array} Returns `array`.
2276   */
2277  function arrayPush(array, values) {
2278    var index = -1,
2279        length = values.length,
2280        offset = array.length;
2281
2282    while (++index < length) {
2283      array[offset + index] = values[index];
2284    }
2285    return array;
2286  }
2287
2288  /**
2289   * A specialized version of `_.reduce` for arrays without support for
2290   * iteratee shorthands.
2291   *
2292   * @private
2293   * @param {Array} [array] The array to iterate over.
2294   * @param {Function} iteratee The function invoked per iteration.
2295   * @param {*} [accumulator] The initial value.
2296   * @param {boolean} [initAccum] Specify using the first element of `array` as
2297   *  the initial value.
2298   * @returns {*} Returns the accumulated value.
2299   */
2300  function arrayReduce(array, iteratee, accumulator, initAccum) {
2301    var index = -1,
2302        length = array == null ? 0 : array.length;
2303
2304    if (initAccum && length) {
2305      accumulator = array[++index];
2306    }
2307    while (++index < length) {
2308      accumulator = iteratee(accumulator, array[index], index, array);
2309    }
2310    return accumulator;
2311  }
2312
2313  /**
2314   * A specialized version of `_.reduceRight` for arrays without support for
2315   * iteratee shorthands.
2316   *
2317   * @private
2318   * @param {Array} [array] The array to iterate over.
2319   * @param {Function} iteratee The function invoked per iteration.
2320   * @param {*} [accumulator] The initial value.
2321   * @param {boolean} [initAccum] Specify using the last element of `array` as
2322   *  the initial value.
2323   * @returns {*} Returns the accumulated value.
2324   */
2325  function arrayReduceRight(array, iteratee, accumulator, initAccum) {
2326    var length = array == null ? 0 : array.length;
2327    if (initAccum && length) {
2328      accumulator = array[--length];
2329    }
2330    while (length--) {
2331      accumulator = iteratee(accumulator, array[length], length, array);
2332    }
2333    return accumulator;
2334  }
2335
2336  /**
2337   * A specialized version of `_.some` for arrays without support for iteratee
2338   * shorthands.
2339   *
2340   * @private
2341   * @param {Array} [array] The array to iterate over.
2342   * @param {Function} predicate The function invoked per iteration.
2343   * @returns {boolean} Returns `true` if any element passes the predicate check,
2344   *  else `false`.
2345   */
2346  function arraySome(array, predicate) {
2347    var index = -1,
2348        length = array == null ? 0 : array.length;
2349
2350    while (++index < length) {
2351      if (predicate(array[index], index, array)) {
2352        return true;
2353      }
2354    }
2355    return false;
vendor: 12,899 bytes, lines 2356-2793
2356  }
2357
2358  /**
2359   * Gets the size of an ASCII `string`.
2360   *
2361   * @private
2362   * @param {string} string The string inspect.
2363   * @returns {number} Returns the string size.
2364   */
2365  var asciiSize = baseProperty('length');
2366
2367  /**
2368   * Converts an ASCII `string` to an array.
2369   *
2370   * @private
2371   * @param {string} string The string to convert.
2372   * @returns {Array} Returns the converted array.
2373   */
2374  function asciiToArray(string) {
2375    return string.split('');
2376  }
2377
2378  /**
2379   * Splits an ASCII `string` into an array of its words.
2380   *
2381   * @private
2382   * @param {string} The string to inspect.
2383   * @returns {Array} Returns the words of `string`.
2384   */
2385  function asciiWords(string) {
2386    return string.match(reAsciiWord) || [];
2387  }
2388
2389  /**
2390   * The base implementation of methods like `_.findKey` and `_.findLastKey`,
2391   * without support for iteratee shorthands, which iterates over `collection`
2392   * using `eachFunc`.
2393   *
2394   * @private
2395   * @param {Array|Object} collection The collection to inspect.
2396   * @param {Function} predicate The function invoked per iteration.
2397   * @param {Function} eachFunc The function to iterate over `collection`.
2398   * @returns {*} Returns the found element or its key, else `undefined`.
2399   */
2400  function baseFindKey(collection, predicate, eachFunc) {
2401    var result;
2402    eachFunc(collection, function(value, key, collection) {
2403      if (predicate(value, key, collection)) {
2404        result = key;
2405        return false;
2406      }
2407    });
2408    return result;
2409  }
2410
2411  /**
2412   * The base implementation of `_.findIndex` and `_.findLastIndex` without
2413   * support for iteratee shorthands.
2414   *
2415   * @private
2416   * @param {Array} array The array to inspect.
2417   * @param {Function} predicate The function invoked per iteration.
2418   * @param {number} fromIndex The index to search from.
2419   * @param {boolean} [fromRight] Specify iterating from right to left.
2420   * @returns {number} Returns the index of the matched value, else `-1`.
2421   */
2422  function baseFindIndex(array, predicate, fromIndex, fromRight) {
2423    var length = array.length,
2424        index = fromIndex + (fromRight ? 1 : -1);
2425
2426    while ((fromRight ? index-- : ++index < length)) {
2427      if (predicate(array[index], index, array)) {
2428        return index;
2429      }
2430    }
2431    return -1;
2432  }
2433
2434  /**
2435   * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
2436   *
2437   * @private
2438   * @param {Array} array The array to inspect.
2439   * @param {*} value The value to search for.
2440   * @param {number} fromIndex The index to search from.
2441   * @returns {number} Returns the index of the matched value, else `-1`.
2442   */
2443  function baseIndexOf(array, value, fromIndex) {
2444    return value === value
2445      ? strictIndexOf(array, value, fromIndex)
2446      : baseFindIndex(array, baseIsNaN, fromIndex);
2447  }
2448
2449  /**
2450   * This function is like `baseIndexOf` except that it accepts a comparator.
2451   *
2452   * @private
2453   * @param {Array} array The array to inspect.
2454   * @param {*} value The value to search for.
2455   * @param {number} fromIndex The index to search from.
2456   * @param {Function} comparator The comparator invoked per element.
2457   * @returns {number} Returns the index of the matched value, else `-1`.
2458   */
2459  function baseIndexOfWith(array, value, fromIndex, comparator) {
2460    var index = fromIndex - 1,
2461        length = array.length;
2462
2463    while (++index < length) {
2464      if (comparator(array[index], value)) {
2465        return index;
2466      }
2467    }
2468    return -1;
2469  }
2470
2471  /**
2472   * The base implementation of `_.isNaN` without support for number objects.
2473   *
2474   * @private
2475   * @param {*} value The value to check.
2476   * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
2477   */
2478  function baseIsNaN(value) {
2479    return value !== value;
2480  }
2481
2482  /**
2483   * The base implementation of `_.mean` and `_.meanBy` without support for
2484   * iteratee shorthands.
2485   *
2486   * @private
2487   * @param {Array} array The array to iterate over.
2488   * @param {Function} iteratee The function invoked per iteration.
2489   * @returns {number} Returns the mean.
2490   */
2491  function baseMean(array, iteratee) {
2492    var length = array == null ? 0 : array.length;
2493    return length ? (baseSum(array, iteratee) / length) : NAN;
2494  }
2495
2496  /**
2497   * The base implementation of `_.property` without support for deep paths.
2498   *
2499   * @private
2500   * @param {string} key The key of the property to get.
2501   * @returns {Function} Returns the new accessor function.
2502   */
2503  function baseProperty(key) {
2504    return function(object) {
2505      return object == null ? undefined : object[key];
2506    };
2507  }
2508
2509  /**
2510   * The base implementation of `_.propertyOf` without support for deep paths.
2511   *
2512   * @private
2513   * @param {Object} object The object to query.
2514   * @returns {Function} Returns the new accessor function.
2515   */
2516  function basePropertyOf(object) {
2517    return function(key) {
2518      return object == null ? undefined : object[key];
2519    };
2520  }
2521
2522  /**
2523   * The base implementation of `_.reduce` and `_.reduceRight`, without support
2524   * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
2525   *
2526   * @private
2527   * @param {Array|Object} collection The collection to iterate over.
2528   * @param {Function} iteratee The function invoked per iteration.
2529   * @param {*} accumulator The initial value.
2530   * @param {boolean} initAccum Specify using the first or last element of
2531   *  `collection` as the initial value.
2532   * @param {Function} eachFunc The function to iterate over `collection`.
2533   * @returns {*} Returns the accumulated value.
2534   */
2535  function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
2536    eachFunc(collection, function(value, index, collection) {
2537      accumulator = initAccum
2538        ? (initAccum = false, value)
2539        : iteratee(accumulator, value, index, collection);
2540    });
2541    return accumulator;
2542  }
2543
2544  /**
2545   * The base implementation of `_.sortBy` which uses `comparer` to define the
2546   * sort order of `array` and replaces criteria objects with their corresponding
2547   * values.
2548   *
2549   * @private
2550   * @param {Array} array The array to sort.
2551   * @param {Function} comparer The function to define sort order.
2552   * @returns {Array} Returns `array`.
2553   */
2554  function baseSortBy(array, comparer) {
2555    var length = array.length;
2556
2557    array.sort(comparer);
2558    while (length--) {
2559      array[length] = array[length].value;
2560    }
2561    return array;
2562  }
2563
2564  /**
2565   * The base implementation of `_.sum` and `_.sumBy` without support for
2566   * iteratee shorthands.
2567   *
2568   * @private
2569   * @param {Array} array The array to iterate over.
2570   * @param {Function} iteratee The function invoked per iteration.
2571   * @returns {number} Returns the sum.
2572   */
2573  function baseSum(array, iteratee) {
2574    var result,
2575        index = -1,
2576        length = array.length;
2577
2578    while (++index < length) {
2579      var current = iteratee(array[index]);
2580      if (current !== undefined) {
2581        result = result === undefined ? current : (result + current);
2582      }
2583    }
2584    return result;
2585  }
2586
2587  /**
2588   * The base implementation of `_.times` without support for iteratee shorthands
2589   * or max array length checks.
2590   *
2591   * @private
2592   * @param {number} n The number of times to invoke `iteratee`.
2593   * @param {Function} iteratee The function invoked per iteration.
2594   * @returns {Array} Returns the array of results.
2595   */
2596  function baseTimes(n, iteratee) {
2597    var index = -1,
2598        result = Array(n);
2599
2600    while (++index < n) {
2601      result[index] = iteratee(index);
2602    }
2603    return result;
2604  }
2605
2606  /**
2607   * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
2608   * of key-value pairs for `object` corresponding to the property names of `props`.
2609   *
2610   * @private
2611   * @param {Object} object The object to query.
2612   * @param {Array} props The property names to get values for.
2613   * @returns {Object} Returns the key-value pairs.
2614   */
2615  function baseToPairs(object, props) {
2616    return arrayMap(props, function(key) {
2617      return [key, object[key]];
2618    });
2619  }
2620
2621  /**
2622   * The base implementation of `_.trim`.
2623   *
2624   * @private
2625   * @param {string} string The string to trim.
2626   * @returns {string} Returns the trimmed string.
2627   */
2628  function baseTrim(string) {
2629    return string
2630      ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '')
2631      : string;
2632  }
2633
2634  /**
2635   * The base implementation of `_.unary` without support for storing metadata.
2636   *
2637   * @private
2638   * @param {Function} func The function to cap arguments for.
2639   * @returns {Function} Returns the new capped function.
2640   */
2641  function baseUnary(func) {
2642    return function(value) {
2643      return func(value);
2644    };
2645  }
2646
2647  /**
2648   * The base implementation of `_.values` and `_.valuesIn` which creates an
2649   * array of `object` property values corresponding to the property names
2650   * of `props`.
2651   *
2652   * @private
2653   * @param {Object} object The object to query.
2654   * @param {Array} props The property names to get values for.
2655   * @returns {Object} Returns the array of property values.
2656   */
2657  function baseValues(object, props) {
2658    return arrayMap(props, function(key) {
2659      return object[key];
2660    });
2661  }
2662
2663  /**
2664   * Checks if a `cache` value for `key` exists.
2665   *
2666   * @private
2667   * @param {Object} cache The cache to query.
2668   * @param {string} key The key of the entry to check.
2669   * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2670   */
2671  function cacheHas(cache, key) {
2672    return cache.has(key);
2673  }
2674
2675  /**
2676   * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
2677   * that is not found in the character symbols.
2678   *
2679   * @private
2680   * @param {Array} strSymbols The string symbols to inspect.
2681   * @param {Array} chrSymbols The character symbols to find.
2682   * @returns {number} Returns the index of the first unmatched string symbol.
2683   */
2684  function charsStartIndex(strSymbols, chrSymbols) {
2685    var index = -1,
2686        length = strSymbols.length;
2687
2688    while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
2689    return index;
2690  }
2691
2692  /**
2693   * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
2694   * that is not found in the character symbols.
2695   *
2696   * @private
2697   * @param {Array} strSymbols The string symbols to inspect.
2698   * @param {Array} chrSymbols The character symbols to find.
2699   * @returns {number} Returns the index of the last unmatched string symbol.
2700   */
2701  function charsEndIndex(strSymbols, chrSymbols) {
2702    var index = strSymbols.length;
2703
2704    while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
2705    return index;
2706  }
2707
2708  /**
2709   * Gets the number of `placeholder` occurrences in `array`.
2710   *
2711   * @private
2712   * @param {Array} array The array to inspect.
2713   * @param {*} placeholder The placeholder to search for.
2714   * @returns {number} Returns the placeholder count.
2715   */
2716  function countHolders(array, placeholder) {
2717    var length = array.length,
2718        result = 0;
2719
2720    while (length--) {
2721      if (array[length] === placeholder) {
2722        ++result;
2723      }
2724    }
2725    return result;
2726  }
2727
2728  /**
2729   * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
2730   * letters to basic Latin letters.
2731   *
2732   * @private
2733   * @param {string} letter The matched letter to deburr.
2734   * @returns {string} Returns the deburred letter.
2735   */
2736  var deburrLetter = basePropertyOf(deburredLetters);
2737
2738  /**
2739   * Used by `_.escape` to convert characters to HTML entities.
2740   *
2741   * @private
2742   * @param {string} chr The matched character to escape.
2743   * @returns {string} Returns the escaped character.
2744   */
2745  var escapeHtmlChar = basePropertyOf(htmlEscapes);
2746
2747  /**
2748   * Used by `_.template` to escape characters for inclusion in compiled string literals.
2749   *
2750   * @private
2751   * @param {string} chr The matched character to escape.
2752   * @returns {string} Returns the escaped character.
2753   */
2754  function escapeStringChar(chr) {
2755    return '\\' + stringEscapes[chr];
2756  }
2757
2758  /**
2759   * Gets the value at `key` of `object`.
2760   *
2761   * @private
2762   * @param {Object} [object] The object to query.
2763   * @param {string} key The key of the property to get.
2764   * @returns {*} Returns the property value.
2765   */
2766  function getValue(object, key) {
2767    return object == null ? undefined : object[key];
2768  }
2769
2770  /**
2771   * Checks if `string` contains Unicode symbols.
2772   *
2773   * @private
2774   * @param {string} string The string to inspect.
2775   * @returns {boolean} Returns `true` if a symbol is found, else `false`.
2776   */
2777  function hasUnicode(string) {
2778    return reHasUnicode.test(string);
2779  }
2780
2781  /**
2782   * Checks if `string` contains a word composed of Unicode symbols.
2783   *
2784   * @private
2785   * @param {string} string The string to inspect.
2786   * @returns {boolean} Returns `true` if a word is found, else `false`.
2787   */
2788  function hasUnicodeWord(string) {
2789    return reHasUnicodeWord.test(string);
2790  }
2791
2792  /**
2793   * Converts `iterator` to an array.
vendor: 8,214 bytes, lines 2794-3103
2794   *
2795   * @private
2796   * @param {Object} iterator The iterator to convert.
2797   * @returns {Array} Returns the converted array.
2798   */
2799  function iteratorToArray(iterator) {
2800    var data,
2801        result = [];
2802
2803    while (!(data = iterator.next()).done) {
2804      result.push(data.value);
2805    }
2806    return result;
2807  }
2808
2809  /**
2810   * Converts `map` to its key-value pairs.
2811   *
2812   * @private
2813   * @param {Object} map The map to convert.
2814   * @returns {Array} Returns the key-value pairs.
2815   */
2816  function mapToArray(map) {
2817    var index = -1,
2818        result = Array(map.size);
2819
2820    map.forEach(function(value, key) {
2821      result[++index] = [key, value];
2822    });
2823    return result;
2824  }
2825
2826  /**
2827   * Creates a unary function that invokes `func` with its argument transformed.
2828   *
2829   * @private
2830   * @param {Function} func The function to wrap.
2831   * @param {Function} transform The argument transform.
2832   * @returns {Function} Returns the new function.
2833   */
2834  function overArg(func, transform) {
2835    return function(arg) {
2836      return func(transform(arg));
2837    };
2838  }
2839
2840  /**
2841   * Replaces all `placeholder` elements in `array` with an internal placeholder
2842   * and returns an array of their indexes.
2843   *
2844   * @private
2845   * @param {Array} array The array to modify.
2846   * @param {*} placeholder The placeholder to replace.
2847   * @returns {Array} Returns the new array of placeholder indexes.
2848   */
2849  function replaceHolders(array, placeholder) {
2850    var index = -1,
2851        length = array.length,
2852        resIndex = 0,
2853        result = [];
2854
2855    while (++index < length) {
2856      var value = array[index];
2857      if (value === placeholder || value === PLACEHOLDER) {
2858        array[index] = PLACEHOLDER;
2859        result[resIndex++] = index;
2860      }
2861    }
2862    return result;
2863  }
2864
2865  /**
2866   * Converts `set` to an array of its values.
2867   *
2868   * @private
2869   * @param {Object} set The set to convert.
2870   * @returns {Array} Returns the values.
2871   */
2872  function setToArray(set) {
2873    var index = -1,
2874        result = Array(set.size);
2875
2876    set.forEach(function(value) {
2877      result[++index] = value;
2878    });
2879    return result;
2880  }
2881
2882  /**
2883   * Converts `set` to its value-value pairs.
2884   *
2885   * @private
2886   * @param {Object} set The set to convert.
2887   * @returns {Array} Returns the value-value pairs.
2888   */
2889  function setToPairs(set) {
2890    var index = -1,
2891        result = Array(set.size);
2892
2893    set.forEach(function(value) {
2894      result[++index] = [value, value];
2895    });
2896    return result;
2897  }
2898
2899  /**
2900   * A specialized version of `_.indexOf` which performs strict equality
2901   * comparisons of values, i.e. `===`.
2902   *
2903   * @private
2904   * @param {Array} array The array to inspect.
2905   * @param {*} value The value to search for.
2906   * @param {number} fromIndex The index to search from.
2907   * @returns {number} Returns the index of the matched value, else `-1`.
2908   */
2909  function strictIndexOf(array, value, fromIndex) {
2910    var index = fromIndex - 1,
2911        length = array.length;
2912
2913    while (++index < length) {
2914      if (array[index] === value) {
2915        return index;
2916      }
2917    }
2918    return -1;
2919  }
2920
2921  /**
2922   * A specialized version of `_.lastIndexOf` which performs strict equality
2923   * comparisons of values, i.e. `===`.
2924   *
2925   * @private
2926   * @param {Array} array The array to inspect.
2927   * @param {*} value The value to search for.
2928   * @param {number} fromIndex The index to search from.
2929   * @returns {number} Returns the index of the matched value, else `-1`.
2930   */
2931  function strictLastIndexOf(array, value, fromIndex) {
2932    var index = fromIndex + 1;
2933    while (index--) {
2934      if (array[index] === value) {
2935        return index;
2936      }
2937    }
2938    return index;
2939  }
2940
2941  /**
2942   * Gets the number of symbols in `string`.
2943   *
2944   * @private
2945   * @param {string} string The string to inspect.
2946   * @returns {number} Returns the string size.
2947   */
2948  function stringSize(string) {
2949    return hasUnicode(string)
2950      ? unicodeSize(string)
2951      : asciiSize(string);
2952  }
2953
2954  /**
2955   * Converts `string` to an array.
2956   *
2957   * @private
2958   * @param {string} string The string to convert.
2959   * @returns {Array} Returns the converted array.
2960   */
2961  function stringToArray(string) {
2962    return hasUnicode(string)
2963      ? unicodeToArray(string)
2964      : asciiToArray(string);
2965  }
2966
2967  /**
2968   * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
2969   * character of `string`.
2970   *
2971   * @private
2972   * @param {string} string The string to inspect.
2973   * @returns {number} Returns the index of the last non-whitespace character.
2974   */
2975  function trimmedEndIndex(string) {
2976    var index = string.length;
2977
2978    while (index-- && reWhitespace.test(string.charAt(index))) {}
2979    return index;
2980  }
2981
2982  /**
2983   * Used by `_.unescape` to convert HTML entities to characters.
2984   *
2985   * @private
2986   * @param {string} chr The matched character to unescape.
2987   * @returns {string} Returns the unescaped character.
2988   */
2989  var unescapeHtmlChar = basePropertyOf(htmlUnescapes);
2990
2991  /**
2992   * Gets the size of a Unicode `string`.
2993   *
2994   * @private
2995   * @param {string} string The string inspect.
2996   * @returns {number} Returns the string size.
2997   */
2998  function unicodeSize(string) {
2999    var result = reUnicode.lastIndex = 0;
3000    while (reUnicode.test(string)) {
3001      ++result;
3002    }
3003    return result;
3004  }
3005
3006  /**
3007   * Converts a Unicode `string` to an array.
3008   *
3009   * @private
3010   * @param {string} string The string to convert.
3011   * @returns {Array} Returns the converted array.
3012   */
3013  function unicodeToArray(string) {
3014    return string.match(reUnicode) || [];
3015  }
3016
3017  /**
3018   * Splits a Unicode `string` into an array of its words.
3019   *
3020   * @private
3021   * @param {string} The string to inspect.
3022   * @returns {Array} Returns the words of `string`.
3023   */
3024  function unicodeWords(string) {
3025    return string.match(reUnicodeWord) || [];
3026  }
3027
3028  /*--------------------------------------------------------------------------*/
3029
3030  /**
3031   * Create a new pristine `lodash` function using the `context` object.
3032   *
3033   * @static
3034   * @memberOf _
3035   * @since 1.1.0
3036   * @category Util
3037   * @param {Object} [context=root] The context object.
3038   * @returns {Function} Returns a new `lodash` function.
3039   * @example
3040   *
3041   * _.mixin({ 'foo': _.constant('foo') });
3042   *
3043   * var lodash = _.runInContext();
3044   * lodash.mixin({ 'bar': lodash.constant('bar') });
3045   *
3046   * _.isFunction(_.foo);
3047   * // => true
3048   * _.isFunction(_.bar);
3049   * // => false
3050   *
3051   * lodash.isFunction(lodash.foo);
3052   * // => false
3053   * lodash.isFunction(lodash.bar);
3054   * // => true
3055   *
3056   * // Create a suped-up `defer` in Node.js.
3057   * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
3058   */
3059  var runInContext = (function runInContext(context) {
3060    context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps));
3061
3062    /** Built-in constructor references. */
3063    var Array = context.Array,
3064        Date = context.Date,
3065        Error = context.Error,
3066        Function = context.Function,
3067        Math = context.Math,
3068        Object = context.Object,
3069        RegExp = context.RegExp,
3070        String = context.String,
3071        TypeError = context.TypeError;
3072
3073    /** Used for built-in method references. */
3074    var arrayProto = Array.prototype,
3075        funcProto = Function.prototype,
3076        objectProto = Object.prototype;
3077
3078    /** Used to detect overreaching core-js shims. */
3079    var coreJsData = context['__core-js_shared__'];
3080
3081    /** Used to resolve the decompiled source of functions. */
3082    var funcToString = funcProto.toString;
3083
3084    /** Used to check objects for own properties. */
3085    var hasOwnProperty = objectProto.hasOwnProperty;
3086
3087    /** Used to generate unique IDs. */
3088    var idCounter = 0;
3089
3090    /** Used to detect methods masquerading as native. */
3091    var maskSrcKey = (function() {
3092      var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
3093      return uid ? ('Symbol(src)_1.' + uid) : '';
3094    }());
3095
3096    /**
3097     * Used to resolve the
3098     * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
3099     * of values.
3100     */
3101    var nativeObjectToString = objectProto.toString;
3102
3103    /** Used to infer the `Object` constructor. */
vendor: 25,659 bytes, lines 3104-3901
3104    var objectCtorString = funcToString.call(Object);
3105
3106    /** Used to restore the original `_` reference in `_.noConflict`. */
3107    var oldDash = root._;
3108
3109    /** Used to detect if a method is native. */
3110    var reIsNative = RegExp('^' +
3111      funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
3112      .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
3113    );
3114
3115    /** Built-in value references. */
3116    var Buffer = moduleExports ? context.Buffer : undefined,
3117        Symbol = context.Symbol,
3118        Uint8Array = context.Uint8Array,
3119        allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
3120        getPrototype = overArg(Object.getPrototypeOf, Object),
3121        objectCreate = Object.create,
3122        propertyIsEnumerable = objectProto.propertyIsEnumerable,
3123        splice = arrayProto.splice,
3124        spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
3125        symIterator = Symbol ? Symbol.iterator : undefined,
3126        symToStringTag = Symbol ? Symbol.toStringTag : undefined;
3127
3128    var defineProperty = (function() {
3129      try {
3130        var func = getNative(Object, 'defineProperty');
3131        func({}, '', {});
3132        return func;
3133      } catch (e) {}
3134    }());
3135
3136    /** Mocked built-ins. */
3137    var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout,
3138        ctxNow = Date && Date.now !== root.Date.now && Date.now,
3139        ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout;
3140
3141    /* Built-in method references for those with the same name as other `lodash` methods. */
3142    var nativeCeil = Math.ceil,
3143        nativeFloor = Math.floor,
3144        nativeGetSymbols = Object.getOwnPropertySymbols,
3145        nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
3146        nativeIsFinite = context.isFinite,
3147        nativeJoin = arrayProto.join,
3148        nativeKeys = overArg(Object.keys, Object),
3149        nativeMax = Math.max,
3150        nativeMin = Math.min,
3151        nativeNow = Date.now,
3152        nativeParseInt = context.parseInt,
3153        nativeRandom = Math.random,
3154        nativeReverse = arrayProto.reverse;
3155
3156    /* Built-in method references that are verified to be native. */
3157    var DataView = getNative(context, 'DataView'),
3158        Map = getNative(context, 'Map'),
3159        Promise = getNative(context, 'Promise'),
3160        Set = getNative(context, 'Set'),
3161        WeakMap = getNative(context, 'WeakMap'),
3162        nativeCreate = getNative(Object, 'create');
3163
3164    /** Used to store function metadata. */
3165    var metaMap = WeakMap && new WeakMap;
3166
3167    /** Used to lookup unminified function names. */
3168    var realNames = {};
3169
3170    /** Used to detect maps, sets, and weakmaps. */
3171    var dataViewCtorString = toSource(DataView),
3172        mapCtorString = toSource(Map),
3173        promiseCtorString = toSource(Promise),
3174        setCtorString = toSource(Set),
3175        weakMapCtorString = toSource(WeakMap);
3176
3177    /** Used to convert symbols to primitives and strings. */
3178    var symbolProto = Symbol ? Symbol.prototype : undefined,
3179        symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
3180        symbolToString = symbolProto ? symbolProto.toString : undefined;
3181
3182    /*------------------------------------------------------------------------*/
3183
3184    /**
3185     * Creates a `lodash` object which wraps `value` to enable implicit method
3186     * chain sequences. Methods that operate on and return arrays, collections,
3187     * and functions can be chained together. Methods that retrieve a single value
3188     * or may return a primitive value will automatically end the chain sequence
3189     * and return the unwrapped value. Otherwise, the value must be unwrapped
3190     * with `_#value`.
3191     *
3192     * Explicit chain sequences, which must be unwrapped with `_#value`, may be
3193     * enabled using `_.chain`.
3194     *
3195     * The execution of chained methods is lazy, that is, it's deferred until
3196     * `_#value` is implicitly or explicitly called.
3197     *
3198     * Lazy evaluation allows several methods to support shortcut fusion.
3199     * Shortcut fusion is an optimization to merge iteratee calls; this avoids
3200     * the creation of intermediate arrays and can greatly reduce the number of
3201     * iteratee executions. Sections of a chain sequence qualify for shortcut
3202     * fusion if the section is applied to an array and iteratees accept only
3203     * one argument. The heuristic for whether a section qualifies for shortcut
3204     * fusion is subject to change.
3205     *
3206     * Chaining is supported in custom builds as long as the `_#value` method is
3207     * directly or indirectly included in the build.
3208     *
3209     * In addition to lodash methods, wrappers have `Array` and `String` methods.
3210     *
3211     * The wrapper `Array` methods are:
3212     * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
3213     *
3214     * The wrapper `String` methods are:
3215     * `replace` and `split`
3216     *
3217     * The wrapper methods that support shortcut fusion are:
3218     * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
3219     * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
3220     * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
3221     *
3222     * The chainable wrapper methods are:
3223     * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
3224     * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
3225     * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
3226     * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
3227     * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
3228     * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
3229     * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
3230     * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
3231     * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
3232     * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
3233     * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
3234     * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
3235     * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
3236     * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
3237     * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
3238     * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
3239     * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
3240     * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
3241     * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
3242     * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
3243     * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
3244     * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
3245     * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
3246     * `zipObject`, `zipObjectDeep`, and `zipWith`
3247     *
3248     * The wrapper methods that are **not** chainable by default are:
3249     * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
3250     * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
3251     * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
3252     * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
3253     * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
3254     * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
3255     * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
3256     * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
3257     * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
3258     * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
3259     * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
3260     * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
3261     * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
3262     * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
3263     * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
3264     * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
3265     * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
3266     * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
3267     * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
3268     * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
3269     * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
3270     * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
3271     * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
3272     * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
3273     * `upperFirst`, `value`, and `words`
3274     *
3275     * @name _
3276     * @constructor
3277     * @category Seq
3278     * @param {*} value The value to wrap in a `lodash` instance.
3279     * @returns {Object} Returns the new `lodash` wrapper instance.
3280     * @example
3281     *
3282     * function square(n) {
3283     *   return n * n;
3284     * }
3285     *
3286     * var wrapped = _([1, 2, 3]);
3287     *
3288     * // Returns an unwrapped value.
3289     * wrapped.reduce(_.add);
3290     * // => 6
3291     *
3292     * // Returns a wrapped value.
3293     * var squares = wrapped.map(square);
3294     *
3295     * _.isArray(squares);
3296     * // => false
3297     *
3298     * _.isArray(squares.value());
3299     * // => true
3300     */
3301    function lodash(value) {
3302      if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
3303        if (value instanceof LodashWrapper) {
3304          return value;
3305        }
3306        if (hasOwnProperty.call(value, '__wrapped__')) {
3307          return wrapperClone(value);
3308        }
3309      }
3310      return new LodashWrapper(value);
3311    }
3312
3313    /**
3314     * The base implementation of `_.create` without support for assigning
3315     * properties to the created object.
3316     *
3317     * @private
3318     * @param {Object} proto The object to inherit from.
3319     * @returns {Object} Returns the new object.
3320     */
3321    var baseCreate = (function() {
3322      function object() {}
3323      return function(proto) {
3324        if (!isObject(proto)) {
3325          return {};
3326        }
3327        if (objectCreate) {
3328          return objectCreate(proto);
3329        }
3330        object.prototype = proto;
3331        var result = new object;
3332        object.prototype = undefined;
3333        return result;
3334      };
3335    }());
3336
3337    /**
3338     * The function whose prototype chain sequence wrappers inherit from.
3339     *
3340     * @private
3341     */
3342    function baseLodash() {
3343      // No operation performed.
3344    }
3345
3346    /**
3347     * The base constructor for creating `lodash` wrapper objects.
3348     *
3349     * @private
3350     * @param {*} value The value to wrap.
3351     * @param {boolean} [chainAll] Enable explicit method chain sequences.
3352     */
3353    function LodashWrapper(value, chainAll) {
3354      this.__wrapped__ = value;
3355      this.__actions__ = [];
3356      this.__chain__ = !!chainAll;
3357      this.__index__ = 0;
3358      this.__values__ = undefined;
3359    }
3360
3361    /**
3362     * By default, the template delimiters used by lodash are like those in
3363     * embedded Ruby (ERB) as well as ES2015 template strings. Change the
3364     * following template settings to use alternative delimiters.
3365     *
3366     * @static
3367     * @memberOf _
3368     * @type {Object}
3369     */
3370    lodash.templateSettings = {
3371
3372      /**
3373       * Used to detect `data` property values to be HTML-escaped.
3374       *
3375       * @memberOf _.templateSettings
3376       * @type {RegExp}
3377       */
3378      'escape': reEscape,
3379
3380      /**
3381       * Used to detect code to be evaluated.
3382       *
3383       * @memberOf _.templateSettings
3384       * @type {RegExp}
3385       */
3386      'evaluate': reEvaluate,
3387
3388      /**
3389       * Used to detect `data` property values to inject.
3390       *
3391       * @memberOf _.templateSettings
3392       * @type {RegExp}
3393       */
3394      'interpolate': reInterpolate,
3395
3396      /**
3397       * Used to reference the data object in the template text.
3398       *
3399       * @memberOf _.templateSettings
3400       * @type {string}
3401       */
3402      'variable': '',
3403
3404      /**
3405       * Used to import variables into the compiled template.
3406       *
3407       * @memberOf _.templateSettings
3408       * @type {Object}
3409       */
3410      'imports': {
3411
3412        /**
3413         * A reference to the `lodash` function.
3414         *
3415         * @memberOf _.templateSettings.imports
3416         * @type {Function}
3417         */
3418        '_': lodash
3419      }
3420    };
3421
3422    // Ensure wrappers are instances of `baseLodash`.
3423    lodash.prototype = baseLodash.prototype;
3424    lodash.prototype.constructor = lodash;
3425
3426    LodashWrapper.prototype = baseCreate(baseLodash.prototype);
3427    LodashWrapper.prototype.constructor = LodashWrapper;
3428
3429    /*------------------------------------------------------------------------*/
3430
3431    /**
3432     * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
3433     *
3434     * @private
3435     * @constructor
3436     * @param {*} value The value to wrap.
3437     */
3438    function LazyWrapper(value) {
3439      this.__wrapped__ = value;
3440      this.__actions__ = [];
3441      this.__dir__ = 1;
3442      this.__filtered__ = false;
3443      this.__iteratees__ = [];
3444      this.__takeCount__ = MAX_ARRAY_LENGTH;
3445      this.__views__ = [];
3446    }
3447
3448    /**
3449     * Creates a clone of the lazy wrapper object.
3450     *
3451     * @private
3452     * @name clone
3453     * @memberOf LazyWrapper
3454     * @returns {Object} Returns the cloned `LazyWrapper` object.
3455     */
3456    function lazyClone() {
3457      var result = new LazyWrapper(this.__wrapped__);
3458      result.__actions__ = copyArray(this.__actions__);
3459      result.__dir__ = this.__dir__;
3460      result.__filtered__ = this.__filtered__;
3461      result.__iteratees__ = copyArray(this.__iteratees__);
3462      result.__takeCount__ = this.__takeCount__;
3463      result.__views__ = copyArray(this.__views__);
3464      return result;
3465    }
3466
3467    /**
3468     * Reverses the direction of lazy iteration.
3469     *
3470     * @private
3471     * @name reverse
3472     * @memberOf LazyWrapper
3473     * @returns {Object} Returns the new reversed `LazyWrapper` object.
3474     */
3475    function lazyReverse() {
3476      if (this.__filtered__) {
3477        var result = new LazyWrapper(this);
3478        result.__dir__ = -1;
3479        result.__filtered__ = true;
3480      } else {
3481        result = this.clone();
3482        result.__dir__ *= -1;
3483      }
3484      return result;
3485    }
3486
3487    /**
3488     * Extracts the unwrapped value from its lazy wrapper.
3489     *
3490     * @private
3491     * @name value
3492     * @memberOf LazyWrapper
3493     * @returns {*} Returns the unwrapped value.
3494     */
3495    function lazyValue() {
3496      var array = this.__wrapped__.value(),
3497          dir = this.__dir__,
3498          isArr = isArray(array),
3499          isRight = dir < 0,
3500          arrLength = isArr ? array.length : 0,
3501          view = getView(0, arrLength, this.__views__),
3502          start = view.start,
3503          end = view.end,
3504          length = end - start,
3505          index = isRight ? end : (start - 1),
3506          iteratees = this.__iteratees__,
3507          iterLength = iteratees.length,
3508          resIndex = 0,
3509          takeCount = nativeMin(length, this.__takeCount__);
3510
3511      if (!isArr || (!isRight && arrLength == length && takeCount == length)) {
3512        return baseWrapperValue(array, this.__actions__);
3513      }
3514      var result = [];
3515
3516      outer:
3517      while (length-- && resIndex < takeCount) {
3518        index += dir;
3519
3520        var iterIndex = -1,
3521            value = array[index];
3522
3523        while (++iterIndex < iterLength) {
3524          var data = iteratees[iterIndex],
3525              iteratee = data.iteratee,
3526              type = data.type,
3527              computed = iteratee(value);
3528
3529          if (type == LAZY_MAP_FLAG) {
3530            value = computed;
3531          } else if (!computed) {
3532            if (type == LAZY_FILTER_FLAG) {
3533              continue outer;
3534            } else {
3535              break outer;
3536            }
3537          }
3538        }
3539        result[resIndex++] = value;
3540      }
3541      return result;
3542    }
3543
3544    // Ensure `LazyWrapper` is an instance of `baseLodash`.
3545    LazyWrapper.prototype = baseCreate(baseLodash.prototype);
3546    LazyWrapper.prototype.constructor = LazyWrapper;
3547
3548    /*------------------------------------------------------------------------*/
3549
3550    /**
3551     * Creates a hash object.
3552     *
3553     * @private
3554     * @constructor
3555     * @param {Array} [entries] The key-value pairs to cache.
3556     */
3557    function Hash(entries) {
3558      var index = -1,
3559          length = entries == null ? 0 : entries.length;
3560
3561      this.clear();
3562      while (++index < length) {
3563        var entry = entries[index];
3564        this.set(entry[0], entry[1]);
3565      }
3566    }
3567
3568    /**
3569     * Removes all key-value entries from the hash.
3570     *
3571     * @private
3572     * @name clear
3573     * @memberOf Hash
3574     */
3575    function hashClear() {
3576      this.__data__ = nativeCreate ? nativeCreate(null) : {};
3577      this.size = 0;
3578    }
3579
3580    /**
3581     * Removes `key` and its value from the hash.
3582     *
3583     * @private
3584     * @name delete
3585     * @memberOf Hash
3586     * @param {Object} hash The hash to modify.
3587     * @param {string} key The key of the value to remove.
3588     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
3589     */
3590    function hashDelete(key) {
3591      var result = this.has(key) && delete this.__data__[key];
3592      this.size -= result ? 1 : 0;
3593      return result;
3594    }
3595
3596    /**
3597     * Gets the hash value for `key`.
3598     *
3599     * @private
3600     * @name get
3601     * @memberOf Hash
3602     * @param {string} key The key of the value to get.
3603     * @returns {*} Returns the entry value.
3604     */
3605    function hashGet(key) {
3606      var data = this.__data__;
3607      if (nativeCreate) {
3608        var result = data[key];
3609        return result === HASH_UNDEFINED ? undefined : result;
3610      }
3611      return hasOwnProperty.call(data, key) ? data[key] : undefined;
3612    }
3613
3614    /**
3615     * Checks if a hash value for `key` exists.
3616     *
3617     * @private
3618     * @name has
3619     * @memberOf Hash
3620     * @param {string} key The key of the entry to check.
3621     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
3622     */
3623    function hashHas(key) {
3624      var data = this.__data__;
3625      return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);
3626    }
3627
3628    /**
3629     * Sets the hash `key` to `value`.
3630     *
3631     * @private
3632     * @name set
3633     * @memberOf Hash
3634     * @param {string} key The key of the value to set.
3635     * @param {*} value The value to set.
3636     * @returns {Object} Returns the hash instance.
3637     */
3638    function hashSet(key, value) {
3639      var data = this.__data__;
3640      this.size += this.has(key) ? 0 : 1;
3641      data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
3642      return this;
3643    }
3644
3645    // Add methods to `Hash`.
3646    Hash.prototype.clear = hashClear;
3647    Hash.prototype['delete'] = hashDelete;
3648    Hash.prototype.get = hashGet;
3649    Hash.prototype.has = hashHas;
3650    Hash.prototype.set = hashSet;
3651
3652    /*------------------------------------------------------------------------*/
3653
3654    /**
3655     * Creates an list cache object.
3656     *
3657     * @private
3658     * @constructor
3659     * @param {Array} [entries] The key-value pairs to cache.
3660     */
3661    function ListCache(entries) {
3662      var index = -1,
3663          length = entries == null ? 0 : entries.length;
3664
3665      this.clear();
3666      while (++index < length) {
3667        var entry = entries[index];
3668        this.set(entry[0], entry[1]);
3669      }
3670    }
3671
3672    /**
3673     * Removes all key-value entries from the list cache.
3674     *
3675     * @private
3676     * @name clear
3677     * @memberOf ListCache
3678     */
3679    function listCacheClear() {
3680      this.__data__ = [];
3681      this.size = 0;
3682    }
3683
3684    /**
3685     * Removes `key` and its value from the list cache.
3686     *
3687     * @private
3688     * @name delete
3689     * @memberOf ListCache
3690     * @param {string} key The key of the value to remove.
3691     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
3692     */
3693    function listCacheDelete(key) {
3694      var data = this.__data__,
3695          index = assocIndexOf(data, key);
3696
3697      if (index < 0) {
3698        return false;
3699      }
3700      var lastIndex = data.length - 1;
3701      if (index == lastIndex) {
3702        data.pop();
3703      } else {
3704        splice.call(data, index, 1);
3705      }
3706      --this.size;
3707      return true;
3708    }
3709
3710    /**
3711     * Gets the list cache value for `key`.
3712     *
3713     * @private
3714     * @name get
3715     * @memberOf ListCache
3716     * @param {string} key The key of the value to get.
3717     * @returns {*} Returns the entry value.
3718     */
3719    function listCacheGet(key) {
3720      var data = this.__data__,
3721          index = assocIndexOf(data, key);
3722
3723      return index < 0 ? undefined : data[index][1];
3724    }
3725
3726    /**
3727     * Checks if a list cache value for `key` exists.
3728     *
3729     * @private
3730     * @name has
3731     * @memberOf ListCache
3732     * @param {string} key The key of the entry to check.
3733     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
3734     */
3735    function listCacheHas(key) {
3736      return assocIndexOf(this.__data__, key) > -1;
3737    }
3738
3739    /**
3740     * Sets the list cache `key` to `value`.
3741     *
3742     * @private
3743     * @name set
3744     * @memberOf ListCache
3745     * @param {string} key The key of the value to set.
3746     * @param {*} value The value to set.
3747     * @returns {Object} Returns the list cache instance.
3748     */
3749    function listCacheSet(key, value) {
3750      var data = this.__data__,
3751          index = assocIndexOf(data, key);
3752
3753      if (index < 0) {
3754        ++this.size;
3755        data.push([key, value]);
3756      } else {
3757        data[index][1] = value;
3758      }
3759      return this;
3760    }
3761
3762    // Add methods to `ListCache`.
3763    ListCache.prototype.clear = listCacheClear;
3764    ListCache.prototype['delete'] = listCacheDelete;
3765    ListCache.prototype.get = listCacheGet;
3766    ListCache.prototype.has = listCacheHas;
3767    ListCache.prototype.set = listCacheSet;
3768
3769    /*------------------------------------------------------------------------*/
3770
3771    /**
3772     * Creates a map cache object to store key-value pairs.
3773     *
3774     * @private
3775     * @constructor
3776     * @param {Array} [entries] The key-value pairs to cache.
3777     */
3778    function MapCache(entries) {
3779      var index = -1,
3780          length = entries == null ? 0 : entries.length;
3781
3782      this.clear();
3783      while (++index < length) {
3784        var entry = entries[index];
3785        this.set(entry[0], entry[1]);
3786      }
3787    }
3788
3789    /**
3790     * Removes all key-value entries from the map.
3791     *
3792     * @private
3793     * @name clear
3794     * @memberOf MapCache
3795     */
3796    function mapCacheClear() {
3797      this.size = 0;
3798      this.__data__ = {
3799        'hash': new Hash,
3800        'map': new (Map || ListCache),
3801        'string': new Hash
3802      };
3803    }
3804
3805    /**
3806     * Removes `key` and its value from the map.
3807     *
3808     * @private
3809     * @name delete
3810     * @memberOf MapCache
3811     * @param {string} key The key of the value to remove.
3812     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
3813     */
3814    function mapCacheDelete(key) {
3815      var result = getMapData(this, key)['delete'](key);
3816      this.size -= result ? 1 : 0;
3817      return result;
3818    }
3819
3820    /**
3821     * Gets the map value for `key`.
3822     *
3823     * @private
3824     * @name get
3825     * @memberOf MapCache
3826     * @param {string} key The key of the value to get.
3827     * @returns {*} Returns the entry value.
3828     */
3829    function mapCacheGet(key) {
3830      return getMapData(this, key).get(key);
3831    }
3832
3833    /**
3834     * Checks if a map value for `key` exists.
3835     *
3836     * @private
3837     * @name has
3838     * @memberOf MapCache
3839     * @param {string} key The key of the entry to check.
3840     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
3841     */
3842    function mapCacheHas(key) {
3843      return getMapData(this, key).has(key);
3844    }
3845
3846    /**
3847     * Sets the map `key` to `value`.
3848     *
3849     * @private
3850     * @name set
3851     * @memberOf MapCache
3852     * @param {string} key The key of the value to set.
3853     * @param {*} value The value to set.
3854     * @returns {Object} Returns the map cache instance.
3855     */
3856    function mapCacheSet(key, value) {
3857      var data = getMapData(this, key),
3858          size = data.size;
3859
3860      data.set(key, value);
3861      this.size += data.size == size ? 0 : 1;
3862      return this;
3863    }
3864
3865    // Add methods to `MapCache`.
3866    MapCache.prototype.clear = mapCacheClear;
3867    MapCache.prototype['delete'] = mapCacheDelete;
3868    MapCache.prototype.get = mapCacheGet;
3869    MapCache.prototype.has = mapCacheHas;
3870    MapCache.prototype.set = mapCacheSet;
3871
3872    /*------------------------------------------------------------------------*/
3873
3874    /**
3875     *
3876     * Creates an array cache object to store unique values.
3877     *
3878     * @private
3879     * @constructor
3880     * @param {Array} [values] The values to cache.
3881     */
3882    function SetCache(values) {
3883      var index = -1,
3884          length = values == null ? 0 : values.length;
3885
3886      this.__data__ = new MapCache;
3887      while (++index < length) {
3888        this.add(values[index]);
3889      }
3890    }
3891
3892    /**
3893     * Adds `value` to the array cache.
3894     *
3895     * @private
3896     * @name add
3897     * @memberOf SetCache
3898     * @alias push
3899     * @param {*} value The value to cache.
3900     * @returns {Object} Returns the cache instance.
3901     */
vendor: 3,741 bytes, lines 3902-4038
3902    function setCacheAdd(value) {
3903      this.__data__.set(value, HASH_UNDEFINED);
3904      return this;
3905    }
3906
3907    /**
3908     * Checks if `value` is in the array cache.
3909     *
3910     * @private
3911     * @name has
3912     * @memberOf SetCache
3913     * @param {*} value The value to search for.
3914     * @returns {number} Returns `true` if `value` is found, else `false`.
3915     */
3916    function setCacheHas(value) {
3917      return this.__data__.has(value);
3918    }
3919
3920    // Add methods to `SetCache`.
3921    SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
3922    SetCache.prototype.has = setCacheHas;
3923
3924    /*------------------------------------------------------------------------*/
3925
3926    /**
3927     * Creates a stack cache object to store key-value pairs.
3928     *
3929     * @private
3930     * @constructor
3931     * @param {Array} [entries] The key-value pairs to cache.
3932     */
3933    function Stack(entries) {
3934      var data = this.__data__ = new ListCache(entries);
3935      this.size = data.size;
3936    }
3937
3938    /**
3939     * Removes all key-value entries from the stack.
3940     *
3941     * @private
3942     * @name clear
3943     * @memberOf Stack
3944     */
3945    function stackClear() {
3946      this.__data__ = new ListCache;
3947      this.size = 0;
3948    }
3949
3950    /**
3951     * Removes `key` and its value from the stack.
3952     *
3953     * @private
3954     * @name delete
3955     * @memberOf Stack
3956     * @param {string} key The key of the value to remove.
3957     * @returns {boolean} Returns `true` if the entry was removed, else `false`.
3958     */
3959    function stackDelete(key) {
3960      var data = this.__data__,
3961          result = data['delete'](key);
3962
3963      this.size = data.size;
3964      return result;
3965    }
3966
3967    /**
3968     * Gets the stack value for `key`.
3969     *
3970     * @private
3971     * @name get
3972     * @memberOf Stack
3973     * @param {string} key The key of the value to get.
3974     * @returns {*} Returns the entry value.
3975     */
3976    function stackGet(key) {
3977      return this.__data__.get(key);
3978    }
3979
3980    /**
3981     * Checks if a stack value for `key` exists.
3982     *
3983     * @private
3984     * @name has
3985     * @memberOf Stack
3986     * @param {string} key The key of the entry to check.
3987     * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
3988     */
3989    function stackHas(key) {
3990      return this.__data__.has(key);
3991    }
3992
3993    /**
3994     * Sets the stack `key` to `value`.
3995     *
3996     * @private
3997     * @name set
3998     * @memberOf Stack
3999     * @param {string} key The key of the value to set.
4000     * @param {*} value The value to set.
4001     * @returns {Object} Returns the stack cache instance.
4002     */
4003    function stackSet(key, value) {
4004      var data = this.__data__;
4005      if (data instanceof ListCache) {
4006        var pairs = data.__data__;
4007        if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
4008          pairs.push([key, value]);
4009          this.size = ++data.size;
4010          return this;
4011        }
4012        data = this.__data__ = new MapCache(pairs);
4013      }
4014      data.set(key, value);
4015      this.size = data.size;
4016      return this;
4017    }
4018
4019    // Add methods to `Stack`.
4020    Stack.prototype.clear = stackClear;
4021    Stack.prototype['delete'] = stackDelete;
4022    Stack.prototype.get = stackGet;
4023    Stack.prototype.has = stackHas;
4024    Stack.prototype.set = stackSet;
4025
4026    /*------------------------------------------------------------------------*/
4027
4028    /**
4029     * Creates an array of the enumerable property names of the array-like `value`.
4030     *
4031     * @private
4032     * @param {*} value The value to query.
4033     * @param {boolean} inherited Specify returning inherited property names.
4034     * @returns {Array} Returns the array of property names.
4035     */
4036    function arrayLikeKeys(value, inherited) {
4037      var isArr = isArray(value),
4038          isArg = !isArr && isArguments(value),
vendor: 111,524 bytes, lines 4039-7332
4039          isBuff = !isArr && !isArg && isBuffer(value),
4040          isType = !isArr && !isArg && !isBuff && isTypedArray(value),
4041          skipIndexes = isArr || isArg || isBuff || isType,
4042          result = skipIndexes ? baseTimes(value.length, String) : [],
4043          length = result.length;
4044
4045      for (var key in value) {
4046        if ((inherited || hasOwnProperty.call(value, key)) &&
4047            !(skipIndexes && (
4048               // Safari 9 has enumerable `arguments.length` in strict mode.
4049               key == 'length' ||
4050               // Node.js 0.10 has enumerable non-index properties on buffers.
4051               (isBuff && (key == 'offset' || key == 'parent')) ||
4052               // PhantomJS 2 has enumerable non-index properties on typed arrays.
4053               (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
4054               // Skip index properties.
4055               isIndex(key, length)
4056            ))) {
4057          result.push(key);
4058        }
4059      }
4060      return result;
4061    }
4062
4063    /**
4064     * A specialized version of `_.sample` for arrays.
4065     *
4066     * @private
4067     * @param {Array} array The array to sample.
4068     * @returns {*} Returns the random element.
4069     */
4070    function arraySample(array) {
4071      var length = array.length;
4072      return length ? array[baseRandom(0, length - 1)] : undefined;
4073    }
4074
4075    /**
4076     * A specialized version of `_.sampleSize` for arrays.
4077     *
4078     * @private
4079     * @param {Array} array The array to sample.
4080     * @param {number} n The number of elements to sample.
4081     * @returns {Array} Returns the random elements.
4082     */
4083    function arraySampleSize(array, n) {
4084      return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
4085    }
4086
4087    /**
4088     * A specialized version of `_.shuffle` for arrays.
4089     *
4090     * @private
4091     * @param {Array} array The array to shuffle.
4092     * @returns {Array} Returns the new shuffled array.
4093     */
4094    function arrayShuffle(array) {
4095      return shuffleSelf(copyArray(array));
4096    }
4097
4098    /**
4099     * This function is like `assignValue` except that it doesn't assign
4100     * `undefined` values.
4101     *
4102     * @private
4103     * @param {Object} object The object to modify.
4104     * @param {string} key The key of the property to assign.
4105     * @param {*} value The value to assign.
4106     */
4107    function assignMergeValue(object, key, value) {
4108      if ((value !== undefined && !eq(object[key], value)) ||
4109          (value === undefined && !(key in object))) {
4110        baseAssignValue(object, key, value);
4111      }
4112    }
4113
4114    /**
4115     * Assigns `value` to `key` of `object` if the existing value is not equivalent
4116     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
4117     * for equality comparisons.
4118     *
4119     * @private
4120     * @param {Object} object The object to modify.
4121     * @param {string} key The key of the property to assign.
4122     * @param {*} value The value to assign.
4123     */
4124    function assignValue(object, key, value) {
4125      var objValue = object[key];
4126      if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
4127          (value === undefined && !(key in object))) {
4128        baseAssignValue(object, key, value);
4129      }
4130    }
4131
4132    /**
4133     * Gets the index at which the `key` is found in `array` of key-value pairs.
4134     *
4135     * @private
4136     * @param {Array} array The array to inspect.
4137     * @param {*} key The key to search for.
4138     * @returns {number} Returns the index of the matched value, else `-1`.
4139     */
4140    function assocIndexOf(array, key) {
4141      var length = array.length;
4142      while (length--) {
4143        if (eq(array[length][0], key)) {
4144          return length;
4145        }
4146      }
4147      return -1;
4148    }
4149
4150    /**
4151     * Aggregates elements of `collection` on `accumulator` with keys transformed
4152     * by `iteratee` and values set by `setter`.
4153     *
4154     * @private
4155     * @param {Array|Object} collection The collection to iterate over.
4156     * @param {Function} setter The function to set `accumulator` values.
4157     * @param {Function} iteratee The iteratee to transform keys.
4158     * @param {Object} accumulator The initial aggregated object.
4159     * @returns {Function} Returns `accumulator`.
4160     */
4161    function baseAggregator(collection, setter, iteratee, accumulator) {
4162      baseEach(collection, function(value, key, collection) {
4163        setter(accumulator, value, iteratee(value), collection);
4164      });
4165      return accumulator;
4166    }
4167
4168    /**
4169     * The base implementation of `_.assign` without support for multiple sources
4170     * or `customizer` functions.
4171     *
4172     * @private
4173     * @param {Object} object The destination object.
4174     * @param {Object} source The source object.
4175     * @returns {Object} Returns `object`.
4176     */
4177    function baseAssign(object, source) {
4178      return object && copyObject(source, keys(source), object);
4179    }
4180
4181    /**
4182     * The base implementation of `_.assignIn` without support for multiple sources
4183     * or `customizer` functions.
4184     *
4185     * @private
4186     * @param {Object} object The destination object.
4187     * @param {Object} source The source object.
4188     * @returns {Object} Returns `object`.
4189     */
4190    function baseAssignIn(object, source) {
4191      return object && copyObject(source, keysIn(source), object);
4192    }
4193
4194    /**
4195     * The base implementation of `assignValue` and `assignMergeValue` without
4196     * value checks.
4197     *
4198     * @private
4199     * @param {Object} object The object to modify.
4200     * @param {string} key The key of the property to assign.
4201     * @param {*} value The value to assign.
4202     */
4203    function baseAssignValue(object, key, value) {
4204      if (key == '__proto__' && defineProperty) {
4205        defineProperty(object, key, {
4206          'configurable': true,
4207          'enumerable': true,
4208          'value': value,
4209          'writable': true
4210        });
4211      } else {
4212        object[key] = value;
4213      }
4214    }
4215
4216    /**
4217     * The base implementation of `_.at` without support for individual paths.
4218     *
4219     * @private
4220     * @param {Object} object The object to iterate over.
4221     * @param {string[]} paths The property paths to pick.
4222     * @returns {Array} Returns the picked elements.
4223     */
4224    function baseAt(object, paths) {
4225      var index = -1,
4226          length = paths.length,
4227          result = Array(length),
4228          skip = object == null;
4229
4230      while (++index < length) {
4231        result[index] = skip ? undefined : get(object, paths[index]);
4232      }
4233      return result;
4234    }
4235
4236    /**
4237     * The base implementation of `_.clamp` which doesn't coerce arguments.
4238     *
4239     * @private
4240     * @param {number} number The number to clamp.
4241     * @param {number} [lower] The lower bound.
4242     * @param {number} upper The upper bound.
4243     * @returns {number} Returns the clamped number.
4244     */
4245    function baseClamp(number, lower, upper) {
4246      if (number === number) {
4247        if (upper !== undefined) {
4248          number = number <= upper ? number : upper;
4249        }
4250        if (lower !== undefined) {
4251          number = number >= lower ? number : lower;
4252        }
4253      }
4254      return number;
4255    }
4256
4257    /**
4258     * The base implementation of `_.clone` and `_.cloneDeep` which tracks
4259     * traversed objects.
4260     *
4261     * @private
4262     * @param {*} value The value to clone.
4263     * @param {boolean} bitmask The bitmask flags.
4264     *  1 - Deep clone
4265     *  2 - Flatten inherited properties
4266     *  4 - Clone symbols
4267     * @param {Function} [customizer] The function to customize cloning.
4268     * @param {string} [key] The key of `value`.
4269     * @param {Object} [object] The parent object of `value`.
4270     * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
4271     * @returns {*} Returns the cloned value.
4272     */
4273    function baseClone(value, bitmask, customizer, key, object, stack) {
4274      var result,
4275          isDeep = bitmask & CLONE_DEEP_FLAG,
4276          isFlat = bitmask & CLONE_FLAT_FLAG,
4277          isFull = bitmask & CLONE_SYMBOLS_FLAG;
4278
4279      if (customizer) {
4280        result = object ? customizer(value, key, object, stack) : customizer(value);
4281      }
4282      if (result !== undefined) {
4283        return result;
4284      }
4285      if (!isObject(value)) {
4286        return value;
4287      }
4288      var isArr = isArray(value);
4289      if (isArr) {
4290        result = initCloneArray(value);
4291        if (!isDeep) {
4292          return copyArray(value, result);
4293        }
4294      } else {
4295        var tag = getTag(value),
4296            isFunc = tag == funcTag || tag == genTag;
4297
4298        if (isBuffer(value)) {
4299          return cloneBuffer(value, isDeep);
4300        }
4301        if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
4302          result = (isFlat || isFunc) ? {} : initCloneObject(value);
4303          if (!isDeep) {
4304            return isFlat
4305              ? copySymbolsIn(value, baseAssignIn(result, value))
4306              : copySymbols(value, baseAssign(result, value));
4307          }
4308        } else {
4309          if (!cloneableTags[tag]) {
4310            return object ? value : {};
4311          }
4312          result = initCloneByTag(value, tag, isDeep);
4313        }
4314      }
4315      // Check for circular references and return its corresponding clone.
4316      stack || (stack = new Stack);
4317      var stacked = stack.get(value);
4318      if (stacked) {
4319        return stacked;
4320      }
4321      stack.set(value, result);
4322
4323      if (isSet(value)) {
4324        value.forEach(function(subValue) {
4325          result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));
4326        });
4327      } else if (isMap(value)) {
4328        value.forEach(function(subValue, key) {
4329          result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));
4330        });
4331      }
4332
4333      var keysFunc = isFull
4334        ? (isFlat ? getAllKeysIn : getAllKeys)
4335        : (isFlat ? keysIn : keys);
4336
4337      var props = isArr ? undefined : keysFunc(value);
4338      arrayEach(props || value, function(subValue, key) {
4339        if (props) {
4340          key = subValue;
4341          subValue = value[key];
4342        }
4343        // Recursively populate clone (susceptible to call stack limits).
4344        assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
4345      });
4346      return result;
4347    }
4348
4349    /**
4350     * The base implementation of `_.conforms` which doesn't clone `source`.
4351     *
4352     * @private
4353     * @param {Object} source The object of property predicates to conform to.
4354     * @returns {Function} Returns the new spec function.
4355     */
4356    function baseConforms(source) {
4357      var props = keys(source);
4358      return function(object) {
4359        return baseConformsTo(object, source, props);
4360      };
4361    }
4362
4363    /**
4364     * The base implementation of `_.conformsTo` which accepts `props` to check.
4365     *
4366     * @private
4367     * @param {Object} object The object to inspect.
4368     * @param {Object} source The object of property predicates to conform to.
4369     * @returns {boolean} Returns `true` if `object` conforms, else `false`.
4370     */
4371    function baseConformsTo(object, source, props) {
4372      var length = props.length;
4373      if (object == null) {
4374        return !length;
4375      }
4376      object = Object(object);
4377      while (length--) {
4378        var key = props[length],
4379            predicate = source[key],
4380            value = object[key];
4381
4382        if ((value === undefined && !(key in object)) || !predicate(value)) {
4383          return false;
4384        }
4385      }
4386      return true;
4387    }
4388
4389    /**
4390     * The base implementation of `_.delay` and `_.defer` which accepts `args`
4391     * to provide to `func`.
4392     *
4393     * @private
4394     * @param {Function} func The function to delay.
4395     * @param {number} wait The number of milliseconds to delay invocation.
4396     * @param {Array} args The arguments to provide to `func`.
4397     * @returns {number|Object} Returns the timer id or timeout object.
4398     */
4399    function baseDelay(func, wait, args) {
4400      if (typeof func != 'function') {
4401        throw new TypeError(FUNC_ERROR_TEXT);
4402      }
4403      return setTimeout(function() { func.apply(undefined, args); }, wait);
4404    }
4405
4406    /**
4407     * The base implementation of methods like `_.difference` without support
4408     * for excluding multiple arrays or iteratee shorthands.
4409     *
4410     * @private
4411     * @param {Array} array The array to inspect.
4412     * @param {Array} values The values to exclude.
4413     * @param {Function} [iteratee] The iteratee invoked per element.
4414     * @param {Function} [comparator] The comparator invoked per element.
4415     * @returns {Array} Returns the new array of filtered values.
4416     */
4417    function baseDifference(array, values, iteratee, comparator) {
4418      var index = -1,
4419          includes = arrayIncludes,
4420          isCommon = true,
4421          length = array.length,
4422          result = [],
4423          valuesLength = values.length;
4424
4425      if (!length) {
4426        return result;
4427      }
4428      if (iteratee) {
4429        values = arrayMap(values, baseUnary(iteratee));
4430      }
4431      if (comparator) {
4432        includes = arrayIncludesWith;
4433        isCommon = false;
4434      }
4435      else if (values.length >= LARGE_ARRAY_SIZE) {
4436        includes = cacheHas;
4437        isCommon = false;
4438        values = new SetCache(values);
4439      }
4440      outer:
4441      while (++index < length) {
4442        var value = array[index],
4443            computed = iteratee == null ? value : iteratee(value);
4444
4445        value = (comparator || value !== 0) ? value : 0;
4446        if (isCommon && computed === computed) {
4447          var valuesIndex = valuesLength;
4448          while (valuesIndex--) {
4449            if (values[valuesIndex] === computed) {
4450              continue outer;
4451            }
4452          }
4453          result.push(value);
4454        }
4455        else if (!includes(values, computed, comparator)) {
4456          result.push(value);
4457        }
4458      }
4459      return result;
4460    }
4461
4462    /**
4463     * The base implementation of `_.forEach` without support for iteratee shorthands.
4464     *
4465     * @private
4466     * @param {Array|Object} collection The collection to iterate over.
4467     * @param {Function} iteratee The function invoked per iteration.
4468     * @returns {Array|Object} Returns `collection`.
4469     */
4470    var baseEach = createBaseEach(baseForOwn);
4471
4472    /**
4473     * The base implementation of `_.forEachRight` without support for iteratee shorthands.
4474     *
4475     * @private
4476     * @param {Array|Object} collection The collection to iterate over.
4477     * @param {Function} iteratee The function invoked per iteration.
4478     * @returns {Array|Object} Returns `collection`.
4479     */
4480    var baseEachRight = createBaseEach(baseForOwnRight, true);
4481
4482    /**
4483     * The base implementation of `_.every` without support for iteratee shorthands.
4484     *
4485     * @private
4486     * @param {Array|Object} collection The collection to iterate over.
4487     * @param {Function} predicate The function invoked per iteration.
4488     * @returns {boolean} Returns `true` if all elements pass the predicate check,
4489     *  else `false`
4490     */
4491    function baseEvery(collection, predicate) {
4492      var result = true;
4493      baseEach(collection, function(value, index, collection) {
4494        result = !!predicate(value, index, collection);
4495        return result;
4496      });
4497      return result;
4498    }
4499
4500    /**
4501     * The base implementation of methods like `_.max` and `_.min` which accepts a
4502     * `comparator` to determine the extremum value.
4503     *
4504     * @private
4505     * @param {Array} array The array to iterate over.
4506     * @param {Function} iteratee The iteratee invoked per iteration.
4507     * @param {Function} comparator The comparator used to compare values.
4508     * @returns {*} Returns the extremum value.
4509     */
4510    function baseExtremum(array, iteratee, comparator) {
4511      var index = -1,
4512          length = array.length;
4513
4514      while (++index < length) {
4515        var value = array[index],
4516            current = iteratee(value);
4517
4518        if (current != null && (computed === undefined
4519              ? (current === current && !isSymbol(current))
4520              : comparator(current, computed)
4521            )) {
4522          var computed = current,
4523              result = value;
4524        }
4525      }
4526      return result;
4527    }
4528
4529    /**
4530     * The base implementation of `_.fill` without an iteratee call guard.
4531     *
4532     * @private
4533     * @param {Array} array The array to fill.
4534     * @param {*} value The value to fill `array` with.
4535     * @param {number} [start=0] The start position.
4536     * @param {number} [end=array.length] The end position.
4537     * @returns {Array} Returns `array`.
4538     */
4539    function baseFill(array, value, start, end) {
4540      var length = array.length;
4541
4542      start = toInteger(start);
4543      if (start < 0) {
4544        start = -start > length ? 0 : (length + start);
4545      }
4546      end = (end === undefined || end > length) ? length : toInteger(end);
4547      if (end < 0) {
4548        end += length;
4549      }
4550      end = start > end ? 0 : toLength(end);
4551      while (start < end) {
4552        array[start++] = value;
4553      }
4554      return array;
4555    }
4556
4557    /**
4558     * The base implementation of `_.filter` without support for iteratee shorthands.
4559     *
4560     * @private
4561     * @param {Array|Object} collection The collection to iterate over.
4562     * @param {Function} predicate The function invoked per iteration.
4563     * @returns {Array} Returns the new filtered array.
4564     */
4565    function baseFilter(collection, predicate) {
4566      var result = [];
4567      baseEach(collection, function(value, index, collection) {
4568        if (predicate(value, index, collection)) {
4569          result.push(value);
4570        }
4571      });
4572      return result;
4573    }
4574
4575    /**
4576     * The base implementation of `_.flatten` with support for restricting flattening.
4577     *
4578     * @private
4579     * @param {Array} array The array to flatten.
4580     * @param {number} depth The maximum recursion depth.
4581     * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
4582     * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
4583     * @param {Array} [result=[]] The initial result value.
4584     * @returns {Array} Returns the new flattened array.
4585     */
4586    function baseFlatten(array, depth, predicate, isStrict, result) {
4587      var index = -1,
4588          length = array.length;
4589
4590      predicate || (predicate = isFlattenable);
4591      result || (result = []);
4592
4593      while (++index < length) {
4594        var value = array[index];
4595        if (depth > 0 && predicate(value)) {
4596          if (depth > 1) {
4597            // Recursively flatten arrays (susceptible to call stack limits).
4598            baseFlatten(value, depth - 1, predicate, isStrict, result);
4599          } else {
4600            arrayPush(result, value);
4601          }
4602        } else if (!isStrict) {
4603          result[result.length] = value;
4604        }
4605      }
4606      return result;
4607    }
4608
4609    /**
4610     * The base implementation of `baseForOwn` which iterates over `object`
4611     * properties returned by `keysFunc` and invokes `iteratee` for each property.
4612     * Iteratee functions may exit iteration early by explicitly returning `false`.
4613     *
4614     * @private
4615     * @param {Object} object The object to iterate over.
4616     * @param {Function} iteratee The function invoked per iteration.
4617     * @param {Function} keysFunc The function to get the keys of `object`.
4618     * @returns {Object} Returns `object`.
4619     */
4620    var baseFor = createBaseFor();
4621
4622    /**
4623     * This function is like `baseFor` except that it iterates over properties
4624     * in the opposite order.
4625     *
4626     * @private
4627     * @param {Object} object The object to iterate over.
4628     * @param {Function} iteratee The function invoked per iteration.
4629     * @param {Function} keysFunc The function to get the keys of `object`.
4630     * @returns {Object} Returns `object`.
4631     */
4632    var baseForRight = createBaseFor(true);
4633
4634    /**
4635     * The base implementation of `_.forOwn` without support for iteratee shorthands.
4636     *
4637     * @private
4638     * @param {Object} object The object to iterate over.
4639     * @param {Function} iteratee The function invoked per iteration.
4640     * @returns {Object} Returns `object`.
4641     */
4642    function baseForOwn(object, iteratee) {
4643      return object && baseFor(object, iteratee, keys);
4644    }
4645
4646    /**
4647     * The base implementation of `_.forOwnRight` without support for iteratee shorthands.
4648     *
4649     * @private
4650     * @param {Object} object The object to iterate over.
4651     * @param {Function} iteratee The function invoked per iteration.
4652     * @returns {Object} Returns `object`.
4653     */
4654    function baseForOwnRight(object, iteratee) {
4655      return object && baseForRight(object, iteratee, keys);
4656    }
4657
4658    /**
4659     * The base implementation of `_.functions` which creates an array of
4660     * `object` function property names filtered from `props`.
4661     *
4662     * @private
4663     * @param {Object} object The object to inspect.
4664     * @param {Array} props The property names to filter.
4665     * @returns {Array} Returns the function names.
4666     */
4667    function baseFunctions(object, props) {
4668      return arrayFilter(props, function(key) {
4669        return isFunction(object[key]);
4670      });
4671    }
4672
4673    /**
4674     * The base implementation of `_.get` without support for default values.
4675     *
4676     * @private
4677     * @param {Object} object The object to query.
4678     * @param {Array|string} path The path of the property to get.
4679     * @returns {*} Returns the resolved value.
4680     */
4681    function baseGet(object, path) {
4682      path = castPath(path, object);
4683
4684      var index = 0,
4685          length = path.length;
4686
4687      while (object != null && index < length) {
4688        object = object[toKey(path[index++])];
4689      }
4690      return (index && index == length) ? object : undefined;
4691    }
4692
4693    /**
4694     * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
4695     * `keysFunc` and `symbolsFunc` to get the enumerable property names and
4696     * symbols of `object`.
4697     *
4698     * @private
4699     * @param {Object} object The object to query.
4700     * @param {Function} keysFunc The function to get the keys of `object`.
4701     * @param {Function} symbolsFunc The function to get the symbols of `object`.
4702     * @returns {Array} Returns the array of property names and symbols.
4703     */
4704    function baseGetAllKeys(object, keysFunc, symbolsFunc) {
4705      var result = keysFunc(object);
4706      return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
4707    }
4708
4709    /**
4710     * The base implementation of `getTag` without fallbacks for buggy environments.
4711     *
4712     * @private
4713     * @param {*} value The value to query.
4714     * @returns {string} Returns the `toStringTag`.
4715     */
4716    function baseGetTag(value) {
4717      if (value == null) {
4718        return value === undefined ? undefinedTag : nullTag;
4719      }
4720      return (symToStringTag && symToStringTag in Object(value))
4721        ? getRawTag(value)
4722        : objectToString(value);
4723    }
4724
4725    /**
4726     * The base implementation of `_.gt` which doesn't coerce arguments.
4727     *
4728     * @private
4729     * @param {*} value The value to compare.
4730     * @param {*} other The other value to compare.
4731     * @returns {boolean} Returns `true` if `value` is greater than `other`,
4732     *  else `false`.
4733     */
4734    function baseGt(value, other) {
4735      return value > other;
4736    }
4737
4738    /**
4739     * The base implementation of `_.has` without support for deep paths.
4740     *
4741     * @private
4742     * @param {Object} [object] The object to query.
4743     * @param {Array|string} key The key to check.
4744     * @returns {boolean} Returns `true` if `key` exists, else `false`.
4745     */
4746    function baseHas(object, key) {
4747      return object != null && hasOwnProperty.call(object, key);
4748    }
4749
4750    /**
4751     * The base implementation of `_.hasIn` without support for deep paths.
4752     *
4753     * @private
4754     * @param {Object} [object] The object to query.
4755     * @param {Array|string} key The key to check.
4756     * @returns {boolean} Returns `true` if `key` exists, else `false`.
4757     */
4758    function baseHasIn(object, key) {
4759      return object != null && key in Object(object);
4760    }
4761
4762    /**
4763     * The base implementation of `_.inRange` which doesn't coerce arguments.
4764     *
4765     * @private
4766     * @param {number} number The number to check.
4767     * @param {number} start The start of the range.
4768     * @param {number} end The end of the range.
4769     * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
4770     */
4771    function baseInRange(number, start, end) {
4772      return number >= nativeMin(start, end) && number < nativeMax(start, end);
4773    }
4774
4775    /**
4776     * The base implementation of methods like `_.intersection`, without support
4777     * for iteratee shorthands, that accepts an array of arrays to inspect.
4778     *
4779     * @private
4780     * @param {Array} arrays The arrays to inspect.
4781     * @param {Function} [iteratee] The iteratee invoked per element.
4782     * @param {Function} [comparator] The comparator invoked per element.
4783     * @returns {Array} Returns the new array of shared values.
4784     */
4785    function baseIntersection(arrays, iteratee, comparator) {
4786      var includes = comparator ? arrayIncludesWith : arrayIncludes,
4787          length = arrays[0].length,
4788          othLength = arrays.length,
4789          othIndex = othLength,
4790          caches = Array(othLength),
4791          maxLength = Infinity,
4792          result = [];
4793
4794      while (othIndex--) {
4795        var array = arrays[othIndex];
4796        if (othIndex && iteratee) {
4797          array = arrayMap(array, baseUnary(iteratee));
4798        }
4799        maxLength = nativeMin(array.length, maxLength);
4800        caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
4801          ? new SetCache(othIndex && array)
4802          : undefined;
4803      }
4804      array = arrays[0];
4805
4806      var index = -1,
4807          seen = caches[0];
4808
4809      outer:
4810      while (++index < length && result.length < maxLength) {
4811        var value = array[index],
4812            computed = iteratee ? iteratee(value) : value;
4813
4814        value = (comparator || value !== 0) ? value : 0;
4815        if (!(seen
4816              ? cacheHas(seen, computed)
4817              : includes(result, computed, comparator)
4818            )) {
4819          othIndex = othLength;
4820          while (--othIndex) {
4821            var cache = caches[othIndex];
4822            if (!(cache
4823                  ? cacheHas(cache, computed)
4824                  : includes(arrays[othIndex], computed, comparator))
4825                ) {
4826              continue outer;
4827            }
4828          }
4829          if (seen) {
4830            seen.push(computed);
4831          }
4832          result.push(value);
4833        }
4834      }
4835      return result;
4836    }
4837
4838    /**
4839     * The base implementation of `_.invert` and `_.invertBy` which inverts
4840     * `object` with values transformed by `iteratee` and set by `setter`.
4841     *
4842     * @private
4843     * @param {Object} object The object to iterate over.
4844     * @param {Function} setter The function to set `accumulator` values.
4845     * @param {Function} iteratee The iteratee to transform values.
4846     * @param {Object} accumulator The initial inverted object.
4847     * @returns {Function} Returns `accumulator`.
4848     */
4849    function baseInverter(object, setter, iteratee, accumulator) {
4850      baseForOwn(object, function(value, key, object) {
4851        setter(accumulator, iteratee(value), key, object);
4852      });
4853      return accumulator;
4854    }
4855
4856    /**
4857     * The base implementation of `_.invoke` without support for individual
4858     * method arguments.
4859     *
4860     * @private
4861     * @param {Object} object The object to query.
4862     * @param {Array|string} path The path of the method to invoke.
4863     * @param {Array} args The arguments to invoke the method with.
4864     * @returns {*} Returns the result of the invoked method.
4865     */
4866    function baseInvoke(object, path, args) {
4867      path = castPath(path, object);
4868      object = parent(object, path);
4869      var func = object == null ? object : object[toKey(last(path))];
4870      return func == null ? undefined : apply(func, object, args);
4871    }
4872
4873    /**
4874     * The base implementation of `_.isArguments`.
4875     *
4876     * @private
4877     * @param {*} value The value to check.
4878     * @returns {boolean} Returns `true` if `value` is an `arguments` object,
4879     */
4880    function baseIsArguments(value) {
4881      return isObjectLike(value) && baseGetTag(value) == argsTag;
4882    }
4883
4884    /**
4885     * The base implementation of `_.isArrayBuffer` without Node.js optimizations.
4886     *
4887     * @private
4888     * @param {*} value The value to check.
4889     * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
4890     */
4891    function baseIsArrayBuffer(value) {
4892      return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
4893    }
4894
4895    /**
4896     * The base implementation of `_.isDate` without Node.js optimizations.
4897     *
4898     * @private
4899     * @param {*} value The value to check.
4900     * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
4901     */
4902    function baseIsDate(value) {
4903      return isObjectLike(value) && baseGetTag(value) == dateTag;
4904    }
4905
4906    /**
4907     * The base implementation of `_.isEqual` which supports partial comparisons
4908     * and tracks traversed objects.
4909     *
4910     * @private
4911     * @param {*} value The value to compare.
4912     * @param {*} other The other value to compare.
4913     * @param {boolean} bitmask The bitmask flags.
4914     *  1 - Unordered comparison
4915     *  2 - Partial comparison
4916     * @param {Function} [customizer] The function to customize comparisons.
4917     * @param {Object} [stack] Tracks traversed `value` and `other` objects.
4918     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
4919     */
4920    function baseIsEqual(value, other, bitmask, customizer, stack) {
4921      if (value === other) {
4922        return true;
4923      }
4924      if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
4925        return value !== value && other !== other;
4926      }
4927      return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
4928    }
4929
4930    /**
4931     * A specialized version of `baseIsEqual` for arrays and objects which performs
4932     * deep comparisons and tracks traversed objects enabling objects with circular
4933     * references to be compared.
4934     *
4935     * @private
4936     * @param {Object} object The object to compare.
4937     * @param {Object} other The other object to compare.
4938     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
4939     * @param {Function} customizer The function to customize comparisons.
4940     * @param {Function} equalFunc The function to determine equivalents of values.
4941     * @param {Object} [stack] Tracks traversed `object` and `other` objects.
4942     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
4943     */
4944    function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
4945      var objIsArr = isArray(object),
4946          othIsArr = isArray(other),
4947          objTag = objIsArr ? arrayTag : getTag(object),
4948          othTag = othIsArr ? arrayTag : getTag(other);
4949
4950      objTag = objTag == argsTag ? objectTag : objTag;
4951      othTag = othTag == argsTag ? objectTag : othTag;
4952
4953      var objIsObj = objTag == objectTag,
4954          othIsObj = othTag == objectTag,
4955          isSameTag = objTag == othTag;
4956
4957      if (isSameTag && isBuffer(object)) {
4958        if (!isBuffer(other)) {
4959          return false;
4960        }
4961        objIsArr = true;
4962        objIsObj = false;
4963      }
4964      if (isSameTag && !objIsObj) {
4965        stack || (stack = new Stack);
4966        return (objIsArr || isTypedArray(object))
4967          ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
4968          : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
4969      }
4970      if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
4971        var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
4972            othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
4973
4974        if (objIsWrapped || othIsWrapped) {
4975          var objUnwrapped = objIsWrapped ? object.value() : object,
4976              othUnwrapped = othIsWrapped ? other.value() : other;
4977
4978          stack || (stack = new Stack);
4979          return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
4980        }
4981      }
4982      if (!isSameTag) {
4983        return false;
4984      }
4985      stack || (stack = new Stack);
4986      return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
4987    }
4988
4989    /**
4990     * The base implementation of `_.isMap` without Node.js optimizations.
4991     *
4992     * @private
4993     * @param {*} value The value to check.
4994     * @returns {boolean} Returns `true` if `value` is a map, else `false`.
4995     */
4996    function baseIsMap(value) {
4997      return isObjectLike(value) && getTag(value) == mapTag;
4998    }
4999
5000    /**
5001     * The base implementation of `_.isMatch` without support for iteratee shorthands.
5002     *
5003     * @private
5004     * @param {Object} object The object to inspect.
5005     * @param {Object} source The object of property values to match.
5006     * @param {Array} matchData The property names, values, and compare flags to match.
5007     * @param {Function} [customizer] The function to customize comparisons.
5008     * @returns {boolean} Returns `true` if `object` is a match, else `false`.
5009     */
5010    function baseIsMatch(object, source, matchData, customizer) {
5011      var index = matchData.length,
5012          length = index,
5013          noCustomizer = !customizer;
5014
5015      if (object == null) {
5016        return !length;
5017      }
5018      object = Object(object);
5019      while (index--) {
5020        var data = matchData[index];
5021        if ((noCustomizer && data[2])
5022              ? data[1] !== object[data[0]]
5023              : !(data[0] in object)
5024            ) {
5025          return false;
5026        }
5027      }
5028      while (++index < length) {
5029        data = matchData[index];
5030        var key = data[0],
5031            objValue = object[key],
5032            srcValue = data[1];
5033
5034        if (noCustomizer && data[2]) {
5035          if (objValue === undefined && !(key in object)) {
5036            return false;
5037          }
5038        } else {
5039          var stack = new Stack;
5040          if (customizer) {
5041            var result = customizer(objValue, srcValue, key, object, source, stack);
5042          }
5043          if (!(result === undefined
5044                ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
5045                : result
5046              )) {
5047            return false;
5048          }
5049        }
5050      }
5051      return true;
5052    }
5053
5054    /**
5055     * The base implementation of `_.isNative` without bad shim checks.
5056     *
5057     * @private
5058     * @param {*} value The value to check.
5059     * @returns {boolean} Returns `true` if `value` is a native function,
5060     *  else `false`.
5061     */
5062    function baseIsNative(value) {
5063      if (!isObject(value) || isMasked(value)) {
5064        return false;
5065      }
5066      var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
5067      return pattern.test(toSource(value));
5068    }
5069
5070    /**
5071     * The base implementation of `_.isRegExp` without Node.js optimizations.
5072     *
5073     * @private
5074     * @param {*} value The value to check.
5075     * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
5076     */
5077    function baseIsRegExp(value) {
5078      return isObjectLike(value) && baseGetTag(value) == regexpTag;
5079    }
5080
5081    /**
5082     * The base implementation of `_.isSet` without Node.js optimizations.
5083     *
5084     * @private
5085     * @param {*} value The value to check.
5086     * @returns {boolean} Returns `true` if `value` is a set, else `false`.
5087     */
5088    function baseIsSet(value) {
5089      return isObjectLike(value) && getTag(value) == setTag;
5090    }
5091
5092    /**
5093     * The base implementation of `_.isTypedArray` without Node.js optimizations.
5094     *
5095     * @private
5096     * @param {*} value The value to check.
5097     * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
5098     */
5099    function baseIsTypedArray(value) {
5100      return isObjectLike(value) &&
5101        isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
5102    }
5103
5104    /**
5105     * The base implementation of `_.iteratee`.
5106     *
5107     * @private
5108     * @param {*} [value=_.identity] The value to convert to an iteratee.
5109     * @returns {Function} Returns the iteratee.
5110     */
5111    function baseIteratee(value) {
5112      // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
5113      // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
5114      if (typeof value == 'function') {
5115        return value;
5116      }
5117      if (value == null) {
5118        return identity;
5119      }
5120      if (typeof value == 'object') {
5121        return isArray(value)
5122          ? baseMatchesProperty(value[0], value[1])
5123          : baseMatches(value);
5124      }
5125      return property(value);
5126    }
5127
5128    /**
5129     * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
5130     *
5131     * @private
5132     * @param {Object} object The object to query.
5133     * @returns {Array} Returns the array of property names.
5134     */
5135    function baseKeys(object) {
5136      if (!isPrototype(object)) {
5137        return nativeKeys(object);
5138      }
5139      var result = [];
5140      for (var key in Object(object)) {
5141        if (hasOwnProperty.call(object, key) && key != 'constructor') {
5142          result.push(key);
5143        }
5144      }
5145      return result;
5146    }
5147
5148    /**
5149     * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
5150     *
5151     * @private
5152     * @param {Object} object The object to query.
5153     * @returns {Array} Returns the array of property names.
5154     */
5155    function baseKeysIn(object) {
5156      if (!isObject(object)) {
5157        return nativeKeysIn(object);
5158      }
5159      var isProto = isPrototype(object),
5160          result = [];
5161
5162      for (var key in object) {
5163        if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
5164          result.push(key);
5165        }
5166      }
5167      return result;
5168    }
5169
5170    /**
5171     * The base implementation of `_.lt` which doesn't coerce arguments.
5172     *
5173     * @private
5174     * @param {*} value The value to compare.
5175     * @param {*} other The other value to compare.
5176     * @returns {boolean} Returns `true` if `value` is less than `other`,
5177     *  else `false`.
5178     */
5179    function baseLt(value, other) {
5180      return value < other;
5181    }
5182
5183    /**
5184     * The base implementation of `_.map` without support for iteratee shorthands.
5185     *
5186     * @private
5187     * @param {Array|Object} collection The collection to iterate over.
5188     * @param {Function} iteratee The function invoked per iteration.
5189     * @returns {Array} Returns the new mapped array.
5190     */
5191    function baseMap(collection, iteratee) {
5192      var index = -1,
5193          result = isArrayLike(collection) ? Array(collection.length) : [];
5194
5195      baseEach(collection, function(value, key, collection) {
5196        result[++index] = iteratee(value, key, collection);
5197      });
5198      return result;
5199    }
5200
5201    /**
5202     * The base implementation of `_.matches` which doesn't clone `source`.
5203     *
5204     * @private
5205     * @param {Object} source The object of property values to match.
5206     * @returns {Function} Returns the new spec function.
5207     */
5208    function baseMatches(source) {
5209      var matchData = getMatchData(source);
5210      if (matchData.length == 1 && matchData[0][2]) {
5211        return matchesStrictComparable(matchData[0][0], matchData[0][1]);
5212      }
5213      return function(object) {
5214        return object === source || baseIsMatch(object, source, matchData);
5215      };
5216    }
5217
5218    /**
5219     * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
5220     *
5221     * @private
5222     * @param {string} path The path of the property to get.
5223     * @param {*} srcValue The value to match.
5224     * @returns {Function} Returns the new spec function.
5225     */
5226    function baseMatchesProperty(path, srcValue) {
5227      if (isKey(path) && isStrictComparable(srcValue)) {
5228        return matchesStrictComparable(toKey(path), srcValue);
5229      }
5230      return function(object) {
5231        var objValue = get(object, path);
5232        return (objValue === undefined && objValue === srcValue)
5233          ? hasIn(object, path)
5234          : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
5235      };
5236    }
5237
5238    /**
5239     * The base implementation of `_.merge` without support for multiple sources.
5240     *
5241     * @private
5242     * @param {Object} object The destination object.
5243     * @param {Object} source The source object.
5244     * @param {number} srcIndex The index of `source`.
5245     * @param {Function} [customizer] The function to customize merged values.
5246     * @param {Object} [stack] Tracks traversed source values and their merged
5247     *  counterparts.
5248     */
5249    function baseMerge(object, source, srcIndex, customizer, stack) {
5250      if (object === source) {
5251        return;
5252      }
5253      baseFor(source, function(srcValue, key) {
5254        stack || (stack = new Stack);
5255        if (isObject(srcValue)) {
5256          baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
5257        }
5258        else {
5259          var newValue = customizer
5260            ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack)
5261            : undefined;
5262
5263          if (newValue === undefined) {
5264            newValue = srcValue;
5265          }
5266          assignMergeValue(object, key, newValue);
5267        }
5268      }, keysIn);
5269    }
5270
5271    /**
5272     * A specialized version of `baseMerge` for arrays and objects which performs
5273     * deep merges and tracks traversed objects enabling objects with circular
5274     * references to be merged.
5275     *
5276     * @private
5277     * @param {Object} object The destination object.
5278     * @param {Object} source The source object.
5279     * @param {string} key The key of the value to merge.
5280     * @param {number} srcIndex The index of `source`.
5281     * @param {Function} mergeFunc The function to merge values.
5282     * @param {Function} [customizer] The function to customize assigned values.
5283     * @param {Object} [stack] Tracks traversed source values and their merged
5284     *  counterparts.
5285     */
5286    function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
5287      var objValue = safeGet(object, key),
5288          srcValue = safeGet(source, key),
5289          stacked = stack.get(srcValue);
5290
5291      if (stacked) {
5292        assignMergeValue(object, key, stacked);
5293        return;
5294      }
5295      var newValue = customizer
5296        ? customizer(objValue, srcValue, (key + ''), object, source, stack)
5297        : undefined;
5298
5299      var isCommon = newValue === undefined;
5300
5301      if (isCommon) {
5302        var isArr = isArray(srcValue),
5303            isBuff = !isArr && isBuffer(srcValue),
5304            isTyped = !isArr && !isBuff && isTypedArray(srcValue);
5305
5306        newValue = srcValue;
5307        if (isArr || isBuff || isTyped) {
5308          if (isArray(objValue)) {
5309            newValue = objValue;
5310          }
5311          else if (isArrayLikeObject(objValue)) {
5312            newValue = copyArray(objValue);
5313          }
5314          else if (isBuff) {
5315            isCommon = false;
5316            newValue = cloneBuffer(srcValue, true);
5317          }
5318          else if (isTyped) {
5319            isCommon = false;
5320            newValue = cloneTypedArray(srcValue, true);
5321          }
5322          else {
5323            newValue = [];
5324          }
5325        }
5326        else if (isPlainObject(srcValue) || isArguments(srcValue)) {
5327          newValue = objValue;
5328          if (isArguments(objValue)) {
5329            newValue = toPlainObject(objValue);
5330          }
5331          else if (!isObject(objValue) || isFunction(objValue)) {
5332            newValue = initCloneObject(srcValue);
5333          }
5334        }
5335        else {
5336          isCommon = false;
5337        }
5338      }
5339      if (isCommon) {
5340        // Recursively merge objects and arrays (susceptible to call stack limits).
5341        stack.set(srcValue, newValue);
5342        mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
5343        stack['delete'](srcValue);
5344      }
5345      assignMergeValue(object, key, newValue);
5346    }
5347
5348    /**
5349     * The base implementation of `_.nth` which doesn't coerce arguments.
5350     *
5351     * @private
5352     * @param {Array} array The array to query.
5353     * @param {number} n The index of the element to return.
5354     * @returns {*} Returns the nth element of `array`.
5355     */
5356    function baseNth(array, n) {
5357      var length = array.length;
5358      if (!length) {
5359        return;
5360      }
5361      n += n < 0 ? length : 0;
5362      return isIndex(n, length) ? array[n] : undefined;
5363    }
5364
5365    /**
5366     * The base implementation of `_.orderBy` without param guards.
5367     *
5368     * @private
5369     * @param {Array|Object} collection The collection to iterate over.
5370     * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
5371     * @param {string[]} orders The sort orders of `iteratees`.
5372     * @returns {Array} Returns the new sorted array.
5373     */
5374    function baseOrderBy(collection, iteratees, orders) {
5375      if (iteratees.length) {
5376        iteratees = arrayMap(iteratees, function(iteratee) {
5377          if (isArray(iteratee)) {
5378            return function(value) {
5379              return baseGet(value, iteratee.length === 1 ? iteratee[0] : iteratee);
5380            }
5381          }
5382          return iteratee;
5383        });
5384      } else {
5385        iteratees = [identity];
5386      }
5387
5388      var index = -1;
5389      iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
5390
5391      var result = baseMap(collection, function(value, key, collection) {
5392        var criteria = arrayMap(iteratees, function(iteratee) {
5393          return iteratee(value);
5394        });
5395        return { 'criteria': criteria, 'index': ++index, 'value': value };
5396      });
5397
5398      return baseSortBy(result, function(object, other) {
5399        return compareMultiple(object, other, orders);
5400      });
5401    }
5402
5403    /**
5404     * The base implementation of `_.pick` without support for individual
5405     * property identifiers.
5406     *
5407     * @private
5408     * @param {Object} object The source object.
5409     * @param {string[]} paths The property paths to pick.
5410     * @returns {Object} Returns the new object.
5411     */
5412    function basePick(object, paths) {
5413      return basePickBy(object, paths, function(value, path) {
5414        return hasIn(object, path);
5415      });
5416    }
5417
5418    /**
5419     * The base implementation of  `_.pickBy` without support for iteratee shorthands.
5420     *
5421     * @private
5422     * @param {Object} object The source object.
5423     * @param {string[]} paths The property paths to pick.
5424     * @param {Function} predicate The function invoked per property.
5425     * @returns {Object} Returns the new object.
5426     */
5427    function basePickBy(object, paths, predicate) {
5428      var index = -1,
5429          length = paths.length,
5430          result = {};
5431
5432      while (++index < length) {
5433        var path = paths[index],
5434            value = baseGet(object, path);
5435
5436        if (predicate(value, path)) {
5437          baseSet(result, castPath(path, object), value);
5438        }
5439      }
5440      return result;
5441    }
5442
5443    /**
5444     * A specialized version of `baseProperty` which supports deep paths.
5445     *
5446     * @private
5447     * @param {Array|string} path The path of the property to get.
5448     * @returns {Function} Returns the new accessor function.
5449     */
5450    function basePropertyDeep(path) {
5451      return function(object) {
5452        return baseGet(object, path);
5453      };
5454    }
5455
5456    /**
5457     * The base implementation of `_.pullAllBy` without support for iteratee
5458     * shorthands.
5459     *
5460     * @private
5461     * @param {Array} array The array to modify.
5462     * @param {Array} values The values to remove.
5463     * @param {Function} [iteratee] The iteratee invoked per element.
5464     * @param {Function} [comparator] The comparator invoked per element.
5465     * @returns {Array} Returns `array`.
5466     */
5467    function basePullAll(array, values, iteratee, comparator) {
5468      var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
5469          index = -1,
5470          length = values.length,
5471          seen = array;
5472
5473      if (array === values) {
5474        values = copyArray(values);
5475      }
5476      if (iteratee) {
5477        seen = arrayMap(array, baseUnary(iteratee));
5478      }
5479      while (++index < length) {
5480        var fromIndex = 0,
5481            value = values[index],
5482            computed = iteratee ? iteratee(value) : value;
5483
5484        while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
5485          if (seen !== array) {
5486            splice.call(seen, fromIndex, 1);
5487          }
5488          splice.call(array, fromIndex, 1);
5489        }
5490      }
5491      return array;
5492    }
5493
5494    /**
5495     * The base implementation of `_.pullAt` without support for individual
5496     * indexes or capturing the removed elements.
5497     *
5498     * @private
5499     * @param {Array} array The array to modify.
5500     * @param {number[]} indexes The indexes of elements to remove.
5501     * @returns {Array} Returns `array`.
5502     */
5503    function basePullAt(array, indexes) {
5504      var length = array ? indexes.length : 0,
5505          lastIndex = length - 1;
5506
5507      while (length--) {
5508        var index = indexes[length];
5509        if (length == lastIndex || index !== previous) {
5510          var previous = index;
5511          if (isIndex(index)) {
5512            splice.call(array, index, 1);
5513          } else {
5514            baseUnset(array, index);
5515          }
5516        }
5517      }
5518      return array;
5519    }
5520
5521    /**
5522     * The base implementation of `_.random` without support for returning
5523     * floating-point numbers.
5524     *
5525     * @private
5526     * @param {number} lower The lower bound.
5527     * @param {number} upper The upper bound.
5528     * @returns {number} Returns the random number.
5529     */
5530    function baseRandom(lower, upper) {
5531      return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
5532    }
5533
5534    /**
5535     * The base implementation of `_.range` and `_.rangeRight` which doesn't
5536     * coerce arguments.
5537     *
5538     * @private
5539     * @param {number} start The start of the range.
5540     * @param {number} end The end of the range.
5541     * @param {number} step The value to increment or decrement by.
5542     * @param {boolean} [fromRight] Specify iterating from right to left.
5543     * @returns {Array} Returns the range of numbers.
5544     */
5545    function baseRange(start, end, step, fromRight) {
5546      var index = -1,
5547          length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
5548          result = Array(length);
5549
5550      while (length--) {
5551        result[fromRight ? length : ++index] = start;
5552        start += step;
5553      }
5554      return result;
5555    }
5556
5557    /**
5558     * The base implementation of `_.repeat` which doesn't coerce arguments.
5559     *
5560     * @private
5561     * @param {string} string The string to repeat.
5562     * @param {number} n The number of times to repeat the string.
5563     * @returns {string} Returns the repeated string.
5564     */
5565    function baseRepeat(string, n) {
5566      var result = '';
5567      if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
5568        return result;
5569      }
5570      // Leverage the exponentiation by squaring algorithm for a faster repeat.
5571      // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
5572      do {
5573        if (n % 2) {
5574          result += string;
5575        }
5576        n = nativeFloor(n / 2);
5577        if (n) {
5578          string += string;
5579        }
5580      } while (n);
5581
5582      return result;
5583    }
5584
5585    /**
5586     * The base implementation of `_.rest` which doesn't validate or coerce arguments.
5587     *
5588     * @private
5589     * @param {Function} func The function to apply a rest parameter to.
5590     * @param {number} [start=func.length-1] The start position of the rest parameter.
5591     * @returns {Function} Returns the new function.
5592     */
5593    function baseRest(func, start) {
5594      return setToString(overRest(func, start, identity), func + '');
5595    }
5596
5597    /**
5598     * The base implementation of `_.sample`.
5599     *
5600     * @private
5601     * @param {Array|Object} collection The collection to sample.
5602     * @returns {*} Returns the random element.
5603     */
5604    function baseSample(collection) {
5605      return arraySample(values(collection));
5606    }
5607
5608    /**
5609     * The base implementation of `_.sampleSize` without param guards.
5610     *
5611     * @private
5612     * @param {Array|Object} collection The collection to sample.
5613     * @param {number} n The number of elements to sample.
5614     * @returns {Array} Returns the random elements.
5615     */
5616    function baseSampleSize(collection, n) {
5617      var array = values(collection);
5618      return shuffleSelf(array, baseClamp(n, 0, array.length));
5619    }
5620
5621    /**
5622     * The base implementation of `_.set`.
5623     *
5624     * @private
5625     * @param {Object} object The object to modify.
5626     * @param {Array|string} path The path of the property to set.
5627     * @param {*} value The value to set.
5628     * @param {Function} [customizer] The function to customize path creation.
5629     * @returns {Object} Returns `object`.
5630     */
5631    function baseSet(object, path, value, customizer) {
5632      if (!isObject(object)) {
5633        return object;
5634      }
5635      path = castPath(path, object);
5636
5637      var index = -1,
5638          length = path.length,
5639          lastIndex = length - 1,
5640          nested = object;
5641
5642      while (nested != null && ++index < length) {
5643        var key = toKey(path[index]),
5644            newValue = value;
5645
5646        if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
5647          return object;
5648        }
5649
5650        if (index != lastIndex) {
5651          var objValue = nested[key];
5652          newValue = customizer ? customizer(objValue, key, nested) : undefined;
5653          if (newValue === undefined) {
5654            newValue = isObject(objValue)
5655              ? objValue
5656              : (isIndex(path[index + 1]) ? [] : {});
5657          }
5658        }
5659        assignValue(nested, key, newValue);
5660        nested = nested[key];
5661      }
5662      return object;
5663    }
5664
5665    /**
5666     * The base implementation of `setData` without support for hot loop shorting.
5667     *
5668     * @private
5669     * @param {Function} func The function to associate metadata with.
5670     * @param {*} data The metadata.
5671     * @returns {Function} Returns `func`.
5672     */
5673    var baseSetData = !metaMap ? identity : function(func, data) {
5674      metaMap.set(func, data);
5675      return func;
5676    };
5677
5678    /**
5679     * The base implementation of `setToString` without support for hot loop shorting.
5680     *
5681     * @private
5682     * @param {Function} func The function to modify.
5683     * @param {Function} string The `toString` result.
5684     * @returns {Function} Returns `func`.
5685     */
5686    var baseSetToString = !defineProperty ? identity : function(func, string) {
5687      return defineProperty(func, 'toString', {
5688        'configurable': true,
5689        'enumerable': false,
5690        'value': constant(string),
5691        'writable': true
5692      });
5693    };
5694
5695    /**
5696     * The base implementation of `_.shuffle`.
5697     *
5698     * @private
5699     * @param {Array|Object} collection The collection to shuffle.
5700     * @returns {Array} Returns the new shuffled array.
5701     */
5702    function baseShuffle(collection) {
5703      return shuffleSelf(values(collection));
5704    }
5705
5706    /**
5707     * The base implementation of `_.slice` without an iteratee call guard.
5708     *
5709     * @private
5710     * @param {Array} array The array to slice.
5711     * @param {number} [start=0] The start position.
5712     * @param {number} [end=array.length] The end position.
5713     * @returns {Array} Returns the slice of `array`.
5714     */
5715    function baseSlice(array, start, end) {
5716      var index = -1,
5717          length = array.length;
5718
5719      if (start < 0) {
5720        start = -start > length ? 0 : (length + start);
5721      }
5722      end = end > length ? length : end;
5723      if (end < 0) {
5724        end += length;
5725      }
5726      length = start > end ? 0 : ((end - start) >>> 0);
5727      start >>>= 0;
5728
5729      var result = Array(length);
5730      while (++index < length) {
5731        result[index] = array[index + start];
5732      }
5733      return result;
5734    }
5735
5736    /**
5737     * The base implementation of `_.some` without support for iteratee shorthands.
5738     *
5739     * @private
5740     * @param {Array|Object} collection The collection to iterate over.
5741     * @param {Function} predicate The function invoked per iteration.
5742     * @returns {boolean} Returns `true` if any element passes the predicate check,
5743     *  else `false`.
5744     */
5745    function baseSome(collection, predicate) {
5746      var result;
5747
5748      baseEach(collection, function(value, index, collection) {
5749        result = predicate(value, index, collection);
5750        return !result;
5751      });
5752      return !!result;
5753    }
5754
5755    /**
5756     * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
5757     * performs a binary search of `array` to determine the index at which `value`
5758     * should be inserted into `array` in order to maintain its sort order.
5759     *
5760     * @private
5761     * @param {Array} array The sorted array to inspect.
5762     * @param {*} value The value to evaluate.
5763     * @param {boolean} [retHighest] Specify returning the highest qualified index.
5764     * @returns {number} Returns the index at which `value` should be inserted
5765     *  into `array`.
5766     */
5767    function baseSortedIndex(array, value, retHighest) {
5768      var low = 0,
5769          high = array == null ? low : array.length;
5770
5771      if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
5772        while (low < high) {
5773          var mid = (low + high) >>> 1,
5774              computed = array[mid];
5775
5776          if (computed !== null && !isSymbol(computed) &&
5777              (retHighest ? (computed <= value) : (computed < value))) {
5778            low = mid + 1;
5779          } else {
5780            high = mid;
5781          }
5782        }
5783        return high;
5784      }
5785      return baseSortedIndexBy(array, value, identity, retHighest);
5786    }
5787
5788    /**
5789     * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
5790     * which invokes `iteratee` for `value` and each element of `array` to compute
5791     * their sort ranking. The iteratee is invoked with one argument; (value).
5792     *
5793     * @private
5794     * @param {Array} array The sorted array to inspect.
5795     * @param {*} value The value to evaluate.
5796     * @param {Function} iteratee The iteratee invoked per element.
5797     * @param {boolean} [retHighest] Specify returning the highest qualified index.
5798     * @returns {number} Returns the index at which `value` should be inserted
5799     *  into `array`.
5800     */
5801    function baseSortedIndexBy(array, value, iteratee, retHighest) {
5802      var low = 0,
5803          high = array == null ? 0 : array.length;
5804      if (high === 0) {
5805        return 0;
5806      }
5807
5808      value = iteratee(value);
5809      var valIsNaN = value !== value,
5810          valIsNull = value === null,
5811          valIsSymbol = isSymbol(value),
5812          valIsUndefined = value === undefined;
5813
5814      while (low < high) {
5815        var mid = nativeFloor((low + high) / 2),
5816            computed = iteratee(array[mid]),
5817            othIsDefined = computed !== undefined,
5818            othIsNull = computed === null,
5819            othIsReflexive = computed === computed,
5820            othIsSymbol = isSymbol(computed);
5821
5822        if (valIsNaN) {
5823          var setLow = retHighest || othIsReflexive;
5824        } else if (valIsUndefined) {
5825          setLow = othIsReflexive && (retHighest || othIsDefined);
5826        } else if (valIsNull) {
5827          setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
5828        } else if (valIsSymbol) {
5829          setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
5830        } else if (othIsNull || othIsSymbol) {
5831          setLow = false;
5832        } else {
5833          setLow = retHighest ? (computed <= value) : (computed < value);
5834        }
5835        if (setLow) {
5836          low = mid + 1;
5837        } else {
5838          high = mid;
5839        }
5840      }
5841      return nativeMin(high, MAX_ARRAY_INDEX);
5842    }
5843
5844    /**
5845     * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
5846     * support for iteratee shorthands.
5847     *
5848     * @private
5849     * @param {Array} array The array to inspect.
5850     * @param {Function} [iteratee] The iteratee invoked per element.
5851     * @returns {Array} Returns the new duplicate free array.
5852     */
5853    function baseSortedUniq(array, iteratee) {
5854      var index = -1,
5855          length = array.length,
5856          resIndex = 0,
5857          result = [];
5858
5859      while (++index < length) {
5860        var value = array[index],
5861            computed = iteratee ? iteratee(value) : value;
5862
5863        if (!index || !eq(computed, seen)) {
5864          var seen = computed;
5865          result[resIndex++] = value === 0 ? 0 : value;
5866        }
5867      }
5868      return result;
5869    }
5870
5871    /**
5872     * The base implementation of `_.toNumber` which doesn't ensure correct
5873     * conversions of binary, hexadecimal, or octal string values.
5874     *
5875     * @private
5876     * @param {*} value The value to process.
5877     * @returns {number} Returns the number.
5878     */
5879    function baseToNumber(value) {
5880      if (typeof value == 'number') {
5881        return value;
5882      }
5883      if (isSymbol(value)) {
5884        return NAN;
5885      }
5886      return +value;
5887    }
5888
5889    /**
5890     * The base implementation of `_.toString` which doesn't convert nullish
5891     * values to empty strings.
5892     *
5893     * @private
5894     * @param {*} value The value to process.
5895     * @returns {string} Returns the string.
5896     */
5897    function baseToString(value) {
5898      // Exit early for strings to avoid a performance hit in some environments.
5899      if (typeof value == 'string') {
5900        return value;
5901      }
5902      if (isArray(value)) {
5903        // Recursively convert values (susceptible to call stack limits).
5904        return arrayMap(value, baseToString) + '';
5905      }
5906      if (isSymbol(value)) {
5907        return symbolToString ? symbolToString.call(value) : '';
5908      }
5909      var result = (value + '');
5910      return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
5911    }
5912
5913    /**
5914     * The base implementation of `_.uniqBy` without support for iteratee shorthands.
5915     *
5916     * @private
5917     * @param {Array} array The array to inspect.
5918     * @param {Function} [iteratee] The iteratee invoked per element.
5919     * @param {Function} [comparator] The comparator invoked per element.
5920     * @returns {Array} Returns the new duplicate free array.
5921     */
5922    function baseUniq(array, iteratee, comparator) {
5923      var index = -1,
5924          includes = arrayIncludes,
5925          length = array.length,
5926          isCommon = true,
5927          result = [],
5928          seen = result;
5929
5930      if (comparator) {
5931        isCommon = false;
5932        includes = arrayIncludesWith;
5933      }
5934      else if (length >= LARGE_ARRAY_SIZE) {
5935        var set = iteratee ? null : createSet(array);
5936        if (set) {
5937          return setToArray(set);
5938        }
5939        isCommon = false;
5940        includes = cacheHas;
5941        seen = new SetCache;
5942      }
5943      else {
5944        seen = iteratee ? [] : result;
5945      }
5946      outer:
5947      while (++index < length) {
5948        var value = array[index],
5949            computed = iteratee ? iteratee(value) : value;
5950
5951        value = (comparator || value !== 0) ? value : 0;
5952        if (isCommon && computed === computed) {
5953          var seenIndex = seen.length;
5954          while (seenIndex--) {
5955            if (seen[seenIndex] === computed) {
5956              continue outer;
5957            }
5958          }
5959          if (iteratee) {
5960            seen.push(computed);
5961          }
5962          result.push(value);
5963        }
5964        else if (!includes(seen, computed, comparator)) {
5965          if (seen !== result) {
5966            seen.push(computed);
5967          }
5968          result.push(value);
5969        }
5970      }
5971      return result;
5972    }
5973
5974    /**
5975     * The base implementation of `_.unset`.
5976     *
5977     * @private
5978     * @param {Object} object The object to modify.
5979     * @param {Array|string} path The property path to unset.
5980     * @returns {boolean} Returns `true` if the property is deleted, else `false`.
5981     */
5982    function baseUnset(object, path) {
5983      path = castPath(path, object);
5984      object = parent(object, path);
5985      return object == null || delete object[toKey(last(path))];
5986    }
5987
5988    /**
5989     * The base implementation of `_.update`.
5990     *
5991     * @private
5992     * @param {Object} object The object to modify.
5993     * @param {Array|string} path The path of the property to update.
5994     * @param {Function} updater The function to produce the updated value.
5995     * @param {Function} [customizer] The function to customize path creation.
5996     * @returns {Object} Returns `object`.
5997     */
5998    function baseUpdate(object, path, updater, customizer) {
5999      return baseSet(object, path, updater(baseGet(object, path)), customizer);
6000    }
6001
6002    /**
6003     * The base implementation of methods like `_.dropWhile` and `_.takeWhile`
6004     * without support for iteratee shorthands.
6005     *
6006     * @private
6007     * @param {Array} array The array to query.
6008     * @param {Function} predicate The function invoked per iteration.
6009     * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
6010     * @param {boolean} [fromRight] Specify iterating from right to left.
6011     * @returns {Array} Returns the slice of `array`.
6012     */
6013    function baseWhile(array, predicate, isDrop, fromRight) {
6014      var length = array.length,
6015          index = fromRight ? length : -1;
6016
6017      while ((fromRight ? index-- : ++index < length) &&
6018        predicate(array[index], index, array)) {}
6019
6020      return isDrop
6021        ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
6022        : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
6023    }
6024
6025    /**
6026     * The base implementation of `wrapperValue` which returns the result of
6027     * performing a sequence of actions on the unwrapped `value`, where each
6028     * successive action is supplied the return value of the previous.
6029     *
6030     * @private
6031     * @param {*} value The unwrapped value.
6032     * @param {Array} actions Actions to perform to resolve the unwrapped value.
6033     * @returns {*} Returns the resolved value.
6034     */
6035    function baseWrapperValue(value, actions) {
6036      var result = value;
6037      if (result instanceof LazyWrapper) {
6038        result = result.value();
6039      }
6040      return arrayReduce(actions, function(result, action) {
6041        return action.func.apply(action.thisArg, arrayPush([result], action.args));
6042      }, result);
6043    }
6044
6045    /**
6046     * The base implementation of methods like `_.xor`, without support for
6047     * iteratee shorthands, that accepts an array of arrays to inspect.
6048     *
6049     * @private
6050     * @param {Array} arrays The arrays to inspect.
6051     * @param {Function} [iteratee] The iteratee invoked per element.
6052     * @param {Function} [comparator] The comparator invoked per element.
6053     * @returns {Array} Returns the new array of values.
6054     */
6055    function baseXor(arrays, iteratee, comparator) {
6056      var length = arrays.length;
6057      if (length < 2) {
6058        return length ? baseUniq(arrays[0]) : [];
6059      }
6060      var index = -1,
6061          result = Array(length);
6062
6063      while (++index < length) {
6064        var array = arrays[index],
6065            othIndex = -1;
6066
6067        while (++othIndex < length) {
6068          if (othIndex != index) {
6069            result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator);
6070          }
6071        }
6072      }
6073      return baseUniq(baseFlatten(result, 1), iteratee, comparator);
6074    }
6075
6076    /**
6077     * This base implementation of `_.zipObject` which assigns values using `assignFunc`.
6078     *
6079     * @private
6080     * @param {Array} props The property identifiers.
6081     * @param {Array} values The property values.
6082     * @param {Function} assignFunc The function to assign values.
6083     * @returns {Object} Returns the new object.
6084     */
6085    function baseZipObject(props, values, assignFunc) {
6086      var index = -1,
6087          length = props.length,
6088          valsLength = values.length,
6089          result = {};
6090
6091      while (++index < length) {
6092        var value = index < valsLength ? values[index] : undefined;
6093        assignFunc(result, props[index], value);
6094      }
6095      return result;
6096    }
6097
6098    /**
6099     * Casts `value` to an empty array if it's not an array like object.
6100     *
6101     * @private
6102     * @param {*} value The value to inspect.
6103     * @returns {Array|Object} Returns the cast array-like object.
6104     */
6105    function castArrayLikeObject(value) {
6106      return isArrayLikeObject(value) ? value : [];
6107    }
6108
6109    /**
6110     * Casts `value` to `identity` if it's not a function.
6111     *
6112     * @private
6113     * @param {*} value The value to inspect.
6114     * @returns {Function} Returns cast function.
6115     */
6116    function castFunction(value) {
6117      return typeof value == 'function' ? value : identity;
6118    }
6119
6120    /**
6121     * Casts `value` to a path array if it's not one.
6122     *
6123     * @private
6124     * @param {*} value The value to inspect.
6125     * @param {Object} [object] The object to query keys on.
6126     * @returns {Array} Returns the cast property path array.
6127     */
6128    function castPath(value, object) {
6129      if (isArray(value)) {
6130        return value;
6131      }
6132      return isKey(value, object) ? [value] : stringToPath(toString(value));
6133    }
6134
6135    /**
6136     * A `baseRest` alias which can be replaced with `identity` by module
6137     * replacement plugins.
6138     *
6139     * @private
6140     * @type {Function}
6141     * @param {Function} func The function to apply a rest parameter to.
6142     * @returns {Function} Returns the new function.
6143     */
6144    var castRest = baseRest;
6145
6146    /**
6147     * Casts `array` to a slice if it's needed.
6148     *
6149     * @private
6150     * @param {Array} array The array to inspect.
6151     * @param {number} start The start position.
6152     * @param {number} [end=array.length] The end position.
6153     * @returns {Array} Returns the cast slice.
6154     */
6155    function castSlice(array, start, end) {
6156      var length = array.length;
6157      end = end === undefined ? length : end;
6158      return (!start && end >= length) ? array : baseSlice(array, start, end);
6159    }
6160
6161    /**
6162     * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
6163     *
6164     * @private
6165     * @param {number|Object} id The timer id or timeout object of the timer to clear.
6166     */
6167    var clearTimeout = ctxClearTimeout || function(id) {
6168      return root.clearTimeout(id);
6169    };
6170
6171    /**
6172     * Creates a clone of  `buffer`.
6173     *
6174     * @private
6175     * @param {Buffer} buffer The buffer to clone.
6176     * @param {boolean} [isDeep] Specify a deep clone.
6177     * @returns {Buffer} Returns the cloned buffer.
6178     */
6179    function cloneBuffer(buffer, isDeep) {
6180      if (isDeep) {
6181        return buffer.slice();
6182      }
6183      var length = buffer.length,
6184          result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);
6185
6186      buffer.copy(result);
6187      return result;
6188    }
6189
6190    /**
6191     * Creates a clone of `arrayBuffer`.
6192     *
6193     * @private
6194     * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
6195     * @returns {ArrayBuffer} Returns the cloned array buffer.
6196     */
6197    function cloneArrayBuffer(arrayBuffer) {
6198      var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
6199      new Uint8Array(result).set(new Uint8Array(arrayBuffer));
6200      return result;
6201    }
6202
6203    /**
6204     * Creates a clone of `dataView`.
6205     *
6206     * @private
6207     * @param {Object} dataView The data view to clone.
6208     * @param {boolean} [isDeep] Specify a deep clone.
6209     * @returns {Object} Returns the cloned data view.
6210     */
6211    function cloneDataView(dataView, isDeep) {
6212      var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
6213      return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
6214    }
6215
6216    /**
6217     * Creates a clone of `regexp`.
6218     *
6219     * @private
6220     * @param {Object} regexp The regexp to clone.
6221     * @returns {Object} Returns the cloned regexp.
6222     */
6223    function cloneRegExp(regexp) {
6224      var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
6225      result.lastIndex = regexp.lastIndex;
6226      return result;
6227    }
6228
6229    /**
6230     * Creates a clone of the `symbol` object.
6231     *
6232     * @private
6233     * @param {Object} symbol The symbol object to clone.
6234     * @returns {Object} Returns the cloned symbol object.
6235     */
6236    function cloneSymbol(symbol) {
6237      return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
6238    }
6239
6240    /**
6241     * Creates a clone of `typedArray`.
6242     *
6243     * @private
6244     * @param {Object} typedArray The typed array to clone.
6245     * @param {boolean} [isDeep] Specify a deep clone.
6246     * @returns {Object} Returns the cloned typed array.
6247     */
6248    function cloneTypedArray(typedArray, isDeep) {
6249      var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
6250      return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
6251    }
6252
6253    /**
6254     * Compares values to sort them in ascending order.
6255     *
6256     * @private
6257     * @param {*} value The value to compare.
6258     * @param {*} other The other value to compare.
6259     * @returns {number} Returns the sort order indicator for `value`.
6260     */
6261    function compareAscending(value, other) {
6262      if (value !== other) {
6263        var valIsDefined = value !== undefined,
6264            valIsNull = value === null,
6265            valIsReflexive = value === value,
6266            valIsSymbol = isSymbol(value);
6267
6268        var othIsDefined = other !== undefined,
6269            othIsNull = other === null,
6270            othIsReflexive = other === other,
6271            othIsSymbol = isSymbol(other);
6272
6273        if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
6274            (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
6275            (valIsNull && othIsDefined && othIsReflexive) ||
6276            (!valIsDefined && othIsReflexive) ||
6277            !valIsReflexive) {
6278          return 1;
6279        }
6280        if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
6281            (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
6282            (othIsNull && valIsDefined && valIsReflexive) ||
6283            (!othIsDefined && valIsReflexive) ||
6284            !othIsReflexive) {
6285          return -1;
6286        }
6287      }
6288      return 0;
6289    }
6290
6291    /**
6292     * Used by `_.orderBy` to compare multiple properties of a value to another
6293     * and stable sort them.
6294     *
6295     * If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
6296     * specify an order of "desc" for descending or "asc" for ascending sort order
6297     * of corresponding values.
6298     *
6299     * @private
6300     * @param {Object} object The object to compare.
6301     * @param {Object} other The other object to compare.
6302     * @param {boolean[]|string[]} orders The order to sort by for each property.
6303     * @returns {number} Returns the sort order indicator for `object`.
6304     */
6305    function compareMultiple(object, other, orders) {
6306      var index = -1,
6307          objCriteria = object.criteria,
6308          othCriteria = other.criteria,
6309          length = objCriteria.length,
6310          ordersLength = orders.length;
6311
6312      while (++index < length) {
6313        var result = compareAscending(objCriteria[index], othCriteria[index]);
6314        if (result) {
6315          if (index >= ordersLength) {
6316            return result;
6317          }
6318          var order = orders[index];
6319          return result * (order == 'desc' ? -1 : 1);
6320        }
6321      }
6322      // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
6323      // that causes it, under certain circumstances, to provide the same value for
6324      // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
6325      // for more details.
6326      //
6327      // This also ensures a stable sort in V8 and other engines.
6328      // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
6329      return object.index - other.index;
6330    }
6331
6332    /**
6333     * Creates an array that is the composition of partially applied arguments,
6334     * placeholders, and provided arguments into a single array of arguments.
6335     *
6336     * @private
6337     * @param {Array} args The provided arguments.
6338     * @param {Array} partials The arguments to prepend to those provided.
6339     * @param {Array} holders The `partials` placeholder indexes.
6340     * @params {boolean} [isCurried] Specify composing for a curried function.
6341     * @returns {Array} Returns the new array of composed arguments.
6342     */
6343    function composeArgs(args, partials, holders, isCurried) {
6344      var argsIndex = -1,
6345          argsLength = args.length,
6346          holdersLength = holders.length,
6347          leftIndex = -1,
6348          leftLength = partials.length,
6349          rangeLength = nativeMax(argsLength - holdersLength, 0),
6350          result = Array(leftLength + rangeLength),
6351          isUncurried = !isCurried;
6352
6353      while (++leftIndex < leftLength) {
6354        result[leftIndex] = partials[leftIndex];
6355      }
6356      while (++argsIndex < holdersLength) {
6357        if (isUncurried || argsIndex < argsLength) {
6358          result[holders[argsIndex]] = args[argsIndex];
6359        }
6360      }
6361      while (rangeLength--) {
6362        result[leftIndex++] = args[argsIndex++];
6363      }
6364      return result;
6365    }
6366
6367    /**
6368     * This function is like `composeArgs` except that the arguments composition
6369     * is tailored for `_.partialRight`.
6370     *
6371     * @private
6372     * @param {Array} args The provided arguments.
6373     * @param {Array} partials The arguments to append to those provided.
6374     * @param {Array} holders The `partials` placeholder indexes.
6375     * @params {boolean} [isCurried] Specify composing for a curried function.
6376     * @returns {Array} Returns the new array of composed arguments.
6377     */
6378    function composeArgsRight(args, partials, holders, isCurried) {
6379      var argsIndex = -1,
6380          argsLength = args.length,
6381          holdersIndex = -1,
6382          holdersLength = holders.length,
6383          rightIndex = -1,
6384          rightLength = partials.length,
6385          rangeLength = nativeMax(argsLength - holdersLength, 0),
6386          result = Array(rangeLength + rightLength),
6387          isUncurried = !isCurried;
6388
6389      while (++argsIndex < rangeLength) {
6390        result[argsIndex] = args[argsIndex];
6391      }
6392      var offset = argsIndex;
6393      while (++rightIndex < rightLength) {
6394        result[offset + rightIndex] = partials[rightIndex];
6395      }
6396      while (++holdersIndex < holdersLength) {
6397        if (isUncurried || argsIndex < argsLength) {
6398          result[offset + holders[holdersIndex]] = args[argsIndex++];
6399        }
6400      }
6401      return result;
6402    }
6403
6404    /**
6405     * Copies the values of `source` to `array`.
6406     *
6407     * @private
6408     * @param {Array} source The array to copy values from.
6409     * @param {Array} [array=[]] The array to copy values to.
6410     * @returns {Array} Returns `array`.
6411     */
6412    function copyArray(source, array) {
6413      var index = -1,
6414          length = source.length;
6415
6416      array || (array = Array(length));
6417      while (++index < length) {
6418        array[index] = source[index];
6419      }
6420      return array;
6421    }
6422
6423    /**
6424     * Copies properties of `source` to `object`.
6425     *
6426     * @private
6427     * @param {Object} source The object to copy properties from.
6428     * @param {Array} props The property identifiers to copy.
6429     * @param {Object} [object={}] The object to copy properties to.
6430     * @param {Function} [customizer] The function to customize copied values.
6431     * @returns {Object} Returns `object`.
6432     */
6433    function copyObject(source, props, object, customizer) {
6434      var isNew = !object;
6435      object || (object = {});
6436
6437      var index = -1,
6438          length = props.length;
6439
6440      while (++index < length) {
6441        var key = props[index];
6442
6443        var newValue = customizer
6444          ? customizer(object[key], source[key], key, object, source)
6445          : undefined;
6446
6447        if (newValue === undefined) {
6448          newValue = source[key];
6449        }
6450        if (isNew) {
6451          baseAssignValue(object, key, newValue);
6452        } else {
6453          assignValue(object, key, newValue);
6454        }
6455      }
6456      return object;
6457    }
6458
6459    /**
6460     * Copies own symbols of `source` to `object`.
6461     *
6462     * @private
6463     * @param {Object} source The object to copy symbols from.
6464     * @param {Object} [object={}] The object to copy symbols to.
6465     * @returns {Object} Returns `object`.
6466     */
6467    function copySymbols(source, object) {
6468      return copyObject(source, getSymbols(source), object);
6469    }
6470
6471    /**
6472     * Copies own and inherited symbols of `source` to `object`.
6473     *
6474     * @private
6475     * @param {Object} source The object to copy symbols from.
6476     * @param {Object} [object={}] The object to copy symbols to.
6477     * @returns {Object} Returns `object`.
6478     */
6479    function copySymbolsIn(source, object) {
6480      return copyObject(source, getSymbolsIn(source), object);
6481    }
6482
6483    /**
6484     * Creates a function like `_.groupBy`.
6485     *
6486     * @private
6487     * @param {Function} setter The function to set accumulator values.
6488     * @param {Function} [initializer] The accumulator object initializer.
6489     * @returns {Function} Returns the new aggregator function.
6490     */
6491    function createAggregator(setter, initializer) {
6492      return function(collection, iteratee) {
6493        var func = isArray(collection) ? arrayAggregator : baseAggregator,
6494            accumulator = initializer ? initializer() : {};
6495
6496        return func(collection, setter, getIteratee(iteratee, 2), accumulator);
6497      };
6498    }
6499
6500    /**
6501     * Creates a function like `_.assign`.
6502     *
6503     * @private
6504     * @param {Function} assigner The function to assign values.
6505     * @returns {Function} Returns the new assigner function.
6506     */
6507    function createAssigner(assigner) {
6508      return baseRest(function(object, sources) {
6509        var index = -1,
6510            length = sources.length,
6511            customizer = length > 1 ? sources[length - 1] : undefined,
6512            guard = length > 2 ? sources[2] : undefined;
6513
6514        customizer = (assigner.length > 3 && typeof customizer == 'function')
6515          ? (length--, customizer)
6516          : undefined;
6517
6518        if (guard && isIterateeCall(sources[0], sources[1], guard)) {
6519          customizer = length < 3 ? undefined : customizer;
6520          length = 1;
6521        }
6522        object = Object(object);
6523        while (++index < length) {
6524          var source = sources[index];
6525          if (source) {
6526            assigner(object, source, index, customizer);
6527          }
6528        }
6529        return object;
6530      });
6531    }
6532
6533    /**
6534     * Creates a `baseEach` or `baseEachRight` function.
6535     *
6536     * @private
6537     * @param {Function} eachFunc The function to iterate over a collection.
6538     * @param {boolean} [fromRight] Specify iterating from right to left.
6539     * @returns {Function} Returns the new base function.
6540     */
6541    function createBaseEach(eachFunc, fromRight) {
6542      return function(collection, iteratee) {
6543        if (collection == null) {
6544          return collection;
6545        }
6546        if (!isArrayLike(collection)) {
6547          return eachFunc(collection, iteratee);
6548        }
6549        var length = collection.length,
6550            index = fromRight ? length : -1,
6551            iterable = Object(collection);
6552
6553        while ((fromRight ? index-- : ++index < length)) {
6554          if (iteratee(iterable[index], index, iterable) === false) {
6555            break;
6556          }
6557        }
6558        return collection;
6559      };
6560    }
6561
6562    /**
6563     * Creates a base function for methods like `_.forIn` and `_.forOwn`.
6564     *
6565     * @private
6566     * @param {boolean} [fromRight] Specify iterating from right to left.
6567     * @returns {Function} Returns the new base function.
6568     */
6569    function createBaseFor(fromRight) {
6570      return function(object, iteratee, keysFunc) {
6571        var index = -1,
6572            iterable = Object(object),
6573            props = keysFunc(object),
6574            length = props.length;
6575
6576        while (length--) {
6577          var key = props[fromRight ? length : ++index];
6578          if (iteratee(iterable[key], key, iterable) === false) {
6579            break;
6580          }
6581        }
6582        return object;
6583      };
6584    }
6585
6586    /**
6587     * Creates a function that wraps `func` to invoke it with the optional `this`
6588     * binding of `thisArg`.
6589     *
6590     * @private
6591     * @param {Function} func The function to wrap.
6592     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6593     * @param {*} [thisArg] The `this` binding of `func`.
6594     * @returns {Function} Returns the new wrapped function.
6595     */
6596    function createBind(func, bitmask, thisArg) {
6597      var isBind = bitmask & WRAP_BIND_FLAG,
6598          Ctor = createCtor(func);
6599
6600      function wrapper() {
6601        var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
6602        return fn.apply(isBind ? thisArg : this, arguments);
6603      }
6604      return wrapper;
6605    }
6606
6607    /**
6608     * Creates a function like `_.lowerFirst`.
6609     *
6610     * @private
6611     * @param {string} methodName The name of the `String` case method to use.
6612     * @returns {Function} Returns the new case function.
6613     */
6614    function createCaseFirst(methodName) {
6615      return function(string) {
6616        string = toString(string);
6617
6618        var strSymbols = hasUnicode(string)
6619          ? stringToArray(string)
6620          : undefined;
6621
6622        var chr = strSymbols
6623          ? strSymbols[0]
6624          : string.charAt(0);
6625
6626        var trailing = strSymbols
6627          ? castSlice(strSymbols, 1).join('')
6628          : string.slice(1);
6629
6630        return chr[methodName]() + trailing;
6631      };
6632    }
6633
6634    /**
6635     * Creates a function like `_.camelCase`.
6636     *
6637     * @private
6638     * @param {Function} callback The function to combine each word.
6639     * @returns {Function} Returns the new compounder function.
6640     */
6641    function createCompounder(callback) {
6642      return function(string) {
6643        return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
6644      };
6645    }
6646
6647    /**
6648     * Creates a function that produces an instance of `Ctor` regardless of
6649     * whether it was invoked as part of a `new` expression or by `call` or `apply`.
6650     *
6651     * @private
6652     * @param {Function} Ctor The constructor to wrap.
6653     * @returns {Function} Returns the new wrapped function.
6654     */
6655    function createCtor(Ctor) {
6656      return function() {
6657        // Use a `switch` statement to work with class constructors. See
6658        // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
6659        // for more details.
6660        var args = arguments;
6661        switch (args.length) {
6662          case 0: return new Ctor;
6663          case 1: return new Ctor(args[0]);
6664          case 2: return new Ctor(args[0], args[1]);
6665          case 3: return new Ctor(args[0], args[1], args[2]);
6666          case 4: return new Ctor(args[0], args[1], args[2], args[3]);
6667          case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
6668          case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
6669          case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
6670        }
6671        var thisBinding = baseCreate(Ctor.prototype),
6672            result = Ctor.apply(thisBinding, args);
6673
6674        // Mimic the constructor's `return` behavior.
6675        // See https://es5.github.io/#x13.2.2 for more details.
6676        return isObject(result) ? result : thisBinding;
6677      };
6678    }
6679
6680    /**
6681     * Creates a function that wraps `func` to enable currying.
6682     *
6683     * @private
6684     * @param {Function} func The function to wrap.
6685     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6686     * @param {number} arity The arity of `func`.
6687     * @returns {Function} Returns the new wrapped function.
6688     */
6689    function createCurry(func, bitmask, arity) {
6690      var Ctor = createCtor(func);
6691
6692      function wrapper() {
6693        var length = arguments.length,
6694            args = Array(length),
6695            index = length,
6696            placeholder = getHolder(wrapper);
6697
6698        while (index--) {
6699          args[index] = arguments[index];
6700        }
6701        var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
6702          ? []
6703          : replaceHolders(args, placeholder);
6704
6705        length -= holders.length;
6706        if (length < arity) {
6707          return createRecurry(
6708            func, bitmask, createHybrid, wrapper.placeholder, undefined,
6709            args, holders, undefined, undefined, arity - length);
6710        }
6711        var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
6712        return apply(fn, this, args);
6713      }
6714      return wrapper;
6715    }
6716
6717    /**
6718     * Creates a `_.find` or `_.findLast` function.
6719     *
6720     * @private
6721     * @param {Function} findIndexFunc The function to find the collection index.
6722     * @returns {Function} Returns the new find function.
6723     */
6724    function createFind(findIndexFunc) {
6725      return function(collection, predicate, fromIndex) {
6726        var iterable = Object(collection);
6727        if (!isArrayLike(collection)) {
6728          var iteratee = getIteratee(predicate, 3);
6729          collection = keys(collection);
6730          predicate = function(key) { return iteratee(iterable[key], key, iterable); };
6731        }
6732        var index = findIndexFunc(collection, predicate, fromIndex);
6733        return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
6734      };
6735    }
6736
6737    /**
6738     * Creates a `_.flow` or `_.flowRight` function.
6739     *
6740     * @private
6741     * @param {boolean} [fromRight] Specify iterating from right to left.
6742     * @returns {Function} Returns the new flow function.
6743     */
6744    function createFlow(fromRight) {
6745      return flatRest(function(funcs) {
6746        var length = funcs.length,
6747            index = length,
6748            prereq = LodashWrapper.prototype.thru;
6749
6750        if (fromRight) {
6751          funcs.reverse();
6752        }
6753        while (index--) {
6754          var func = funcs[index];
6755          if (typeof func != 'function') {
6756            throw new TypeError(FUNC_ERROR_TEXT);
6757          }
6758          if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
6759            var wrapper = new LodashWrapper([], true);
6760          }
6761        }
6762        index = wrapper ? index : length;
6763        while (++index < length) {
6764          func = funcs[index];
6765
6766          var funcName = getFuncName(func),
6767              data = funcName == 'wrapper' ? getData(func) : undefined;
6768
6769          if (data && isLaziable(data[0]) &&
6770                data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) &&
6771                !data[4].length && data[9] == 1
6772              ) {
6773            wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
6774          } else {
6775            wrapper = (func.length == 1 && isLaziable(func))
6776              ? wrapper[funcName]()
6777              : wrapper.thru(func);
6778          }
6779        }
6780        return function() {
6781          var args = arguments,
6782              value = args[0];
6783
6784          if (wrapper && args.length == 1 && isArray(value)) {
6785            return wrapper.plant(value).value();
6786          }
6787          var index = 0,
6788              result = length ? funcs[index].apply(this, args) : value;
6789
6790          while (++index < length) {
6791            result = funcs[index].call(this, result);
6792          }
6793          return result;
6794        };
6795      });
6796    }
6797
6798    /**
6799     * Creates a function that wraps `func` to invoke it with optional `this`
6800     * binding of `thisArg`, partial application, and currying.
6801     *
6802     * @private
6803     * @param {Function|string} func The function or method name to wrap.
6804     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6805     * @param {*} [thisArg] The `this` binding of `func`.
6806     * @param {Array} [partials] The arguments to prepend to those provided to
6807     *  the new function.
6808     * @param {Array} [holders] The `partials` placeholder indexes.
6809     * @param {Array} [partialsRight] The arguments to append to those provided
6810     *  to the new function.
6811     * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
6812     * @param {Array} [argPos] The argument positions of the new function.
6813     * @param {number} [ary] The arity cap of `func`.
6814     * @param {number} [arity] The arity of `func`.
6815     * @returns {Function} Returns the new wrapped function.
6816     */
6817    function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
6818      var isAry = bitmask & WRAP_ARY_FLAG,
6819          isBind = bitmask & WRAP_BIND_FLAG,
6820          isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
6821          isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
6822          isFlip = bitmask & WRAP_FLIP_FLAG,
6823          Ctor = isBindKey ? undefined : createCtor(func);
6824
6825      function wrapper() {
6826        var length = arguments.length,
6827            args = Array(length),
6828            index = length;
6829
6830        while (index--) {
6831          args[index] = arguments[index];
6832        }
6833        if (isCurried) {
6834          var placeholder = getHolder(wrapper),
6835              holdersCount = countHolders(args, placeholder);
6836        }
6837        if (partials) {
6838          args = composeArgs(args, partials, holders, isCurried);
6839        }
6840        if (partialsRight) {
6841          args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
6842        }
6843        length -= holdersCount;
6844        if (isCurried && length < arity) {
6845          var newHolders = replaceHolders(args, placeholder);
6846          return createRecurry(
6847            func, bitmask, createHybrid, wrapper.placeholder, thisArg,
6848            args, newHolders, argPos, ary, arity - length
6849          );
6850        }
6851        var thisBinding = isBind ? thisArg : this,
6852            fn = isBindKey ? thisBinding[func] : func;
6853
6854        length = args.length;
6855        if (argPos) {
6856          args = reorder(args, argPos);
6857        } else if (isFlip && length > 1) {
6858          args.reverse();
6859        }
6860        if (isAry && ary < length) {
6861          args.length = ary;
6862        }
6863        if (this && this !== root && this instanceof wrapper) {
6864          fn = Ctor || createCtor(fn);
6865        }
6866        return fn.apply(thisBinding, args);
6867      }
6868      return wrapper;
6869    }
6870
6871    /**
6872     * Creates a function like `_.invertBy`.
6873     *
6874     * @private
6875     * @param {Function} setter The function to set accumulator values.
6876     * @param {Function} toIteratee The function to resolve iteratees.
6877     * @returns {Function} Returns the new inverter function.
6878     */
6879    function createInverter(setter, toIteratee) {
6880      return function(object, iteratee) {
6881        return baseInverter(object, setter, toIteratee(iteratee), {});
6882      };
6883    }
6884
6885    /**
6886     * Creates a function that performs a mathematical operation on two values.
6887     *
6888     * @private
6889     * @param {Function} operator The function to perform the operation.
6890     * @param {number} [defaultValue] The value used for `undefined` arguments.
6891     * @returns {Function} Returns the new mathematical operation function.
6892     */
6893    function createMathOperation(operator, defaultValue) {
6894      return function(value, other) {
6895        var result;
6896        if (value === undefined && other === undefined) {
6897          return defaultValue;
6898        }
6899        if (value !== undefined) {
6900          result = value;
6901        }
6902        if (other !== undefined) {
6903          if (result === undefined) {
6904            return other;
6905          }
6906          if (typeof value == 'string' || typeof other == 'string') {
6907            value = baseToString(value);
6908            other = baseToString(other);
6909          } else {
6910            value = baseToNumber(value);
6911            other = baseToNumber(other);
6912          }
6913          result = operator(value, other);
6914        }
6915        return result;
6916      };
6917    }
6918
6919    /**
6920     * Creates a function like `_.over`.
6921     *
6922     * @private
6923     * @param {Function} arrayFunc The function to iterate over iteratees.
6924     * @returns {Function} Returns the new over function.
6925     */
6926    function createOver(arrayFunc) {
6927      return flatRest(function(iteratees) {
6928        iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
6929        return baseRest(function(args) {
6930          var thisArg = this;
6931          return arrayFunc(iteratees, function(iteratee) {
6932            return apply(iteratee, thisArg, args);
6933          });
6934        });
6935      });
6936    }
6937
6938    /**
6939     * Creates the padding for `string` based on `length`. The `chars` string
6940     * is truncated if the number of characters exceeds `length`.
6941     *
6942     * @private
6943     * @param {number} length The padding length.
6944     * @param {string} [chars=' '] The string used as padding.
6945     * @returns {string} Returns the padding for `string`.
6946     */
6947    function createPadding(length, chars) {
6948      chars = chars === undefined ? ' ' : baseToString(chars);
6949
6950      var charsLength = chars.length;
6951      if (charsLength < 2) {
6952        return charsLength ? baseRepeat(chars, length) : chars;
6953      }
6954      var result = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
6955      return hasUnicode(chars)
6956        ? castSlice(stringToArray(result), 0, length).join('')
6957        : result.slice(0, length);
6958    }
6959
6960    /**
6961     * Creates a function that wraps `func` to invoke it with the `this` binding
6962     * of `thisArg` and `partials` prepended to the arguments it receives.
6963     *
6964     * @private
6965     * @param {Function} func The function to wrap.
6966     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6967     * @param {*} thisArg The `this` binding of `func`.
6968     * @param {Array} partials The arguments to prepend to those provided to
6969     *  the new function.
6970     * @returns {Function} Returns the new wrapped function.
6971     */
6972    function createPartial(func, bitmask, thisArg, partials) {
6973      var isBind = bitmask & WRAP_BIND_FLAG,
6974          Ctor = createCtor(func);
6975
6976      function wrapper() {
6977        var argsIndex = -1,
6978            argsLength = arguments.length,
6979            leftIndex = -1,
6980            leftLength = partials.length,
6981            args = Array(leftLength + argsLength),
6982            fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
6983
6984        while (++leftIndex < leftLength) {
6985          args[leftIndex] = partials[leftIndex];
6986        }
6987        while (argsLength--) {
6988          args[leftIndex++] = arguments[++argsIndex];
6989        }
6990        return apply(fn, isBind ? thisArg : this, args);
6991      }
6992      return wrapper;
6993    }
6994
6995    /**
6996     * Creates a `_.range` or `_.rangeRight` function.
6997     *
6998     * @private
6999     * @param {boolean} [fromRight] Specify iterating from right to left.
7000     * @returns {Function} Returns the new range function.
7001     */
7002    function createRange(fromRight) {
7003      return function(start, end, step) {
7004        if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {
7005          end = step = undefined;
7006        }
7007        // Ensure the sign of `-0` is preserved.
7008        start = toFinite(start);
7009        if (end === undefined) {
7010          end = start;
7011          start = 0;
7012        } else {
7013          end = toFinite(end);
7014        }
7015        step = step === undefined ? (start < end ? 1 : -1) : toFinite(step);
7016        return baseRange(start, end, step, fromRight);
7017      };
7018    }
7019
7020    /**
7021     * Creates a function that performs a relational operation on two values.
7022     *
7023     * @private
7024     * @param {Function} operator The function to perform the operation.
7025     * @returns {Function} Returns the new relational operation function.
7026     */
7027    function createRelationalOperation(operator) {
7028      return function(value, other) {
7029        if (!(typeof value == 'string' && typeof other == 'string')) {
7030          value = toNumber(value);
7031          other = toNumber(other);
7032        }
7033        return operator(value, other);
7034      };
7035    }
7036
7037    /**
7038     * Creates a function that wraps `func` to continue currying.
7039     *
7040     * @private
7041     * @param {Function} func The function to wrap.
7042     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
7043     * @param {Function} wrapFunc The function to create the `func` wrapper.
7044     * @param {*} placeholder The placeholder value.
7045     * @param {*} [thisArg] The `this` binding of `func`.
7046     * @param {Array} [partials] The arguments to prepend to those provided to
7047     *  the new function.
7048     * @param {Array} [holders] The `partials` placeholder indexes.
7049     * @param {Array} [argPos] The argument positions of the new function.
7050     * @param {number} [ary] The arity cap of `func`.
7051     * @param {number} [arity] The arity of `func`.
7052     * @returns {Function} Returns the new wrapped function.
7053     */
7054    function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
7055      var isCurry = bitmask & WRAP_CURRY_FLAG,
7056          newHolders = isCurry ? holders : undefined,
7057          newHoldersRight = isCurry ? undefined : holders,
7058          newPartials = isCurry ? partials : undefined,
7059          newPartialsRight = isCurry ? undefined : partials;
7060
7061      bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG);
7062      bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);
7063
7064      if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
7065        bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG);
7066      }
7067      var newData = [
7068        func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
7069        newHoldersRight, argPos, ary, arity
7070      ];
7071
7072      var result = wrapFunc.apply(undefined, newData);
7073      if (isLaziable(func)) {
7074        setData(result, newData);
7075      }
7076      result.placeholder = placeholder;
7077      return setWrapToString(result, func, bitmask);
7078    }
7079
7080    /**
7081     * Creates a function like `_.round`.
7082     *
7083     * @private
7084     * @param {string} methodName The name of the `Math` method to use when rounding.
7085     * @returns {Function} Returns the new round function.
7086     */
7087    function createRound(methodName) {
7088      var func = Math[methodName];
7089      return function(number, precision) {
7090        number = toNumber(number);
7091        precision = precision == null ? 0 : nativeMin(toInteger(precision), 292);
7092        if (precision && nativeIsFinite(number)) {
7093          // Shift with exponential notation to avoid floating-point issues.
7094          // See [MDN](https://mdn.io/round#Examples) for more details.
7095          var pair = (toString(number) + 'e').split('e'),
7096              value = func(pair[0] + 'e' + (+pair[1] + precision));
7097
7098          pair = (toString(value) + 'e').split('e');
7099          return +(pair[0] + 'e' + (+pair[1] - precision));
7100        }
7101        return func(number);
7102      };
7103    }
7104
7105    /**
7106     * Creates a set object of `values`.
7107     *
7108     * @private
7109     * @param {Array} values The values to add to the set.
7110     * @returns {Object} Returns the new set.
7111     */
7112    var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
7113      return new Set(values);
7114    };
7115
7116    /**
7117     * Creates a `_.toPairs` or `_.toPairsIn` function.
7118     *
7119     * @private
7120     * @param {Function} keysFunc The function to get the keys of a given object.
7121     * @returns {Function} Returns the new pairs function.
7122     */
7123    function createToPairs(keysFunc) {
7124      return function(object) {
7125        var tag = getTag(object);
7126        if (tag == mapTag) {
7127          return mapToArray(object);
7128        }
7129        if (tag == setTag) {
7130          return setToPairs(object);
7131        }
7132        return baseToPairs(object, keysFunc(object));
7133      };
7134    }
7135
7136    /**
7137     * Creates a function that either curries or invokes `func` with optional
7138     * `this` binding and partially applied arguments.
7139     *
7140     * @private
7141     * @param {Function|string} func The function or method name to wrap.
7142     * @param {number} bitmask The bitmask flags.
7143     *    1 - `_.bind`
7144     *    2 - `_.bindKey`
7145     *    4 - `_.curry` or `_.curryRight` of a bound function
7146     *    8 - `_.curry`
7147     *   16 - `_.curryRight`
7148     *   32 - `_.partial`
7149     *   64 - `_.partialRight`
7150     *  128 - `_.rearg`
7151     *  256 - `_.ary`
7152     *  512 - `_.flip`
7153     * @param {*} [thisArg] The `this` binding of `func`.
7154     * @param {Array} [partials] The arguments to be partially applied.
7155     * @param {Array} [holders] The `partials` placeholder indexes.
7156     * @param {Array} [argPos] The argument positions of the new function.
7157     * @param {number} [ary] The arity cap of `func`.
7158     * @param {number} [arity] The arity of `func`.
7159     * @returns {Function} Returns the new wrapped function.
7160     */
7161    function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
7162      var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;
7163      if (!isBindKey && typeof func != 'function') {
7164        throw new TypeError(FUNC_ERROR_TEXT);
7165      }
7166      var length = partials ? partials.length : 0;
7167      if (!length) {
7168        bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);
7169        partials = holders = undefined;
7170      }
7171      ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
7172      arity = arity === undefined ? arity : toInteger(arity);
7173      length -= holders ? holders.length : 0;
7174
7175      if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {
7176        var partialsRight = partials,
7177            holdersRight = holders;
7178
7179        partials = holders = undefined;
7180      }
7181      var data = isBindKey ? undefined : getData(func);
7182
7183      var newData = [
7184        func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
7185        argPos, ary, arity
7186      ];
7187
7188      if (data) {
7189        mergeData(newData, data);
7190      }
7191      func = newData[0];
7192      bitmask = newData[1];
7193      thisArg = newData[2];
7194      partials = newData[3];
7195      holders = newData[4];
7196      arity = newData[9] = newData[9] === undefined
7197        ? (isBindKey ? 0 : func.length)
7198        : nativeMax(newData[9] - length, 0);
7199
7200      if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
7201        bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG);
7202      }
7203      if (!bitmask || bitmask == WRAP_BIND_FLAG) {
7204        var result = createBind(func, bitmask, thisArg);
7205      } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) {
7206        result = createCurry(func, bitmask, arity);
7207      } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) {
7208        result = createPartial(func, bitmask, thisArg, partials);
7209      } else {
7210        result = createHybrid.apply(undefined, newData);
7211      }
7212      var setter = data ? baseSetData : setData;
7213      return setWrapToString(setter(result, newData), func, bitmask);
7214    }
7215
7216    /**
7217     * Used by `_.defaults` to customize its `_.assignIn` use to assign properties
7218     * of source objects to the destination object for all destination properties
7219     * that resolve to `undefined`.
7220     *
7221     * @private
7222     * @param {*} objValue The destination value.
7223     * @param {*} srcValue The source value.
7224     * @param {string} key The key of the property to assign.
7225     * @param {Object} object The parent object of `objValue`.
7226     * @returns {*} Returns the value to assign.
7227     */
7228    function customDefaultsAssignIn(objValue, srcValue, key, object) {
7229      if (objValue === undefined ||
7230          (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) {
7231        return srcValue;
7232      }
7233      return objValue;
7234    }
7235
7236    /**
7237     * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source
7238     * objects into destination objects that are passed thru.
7239     *
7240     * @private
7241     * @param {*} objValue The destination value.
7242     * @param {*} srcValue The source value.
7243     * @param {string} key The key of the property to merge.
7244     * @param {Object} object The parent object of `objValue`.
7245     * @param {Object} source The parent object of `srcValue`.
7246     * @param {Object} [stack] Tracks traversed source values and their merged
7247     *  counterparts.
7248     * @returns {*} Returns the value to assign.
7249     */
7250    function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
7251      if (isObject(objValue) && isObject(srcValue)) {
7252        // Recursively merge objects and arrays (susceptible to call stack limits).
7253        stack.set(srcValue, objValue);
7254        baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack);
7255        stack['delete'](srcValue);
7256      }
7257      return objValue;
7258    }
7259
7260    /**
7261     * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain
7262     * objects.
7263     *
7264     * @private
7265     * @param {*} value The value to inspect.
7266     * @param {string} key The key of the property to inspect.
7267     * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.
7268     */
7269    function customOmitClone(value) {
7270      return isPlainObject(value) ? undefined : value;
7271    }
7272
7273    /**
7274     * A specialized version of `baseIsEqualDeep` for arrays with support for
7275     * partial deep comparisons.
7276     *
7277     * @private
7278     * @param {Array} array The array to compare.
7279     * @param {Array} other The other array to compare.
7280     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
7281     * @param {Function} customizer The function to customize comparisons.
7282     * @param {Function} equalFunc The function to determine equivalents of values.
7283     * @param {Object} stack Tracks traversed `array` and `other` objects.
7284     * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
7285     */
7286    function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
7287      var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
7288          arrLength = array.length,
7289          othLength = other.length;
7290
7291      if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
7292        return false;
7293      }
7294      // Check that cyclic values are equal.
7295      var arrStacked = stack.get(array);
7296      var othStacked = stack.get(other);
7297      if (arrStacked && othStacked) {
7298        return arrStacked == other && othStacked == array;
7299      }
7300      var index = -1,
7301          result = true,
7302          seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;
7303
7304      stack.set(array, other);
7305      stack.set(other, array);
7306
7307      // Ignore non-index properties.
7308      while (++index < arrLength) {
7309        var arrValue = array[index],
7310            othValue = other[index];
7311
7312        if (customizer) {
7313          var compared = isPartial
7314            ? customizer(othValue, arrValue, index, other, array, stack)
7315            : customizer(arrValue, othValue, index, array, other, stack);
7316        }
7317        if (compared !== undefined) {
7318          if (compared) {
7319            continue;
7320          }
7321          result = false;
7322          break;
7323        }
7324        // Recursively compare arrays (susceptible to call stack limits).
7325        if (seen) {
7326          if (!arraySome(other, function(othValue, othIndex) {
7327                if (!cacheHas(seen, othIndex) &&
7328                    (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
7329                  return seen.push(othIndex);
7330                }
7331              })) {
7332            result = false;
vendor: 4,179 bytes, lines 7333-7444
7333            break;
7334          }
7335        } else if (!(
7336              arrValue === othValue ||
7337                equalFunc(arrValue, othValue, bitmask, customizer, stack)
7338            )) {
7339          result = false;
7340          break;
7341        }
7342      }
7343      stack['delete'](array);
7344      stack['delete'](other);
7345      return result;
7346    }
7347
7348    /**
7349     * A specialized version of `baseIsEqualDeep` for comparing objects of
7350     * the same `toStringTag`.
7351     *
7352     * **Note:** This function only supports comparing values with tags of
7353     * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
7354     *
7355     * @private
7356     * @param {Object} object The object to compare.
7357     * @param {Object} other The other object to compare.
7358     * @param {string} tag The `toStringTag` of the objects to compare.
7359     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
7360     * @param {Function} customizer The function to customize comparisons.
7361     * @param {Function} equalFunc The function to determine equivalents of values.
7362     * @param {Object} stack Tracks traversed `object` and `other` objects.
7363     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
7364     */
7365    function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
7366      switch (tag) {
7367        case dataViewTag:
7368          if ((object.byteLength != other.byteLength) ||
7369              (object.byteOffset != other.byteOffset)) {
7370            return false;
7371          }
7372          object = object.buffer;
7373          other = other.buffer;
7374
7375        case arrayBufferTag:
7376          if ((object.byteLength != other.byteLength) ||
7377              !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
7378            return false;
7379          }
7380          return true;
7381
7382        case boolTag:
7383        case dateTag:
7384        case numberTag:
7385          // Coerce booleans to `1` or `0` and dates to milliseconds.
7386          // Invalid dates are coerced to `NaN`.
7387          return eq(+object, +other);
7388
7389        case errorTag:
7390          return object.name == other.name && object.message == other.message;
7391
7392        case regexpTag:
7393        case stringTag:
7394          // Coerce regexes to strings and treat strings, primitives and objects,
7395          // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
7396          // for more details.
7397          return object == (other + '');
7398
7399        case mapTag:
7400          var convert = mapToArray;
7401
7402        case setTag:
7403          var isPartial = bitmask & COMPARE_PARTIAL_FLAG;
7404          convert || (convert = setToArray);
7405
7406          if (object.size != other.size && !isPartial) {
7407            return false;
7408          }
7409          // Assume cyclic values are equal.
7410          var stacked = stack.get(object);
7411          if (stacked) {
7412            return stacked == other;
7413          }
7414          bitmask |= COMPARE_UNORDERED_FLAG;
7415
7416          // Recursively compare objects (susceptible to call stack limits).
7417          stack.set(object, other);
7418          var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
7419          stack['delete'](object);
7420          return result;
7421
7422        case symbolTag:
7423          if (symbolValueOf) {
7424            return symbolValueOf.call(object) == symbolValueOf.call(other);
7425          }
7426      }
7427      return false;
7428    }
7429
7430    /**
7431     * A specialized version of `baseIsEqualDeep` for objects with support for
7432     * partial deep comparisons.
7433     *
7434     * @private
7435     * @param {Object} object The object to compare.
7436     * @param {Object} other The other object to compare.
7437     * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
7438     * @param {Function} customizer The function to customize comparisons.
7439     * @param {Function} equalFunc The function to determine equivalents of values.
7440     * @param {Object} stack Tracks traversed `object` and `other` objects.
7441     * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
7442     */
7443    function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
7444      var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
vendor: 9,614 bytes, lines 7445-7752
7445          objProps = getAllKeys(object),
7446          objLength = objProps.length,
7447          othProps = getAllKeys(other),
7448          othLength = othProps.length;
7449
7450      if (objLength != othLength && !isPartial) {
7451        return false;
7452      }
7453      var index = objLength;
7454      while (index--) {
7455        var key = objProps[index];
7456        if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
7457          return false;
7458        }
7459      }
7460      // Check that cyclic values are equal.
7461      var objStacked = stack.get(object);
7462      var othStacked = stack.get(other);
7463      if (objStacked && othStacked) {
7464        return objStacked == other && othStacked == object;
7465      }
7466      var result = true;
7467      stack.set(object, other);
7468      stack.set(other, object);
7469
7470      var skipCtor = isPartial;
7471      while (++index < objLength) {
7472        key = objProps[index];
7473        var objValue = object[key],
7474            othValue = other[key];
7475
7476        if (customizer) {
7477          var compared = isPartial
7478            ? customizer(othValue, objValue, key, other, object, stack)
7479            : customizer(objValue, othValue, key, object, other, stack);
7480        }
7481        // Recursively compare objects (susceptible to call stack limits).
7482        if (!(compared === undefined
7483              ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))
7484              : compared
7485            )) {
7486          result = false;
7487          break;
7488        }
7489        skipCtor || (skipCtor = key == 'constructor');
7490      }
7491      if (result && !skipCtor) {
7492        var objCtor = object.constructor,
7493            othCtor = other.constructor;
7494
7495        // Non `Object` object instances with different constructors are not equal.
7496        if (objCtor != othCtor &&
7497            ('constructor' in object && 'constructor' in other) &&
7498            !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
7499              typeof othCtor == 'function' && othCtor instanceof othCtor)) {
7500          result = false;
7501        }
7502      }
7503      stack['delete'](object);
7504      stack['delete'](other);
7505      return result;
7506    }
7507
7508    /**
7509     * A specialized version of `baseRest` which flattens the rest array.
7510     *
7511     * @private
7512     * @param {Function} func The function to apply a rest parameter to.
7513     * @returns {Function} Returns the new function.
7514     */
7515    function flatRest(func) {
7516      return setToString(overRest(func, undefined, flatten), func + '');
7517    }
7518
7519    /**
7520     * Creates an array of own enumerable property names and symbols of `object`.
7521     *
7522     * @private
7523     * @param {Object} object The object to query.
7524     * @returns {Array} Returns the array of property names and symbols.
7525     */
7526    function getAllKeys(object) {
7527      return baseGetAllKeys(object, keys, getSymbols);
7528    }
7529
7530    /**
7531     * Creates an array of own and inherited enumerable property names and
7532     * symbols of `object`.
7533     *
7534     * @private
7535     * @param {Object} object The object to query.
7536     * @returns {Array} Returns the array of property names and symbols.
7537     */
7538    function getAllKeysIn(object) {
7539      return baseGetAllKeys(object, keysIn, getSymbolsIn);
7540    }
7541
7542    /**
7543     * Gets metadata for `func`.
7544     *
7545     * @private
7546     * @param {Function} func The function to query.
7547     * @returns {*} Returns the metadata for `func`.
7548     */
7549    var getData = !metaMap ? noop : function(func) {
7550      return metaMap.get(func);
7551    };
7552
7553    /**
7554     * Gets the name of `func`.
7555     *
7556     * @private
7557     * @param {Function} func The function to query.
7558     * @returns {string} Returns the function name.
7559     */
7560    function getFuncName(func) {
7561      var result = (func.name + ''),
7562          array = realNames[result],
7563          length = hasOwnProperty.call(realNames, result) ? array.length : 0;
7564
7565      while (length--) {
7566        var data = array[length],
7567            otherFunc = data.func;
7568        if (otherFunc == null || otherFunc == func) {
7569          return data.name;
7570        }
7571      }
7572      return result;
7573    }
7574
7575    /**
7576     * Gets the argument placeholder value for `func`.
7577     *
7578     * @private
7579     * @param {Function} func The function to inspect.
7580     * @returns {*} Returns the placeholder value.
7581     */
7582    function getHolder(func) {
7583      var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
7584      return object.placeholder;
7585    }
7586
7587    /**
7588     * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
7589     * this function returns the custom method, otherwise it returns `baseIteratee`.
7590     * If arguments are provided, the chosen function is invoked with them and
7591     * its result is returned.
7592     *
7593     * @private
7594     * @param {*} [value] The value to convert to an iteratee.
7595     * @param {number} [arity] The arity of the created iteratee.
7596     * @returns {Function} Returns the chosen function or its result.
7597     */
7598    function getIteratee() {
7599      var result = lodash.iteratee || iteratee;
7600      result = result === iteratee ? baseIteratee : result;
7601      return arguments.length ? result(arguments[0], arguments[1]) : result;
7602    }
7603
7604    /**
7605     * Gets the data for `map`.
7606     *
7607     * @private
7608     * @param {Object} map The map to query.
7609     * @param {string} key The reference key.
7610     * @returns {*} Returns the map data.
7611     */
7612    function getMapData(map, key) {
7613      var data = map.__data__;
7614      return isKeyable(key)
7615        ? data[typeof key == 'string' ? 'string' : 'hash']
7616        : data.map;
7617    }
7618
7619    /**
7620     * Gets the property names, values, and compare flags of `object`.
7621     *
7622     * @private
7623     * @param {Object} object The object to query.
7624     * @returns {Array} Returns the match data of `object`.
7625     */
7626    function getMatchData(object) {
7627      var result = keys(object),
7628          length = result.length;
7629
7630      while (length--) {
7631        var key = result[length],
7632            value = object[key];
7633
7634        result[length] = [key, value, isStrictComparable(value)];
7635      }
7636      return result;
7637    }
7638
7639    /**
7640     * Gets the native function at `key` of `object`.
7641     *
7642     * @private
7643     * @param {Object} object The object to query.
7644     * @param {string} key The key of the method to get.
7645     * @returns {*} Returns the function if it's native, else `undefined`.
7646     */
7647    function getNative(object, key) {
7648      var value = getValue(object, key);
7649      return baseIsNative(value) ? value : undefined;
7650    }
7651
7652    /**
7653     * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
7654     *
7655     * @private
7656     * @param {*} value The value to query.
7657     * @returns {string} Returns the raw `toStringTag`.
7658     */
7659    function getRawTag(value) {
7660      var isOwn = hasOwnProperty.call(value, symToStringTag),
7661          tag = value[symToStringTag];
7662
7663      try {
7664        value[symToStringTag] = undefined;
7665        var unmasked = true;
7666      } catch (e) {}
7667
7668      var result = nativeObjectToString.call(value);
7669      if (unmasked) {
7670        if (isOwn) {
7671          value[symToStringTag] = tag;
7672        } else {
7673          delete value[symToStringTag];
7674        }
7675      }
7676      return result;
7677    }
7678
7679    /**
7680     * Creates an array of the own enumerable symbols of `object`.
7681     *
7682     * @private
7683     * @param {Object} object The object to query.
7684     * @returns {Array} Returns the array of symbols.
7685     */
7686    var getSymbols = !nativeGetSymbols ? stubArray : function(object) {
7687      if (object == null) {
7688        return [];
7689      }
7690      object = Object(object);
7691      return arrayFilter(nativeGetSymbols(object), function(symbol) {
7692        return propertyIsEnumerable.call(object, symbol);
7693      });
7694    };
7695
7696    /**
7697     * Creates an array of the own and inherited enumerable symbols of `object`.
7698     *
7699     * @private
7700     * @param {Object} object The object to query.
7701     * @returns {Array} Returns the array of symbols.
7702     */
7703    var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {
7704      var result = [];
7705      while (object) {
7706        arrayPush(result, getSymbols(object));
7707        object = getPrototype(object);
7708      }
7709      return result;
7710    };
7711
7712    /**
7713     * Gets the `toStringTag` of `value`.
7714     *
7715     * @private
7716     * @param {*} value The value to query.
7717     * @returns {string} Returns the `toStringTag`.
7718     */
7719    var getTag = baseGetTag;
7720
7721    // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
7722    if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
7723        (Map && getTag(new Map) != mapTag) ||
7724        (Promise && getTag(Promise.resolve()) != promiseTag) ||
7725        (Set && getTag(new Set) != setTag) ||
7726        (WeakMap && getTag(new WeakMap) != weakMapTag)) {
7727      getTag = function(value) {
7728        var result = baseGetTag(value),
7729            Ctor = result == objectTag ? value.constructor : undefined,
7730            ctorString = Ctor ? toSource(Ctor) : '';
7731
7732        if (ctorString) {
7733          switch (ctorString) {
7734            case dataViewCtorString: return dataViewTag;
7735            case mapCtorString: return mapTag;
7736            case promiseCtorString: return promiseTag;
7737            case setCtorString: return setTag;
7738            case weakMapCtorString: return weakMapTag;
7739          }
7740        }
7741        return result;
7742      };
7743    }
7744
7745    /**
7746     * Gets the view, applying any `transforms` to the `start` and `end` positions.
7747     *
7748     * @private
7749     * @param {number} start The start of the view.
7750     * @param {number} end The end of the view.
7751     * @param {Array} transforms The transformations to apply to the view.
7752     * @returns {Object}
vendor: 6,432 bytes, lines 7752-7957
7752 Returns an object containing the `start` and `end`
7753     *  positions of the view.
7754     */
7755    function getView(start, end, transforms) {
7756      var index = -1,
7757          length = transforms.length;
7758
7759      while (++index < length) {
7760        var data = transforms[index],
7761            size = data.size;
7762
7763        switch (data.type) {
7764          case 'drop':      start += size; break;
7765          case 'dropRight': end -= size; break;
7766          case 'take':      end = nativeMin(end, start + size); break;
7767          case 'takeRight': start = nativeMax(start, end - size); break;
7768        }
7769      }
7770      return { 'start': start, 'end': end };
7771    }
7772
7773    /**
7774     * Extracts wrapper details from the `source` body comment.
7775     *
7776     * @private
7777     * @param {string} source The source to inspect.
7778     * @returns {Array} Returns the wrapper details.
7779     */
7780    function getWrapDetails(source) {
7781      var match = source.match(reWrapDetails);
7782      return match ? match[1].split(reSplitDetails) : [];
7783    }
7784
7785    /**
7786     * Checks if `path` exists on `object`.
7787     *
7788     * @private
7789     * @param {Object} object The object to query.
7790     * @param {Array|string} path The path to check.
7791     * @param {Function} hasFunc The function to check properties.
7792     * @returns {boolean} Returns `true` if `path` exists, else `false`.
7793     */
7794    function hasPath(object, path, hasFunc) {
7795      path = castPath(path, object);
7796
7797      var index = -1,
7798          length = path.length,
7799          result = false;
7800
7801      while (++index < length) {
7802        var key = toKey(path[index]);
7803        if (!(result = object != null && hasFunc(object, key))) {
7804          break;
7805        }
7806        object = object[key];
7807      }
7808      if (result || ++index != length) {
7809        return result;
7810      }
7811      length = object == null ? 0 : object.length;
7812      return !!length && isLength(length) && isIndex(key, length) &&
7813        (isArray(object) || isArguments(object));
7814    }
7815
7816    /**
7817     * Initializes an array clone.
7818     *
7819     * @private
7820     * @param {Array} array The array to clone.
7821     * @returns {Array} Returns the initialized clone.
7822     */
7823    function initCloneArray(array) {
7824      var length = array.length,
7825          result = new array.constructor(length);
7826
7827      // Add properties assigned by `RegExp#exec`.
7828      if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
7829        result.index = array.index;
7830        result.input = array.input;
7831      }
7832      return result;
7833    }
7834
7835    /**
7836     * Initializes an object clone.
7837     *
7838     * @private
7839     * @param {Object} object The object to clone.
7840     * @returns {Object} Returns the initialized clone.
7841     */
7842    function initCloneObject(object) {
7843      return (typeof object.constructor == 'function' && !isPrototype(object))
7844        ? baseCreate(getPrototype(object))
7845        : {};
7846    }
7847
7848    /**
7849     * Initializes an object clone based on its `toStringTag`.
7850     *
7851     * **Note:** This function only supports cloning values with tags of
7852     * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.
7853     *
7854     * @private
7855     * @param {Object} object The object to clone.
7856     * @param {string} tag The `toStringTag` of the object to clone.
7857     * @param {boolean} [isDeep] Specify a deep clone.
7858     * @returns {Object} Returns the initialized clone.
7859     */
7860    function initCloneByTag(object, tag, isDeep) {
7861      var Ctor = object.constructor;
7862      switch (tag) {
7863        case arrayBufferTag:
7864          return cloneArrayBuffer(object);
7865
7866        case boolTag:
7867        case dateTag:
7868          return new Ctor(+object);
7869
7870        case dataViewTag:
7871          return cloneDataView(object, isDeep);
7872
7873        case float32Tag: case float64Tag:
7874        case int8Tag: case int16Tag: case int32Tag:
7875        case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
7876          return cloneTypedArray(object, isDeep);
7877
7878        case mapTag:
7879          return new Ctor;
7880
7881        case numberTag:
7882        case stringTag:
7883          return new Ctor(object);
7884
7885        case regexpTag:
7886          return cloneRegExp(object);
7887
7888        case setTag:
7889          return new Ctor;
7890
7891        case symbolTag:
7892          return cloneSymbol(object);
7893      }
7894    }
7895
7896    /**
7897     * Inserts wrapper `details` in a comment at the top of the `source` body.
7898     *
7899     * @private
7900     * @param {string} source The source to modify.
7901     * @returns {Array} details The details to insert.
7902     * @returns {string} Returns the modified source.
7903     */
7904    function insertWrapDetails(source, details) {
7905      var length = details.length;
7906      if (!length) {
7907        return source;
7908      }
7909      var lastIndex = length - 1;
7910      details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex];
7911      details = details.join(length > 2 ? ', ' : ' ');
7912      return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n');
7913    }
7914
7915    /**
7916     * Checks if `value` is a flattenable `arguments` object or array.
7917     *
7918     * @private
7919     * @param {*} value The value to check.
7920     * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
7921     */
7922    function isFlattenable(value) {
7923      return isArray(value) || isArguments(value) ||
7924        !!(spreadableSymbol && value && value[spreadableSymbol]);
7925    }
7926
7927    /**
7928     * Checks if `value` is a valid array-like index.
7929     *
7930     * @private
7931     * @param {*} value The value to check.
7932     * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
7933     * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
7934     */
7935    function isIndex(value, length) {
7936      var type = typeof value;
7937      length = length == null ? MAX_SAFE_INTEGER : length;
7938
7939      return !!length &&
7940        (type == 'number' ||
7941          (type != 'symbol' && reIsUint.test(value))) &&
7942            (value > -1 && value % 1 == 0 && value < length);
7943    }
7944
7945    /**
7946     * Checks if the given arguments are from an iteratee call.
7947     *
7948     * @private
7949     * @param {*} value The potential iteratee value argument.
7950     * @param {*} index The potential iteratee index or key argument.
7951     * @param {*} object The potential iteratee object argument.
7952     * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
7953     *  else `false`.
7954     */
7955    function isIterateeCall(value, index, object) {
7956      if (!isObject(object)) {
7957        return false;
vendor: 14,387 bytes, lines 7958-8404
7958      }
7959      var type = typeof index;
7960      if (type == 'number'
7961            ? (isArrayLike(object) && isIndex(index, object.length))
7962            : (type == 'string' && index in object)
7963          ) {
7964        return eq(object[index], value);
7965      }
7966      return false;
7967    }
7968
7969    /**
7970     * Checks if `value` is a property name and not a property path.
7971     *
7972     * @private
7973     * @param {*} value The value to check.
7974     * @param {Object} [object] The object to query keys on.
7975     * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
7976     */
7977    function isKey(value, object) {
7978      if (isArray(value)) {
7979        return false;
7980      }
7981      var type = typeof value;
7982      if (type == 'number' || type == 'symbol' || type == 'boolean' ||
7983          value == null || isSymbol(value)) {
7984        return true;
7985      }
7986      return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
7987        (object != null && value in Object(object));
7988    }
7989
7990    /**
7991     * Checks if `value` is suitable for use as unique object key.
7992     *
7993     * @private
7994     * @param {*} value The value to check.
7995     * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
7996     */
7997    function isKeyable(value) {
7998      var type = typeof value;
7999      return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
8000        ? (value !== '__proto__')
8001        : (value === null);
8002    }
8003
8004    /**
8005     * Checks if `func` has a lazy counterpart.
8006     *
8007     * @private
8008     * @param {Function} func The function to check.
8009     * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
8010     *  else `false`.
8011     */
8012    function isLaziable(func) {
8013      var funcName = getFuncName(func),
8014          other = lodash[funcName];
8015
8016      if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
8017        return false;
8018      }
8019      if (func === other) {
8020        return true;
8021      }
8022      var data = getData(other);
8023      return !!data && func === data[0];
8024    }
8025
8026    /**
8027     * Checks if `func` has its source masked.
8028     *
8029     * @private
8030     * @param {Function} func The function to check.
8031     * @returns {boolean} Returns `true` if `func` is masked, else `false`.
8032     */
8033    function isMasked(func) {
8034      return !!maskSrcKey && (maskSrcKey in func);
8035    }
8036
8037    /**
8038     * Checks if `func` is capable of being masked.
8039     *
8040     * @private
8041     * @param {*} value The value to check.
8042     * @returns {boolean} Returns `true` if `func` is maskable, else `false`.
8043     */
8044    var isMaskable = coreJsData ? isFunction : stubFalse;
8045
8046    /**
8047     * Checks if `value` is likely a prototype object.
8048     *
8049     * @private
8050     * @param {*} value The value to check.
8051     * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
8052     */
8053    function isPrototype(value) {
8054      var Ctor = value && value.constructor,
8055          proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
8056
8057      return value === proto;
8058    }
8059
8060    /**
8061     * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
8062     *
8063     * @private
8064     * @param {*} value The value to check.
8065     * @returns {boolean} Returns `true` if `value` if suitable for strict
8066     *  equality comparisons, else `false`.
8067     */
8068    function isStrictComparable(value) {
8069      return value === value && !isObject(value);
8070    }
8071
8072    /**
8073     * A specialized version of `matchesProperty` for source values suitable
8074     * for strict equality comparisons, i.e. `===`.
8075     *
8076     * @private
8077     * @param {string} key The key of the property to get.
8078     * @param {*} srcValue The value to match.
8079     * @returns {Function} Returns the new spec function.
8080     */
8081    function matchesStrictComparable(key, srcValue) {
8082      return function(object) {
8083        if (object == null) {
8084          return false;
8085        }
8086        return object[key] === srcValue &&
8087          (srcValue !== undefined || (key in Object(object)));
8088      };
8089    }
8090
8091    /**
8092     * A specialized version of `_.memoize` which clears the memoized function's
8093     * cache when it exceeds `MAX_MEMOIZE_SIZE`.
8094     *
8095     * @private
8096     * @param {Function} func The function to have its output memoized.
8097     * @returns {Function} Returns the new memoized function.
8098     */
8099    function memoizeCapped(func) {
8100      var result = memoize(func, function(key) {
8101        if (cache.size === MAX_MEMOIZE_SIZE) {
8102          cache.clear();
8103        }
8104        return key;
8105      });
8106
8107      var cache = result.cache;
8108      return result;
8109    }
8110
8111    /**
8112     * Merges the function metadata of `source` into `data`.
8113     *
8114     * Merging metadata reduces the number of wrappers used to invoke a function.
8115     * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
8116     * may be applied regardless of execution order. Methods like `_.ary` and
8117     * `_.rearg` modify function arguments, making the order in which they are
8118     * executed important, preventing the merging of metadata. However, we make
8119     * an exception for a safe combined case where curried functions have `_.ary`
8120     * and or `_.rearg` applied.
8121     *
8122     * @private
8123     * @param {Array} data The destination metadata.
8124     * @param {Array} source The source metadata.
8125     * @returns {Array} Returns `data`.
8126     */
8127    function mergeData(data, source) {
8128      var bitmask = data[1],
8129          srcBitmask = source[1],
8130          newBitmask = bitmask | srcBitmask,
8131          isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG);
8132
8133      var isCombo =
8134        ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) ||
8135        ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) ||
8136        ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG));
8137
8138      // Exit early if metadata can't be merged.
8139      if (!(isCommon || isCombo)) {
8140        return data;
8141      }
8142      // Use source `thisArg` if available.
8143      if (srcBitmask & WRAP_BIND_FLAG) {
8144        data[2] = source[2];
8145        // Set when currying a bound function.
8146        newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG;
8147      }
8148      // Compose partial arguments.
8149      var value = source[3];
8150      if (value) {
8151        var partials = data[3];
8152        data[3] = partials ? composeArgs(partials, value, source[4]) : value;
8153        data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
8154      }
8155      // Compose partial right arguments.
8156      value = source[5];
8157      if (value) {
8158        partials = data[5];
8159        data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
8160        data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
8161      }
8162      // Use source `argPos` if available.
8163      value = source[7];
8164      if (value) {
8165        data[7] = value;
8166      }
8167      // Use source `ary` if it's smaller.
8168      if (srcBitmask & WRAP_ARY_FLAG) {
8169        data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
8170      }
8171      // Use source `arity` if one is not provided.
8172      if (data[9] == null) {
8173        data[9] = source[9];
8174      }
8175      // Use source `func` and merge bitmasks.
8176      data[0] = source[0];
8177      data[1] = newBitmask;
8178
8179      return data;
8180    }
8181
8182    /**
8183     * This function is like
8184     * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
8185     * except that it includes inherited enumerable properties.
8186     *
8187     * @private
8188     * @param {Object} object The object to query.
8189     * @returns {Array} Returns the array of property names.
8190     */
8191    function nativeKeysIn(object) {
8192      var result = [];
8193      if (object != null) {
8194        for (var key in Object(object)) {
8195          result.push(key);
8196        }
8197      }
8198      return result;
8199    }
8200
8201    /**
8202     * Converts `value` to a string using `Object.prototype.toString`.
8203     *
8204     * @private
8205     * @param {*} value The value to convert.
8206     * @returns {string} Returns the converted string.
8207     */
8208    function objectToString(value) {
8209      return nativeObjectToString.call(value);
8210    }
8211
8212    /**
8213     * A specialized version of `baseRest` which transforms the rest array.
8214     *
8215     * @private
8216     * @param {Function} func The function to apply a rest parameter to.
8217     * @param {number} [start=func.length-1] The start position of the rest parameter.
8218     * @param {Function} transform The rest array transform.
8219     * @returns {Function} Returns the new function.
8220     */
8221    function overRest(func, start, transform) {
8222      start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
8223      return function() {
8224        var args = arguments,
8225            index = -1,
8226            length = nativeMax(args.length - start, 0),
8227            array = Array(length);
8228
8229        while (++index < length) {
8230          array[index] = args[start + index];
8231        }
8232        index = -1;
8233        var otherArgs = Array(start + 1);
8234        while (++index < start) {
8235          otherArgs[index] = args[index];
8236        }
8237        otherArgs[start] = transform(array);
8238        return apply(func, this, otherArgs);
8239      };
8240    }
8241
8242    /**
8243     * Gets the parent value at `path` of `object`.
8244     *
8245     * @private
8246     * @param {Object} object The object to query.
8247     * @param {Array} path The path to get the parent value of.
8248     * @returns {*} Returns the parent value.
8249     */
8250    function parent(object, path) {
8251      return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
8252    }
8253
8254    /**
8255     * Reorder `array` according to the specified indexes where the element at
8256     * the first index is assigned as the first element, the element at
8257     * the second index is assigned as the second element, and so on.
8258     *
8259     * @private
8260     * @param {Array} array The array to reorder.
8261     * @param {Array} indexes The arranged array indexes.
8262     * @returns {Array} Returns `array`.
8263     */
8264    function reorder(array, indexes) {
8265      var arrLength = array.length,
8266          length = nativeMin(indexes.length, arrLength),
8267          oldArray = copyArray(array);
8268
8269      while (length--) {
8270        var index = indexes[length];
8271        array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
8272      }
8273      return array;
8274    }
8275
8276    /**
8277     * Gets the value at `key`, unless `key` is "__proto__" or "constructor".
8278     *
8279     * @private
8280     * @param {Object} object The object to query.
8281     * @param {string} key The key of the property to get.
8282     * @returns {*} Returns the property value.
8283     */
8284    function safeGet(object, key) {
8285      if (key === 'constructor' && typeof object[key] === 'function') {
8286        return;
8287      }
8288
8289      if (key == '__proto__') {
8290        return;
8291      }
8292
8293      return object[key];
8294    }
8295
8296    /**
8297     * Sets metadata for `func`.
8298     *
8299     * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
8300     * period of time, it will trip its breaker and transition to an identity
8301     * function to avoid garbage collection pauses in V8. See
8302     * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
8303     * for more details.
8304     *
8305     * @private
8306     * @param {Function} func The function to associate metadata with.
8307     * @param {*} data The metadata.
8308     * @returns {Function} Returns `func`.
8309     */
8310    var setData = shortOut(baseSetData);
8311
8312    /**
8313     * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout).
8314     *
8315     * @private
8316     * @param {Function} func The function to delay.
8317     * @param {number} wait The number of milliseconds to delay invocation.
8318     * @returns {number|Object} Returns the timer id or timeout object.
8319     */
8320    var setTimeout = ctxSetTimeout || function(func, wait) {
8321      return root.setTimeout(func, wait);
8322    };
8323
8324    /**
8325     * Sets the `toString` method of `func` to return `string`.
8326     *
8327     * @private
8328     * @param {Function} func The function to modify.
8329     * @param {Function} string The `toString` result.
8330     * @returns {Function} Returns `func`.
8331     */
8332    var setToString = shortOut(baseSetToString);
8333
8334    /**
8335     * Sets the `toString` method of `wrapper` to mimic the source of `reference`
8336     * with wrapper details in a comment at the top of the source body.
8337     *
8338     * @private
8339     * @param {Function} wrapper The function to modify.
8340     * @param {Function} reference The reference function.
8341     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
8342     * @returns {Function} Returns `wrapper`.
8343     */
8344    function setWrapToString(wrapper, reference, bitmask) {
8345      var source = (reference + '');
8346      return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask)));
8347    }
8348
8349    /**
8350     * Creates a function that'll short out and invoke `identity` instead
8351     * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
8352     * milliseconds.
8353     *
8354     * @private
8355     * @param {Function} func The function to restrict.
8356     * @returns {Function} Returns the new shortable function.
8357     */
8358    function shortOut(func) {
8359      var count = 0,
8360          lastCalled = 0;
8361
8362      return function() {
8363        var stamp = nativeNow(),
8364            remaining = HOT_SPAN - (stamp - lastCalled);
8365
8366        lastCalled = stamp;
8367        if (remaining > 0) {
8368          if (++count >= HOT_COUNT) {
8369            return arguments[0];
8370          }
8371        } else {
8372          count = 0;
8373        }
8374        return func.apply(undefined, arguments);
8375      };
8376    }
8377
8378    /**
8379     * A specialized version of `_.shuffle` which mutates and sets the size of `array`.
8380     *
8381     * @private
8382     * @param {Array} array The array to shuffle.
8383     * @param {number} [size=array.length] The size of `array`.
8384     * @returns {Array} Returns `array`.
8385     */
8386    function shuffleSelf(array, size) {
8387      var index = -1,
8388          length = array.length,
8389          lastIndex = length - 1;
8390
8391      size = size === undefined ? length : size;
8392      while (++index < size) {
8393        var rand = baseRandom(index, lastIndex),
8394            value = array[rand];
8395
8396        array[rand] = array[index];
8397        array[index] = value;
8398      }
8399      array.length = size;
8400      return array;
8401    }
8402
8403    /**
8404     * Converts `string` to a property path array.
vendor: 1,775 bytes, lines 8405-8465
8405     *
8406     * @private
8407     * @param {string} string The string to convert.
8408     * @returns {Array} Returns the property path array.
8409     */
8410    var stringToPath = memoizeCapped(function(string) {
8411      var result = [];
8412      if (string.charCodeAt(0) === 46 /* . */) {
8413        result.push('');
8414      }
8415      string.replace(rePropName, function(match, number, quote, subString) {
8416        result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match));
8417      });
8418      return result;
8419    });
8420
8421    /**
8422     * Converts `value` to a string key if it's not a string or symbol.
8423     *
8424     * @private
8425     * @param {*} value The value to inspect.
8426     * @returns {string|symbol} Returns the key.
8427     */
8428    function toKey(value) {
8429      if (typeof value == 'string' || isSymbol(value)) {
8430        return value;
8431      }
8432      var result = (value + '');
8433      return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
8434    }
8435
8436    /**
8437     * Converts `func` to its source code.
8438     *
8439     * @private
8440     * @param {Function} func The function to convert.
8441     * @returns {string} Returns the source code.
8442     */
8443    function toSource(func) {
8444      if (func != null) {
8445        try {
8446          return funcToString.call(func);
8447        } catch (e) {}
8448        try {
8449          return (func + '');
8450        } catch (e) {}
8451      }
8452      return '';
8453    }
8454
8455    /**
8456     * Updates wrapper `details` based on `bitmask` flags.
8457     *
8458     * @private
8459     * @returns {Array} details The details to modify.
8460     * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
8461     * @returns {Array} Returns `details`.
8462     */
8463    function updateWrapDetails(details, bitmask) {
8464      arrayEach(wrapFlags, function(pair) {
8465        var value = '_.' + pair[0];
vendor: 80,381 bytes, lines 8466-11049
8466        if ((bitmask & pair[1]) && !arrayIncludes(details, value)) {
8467          details.push(value);
8468        }
8469      });
8470      return details.sort();
8471    }
8472
8473    /**
8474     * Creates a clone of `wrapper`.
8475     *
8476     * @private
8477     * @param {Object} wrapper The wrapper to clone.
8478     * @returns {Object} Returns the cloned wrapper.
8479     */
8480    function wrapperClone(wrapper) {
8481      if (wrapper instanceof LazyWrapper) {
8482        return wrapper.clone();
8483      }
8484      var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
8485      result.__actions__ = copyArray(wrapper.__actions__);
8486      result.__index__  = wrapper.__index__;
8487      result.__values__ = wrapper.__values__;
8488      return result;
8489    }
8490
8491    /*------------------------------------------------------------------------*/
8492
8493    /**
8494     * Creates an array of elements split into groups the length of `size`.
8495     * If `array` can't be split evenly, the final chunk will be the remaining
8496     * elements.
8497     *
8498     * @static
8499     * @memberOf _
8500     * @since 3.0.0
8501     * @category Array
8502     * @param {Array} array The array to process.
8503     * @param {number} [size=1] The length of each chunk
8504     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
8505     * @returns {Array} Returns the new array of chunks.
8506     * @example
8507     *
8508     * _.chunk(['a', 'b', 'c', 'd'], 2);
8509     * // => [['a', 'b'], ['c', 'd']]
8510     *
8511     * _.chunk(['a', 'b', 'c', 'd'], 3);
8512     * // => [['a', 'b', 'c'], ['d']]
8513     */
8514    function chunk(array, size, guard) {
8515      if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
8516        size = 1;
8517      } else {
8518        size = nativeMax(toInteger(size), 0);
8519      }
8520      var length = array == null ? 0 : array.length;
8521      if (!length || size < 1) {
8522        return [];
8523      }
8524      var index = 0,
8525          resIndex = 0,
8526          result = Array(nativeCeil(length / size));
8527
8528      while (index < length) {
8529        result[resIndex++] = baseSlice(array, index, (index += size));
8530      }
8531      return result;
8532    }
8533
8534    /**
8535     * Creates an array with all falsey values removed. The values `false`, `null`,
8536     * `0`, `""`, `undefined`, and `NaN` are falsey.
8537     *
8538     * @static
8539     * @memberOf _
8540     * @since 0.1.0
8541     * @category Array
8542     * @param {Array} array The array to compact.
8543     * @returns {Array} Returns the new array of filtered values.
8544     * @example
8545     *
8546     * _.compact([0, 1, false, 2, '', 3]);
8547     * // => [1, 2, 3]
8548     */
8549    function compact(array) {
8550      var index = -1,
8551          length = array == null ? 0 : array.length,
8552          resIndex = 0,
8553          result = [];
8554
8555      while (++index < length) {
8556        var value = array[index];
8557        if (value) {
8558          result[resIndex++] = value;
8559        }
8560      }
8561      return result;
8562    }
8563
8564    /**
8565     * Creates a new array concatenating `array` with any additional arrays
8566     * and/or values.
8567     *
8568     * @static
8569     * @memberOf _
8570     * @since 4.0.0
8571     * @category Array
8572     * @param {Array} array The array to concatenate.
8573     * @param {...*} [values] The values to concatenate.
8574     * @returns {Array} Returns the new concatenated array.
8575     * @example
8576     *
8577     * var array = [1];
8578     * var other = _.concat(array, 2, [3], [[4]]);
8579     *
8580     * console.log(other);
8581     * // => [1, 2, 3, [4]]
8582     *
8583     * console.log(array);
8584     * // => [1]
8585     */
8586    function concat() {
8587      var length = arguments.length;
8588      if (!length) {
8589        return [];
8590      }
8591      var args = Array(length - 1),
8592          array = arguments[0],
8593          index = length;
8594
8595      while (index--) {
8596        args[index - 1] = arguments[index];
8597      }
8598      return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
8599    }
8600
8601    /**
8602     * Creates an array of `array` values not included in the other given arrays
8603     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8604     * for equality comparisons. The order and references of result values are
8605     * determined by the first array.
8606     *
8607     * **Note:** Unlike `_.pullAll`, this method returns a new array.
8608     *
8609     * @static
8610     * @memberOf _
8611     * @since 0.1.0
8612     * @category Array
8613     * @param {Array} array The array to inspect.
8614     * @param {...Array} [values] The values to exclude.
8615     * @returns {Array} Returns the new array of filtered values.
8616     * @see _.without, _.xor
8617     * @example
8618     *
8619     * _.difference([2, 1], [2, 3]);
8620     * // => [1]
8621     */
8622    var difference = baseRest(function(array, values) {
8623      return isArrayLikeObject(array)
8624        ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
8625        : [];
8626    });
8627
8628    /**
8629     * This method is like `_.difference` except that it accepts `iteratee` which
8630     * is invoked for each element of `array` and `values` to generate the criterion
8631     * by which they're compared. The order and references of result values are
8632     * determined by the first array. The iteratee is invoked with one argument:
8633     * (value).
8634     *
8635     * **Note:** Unlike `_.pullAllBy`, this method returns a new array.
8636     *
8637     * @static
8638     * @memberOf _
8639     * @since 4.0.0
8640     * @category Array
8641     * @param {Array} array The array to inspect.
8642     * @param {...Array} [values] The values to exclude.
8643     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8644     * @returns {Array} Returns the new array of filtered values.
8645     * @example
8646     *
8647     * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
8648     * // => [1.2]
8649     *
8650     * // The `_.property` iteratee shorthand.
8651     * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
8652     * // => [{ 'x': 2 }]
8653     */
8654    var differenceBy = baseRest(function(array, values) {
8655      var iteratee = last(values);
8656      if (isArrayLikeObject(iteratee)) {
8657        iteratee = undefined;
8658      }
8659      return isArrayLikeObject(array)
8660        ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2))
8661        : [];
8662    });
8663
8664    /**
8665     * This method is like `_.difference` except that it accepts `comparator`
8666     * which is invoked to compare elements of `array` to `values`. The order and
8667     * references of result values are determined by the first array. The comparator
8668     * is invoked with two arguments: (arrVal, othVal).
8669     *
8670     * **Note:** Unlike `_.pullAllWith`, this method returns a new array.
8671     *
8672     * @static
8673     * @memberOf _
8674     * @since 4.0.0
8675     * @category Array
8676     * @param {Array} array The array to inspect.
8677     * @param {...Array} [values] The values to exclude.
8678     * @param {Function} [comparator] The comparator invoked per element.
8679     * @returns {Array} Returns the new array of filtered values.
8680     * @example
8681     *
8682     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
8683     *
8684     * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
8685     * // => [{ 'x': 2, 'y': 1 }]
8686     */
8687    var differenceWith = baseRest(function(array, values) {
8688      var comparator = last(values);
8689      if (isArrayLikeObject(comparator)) {
8690        comparator = undefined;
8691      }
8692      return isArrayLikeObject(array)
8693        ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
8694        : [];
8695    });
8696
8697    /**
8698     * Creates a slice of `array` with `n` elements dropped from the beginning.
8699     *
8700     * @static
8701     * @memberOf _
8702     * @since 0.5.0
8703     * @category Array
8704     * @param {Array} array The array to query.
8705     * @param {number} [n=1] The number of elements to drop.
8706     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
8707     * @returns {Array} Returns the slice of `array`.
8708     * @example
8709     *
8710     * _.drop([1, 2, 3]);
8711     * // => [2, 3]
8712     *
8713     * _.drop([1, 2, 3], 2);
8714     * // => [3]
8715     *
8716     * _.drop([1, 2, 3], 5);
8717     * // => []
8718     *
8719     * _.drop([1, 2, 3], 0);
8720     * // => [1, 2, 3]
8721     */
8722    function drop(array, n, guard) {
8723      var length = array == null ? 0 : array.length;
8724      if (!length) {
8725        return [];
8726      }
8727      n = (guard || n === undefined) ? 1 : toInteger(n);
8728      return baseSlice(array, n < 0 ? 0 : n, length);
8729    }
8730
8731    /**
8732     * Creates a slice of `array` with `n` elements dropped from the end.
8733     *
8734     * @static
8735     * @memberOf _
8736     * @since 3.0.0
8737     * @category Array
8738     * @param {Array} array The array to query.
8739     * @param {number} [n=1] The number of elements to drop.
8740     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
8741     * @returns {Array} Returns the slice of `array`.
8742     * @example
8743     *
8744     * _.dropRight([1, 2, 3]);
8745     * // => [1, 2]
8746     *
8747     * _.dropRight([1, 2, 3], 2);
8748     * // => [1]
8749     *
8750     * _.dropRight([1, 2, 3], 5);
8751     * // => []
8752     *
8753     * _.dropRight([1, 2, 3], 0);
8754     * // => [1, 2, 3]
8755     */
8756    function dropRight(array, n, guard) {
8757      var length = array == null ? 0 : array.length;
8758      if (!length) {
8759        return [];
8760      }
8761      n = (guard || n === undefined) ? 1 : toInteger(n);
8762      n = length - n;
8763      return baseSlice(array, 0, n < 0 ? 0 : n);
8764    }
8765
8766    /**
8767     * Creates a slice of `array` excluding elements dropped from the end.
8768     * Elements are dropped until `predicate` returns falsey. The predicate is
8769     * invoked with three arguments: (value, index, array).
8770     *
8771     * @static
8772     * @memberOf _
8773     * @since 3.0.0
8774     * @category Array
8775     * @param {Array} array The array to query.
8776     * @param {Function} [predicate=_.identity] The function invoked per iteration.
8777     * @returns {Array} Returns the slice of `array`.
8778     * @example
8779     *
8780     * var users = [
8781     *   { 'user': 'barney',  'active': true },
8782     *   { 'user': 'fred',    'active': false },
8783     *   { 'user': 'pebbles', 'active': false }
8784     * ];
8785     *
8786     * _.dropRightWhile(users, function(o) { return !o.active; });
8787     * // => objects for ['barney']
8788     *
8789     * // The `_.matches` iteratee shorthand.
8790     * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
8791     * // => objects for ['barney', 'fred']
8792     *
8793     * // The `_.matchesProperty` iteratee shorthand.
8794     * _.dropRightWhile(users, ['active', false]);
8795     * // => objects for ['barney']
8796     *
8797     * // The `_.property` iteratee shorthand.
8798     * _.dropRightWhile(users, 'active');
8799     * // => objects for ['barney', 'fred', 'pebbles']
8800     */
8801    function dropRightWhile(array, predicate) {
8802      return (array && array.length)
8803        ? baseWhile(array, getIteratee(predicate, 3), true, true)
8804        : [];
8805    }
8806
8807    /**
8808     * Creates a slice of `array` excluding elements dropped from the beginning.
8809     * Elements are dropped until `predicate` returns falsey. The predicate is
8810     * invoked with three arguments: (value, index, array).
8811     *
8812     * @static
8813     * @memberOf _
8814     * @since 3.0.0
8815     * @category Array
8816     * @param {Array} array The array to query.
8817     * @param {Function} [predicate=_.identity] The function invoked per iteration.
8818     * @returns {Array} Returns the slice of `array`.
8819     * @example
8820     *
8821     * var users = [
8822     *   { 'user': 'barney',  'active': false },
8823     *   { 'user': 'fred',    'active': false },
8824     *   { 'user': 'pebbles', 'active': true }
8825     * ];
8826     *
8827     * _.dropWhile(users, function(o) { return !o.active; });
8828     * // => objects for ['pebbles']
8829     *
8830     * // The `_.matches` iteratee shorthand.
8831     * _.dropWhile(users, { 'user': 'barney', 'active': false });
8832     * // => objects for ['fred', 'pebbles']
8833     *
8834     * // The `_.matchesProperty` iteratee shorthand.
8835     * _.dropWhile(users, ['active', false]);
8836     * // => objects for ['pebbles']
8837     *
8838     * // The `_.property` iteratee shorthand.
8839     * _.dropWhile(users, 'active');
8840     * // => objects for ['barney', 'fred', 'pebbles']
8841     */
8842    function dropWhile(array, predicate) {
8843      return (array && array.length)
8844        ? baseWhile(array, getIteratee(predicate, 3), true)
8845        : [];
8846    }
8847
8848    /**
8849     * Fills elements of `array` with `value` from `start` up to, but not
8850     * including, `end`.
8851     *
8852     * **Note:** This method mutates `array`.
8853     *
8854     * @static
8855     * @memberOf _
8856     * @since 3.2.0
8857     * @category Array
8858     * @param {Array} array The array to fill.
8859     * @param {*} value The value to fill `array` with.
8860     * @param {number} [start=0] The start position.
8861     * @param {number} [end=array.length] The end position.
8862     * @returns {Array} Returns `array`.
8863     * @example
8864     *
8865     * var array = [1, 2, 3];
8866     *
8867     * _.fill(array, 'a');
8868     * console.log(array);
8869     * // => ['a', 'a', 'a']
8870     *
8871     * _.fill(Array(3), 2);
8872     * // => [2, 2, 2]
8873     *
8874     * _.fill([4, 6, 8, 10], '*', 1, 3);
8875     * // => [4, '*', '*', 10]
8876     */
8877    function fill(array, value, start, end) {
8878      var length = array == null ? 0 : array.length;
8879      if (!length) {
8880        return [];
8881      }
8882      if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
8883        start = 0;
8884        end = length;
8885      }
8886      return baseFill(array, value, start, end);
8887    }
8888
8889    /**
8890     * This method is like `_.find` except that it returns the index of the first
8891     * element `predicate` returns truthy for instead of the element itself.
8892     *
8893     * @static
8894     * @memberOf _
8895     * @since 1.1.0
8896     * @category Array
8897     * @param {Array} array The array to inspect.
8898     * @param {Function} [predicate=_.identity] The function invoked per iteration.
8899     * @param {number} [fromIndex=0] The index to search from.
8900     * @returns {number} Returns the index of the found element, else `-1`.
8901     * @example
8902     *
8903     * var users = [
8904     *   { 'user': 'barney',  'active': false },
8905     *   { 'user': 'fred',    'active': false },
8906     *   { 'user': 'pebbles', 'active': true }
8907     * ];
8908     *
8909     * _.findIndex(users, function(o) { return o.user == 'barney'; });
8910     * // => 0
8911     *
8912     * // The `_.matches` iteratee shorthand.
8913     * _.findIndex(users, { 'user': 'fred', 'active': false });
8914     * // => 1
8915     *
8916     * // The `_.matchesProperty` iteratee shorthand.
8917     * _.findIndex(users, ['active', false]);
8918     * // => 0
8919     *
8920     * // The `_.property` iteratee shorthand.
8921     * _.findIndex(users, 'active');
8922     * // => 2
8923     */
8924    function findIndex(array, predicate, fromIndex) {
8925      var length = array == null ? 0 : array.length;
8926      if (!length) {
8927        return -1;
8928      }
8929      var index = fromIndex == null ? 0 : toInteger(fromIndex);
8930      if (index < 0) {
8931        index = nativeMax(length + index, 0);
8932      }
8933      return baseFindIndex(array, getIteratee(predicate, 3), index);
8934    }
8935
8936    /**
8937     * This method is like `_.findIndex` except that it iterates over elements
8938     * of `collection` from right to left.
8939     *
8940     * @static
8941     * @memberOf _
8942     * @since 2.0.0
8943     * @category Array
8944     * @param {Array} array The array to inspect.
8945     * @param {Function} [predicate=_.identity] The function invoked per iteration.
8946     * @param {number} [fromIndex=array.length-1] The index to search from.
8947     * @returns {number} Returns the index of the found element, else `-1`.
8948     * @example
8949     *
8950     * var users = [
8951     *   { 'user': 'barney',  'active': true },
8952     *   { 'user': 'fred',    'active': false },
8953     *   { 'user': 'pebbles', 'active': false }
8954     * ];
8955     *
8956     * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
8957     * // => 2
8958     *
8959     * // The `_.matches` iteratee shorthand.
8960     * _.findLastIndex(users, { 'user': 'barney', 'active': true });
8961     * // => 0
8962     *
8963     * // The `_.matchesProperty` iteratee shorthand.
8964     * _.findLastIndex(users, ['active', false]);
8965     * // => 2
8966     *
8967     * // The `_.property` iteratee shorthand.
8968     * _.findLastIndex(users, 'active');
8969     * // => 0
8970     */
8971    function findLastIndex(array, predicate, fromIndex) {
8972      var length = array == null ? 0 : array.length;
8973      if (!length) {
8974        return -1;
8975      }
8976      var index = length - 1;
8977      if (fromIndex !== undefined) {
8978        index = toInteger(fromIndex);
8979        index = fromIndex < 0
8980          ? nativeMax(length + index, 0)
8981          : nativeMin(index, length - 1);
8982      }
8983      return baseFindIndex(array, getIteratee(predicate, 3), index, true);
8984    }
8985
8986    /**
8987     * Flattens `array` a single level deep.
8988     *
8989     * @static
8990     * @memberOf _
8991     * @since 0.1.0
8992     * @category Array
8993     * @param {Array} array The array to flatten.
8994     * @returns {Array} Returns the new flattened array.
8995     * @example
8996     *
8997     * _.flatten([1, [2, [3, [4]], 5]]);
8998     * // => [1, 2, [3, [4]], 5]
8999     */
9000    function flatten(array) {
9001      var length = array == null ? 0 : array.length;
9002      return length ? baseFlatten(array, 1) : [];
9003    }
9004
9005    /**
9006     * Recursively flattens `array`.
9007     *
9008     * @static
9009     * @memberOf _
9010     * @since 3.0.0
9011     * @category Array
9012     * @param {Array} array The array to flatten.
9013     * @returns {Array} Returns the new flattened array.
9014     * @example
9015     *
9016     * _.flattenDeep([1, [2, [3, [4]], 5]]);
9017     * // => [1, 2, 3, 4, 5]
9018     */
9019    function flattenDeep(array) {
9020      var length = array == null ? 0 : array.length;
9021      return length ? baseFlatten(array, INFINITY) : [];
9022    }
9023
9024    /**
9025     * Recursively flatten `array` up to `depth` times.
9026     *
9027     * @static
9028     * @memberOf _
9029     * @since 4.4.0
9030     * @category Array
9031     * @param {Array} array The array to flatten.
9032     * @param {number} [depth=1] The maximum recursion depth.
9033     * @returns {Array} Returns the new flattened array.
9034     * @example
9035     *
9036     * var array = [1, [2, [3, [4]], 5]];
9037     *
9038     * _.flattenDepth(array, 1);
9039     * // => [1, 2, [3, [4]], 5]
9040     *
9041     * _.flattenDepth(array, 2);
9042     * // => [1, 2, 3, [4], 5]
9043     */
9044    function flattenDepth(array, depth) {
9045      var length = array == null ? 0 : array.length;
9046      if (!length) {
9047        return [];
9048      }
9049      depth = depth === undefined ? 1 : toInteger(depth);
9050      return baseFlatten(array, depth);
9051    }
9052
9053    /**
9054     * The inverse of `_.toPairs`; this method returns an object composed
9055     * from key-value `pairs`.
9056     *
9057     * @static
9058     * @memberOf _
9059     * @since 4.0.0
9060     * @category Array
9061     * @param {Array} pairs The key-value pairs.
9062     * @returns {Object} Returns the new object.
9063     * @example
9064     *
9065     * _.fromPairs([['a', 1], ['b', 2]]);
9066     * // => { 'a': 1, 'b': 2 }
9067     */
9068    function fromPairs(pairs) {
9069      var index = -1,
9070          length = pairs == null ? 0 : pairs.length,
9071          result = {};
9072
9073      while (++index < length) {
9074        var pair = pairs[index];
9075        result[pair[0]] = pair[1];
9076      }
9077      return result;
9078    }
9079
9080    /**
9081     * Gets the first element of `array`.
9082     *
9083     * @static
9084     * @memberOf _
9085     * @since 0.1.0
9086     * @alias first
9087     * @category Array
9088     * @param {Array} array The array to query.
9089     * @returns {*} Returns the first element of `array`.
9090     * @example
9091     *
9092     * _.head([1, 2, 3]);
9093     * // => 1
9094     *
9095     * _.head([]);
9096     * // => undefined
9097     */
9098    function head(array) {
9099      return (array && array.length) ? array[0] : undefined;
9100    }
9101
9102    /**
9103     * Gets the index at which the first occurrence of `value` is found in `array`
9104     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
9105     * for equality comparisons. If `fromIndex` is negative, it's used as the
9106     * offset from the end of `array`.
9107     *
9108     * @static
9109     * @memberOf _
9110     * @since 0.1.0
9111     * @category Array
9112     * @param {Array} array The array to inspect.
9113     * @param {*} value The value to search for.
9114     * @param {number} [fromIndex=0] The index to search from.
9115     * @returns {number} Returns the index of the matched value, else `-1`.
9116     * @example
9117     *
9118     * _.indexOf([1, 2, 1, 2], 2);
9119     * // => 1
9120     *
9121     * // Search from the `fromIndex`.
9122     * _.indexOf([1, 2, 1, 2], 2, 2);
9123     * // => 3
9124     */
9125    function indexOf(array, value, fromIndex) {
9126      var length = array == null ? 0 : array.length;
9127      if (!length) {
9128        return -1;
9129      }
9130      var index = fromIndex == null ? 0 : toInteger(fromIndex);
9131      if (index < 0) {
9132        index = nativeMax(length + index, 0);
9133      }
9134      return baseIndexOf(array, value, index);
9135    }
9136
9137    /**
9138     * Gets all but the last element of `array`.
9139     *
9140     * @static
9141     * @memberOf _
9142     * @since 0.1.0
9143     * @category Array
9144     * @param {Array} array The array to query.
9145     * @returns {Array} Returns the slice of `array`.
9146     * @example
9147     *
9148     * _.initial([1, 2, 3]);
9149     * // => [1, 2]
9150     */
9151    function initial(array) {
9152      var length = array == null ? 0 : array.length;
9153      return length ? baseSlice(array, 0, -1) : [];
9154    }
9155
9156    /**
9157     * Creates an array of unique values that are included in all given arrays
9158     * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
9159     * for equality comparisons. The order and references of result values are
9160     * determined by the first array.
9161     *
9162     * @static
9163     * @memberOf _
9164     * @since 0.1.0
9165     * @category Array
9166     * @param {...Array} [arrays] The arrays to inspect.
9167     * @returns {Array} Returns the new array of intersecting values.
9168     * @example
9169     *
9170     * _.intersection([2, 1], [2, 3]);
9171     * // => [2]
9172     */
9173    var intersection = baseRest(function(arrays) {
9174      var mapped = arrayMap(arrays, castArrayLikeObject);
9175      return (mapped.length && mapped[0] === arrays[0])
9176        ? baseIntersection(mapped)
9177        : [];
9178    });
9179
9180    /**
9181     * This method is like `_.intersection` except that it accepts `iteratee`
9182     * which is invoked for each element of each `arrays` to generate the criterion
9183     * by which they're compared. The order and references of result values are
9184     * determined by the first array. The iteratee is invoked with one argument:
9185     * (value).
9186     *
9187     * @static
9188     * @memberOf _
9189     * @since 4.0.0
9190     * @category Array
9191     * @param {...Array} [arrays] The arrays to inspect.
9192     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
9193     * @returns {Array} Returns the new array of intersecting values.
9194     * @example
9195     *
9196     * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
9197     * // => [2.1]
9198     *
9199     * // The `_.property` iteratee shorthand.
9200     * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
9201     * // => [{ 'x': 1 }]
9202     */
9203    var intersectionBy = baseRest(function(arrays) {
9204      var iteratee = last(arrays),
9205          mapped = arrayMap(arrays, castArrayLikeObject);
9206
9207      if (iteratee === last(mapped)) {
9208        iteratee = undefined;
9209      } else {
9210        mapped.pop();
9211      }
9212      return (mapped.length && mapped[0] === arrays[0])
9213        ? baseIntersection(mapped, getIteratee(iteratee, 2))
9214        : [];
9215    });
9216
9217    /**
9218     * This method is like `_.intersection` except that it accepts `comparator`
9219     * which is invoked to compare elements of `arrays`. The order and references
9220     * of result values are determined by the first array. The comparator is
9221     * invoked with two arguments: (arrVal, othVal).
9222     *
9223     * @static
9224     * @memberOf _
9225     * @since 4.0.0
9226     * @category Array
9227     * @param {...Array} [arrays] The arrays to inspect.
9228     * @param {Function} [comparator] The comparator invoked per element.
9229     * @returns {Array} Returns the new array of intersecting values.
9230     * @example
9231     *
9232     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
9233     * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
9234     *
9235     * _.intersectionWith(objects, others, _.isEqual);
9236     * // => [{ 'x': 1, 'y': 2 }]
9237     */
9238    var intersectionWith = baseRest(function(arrays) {
9239      var comparator = last(arrays),
9240          mapped = arrayMap(arrays, castArrayLikeObject);
9241
9242      comparator = typeof comparator == 'function' ? comparator : undefined;
9243      if (comparator) {
9244        mapped.pop();
9245      }
9246      return (mapped.length && mapped[0] === arrays[0])
9247        ? baseIntersection(mapped, undefined, comparator)
9248        : [];
9249    });
9250
9251    /**
9252     * Converts all elements in `array` into a string separated by `separator`.
9253     *
9254     * @static
9255     * @memberOf _
9256     * @since 4.0.0
9257     * @category Array
9258     * @param {Array} array The array to convert.
9259     * @param {string} [separator=','] The element separator.
9260     * @returns {string} Returns the joined string.
9261     * @example
9262     *
9263     * _.join(['a', 'b', 'c'], '~');
9264     * // => 'a~b~c'
9265     */
9266    function join(array, separator) {
9267      return array == null ? '' : nativeJoin.call(array, separator);
9268    }
9269
9270    /**
9271     * Gets the last element of `array`.
9272     *
9273     * @static
9274     * @memberOf _
9275     * @since 0.1.0
9276     * @category Array
9277     * @param {Array} array The array to query.
9278     * @returns {*} Returns the last element of `array`.
9279     * @example
9280     *
9281     * _.last([1, 2, 3]);
9282     * // => 3
9283     */
9284    function last(array) {
9285      var length = array == null ? 0 : array.length;
9286      return length ? array[length - 1] : undefined;
9287    }
9288
9289    /**
9290     * This method is like `_.indexOf` except that it iterates over elements of
9291     * `array` from right to left.
9292     *
9293     * @static
9294     * @memberOf _
9295     * @since 0.1.0
9296     * @category Array
9297     * @param {Array} array The array to inspect.
9298     * @param {*} value The value to search for.
9299     * @param {number} [fromIndex=array.length-1] The index to search from.
9300     * @returns {number} Returns the index of the matched value, else `-1`.
9301     * @example
9302     *
9303     * _.lastIndexOf([1, 2, 1, 2], 2);
9304     * // => 3
9305     *
9306     * // Search from the `fromIndex`.
9307     * _.lastIndexOf([1, 2, 1, 2], 2, 2);
9308     * // => 1
9309     */
9310    function lastIndexOf(array, value, fromIndex) {
9311      var length = array == null ? 0 : array.length;
9312      if (!length) {
9313        return -1;
9314      }
9315      var index = length;
9316      if (fromIndex !== undefined) {
9317        index = toInteger(fromIndex);
9318        index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
9319      }
9320      return value === value
9321        ? strictLastIndexOf(array, value, index)
9322        : baseFindIndex(array, baseIsNaN, index, true);
9323    }
9324
9325    /**
9326     * Gets the element at index `n` of `array`. If `n` is negative, the nth
9327     * element from the end is returned.
9328     *
9329     * @static
9330     * @memberOf _
9331     * @since 4.11.0
9332     * @category Array
9333     * @param {Array} array The array to query.
9334     * @param {number} [n=0] The index of the element to return.
9335     * @returns {*} Returns the nth element of `array`.
9336     * @example
9337     *
9338     * var array = ['a', 'b', 'c', 'd'];
9339     *
9340     * _.nth(array, 1);
9341     * // => 'b'
9342     *
9343     * _.nth(array, -2);
9344     * // => 'c';
9345     */
9346    function nth(array, n) {
9347      return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;
9348    }
9349
9350    /**
9351     * Removes all given values from `array` using
9352     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
9353     * for equality comparisons.
9354     *
9355     * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
9356     * to remove elements from an array by predicate.
9357     *
9358     * @static
9359     * @memberOf _
9360     * @since 2.0.0
9361     * @category Array
9362     * @param {Array} array The array to modify.
9363     * @param {...*} [values] The values to remove.
9364     * @returns {Array} Returns `array`.
9365     * @example
9366     *
9367     * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
9368     *
9369     * _.pull(array, 'a', 'c');
9370     * console.log(array);
9371     * // => ['b', 'b']
9372     */
9373    var pull = baseRest(pullAll);
9374
9375    /**
9376     * This method is like `_.pull` except that it accepts an array of values to remove.
9377     *
9378     * **Note:** Unlike `_.difference`, this method mutates `array`.
9379     *
9380     * @static
9381     * @memberOf _
9382     * @since 4.0.0
9383     * @category Array
9384     * @param {Array} array The array to modify.
9385     * @param {Array} values The values to remove.
9386     * @returns {Array} Returns `array`.
9387     * @example
9388     *
9389     * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
9390     *
9391     * _.pullAll(array, ['a', 'c']);
9392     * console.log(array);
9393     * // => ['b', 'b']
9394     */
9395    function pullAll(array, values) {
9396      return (array && array.length && values && values.length)
9397        ? basePullAll(array, values)
9398        : array;
9399    }
9400
9401    /**
9402     * This method is like `_.pullAll` except that it accepts `iteratee` which is
9403     * invoked for each element of `array` and `values` to generate the criterion
9404     * by which they're compared. The iteratee is invoked with one argument: (value).
9405     *
9406     * **Note:** Unlike `_.differenceBy`, this method mutates `array`.
9407     *
9408     * @static
9409     * @memberOf _
9410     * @since 4.0.0
9411     * @category Array
9412     * @param {Array} array The array to modify.
9413     * @param {Array} values The values to remove.
9414     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
9415     * @returns {Array} Returns `array`.
9416     * @example
9417     *
9418     * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
9419     *
9420     * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
9421     * console.log(array);
9422     * // => [{ 'x': 2 }]
9423     */
9424    function pullAllBy(array, values, iteratee) {
9425      return (array && array.length && values && values.length)
9426        ? basePullAll(array, values, getIteratee(iteratee, 2))
9427        : array;
9428    }
9429
9430    /**
9431     * This method is like `_.pullAll` except that it accepts `comparator` which
9432     * is invoked to compare elements of `array` to `values`. The comparator is
9433     * invoked with two arguments: (arrVal, othVal).
9434     *
9435     * **Note:** Unlike `_.differenceWith`, this method mutates `array`.
9436     *
9437     * @static
9438     * @memberOf _
9439     * @since 4.6.0
9440     * @category Array
9441     * @param {Array} array The array to modify.
9442     * @param {Array} values The values to remove.
9443     * @param {Function} [comparator] The comparator invoked per element.
9444     * @returns {Array} Returns `array`.
9445     * @example
9446     *
9447     * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
9448     *
9449     * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
9450     * console.log(array);
9451     * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
9452     */
9453    function pullAllWith(array, values, comparator) {
9454      return (array && array.length && values && values.length)
9455        ? basePullAll(array, values, undefined, comparator)
9456        : array;
9457    }
9458
9459    /**
9460     * Removes elements from `array` corresponding to `indexes` and returns an
9461     * array of removed elements.
9462     *
9463     * **Note:** Unlike `_.at`, this method mutates `array`.
9464     *
9465     * @static
9466     * @memberOf _
9467     * @since 3.0.0
9468     * @category Array
9469     * @param {Array} array The array to modify.
9470     * @param {...(number|number[])} [indexes] The indexes of elements to remove.
9471     * @returns {Array} Returns the new array of removed elements.
9472     * @example
9473     *
9474     * var array = ['a', 'b', 'c', 'd'];
9475     * var pulled = _.pullAt(array, [1, 3]);
9476     *
9477     * console.log(array);
9478     * // => ['a', 'c']
9479     *
9480     * console.log(pulled);
9481     * // => ['b', 'd']
9482     */
9483    var pullAt = flatRest(function(array, indexes) {
9484      var length = array == null ? 0 : array.length,
9485          result = baseAt(array, indexes);
9486
9487      basePullAt(array, arrayMap(indexes, function(index) {
9488        return isIndex(index, length) ? +index : index;
9489      }).sort(compareAscending));
9490
9491      return result;
9492    });
9493
9494    /**
9495     * Removes all elements from `array` that `predicate` returns truthy for
9496     * and returns an array of the removed elements. The predicate is invoked
9497     * with three arguments: (value, index, array).
9498     *
9499     * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
9500     * to pull elements from an array by value.
9501     *
9502     * @static
9503     * @memberOf _
9504     * @since 2.0.0
9505     * @category Array
9506     * @param {Array} array The array to modify.
9507     * @param {Function} [predicate=_.identity] The function invoked per iteration.
9508     * @returns {Array} Returns the new array of removed elements.
9509     * @example
9510     *
9511     * var array = [1, 2, 3, 4];
9512     * var evens = _.remove(array, function(n) {
9513     *   return n % 2 == 0;
9514     * });
9515     *
9516     * console.log(array);
9517     * // => [1, 3]
9518     *
9519     * console.log(evens);
9520     * // => [2, 4]
9521     */
9522    function remove(array, predicate) {
9523      var result = [];
9524      if (!(array && array.length)) {
9525        return result;
9526      }
9527      var index = -1,
9528          indexes = [],
9529          length = array.length;
9530
9531      predicate = getIteratee(predicate, 3);
9532      while (++index < length) {
9533        var value = array[index];
9534        if (predicate(value, index, array)) {
9535          result.push(value);
9536          indexes.push(index);
9537        }
9538      }
9539      basePullAt(array, indexes);
9540      return result;
9541    }
9542
9543    /**
9544     * Reverses `array` so that the first element becomes the last, the second
9545     * element becomes the second to last, and so on.
9546     *
9547     * **Note:** This method mutates `array` and is based on
9548     * [`Array#reverse`](https://mdn.io/Array/reverse).
9549     *
9550     * @static
9551     * @memberOf _
9552     * @since 4.0.0
9553     * @category Array
9554     * @param {Array} array The array to modify.
9555     * @returns {Array} Returns `array`.
9556     * @example
9557     *
9558     * var array = [1, 2, 3];
9559     *
9560     * _.reverse(array);
9561     * // => [3, 2, 1]
9562     *
9563     * console.log(array);
9564     * // => [3, 2, 1]
9565     */
9566    function reverse(array) {
9567      return array == null ? array : nativeReverse.call(array);
9568    }
9569
9570    /**
9571     * Creates a slice of `array` from `start` up to, but not including, `end`.
9572     *
9573     * **Note:** This method is used instead of
9574     * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
9575     * returned.
9576     *
9577     * @static
9578     * @memberOf _
9579     * @since 3.0.0
9580     * @category Array
9581     * @param {Array} array The array to slice.
9582     * @param {number} [start=0] The start position.
9583     * @param {number} [end=array.length] The end position.
9584     * @returns {Array} Returns the slice of `array`.
9585     */
9586    function slice(array, start, end) {
9587      var length = array == null ? 0 : array.length;
9588      if (!length) {
9589        return [];
9590      }
9591      if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
9592        start = 0;
9593        end = length;
9594      }
9595      else {
9596        start = start == null ? 0 : toInteger(start);
9597        end = end === undefined ? length : toInteger(end);
9598      }
9599      return baseSlice(array, start, end);
9600    }
9601
9602    /**
9603     * Uses a binary search to determine the lowest index at which `value`
9604     * should be inserted into `array` in order to maintain its sort order.
9605     *
9606     * @static
9607     * @memberOf _
9608     * @since 0.1.0
9609     * @category Array
9610     * @param {Array} array The sorted array to inspect.
9611     * @param {*} value The value to evaluate.
9612     * @returns {number} Returns the index at which `value` should be inserted
9613     *  into `array`.
9614     * @example
9615     *
9616     * _.sortedIndex([30, 50], 40);
9617     * // => 1
9618     */
9619    function sortedIndex(array, value) {
9620      return baseSortedIndex(array, value);
9621    }
9622
9623    /**
9624     * This method is like `_.sortedIndex` except that it accepts `iteratee`
9625     * which is invoked for `value` and each element of `array` to compute their
9626     * sort ranking. The iteratee is invoked with one argument: (value).
9627     *
9628     * @static
9629     * @memberOf _
9630     * @since 4.0.0
9631     * @category Array
9632     * @param {Array} array The sorted array to inspect.
9633     * @param {*} value The value to evaluate.
9634     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
9635     * @returns {number} Returns the index at which `value` should be inserted
9636     *  into `array`.
9637     * @example
9638     *
9639     * var objects = [{ 'x': 4 }, { 'x': 5 }];
9640     *
9641     * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
9642     * // => 0
9643     *
9644     * // The `_.property` iteratee shorthand.
9645     * _.sortedIndexBy(objects, { 'x': 4 }, 'x');
9646     * // => 0
9647     */
9648    function sortedIndexBy(array, value, iteratee) {
9649      return baseSortedIndexBy(array, value, getIteratee(iteratee, 2));
9650    }
9651
9652    /**
9653     * This method is like `_.indexOf` except that it performs a binary
9654     * search on a sorted `array`.
9655     *
9656     * @static
9657     * @memberOf _
9658     * @since 4.0.0
9659     * @category Array
9660     * @param {Array} array The array to inspect.
9661     * @param {*} value The value to search for.
9662     * @returns {number} Returns the index of the matched value, else `-1`.
9663     * @example
9664     *
9665     * _.sortedIndexOf([4, 5, 5, 5, 6], 5);
9666     * // => 1
9667     */
9668    function sortedIndexOf(array, value) {
9669      var length = array == null ? 0 : array.length;
9670      if (length) {
9671        var index = baseSortedIndex(array, value);
9672        if (index < length && eq(array[index], value)) {
9673          return index;
9674        }
9675      }
9676      return -1;
9677    }
9678
9679    /**
9680     * This method is like `_.sortedIndex` except that it returns the highest
9681     * index at which `value` should be inserted into `array` in order to
9682     * maintain its sort order.
9683     *
9684     * @static
9685     * @memberOf _
9686     * @since 3.0.0
9687     * @category Array
9688     * @param {Array} array The sorted array to inspect.
9689     * @param {*} value The value to evaluate.
9690     * @returns {number} Returns the index at which `value` should be inserted
9691     *  into `array`.
9692     * @example
9693     *
9694     * _.sortedLastIndex([4, 5, 5, 5, 6], 5);
9695     * // => 4
9696     */
9697    function sortedLastIndex(array, value) {
9698      return baseSortedIndex(array, value, true);
9699    }
9700
9701    /**
9702     * This method is like `_.sortedLastIndex` except that it accepts `iteratee`
9703     * which is invoked for `value` and each element of `array` to compute their
9704     * sort ranking. The iteratee is invoked with one argument: (value).
9705     *
9706     * @static
9707     * @memberOf _
9708     * @since 4.0.0
9709     * @category Array
9710     * @param {Array} array The sorted array to inspect.
9711     * @param {*} value The value to evaluate.
9712     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
9713     * @returns {number} Returns the index at which `value` should be inserted
9714     *  into `array`.
9715     * @example
9716     *
9717     * var objects = [{ 'x': 4 }, { 'x': 5 }];
9718     *
9719     * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
9720     * // => 1
9721     *
9722     * // The `_.property` iteratee shorthand.
9723     * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x');
9724     * // => 1
9725     */
9726    function sortedLastIndexBy(array, value, iteratee) {
9727      return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true);
9728    }
9729
9730    /**
9731     * This method is like `_.lastIndexOf` except that it performs a binary
9732     * search on a sorted `array`.
9733     *
9734     * @static
9735     * @memberOf _
9736     * @since 4.0.0
9737     * @category Array
9738     * @param {Array} array The array to inspect.
9739     * @param {*} value The value to search for.
9740     * @returns {number} Returns the index of the matched value, else `-1`.
9741     * @example
9742     *
9743     * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5);
9744     * // => 3
9745     */
9746    function sortedLastIndexOf(array, value) {
9747      var length = array == null ? 0 : array.length;
9748      if (length) {
9749        var index = baseSortedIndex(array, value, true) - 1;
9750        if (eq(array[index], value)) {
9751          return index;
9752        }
9753      }
9754      return -1;
9755    }
9756
9757    /**
9758     * This method is like `_.uniq` except that it's designed and optimized
9759     * for sorted arrays.
9760     *
9761     * @static
9762     * @memberOf _
9763     * @since 4.0.0
9764     * @category Array
9765     * @param {Array} array The array to inspect.
9766     * @returns {Array} Returns the new duplicate free array.
9767     * @example
9768     *
9769     * _.sortedUniq([1, 1, 2]);
9770     * // => [1, 2]
9771     */
9772    function sortedUniq(array) {
9773      return (array && array.length)
9774        ? baseSortedUniq(array)
9775        : [];
9776    }
9777
9778    /**
9779     * This method is like `_.uniqBy` except that it's designed and optimized
9780     * for sorted arrays.
9781     *
9782     * @static
9783     * @memberOf _
9784     * @since 4.0.0
9785     * @category Array
9786     * @param {Array} array The array to inspect.
9787     * @param {Function} [iteratee] The iteratee invoked per element.
9788     * @returns {Array} Returns the new duplicate free array.
9789     * @example
9790     *
9791     * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
9792     * // => [1.1, 2.3]
9793     */
9794    function sortedUniqBy(array, iteratee) {
9795      return (array && array.length)
9796        ? baseSortedUniq(array, getIteratee(iteratee, 2))
9797        : [];
9798    }
9799
9800    /**
9801     * Gets all but the first element of `array`.
9802     *
9803     * @static
9804     * @memberOf _
9805     * @since 4.0.0
9806     * @category Array
9807     * @param {Array} array The array to query.
9808     * @returns {Array} Returns the slice of `array`.
9809     * @example
9810     *
9811     * _.tail([1, 2, 3]);
9812     * // => [2, 3]
9813     */
9814    function tail(array) {
9815      var length = array == null ? 0 : array.length;
9816      return length ? baseSlice(array, 1, length) : [];
9817    }
9818
9819    /**
9820     * Creates a slice of `array` with `n` elements taken from the beginning.
9821     *
9822     * @static
9823     * @memberOf _
9824     * @since 0.1.0
9825     * @category Array
9826     * @param {Array} array The array to query.
9827     * @param {number} [n=1] The number of elements to take.
9828     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9829     * @returns {Array} Returns the slice of `array`.
9830     * @example
9831     *
9832     * _.take([1, 2, 3]);
9833     * // => [1]
9834     *
9835     * _.take([1, 2, 3], 2);
9836     * // => [1, 2]
9837     *
9838     * _.take([1, 2, 3], 5);
9839     * // => [1, 2, 3]
9840     *
9841     * _.take([1, 2, 3], 0);
9842     * // => []
9843     */
9844    function take(array, n, guard) {
9845      if (!(array && array.length)) {
9846        return [];
9847      }
9848      n = (guard || n === undefined) ? 1 : toInteger(n);
9849      return baseSlice(array, 0, n < 0 ? 0 : n);
9850    }
9851
9852    /**
9853     * Creates a slice of `array` with `n` elements taken from the end.
9854     *
9855     * @static
9856     * @memberOf _
9857     * @since 3.0.0
9858     * @category Array
9859     * @param {Array} array The array to query.
9860     * @param {number} [n=1] The number of elements to take.
9861     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9862     * @returns {Array} Returns the slice of `array`.
9863     * @example
9864     *
9865     * _.takeRight([1, 2, 3]);
9866     * // => [3]
9867     *
9868     * _.takeRight([1, 2, 3], 2);
9869     * // => [2, 3]
9870     *
9871     * _.takeRight([1, 2, 3], 5);
9872     * // => [1, 2, 3]
9873     *
9874     * _.takeRight([1, 2, 3], 0);
9875     * // => []
9876     */
9877    function takeRight(array, n, guard) {
9878      var length = array == null ? 0 : array.length;
9879      if (!length) {
9880        return [];
9881      }
9882      n = (guard || n === undefined) ? 1 : toInteger(n);
9883      n = length - n;
9884      return baseSlice(array, n < 0 ? 0 : n, length);
9885    }
9886
9887    /**
9888     * Creates a slice of `array` with elements taken from the end. Elements are
9889     * taken until `predicate` returns falsey. The predicate is invoked with
9890     * three arguments: (value, index, array).
9891     *
9892     * @static
9893     * @memberOf _
9894     * @since 3.0.0
9895     * @category Array
9896     * @param {Array} array The array to query.
9897     * @param {Function} [predicate=_.identity] The function invoked per iteration.
9898     * @returns {Array} Returns the slice of `array`.
9899     * @example
9900     *
9901     * var users = [
9902     *   { 'user': 'barney',  'active': true },
9903     *   { 'user': 'fred',    'active': false },
9904     *   { 'user': 'pebbles', 'active': false }
9905     * ];
9906     *
9907     * _.takeRightWhile(users, function(o) { return !o.active; });
9908     * // => objects for ['fred', 'pebbles']
9909     *
9910     * // The `_.matches` iteratee shorthand.
9911     * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
9912     * // => objects for ['pebbles']
9913     *
9914     * // The `_.matchesProperty` iteratee shorthand.
9915     * _.takeRightWhile(users, ['active', false]);
9916     * // => objects for ['fred', 'pebbles']
9917     *
9918     * // The `_.property` iteratee shorthand.
9919     * _.takeRightWhile(users, 'active');
9920     * // => []
9921     */
9922    function takeRightWhile(array, predicate) {
9923      return (array && array.length)
9924        ? baseWhile(array, getIteratee(predicate, 3), false, true)
9925        : [];
9926    }
9927
9928    /**
9929     * Creates a slice of `array` with elements taken from the beginning. Elements
9930     * are taken until `predicate` returns falsey. The predicate is invoked with
9931     * three arguments: (value, index, array).
9932     *
9933     * @static
9934     * @memberOf _
9935     * @since 3.0.0
9936     * @category Array
9937     * @param {Array} array The array to query.
9938     * @param {Function} [predicate=_.identity] The function invoked per iteration.
9939     * @returns {Array} Returns the slice of `array`.
9940     * @example
9941     *
9942     * var users = [
9943     *   { 'user': 'barney',  'active': false },
9944     *   { 'user': 'fred',    'active': false },
9945     *   { 'user': 'pebbles', 'active': true }
9946     * ];
9947     *
9948     * _.takeWhile(users, function(o) { return !o.active; });
9949     * // => objects for ['barney', 'fred']
9950     *
9951     * // The `_.matches` iteratee shorthand.
9952     * _.takeWhile(users, { 'user': 'barney', 'active': false });
9953     * // => objects for ['barney']
9954     *
9955     * // The `_.matchesProperty` iteratee shorthand.
9956     * _.takeWhile(users, ['active', false]);
9957     * // => objects for ['barney', 'fred']
9958     *
9959     * // The `_.property` iteratee shorthand.
9960     * _.takeWhile(users, 'active');
9961     * // => []
9962     */
9963    function takeWhile(array, predicate) {
9964      return (array && array.length)
9965        ? baseWhile(array, getIteratee(predicate, 3))
9966        : [];
9967    }
9968
9969    /**
9970     * Creates an array of unique values, in order, from all given arrays using
9971     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
9972     * for equality comparisons.
9973     *
9974     * @static
9975     * @memberOf _
9976     * @since 0.1.0
9977     * @category Array
9978     * @param {...Array} [arrays] The arrays to inspect.
9979     * @returns {Array} Returns the new array of combined values.
9980     * @example
9981     *
9982     * _.union([2], [1, 2]);
9983     * // => [2, 1]
9984     */
9985    var union = baseRest(function(arrays) {
9986      return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
9987    });
9988
9989    /**
9990     * This method is like `_.union` except that it accepts `iteratee` which is
9991     * invoked for each element of each `arrays` to generate the criterion by
9992     * which uniqueness is computed. Result values are chosen from the first
9993     * array in which the value occurs. The iteratee is invoked with one argument:
9994     * (value).
9995     *
9996     * @static
9997     * @memberOf _
9998     * @since 4.0.0
9999     * @category Array
10000     * @param {...Array} [arrays] The arrays to inspect.
10001     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
10002     * @returns {Array} Returns the new array of combined values.
10003     * @example
10004     *
10005     * _.unionBy([2.1], [1.2, 2.3], Math.floor);
10006     * // => [2.1, 1.2]
10007     *
10008     * // The `_.property` iteratee shorthand.
10009     * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
10010     * // => [{ 'x': 1 }, { 'x': 2 }]
10011     */
10012    var unionBy = baseRest(function(arrays) {
10013      var iteratee = last(arrays);
10014      if (isArrayLikeObject(iteratee)) {
10015        iteratee = undefined;
10016      }
10017      return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2));
10018    });
10019
10020    /**
10021     * This method is like `_.union` except that it accepts `comparator` which
10022     * is invoked to compare elements of `arrays`. Result values are chosen from
10023     * the first array in which the value occurs. The comparator is invoked
10024     * with two arguments: (arrVal, othVal).
10025     *
10026     * @static
10027     * @memberOf _
10028     * @since 4.0.0
10029     * @category Array
10030     * @param {...Array} [arrays] The arrays to inspect.
10031     * @param {Function} [comparator] The comparator invoked per element.
10032     * @returns {Array} Returns the new array of combined values.
10033     * @example
10034     *
10035     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
10036     * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
10037     *
10038     * _.unionWith(objects, others, _.isEqual);
10039     * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
10040     */
10041    var unionWith = baseRest(function(arrays) {
10042      var comparator = last(arrays);
10043      comparator = typeof comparator == 'function' ? comparator : undefined;
10044      return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
10045    });
10046
10047    /**
10048     * Creates a duplicate-free version of an array, using
10049     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
10050     * for equality comparisons, in which only the first occurrence of each element
10051     * is kept. The order of result values is determined by the order they occur
10052     * in the array.
10053     *
10054     * @static
10055     * @memberOf _
10056     * @since 0.1.0
10057     * @category Array
10058     * @param {Array} array The array to inspect.
10059     * @returns {Array} Returns the new duplicate free array.
10060     * @example
10061     *
10062     * _.uniq([2, 1, 2]);
10063     * // => [2, 1]
10064     */
10065    function uniq(array) {
10066      return (array && array.length) ? baseUniq(array) : [];
10067    }
10068
10069    /**
10070     * This method is like `_.uniq` except that it accepts `iteratee` which is
10071     * invoked for each element in `array` to generate the criterion by which
10072     * uniqueness is computed. The order of result values is determined by the
10073     * order they occur in the array. The iteratee is invoked with one argument:
10074     * (value).
10075     *
10076     * @static
10077     * @memberOf _
10078     * @since 4.0.0
10079     * @category Array
10080     * @param {Array} array The array to inspect.
10081     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
10082     * @returns {Array} Returns the new duplicate free array.
10083     * @example
10084     *
10085     * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
10086     * // => [2.1, 1.2]
10087     *
10088     * // The `_.property` iteratee shorthand.
10089     * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
10090     * // => [{ 'x': 1 }, { 'x': 2 }]
10091     */
10092    function uniqBy(array, iteratee) {
10093      return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : [];
10094    }
10095
10096    /**
10097     * This method is like `_.uniq` except that it accepts `comparator` which
10098     * is invoked to compare elements of `array`. The order of result values is
10099     * determined by the order they occur in the array.The comparator is invoked
10100     * with two arguments: (arrVal, othVal).
10101     *
10102     * @static
10103     * @memberOf _
10104     * @since 4.0.0
10105     * @category Array
10106     * @param {Array} array The array to inspect.
10107     * @param {Function} [comparator] The comparator invoked per element.
10108     * @returns {Array} Returns the new duplicate free array.
10109     * @example
10110     *
10111     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
10112     *
10113     * _.uniqWith(objects, _.isEqual);
10114     * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
10115     */
10116    function uniqWith(array, comparator) {
10117      comparator = typeof comparator == 'function' ? comparator : undefined;
10118      return (array && array.length) ? baseUniq(array, undefined, comparator) : [];
10119    }
10120
10121    /**
10122     * This method is like `_.zip` except that it accepts an array of grouped
10123     * elements and creates an array regrouping the elements to their pre-zip
10124     * configuration.
10125     *
10126     * @static
10127     * @memberOf _
10128     * @since 1.2.0
10129     * @category Array
10130     * @param {Array} array The array of grouped elements to process.
10131     * @returns {Array} Returns the new array of regrouped elements.
10132     * @example
10133     *
10134     * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
10135     * // => [['a', 1, true], ['b', 2, false]]
10136     *
10137     * _.unzip(zipped);
10138     * // => [['a', 'b'], [1, 2], [true, false]]
10139     */
10140    function unzip(array) {
10141      if (!(array && array.length)) {
10142        return [];
10143      }
10144      var length = 0;
10145      array = arrayFilter(array, function(group) {
10146        if (isArrayLikeObject(group)) {
10147          length = nativeMax(group.length, length);
10148          return true;
10149        }
10150      });
10151      return baseTimes(length, function(index) {
10152        return arrayMap(array, baseProperty(index));
10153      });
10154    }
10155
10156    /**
10157     * This method is like `_.unzip` except that it accepts `iteratee` to specify
10158     * how regrouped values should be combined. The iteratee is invoked with the
10159     * elements of each group: (...group).
10160     *
10161     * @static
10162     * @memberOf _
10163     * @since 3.8.0
10164     * @category Array
10165     * @param {Array} array The array of grouped elements to process.
10166     * @param {Function} [iteratee=_.identity] The function to combine
10167     *  regrouped values.
10168     * @returns {Array} Returns the new array of regrouped elements.
10169     * @example
10170     *
10171     * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
10172     * // => [[1, 10, 100], [2, 20, 200]]
10173     *
10174     * _.unzipWith(zipped, _.add);
10175     * // => [3, 30, 300]
10176     */
10177    function unzipWith(array, iteratee) {
10178      if (!(array && array.length)) {
10179        return [];
10180      }
10181      var result = unzip(array);
10182      if (iteratee == null) {
10183        return result;
10184      }
10185      return arrayMap(result, function(group) {
10186        return apply(iteratee, undefined, group);
10187      });
10188    }
10189
10190    /**
10191     * Creates an array excluding all given values using
10192     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
10193     * for equality comparisons.
10194     *
10195     * **Note:** Unlike `_.pull`, this method returns a new array.
10196     *
10197     * @static
10198     * @memberOf _
10199     * @since 0.1.0
10200     * @category Array
10201     * @param {Array} array The array to inspect.
10202     * @param {...*} [values] The values to exclude.
10203     * @returns {Array} Returns the new array of filtered values.
10204     * @see _.difference, _.xor
10205     * @example
10206     *
10207     * _.without([2, 1, 2, 3], 1, 2);
10208     * // => [3]
10209     */
10210    var without = baseRest(function(array, values) {
10211      return isArrayLikeObject(array)
10212        ? baseDifference(array, values)
10213        : [];
10214    });
10215
10216    /**
10217     * Creates an array of unique values that is the
10218     * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
10219     * of the given arrays. The order of result values is determined by the order
10220     * they occur in the arrays.
10221     *
10222     * @static
10223     * @memberOf _
10224     * @since 2.4.0
10225     * @category Array
10226     * @param {...Array} [arrays] The arrays to inspect.
10227     * @returns {Array} Returns the new array of filtered values.
10228     * @see _.difference, _.without
10229     * @example
10230     *
10231     * _.xor([2, 1], [2, 3]);
10232     * // => [1, 3]
10233     */
10234    var xor = baseRest(function(arrays) {
10235      return baseXor(arrayFilter(arrays, isArrayLikeObject));
10236    });
10237
10238    /**
10239     * This method is like `_.xor` except that it accepts `iteratee` which is
10240     * invoked for each element of each `arrays` to generate the criterion by
10241     * which by which they're compared. The order of result values is determined
10242     * by the order they occur in the arrays. The iteratee is invoked with one
10243     * argument: (value).
10244     *
10245     * @static
10246     * @memberOf _
10247     * @since 4.0.0
10248     * @category Array
10249     * @param {...Array} [arrays] The arrays to inspect.
10250     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
10251     * @returns {Array} Returns the new array of filtered values.
10252     * @example
10253     *
10254     * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
10255     * // => [1.2, 3.4]
10256     *
10257     * // The `_.property` iteratee shorthand.
10258     * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
10259     * // => [{ 'x': 2 }]
10260     */
10261    var xorBy = baseRest(function(arrays) {
10262      var iteratee = last(arrays);
10263      if (isArrayLikeObject(iteratee)) {
10264        iteratee = undefined;
10265      }
10266      return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2));
10267    });
10268
10269    /**
10270     * This method is like `_.xor` except that it accepts `comparator` which is
10271     * invoked to compare elements of `arrays`. The order of result values is
10272     * determined by the order they occur in the arrays. The comparator is invoked
10273     * with two arguments: (arrVal, othVal).
10274     *
10275     * @static
10276     * @memberOf _
10277     * @since 4.0.0
10278     * @category Array
10279     * @param {...Array} [arrays] The arrays to inspect.
10280     * @param {Function} [comparator] The comparator invoked per element.
10281     * @returns {Array} Returns the new array of filtered values.
10282     * @example
10283     *
10284     * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
10285     * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
10286     *
10287     * _.xorWith(objects, others, _.isEqual);
10288     * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
10289     */
10290    var xorWith = baseRest(function(arrays) {
10291      var comparator = last(arrays);
10292      comparator = typeof comparator == 'function' ? comparator : undefined;
10293      return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
10294    });
10295
10296    /**
10297     * Creates an array of grouped elements, the first of which contains the
10298     * first elements of the given arrays, the second of which contains the
10299     * second elements of the given arrays, and so on.
10300     *
10301     * @static
10302     * @memberOf _
10303     * @since 0.1.0
10304     * @category Array
10305     * @param {...Array} [arrays] The arrays to process.
10306     * @returns {Array} Returns the new array of grouped elements.
10307     * @example
10308     *
10309     * _.zip(['a', 'b'], [1, 2], [true, false]);
10310     * // => [['a', 1, true], ['b', 2, false]]
10311     */
10312    var zip = baseRest(unzip);
10313
10314    /**
10315     * This method is like `_.fromPairs` except that it accepts two arrays,
10316     * one of property identifiers and one of corresponding values.
10317     *
10318     * @static
10319     * @memberOf _
10320     * @since 0.4.0
10321     * @category Array
10322     * @param {Array} [props=[]] The property identifiers.
10323     * @param {Array} [values=[]] The property values.
10324     * @returns {Object} Returns the new object.
10325     * @example
10326     *
10327     * _.zipObject(['a', 'b'], [1, 2]);
10328     * // => { 'a': 1, 'b': 2 }
10329     */
10330    function zipObject(props, values) {
10331      return baseZipObject(props || [], values || [], assignValue);
10332    }
10333
10334    /**
10335     * This method is like `_.zipObject` except that it supports property paths.
10336     *
10337     * @static
10338     * @memberOf _
10339     * @since 4.1.0
10340     * @category Array
10341     * @param {Array} [props=[]] The property identifiers.
10342     * @param {Array} [values=[]] The property values.
10343     * @returns {Object} Returns the new object.
10344     * @example
10345     *
10346     * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
10347     * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
10348     */
10349    function zipObjectDeep(props, values) {
10350      return baseZipObject(props || [], values || [], baseSet);
10351    }
10352
10353    /**
10354     * This method is like `_.zip` except that it accepts `iteratee` to specify
10355     * how grouped values should be combined. The iteratee is invoked with the
10356     * elements of each group: (...group).
10357     *
10358     * @static
10359     * @memberOf _
10360     * @since 3.8.0
10361     * @category Array
10362     * @param {...Array} [arrays] The arrays to process.
10363     * @param {Function} [iteratee=_.identity] The function to combine
10364     *  grouped values.
10365     * @returns {Array} Returns the new array of grouped elements.
10366     * @example
10367     *
10368     * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
10369     *   return a + b + c;
10370     * });
10371     * // => [111, 222]
10372     */
10373    var zipWith = baseRest(function(arrays) {
10374      var length = arrays.length,
10375          iteratee = length > 1 ? arrays[length - 1] : undefined;
10376
10377      iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;
10378      return unzipWith(arrays, iteratee);
10379    });
10380
10381    /*------------------------------------------------------------------------*/
10382
10383    /**
10384     * Creates a `lodash` wrapper instance that wraps `value` with explicit method
10385     * chain sequences enabled. The result of such sequences must be unwrapped
10386     * with `_#value`.
10387     *
10388     * @static
10389     * @memberOf _
10390     * @since 1.3.0
10391     * @category Seq
10392     * @param {*} value The value to wrap.
10393     * @returns {Object} Returns the new `lodash` wrapper instance.
10394     * @example
10395     *
10396     * var users = [
10397     *   { 'user': 'barney',  'age': 36 },
10398     *   { 'user': 'fred',    'age': 40 },
10399     *   { 'user': 'pebbles', 'age': 1 }
10400     * ];
10401     *
10402     * var youngest = _
10403     *   .chain(users)
10404     *   .sortBy('age')
10405     *   .map(function(o) {
10406     *     return o.user + ' is ' + o.age;
10407     *   })
10408     *   .head()
10409     *   .value();
10410     * // => 'pebbles is 1'
10411     */
10412    function chain(value) {
10413      var result = lodash(value);
10414      result.__chain__ = true;
10415      return result;
10416    }
10417
10418    /**
10419     * This method invokes `interceptor` and returns `value`. The interceptor
10420     * is invoked with one argument; (value). The purpose of this method is to
10421     * "tap into" a method chain sequence in order to modify intermediate results.
10422     *
10423     * @static
10424     * @memberOf _
10425     * @since 0.1.0
10426     * @category Seq
10427     * @param {*} value The value to provide to `interceptor`.
10428     * @param {Function} interceptor The function to invoke.
10429     * @returns {*} Returns `value`.
10430     * @example
10431     *
10432     * _([1, 2, 3])
10433     *  .tap(function(array) {
10434     *    // Mutate input array.
10435     *    array.pop();
10436     *  })
10437     *  .reverse()
10438     *  .value();
10439     * // => [2, 1]
10440     */
10441    function tap(value, interceptor) {
10442      interceptor(value);
10443      return value;
10444    }
10445
10446    /**
10447     * This method is like `_.tap` except that it returns the result of `interceptor`.
10448     * The purpose of this method is to "pass thru" values replacing intermediate
10449     * results in a method chain sequence.
10450     *
10451     * @static
10452     * @memberOf _
10453     * @since 3.0.0
10454     * @category Seq
10455     * @param {*} value The value to provide to `interceptor`.
10456     * @param {Function} interceptor The function to invoke.
10457     * @returns {*} Returns the result of `interceptor`.
10458     * @example
10459     *
10460     * _('  abc  ')
10461     *  .chain()
10462     *  .trim()
10463     *  .thru(function(value) {
10464     *    return [value];
10465     *  })
10466     *  .value();
10467     * // => ['abc']
10468     */
10469    function thru(value, interceptor) {
10470      return interceptor(value);
10471    }
10472
10473    /**
10474     * This method is the wrapper version of `_.at`.
10475     *
10476     * @name at
10477     * @memberOf _
10478     * @since 1.0.0
10479     * @category Seq
10480     * @param {...(string|string[])} [paths] The property paths to pick.
10481     * @returns {Object} Returns the new `lodash` wrapper instance.
10482     * @example
10483     *
10484     * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
10485     *
10486     * _(object).at(['a[0].b.c', 'a[1]']).value();
10487     * // => [3, 4]
10488     */
10489    var wrapperAt = flatRest(function(paths) {
10490      var length = paths.length,
10491          start = length ? paths[0] : 0,
10492          value = this.__wrapped__,
10493          interceptor = function(object) { return baseAt(object, paths); };
10494
10495      if (length > 1 || this.__actions__.length ||
10496          !(value instanceof LazyWrapper) || !isIndex(start)) {
10497        return this.thru(interceptor);
10498      }
10499      value = value.slice(start, +start + (length ? 1 : 0));
10500      value.__actions__.push({
10501        'func': thru,
10502        'args': [interceptor],
10503        'thisArg': undefined
10504      });
10505      return new LodashWrapper(value, this.__chain__).thru(function(array) {
10506        if (length && !array.length) {
10507          array.push(undefined);
10508        }
10509        return array;
10510      });
10511    });
10512
10513    /**
10514     * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
10515     *
10516     * @name chain
10517     * @memberOf _
10518     * @since 0.1.0
10519     * @category Seq
10520     * @returns {Object} Returns the new `lodash` wrapper instance.
10521     * @example
10522     *
10523     * var users = [
10524     *   { 'user': 'barney', 'age': 36 },
10525     *   { 'user': 'fred',   'age': 40 }
10526     * ];
10527     *
10528     * // A sequence without explicit chaining.
10529     * _(users).head();
10530     * // => { 'user': 'barney', 'age': 36 }
10531     *
10532     * // A sequence with explicit chaining.
10533     * _(users)
10534     *   .chain()
10535     *   .head()
10536     *   .pick('user')
10537     *   .value();
10538     * // => { 'user': 'barney' }
10539     */
10540    function wrapperChain() {
10541      return chain(this);
10542    }
10543
10544    /**
10545     * Executes the chain sequence and returns the wrapped result.
10546     *
10547     * @name commit
10548     * @memberOf _
10549     * @since 3.2.0
10550     * @category Seq
10551     * @returns {Object} Returns the new `lodash` wrapper instance.
10552     * @example
10553     *
10554     * var array = [1, 2];
10555     * var wrapped = _(array).push(3);
10556     *
10557     * console.log(array);
10558     * // => [1, 2]
10559     *
10560     * wrapped = wrapped.commit();
10561     * console.log(array);
10562     * // => [1, 2, 3]
10563     *
10564     * wrapped.last();
10565     * // => 3
10566     *
10567     * console.log(array);
10568     * // => [1, 2, 3]
10569     */
10570    function wrapperCommit() {
10571      return new LodashWrapper(this.value(), this.__chain__);
10572    }
10573
10574    /**
10575     * Gets the next value on a wrapped object following the
10576     * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
10577     *
10578     * @name next
10579     * @memberOf _
10580     * @since 4.0.0
10581     * @category Seq
10582     * @returns {Object} Returns the next iterator value.
10583     * @example
10584     *
10585     * var wrapped = _([1, 2]);
10586     *
10587     * wrapped.next();
10588     * // => { 'done': false, 'value': 1 }
10589     *
10590     * wrapped.next();
10591     * // => { 'done': false, 'value': 2 }
10592     *
10593     * wrapped.next();
10594     * // => { 'done': true, 'value': undefined }
10595     */
10596    function wrapperNext() {
10597      if (this.__values__ === undefined) {
10598        this.__values__ = toArray(this.value());
10599      }
10600      var done = this.__index__ >= this.__values__.length,
10601          value = done ? undefined : this.__values__[this.__index__++];
10602
10603      return { 'done': done, 'value': value };
10604    }
10605
10606    /**
10607     * Enables the wrapper to be iterable.
10608     *
10609     * @name Symbol.iterator
10610     * @memberOf _
10611     * @since 4.0.0
10612     * @category Seq
10613     * @returns {Object} Returns the wrapper object.
10614     * @example
10615     *
10616     * var wrapped = _([1, 2]);
10617     *
10618     * wrapped[Symbol.iterator]() === wrapped;
10619     * // => true
10620     *
10621     * Array.from(wrapped);
10622     * // => [1, 2]
10623     */
10624    function wrapperToIterator() {
10625      return this;
10626    }
10627
10628    /**
10629     * Creates a clone of the chain sequence planting `value` as the wrapped value.
10630     *
10631     * @name plant
10632     * @memberOf _
10633     * @since 3.2.0
10634     * @category Seq
10635     * @param {*} value The value to plant.
10636     * @returns {Object} Returns the new `lodash` wrapper instance.
10637     * @example
10638     *
10639     * function square(n) {
10640     *   return n * n;
10641     * }
10642     *
10643     * var wrapped = _([1, 2]).map(square);
10644     * var other = wrapped.plant([3, 4]);
10645     *
10646     * other.value();
10647     * // => [9, 16]
10648     *
10649     * wrapped.value();
10650     * // => [1, 4]
10651     */
10652    function wrapperPlant(value) {
10653      var result,
10654          parent = this;
10655
10656      while (parent instanceof baseLodash) {
10657        var clone = wrapperClone(parent);
10658        clone.__index__ = 0;
10659        clone.__values__ = undefined;
10660        if (result) {
10661          previous.__wrapped__ = clone;
10662        } else {
10663          result = clone;
10664        }
10665        var previous = clone;
10666        parent = parent.__wrapped__;
10667      }
10668      previous.__wrapped__ = value;
10669      return result;
10670    }
10671
10672    /**
10673     * This method is the wrapper version of `_.reverse`.
10674     *
10675     * **Note:** This method mutates the wrapped array.
10676     *
10677     * @name reverse
10678     * @memberOf _
10679     * @since 0.1.0
10680     * @category Seq
10681     * @returns {Object} Returns the new `lodash` wrapper instance.
10682     * @example
10683     *
10684     * var array = [1, 2, 3];
10685     *
10686     * _(array).reverse().value()
10687     * // => [3, 2, 1]
10688     *
10689     * console.log(array);
10690     * // => [3, 2, 1]
10691     */
10692    function wrapperReverse() {
10693      var value = this.__wrapped__;
10694      if (value instanceof LazyWrapper) {
10695        var wrapped = value;
10696        if (this.__actions__.length) {
10697          wrapped = new LazyWrapper(this);
10698        }
10699        wrapped = wrapped.reverse();
10700        wrapped.__actions__.push({
10701          'func': thru,
10702          'args': [reverse],
10703          'thisArg': undefined
10704        });
10705        return new LodashWrapper(wrapped, this.__chain__);
10706      }
10707      return this.thru(reverse);
10708    }
10709
10710    /**
10711     * Executes the chain sequence to resolve the unwrapped value.
10712     *
10713     * @name value
10714     * @memberOf _
10715     * @since 0.1.0
10716     * @alias toJSON, valueOf
10717     * @category Seq
10718     * @returns {*} Returns the resolved unwrapped value.
10719     * @example
10720     *
10721     * _([1, 2, 3]).value();
10722     * // => [1, 2, 3]
10723     */
10724    function wrapperValue() {
10725      return baseWrapperValue(this.__wrapped__, this.__actions__);
10726    }
10727
10728    /*------------------------------------------------------------------------*/
10729
10730    /**
10731     * Creates an object composed of keys generated from the results of running
10732     * each element of `collection` thru `iteratee`. The corresponding value of
10733     * each key is the number of times the key was returned by `iteratee`. The
10734     * iteratee is invoked with one argument: (value).
10735     *
10736     * @static
10737     * @memberOf _
10738     * @since 0.5.0
10739     * @category Collection
10740     * @param {Array|Object} collection The collection to iterate over.
10741     * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
10742     * @returns {Object} Returns the composed aggregate object.
10743     * @example
10744     *
10745     * _.countBy([6.1, 4.2, 6.3], Math.floor);
10746     * // => { '4': 1, '6': 2 }
10747     *
10748     * // The `_.property` iteratee shorthand.
10749     * _.countBy(['one', 'two', 'three'], 'length');
10750     * // => { '3': 2, '5': 1 }
10751     */
10752    var countBy = createAggregator(function(result, value, key) {
10753      if (hasOwnProperty.call(result, key)) {
10754        ++result[key];
10755      } else {
10756        baseAssignValue(result, key, 1);
10757      }
10758    });
10759
10760    /**
10761     * Checks if `predicate` returns truthy for **all** elements of `collection`.
10762     * Iteration is stopped once `predicate` returns falsey. The predicate is
10763     * invoked with three arguments: (value, index|key, collection).
10764     *
10765     * **Note:** This method returns `true` for
10766     * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because
10767     * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of
10768     * elements of empty collections.
10769     *
10770     * @static
10771     * @memberOf _
10772     * @since 0.1.0
10773     * @category Collection
10774     * @param {Array|Object} collection The collection to iterate over.
10775     * @param {Function} [predicate=_.identity] The function invoked per iteration.
10776     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10777     * @returns {boolean} Returns `true` if all elements pass the predicate check,
10778     *  else `false`.
10779     * @example
10780     *
10781     * _.every([true, 1, null, 'yes'], Boolean);
10782     * // => false
10783     *
10784     * var users = [
10785     *   { 'user': 'barney', 'age': 36, 'active': false },
10786     *   { 'user': 'fred',   'age': 40, 'active': false }
10787     * ];
10788     *
10789     * // The `_.matches` iteratee shorthand.
10790     * _.every(users, { 'user': 'barney', 'active': false });
10791     * // => false
10792     *
10793     * // The `_.matchesProperty` iteratee shorthand.
10794     * _.every(users, ['active', false]);
10795     * // => true
10796     *
10797     * // The `_.property` iteratee shorthand.
10798     * _.every(users, 'active');
10799     * // => false
10800     */
10801    function every(collection, predicate, guard) {
10802      var func = isArray(collection) ? arrayEvery : baseEvery;
10803      if (guard && isIterateeCall(collection, predicate, guard)) {
10804        predicate = undefined;
10805      }
10806      return func(collection, getIteratee(predicate, 3));
10807    }
10808
10809    /**
10810     * Iterates over elements of `collection`, returning an array of all elements
10811     * `predicate` returns truthy for. The predicate is invoked with three
10812     * arguments: (value, index|key, collection).
10813     *
10814     * **Note:** Unlike `_.remove`, this method returns a new array.
10815     *
10816     * @static
10817     * @memberOf _
10818     * @since 0.1.0
10819     * @category Collection
10820     * @param {Array|Object} collection The collection to iterate over.
10821     * @param {Function} [predicate=_.identity] The function invoked per iteration.
10822     * @returns {Array} Returns the new filtered array.
10823     * @see _.reject
10824     * @example
10825     *
10826     * var users = [
10827     *   { 'user': 'barney', 'age': 36, 'active': true },
10828     *   { 'user': 'fred',   'age': 40, 'active': false }
10829     * ];
10830     *
10831     * _.filter(users, function(o) { return !o.active; });
10832     * // => objects for ['fred']
10833     *
10834     * // The `_.matches` iteratee shorthand.
10835     * _.filter(users, { 'age': 36, 'active': true });
10836     * // => objects for ['barney']
10837     *
10838     * // The `_.matchesProperty` iteratee shorthand.
10839     * _.filter(users, ['active', false]);
10840     * // => objects for ['fred']
10841     *
10842     * // The `_.property` iteratee shorthand.
10843     * _.filter(users, 'active');
10844     * // => objects for ['barney']
10845     *
10846     * // Combining several predicates using `_.overEvery` or `_.overSome`.
10847     * _.filter(users, _.overSome([{ 'age': 36 }, ['age', 40]]));
10848     * // => objects for ['fred', 'barney']
10849     */
10850    function filter(collection, predicate) {
10851      var func = isArray(collection) ? arrayFilter : baseFilter;
10852      return func(collection, getIteratee(predicate, 3));
10853    }
10854
10855    /**
10856     * Iterates over elements of `collection`, returning the first element
10857     * `predicate` returns truthy for. The predicate is invoked with three
10858     * arguments: (value, index|key, collection).
10859     *
10860     * @static
10861     * @memberOf _
10862     * @since 0.1.0
10863     * @category Collection
10864     * @param {Array|Object} collection The collection to inspect.
10865     * @param {Function} [predicate=_.identity] The function invoked per iteration.
10866     * @param {number} [fromIndex=0] The index to search from.
10867     * @returns {*} Returns the matched element, else `undefined`.
10868     * @example
10869     *
10870     * var users = [
10871     *   { 'user': 'barney',  'age': 36, 'active': true },
10872     *   { 'user': 'fred',    'age': 40, 'active': false },
10873     *   { 'user': 'pebbles', 'age': 1,  'active': true }
10874     * ];
10875     *
10876     * _.find(users, function(o) { return o.age < 40; });
10877     * // => object for 'barney'
10878     *
10879     * // The `_.matches` iteratee shorthand.
10880     * _.find(users, { 'age': 1, 'active': true });
10881     * // => object for 'pebbles'
10882     *
10883     * // The `_.matchesProperty` iteratee shorthand.
10884     * _.find(users, ['active', false]);
10885     * // => object for 'fred'
10886     *
10887     * // The `_.property` iteratee shorthand.
10888     * _.find(users, 'active');
10889     * // => object for 'barney'
10890     */
10891    var find = createFind(findIndex);
10892
10893    /**
10894     * This method is like `_.find` except that it iterates over elements of
10895     * `collection` from right to left.
10896     *
10897     * @static
10898     * @memberOf _
10899     * @since 2.0.0
10900     * @category Collection
10901     * @param {Array|Object} collection The collection to inspect.
10902     * @param {Function} [predicate=_.identity] The function invoked per iteration.
10903     * @param {number} [fromIndex=collection.length-1] The index to search from.
10904     * @returns {*} Returns the matched element, else `undefined`.
10905     * @example
10906     *
10907     * _.findLast([1, 2, 3, 4], function(n) {
10908     *   return n % 2 == 1;
10909     * });
10910     * // => 3
10911     */
10912    var findLast = createFind(findLastIndex);
10913
10914    /**
10915     * Creates a flattened array of values by running each element in `collection`
10916     * thru `iteratee` and flattening the mapped results. The iteratee is invoked
10917     * with three arguments: (value, index|key, collection).
10918     *
10919     * @static
10920     * @memberOf _
10921     * @since 4.0.0
10922     * @category Collection
10923     * @param {Array|Object} collection The collection to iterate over.
10924     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
10925     * @returns {Array} Returns the new flattened array.
10926     * @example
10927     *
10928     * function duplicate(n) {
10929     *   return [n, n];
10930     * }
10931     *
10932     * _.flatMap([1, 2], duplicate);
10933     * // => [1, 1, 2, 2]
10934     */
10935    function flatMap(collection, iteratee) {
10936      return baseFlatten(map(collection, iteratee), 1);
10937    }
10938
10939    /**
10940     * This method is like `_.flatMap` except that it recursively flattens the
10941     * mapped results.
10942     *
10943     * @static
10944     * @memberOf _
10945     * @since 4.7.0
10946     * @category Collection
10947     * @param {Array|Object} collection The collection to iterate over.
10948     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
10949     * @returns {Array} Returns the new flattened array.
10950     * @example
10951     *
10952     * function duplicate(n) {
10953     *   return [[[n, n]]];
10954     * }
10955     *
10956     * _.flatMapDeep([1, 2], duplicate);
10957     * // => [1, 1, 2, 2]
10958     */
10959    function flatMapDeep(collection, iteratee) {
10960      return baseFlatten(map(collection, iteratee), INFINITY);
10961    }
10962
10963    /**
10964     * This method is like `_.flatMap` except that it recursively flattens the
10965     * mapped results up to `depth` times.
10966     *
10967     * @static
10968     * @memberOf _
10969     * @since 4.7.0
10970     * @category Collection
10971     * @param {Array|Object} collection The collection to iterate over.
10972     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
10973     * @param {number} [depth=1] The maximum recursion depth.
10974     * @returns {Array} Returns the new flattened array.
10975     * @example
10976     *
10977     * function duplicate(n) {
10978     *   return [[[n, n]]];
10979     * }
10980     *
10981     * _.flatMapDepth([1, 2], duplicate, 2);
10982     * // => [[1, 1], [2, 2]]
10983     */
10984    function flatMapDepth(collection, iteratee, depth) {
10985      depth = depth === undefined ? 1 : toInteger(depth);
10986      return baseFlatten(map(collection, iteratee), depth);
10987    }
10988
10989    /**
10990     * Iterates over elements of `collection` and invokes `iteratee` for each element.
10991     * The iteratee is invoked with three arguments: (value, index|key, collection).
10992     * Iteratee functions may exit iteration early by explicitly returning `false`.
10993     *
10994     * **Note:** As with other "Collections" methods, objects with a "length"
10995     * property are iterated like arrays. To avoid this behavior use `_.forIn`
10996     * or `_.forOwn` for object iteration.
10997     *
10998     * @static
10999     * @memberOf _
11000     * @since 0.1.0
11001     * @alias each
11002     * @category Collection
11003     * @param {Array|Object} collection The collection to iterate over.
11004     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
11005     * @returns {Array|Object} Returns `collection`.
11006     * @see _.forEachRight
11007     * @example
11008     *
11009     * _.forEach([1, 2], function(value) {
11010     *   console.log(value);
11011     * });
11012     * // => Logs `1` then `2`.
11013     *
11014     * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
11015     *   console.log(key);
11016     * });
11017     * // => Logs 'a' then 'b' (iteration order is not guaranteed).
11018     */
11019    function forEach(collection, iteratee) {
11020      var func = isArray(collection) ? arrayEach : baseEach;
11021      return func(collection, getIteratee(iteratee, 3));
11022    }
11023
11024    /**
11025     * This method is like `_.forEach` except that it iterates over elements of
11026     * `collection` from right to left.
11027     *
11028     * @static
11029     * @memberOf _
11030     * @since 2.0.0
11031     * @alias eachRight
11032     * @category Collection
11033     * @param {Array|Object} collection The collection to iterate over.
11034     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
11035     * @returns {Array|Object} Returns `collection`.
11036     * @see _.forEach
11037     * @example
11038     *
11039     * _.forEachRight([1, 2], function(value) {
11040     *   console.log(value);
11041     * });
11042     * // => Logs `2` then `1`.
11043     */
11044    function forEachRight(collection, iteratee) {
11045      var func = isArray(collection) ? arrayEachRight : baseEachRight;
11046      return func(collection, getIteratee(iteratee, 3));
11047    }
11048
11049    /**
vendor: 4,136 bytes, lines 11050-11157
11050     * Creates an object composed of keys generated from the results of running
11051     * each element of `collection` thru `iteratee`. The order of grouped values
11052     * is determined by the order they occur in `collection`. The corresponding
11053     * value of each key is an array of elements responsible for generating the
11054     * key. The iteratee is invoked with one argument: (value).
11055     *
11056     * @static
11057     * @memberOf _
11058     * @since 0.1.0
11059     * @category Collection
11060     * @param {Array|Object} collection The collection to iterate over.
11061     * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
11062     * @returns {Object} Returns the composed aggregate object.
11063     * @example
11064     *
11065     * _.groupBy([6.1, 4.2, 6.3], Math.floor);
11066     * // => { '4': [4.2], '6': [6.1, 6.3] }
11067     *
11068     * // The `_.property` iteratee shorthand.
11069     * _.groupBy(['one', 'two', 'three'], 'length');
11070     * // => { '3': ['one', 'two'], '5': ['three'] }
11071     */
11072    var groupBy = createAggregator(function(result, value, key) {
11073      if (hasOwnProperty.call(result, key)) {
11074        result[key].push(value);
11075      } else {
11076        baseAssignValue(result, key, [value]);
11077      }
11078    });
11079
11080    /**
11081     * Checks if `value` is in `collection`. If `collection` is a string, it's
11082     * checked for a substring of `value`, otherwise
11083     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
11084     * is used for equality comparisons. If `fromIndex` is negative, it's used as
11085     * the offset from the end of `collection`.
11086     *
11087     * @static
11088     * @memberOf _
11089     * @since 0.1.0
11090     * @category Collection
11091     * @param {Array|Object|string} collection The collection to inspect.
11092     * @param {*} value The value to search for.
11093     * @param {number} [fromIndex=0] The index to search from.
11094     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
11095     * @returns {boolean} Returns `true` if `value` is found, else `false`.
11096     * @example
11097     *
11098     * _.includes([1, 2, 3], 1);
11099     * // => true
11100     *
11101     * _.includes([1, 2, 3], 1, 2);
11102     * // => false
11103     *
11104     * _.includes({ 'a': 1, 'b': 2 }, 1);
11105     * // => true
11106     *
11107     * _.includes('abcd', 'bc');
11108     * // => true
11109     */
11110    function includes(collection, value, fromIndex, guard) {
11111      collection = isArrayLike(collection) ? collection : values(collection);
11112      fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;
11113
11114      var length = collection.length;
11115      if (fromIndex < 0) {
11116        fromIndex = nativeMax(length + fromIndex, 0);
11117      }
11118      return isString(collection)
11119        ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
11120        : (!!length && baseIndexOf(collection, value, fromIndex) > -1);
11121    }
11122
11123    /**
11124     * Invokes the method at `path` of each element in `collection`, returning
11125     * an array of the results of each invoked method. Any additional arguments
11126     * are provided to each invoked method. If `path` is a function, it's invoked
11127     * for, and `this` bound to, each element in `collection`.
11128     *
11129     * @static
11130     * @memberOf _
11131     * @since 4.0.0
11132     * @category Collection
11133     * @param {Array|Object} collection The collection to iterate over.
11134     * @param {Array|Function|string} path The path of the method to invoke or
11135     *  the function invoked per iteration.
11136     * @param {...*} [args] The arguments to invoke each method with.
11137     * @returns {Array} Returns the array of results.
11138     * @example
11139     *
11140     * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
11141     * // => [[1, 5, 7], [1, 2, 3]]
11142     *
11143     * _.invokeMap([123, 456], String.prototype.split, '');
11144     * // => [['1', '2', '3'], ['4', '5', '6']]
11145     */
11146    var invokeMap = baseRest(function(collection, path, args) {
11147      var index = -1,
11148          isFunc = typeof path == 'function',
11149          result = isArrayLike(collection) ? Array(collection.length) : [];
11150
11151      baseEach(collection, function(value) {
11152        result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
11153      });
11154      return result;
11155    });
11156
11157    /**
vendor: 68,500 bytes, lines 11158-13272
11158     * Creates an object composed of keys generated from the results of running
11159     * each element of `collection` thru `iteratee`. The corresponding value of
11160     * each key is the last element responsible for generating the key. The
11161     * iteratee is invoked with one argument: (value).
11162     *
11163     * @static
11164     * @memberOf _
11165     * @since 4.0.0
11166     * @category Collection
11167     * @param {Array|Object} collection The collection to iterate over.
11168     * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
11169     * @returns {Object} Returns the composed aggregate object.
11170     * @example
11171     *
11172     * var array = [
11173     *   { 'dir': 'left', 'code': 97 },
11174     *   { 'dir': 'right', 'code': 100 }
11175     * ];
11176     *
11177     * _.keyBy(array, function(o) {
11178     *   return String.fromCharCode(o.code);
11179     * });
11180     * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
11181     *
11182     * _.keyBy(array, 'dir');
11183     * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
11184     */
11185    var keyBy = createAggregator(function(result, value, key) {
11186      baseAssignValue(result, key, value);
11187    });
11188
11189    /**
11190     * Creates an array of values by running each element in `collection` thru
11191     * `iteratee`. The iteratee is invoked with three arguments:
11192     * (value, index|key, collection).
11193     *
11194     * Many lodash methods are guarded to work as iteratees for methods like
11195     * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
11196     *
11197     * The guarded methods are:
11198     * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
11199     * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
11200     * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
11201     * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
11202     *
11203     * @static
11204     * @memberOf _
11205     * @since 0.1.0
11206     * @category Collection
11207     * @param {Array|Object} collection The collection to iterate over.
11208     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
11209     * @returns {Array} Returns the new mapped array.
11210     * @example
11211     *
11212     * function square(n) {
11213     *   return n * n;
11214     * }
11215     *
11216     * _.map([4, 8], square);
11217     * // => [16, 64]
11218     *
11219     * _.map({ 'a': 4, 'b': 8 }, square);
11220     * // => [16, 64] (iteration order is not guaranteed)
11221     *
11222     * var users = [
11223     *   { 'user': 'barney' },
11224     *   { 'user': 'fred' }
11225     * ];
11226     *
11227     * // The `_.property` iteratee shorthand.
11228     * _.map(users, 'user');
11229     * // => ['barney', 'fred']
11230     */
11231    function map(collection, iteratee) {
11232      var func = isArray(collection) ? arrayMap : baseMap;
11233      return func(collection, getIteratee(iteratee, 3));
11234    }
11235
11236    /**
11237     * This method is like `_.sortBy` except that it allows specifying the sort
11238     * orders of the iteratees to sort by. If `orders` is unspecified, all values
11239     * are sorted in ascending order. Otherwise, specify an order of "desc" for
11240     * descending or "asc" for ascending sort order of corresponding values.
11241     *
11242     * @static
11243     * @memberOf _
11244     * @since 4.0.0
11245     * @category Collection
11246     * @param {Array|Object} collection The collection to iterate over.
11247     * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
11248     *  The iteratees to sort by.
11249     * @param {string[]} [orders] The sort orders of `iteratees`.
11250     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
11251     * @returns {Array} Returns the new sorted array.
11252     * @example
11253     *
11254     * var users = [
11255     *   { 'user': 'fred',   'age': 48 },
11256     *   { 'user': 'barney', 'age': 34 },
11257     *   { 'user': 'fred',   'age': 40 },
11258     *   { 'user': 'barney', 'age': 36 }
11259     * ];
11260     *
11261     * // Sort by `user` in ascending order and by `age` in descending order.
11262     * _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
11263     * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
11264     */
11265    function orderBy(collection, iteratees, orders, guard) {
11266      if (collection == null) {
11267        return [];
11268      }
11269      if (!isArray(iteratees)) {
11270        iteratees = iteratees == null ? [] : [iteratees];
11271      }
11272      orders = guard ? undefined : orders;
11273      if (!isArray(orders)) {
11274        orders = orders == null ? [] : [orders];
11275      }
11276      return baseOrderBy(collection, iteratees, orders);
11277    }
11278
11279    /**
11280     * Creates an array of elements split into two groups, the first of which
11281     * contains elements `predicate` returns truthy for, the second of which
11282     * contains elements `predicate` returns falsey for. The predicate is
11283     * invoked with one argument: (value).
11284     *
11285     * @static
11286     * @memberOf _
11287     * @since 3.0.0
11288     * @category Collection
11289     * @param {Array|Object} collection The collection to iterate over.
11290     * @param {Function} [predicate=_.identity] The function invoked per iteration.
11291     * @returns {Array} Returns the array of grouped elements.
11292     * @example
11293     *
11294     * var users = [
11295     *   { 'user': 'barney',  'age': 36, 'active': false },
11296     *   { 'user': 'fred',    'age': 40, 'active': true },
11297     *   { 'user': 'pebbles', 'age': 1,  'active': false }
11298     * ];
11299     *
11300     * _.partition(users, function(o) { return o.active; });
11301     * // => objects for [['fred'], ['barney', 'pebbles']]
11302     *
11303     * // The `_.matches` iteratee shorthand.
11304     * _.partition(users, { 'age': 1, 'active': false });
11305     * // => objects for [['pebbles'], ['barney', 'fred']]
11306     *
11307     * // The `_.matchesProperty` iteratee shorthand.
11308     * _.partition(users, ['active', false]);
11309     * // => objects for [['barney', 'pebbles'], ['fred']]
11310     *
11311     * // The `_.property` iteratee shorthand.
11312     * _.partition(users, 'active');
11313     * // => objects for [['fred'], ['barney', 'pebbles']]
11314     */
11315    var partition = createAggregator(function(result, value, key) {
11316      result[key ? 0 : 1].push(value);
11317    }, function() { return [[], []]; });
11318
11319    /**
11320     * Reduces `collection` to a value which is the accumulated result of running
11321     * each element in `collection` thru `iteratee`, where each successive
11322     * invocation is supplied the return value of the previous. If `accumulator`
11323     * is not given, the first element of `collection` is used as the initial
11324     * value. The iteratee is invoked with four arguments:
11325     * (accumulator, value, index|key, collection).
11326     *
11327     * Many lodash methods are guarded to work as iteratees for methods like
11328     * `_.reduce`, `_.reduceRight`, and `_.transform`.
11329     *
11330     * The guarded methods are:
11331     * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
11332     * and `sortBy`
11333     *
11334     * @static
11335     * @memberOf _
11336     * @since 0.1.0
11337     * @category Collection
11338     * @param {Array|Object} collection The collection to iterate over.
11339     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
11340     * @param {*} [accumulator] The initial value.
11341     * @returns {*} Returns the accumulated value.
11342     * @see _.reduceRight
11343     * @example
11344     *
11345     * _.reduce([1, 2], function(sum, n) {
11346     *   return sum + n;
11347     * }, 0);
11348     * // => 3
11349     *
11350     * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
11351     *   (result[value] || (result[value] = [])).push(key);
11352     *   return result;
11353     * }, {});
11354     * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
11355     */
11356    function reduce(collection, iteratee, accumulator) {
11357      var func = isArray(collection) ? arrayReduce : baseReduce,
11358          initAccum = arguments.length < 3;
11359
11360      return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
11361    }
11362
11363    /**
11364     * This method is like `_.reduce` except that it iterates over elements of
11365     * `collection` from right to left.
11366     *
11367     * @static
11368     * @memberOf _
11369     * @since 0.1.0
11370     * @category Collection
11371     * @param {Array|Object} collection The collection to iterate over.
11372     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
11373     * @param {*} [accumulator] The initial value.
11374     * @returns {*} Returns the accumulated value.
11375     * @see _.reduce
11376     * @example
11377     *
11378     * var array = [[0, 1], [2, 3], [4, 5]];
11379     *
11380     * _.reduceRight(array, function(flattened, other) {
11381     *   return flattened.concat(other);
11382     * }, []);
11383     * // => [4, 5, 2, 3, 0, 1]
11384     */
11385    function reduceRight(collection, iteratee, accumulator) {
11386      var func = isArray(collection) ? arrayReduceRight : baseReduce,
11387          initAccum = arguments.length < 3;
11388
11389      return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);
11390    }
11391
11392    /**
11393     * The opposite of `_.filter`; this method returns the elements of `collection`
11394     * that `predicate` does **not** return truthy for.
11395     *
11396     * @static
11397     * @memberOf _
11398     * @since 0.1.0
11399     * @category Collection
11400     * @param {Array|Object} collection The collection to iterate over.
11401     * @param {Function} [predicate=_.identity] The function invoked per iteration.
11402     * @returns {Array} Returns the new filtered array.
11403     * @see _.filter
11404     * @example
11405     *
11406     * var users = [
11407     *   { 'user': 'barney', 'age': 36, 'active': false },
11408     *   { 'user': 'fred',   'age': 40, 'active': true }
11409     * ];
11410     *
11411     * _.reject(users, function(o) { return !o.active; });
11412     * // => objects for ['fred']
11413     *
11414     * // The `_.matches` iteratee shorthand.
11415     * _.reject(users, { 'age': 40, 'active': true });
11416     * // => objects for ['barney']
11417     *
11418     * // The `_.matchesProperty` iteratee shorthand.
11419     * _.reject(users, ['active', false]);
11420     * // => objects for ['fred']
11421     *
11422     * // The `_.property` iteratee shorthand.
11423     * _.reject(users, 'active');
11424     * // => objects for ['barney']
11425     */
11426    function reject(collection, predicate) {
11427      var func = isArray(collection) ? arrayFilter : baseFilter;
11428      return func(collection, negate(getIteratee(predicate, 3)));
11429    }
11430
11431    /**
11432     * Gets a random element from `collection`.
11433     *
11434     * @static
11435     * @memberOf _
11436     * @since 2.0.0
11437     * @category Collection
11438     * @param {Array|Object} collection The collection to sample.
11439     * @returns {*} Returns the random element.
11440     * @example
11441     *
11442     * _.sample([1, 2, 3, 4]);
11443     * // => 2
11444     */
11445    function sample(collection) {
11446      var func = isArray(collection) ? arraySample : baseSample;
11447      return func(collection);
11448    }
11449
11450    /**
11451     * Gets `n` random elements at unique keys from `collection` up to the
11452     * size of `collection`.
11453     *
11454     * @static
11455     * @memberOf _
11456     * @since 4.0.0
11457     * @category Collection
11458     * @param {Array|Object} collection The collection to sample.
11459     * @param {number} [n=1] The number of elements to sample.
11460     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
11461     * @returns {Array} Returns the random elements.
11462     * @example
11463     *
11464     * _.sampleSize([1, 2, 3], 2);
11465     * // => [3, 1]
11466     *
11467     * _.sampleSize([1, 2, 3], 4);
11468     * // => [2, 3, 1]
11469     */
11470    function sampleSize(collection, n, guard) {
11471      if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) {
11472        n = 1;
11473      } else {
11474        n = toInteger(n);
11475      }
11476      var func = isArray(collection) ? arraySampleSize : baseSampleSize;
11477      return func(collection, n);
11478    }
11479
11480    /**
11481     * Creates an array of shuffled values, using a version of the
11482     * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
11483     *
11484     * @static
11485     * @memberOf _
11486     * @since 0.1.0
11487     * @category Collection
11488     * @param {Array|Object} collection The collection to shuffle.
11489     * @returns {Array} Returns the new shuffled array.
11490     * @example
11491     *
11492     * _.shuffle([1, 2, 3, 4]);
11493     * // => [4, 1, 3, 2]
11494     */
11495    function shuffle(collection) {
11496      var func = isArray(collection) ? arrayShuffle : baseShuffle;
11497      return func(collection);
11498    }
11499
11500    /**
11501     * Gets the size of `collection` by returning its length for array-like
11502     * values or the number of own enumerable string keyed properties for objects.
11503     *
11504     * @static
11505     * @memberOf _
11506     * @since 0.1.0
11507     * @category Collection
11508     * @param {Array|Object|string} collection The collection to inspect.
11509     * @returns {number} Returns the collection size.
11510     * @example
11511     *
11512     * _.size([1, 2, 3]);
11513     * // => 3
11514     *
11515     * _.size({ 'a': 1, 'b': 2 });
11516     * // => 2
11517     *
11518     * _.size('pebbles');
11519     * // => 7
11520     */
11521    function size(collection) {
11522      if (collection == null) {
11523        return 0;
11524      }
11525      if (isArrayLike(collection)) {
11526        return isString(collection) ? stringSize(collection) : collection.length;
11527      }
11528      var tag = getTag(collection);
11529      if (tag == mapTag || tag == setTag) {
11530        return collection.size;
11531      }
11532      return baseKeys(collection).length;
11533    }
11534
11535    /**
11536     * Checks if `predicate` returns truthy for **any** element of `collection`.
11537     * Iteration is stopped once `predicate` returns truthy. The predicate is
11538     * invoked with three arguments: (value, index|key, collection).
11539     *
11540     * @static
11541     * @memberOf _
11542     * @since 0.1.0
11543     * @category Collection
11544     * @param {Array|Object} collection The collection to iterate over.
11545     * @param {Function} [predicate=_.identity] The function invoked per iteration.
11546     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
11547     * @returns {boolean} Returns `true` if any element passes the predicate check,
11548     *  else `false`.
11549     * @example
11550     *
11551     * _.some([null, 0, 'yes', false], Boolean);
11552     * // => true
11553     *
11554     * var users = [
11555     *   { 'user': 'barney', 'active': true },
11556     *   { 'user': 'fred',   'active': false }
11557     * ];
11558     *
11559     * // The `_.matches` iteratee shorthand.
11560     * _.some(users, { 'user': 'barney', 'active': false });
11561     * // => false
11562     *
11563     * // The `_.matchesProperty` iteratee shorthand.
11564     * _.some(users, ['active', false]);
11565     * // => true
11566     *
11567     * // The `_.property` iteratee shorthand.
11568     * _.some(users, 'active');
11569     * // => true
11570     */
11571    function some(collection, predicate, guard) {
11572      var func = isArray(collection) ? arraySome : baseSome;
11573      if (guard && isIterateeCall(collection, predicate, guard)) {
11574        predicate = undefined;
11575      }
11576      return func(collection, getIteratee(predicate, 3));
11577    }
11578
11579    /**
11580     * Creates an array of elements, sorted in ascending order by the results of
11581     * running each element in a collection thru each iteratee. This method
11582     * performs a stable sort, that is, it preserves the original sort order of
11583     * equal elements. The iteratees are invoked with one argument: (value).
11584     *
11585     * @static
11586     * @memberOf _
11587     * @since 0.1.0
11588     * @category Collection
11589     * @param {Array|Object} collection The collection to iterate over.
11590     * @param {...(Function|Function[])} [iteratees=[_.identity]]
11591     *  The iteratees to sort by.
11592     * @returns {Array} Returns the new sorted array.
11593     * @example
11594     *
11595     * var users = [
11596     *   { 'user': 'fred',   'age': 48 },
11597     *   { 'user': 'barney', 'age': 36 },
11598     *   { 'user': 'fred',   'age': 30 },
11599     *   { 'user': 'barney', 'age': 34 }
11600     * ];
11601     *
11602     * _.sortBy(users, [function(o) { return o.user; }]);
11603     * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 30]]
11604     *
11605     * _.sortBy(users, ['user', 'age']);
11606     * // => objects for [['barney', 34], ['barney', 36], ['fred', 30], ['fred', 48]]
11607     */
11608    var sortBy = baseRest(function(collection, iteratees) {
11609      if (collection == null) {
11610        return [];
11611      }
11612      var length = iteratees.length;
11613      if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
11614        iteratees = [];
11615      } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
11616        iteratees = [iteratees[0]];
11617      }
11618      return baseOrderBy(collection, baseFlatten(iteratees, 1), []);
11619    });
11620
11621    /*------------------------------------------------------------------------*/
11622
11623    /**
11624     * Gets the timestamp of the number of milliseconds that have elapsed since
11625     * the Unix epoch (1 January 1970 00:00:00 UTC).
11626     *
11627     * @static
11628     * @memberOf _
11629     * @since 2.4.0
11630     * @category Date
11631     * @returns {number} Returns the timestamp.
11632     * @example
11633     *
11634     * _.defer(function(stamp) {
11635     *   console.log(_.now() - stamp);
11636     * }, _.now());
11637     * // => Logs the number of milliseconds it took for the deferred invocation.
11638     */
11639    var now = ctxNow || function() {
11640      return root.Date.now();
11641    };
11642
11643    /*------------------------------------------------------------------------*/
11644
11645    /**
11646     * The opposite of `_.before`; this method creates a function that invokes
11647     * `func` once it's called `n` or more times.
11648     *
11649     * @static
11650     * @memberOf _
11651     * @since 0.1.0
11652     * @category Function
11653     * @param {number} n The number of calls before `func` is invoked.
11654     * @param {Function} func The function to restrict.
11655     * @returns {Function} Returns the new restricted function.
11656     * @example
11657     *
11658     * var saves = ['profile', 'settings'];
11659     *
11660     * var done = _.after(saves.length, function() {
11661     *   console.log('done saving!');
11662     * });
11663     *
11664     * _.forEach(saves, function(type) {
11665     *   asyncSave({ 'type': type, 'complete': done });
11666     * });
11667     * // => Logs 'done saving!' after the two async saves have completed.
11668     */
11669    function after(n, func) {
11670      if (typeof func != 'function') {
11671        throw new TypeError(FUNC_ERROR_TEXT);
11672      }
11673      n = toInteger(n);
11674      return function() {
11675        if (--n < 1) {
11676          return func.apply(this, arguments);
11677        }
11678      };
11679    }
11680
11681    /**
11682     * Creates a function that invokes `func`, with up to `n` arguments,
11683     * ignoring any additional arguments.
11684     *
11685     * @static
11686     * @memberOf _
11687     * @since 3.0.0
11688     * @category Function
11689     * @param {Function} func The function to cap arguments for.
11690     * @param {number} [n=func.length] The arity cap.
11691     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
11692     * @returns {Function} Returns the new capped function.
11693     * @example
11694     *
11695     * _.map(['6', '8', '10'], _.ary(parseInt, 1));
11696     * // => [6, 8, 10]
11697     */
11698    function ary(func, n, guard) {
11699      n = guard ? undefined : n;
11700      n = (func && n == null) ? func.length : n;
11701      return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n);
11702    }
11703
11704    /**
11705     * Creates a function that invokes `func`, with the `this` binding and arguments
11706     * of the created function, while it's called less than `n` times. Subsequent
11707     * calls to the created function return the result of the last `func` invocation.
11708     *
11709     * @static
11710     * @memberOf _
11711     * @since 3.0.0
11712     * @category Function
11713     * @param {number} n The number of calls at which `func` is no longer invoked.
11714     * @param {Function} func The function to restrict.
11715     * @returns {Function} Returns the new restricted function.
11716     * @example
11717     *
11718     * jQuery(element).on('click', _.before(5, addContactToList));
11719     * // => Allows adding up to 4 contacts to the list.
11720     */
11721    function before(n, func) {
11722      var result;
11723      if (typeof func != 'function') {
11724        throw new TypeError(FUNC_ERROR_TEXT);
11725      }
11726      n = toInteger(n);
11727      return function() {
11728        if (--n > 0) {
11729          result = func.apply(this, arguments);
11730        }
11731        if (n <= 1) {
11732          func = undefined;
11733        }
11734        return result;
11735      };
11736    }
11737
11738    /**
11739     * Creates a function that invokes `func` with the `this` binding of `thisArg`
11740     * and `partials` prepended to the arguments it receives.
11741     *
11742     * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
11743     * may be used as a placeholder for partially applied arguments.
11744     *
11745     * **Note:** Unlike native `Function#bind`, this method doesn't set the "length"
11746     * property of bound functions.
11747     *
11748     * @static
11749     * @memberOf _
11750     * @since 0.1.0
11751     * @category Function
11752     * @param {Function} func The function to bind.
11753     * @param {*} thisArg The `this` binding of `func`.
11754     * @param {...*} [partials] The arguments to be partially applied.
11755     * @returns {Function} Returns the new bound function.
11756     * @example
11757     *
11758     * function greet(greeting, punctuation) {
11759     *   return greeting + ' ' + this.user + punctuation;
11760     * }
11761     *
11762     * var object = { 'user': 'fred' };
11763     *
11764     * var bound = _.bind(greet, object, 'hi');
11765     * bound('!');
11766     * // => 'hi fred!'
11767     *
11768     * // Bound with placeholders.
11769     * var bound = _.bind(greet, object, _, '!');
11770     * bound('hi');
11771     * // => 'hi fred!'
11772     */
11773    var bind = baseRest(function(func, thisArg, partials) {
11774      var bitmask = WRAP_BIND_FLAG;
11775      if (partials.length) {
11776        var holders = replaceHolders(partials, getHolder(bind));
11777        bitmask |= WRAP_PARTIAL_FLAG;
11778      }
11779      return createWrap(func, bitmask, thisArg, partials, holders);
11780    });
11781
11782    /**
11783     * Creates a function that invokes the method at `object[key]` with `partials`
11784     * prepended to the arguments it receives.
11785     *
11786     * This method differs from `_.bind` by allowing bound functions to reference
11787     * methods that may be redefined or don't yet exist. See
11788     * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
11789     * for more details.
11790     *
11791     * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
11792     * builds, may be used as a placeholder for partially applied arguments.
11793     *
11794     * @static
11795     * @memberOf _
11796     * @since 0.10.0
11797     * @category Function
11798     * @param {Object} object The object to invoke the method on.
11799     * @param {string} key The key of the method.
11800     * @param {...*} [partials] The arguments to be partially applied.
11801     * @returns {Function} Returns the new bound function.
11802     * @example
11803     *
11804     * var object = {
11805     *   'user': 'fred',
11806     *   'greet': function(greeting, punctuation) {
11807     *     return greeting + ' ' + this.user + punctuation;
11808     *   }
11809     * };
11810     *
11811     * var bound = _.bindKey(object, 'greet', 'hi');
11812     * bound('!');
11813     * // => 'hi fred!'
11814     *
11815     * object.greet = function(greeting, punctuation) {
11816     *   return greeting + 'ya ' + this.user + punctuation;
11817     * };
11818     *
11819     * bound('!');
11820     * // => 'hiya fred!'
11821     *
11822     * // Bound with placeholders.
11823     * var bound = _.bindKey(object, 'greet', _, '!');
11824     * bound('hi');
11825     * // => 'hiya fred!'
11826     */
11827    var bindKey = baseRest(function(object, key, partials) {
11828      var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG;
11829      if (partials.length) {
11830        var holders = replaceHolders(partials, getHolder(bindKey));
11831        bitmask |= WRAP_PARTIAL_FLAG;
11832      }
11833      return createWrap(key, bitmask, object, partials, holders);
11834    });
11835
11836    /**
11837     * Creates a function that accepts arguments of `func` and either invokes
11838     * `func` returning its result, if at least `arity` number of arguments have
11839     * been provided, or returns a function that accepts the remaining `func`
11840     * arguments, and so on. The arity of `func` may be specified if `func.length`
11841     * is not sufficient.
11842     *
11843     * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
11844     * may be used as a placeholder for provided arguments.
11845     *
11846     * **Note:** This method doesn't set the "length" property of curried functions.
11847     *
11848     * @static
11849     * @memberOf _
11850     * @since 2.0.0
11851     * @category Function
11852     * @param {Function} func The function to curry.
11853     * @param {number} [arity=func.length] The arity of `func`.
11854     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
11855     * @returns {Function} Returns the new curried function.
11856     * @example
11857     *
11858     * var abc = function(a, b, c) {
11859     *   return [a, b, c];
11860     * };
11861     *
11862     * var curried = _.curry(abc);
11863     *
11864     * curried(1)(2)(3);
11865     * // => [1, 2, 3]
11866     *
11867     * curried(1, 2)(3);
11868     * // => [1, 2, 3]
11869     *
11870     * curried(1, 2, 3);
11871     * // => [1, 2, 3]
11872     *
11873     * // Curried with placeholders.
11874     * curried(1)(_, 3)(2);
11875     * // => [1, 2, 3]
11876     */
11877    function curry(func, arity, guard) {
11878      arity = guard ? undefined : arity;
11879      var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
11880      result.placeholder = curry.placeholder;
11881      return result;
11882    }
11883
11884    /**
11885     * This method is like `_.curry` except that arguments are applied to `func`
11886     * in the manner of `_.partialRight` instead of `_.partial`.
11887     *
11888     * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
11889     * builds, may be used as a placeholder for provided arguments.
11890     *
11891     * **Note:** This method doesn't set the "length" property of curried functions.
11892     *
11893     * @static
11894     * @memberOf _
11895     * @since 3.0.0
11896     * @category Function
11897     * @param {Function} func The function to curry.
11898     * @param {number} [arity=func.length] The arity of `func`.
11899     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
11900     * @returns {Function} Returns the new curried function.
11901     * @example
11902     *
11903     * var abc = function(a, b, c) {
11904     *   return [a, b, c];
11905     * };
11906     *
11907     * var curried = _.curryRight(abc);
11908     *
11909     * curried(3)(2)(1);
11910     * // => [1, 2, 3]
11911     *
11912     * curried(2, 3)(1);
11913     * // => [1, 2, 3]
11914     *
11915     * curried(1, 2, 3);
11916     * // => [1, 2, 3]
11917     *
11918     * // Curried with placeholders.
11919     * curried(3)(1, _)(2);
11920     * // => [1, 2, 3]
11921     */
11922    function curryRight(func, arity, guard) {
11923      arity = guard ? undefined : arity;
11924      var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
11925      result.placeholder = curryRight.placeholder;
11926      return result;
11927    }
11928
11929    /**
11930     * Creates a debounced function that delays invoking `func` until after `wait`
11931     * milliseconds have elapsed since the last time the debounced function was
11932     * invoked. The debounced function comes with a `cancel` method to cancel
11933     * delayed `func` invocations and a `flush` method to immediately invoke them.
11934     * Provide `options` to indicate whether `func` should be invoked on the
11935     * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
11936     * with the last arguments provided to the debounced function. Subsequent
11937     * calls to the debounced function return the result of the last `func`
11938     * invocation.
11939     *
11940     * **Note:** If `leading` and `trailing` options are `true`, `func` is
11941     * invoked on the trailing edge of the timeout only if the debounced function
11942     * is invoked more than once during the `wait` timeout.
11943     *
11944     * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
11945     * until to the next tick, similar to `setTimeout` with a timeout of `0`.
11946     *
11947     * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
11948     * for details over the differences between `_.debounce` and `_.throttle`.
11949     *
11950     * @static
11951     * @memberOf _
11952     * @since 0.1.0
11953     * @category Function
11954     * @param {Function} func The function to debounce.
11955     * @param {number} [wait=0] The number of milliseconds to delay.
11956     * @param {Object} [options={}] The options object.
11957     * @param {boolean} [options.leading=false]
11958     *  Specify invoking on the leading edge of the timeout.
11959     * @param {number} [options.maxWait]
11960     *  The maximum time `func` is allowed to be delayed before it's invoked.
11961     * @param {boolean} [options.trailing=true]
11962     *  Specify invoking on the trailing edge of the timeout.
11963     * @returns {Function} Returns the new debounced function.
11964     * @example
11965     *
11966     * // Avoid costly calculations while the window size is in flux.
11967     * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
11968     *
11969     * // Invoke `sendMail` when clicked, debouncing subsequent calls.
11970     * jQuery(element).on('click', _.debounce(sendMail, 300, {
11971     *   'leading': true,
11972     *   'trailing': false
11973     * }));
11974     *
11975     * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
11976     * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
11977     * var source = new EventSource('/stream');
11978     * jQuery(source).on('message', debounced);
11979     *
11980     * // Cancel the trailing debounced invocation.
11981     * jQuery(window).on('popstate', debounced.cancel);
11982     */
11983    function debounce(func, wait, options) {
11984      var lastArgs,
11985          lastThis,
11986          maxWait,
11987          result,
11988          timerId,
11989          lastCallTime,
11990          lastInvokeTime = 0,
11991          leading = false,
11992          maxing = false,
11993          trailing = true;
11994
11995      if (typeof func != 'function') {
11996        throw new TypeError(FUNC_ERROR_TEXT);
11997      }
11998      wait = toNumber(wait) || 0;
11999      if (isObject(options)) {
12000        leading = !!options.leading;
12001        maxing = 'maxWait' in options;
12002        maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
12003        trailing = 'trailing' in options ? !!options.trailing : trailing;
12004      }
12005
12006      function invokeFunc(time) {
12007        var args = lastArgs,
12008            thisArg = lastThis;
12009
12010        lastArgs = lastThis = undefined;
12011        lastInvokeTime = time;
12012        result = func.apply(thisArg, args);
12013        return result;
12014      }
12015
12016      function leadingEdge(time) {
12017        // Reset any `maxWait` timer.
12018        lastInvokeTime = time;
12019        // Start the timer for the trailing edge.
12020        timerId = setTimeout(timerExpired, wait);
12021        // Invoke the leading edge.
12022        return leading ? invokeFunc(time) : result;
12023      }
12024
12025      function remainingWait(time) {
12026        var timeSinceLastCall = time - lastCallTime,
12027            timeSinceLastInvoke = time - lastInvokeTime,
12028            timeWaiting = wait - timeSinceLastCall;
12029
12030        return maxing
12031          ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke)
12032          : timeWaiting;
12033      }
12034
12035      function shouldInvoke(time) {
12036        var timeSinceLastCall = time - lastCallTime,
12037            timeSinceLastInvoke = time - lastInvokeTime;
12038
12039        // Either this is the first call, activity has stopped and we're at the
12040        // trailing edge, the system time has gone backwards and we're treating
12041        // it as the trailing edge, or we've hit the `maxWait` limit.
12042        return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
12043          (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
12044      }
12045
12046      function timerExpired() {
12047        var time = now();
12048        if (shouldInvoke(time)) {
12049          return trailingEdge(time);
12050        }
12051        // Restart the timer.
12052        timerId = setTimeout(timerExpired, remainingWait(time));
12053      }
12054
12055      function trailingEdge(time) {
12056        timerId = undefined;
12057
12058        // Only invoke if we have `lastArgs` which means `func` has been
12059        // debounced at least once.
12060        if (trailing && lastArgs) {
12061          return invokeFunc(time);
12062        }
12063        lastArgs = lastThis = undefined;
12064        return result;
12065      }
12066
12067      function cancel() {
12068        if (timerId !== undefined) {
12069          clearTimeout(timerId);
12070        }
12071        lastInvokeTime = 0;
12072        lastArgs = lastCallTime = lastThis = timerId = undefined;
12073      }
12074
12075      function flush() {
12076        return timerId === undefined ? result : trailingEdge(now());
12077      }
12078
12079      function debounced() {
12080        var time = now(),
12081            isInvoking = shouldInvoke(time);
12082
12083        lastArgs = arguments;
12084        lastThis = this;
12085        lastCallTime = time;
12086
12087        if (isInvoking) {
12088          if (timerId === undefined) {
12089            return leadingEdge(lastCallTime);
12090          }
12091          if (maxing) {
12092            // Handle invocations in a tight loop.
12093            clearTimeout(timerId);
12094            timerId = setTimeout(timerExpired, wait);
12095            return invokeFunc(lastCallTime);
12096          }
12097        }
12098        if (timerId === undefined) {
12099          timerId = setTimeout(timerExpired, wait);
12100        }
12101        return result;
12102      }
12103      debounced.cancel = cancel;
12104      debounced.flush = flush;
12105      return debounced;
12106    }
12107
12108    /**
12109     * Defers invoking the `func` until the current call stack has cleared. Any
12110     * additional arguments are provided to `func` when it's invoked.
12111     *
12112     * @static
12113     * @memberOf _
12114     * @since 0.1.0
12115     * @category Function
12116     * @param {Function} func The function to defer.
12117     * @param {...*} [args] The arguments to invoke `func` with.
12118     * @returns {number} Returns the timer id.
12119     * @example
12120     *
12121     * _.defer(function(text) {
12122     *   console.log(text);
12123     * }, 'deferred');
12124     * // => Logs 'deferred' after one millisecond.
12125     */
12126    var defer = baseRest(function(func, args) {
12127      return baseDelay(func, 1, args);
12128    });
12129
12130    /**
12131     * Invokes `func` after `wait` milliseconds. Any additional arguments are
12132     * provided to `func` when it's invoked.
12133     *
12134     * @static
12135     * @memberOf _
12136     * @since 0.1.0
12137     * @category Function
12138     * @param {Function} func The function to delay.
12139     * @param {number} wait The number of milliseconds to delay invocation.
12140     * @param {...*} [args] The arguments to invoke `func` with.
12141     * @returns {number} Returns the timer id.
12142     * @example
12143     *
12144     * _.delay(function(text) {
12145     *   console.log(text);
12146     * }, 1000, 'later');
12147     * // => Logs 'later' after one second.
12148     */
12149    var delay = baseRest(function(func, wait, args) {
12150      return baseDelay(func, toNumber(wait) || 0, args);
12151    });
12152
12153    /**
12154     * Creates a function that invokes `func` with arguments reversed.
12155     *
12156     * @static
12157     * @memberOf _
12158     * @since 4.0.0
12159     * @category Function
12160     * @param {Function} func The function to flip arguments for.
12161     * @returns {Function} Returns the new flipped function.
12162     * @example
12163     *
12164     * var flipped = _.flip(function() {
12165     *   return _.toArray(arguments);
12166     * });
12167     *
12168     * flipped('a', 'b', 'c', 'd');
12169     * // => ['d', 'c', 'b', 'a']
12170     */
12171    function flip(func) {
12172      return createWrap(func, WRAP_FLIP_FLAG);
12173    }
12174
12175    /**
12176     * Creates a function that memoizes the result of `func`. If `resolver` is
12177     * provided, it determines the cache key for storing the result based on the
12178     * arguments provided to the memoized function. By default, the first argument
12179     * provided to the memoized function is used as the map cache key. The `func`
12180     * is invoked with the `this` binding of the memoized function.
12181     *
12182     * **Note:** The cache is exposed as the `cache` property on the memoized
12183     * function. Its creation may be customized by replacing the `_.memoize.Cache`
12184     * constructor with one whose instances implement the
12185     * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
12186     * method interface of `clear`, `delete`, `get`, `has`, and `set`.
12187     *
12188     * @static
12189     * @memberOf _
12190     * @since 0.1.0
12191     * @category Function
12192     * @param {Function} func The function to have its output memoized.
12193     * @param {Function} [resolver] The function to resolve the cache key.
12194     * @returns {Function} Returns the new memoized function.
12195     * @example
12196     *
12197     * var object = { 'a': 1, 'b': 2 };
12198     * var other = { 'c': 3, 'd': 4 };
12199     *
12200     * var values = _.memoize(_.values);
12201     * values(object);
12202     * // => [1, 2]
12203     *
12204     * values(other);
12205     * // => [3, 4]
12206     *
12207     * object.a = 2;
12208     * values(object);
12209     * // => [1, 2]
12210     *
12211     * // Modify the result cache.
12212     * values.cache.set(object, ['a', 'b']);
12213     * values(object);
12214     * // => ['a', 'b']
12215     *
12216     * // Replace `_.memoize.Cache`.
12217     * _.memoize.Cache = WeakMap;
12218     */
12219    function memoize(func, resolver) {
12220      if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
12221        throw new TypeError(FUNC_ERROR_TEXT);
12222      }
12223      var memoized = function() {
12224        var args = arguments,
12225            key = resolver ? resolver.apply(this, args) : args[0],
12226            cache = memoized.cache;
12227
12228        if (cache.has(key)) {
12229          return cache.get(key);
12230        }
12231        var result = func.apply(this, args);
12232        memoized.cache = cache.set(key, result) || cache;
12233        return result;
12234      };
12235      memoized.cache = new (memoize.Cache || MapCache);
12236      return memoized;
12237    }
12238
12239    // Expose `MapCache`.
12240    memoize.Cache = MapCache;
12241
12242    /**
12243     * Creates a function that negates the result of the predicate `func`. The
12244     * `func` predicate is invoked with the `this` binding and arguments of the
12245     * created function.
12246     *
12247     * @static
12248     * @memberOf _
12249     * @since 3.0.0
12250     * @category Function
12251     * @param {Function} predicate The predicate to negate.
12252     * @returns {Function} Returns the new negated function.
12253     * @example
12254     *
12255     * function isEven(n) {
12256     *   return n % 2 == 0;
12257     * }
12258     *
12259     * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
12260     * // => [1, 3, 5]
12261     */
12262    function negate(predicate) {
12263      if (typeof predicate != 'function') {
12264        throw new TypeError(FUNC_ERROR_TEXT);
12265      }
12266      return function() {
12267        var args = arguments;
12268        switch (args.length) {
12269          case 0: return !predicate.call(this);
12270          case 1: return !predicate.call(this, args[0]);
12271          case 2: return !predicate.call(this, args[0], args[1]);
12272          case 3: return !predicate.call(this, args[0], args[1], args[2]);
12273        }
12274        return !predicate.apply(this, args);
12275      };
12276    }
12277
12278    /**
12279     * Creates a function that is restricted to invoking `func` once. Repeat calls
12280     * to the function return the value of the first invocation. The `func` is
12281     * invoked with the `this` binding and arguments of the created function.
12282     *
12283     * @static
12284     * @memberOf _
12285     * @since 0.1.0
12286     * @category Function
12287     * @param {Function} func The function to restrict.
12288     * @returns {Function} Returns the new restricted function.
12289     * @example
12290     *
12291     * var initialize = _.once(createApplication);
12292     * initialize();
12293     * initialize();
12294     * // => `createApplication` is invoked once
12295     */
12296    function once(func) {
12297      return before(2, func);
12298    }
12299
12300    /**
12301     * Creates a function that invokes `func` with its arguments transformed.
12302     *
12303     * @static
12304     * @since 4.0.0
12305     * @memberOf _
12306     * @category Function
12307     * @param {Function} func The function to wrap.
12308     * @param {...(Function|Function[])} [transforms=[_.identity]]
12309     *  The argument transforms.
12310     * @returns {Function} Returns the new function.
12311     * @example
12312     *
12313     * function doubled(n) {
12314     *   return n * 2;
12315     * }
12316     *
12317     * function square(n) {
12318     *   return n * n;
12319     * }
12320     *
12321     * var func = _.overArgs(function(x, y) {
12322     *   return [x, y];
12323     * }, [square, doubled]);
12324     *
12325     * func(9, 3);
12326     * // => [81, 6]
12327     *
12328     * func(10, 5);
12329     * // => [100, 10]
12330     */
12331    var overArgs = castRest(function(func, transforms) {
12332      transforms = (transforms.length == 1 && isArray(transforms[0]))
12333        ? arrayMap(transforms[0], baseUnary(getIteratee()))
12334        : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee()));
12335
12336      var funcsLength = transforms.length;
12337      return baseRest(function(args) {
12338        var index = -1,
12339            length = nativeMin(args.length, funcsLength);
12340
12341        while (++index < length) {
12342          args[index] = transforms[index].call(this, args[index]);
12343        }
12344        return apply(func, this, args);
12345      });
12346    });
12347
12348    /**
12349     * Creates a function that invokes `func` with `partials` prepended to the
12350     * arguments it receives. This method is like `_.bind` except it does **not**
12351     * alter the `this` binding.
12352     *
12353     * The `_.partial.placeholder` value, which defaults to `_` in monolithic
12354     * builds, may be used as a placeholder for partially applied arguments.
12355     *
12356     * **Note:** This method doesn't set the "length" property of partially
12357     * applied functions.
12358     *
12359     * @static
12360     * @memberOf _
12361     * @since 0.2.0
12362     * @category Function
12363     * @param {Function} func The function to partially apply arguments to.
12364     * @param {...*} [partials] The arguments to be partially applied.
12365     * @returns {Function} Returns the new partially applied function.
12366     * @example
12367     *
12368     * function greet(greeting, name) {
12369     *   return greeting + ' ' + name;
12370     * }
12371     *
12372     * var sayHelloTo = _.partial(greet, 'hello');
12373     * sayHelloTo('fred');
12374     * // => 'hello fred'
12375     *
12376     * // Partially applied with placeholders.
12377     * var greetFred = _.partial(greet, _, 'fred');
12378     * greetFred('hi');
12379     * // => 'hi fred'
12380     */
12381    var partial = baseRest(function(func, partials) {
12382      var holders = replaceHolders(partials, getHolder(partial));
12383      return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders);
12384    });
12385
12386    /**
12387     * This method is like `_.partial` except that partially applied arguments
12388     * are appended to the arguments it receives.
12389     *
12390     * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
12391     * builds, may be used as a placeholder for partially applied arguments.
12392     *
12393     * **Note:** This method doesn't set the "length" property of partially
12394     * applied functions.
12395     *
12396     * @static
12397     * @memberOf _
12398     * @since 1.0.0
12399     * @category Function
12400     * @param {Function} func The function to partially apply arguments to.
12401     * @param {...*} [partials] The arguments to be partially applied.
12402     * @returns {Function} Returns the new partially applied function.
12403     * @example
12404     *
12405     * function greet(greeting, name) {
12406     *   return greeting + ' ' + name;
12407     * }
12408     *
12409     * var greetFred = _.partialRight(greet, 'fred');
12410     * greetFred('hi');
12411     * // => 'hi fred'
12412     *
12413     * // Partially applied with placeholders.
12414     * var sayHelloTo = _.partialRight(greet, 'hello', _);
12415     * sayHelloTo('fred');
12416     * // => 'hello fred'
12417     */
12418    var partialRight = baseRest(function(func, partials) {
12419      var holders = replaceHolders(partials, getHolder(partialRight));
12420      return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders);
12421    });
12422
12423    /**
12424     * Creates a function that invokes `func` with arguments arranged according
12425     * to the specified `indexes` where the argument value at the first index is
12426     * provided as the first argument, the argument value at the second index is
12427     * provided as the second argument, and so on.
12428     *
12429     * @static
12430     * @memberOf _
12431     * @since 3.0.0
12432     * @category Function
12433     * @param {Function} func The function to rearrange arguments for.
12434     * @param {...(number|number[])} indexes The arranged argument indexes.
12435     * @returns {Function} Returns the new function.
12436     * @example
12437     *
12438     * var rearged = _.rearg(function(a, b, c) {
12439     *   return [a, b, c];
12440     * }, [2, 0, 1]);
12441     *
12442     * rearged('b', 'c', 'a')
12443     * // => ['a', 'b', 'c']
12444     */
12445    var rearg = flatRest(function(func, indexes) {
12446      return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes);
12447    });
12448
12449    /**
12450     * Creates a function that invokes `func` with the `this` binding of the
12451     * created function and arguments from `start` and beyond provided as
12452     * an array.
12453     *
12454     * **Note:** This method is based on the
12455     * [rest parameter](https://mdn.io/rest_parameters).
12456     *
12457     * @static
12458     * @memberOf _
12459     * @since 4.0.0
12460     * @category Function
12461     * @param {Function} func The function to apply a rest parameter to.
12462     * @param {number} [start=func.length-1] The start position of the rest parameter.
12463     * @returns {Function} Returns the new function.
12464     * @example
12465     *
12466     * var say = _.rest(function(what, names) {
12467     *   return what + ' ' + _.initial(names).join(', ') +
12468     *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
12469     * });
12470     *
12471     * say('hello', 'fred', 'barney', 'pebbles');
12472     * // => 'hello fred, barney, & pebbles'
12473     */
12474    function rest(func, start) {
12475      if (typeof func != 'function') {
12476        throw new TypeError(FUNC_ERROR_TEXT);
12477      }
12478      start = start === undefined ? start : toInteger(start);
12479      return baseRest(func, start);
12480    }
12481
12482    /**
12483     * Creates a function that invokes `func` with the `this` binding of the
12484     * create function and an array of arguments much like
12485     * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
12486     *
12487     * **Note:** This method is based on the
12488     * [spread operator](https://mdn.io/spread_operator).
12489     *
12490     * @static
12491     * @memberOf _
12492     * @since 3.2.0
12493     * @category Function
12494     * @param {Function} func The function to spread arguments over.
12495     * @param {number} [start=0] The start position of the spread.
12496     * @returns {Function} Returns the new function.
12497     * @example
12498     *
12499     * var say = _.spread(function(who, what) {
12500     *   return who + ' says ' + what;
12501     * });
12502     *
12503     * say(['fred', 'hello']);
12504     * // => 'fred says hello'
12505     *
12506     * var numbers = Promise.all([
12507     *   Promise.resolve(40),
12508     *   Promise.resolve(36)
12509     * ]);
12510     *
12511     * numbers.then(_.spread(function(x, y) {
12512     *   return x + y;
12513     * }));
12514     * // => a Promise of 76
12515     */
12516    function spread(func, start) {
12517      if (typeof func != 'function') {
12518        throw new TypeError(FUNC_ERROR_TEXT);
12519      }
12520      start = start == null ? 0 : nativeMax(toInteger(start), 0);
12521      return baseRest(function(args) {
12522        var array = args[start],
12523            otherArgs = castSlice(args, 0, start);
12524
12525        if (array) {
12526          arrayPush(otherArgs, array);
12527        }
12528        return apply(func, this, otherArgs);
12529      });
12530    }
12531
12532    /**
12533     * Creates a throttled function that only invokes `func` at most once per
12534     * every `wait` milliseconds. The throttled function comes with a `cancel`
12535     * method to cancel delayed `func` invocations and a `flush` method to
12536     * immediately invoke them. Provide `options` to indicate whether `func`
12537     * should be invoked on the leading and/or trailing edge of the `wait`
12538     * timeout. The `func` is invoked with the last arguments provided to the
12539     * throttled function. Subsequent calls to the throttled function return the
12540     * result of the last `func` invocation.
12541     *
12542     * **Note:** If `leading` and `trailing` options are `true`, `func` is
12543     * invoked on the trailing edge of the timeout only if the throttled function
12544     * is invoked more than once during the `wait` timeout.
12545     *
12546     * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
12547     * until to the next tick, similar to `setTimeout` with a timeout of `0`.
12548     *
12549     * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
12550     * for details over the differences between `_.throttle` and `_.debounce`.
12551     *
12552     * @static
12553     * @memberOf _
12554     * @since 0.1.0
12555     * @category Function
12556     * @param {Function} func The function to throttle.
12557     * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
12558     * @param {Object} [options={}] The options object.
12559     * @param {boolean} [options.leading=true]
12560     *  Specify invoking on the leading edge of the timeout.
12561     * @param {boolean} [options.trailing=true]
12562     *  Specify invoking on the trailing edge of the timeout.
12563     * @returns {Function} Returns the new throttled function.
12564     * @example
12565     *
12566     * // Avoid excessively updating the position while scrolling.
12567     * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
12568     *
12569     * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
12570     * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
12571     * jQuery(element).on('click', throttled);
12572     *
12573     * // Cancel the trailing throttled invocation.
12574     * jQuery(window).on('popstate', throttled.cancel);
12575     */
12576    function throttle(func, wait, options) {
12577      var leading = true,
12578          trailing = true;
12579
12580      if (typeof func != 'function') {
12581        throw new TypeError(FUNC_ERROR_TEXT);
12582      }
12583      if (isObject(options)) {
12584        leading = 'leading' in options ? !!options.leading : leading;
12585        trailing = 'trailing' in options ? !!options.trailing : trailing;
12586      }
12587      return debounce(func, wait, {
12588        'leading': leading,
12589        'maxWait': wait,
12590        'trailing': trailing
12591      });
12592    }
12593
12594    /**
12595     * Creates a function that accepts up to one argument, ignoring any
12596     * additional arguments.
12597     *
12598     * @static
12599     * @memberOf _
12600     * @since 4.0.0
12601     * @category Function
12602     * @param {Function} func The function to cap arguments for.
12603     * @returns {Function} Returns the new capped function.
12604     * @example
12605     *
12606     * _.map(['6', '8', '10'], _.unary(parseInt));
12607     * // => [6, 8, 10]
12608     */
12609    function unary(func) {
12610      return ary(func, 1);
12611    }
12612
12613    /**
12614     * Creates a function that provides `value` to `wrapper` as its first
12615     * argument. Any additional arguments provided to the function are appended
12616     * to those provided to the `wrapper`. The wrapper is invoked with the `this`
12617     * binding of the created function.
12618     *
12619     * @static
12620     * @memberOf _
12621     * @since 0.1.0
12622     * @category Function
12623     * @param {*} value The value to wrap.
12624     * @param {Function} [wrapper=identity] The wrapper function.
12625     * @returns {Function} Returns the new function.
12626     * @example
12627     *
12628     * var p = _.wrap(_.escape, function(func, text) {
12629     *   return '<p>' + func(text) + '</p>';
12630     * });
12631     *
12632     * p('fred, barney, & pebbles');
12633     * // => '<p>fred, barney, &amp; pebbles</p>'
12634     */
12635    function wrap(value, wrapper) {
12636      return partial(castFunction(wrapper), value);
12637    }
12638
12639    /*------------------------------------------------------------------------*/
12640
12641    /**
12642     * Casts `value` as an array if it's not one.
12643     *
12644     * @static
12645     * @memberOf _
12646     * @since 4.4.0
12647     * @category Lang
12648     * @param {*} value The value to inspect.
12649     * @returns {Array} Returns the cast array.
12650     * @example
12651     *
12652     * _.castArray(1);
12653     * // => [1]
12654     *
12655     * _.castArray({ 'a': 1 });
12656     * // => [{ 'a': 1 }]
12657     *
12658     * _.castArray('abc');
12659     * // => ['abc']
12660     *
12661     * _.castArray(null);
12662     * // => [null]
12663     *
12664     * _.castArray(undefined);
12665     * // => [undefined]
12666     *
12667     * _.castArray();
12668     * // => []
12669     *
12670     * var array = [1, 2, 3];
12671     * console.log(_.castArray(array) === array);
12672     * // => true
12673     */
12674    function castArray() {
12675      if (!arguments.length) {
12676        return [];
12677      }
12678      var value = arguments[0];
12679      return isArray(value) ? value : [value];
12680    }
12681
12682    /**
12683     * Creates a shallow clone of `value`.
12684     *
12685     * **Note:** This method is loosely based on the
12686     * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
12687     * and supports cloning arrays, array buffers, booleans, date objects, maps,
12688     * numbers, `Object` objects, regexes, sets, strings, symbols, and typed
12689     * arrays. The own enumerable properties of `arguments` objects are cloned
12690     * as plain objects. An empty object is returned for uncloneable values such
12691     * as error objects, functions, DOM nodes, and WeakMaps.
12692     *
12693     * @static
12694     * @memberOf _
12695     * @since 0.1.0
12696     * @category Lang
12697     * @param {*} value The value to clone.
12698     * @returns {*} Returns the cloned value.
12699     * @see _.cloneDeep
12700     * @example
12701     *
12702     * var objects = [{ 'a': 1 }, { 'b': 2 }];
12703     *
12704     * var shallow = _.clone(objects);
12705     * console.log(shallow[0] === objects[0]);
12706     * // => true
12707     */
12708    function clone(value) {
12709      return baseClone(value, CLONE_SYMBOLS_FLAG);
12710    }
12711
12712    /**
12713     * This method is like `_.clone` except that it accepts `customizer` which
12714     * is invoked to produce the cloned value. If `customizer` returns `undefined`,
12715     * cloning is handled by the method instead. The `customizer` is invoked with
12716     * up to four arguments; (value [, index|key, object, stack]).
12717     *
12718     * @static
12719     * @memberOf _
12720     * @since 4.0.0
12721     * @category Lang
12722     * @param {*} value The value to clone.
12723     * @param {Function} [customizer] The function to customize cloning.
12724     * @returns {*} Returns the cloned value.
12725     * @see _.cloneDeepWith
12726     * @example
12727     *
12728     * function customizer(value) {
12729     *   if (_.isElement(value)) {
12730     *     return value.cloneNode(false);
12731     *   }
12732     * }
12733     *
12734     * var el = _.cloneWith(document.body, customizer);
12735     *
12736     * console.log(el === document.body);
12737     * // => false
12738     * console.log(el.nodeName);
12739     * // => 'BODY'
12740     * console.log(el.childNodes.length);
12741     * // => 0
12742     */
12743    function cloneWith(value, customizer) {
12744      customizer = typeof customizer == 'function' ? customizer : undefined;
12745      return baseClone(value, CLONE_SYMBOLS_FLAG, customizer);
12746    }
12747
12748    /**
12749     * This method is like `_.clone` except that it recursively clones `value`.
12750     *
12751     * @static
12752     * @memberOf _
12753     * @since 1.0.0
12754     * @category Lang
12755     * @param {*} value The value to recursively clone.
12756     * @returns {*} Returns the deep cloned value.
12757     * @see _.clone
12758     * @example
12759     *
12760     * var objects = [{ 'a': 1 }, { 'b': 2 }];
12761     *
12762     * var deep = _.cloneDeep(objects);
12763     * console.log(deep[0] === objects[0]);
12764     * // => false
12765     */
12766    function cloneDeep(value) {
12767      return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
12768    }
12769
12770    /**
12771     * This method is like `_.cloneWith` except that it recursively clones `value`.
12772     *
12773     * @static
12774     * @memberOf _
12775     * @since 4.0.0
12776     * @category Lang
12777     * @param {*} value The value to recursively clone.
12778     * @param {Function} [customizer] The function to customize cloning.
12779     * @returns {*} Returns the deep cloned value.
12780     * @see _.cloneWith
12781     * @example
12782     *
12783     * function customizer(value) {
12784     *   if (_.isElement(value)) {
12785     *     return value.cloneNode(true);
12786     *   }
12787     * }
12788     *
12789     * var el = _.cloneDeepWith(document.body, customizer);
12790     *
12791     * console.log(el === document.body);
12792     * // => false
12793     * console.log(el.nodeName);
12794     * // => 'BODY'
12795     * console.log(el.childNodes.length);
12796     * // => 20
12797     */
12798    function cloneDeepWith(value, customizer) {
12799      customizer = typeof customizer == 'function' ? customizer : undefined;
12800      return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);
12801    }
12802
12803    /**
12804     * Checks if `object` conforms to `source` by invoking the predicate
12805     * properties of `source` with the corresponding property values of `object`.
12806     *
12807     * **Note:** This method is equivalent to `_.conforms` when `source` is
12808     * partially applied.
12809     *
12810     * @static
12811     * @memberOf _
12812     * @since 4.14.0
12813     * @category Lang
12814     * @param {Object} object The object to inspect.
12815     * @param {Object} source The object of property predicates to conform to.
12816     * @returns {boolean} Returns `true` if `object` conforms, else `false`.
12817     * @example
12818     *
12819     * var object = { 'a': 1, 'b': 2 };
12820     *
12821     * _.conformsTo(object, { 'b': function(n) { return n > 1; } });
12822     * // => true
12823     *
12824     * _.conformsTo(object, { 'b': function(n) { return n > 2; } });
12825     * // => false
12826     */
12827    function conformsTo(object, source) {
12828      return source == null || baseConformsTo(object, source, keys(source));
12829    }
12830
12831    /**
12832     * Performs a
12833     * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
12834     * comparison between two values to determine if they are equivalent.
12835     *
12836     * @static
12837     * @memberOf _
12838     * @since 4.0.0
12839     * @category Lang
12840     * @param {*} value The value to compare.
12841     * @param {*} other The other value to compare.
12842     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
12843     * @example
12844     *
12845     * var object = { 'a': 1 };
12846     * var other = { 'a': 1 };
12847     *
12848     * _.eq(object, object);
12849     * // => true
12850     *
12851     * _.eq(object, other);
12852     * // => false
12853     *
12854     * _.eq('a', 'a');
12855     * // => true
12856     *
12857     * _.eq('a', Object('a'));
12858     * // => false
12859     *
12860     * _.eq(NaN, NaN);
12861     * // => true
12862     */
12863    function eq(value, other) {
12864      return value === other || (value !== value && other !== other);
12865    }
12866
12867    /**
12868     * Checks if `value` is greater than `other`.
12869     *
12870     * @static
12871     * @memberOf _
12872     * @since 3.9.0
12873     * @category Lang
12874     * @param {*} value The value to compare.
12875     * @param {*} other The other value to compare.
12876     * @returns {boolean} Returns `true` if `value` is greater than `other`,
12877     *  else `false`.
12878     * @see _.lt
12879     * @example
12880     *
12881     * _.gt(3, 1);
12882     * // => true
12883     *
12884     * _.gt(3, 3);
12885     * // => false
12886     *
12887     * _.gt(1, 3);
12888     * // => false
12889     */
12890    var gt = createRelationalOperation(baseGt);
12891
12892    /**
12893     * Checks if `value` is greater than or equal to `other`.
12894     *
12895     * @static
12896     * @memberOf _
12897     * @since 3.9.0
12898     * @category Lang
12899     * @param {*} value The value to compare.
12900     * @param {*} other The other value to compare.
12901     * @returns {boolean} Returns `true` if `value` is greater than or equal to
12902     *  `other`, else `false`.
12903     * @see _.lte
12904     * @example
12905     *
12906     * _.gte(3, 1);
12907     * // => true
12908     *
12909     * _.gte(3, 3);
12910     * // => true
12911     *
12912     * _.gte(1, 3);
12913     * // => false
12914     */
12915    var gte = createRelationalOperation(function(value, other) {
12916      return value >= other;
12917    });
12918
12919    /**
12920     * Checks if `value` is likely an `arguments` object.
12921     *
12922     * @static
12923     * @memberOf _
12924     * @since 0.1.0
12925     * @category Lang
12926     * @param {*} value The value to check.
12927     * @returns {boolean} Returns `true` if `value` is an `arguments` object,
12928     *  else `false`.
12929     * @example
12930     *
12931     * _.isArguments(function() { return arguments; }());
12932     * // => true
12933     *
12934     * _.isArguments([1, 2, 3]);
12935     * // => false
12936     */
12937    var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
12938      return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
12939        !propertyIsEnumerable.call(value, 'callee');
12940    };
12941
12942    /**
12943     * Checks if `value` is classified as an `Array` object.
12944     *
12945     * @static
12946     * @memberOf _
12947     * @since 0.1.0
12948     * @category Lang
12949     * @param {*} value The value to check.
12950     * @returns {boolean} Returns `true` if `value` is an array, else `false`.
12951     * @example
12952     *
12953     * _.isArray([1, 2, 3]);
12954     * // => true
12955     *
12956     * _.isArray(document.body.children);
12957     * // => false
12958     *
12959     * _.isArray('abc');
12960     * // => false
12961     *
12962     * _.isArray(_.noop);
12963     * // => false
12964     */
12965    var isArray = Array.isArray;
12966
12967    /**
12968     * Checks if `value` is classified as an `ArrayBuffer` object.
12969     *
12970     * @static
12971     * @memberOf _
12972     * @since 4.3.0
12973     * @category Lang
12974     * @param {*} value The value to check.
12975     * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
12976     * @example
12977     *
12978     * _.isArrayBuffer(new ArrayBuffer(2));
12979     * // => true
12980     *
12981     * _.isArrayBuffer(new Array(2));
12982     * // => false
12983     */
12984    var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;
12985
12986    /**
12987     * Checks if `value` is array-like. A value is considered array-like if it's
12988     * not a function and has a `value.length` that's an integer greater than or
12989     * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
12990     *
12991     * @static
12992     * @memberOf _
12993     * @since 4.0.0
12994     * @category Lang
12995     * @param {*} value The value to check.
12996     * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
12997     * @example
12998     *
12999     * _.isArrayLike([1, 2, 3]);
13000     * // => true
13001     *
13002     * _.isArrayLike(document.body.children);
13003     * // => true
13004     *
13005     * _.isArrayLike('abc');
13006     * // => true
13007     *
13008     * _.isArrayLike(_.noop);
13009     * // => false
13010     */
13011    function isArrayLike(value) {
13012      return value != null && isLength(value.length) && !isFunction(value);
13013    }
13014
13015    /**
13016     * This method is like `_.isArrayLike` except that it also checks if `value`
13017     * is an object.
13018     *
13019     * @static
13020     * @memberOf _
13021     * @since 4.0.0
13022     * @category Lang
13023     * @param {*} value The value to check.
13024     * @returns {boolean} Returns `true` if `value` is an array-like object,
13025     *  else `false`.
13026     * @example
13027     *
13028     * _.isArrayLikeObject([1, 2, 3]);
13029     * // => true
13030     *
13031     * _.isArrayLikeObject(document.body.children);
13032     * // => true
13033     *
13034     * _.isArrayLikeObject('abc');
13035     * // => false
13036     *
13037     * _.isArrayLikeObject(_.noop);
13038     * // => false
13039     */
13040    function isArrayLikeObject(value) {
13041      return isObjectLike(value) && isArrayLike(value);
13042    }
13043
13044    /**
13045     * Checks if `value` is classified as a boolean primitive or object.
13046     *
13047     * @static
13048     * @memberOf _
13049     * @since 0.1.0
13050     * @category Lang
13051     * @param {*} value The value to check.
13052     * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
13053     * @example
13054     *
13055     * _.isBoolean(false);
13056     * // => true
13057     *
13058     * _.isBoolean(null);
13059     * // => false
13060     */
13061    function isBoolean(value) {
13062      return value === true || value === false ||
13063        (isObjectLike(value) && baseGetTag(value) == boolTag);
13064    }
13065
13066    /**
13067     * Checks if `value` is a buffer.
13068     *
13069     * @static
13070     * @memberOf _
13071     * @since 4.3.0
13072     * @category Lang
13073     * @param {*} value The value to check.
13074     * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
13075     * @example
13076     *
13077     * _.isBuffer(new Buffer(2));
13078     * // => true
13079     *
13080     * _.isBuffer(new Uint8Array(2));
13081     * // => false
13082     */
13083    var isBuffer = nativeIsBuffer || stubFalse;
13084
13085    /**
13086     * Checks if `value` is classified as a `Date` object.
13087     *
13088     * @static
13089     * @memberOf _
13090     * @since 0.1.0
13091     * @category Lang
13092     * @param {*} value The value to check.
13093     * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
13094     * @example
13095     *
13096     * _.isDate(new Date);
13097     * // => true
13098     *
13099     * _.isDate('Mon April 23 2012');
13100     * // => false
13101     */
13102    var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
13103
13104    /**
13105     * Checks if `value` is likely a DOM element.
13106     *
13107     * @static
13108     * @memberOf _
13109     * @since 0.1.0
13110     * @category Lang
13111     * @param {*} value The value to check.
13112     * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
13113     * @example
13114     *
13115     * _.isElement(document.body);
13116     * // => true
13117     *
13118     * _.isElement('<body>');
13119     * // => false
13120     */
13121    function isElement(value) {
13122      return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);
13123    }
13124
13125    /**
13126     * Checks if `value` is an empty object, collection, map, or set.
13127     *
13128     * Objects are considered empty if they have no own enumerable string keyed
13129     * properties.
13130     *
13131     * Array-like values such as `arguments` objects, arrays, buffers, strings, or
13132     * jQuery-like collections are considered empty if they have a `length` of `0`.
13133     * Similarly, maps and sets are considered empty if they have a `size` of `0`.
13134     *
13135     * @static
13136     * @memberOf _
13137     * @since 0.1.0
13138     * @category Lang
13139     * @param {*} value The value to check.
13140     * @returns {boolean} Returns `true` if `value` is empty, else `false`.
13141     * @example
13142     *
13143     * _.isEmpty(null);
13144     * // => true
13145     *
13146     * _.isEmpty(true);
13147     * // => true
13148     *
13149     * _.isEmpty(1);
13150     * // => true
13151     *
13152     * _.isEmpty([1, 2, 3]);
13153     * // => false
13154     *
13155     * _.isEmpty({ 'a': 1 });
13156     * // => false
13157     */
13158    function isEmpty(value) {
13159      if (value == null) {
13160        return true;
13161      }
13162      if (isArrayLike(value) &&
13163          (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||
13164            isBuffer(value) || isTypedArray(value) || isArguments(value))) {
13165        return !value.length;
13166      }
13167      var tag = getTag(value);
13168      if (tag == mapTag || tag == setTag) {
13169        return !value.size;
13170      }
13171      if (isPrototype(value)) {
13172        return !baseKeys(value).length;
13173      }
13174      for (var key in value) {
13175        if (hasOwnProperty.call(value, key)) {
13176          return false;
13177        }
13178      }
13179      return true;
13180    }
13181
13182    /**
13183     * Performs a deep comparison between two values to determine if they are
13184     * equivalent.
13185     *
13186     * **Note:** This method supports comparing arrays, array buffers, booleans,
13187     * date objects, error objects, maps, numbers, `Object` objects, regexes,
13188     * sets, strings, symbols, and typed arrays. `Object` objects are compared
13189     * by their own, not inherited, enumerable properties. Functions and DOM
13190     * nodes are compared by strict equality, i.e. `===`.
13191     *
13192     * @static
13193     * @memberOf _
13194     * @since 0.1.0
13195     * @category Lang
13196     * @param {*} value The value to compare.
13197     * @param {*} other The other value to compare.
13198     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
13199     * @example
13200     *
13201     * var object = { 'a': 1 };
13202     * var other = { 'a': 1 };
13203     *
13204     * _.isEqual(object, other);
13205     * // => true
13206     *
13207     * object === other;
13208     * // => false
13209     */
13210    function isEqual(value, other) {
13211      return baseIsEqual(value, other);
13212    }
13213
13214    /**
13215     * This method is like `_.isEqual` except that it accepts `customizer` which
13216     * is invoked to compare values. If `customizer` returns `undefined`, comparisons
13217     * are handled by the method instead. The `customizer` is invoked with up to
13218     * six arguments: (objValue, othValue [, index|key, object, other, stack]).
13219     *
13220     * @static
13221     * @memberOf _
13222     * @since 4.0.0
13223     * @category Lang
13224     * @param {*} value The value to compare.
13225     * @param {*} other The other value to compare.
13226     * @param {Function} [customizer] The function to customize comparisons.
13227     * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
13228     * @example
13229     *
13230     * function isGreeting(value) {
13231     *   return /^h(?:i|ello)$/.test(value);
13232     * }
13233     *
13234     * function customizer(objValue, othValue) {
13235     *   if (isGreeting(objValue) && isGreeting(othValue)) {
13236     *     return true;
13237     *   }
13238     * }
13239     *
13240     * var array = ['hello', 'goodbye'];
13241     * var other = ['hi', 'goodbye'];
13242     *
13243     * _.isEqualWith(array, other, customizer);
13244     * // => true
13245     */
13246    function isEqualWith(value, other, customizer) {
13247      customizer = typeof customizer == 'function' ? customizer : undefined;
13248      var result = customizer ? customizer(value, other) : undefined;
13249      return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;
13250    }
13251
13252    /**
13253     * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
13254     * `SyntaxError`, `TypeError`, or `URIError` object.
13255     *
13256     * @static
13257     * @memberOf _
13258     * @since 3.0.0
13259     * @category Lang
13260     * @param {*} value The value to check.
13261     * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
13262     * @example
13263     *
13264     * _.isError(new Error);
13265     * // => true
13266     *
13267     * _.isError(Error);
13268     * // => false
13269     */
13270    function isError(value) {
13271      if (!isObjectLike(value)) {
13272        return false;
vendor: 6,607 bytes, lines 13273-13510
13273      }
13274      var tag = baseGetTag(value);
13275      return tag == errorTag || tag == domExcTag ||
13276        (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value));
13277    }
13278
13279    /**
13280     * Checks if `value` is a finite primitive number.
13281     *
13282     * **Note:** This method is based on
13283     * [`Number.isFinite`](https://mdn.io/Number/isFinite).
13284     *
13285     * @static
13286     * @memberOf _
13287     * @since 0.1.0
13288     * @category Lang
13289     * @param {*} value The value to check.
13290     * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
13291     * @example
13292     *
13293     * _.isFinite(3);
13294     * // => true
13295     *
13296     * _.isFinite(Number.MIN_VALUE);
13297     * // => true
13298     *
13299     * _.isFinite(Infinity);
13300     * // => false
13301     *
13302     * _.isFinite('3');
13303     * // => false
13304     */
13305    function isFinite(value) {
13306      return typeof value == 'number' && nativeIsFinite(value);
13307    }
13308
13309    /**
13310     * Checks if `value` is classified as a `Function` object.
13311     *
13312     * @static
13313     * @memberOf _
13314     * @since 0.1.0
13315     * @category Lang
13316     * @param {*} value The value to check.
13317     * @returns {boolean} Returns `true` if `value` is a function, else `false`.
13318     * @example
13319     *
13320     * _.isFunction(_);
13321     * // => true
13322     *
13323     * _.isFunction(/abc/);
13324     * // => false
13325     */
13326    function isFunction(value) {
13327      if (!isObject(value)) {
13328        return false;
13329      }
13330      // The use of `Object#toString` avoids issues with the `typeof` operator
13331      // in Safari 9 which returns 'object' for typed arrays and other constructors.
13332      var tag = baseGetTag(value);
13333      return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
13334    }
13335
13336    /**
13337     * Checks if `value` is an integer.
13338     *
13339     * **Note:** This method is based on
13340     * [`Number.isInteger`](https://mdn.io/Number/isInteger).
13341     *
13342     * @static
13343     * @memberOf _
13344     * @since 4.0.0
13345     * @category Lang
13346     * @param {*} value The value to check.
13347     * @returns {boolean} Returns `true` if `value` is an integer, else `false`.
13348     * @example
13349     *
13350     * _.isInteger(3);
13351     * // => true
13352     *
13353     * _.isInteger(Number.MIN_VALUE);
13354     * // => false
13355     *
13356     * _.isInteger(Infinity);
13357     * // => false
13358     *
13359     * _.isInteger('3');
13360     * // => false
13361     */
13362    function isInteger(value) {
13363      return typeof value == 'number' && value == toInteger(value);
13364    }
13365
13366    /**
13367     * Checks if `value` is a valid array-like length.
13368     *
13369     * **Note:** This method is loosely based on
13370     * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
13371     *
13372     * @static
13373     * @memberOf _
13374     * @since 4.0.0
13375     * @category Lang
13376     * @param {*} value The value to check.
13377     * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
13378     * @example
13379     *
13380     * _.isLength(3);
13381     * // => true
13382     *
13383     * _.isLength(Number.MIN_VALUE);
13384     * // => false
13385     *
13386     * _.isLength(Infinity);
13387     * // => false
13388     *
13389     * _.isLength('3');
13390     * // => false
13391     */
13392    function isLength(value) {
13393      return typeof value == 'number' &&
13394        value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
13395    }
13396
13397    /**
13398     * Checks if `value` is the
13399     * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
13400     * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
13401     *
13402     * @static
13403     * @memberOf _
13404     * @since 0.1.0
13405     * @category Lang
13406     * @param {*} value The value to check.
13407     * @returns {boolean} Returns `true` if `value` is an object, else `false`.
13408     * @example
13409     *
13410     * _.isObject({});
13411     * // => true
13412     *
13413     * _.isObject([1, 2, 3]);
13414     * // => true
13415     *
13416     * _.isObject(_.noop);
13417     * // => true
13418     *
13419     * _.isObject(null);
13420     * // => false
13421     */
13422    function isObject(value) {
13423      var type = typeof value;
13424      return value != null && (type == 'object' || type == 'function');
13425    }
13426
13427    /**
13428     * Checks if `value` is object-like. A value is object-like if it's not `null`
13429     * and has a `typeof` result of "object".
13430     *
13431     * @static
13432     * @memberOf _
13433     * @since 4.0.0
13434     * @category Lang
13435     * @param {*} value The value to check.
13436     * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
13437     * @example
13438     *
13439     * _.isObjectLike({});
13440     * // => true
13441     *
13442     * _.isObjectLike([1, 2, 3]);
13443     * // => true
13444     *
13445     * _.isObjectLike(_.noop);
13446     * // => false
13447     *
13448     * _.isObjectLike(null);
13449     * // => false
13450     */
13451    function isObjectLike(value) {
13452      return value != null && typeof value == 'object';
13453    }
13454
13455    /**
13456     * Checks if `value` is classified as a `Map` object.
13457     *
13458     * @static
13459     * @memberOf _
13460     * @since 4.3.0
13461     * @category Lang
13462     * @param {*} value The value to check.
13463     * @returns {boolean} Returns `true` if `value` is a map, else `false`.
13464     * @example
13465     *
13466     * _.isMap(new Map);
13467     * // => true
13468     *
13469     * _.isMap(new WeakMap);
13470     * // => false
13471     */
13472    var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;
13473
13474    /**
13475     * Performs a partial deep comparison between `object` and `source` to
13476     * determine if `object` contains equivalent property values.
13477     *
13478     * **Note:** This method is equivalent to `_.matches` when `source` is
13479     * partially applied.
13480     *
13481     * Partial comparisons will match empty array and empty object `source`
13482     * values against any array or object value, respectively. See `_.isEqual`
13483     * for a list of supported value comparisons.
13484     *
13485     * @static
13486     * @memberOf _
13487     * @since 3.0.0
13488     * @category Lang
13489     * @param {Object} object The object to inspect.
13490     * @param {Object} source The object of property values to match.
13491     * @returns {boolean} Returns `true` if `object` is a match, else `false`.
13492     * @example
13493     *
13494     * var object = { 'a': 1, 'b': 2 };
13495     *
13496     * _.isMatch(object, { 'b': 2 });
13497     * // => true
13498     *
13499     * _.isMatch(object, { 'b': 1 });
13500     * // => false
13501     */
13502    function isMatch(object, source) {
13503      return object === source || baseIsMatch(object, source, getMatchData(source));
13504    }
13505
13506    /**
13507     * This method is like `_.isMatch` except that it accepts `customizer` which
13508     * is invoked to compare values. If `customizer` returns `undefined`, comparisons
13509     * are handled by the method instead. The `customizer` is invoked with five
13510     * arguments: (objValue, srcValue, index|key, object, source).
vendor: 12,241 bytes, lines 13511-13976
13511     *
13512     * @static
13513     * @memberOf _
13514     * @since 4.0.0
13515     * @category Lang
13516     * @param {Object} object The object to inspect.
13517     * @param {Object} source The object of property values to match.
13518     * @param {Function} [customizer] The function to customize comparisons.
13519     * @returns {boolean} Returns `true` if `object` is a match, else `false`.
13520     * @example
13521     *
13522     * function isGreeting(value) {
13523     *   return /^h(?:i|ello)$/.test(value);
13524     * }
13525     *
13526     * function customizer(objValue, srcValue) {
13527     *   if (isGreeting(objValue) && isGreeting(srcValue)) {
13528     *     return true;
13529     *   }
13530     * }
13531     *
13532     * var object = { 'greeting': 'hello' };
13533     * var source = { 'greeting': 'hi' };
13534     *
13535     * _.isMatchWith(object, source, customizer);
13536     * // => true
13537     */
13538    function isMatchWith(object, source, customizer) {
13539      customizer = typeof customizer == 'function' ? customizer : undefined;
13540      return baseIsMatch(object, source, getMatchData(source), customizer);
13541    }
13542
13543    /**
13544     * Checks if `value` is `NaN`.
13545     *
13546     * **Note:** This method is based on
13547     * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as
13548     * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for
13549     * `undefined` and other non-number values.
13550     *
13551     * @static
13552     * @memberOf _
13553     * @since 0.1.0
13554     * @category Lang
13555     * @param {*} value The value to check.
13556     * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
13557     * @example
13558     *
13559     * _.isNaN(NaN);
13560     * // => true
13561     *
13562     * _.isNaN(new Number(NaN));
13563     * // => true
13564     *
13565     * isNaN(undefined);
13566     * // => true
13567     *
13568     * _.isNaN(undefined);
13569     * // => false
13570     */
13571    function isNaN(value) {
13572      // An `NaN` primitive is the only value that is not equal to itself.
13573      // Perform the `toStringTag` check first to avoid errors with some
13574      // ActiveX objects in IE.
13575      return isNumber(value) && value != +value;
13576    }
13577
13578    /**
13579     * Checks if `value` is a pristine native function.
13580     *
13581     * **Note:** This method can't reliably detect native functions in the presence
13582     * of the core-js package because core-js circumvents this kind of detection.
13583     * Despite multiple requests, the core-js maintainer has made it clear: any
13584     * attempt to fix the detection will be obstructed. As a result, we're left
13585     * with little choice but to throw an error. Unfortunately, this also affects
13586     * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill),
13587     * which rely on core-js.
13588     *
13589     * @static
13590     * @memberOf _
13591     * @since 3.0.0
13592     * @category Lang
13593     * @param {*} value The value to check.
13594     * @returns {boolean} Returns `true` if `value` is a native function,
13595     *  else `false`.
13596     * @example
13597     *
13598     * _.isNative(Array.prototype.push);
13599     * // => true
13600     *
13601     * _.isNative(_);
13602     * // => false
13603     */
13604    function isNative(value) {
13605      if (isMaskable(value)) {
13606        throw new Error(CORE_ERROR_TEXT);
13607      }
13608      return baseIsNative(value);
13609    }
13610
13611    /**
13612     * Checks if `value` is `null`.
13613     *
13614     * @static
13615     * @memberOf _
13616     * @since 0.1.0
13617     * @category Lang
13618     * @param {*} value The value to check.
13619     * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
13620     * @example
13621     *
13622     * _.isNull(null);
13623     * // => true
13624     *
13625     * _.isNull(void 0);
13626     * // => false
13627     */
13628    function isNull(value) {
13629      return value === null;
13630    }
13631
13632    /**
13633     * Checks if `value` is `null` or `undefined`.
13634     *
13635     * @static
13636     * @memberOf _
13637     * @since 4.0.0
13638     * @category Lang
13639     * @param {*} value The value to check.
13640     * @returns {boolean} Returns `true` if `value` is nullish, else `false`.
13641     * @example
13642     *
13643     * _.isNil(null);
13644     * // => true
13645     *
13646     * _.isNil(void 0);
13647     * // => true
13648     *
13649     * _.isNil(NaN);
13650     * // => false
13651     */
13652    function isNil(value) {
13653      return value == null;
13654    }
13655
13656    /**
13657     * Checks if `value` is classified as a `Number` primitive or object.
13658     *
13659     * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
13660     * classified as numbers, use the `_.isFinite` method.
13661     *
13662     * @static
13663     * @memberOf _
13664     * @since 0.1.0
13665     * @category Lang
13666     * @param {*} value The value to check.
13667     * @returns {boolean} Returns `true` if `value` is a number, else `false`.
13668     * @example
13669     *
13670     * _.isNumber(3);
13671     * // => true
13672     *
13673     * _.isNumber(Number.MIN_VALUE);
13674     * // => true
13675     *
13676     * _.isNumber(Infinity);
13677     * // => true
13678     *
13679     * _.isNumber('3');
13680     * // => false
13681     */
13682    function isNumber(value) {
13683      return typeof value == 'number' ||
13684        (isObjectLike(value) && baseGetTag(value) == numberTag);
13685    }
13686
13687    /**
13688     * Checks if `value` is a plain object, that is, an object created by the
13689     * `Object` constructor or one with a `[[Prototype]]` of `null`.
13690     *
13691     * @static
13692     * @memberOf _
13693     * @since 0.8.0
13694     * @category Lang
13695     * @param {*} value The value to check.
13696     * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
13697     * @example
13698     *
13699     * function Foo() {
13700     *   this.a = 1;
13701     * }
13702     *
13703     * _.isPlainObject(new Foo);
13704     * // => false
13705     *
13706     * _.isPlainObject([1, 2, 3]);
13707     * // => false
13708     *
13709     * _.isPlainObject({ 'x': 0, 'y': 0 });
13710     * // => true
13711     *
13712     * _.isPlainObject(Object.create(null));
13713     * // => true
13714     */
13715    function isPlainObject(value) {
13716      if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
13717        return false;
13718      }
13719      var proto = getPrototype(value);
13720      if (proto === null) {
13721        return true;
13722      }
13723      var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
13724      return typeof Ctor == 'function' && Ctor instanceof Ctor &&
13725        funcToString.call(Ctor) == objectCtorString;
13726    }
13727
13728    /**
13729     * Checks if `value` is classified as a `RegExp` object.
13730     *
13731     * @static
13732     * @memberOf _
13733     * @since 0.1.0
13734     * @category Lang
13735     * @param {*} value The value to check.
13736     * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
13737     * @example
13738     *
13739     * _.isRegExp(/abc/);
13740     * // => true
13741     *
13742     * _.isRegExp('/abc/');
13743     * // => false
13744     */
13745    var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;
13746
13747    /**
13748     * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754
13749     * double precision number which isn't the result of a rounded unsafe integer.
13750     *
13751     * **Note:** This method is based on
13752     * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).
13753     *
13754     * @static
13755     * @memberOf _
13756     * @since 4.0.0
13757     * @category Lang
13758     * @param {*} value The value to check.
13759     * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`.
13760     * @example
13761     *
13762     * _.isSafeInteger(3);
13763     * // => true
13764     *
13765     * _.isSafeInteger(Number.MIN_VALUE);
13766     * // => false
13767     *
13768     * _.isSafeInteger(Infinity);
13769     * // => false
13770     *
13771     * _.isSafeInteger('3');
13772     * // => false
13773     */
13774    function isSafeInteger(value) {
13775      return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
13776    }
13777
13778    /**
13779     * Checks if `value` is classified as a `Set` object.
13780     *
13781     * @static
13782     * @memberOf _
13783     * @since 4.3.0
13784     * @category Lang
13785     * @param {*} value The value to check.
13786     * @returns {boolean} Returns `true` if `value` is a set, else `false`.
13787     * @example
13788     *
13789     * _.isSet(new Set);
13790     * // => true
13791     *
13792     * _.isSet(new WeakSet);
13793     * // => false
13794     */
13795    var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;
13796
13797    /**
13798     * Checks if `value` is classified as a `String` primitive or object.
13799     *
13800     * @static
13801     * @since 0.1.0
13802     * @memberOf _
13803     * @category Lang
13804     * @param {*} value The value to check.
13805     * @returns {boolean} Returns `true` if `value` is a string, else `false`.
13806     * @example
13807     *
13808     * _.isString('abc');
13809     * // => true
13810     *
13811     * _.isString(1);
13812     * // => false
13813     */
13814    function isString(value) {
13815      return typeof value == 'string' ||
13816        (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);
13817    }
13818
13819    /**
13820     * Checks if `value` is classified as a `Symbol` primitive or object.
13821     *
13822     * @static
13823     * @memberOf _
13824     * @since 4.0.0
13825     * @category Lang
13826     * @param {*} value The value to check.
13827     * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
13828     * @example
13829     *
13830     * _.isSymbol(Symbol.iterator);
13831     * // => true
13832     *
13833     * _.isSymbol('abc');
13834     * // => false
13835     */
13836    function isSymbol(value) {
13837      return typeof value == 'symbol' ||
13838        (isObjectLike(value) && baseGetTag(value) == symbolTag);
13839    }
13840
13841    /**
13842     * Checks if `value` is classified as a typed array.
13843     *
13844     * @static
13845     * @memberOf _
13846     * @since 3.0.0
13847     * @category Lang
13848     * @param {*} value The value to check.
13849     * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
13850     * @example
13851     *
13852     * _.isTypedArray(new Uint8Array);
13853     * // => true
13854     *
13855     * _.isTypedArray([]);
13856     * // => false
13857     */
13858    var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
13859
13860    /**
13861     * Checks if `value` is `undefined`.
13862     *
13863     * @static
13864     * @since 0.1.0
13865     * @memberOf _
13866     * @category Lang
13867     * @param {*} value The value to check.
13868     * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
13869     * @example
13870     *
13871     * _.isUndefined(void 0);
13872     * // => true
13873     *
13874     * _.isUndefined(null);
13875     * // => false
13876     */
13877    function isUndefined(value) {
13878      return value === undefined;
13879    }
13880
13881    /**
13882     * Checks if `value` is classified as a `WeakMap` object.
13883     *
13884     * @static
13885     * @memberOf _
13886     * @since 4.3.0
13887     * @category Lang
13888     * @param {*} value The value to check.
13889     * @returns {boolean} Returns `true` if `value` is a weak map, else `false`.
13890     * @example
13891     *
13892     * _.isWeakMap(new WeakMap);
13893     * // => true
13894     *
13895     * _.isWeakMap(new Map);
13896     * // => false
13897     */
13898    function isWeakMap(value) {
13899      return isObjectLike(value) && getTag(value) == weakMapTag;
13900    }
13901
13902    /**
13903     * Checks if `value` is classified as a `WeakSet` object.
13904     *
13905     * @static
13906     * @memberOf _
13907     * @since 4.3.0
13908     * @category Lang
13909     * @param {*} value The value to check.
13910     * @returns {boolean} Returns `true` if `value` is a weak set, else `false`.
13911     * @example
13912     *
13913     * _.isWeakSet(new WeakSet);
13914     * // => true
13915     *
13916     * _.isWeakSet(new Set);
13917     * // => false
13918     */
13919    function isWeakSet(value) {
13920      return isObjectLike(value) && baseGetTag(value) == weakSetTag;
13921    }
13922
13923    /**
13924     * Checks if `value` is less than `other`.
13925     *
13926     * @static
13927     * @memberOf _
13928     * @since 3.9.0
13929     * @category Lang
13930     * @param {*} value The value to compare.
13931     * @param {*} other The other value to compare.
13932     * @returns {boolean} Returns `true` if `value` is less than `other`,
13933     *  else `false`.
13934     * @see _.gt
13935     * @example
13936     *
13937     * _.lt(1, 3);
13938     * // => true
13939     *
13940     * _.lt(3, 3);
13941     * // => false
13942     *
13943     * _.lt(3, 1);
13944     * // => false
13945     */
13946    var lt = createRelationalOperation(baseLt);
13947
13948    /**
13949     * Checks if `value` is less than or equal to `other`.
13950     *
13951     * @static
13952     * @memberOf _
13953     * @since 3.9.0
13954     * @category Lang
13955     * @param {*} value The value to compare.
13956     * @param {*} other The other value to compare.
13957     * @returns {boolean} Returns `true` if `value` is less than or equal to
13958     *  `other`, else `false`.
13959     * @see _.gte
13960     * @example
13961     *
13962     * _.lte(1, 3);
13963     * // => true
13964     *
13965     * _.lte(3, 3);
13966     * // => true
13967     *
13968     * _.lte(3, 1);
13969     * // => false
13970     */
13971    var lte = createRelationalOperation(function(value, other) {
13972      return value <= other;
13973    });
13974
13975    /**
13976     * Converts `value` to an array.
vendor: 11,756 bytes, lines 13977-14406
13977     *
13978     * @static
13979     * @since 0.1.0
13980     * @memberOf _
13981     * @category Lang
13982     * @param {*} value The value to convert.
13983     * @returns {Array} Returns the converted array.
13984     * @example
13985     *
13986     * _.toArray({ 'a': 1, 'b': 2 });
13987     * // => [1, 2]
13988     *
13989     * _.toArray('abc');
13990     * // => ['a', 'b', 'c']
13991     *
13992     * _.toArray(1);
13993     * // => []
13994     *
13995     * _.toArray(null);
13996     * // => []
13997     */
13998    function toArray(value) {
13999      if (!value) {
14000        return [];
14001      }
14002      if (isArrayLike(value)) {
14003        return isString(value) ? stringToArray(value) : copyArray(value);
14004      }
14005      if (symIterator && value[symIterator]) {
14006        return iteratorToArray(value[symIterator]());
14007      }
14008      var tag = getTag(value),
14009          func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);
14010
14011      return func(value);
14012    }
14013
14014    /**
14015     * Converts `value` to a finite number.
14016     *
14017     * @static
14018     * @memberOf _
14019     * @since 4.12.0
14020     * @category Lang
14021     * @param {*} value The value to convert.
14022     * @returns {number} Returns the converted number.
14023     * @example
14024     *
14025     * _.toFinite(3.2);
14026     * // => 3.2
14027     *
14028     * _.toFinite(Number.MIN_VALUE);
14029     * // => 5e-324
14030     *
14031     * _.toFinite(Infinity);
14032     * // => 1.7976931348623157e+308
14033     *
14034     * _.toFinite('3.2');
14035     * // => 3.2
14036     */
14037    function toFinite(value) {
14038      if (!value) {
14039        return value === 0 ? value : 0;
14040      }
14041      value = toNumber(value);
14042      if (value === INFINITY || value === -INFINITY) {
14043        var sign = (value < 0 ? -1 : 1);
14044        return sign * MAX_INTEGER;
14045      }
14046      return value === value ? value : 0;
14047    }
14048
14049    /**
14050     * Converts `value` to an integer.
14051     *
14052     * **Note:** This method is loosely based on
14053     * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
14054     *
14055     * @static
14056     * @memberOf _
14057     * @since 4.0.0
14058     * @category Lang
14059     * @param {*} value The value to convert.
14060     * @returns {number} Returns the converted integer.
14061     * @example
14062     *
14063     * _.toInteger(3.2);
14064     * // => 3
14065     *
14066     * _.toInteger(Number.MIN_VALUE);
14067     * // => 0
14068     *
14069     * _.toInteger(Infinity);
14070     * // => 1.7976931348623157e+308
14071     *
14072     * _.toInteger('3.2');
14073     * // => 3
14074     */
14075    function toInteger(value) {
14076      var result = toFinite(value),
14077          remainder = result % 1;
14078
14079      return result === result ? (remainder ? result - remainder : result) : 0;
14080    }
14081
14082    /**
14083     * Converts `value` to an integer suitable for use as the length of an
14084     * array-like object.
14085     *
14086     * **Note:** This method is based on
14087     * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
14088     *
14089     * @static
14090     * @memberOf _
14091     * @since 4.0.0
14092     * @category Lang
14093     * @param {*} value The value to convert.
14094     * @returns {number} Returns the converted integer.
14095     * @example
14096     *
14097     * _.toLength(3.2);
14098     * // => 3
14099     *
14100     * _.toLength(Number.MIN_VALUE);
14101     * // => 0
14102     *
14103     * _.toLength(Infinity);
14104     * // => 4294967295
14105     *
14106     * _.toLength('3.2');
14107     * // => 3
14108     */
14109    function toLength(value) {
14110      return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;
14111    }
14112
14113    /**
14114     * Converts `value` to a number.
14115     *
14116     * @static
14117     * @memberOf _
14118     * @since 4.0.0
14119     * @category Lang
14120     * @param {*} value The value to process.
14121     * @returns {number} Returns the number.
14122     * @example
14123     *
14124     * _.toNumber(3.2);
14125     * // => 3.2
14126     *
14127     * _.toNumber(Number.MIN_VALUE);
14128     * // => 5e-324
14129     *
14130     * _.toNumber(Infinity);
14131     * // => Infinity
14132     *
14133     * _.toNumber('3.2');
14134     * // => 3.2
14135     */
14136    function toNumber(value) {
14137      if (typeof value == 'number') {
14138        return value;
14139      }
14140      if (isSymbol(value)) {
14141        return NAN;
14142      }
14143      if (isObject(value)) {
14144        var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
14145        value = isObject(other) ? (other + '') : other;
14146      }
14147      if (typeof value != 'string') {
14148        return value === 0 ? value : +value;
14149      }
14150      value = baseTrim(value);
14151      var isBinary = reIsBinary.test(value);
14152      return (isBinary || reIsOctal.test(value))
14153        ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
14154        : (reIsBadHex.test(value) ? NAN : +value);
14155    }
14156
14157    /**
14158     * Converts `value` to a plain object flattening inherited enumerable string
14159     * keyed properties of `value` to own properties of the plain object.
14160     *
14161     * @static
14162     * @memberOf _
14163     * @since 3.0.0
14164     * @category Lang
14165     * @param {*} value The value to convert.
14166     * @returns {Object} Returns the converted plain object.
14167     * @example
14168     *
14169     * function Foo() {
14170     *   this.b = 2;
14171     * }
14172     *
14173     * Foo.prototype.c = 3;
14174     *
14175     * _.assign({ 'a': 1 }, new Foo);
14176     * // => { 'a': 1, 'b': 2 }
14177     *
14178     * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
14179     * // => { 'a': 1, 'b': 2, 'c': 3 }
14180     */
14181    function toPlainObject(value) {
14182      return copyObject(value, keysIn(value));
14183    }
14184
14185    /**
14186     * Converts `value` to a safe integer. A safe integer can be compared and
14187     * represented correctly.
14188     *
14189     * @static
14190     * @memberOf _
14191     * @since 4.0.0
14192     * @category Lang
14193     * @param {*} value The value to convert.
14194     * @returns {number} Returns the converted integer.
14195     * @example
14196     *
14197     * _.toSafeInteger(3.2);
14198     * // => 3
14199     *
14200     * _.toSafeInteger(Number.MIN_VALUE);
14201     * // => 0
14202     *
14203     * _.toSafeInteger(Infinity);
14204     * // => 9007199254740991
14205     *
14206     * _.toSafeInteger('3.2');
14207     * // => 3
14208     */
14209    function toSafeInteger(value) {
14210      return value
14211        ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER)
14212        : (value === 0 ? value : 0);
14213    }
14214
14215    /**
14216     * Converts `value` to a string. An empty string is returned for `null`
14217     * and `undefined` values. The sign of `-0` is preserved.
14218     *
14219     * @static
14220     * @memberOf _
14221     * @since 4.0.0
14222     * @category Lang
14223     * @param {*} value The value to convert.
14224     * @returns {string} Returns the converted string.
14225     * @example
14226     *
14227     * _.toString(null);
14228     * // => ''
14229     *
14230     * _.toString(-0);
14231     * // => '-0'
14232     *
14233     * _.toString([1, 2, 3]);
14234     * // => '1,2,3'
14235     */
14236    function toString(value) {
14237      return value == null ? '' : baseToString(value);
14238    }
14239
14240    /*------------------------------------------------------------------------*/
14241
14242    /**
14243     * Assigns own enumerable string keyed properties of source objects to the
14244     * destination object. Source objects are applied from left to right.
14245     * Subsequent sources overwrite property assignments of previous sources.
14246     *
14247     * **Note:** This method mutates `object` and is loosely based on
14248     * [`Object.assign`](https://mdn.io/Object/assign).
14249     *
14250     * @static
14251     * @memberOf _
14252     * @since 0.10.0
14253     * @category Object
14254     * @param {Object} object The destination object.
14255     * @param {...Object} [sources] The source objects.
14256     * @returns {Object} Returns `object`.
14257     * @see _.assignIn
14258     * @example
14259     *
14260     * function Foo() {
14261     *   this.a = 1;
14262     * }
14263     *
14264     * function Bar() {
14265     *   this.c = 3;
14266     * }
14267     *
14268     * Foo.prototype.b = 2;
14269     * Bar.prototype.d = 4;
14270     *
14271     * _.assign({ 'a': 0 }, new Foo, new Bar);
14272     * // => { 'a': 1, 'c': 3 }
14273     */
14274    var assign = createAssigner(function(object, source) {
14275      if (isPrototype(source) || isArrayLike(source)) {
14276        copyObject(source, keys(source), object);
14277        return;
14278      }
14279      for (var key in source) {
14280        if (hasOwnProperty.call(source, key)) {
14281          assignValue(object, key, source[key]);
14282        }
14283      }
14284    });
14285
14286    /**
14287     * This method is like `_.assign` except that it iterates over own and
14288     * inherited source properties.
14289     *
14290     * **Note:** This method mutates `object`.
14291     *
14292     * @static
14293     * @memberOf _
14294     * @since 4.0.0
14295     * @alias extend
14296     * @category Object
14297     * @param {Object} object The destination object.
14298     * @param {...Object} [sources] The source objects.
14299     * @returns {Object} Returns `object`.
14300     * @see _.assign
14301     * @example
14302     *
14303     * function Foo() {
14304     *   this.a = 1;
14305     * }
14306     *
14307     * function Bar() {
14308     *   this.c = 3;
14309     * }
14310     *
14311     * Foo.prototype.b = 2;
14312     * Bar.prototype.d = 4;
14313     *
14314     * _.assignIn({ 'a': 0 }, new Foo, new Bar);
14315     * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }
14316     */
14317    var assignIn = createAssigner(function(object, source) {
14318      copyObject(source, keysIn(source), object);
14319    });
14320
14321    /**
14322     * This method is like `_.assignIn` except that it accepts `customizer`
14323     * which is invoked to produce the assigned values. If `customizer` returns
14324     * `undefined`, assignment is handled by the method instead. The `customizer`
14325     * is invoked with five arguments: (objValue, srcValue, key, object, source).
14326     *
14327     * **Note:** This method mutates `object`.
14328     *
14329     * @static
14330     * @memberOf _
14331     * @since 4.0.0
14332     * @alias extendWith
14333     * @category Object
14334     * @param {Object} object The destination object.
14335     * @param {...Object} sources The source objects.
14336     * @param {Function} [customizer] The function to customize assigned values.
14337     * @returns {Object} Returns `object`.
14338     * @see _.assignWith
14339     * @example
14340     *
14341     * function customizer(objValue, srcValue) {
14342     *   return _.isUndefined(objValue) ? srcValue : objValue;
14343     * }
14344     *
14345     * var defaults = _.partialRight(_.assignInWith, customizer);
14346     *
14347     * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
14348     * // => { 'a': 1, 'b': 2 }
14349     */
14350    var assignInWith = createAssigner(function(object, source, srcIndex, customizer) {
14351      copyObject(source, keysIn(source), object, customizer);
14352    });
14353
14354    /**
14355     * This method is like `_.assign` except that it accepts `customizer`
14356     * which is invoked to produce the assigned values. If `customizer` returns
14357     * `undefined`, assignment is handled by the method instead. The `customizer`
14358     * is invoked with five arguments: (objValue, srcValue, key, object, source).
14359     *
14360     * **Note:** This method mutates `object`.
14361     *
14362     * @static
14363     * @memberOf _
14364     * @since 4.0.0
14365     * @category Object
14366     * @param {Object} object The destination object.
14367     * @param {...Object} sources The source objects.
14368     * @param {Function} [customizer] The function to customize assigned values.
14369     * @returns {Object} Returns `object`.
14370     * @see _.assignInWith
14371     * @example
14372     *
14373     * function customizer(objValue, srcValue) {
14374     *   return _.isUndefined(objValue) ? srcValue : objValue;
14375     * }
14376     *
14377     * var defaults = _.partialRight(_.assignWith, customizer);
14378     *
14379     * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
14380     * // => { 'a': 1, 'b': 2 }
14381     */
14382    var assignWith = createAssigner(function(object, source, srcIndex, customizer) {
14383      copyObject(source, keys(source), object, customizer);
14384    });
14385
14386    /**
14387     * Creates an array of values corresponding to `paths` of `object`.
14388     *
14389     * @static
14390     * @memberOf _
14391     * @since 1.0.0
14392     * @category Object
14393     * @param {Object} object The object to iterate over.
14394     * @param {...(string|string[])} [paths] The property paths to pick.
14395     * @returns {Array} Returns the picked values.
14396     * @example
14397     *
14398     * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
14399     *
14400     * _.at(object, ['a[0].b.c', 'a[1]']);
14401     * // => [3, 4]
14402     */
14403    var at = flatRest(baseAt);
14404
14405    /**
14406     * Creates an object that inherits from the `prototype` object. If a
vendor: 13,619 bytes, lines 14407-14871
14407     * `properties` object is given, its own enumerable string keyed properties
14408     * are assigned to the created object.
14409     *
14410     * @static
14411     * @memberOf _
14412     * @since 2.3.0
14413     * @category Object
14414     * @param {Object} prototype The object to inherit from.
14415     * @param {Object} [properties] The properties to assign to the object.
14416     * @returns {Object} Returns the new object.
14417     * @example
14418     *
14419     * function Shape() {
14420     *   this.x = 0;
14421     *   this.y = 0;
14422     * }
14423     *
14424     * function Circle() {
14425     *   Shape.call(this);
14426     * }
14427     *
14428     * Circle.prototype = _.create(Shape.prototype, {
14429     *   'constructor': Circle
14430     * });
14431     *
14432     * var circle = new Circle;
14433     * circle instanceof Circle;
14434     * // => true
14435     *
14436     * circle instanceof Shape;
14437     * // => true
14438     */
14439    function create(prototype, properties) {
14440      var result = baseCreate(prototype);
14441      return properties == null ? result : baseAssign(result, properties);
14442    }
14443
14444    /**
14445     * Assigns own and inherited enumerable string keyed properties of source
14446     * objects to the destination object for all destination properties that
14447     * resolve to `undefined`. Source objects are applied from left to right.
14448     * Once a property is set, additional values of the same property are ignored.
14449     *
14450     * **Note:** This method mutates `object`.
14451     *
14452     * @static
14453     * @since 0.1.0
14454     * @memberOf _
14455     * @category Object
14456     * @param {Object} object The destination object.
14457     * @param {...Object} [sources] The source objects.
14458     * @returns {Object} Returns `object`.
14459     * @see _.defaultsDeep
14460     * @example
14461     *
14462     * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
14463     * // => { 'a': 1, 'b': 2 }
14464     */
14465    var defaults = baseRest(function(object, sources) {
14466      object = Object(object);
14467
14468      var index = -1;
14469      var length = sources.length;
14470      var guard = length > 2 ? sources[2] : undefined;
14471
14472      if (guard && isIterateeCall(sources[0], sources[1], guard)) {
14473        length = 1;
14474      }
14475
14476      while (++index < length) {
14477        var source = sources[index];
14478        var props = keysIn(source);
14479        var propsIndex = -1;
14480        var propsLength = props.length;
14481
14482        while (++propsIndex < propsLength) {
14483          var key = props[propsIndex];
14484          var value = object[key];
14485
14486          if (value === undefined ||
14487              (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) {
14488            object[key] = source[key];
14489          }
14490        }
14491      }
14492
14493      return object;
14494    });
14495
14496    /**
14497     * This method is like `_.defaults` except that it recursively assigns
14498     * default properties.
14499     *
14500     * **Note:** This method mutates `object`.
14501     *
14502     * @static
14503     * @memberOf _
14504     * @since 3.10.0
14505     * @category Object
14506     * @param {Object} object The destination object.
14507     * @param {...Object} [sources] The source objects.
14508     * @returns {Object} Returns `object`.
14509     * @see _.defaults
14510     * @example
14511     *
14512     * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });
14513     * // => { 'a': { 'b': 2, 'c': 3 } }
14514     */
14515    var defaultsDeep = baseRest(function(args) {
14516      args.push(undefined, customDefaultsMerge);
14517      return apply(mergeWith, undefined, args);
14518    });
14519
14520    /**
14521     * This method is like `_.find` except that it returns the key of the first
14522     * element `predicate` returns truthy for instead of the element itself.
14523     *
14524     * @static
14525     * @memberOf _
14526     * @since 1.1.0
14527     * @category Object
14528     * @param {Object} object The object to inspect.
14529     * @param {Function} [predicate=_.identity] The function invoked per iteration.
14530     * @returns {string|undefined} Returns the key of the matched element,
14531     *  else `undefined`.
14532     * @example
14533     *
14534     * var users = {
14535     *   'barney':  { 'age': 36, 'active': true },
14536     *   'fred':    { 'age': 40, 'active': false },
14537     *   'pebbles': { 'age': 1,  'active': true }
14538     * };
14539     *
14540     * _.findKey(users, function(o) { return o.age < 40; });
14541     * // => 'barney' (iteration order is not guaranteed)
14542     *
14543     * // The `_.matches` iteratee shorthand.
14544     * _.findKey(users, { 'age': 1, 'active': true });
14545     * // => 'pebbles'
14546     *
14547     * // The `_.matchesProperty` iteratee shorthand.
14548     * _.findKey(users, ['active', false]);
14549     * // => 'fred'
14550     *
14551     * // The `_.property` iteratee shorthand.
14552     * _.findKey(users, 'active');
14553     * // => 'barney'
14554     */
14555    function findKey(object, predicate) {
14556      return baseFindKey(object, getIteratee(predicate, 3), baseForOwn);
14557    }
14558
14559    /**
14560     * This method is like `_.findKey` except that it iterates over elements of
14561     * a collection in the opposite order.
14562     *
14563     * @static
14564     * @memberOf _
14565     * @since 2.0.0
14566     * @category Object
14567     * @param {Object} object The object to inspect.
14568     * @param {Function} [predicate=_.identity] The function invoked per iteration.
14569     * @returns {string|undefined} Returns the key of the matched element,
14570     *  else `undefined`.
14571     * @example
14572     *
14573     * var users = {
14574     *   'barney':  { 'age': 36, 'active': true },
14575     *   'fred':    { 'age': 40, 'active': false },
14576     *   'pebbles': { 'age': 1,  'active': true }
14577     * };
14578     *
14579     * _.findLastKey(users, function(o) { return o.age < 40; });
14580     * // => returns 'pebbles' assuming `_.findKey` returns 'barney'
14581     *
14582     * // The `_.matches` iteratee shorthand.
14583     * _.findLastKey(users, { 'age': 36, 'active': true });
14584     * // => 'barney'
14585     *
14586     * // The `_.matchesProperty` iteratee shorthand.
14587     * _.findLastKey(users, ['active', false]);
14588     * // => 'fred'
14589     *
14590     * // The `_.property` iteratee shorthand.
14591     * _.findLastKey(users, 'active');
14592     * // => 'pebbles'
14593     */
14594    function findLastKey(object, predicate) {
14595      return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight);
14596    }
14597
14598    /**
14599     * Iterates over own and inherited enumerable string keyed properties of an
14600     * object and invokes `iteratee` for each property. The iteratee is invoked
14601     * with three arguments: (value, key, object). Iteratee functions may exit
14602     * iteration early by explicitly returning `false`.
14603     *
14604     * @static
14605     * @memberOf _
14606     * @since 0.3.0
14607     * @category Object
14608     * @param {Object} object The object to iterate over.
14609     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
14610     * @returns {Object} Returns `object`.
14611     * @see _.forInRight
14612     * @example
14613     *
14614     * function Foo() {
14615     *   this.a = 1;
14616     *   this.b = 2;
14617     * }
14618     *
14619     * Foo.prototype.c = 3;
14620     *
14621     * _.forIn(new Foo, function(value, key) {
14622     *   console.log(key);
14623     * });
14624     * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).
14625     */
14626    function forIn(object, iteratee) {
14627      return object == null
14628        ? object
14629        : baseFor(object, getIteratee(iteratee, 3), keysIn);
14630    }
14631
14632    /**
14633     * This method is like `_.forIn` except that it iterates over properties of
14634     * `object` in the opposite order.
14635     *
14636     * @static
14637     * @memberOf _
14638     * @since 2.0.0
14639     * @category Object
14640     * @param {Object} object The object to iterate over.
14641     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
14642     * @returns {Object} Returns `object`.
14643     * @see _.forIn
14644     * @example
14645     *
14646     * function Foo() {
14647     *   this.a = 1;
14648     *   this.b = 2;
14649     * }
14650     *
14651     * Foo.prototype.c = 3;
14652     *
14653     * _.forInRight(new Foo, function(value, key) {
14654     *   console.log(key);
14655     * });
14656     * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.
14657     */
14658    function forInRight(object, iteratee) {
14659      return object == null
14660        ? object
14661        : baseForRight(object, getIteratee(iteratee, 3), keysIn);
14662    }
14663
14664    /**
14665     * Iterates over own enumerable string keyed properties of an object and
14666     * invokes `iteratee` for each property. The iteratee is invoked with three
14667     * arguments: (value, key, object). Iteratee functions may exit iteration
14668     * early by explicitly returning `false`.
14669     *
14670     * @static
14671     * @memberOf _
14672     * @since 0.3.0
14673     * @category Object
14674     * @param {Object} object The object to iterate over.
14675     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
14676     * @returns {Object} Returns `object`.
14677     * @see _.forOwnRight
14678     * @example
14679     *
14680     * function Foo() {
14681     *   this.a = 1;
14682     *   this.b = 2;
14683     * }
14684     *
14685     * Foo.prototype.c = 3;
14686     *
14687     * _.forOwn(new Foo, function(value, key) {
14688     *   console.log(key);
14689     * });
14690     * // => Logs 'a' then 'b' (iteration order is not guaranteed).
14691     */
14692    function forOwn(object, iteratee) {
14693      return object && baseForOwn(object, getIteratee(iteratee, 3));
14694    }
14695
14696    /**
14697     * This method is like `_.forOwn` except that it iterates over properties of
14698     * `object` in the opposite order.
14699     *
14700     * @static
14701     * @memberOf _
14702     * @since 2.0.0
14703     * @category Object
14704     * @param {Object} object The object to iterate over.
14705     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
14706     * @returns {Object} Returns `object`.
14707     * @see _.forOwn
14708     * @example
14709     *
14710     * function Foo() {
14711     *   this.a = 1;
14712     *   this.b = 2;
14713     * }
14714     *
14715     * Foo.prototype.c = 3;
14716     *
14717     * _.forOwnRight(new Foo, function(value, key) {
14718     *   console.log(key);
14719     * });
14720     * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
14721     */
14722    function forOwnRight(object, iteratee) {
14723      return object && baseForOwnRight(object, getIteratee(iteratee, 3));
14724    }
14725
14726    /**
14727     * Creates an array of function property names from own enumerable properties
14728     * of `object`.
14729     *
14730     * @static
14731     * @since 0.1.0
14732     * @memberOf _
14733     * @category Object
14734     * @param {Object} object The object to inspect.
14735     * @returns {Array} Returns the function names.
14736     * @see _.functionsIn
14737     * @example
14738     *
14739     * function Foo() {
14740     *   this.a = _.constant('a');
14741     *   this.b = _.constant('b');
14742     * }
14743     *
14744     * Foo.prototype.c = _.constant('c');
14745     *
14746     * _.functions(new Foo);
14747     * // => ['a', 'b']
14748     */
14749    function functions(object) {
14750      return object == null ? [] : baseFunctions(object, keys(object));
14751    }
14752
14753    /**
14754     * Creates an array of function property names from own and inherited
14755     * enumerable properties of `object`.
14756     *
14757     * @static
14758     * @memberOf _
14759     * @since 4.0.0
14760     * @category Object
14761     * @param {Object} object The object to inspect.
14762     * @returns {Array} Returns the function names.
14763     * @see _.functions
14764     * @example
14765     *
14766     * function Foo() {
14767     *   this.a = _.constant('a');
14768     *   this.b = _.constant('b');
14769     * }
14770     *
14771     * Foo.prototype.c = _.constant('c');
14772     *
14773     * _.functionsIn(new Foo);
14774     * // => ['a', 'b', 'c']
14775     */
14776    function functionsIn(object) {
14777      return object == null ? [] : baseFunctions(object, keysIn(object));
14778    }
14779
14780    /**
14781     * Gets the value at `path` of `object`. If the resolved value is
14782     * `undefined`, the `defaultValue` is returned in its place.
14783     *
14784     * @static
14785     * @memberOf _
14786     * @since 3.7.0
14787     * @category Object
14788     * @param {Object} object The object to query.
14789     * @param {Array|string} path The path of the property to get.
14790     * @param {*} [defaultValue] The value returned for `undefined` resolved values.
14791     * @returns {*} Returns the resolved value.
14792     * @example
14793     *
14794     * var object = { 'a': [{ 'b': { 'c': 3 } }] };
14795     *
14796     * _.get(object, 'a[0].b.c');
14797     * // => 3
14798     *
14799     * _.get(object, ['a', '0', 'b', 'c']);
14800     * // => 3
14801     *
14802     * _.get(object, 'a.b.c', 'default');
14803     * // => 'default'
14804     */
14805    function get(object, path, defaultValue) {
14806      var result = object == null ? undefined : baseGet(object, path);
14807      return result === undefined ? defaultValue : result;
14808    }
14809
14810    /**
14811     * Checks if `path` is a direct property of `object`.
14812     *
14813     * @static
14814     * @since 0.1.0
14815     * @memberOf _
14816     * @category Object
14817     * @param {Object} object The object to query.
14818     * @param {Array|string} path The path to check.
14819     * @returns {boolean} Returns `true` if `path` exists, else `false`.
14820     * @example
14821     *
14822     * var object = { 'a': { 'b': 2 } };
14823     * var other = _.create({ 'a': _.create({ 'b': 2 }) });
14824     *
14825     * _.has(object, 'a');
14826     * // => true
14827     *
14828     * _.has(object, 'a.b');
14829     * // => true
14830     *
14831     * _.has(object, ['a', 'b']);
14832     * // => true
14833     *
14834     * _.has(other, 'a');
14835     * // => false
14836     */
14837    function has(object, path) {
14838      return object != null && hasPath(object, path, baseHas);
14839    }
14840
14841    /**
14842     * Checks if `path` is a direct or inherited property of `object`.
14843     *
14844     * @static
14845     * @memberOf _
14846     * @since 4.0.0
14847     * @category Object
14848     * @param {Object} object The object to query.
14849     * @param {Array|string} path The path to check.
14850     * @returns {boolean} Returns `true` if `path` exists, else `false`.
14851     * @example
14852     *
14853     * var object = _.create({ 'a': _.create({ 'b': 2 }) });
14854     *
14855     * _.hasIn(object, 'a');
14856     * // => true
14857     *
14858     * _.hasIn(object, 'a.b');
14859     * // => true
14860     *
14861     * _.hasIn(object, ['a', 'b']);
14862     * // => true
14863     *
14864     * _.hasIn(object, 'b');
14865     * // => false
14866     */
14867    function hasIn(object, path) {
14868      return object != null && hasPath(object, path, baseHasIn);
14869    }
14870
14871    /**
vendor: 11,848 bytes, lines 14872-15242
14872     * Creates an object composed of the inverted keys and values of `object`.
14873     * If `object` contains duplicate values, subsequent values overwrite
14874     * property assignments of previous values.
14875     *
14876     * @static
14877     * @memberOf _
14878     * @since 0.7.0
14879     * @category Object
14880     * @param {Object} object The object to invert.
14881     * @returns {Object} Returns the new inverted object.
14882     * @example
14883     *
14884     * var object = { 'a': 1, 'b': 2, 'c': 1 };
14885     *
14886     * _.invert(object);
14887     * // => { '1': 'c', '2': 'b' }
14888     */
14889    var invert = createInverter(function(result, value, key) {
14890      if (value != null &&
14891          typeof value.toString != 'function') {
14892        value = nativeObjectToString.call(value);
14893      }
14894
14895      result[value] = key;
14896    }, constant(identity));
14897
14898    /**
14899     * This method is like `_.invert` except that the inverted object is generated
14900     * from the results of running each element of `object` thru `iteratee`. The
14901     * corresponding inverted value of each inverted key is an array of keys
14902     * responsible for generating the inverted value. The iteratee is invoked
14903     * with one argument: (value).
14904     *
14905     * @static
14906     * @memberOf _
14907     * @since 4.1.0
14908     * @category Object
14909     * @param {Object} object The object to invert.
14910     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
14911     * @returns {Object} Returns the new inverted object.
14912     * @example
14913     *
14914     * var object = { 'a': 1, 'b': 2, 'c': 1 };
14915     *
14916     * _.invertBy(object);
14917     * // => { '1': ['a', 'c'], '2': ['b'] }
14918     *
14919     * _.invertBy(object, function(value) {
14920     *   return 'group' + value;
14921     * });
14922     * // => { 'group1': ['a', 'c'], 'group2': ['b'] }
14923     */
14924    var invertBy = createInverter(function(result, value, key) {
14925      if (value != null &&
14926          typeof value.toString != 'function') {
14927        value = nativeObjectToString.call(value);
14928      }
14929
14930      if (hasOwnProperty.call(result, value)) {
14931        result[value].push(key);
14932      } else {
14933        result[value] = [key];
14934      }
14935    }, getIteratee);
14936
14937    /**
14938     * Invokes the method at `path` of `object`.
14939     *
14940     * @static
14941     * @memberOf _
14942     * @since 4.0.0
14943     * @category Object
14944     * @param {Object} object The object to query.
14945     * @param {Array|string} path The path of the method to invoke.
14946     * @param {...*} [args] The arguments to invoke the method with.
14947     * @returns {*} Returns the result of the invoked method.
14948     * @example
14949     *
14950     * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };
14951     *
14952     * _.invoke(object, 'a[0].b.c.slice', 1, 3);
14953     * // => [2, 3]
14954     */
14955    var invoke = baseRest(baseInvoke);
14956
14957    /**
14958     * Creates an array of the own enumerable property names of `object`.
14959     *
14960     * **Note:** Non-object values are coerced to objects. See the
14961     * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
14962     * for more details.
14963     *
14964     * @static
14965     * @since 0.1.0
14966     * @memberOf _
14967     * @category Object
14968     * @param {Object} object The object to query.
14969     * @returns {Array} Returns the array of property names.
14970     * @example
14971     *
14972     * function Foo() {
14973     *   this.a = 1;
14974     *   this.b = 2;
14975     * }
14976     *
14977     * Foo.prototype.c = 3;
14978     *
14979     * _.keys(new Foo);
14980     * // => ['a', 'b'] (iteration order is not guaranteed)
14981     *
14982     * _.keys('hi');
14983     * // => ['0', '1']
14984     */
14985    function keys(object) {
14986      return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
14987    }
14988
14989    /**
14990     * Creates an array of the own and inherited enumerable property names of `object`.
14991     *
14992     * **Note:** Non-object values are coerced to objects.
14993     *
14994     * @static
14995     * @memberOf _
14996     * @since 3.0.0
14997     * @category Object
14998     * @param {Object} object The object to query.
14999     * @returns {Array} Returns the array of property names.
15000     * @example
15001     *
15002     * function Foo() {
15003     *   this.a = 1;
15004     *   this.b = 2;
15005     * }
15006     *
15007     * Foo.prototype.c = 3;
15008     *
15009     * _.keysIn(new Foo);
15010     * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
15011     */
15012    function keysIn(object) {
15013      return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
15014    }
15015
15016    /**
15017     * The opposite of `_.mapValues`; this method creates an object with the
15018     * same values as `object` and keys generated by running each own enumerable
15019     * string keyed property of `object` thru `iteratee`. The iteratee is invoked
15020     * with three arguments: (value, key, object).
15021     *
15022     * @static
15023     * @memberOf _
15024     * @since 3.8.0
15025     * @category Object
15026     * @param {Object} object The object to iterate over.
15027     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
15028     * @returns {Object} Returns the new mapped object.
15029     * @see _.mapValues
15030     * @example
15031     *
15032     * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
15033     *   return key + value;
15034     * });
15035     * // => { 'a1': 1, 'b2': 2 }
15036     */
15037    function mapKeys(object, iteratee) {
15038      var result = {};
15039      iteratee = getIteratee(iteratee, 3);
15040
15041      baseForOwn(object, function(value, key, object) {
15042        baseAssignValue(result, iteratee(value, key, object), value);
15043      });
15044      return result;
15045    }
15046
15047    /**
15048     * Creates an object with the same keys as `object` and values generated
15049     * by running each own enumerable string keyed property of `object` thru
15050     * `iteratee`. The iteratee is invoked with three arguments:
15051     * (value, key, object).
15052     *
15053     * @static
15054     * @memberOf _
15055     * @since 2.4.0
15056     * @category Object
15057     * @param {Object} object The object to iterate over.
15058     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
15059     * @returns {Object} Returns the new mapped object.
15060     * @see _.mapKeys
15061     * @example
15062     *
15063     * var users = {
15064     *   'fred':    { 'user': 'fred',    'age': 40 },
15065     *   'pebbles': { 'user': 'pebbles', 'age': 1 }
15066     * };
15067     *
15068     * _.mapValues(users, function(o) { return o.age; });
15069     * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
15070     *
15071     * // The `_.property` iteratee shorthand.
15072     * _.mapValues(users, 'age');
15073     * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
15074     */
15075    function mapValues(object, iteratee) {
15076      var result = {};
15077      iteratee = getIteratee(iteratee, 3);
15078
15079      baseForOwn(object, function(value, key, object) {
15080        baseAssignValue(result, key, iteratee(value, key, object));
15081      });
15082      return result;
15083    }
15084
15085    /**
15086     * This method is like `_.assign` except that it recursively merges own and
15087     * inherited enumerable string keyed properties of source objects into the
15088     * destination object. Source properties that resolve to `undefined` are
15089     * skipped if a destination value exists. Array and plain object properties
15090     * are merged recursively. Other objects and value types are overridden by
15091     * assignment. Source objects are applied from left to right. Subsequent
15092     * sources overwrite property assignments of previous sources.
15093     *
15094     * **Note:** This method mutates `object`.
15095     *
15096     * @static
15097     * @memberOf _
15098     * @since 0.5.0
15099     * @category Object
15100     * @param {Object} object The destination object.
15101     * @param {...Object} [sources] The source objects.
15102     * @returns {Object} Returns `object`.
15103     * @example
15104     *
15105     * var object = {
15106     *   'a': [{ 'b': 2 }, { 'd': 4 }]
15107     * };
15108     *
15109     * var other = {
15110     *   'a': [{ 'c': 3 }, { 'e': 5 }]
15111     * };
15112     *
15113     * _.merge(object, other);
15114     * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
15115     */
15116    var merge = createAssigner(function(object, source, srcIndex) {
15117      baseMerge(object, source, srcIndex);
15118    });
15119
15120    /**
15121     * This method is like `_.merge` except that it accepts `customizer` which
15122     * is invoked to produce the merged values of the destination and source
15123     * properties. If `customizer` returns `undefined`, merging is handled by the
15124     * method instead. The `customizer` is invoked with six arguments:
15125     * (objValue, srcValue, key, object, source, stack).
15126     *
15127     * **Note:** This method mutates `object`.
15128     *
15129     * @static
15130     * @memberOf _
15131     * @since 4.0.0
15132     * @category Object
15133     * @param {Object} object The destination object.
15134     * @param {...Object} sources The source objects.
15135     * @param {Function} customizer The function to customize assigned values.
15136     * @returns {Object} Returns `object`.
15137     * @example
15138     *
15139     * function customizer(objValue, srcValue) {
15140     *   if (_.isArray(objValue)) {
15141     *     return objValue.concat(srcValue);
15142     *   }
15143     * }
15144     *
15145     * var object = { 'a': [1], 'b': [2] };
15146     * var other = { 'a': [3], 'b': [4] };
15147     *
15148     * _.mergeWith(object, other, customizer);
15149     * // => { 'a': [1, 3], 'b': [2, 4] }
15150     */
15151    var mergeWith = createAssigner(function(object, source, srcIndex, customizer) {
15152      baseMerge(object, source, srcIndex, customizer);
15153    });
15154
15155    /**
15156     * The opposite of `_.pick`; this method creates an object composed of the
15157     * own and inherited enumerable property paths of `object` that are not omitted.
15158     *
15159     * **Note:** This method is considerably slower than `_.pick`.
15160     *
15161     * @static
15162     * @since 0.1.0
15163     * @memberOf _
15164     * @category Object
15165     * @param {Object} object The source object.
15166     * @param {...(string|string[])} [paths] The property paths to omit.
15167     * @returns {Object} Returns the new object.
15168     * @example
15169     *
15170     * var object = { 'a': 1, 'b': '2', 'c': 3 };
15171     *
15172     * _.omit(object, ['a', 'c']);
15173     * // => { 'b': '2' }
15174     */
15175    var omit = flatRest(function(object, paths) {
15176      var result = {};
15177      if (object == null) {
15178        return result;
15179      }
15180      var isDeep = false;
15181      paths = arrayMap(paths, function(path) {
15182        path = castPath(path, object);
15183        isDeep || (isDeep = path.length > 1);
15184        return path;
15185      });
15186      copyObject(object, getAllKeysIn(object), result);
15187      if (isDeep) {
15188        result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone);
15189      }
15190      var length = paths.length;
15191      while (length--) {
15192        baseUnset(result, paths[length]);
15193      }
15194      return result;
15195    });
15196
15197    /**
15198     * The opposite of `_.pickBy`; this method creates an object composed of
15199     * the own and inherited enumerable string keyed properties of `object` that
15200     * `predicate` doesn't return truthy for. The predicate is invoked with two
15201     * arguments: (value, key).
15202     *
15203     * @static
15204     * @memberOf _
15205     * @since 4.0.0
15206     * @category Object
15207     * @param {Object} object The source object.
15208     * @param {Function} [predicate=_.identity] The function invoked per property.
15209     * @returns {Object} Returns the new object.
15210     * @example
15211     *
15212     * var object = { 'a': 1, 'b': '2', 'c': 3 };
15213     *
15214     * _.omitBy(object, _.isNumber);
15215     * // => { 'b': '2' }
15216     */
15217    function omitBy(object, predicate) {
15218      return pickBy(object, negate(getIteratee(predicate)));
15219    }
15220
15221    /**
15222     * Creates an object composed of the picked `object` properties.
15223     *
15224     * @static
15225     * @since 0.1.0
15226     * @memberOf _
15227     * @category Object
15228     * @param {Object} object The source object.
15229     * @param {...(string|string[])} [paths] The property paths to pick.
15230     * @returns {Object} Returns the new object.
15231     * @example
15232     *
15233     * var object = { 'a': 1, 'b': '2', 'c': 3 };
15234     *
15235     * _.pick(object, ['a', 'c']);
15236     * // => { 'a': 1, 'c': 3 }
15237     */
15238    var pick = flatRest(function(object, paths) {
15239      return object == null ? {} : basePick(object, paths);
15240    });
15241
15242    /**
vendor: 11,160 bytes, lines 15243-15581
15243     * Creates an object composed of the `object` properties `predicate` returns
15244     * truthy for. The predicate is invoked with two arguments: (value, key).
15245     *
15246     * @static
15247     * @memberOf _
15248     * @since 4.0.0
15249     * @category Object
15250     * @param {Object} object The source object.
15251     * @param {Function} [predicate=_.identity] The function invoked per property.
15252     * @returns {Object} Returns the new object.
15253     * @example
15254     *
15255     * var object = { 'a': 1, 'b': '2', 'c': 3 };
15256     *
15257     * _.pickBy(object, _.isNumber);
15258     * // => { 'a': 1, 'c': 3 }
15259     */
15260    function pickBy(object, predicate) {
15261      if (object == null) {
15262        return {};
15263      }
15264      var props = arrayMap(getAllKeysIn(object), function(prop) {
15265        return [prop];
15266      });
15267      predicate = getIteratee(predicate);
15268      return basePickBy(object, props, function(value, path) {
15269        return predicate(value, path[0]);
15270      });
15271    }
15272
15273    /**
15274     * This method is like `_.get` except that if the resolved value is a
15275     * function it's invoked with the `this` binding of its parent object and
15276     * its result is returned.
15277     *
15278     * @static
15279     * @since 0.1.0
15280     * @memberOf _
15281     * @category Object
15282     * @param {Object} object The object to query.
15283     * @param {Array|string} path The path of the property to resolve.
15284     * @param {*} [defaultValue] The value returned for `undefined` resolved values.
15285     * @returns {*} Returns the resolved value.
15286     * @example
15287     *
15288     * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
15289     *
15290     * _.result(object, 'a[0].b.c1');
15291     * // => 3
15292     *
15293     * _.result(object, 'a[0].b.c2');
15294     * // => 4
15295     *
15296     * _.result(object, 'a[0].b.c3', 'default');
15297     * // => 'default'
15298     *
15299     * _.result(object, 'a[0].b.c3', _.constant('default'));
15300     * // => 'default'
15301     */
15302    function result(object, path, defaultValue) {
15303      path = castPath(path, object);
15304
15305      var index = -1,
15306          length = path.length;
15307
15308      // Ensure the loop is entered when path is empty.
15309      if (!length) {
15310        length = 1;
15311        object = undefined;
15312      }
15313      while (++index < length) {
15314        var value = object == null ? undefined : object[toKey(path[index])];
15315        if (value === undefined) {
15316          index = length;
15317          value = defaultValue;
15318        }
15319        object = isFunction(value) ? value.call(object) : value;
15320      }
15321      return object;
15322    }
15323
15324    /**
15325     * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
15326     * it's created. Arrays are created for missing index properties while objects
15327     * are created for all other missing properties. Use `_.setWith` to customize
15328     * `path` creation.
15329     *
15330     * **Note:** This method mutates `object`.
15331     *
15332     * @static
15333     * @memberOf _
15334     * @since 3.7.0
15335     * @category Object
15336     * @param {Object} object The object to modify.
15337     * @param {Array|string} path The path of the property to set.
15338     * @param {*} value The value to set.
15339     * @returns {Object} Returns `object`.
15340     * @example
15341     *
15342     * var object = { 'a': [{ 'b': { 'c': 3 } }] };
15343     *
15344     * _.set(object, 'a[0].b.c', 4);
15345     * console.log(object.a[0].b.c);
15346     * // => 4
15347     *
15348     * _.set(object, ['x', '0', 'y', 'z'], 5);
15349     * console.log(object.x[0].y.z);
15350     * // => 5
15351     */
15352    function set(object, path, value) {
15353      return object == null ? object : baseSet(object, path, value);
15354    }
15355
15356    /**
15357     * This method is like `_.set` except that it accepts `customizer` which is
15358     * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
15359     * path creation is handled by the method instead. The `customizer` is invoked
15360     * with three arguments: (nsValue, key, nsObject).
15361     *
15362     * **Note:** This method mutates `object`.
15363     *
15364     * @static
15365     * @memberOf _
15366     * @since 4.0.0
15367     * @category Object
15368     * @param {Object} object The object to modify.
15369     * @param {Array|string} path The path of the property to set.
15370     * @param {*} value The value to set.
15371     * @param {Function} [customizer] The function to customize assigned values.
15372     * @returns {Object} Returns `object`.
15373     * @example
15374     *
15375     * var object = {};
15376     *
15377     * _.setWith(object, '[0][1]', 'a', Object);
15378     * // => { '0': { '1': 'a' } }
15379     */
15380    function setWith(object, path, value, customizer) {
15381      customizer = typeof customizer == 'function' ? customizer : undefined;
15382      return object == null ? object : baseSet(object, path, value, customizer);
15383    }
15384
15385    /**
15386     * Creates an array of own enumerable string keyed-value pairs for `object`
15387     * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
15388     * entries are returned.
15389     *
15390     * @static
15391     * @memberOf _
15392     * @since 4.0.0
15393     * @alias entries
15394     * @category Object
15395     * @param {Object} object The object to query.
15396     * @returns {Array} Returns the key-value pairs.
15397     * @example
15398     *
15399     * function Foo() {
15400     *   this.a = 1;
15401     *   this.b = 2;
15402     * }
15403     *
15404     * Foo.prototype.c = 3;
15405     *
15406     * _.toPairs(new Foo);
15407     * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
15408     */
15409    var toPairs = createToPairs(keys);
15410
15411    /**
15412     * Creates an array of own and inherited enumerable string keyed-value pairs
15413     * for `object` which can be consumed by `_.fromPairs`. If `object` is a map
15414     * or set, its entries are returned.
15415     *
15416     * @static
15417     * @memberOf _
15418     * @since 4.0.0
15419     * @alias entriesIn
15420     * @category Object
15421     * @param {Object} object The object to query.
15422     * @returns {Array} Returns the key-value pairs.
15423     * @example
15424     *
15425     * function Foo() {
15426     *   this.a = 1;
15427     *   this.b = 2;
15428     * }
15429     *
15430     * Foo.prototype.c = 3;
15431     *
15432     * _.toPairsIn(new Foo);
15433     * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)
15434     */
15435    var toPairsIn = createToPairs(keysIn);
15436
15437    /**
15438     * An alternative to `_.reduce`; this method transforms `object` to a new
15439     * `accumulator` object which is the result of running each of its own
15440     * enumerable string keyed properties thru `iteratee`, with each invocation
15441     * potentially mutating the `accumulator` object. If `accumulator` is not
15442     * provided, a new object with the same `[[Prototype]]` will be used. The
15443     * iteratee is invoked with four arguments: (accumulator, value, key, object).
15444     * Iteratee functions may exit iteration early by explicitly returning `false`.
15445     *
15446     * @static
15447     * @memberOf _
15448     * @since 1.3.0
15449     * @category Object
15450     * @param {Object} object The object to iterate over.
15451     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
15452     * @param {*} [accumulator] The custom accumulator value.
15453     * @returns {*} Returns the accumulated value.
15454     * @example
15455     *
15456     * _.transform([2, 3, 4], function(result, n) {
15457     *   result.push(n *= n);
15458     *   return n % 2 == 0;
15459     * }, []);
15460     * // => [4, 9]
15461     *
15462     * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
15463     *   (result[value] || (result[value] = [])).push(key);
15464     * }, {});
15465     * // => { '1': ['a', 'c'], '2': ['b'] }
15466     */
15467    function transform(object, iteratee, accumulator) {
15468      var isArr = isArray(object),
15469          isArrLike = isArr || isBuffer(object) || isTypedArray(object);
15470
15471      iteratee = getIteratee(iteratee, 4);
15472      if (accumulator == null) {
15473        var Ctor = object && object.constructor;
15474        if (isArrLike) {
15475          accumulator = isArr ? new Ctor : [];
15476        }
15477        else if (isObject(object)) {
15478          accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};
15479        }
15480        else {
15481          accumulator = {};
15482        }
15483      }
15484      (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) {
15485        return iteratee(accumulator, value, index, object);
15486      });
15487      return accumulator;
15488    }
15489
15490    /**
15491     * Removes the property at `path` of `object`.
15492     *
15493     * **Note:** This method mutates `object`.
15494     *
15495     * @static
15496     * @memberOf _
15497     * @since 4.0.0
15498     * @category Object
15499     * @param {Object} object The object to modify.
15500     * @param {Array|string} path The path of the property to unset.
15501     * @returns {boolean} Returns `true` if the property is deleted, else `false`.
15502     * @example
15503     *
15504     * var object = { 'a': [{ 'b': { 'c': 7 } }] };
15505     * _.unset(object, 'a[0].b.c');
15506     * // => true
15507     *
15508     * console.log(object);
15509     * // => { 'a': [{ 'b': {} }] };
15510     *
15511     * _.unset(object, ['a', '0', 'b', 'c']);
15512     * // => true
15513     *
15514     * console.log(object);
15515     * // => { 'a': [{ 'b': {} }] };
15516     */
15517    function unset(object, path) {
15518      return object == null ? true : baseUnset(object, path);
15519    }
15520
15521    /**
15522     * This method is like `_.set` except that accepts `updater` to produce the
15523     * value to set. Use `_.updateWith` to customize `path` creation. The `updater`
15524     * is invoked with one argument: (value).
15525     *
15526     * **Note:** This method mutates `object`.
15527     *
15528     * @static
15529     * @memberOf _
15530     * @since 4.6.0
15531     * @category Object
15532     * @param {Object} object The object to modify.
15533     * @param {Array|string} path The path of the property to set.
15534     * @param {Function} updater The function to produce the updated value.
15535     * @returns {Object} Returns `object`.
15536     * @example
15537     *
15538     * var object = { 'a': [{ 'b': { 'c': 3 } }] };
15539     *
15540     * _.update(object, 'a[0].b.c', function(n) { return n * n; });
15541     * console.log(object.a[0].b.c);
15542     * // => 9
15543     *
15544     * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });
15545     * console.log(object.x[0].y.z);
15546     * // => 0
15547     */
15548    function update(object, path, updater) {
15549      return object == null ? object : baseUpdate(object, path, castFunction(updater));
15550    }
15551
15552    /**
15553     * This method is like `_.update` except that it accepts `customizer` which is
15554     * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
15555     * path creation is handled by the method instead. The `customizer` is invoked
15556     * with three arguments: (nsValue, key, nsObject).
15557     *
15558     * **Note:** This method mutates `object`.
15559     *
15560     * @static
15561     * @memberOf _
15562     * @since 4.6.0
15563     * @category Object
15564     * @param {Object} object The object to modify.
15565     * @param {Array|string} path The path of the property to set.
15566     * @param {Function} updater The function to produce the updated value.
15567     * @param {Function} [customizer] The function to customize assigned values.
15568     * @returns {Object} Returns `object`.
15569     * @example
15570     *
15571     * var object = {};
15572     *
15573     * _.updateWith(object, '[0][1]', _.constant('a'), Object);
15574     * // => { '0': { '1': 'a' } }
15575     */
15576    function updateWith(object, path, updater, customizer) {
15577      customizer = typeof customizer == 'function' ? customizer : undefined;
15578      return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);
15579    }
15580
15581    /**
vendor: 1,263 bytes, lines 15582-15631
15582     * Creates an array of the own enumerable string keyed property values of `object`.
15583     *
15584     * **Note:** Non-object values are coerced to objects.
15585     *
15586     * @static
15587     * @since 0.1.0
15588     * @memberOf _
15589     * @category Object
15590     * @param {Object} object The object to query.
15591     * @returns {Array} Returns the array of property values.
15592     * @example
15593     *
15594     * function Foo() {
15595     *   this.a = 1;
15596     *   this.b = 2;
15597     * }
15598     *
15599     * Foo.prototype.c = 3;
15600     *
15601     * _.values(new Foo);
15602     * // => [1, 2] (iteration order is not guaranteed)
15603     *
15604     * _.values('hi');
15605     * // => ['h', 'i']
15606     */
15607    function values(object) {
15608      return object == null ? [] : baseValues(object, keys(object));
15609    }
15610
15611    /**
15612     * Creates an array of the own and inherited enumerable string keyed property
15613     * values of `object`.
15614     *
15615     * **Note:** Non-object values are coerced to objects.
15616     *
15617     * @static
15618     * @memberOf _
15619     * @since 3.0.0
15620     * @category Object
15621     * @param {Object} object The object to query.
15622     * @returns {Array} Returns the array of property values.
15623     * @example
15624     *
15625     * function Foo() {
15626     *   this.a = 1;
15627     *   this.b = 2;
15628     * }
15629     *
15630     * Foo.prototype.c = 3;
15631     *
vendor: 9,679 bytes, lines 15632-15952
15632     * _.valuesIn(new Foo);
15633     * // => [1, 2, 3] (iteration order is not guaranteed)
15634     */
15635    function valuesIn(object) {
15636      return object == null ? [] : baseValues(object, keysIn(object));
15637    }
15638
15639    /*------------------------------------------------------------------------*/
15640
15641    /**
15642     * Clamps `number` within the inclusive `lower` and `upper` bounds.
15643     *
15644     * @static
15645     * @memberOf _
15646     * @since 4.0.0
15647     * @category Number
15648     * @param {number} number The number to clamp.
15649     * @param {number} [lower] The lower bound.
15650     * @param {number} upper The upper bound.
15651     * @returns {number} Returns the clamped number.
15652     * @example
15653     *
15654     * _.clamp(-10, -5, 5);
15655     * // => -5
15656     *
15657     * _.clamp(10, -5, 5);
15658     * // => 5
15659     */
15660    function clamp(number, lower, upper) {
15661      if (upper === undefined) {
15662        upper = lower;
15663        lower = undefined;
15664      }
15665      if (upper !== undefined) {
15666        upper = toNumber(upper);
15667        upper = upper === upper ? upper : 0;
15668      }
15669      if (lower !== undefined) {
15670        lower = toNumber(lower);
15671        lower = lower === lower ? lower : 0;
15672      }
15673      return baseClamp(toNumber(number), lower, upper);
15674    }
15675
15676    /**
15677     * Checks if `n` is between `start` and up to, but not including, `end`. If
15678     * `end` is not specified, it's set to `start` with `start` then set to `0`.
15679     * If `start` is greater than `end` the params are swapped to support
15680     * negative ranges.
15681     *
15682     * @static
15683     * @memberOf _
15684     * @since 3.3.0
15685     * @category Number
15686     * @param {number} number The number to check.
15687     * @param {number} [start=0] The start of the range.
15688     * @param {number} end The end of the range.
15689     * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
15690     * @see _.range, _.rangeRight
15691     * @example
15692     *
15693     * _.inRange(3, 2, 4);
15694     * // => true
15695     *
15696     * _.inRange(4, 8);
15697     * // => true
15698     *
15699     * _.inRange(4, 2);
15700     * // => false
15701     *
15702     * _.inRange(2, 2);
15703     * // => false
15704     *
15705     * _.inRange(1.2, 2);
15706     * // => true
15707     *
15708     * _.inRange(5.2, 4);
15709     * // => false
15710     *
15711     * _.inRange(-3, -2, -6);
15712     * // => true
15713     */
15714    function inRange(number, start, end) {
15715      start = toFinite(start);
15716      if (end === undefined) {
15717        end = start;
15718        start = 0;
15719      } else {
15720        end = toFinite(end);
15721      }
15722      number = toNumber(number);
15723      return baseInRange(number, start, end);
15724    }
15725
15726    /**
15727     * Produces a random number between the inclusive `lower` and `upper` bounds.
15728     * If only one argument is provided a number between `0` and the given number
15729     * is returned. If `floating` is `true`, or either `lower` or `upper` are
15730     * floats, a floating-point number is returned instead of an integer.
15731     *
15732     * **Note:** JavaScript follows the IEEE-754 standard for resolving
15733     * floating-point values which can produce unexpected results.
15734     *
15735     * @static
15736     * @memberOf _
15737     * @since 0.7.0
15738     * @category Number
15739     * @param {number} [lower=0] The lower bound.
15740     * @param {number} [upper=1] The upper bound.
15741     * @param {boolean} [floating] Specify returning a floating-point number.
15742     * @returns {number} Returns the random number.
15743     * @example
15744     *
15745     * _.random(0, 5);
15746     * // => an integer between 0 and 5
15747     *
15748     * _.random(5);
15749     * // => also an integer between 0 and 5
15750     *
15751     * _.random(5, true);
15752     * // => a floating-point number between 0 and 5
15753     *
15754     * _.random(1.2, 5.2);
15755     * // => a floating-point number between 1.2 and 5.2
15756     */
15757    function random(lower, upper, floating) {
15758      if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) {
15759        upper = floating = undefined;
15760      }
15761      if (floating === undefined) {
15762        if (typeof upper == 'boolean') {
15763          floating = upper;
15764          upper = undefined;
15765        }
15766        else if (typeof lower == 'boolean') {
15767          floating = lower;
15768          lower = undefined;
15769        }
15770      }
15771      if (lower === undefined && upper === undefined) {
15772        lower = 0;
15773        upper = 1;
15774      }
15775      else {
15776        lower = toFinite(lower);
15777        if (upper === undefined) {
15778          upper = lower;
15779          lower = 0;
15780        } else {
15781          upper = toFinite(upper);
15782        }
15783      }
15784      if (lower > upper) {
15785        var temp = lower;
15786        lower = upper;
15787        upper = temp;
15788      }
15789      if (floating || lower % 1 || upper % 1) {
15790        var rand = nativeRandom();
15791        return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper);
15792      }
15793      return baseRandom(lower, upper);
15794    }
15795
15796    /*------------------------------------------------------------------------*/
15797
15798    /**
15799     * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
15800     *
15801     * @static
15802     * @memberOf _
15803     * @since 3.0.0
15804     * @category String
15805     * @param {string} [string=''] The string to convert.
15806     * @returns {string} Returns the camel cased string.
15807     * @example
15808     *
15809     * _.camelCase('Foo Bar');
15810     * // => 'fooBar'
15811     *
15812     * _.camelCase('--foo-bar--');
15813     * // => 'fooBar'
15814     *
15815     * _.camelCase('__FOO_BAR__');
15816     * // => 'fooBar'
15817     */
15818    var camelCase = createCompounder(function(result, word, index) {
15819      word = word.toLowerCase();
15820      return result + (index ? capitalize(word) : word);
15821    });
15822
15823    /**
15824     * Converts the first character of `string` to upper case and the remaining
15825     * to lower case.
15826     *
15827     * @static
15828     * @memberOf _
15829     * @since 3.0.0
15830     * @category String
15831     * @param {string} [string=''] The string to capitalize.
15832     * @returns {string} Returns the capitalized string.
15833     * @example
15834     *
15835     * _.capitalize('FRED');
15836     * // => 'Fred'
15837     */
15838    function capitalize(string) {
15839      return upperFirst(toString(string).toLowerCase());
15840    }
15841
15842    /**
15843     * Deburrs `string` by converting
15844     * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
15845     * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
15846     * letters to basic Latin letters and removing
15847     * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
15848     *
15849     * @static
15850     * @memberOf _
15851     * @since 3.0.0
15852     * @category String
15853     * @param {string} [string=''] The string to deburr.
15854     * @returns {string} Returns the deburred string.
15855     * @example
15856     *
15857     * _.deburr('déjà vu');
15858     * // => 'deja vu'
15859     */
15860    function deburr(string) {
15861      string = toString(string);
15862      return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
15863    }
15864
15865    /**
15866     * Checks if `string` ends with the given target string.
15867     *
15868     * @static
15869     * @memberOf _
15870     * @since 3.0.0
15871     * @category String
15872     * @param {string} [string=''] The string to inspect.
15873     * @param {string} [target] The string to search for.
15874     * @param {number} [position=string.length] The position to search up to.
15875     * @returns {boolean} Returns `true` if `string` ends with `target`,
15876     *  else `false`.
15877     * @example
15878     *
15879     * _.endsWith('abc', 'c');
15880     * // => true
15881     *
15882     * _.endsWith('abc', 'b');
15883     * // => false
15884     *
15885     * _.endsWith('abc', 'b', 2);
15886     * // => true
15887     */
15888    function endsWith(string, target, position) {
15889      string = toString(string);
15890      target = baseToString(target);
15891
15892      var length = string.length;
15893      position = position === undefined
15894        ? length
15895        : baseClamp(toInteger(position), 0, length);
15896
15897      var end = position;
15898      position -= target.length;
15899      return position >= 0 && string.slice(position, end) == target;
15900    }
15901
15902    /**
15903     * Converts the characters "&", "<", ">", '"', and "'" in `string` to their
15904     * corresponding HTML entities.
15905     *
15906     * **Note:** No other characters are escaped. To escape additional
15907     * characters use a third-party library like [_he_](https://mths.be/he).
15908     *
15909     * Though the ">" character is escaped for symmetry, characters like
15910     * ">" and "/" don't need escaping in HTML and have no special meaning
15911     * unless they're part of a tag or unquoted attribute value. See
15912     * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
15913     * (under "semi-related fun fact") for more details.
15914     *
15915     * When working with HTML you should always
15916     * [quote attribute values](http://wonko.com/post/html-escaping) to reduce
15917     * XSS vectors.
15918     *
15919     * @static
15920     * @since 0.1.0
15921     * @memberOf _
15922     * @category String
15923     * @param {string} [string=''] The string to escape.
15924     * @returns {string} Returns the escaped string.
15925     * @example
15926     *
15927     * _.escape('fred, barney, & pebbles');
15928     * // => 'fred, barney, &amp; pebbles'
15929     */
15930    function escape(string) {
15931      string = toString(string);
15932      return (string && reHasUnescapedHtml.test(string))
15933        ? string.replace(reUnescapedHtml, escapeHtmlChar)
15934        : string;
15935    }
15936
15937    /**
15938     * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
15939     * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
15940     *
15941     * @static
15942     * @memberOf _
15943     * @since 3.0.0
15944     * @category String
15945     * @param {string} [string=''] The string to escape.
15946     * @returns {string} Returns the escaped string.
15947     * @example
15948     *
15949     * _.escapeRegExp('[lodash](https://lodash.com/)');
15950     * // => '\[lodash\]\(https://lodash\.com/\)'
15951     */
15952    function escapeRegExp(string) {
vendor: 4,658 bytes, lines 15953-16122
15953      string = toString(string);
15954      return (string && reHasRegExpChar.test(string))
15955        ? string.replace(reRegExpChar, '\\$&')
15956        : string;
15957    }
15958
15959    /**
15960     * Converts `string` to
15961     * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
15962     *
15963     * @static
15964     * @memberOf _
15965     * @since 3.0.0
15966     * @category String
15967     * @param {string} [string=''] The string to convert.
15968     * @returns {string} Returns the kebab cased string.
15969     * @example
15970     *
15971     * _.kebabCase('Foo Bar');
15972     * // => 'foo-bar'
15973     *
15974     * _.kebabCase('fooBar');
15975     * // => 'foo-bar'
15976     *
15977     * _.kebabCase('__FOO_BAR__');
15978     * // => 'foo-bar'
15979     */
15980    var kebabCase = createCompounder(function(result, word, index) {
15981      return result + (index ? '-' : '') + word.toLowerCase();
15982    });
15983
15984    /**
15985     * Converts `string`, as space separated words, to lower case.
15986     *
15987     * @static
15988     * @memberOf _
15989     * @since 4.0.0
15990     * @category String
15991     * @param {string} [string=''] The string to convert.
15992     * @returns {string} Returns the lower cased string.
15993     * @example
15994     *
15995     * _.lowerCase('--Foo-Bar--');
15996     * // => 'foo bar'
15997     *
15998     * _.lowerCase('fooBar');
15999     * // => 'foo bar'
16000     *
16001     * _.lowerCase('__FOO_BAR__');
16002     * // => 'foo bar'
16003     */
16004    var lowerCase = createCompounder(function(result, word, index) {
16005      return result + (index ? ' ' : '') + word.toLowerCase();
16006    });
16007
16008    /**
16009     * Converts the first character of `string` to lower case.
16010     *
16011     * @static
16012     * @memberOf _
16013     * @since 4.0.0
16014     * @category String
16015     * @param {string} [string=''] The string to convert.
16016     * @returns {string} Returns the converted string.
16017     * @example
16018     *
16019     * _.lowerFirst('Fred');
16020     * // => 'fred'
16021     *
16022     * _.lowerFirst('FRED');
16023     * // => 'fRED'
16024     */
16025    var lowerFirst = createCaseFirst('toLowerCase');
16026
16027    /**
16028     * Pads `string` on the left and right sides if it's shorter than `length`.
16029     * Padding characters are truncated if they can't be evenly divided by `length`.
16030     *
16031     * @static
16032     * @memberOf _
16033     * @since 3.0.0
16034     * @category String
16035     * @param {string} [string=''] The string to pad.
16036     * @param {number} [length=0] The padding length.
16037     * @param {string} [chars=' '] The string used as padding.
16038     * @returns {string} Returns the padded string.
16039     * @example
16040     *
16041     * _.pad('abc', 8);
16042     * // => '  abc   '
16043     *
16044     * _.pad('abc', 8, '_-');
16045     * // => '_-abc_-_'
16046     *
16047     * _.pad('abc', 3);
16048     * // => 'abc'
16049     */
16050    function pad(string, length, chars) {
16051      string = toString(string);
16052      length = toInteger(length);
16053
16054      var strLength = length ? stringSize(string) : 0;
16055      if (!length || strLength >= length) {
16056        return string;
16057      }
16058      var mid = (length - strLength) / 2;
16059      return (
16060        createPadding(nativeFloor(mid), chars) +
16061        string +
16062        createPadding(nativeCeil(mid), chars)
16063      );
16064    }
16065
16066    /**
16067     * Pads `string` on the right side if it's shorter than `length`. Padding
16068     * characters are truncated if they exceed `length`.
16069     *
16070     * @static
16071     * @memberOf _
16072     * @since 4.0.0
16073     * @category String
16074     * @param {string} [string=''] The string to pad.
16075     * @param {number} [length=0] The padding length.
16076     * @param {string} [chars=' '] The string used as padding.
16077     * @returns {string} Returns the padded string.
16078     * @example
16079     *
16080     * _.padEnd('abc', 6);
16081     * // => 'abc   '
16082     *
16083     * _.padEnd('abc', 6, '_-');
16084     * // => 'abc_-_'
16085     *
16086     * _.padEnd('abc', 3);
16087     * // => 'abc'
16088     */
16089    function padEnd(string, length, chars) {
16090      string = toString(string);
16091      length = toInteger(length);
16092
16093      var strLength = length ? stringSize(string) : 0;
16094      return (length && strLength < length)
16095        ? (string + createPadding(length - strLength, chars))
16096        : string;
16097    }
16098
16099    /**
16100     * Pads `string` on the left side if it's shorter than `length`. Padding
16101     * characters are truncated if they exceed `length`.
16102     *
16103     * @static
16104     * @memberOf _
16105     * @since 4.0.0
16106     * @category String
16107     * @param {string} [string=''] The string to pad.
16108     * @param {number} [length=0] The padding length.
16109     * @param {string} [chars=' '] The string used as padding.
16110     * @returns {string} Returns the padded string.
16111     * @example
16112     *
16113     * _.padStart('abc', 6);
16114     * // => '   abc'
16115     *
16116     * _.padStart('abc', 6, '_-');
16117     * // => '_-_abc'
16118     *
16119     * _.padStart('abc', 3);
16120     * // => 'abc'
16121     */
16122    function padStart(string, length, chars) {
vendor: 29,827 bytes, lines 16123-17020
16123      string = toString(string);
16124      length = toInteger(length);
16125
16126      var strLength = length ? stringSize(string) : 0;
16127      return (length && strLength < length)
16128        ? (createPadding(length - strLength, chars) + string)
16129        : string;
16130    }
16131
16132    /**
16133     * Converts `string` to an integer of the specified radix. If `radix` is
16134     * `undefined` or `0`, a `radix` of `10` is used unless `value` is a
16135     * hexadecimal, in which case a `radix` of `16` is used.
16136     *
16137     * **Note:** This method aligns with the
16138     * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.
16139     *
16140     * @static
16141     * @memberOf _
16142     * @since 1.1.0
16143     * @category String
16144     * @param {string} string The string to convert.
16145     * @param {number} [radix=10] The radix to interpret `value` by.
16146     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
16147     * @returns {number} Returns the converted integer.
16148     * @example
16149     *
16150     * _.parseInt('08');
16151     * // => 8
16152     *
16153     * _.map(['6', '08', '10'], _.parseInt);
16154     * // => [6, 8, 10]
16155     */
16156    function parseInt(string, radix, guard) {
16157      if (guard || radix == null) {
16158        radix = 0;
16159      } else if (radix) {
16160        radix = +radix;
16161      }
16162      return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0);
16163    }
16164
16165    /**
16166     * Repeats the given string `n` times.
16167     *
16168     * @static
16169     * @memberOf _
16170     * @since 3.0.0
16171     * @category String
16172     * @param {string} [string=''] The string to repeat.
16173     * @param {number} [n=1] The number of times to repeat the string.
16174     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
16175     * @returns {string} Returns the repeated string.
16176     * @example
16177     *
16178     * _.repeat('*', 3);
16179     * // => '***'
16180     *
16181     * _.repeat('abc', 2);
16182     * // => 'abcabc'
16183     *
16184     * _.repeat('abc', 0);
16185     * // => ''
16186     */
16187    function repeat(string, n, guard) {
16188      if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) {
16189        n = 1;
16190      } else {
16191        n = toInteger(n);
16192      }
16193      return baseRepeat(toString(string), n);
16194    }
16195
16196    /**
16197     * Replaces matches for `pattern` in `string` with `replacement`.
16198     *
16199     * **Note:** This method is based on
16200     * [`String#replace`](https://mdn.io/String/replace).
16201     *
16202     * @static
16203     * @memberOf _
16204     * @since 4.0.0
16205     * @category String
16206     * @param {string} [string=''] The string to modify.
16207     * @param {RegExp|string} pattern The pattern to replace.
16208     * @param {Function|string} replacement The match replacement.
16209     * @returns {string} Returns the modified string.
16210     * @example
16211     *
16212     * _.replace('Hi Fred', 'Fred', 'Barney');
16213     * // => 'Hi Barney'
16214     */
16215    function replace() {
16216      var args = arguments,
16217          string = toString(args[0]);
16218
16219      return args.length < 3 ? string : string.replace(args[1], args[2]);
16220    }
16221
16222    /**
16223     * Converts `string` to
16224     * [snake case](https://en.wikipedia.org/wiki/Snake_case).
16225     *
16226     * @static
16227     * @memberOf _
16228     * @since 3.0.0
16229     * @category String
16230     * @param {string} [string=''] The string to convert.
16231     * @returns {string} Returns the snake cased string.
16232     * @example
16233     *
16234     * _.snakeCase('Foo Bar');
16235     * // => 'foo_bar'
16236     *
16237     * _.snakeCase('fooBar');
16238     * // => 'foo_bar'
16239     *
16240     * _.snakeCase('--FOO-BAR--');
16241     * // => 'foo_bar'
16242     */
16243    var snakeCase = createCompounder(function(result, word, index) {
16244      return result + (index ? '_' : '') + word.toLowerCase();
16245    });
16246
16247    /**
16248     * Splits `string` by `separator`.
16249     *
16250     * **Note:** This method is based on
16251     * [`String#split`](https://mdn.io/String/split).
16252     *
16253     * @static
16254     * @memberOf _
16255     * @since 4.0.0
16256     * @category String
16257     * @param {string} [string=''] The string to split.
16258     * @param {RegExp|string} separator The separator pattern to split by.
16259     * @param {number} [limit] The length to truncate results to.
16260     * @returns {Array} Returns the string segments.
16261     * @example
16262     *
16263     * _.split('a-b-c', '-', 2);
16264     * // => ['a', 'b']
16265     */
16266    function split(string, separator, limit) {
16267      if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) {
16268        separator = limit = undefined;
16269      }
16270      limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0;
16271      if (!limit) {
16272        return [];
16273      }
16274      string = toString(string);
16275      if (string && (
16276            typeof separator == 'string' ||
16277            (separator != null && !isRegExp(separator))
16278          )) {
16279        separator = baseToString(separator);
16280        if (!separator && hasUnicode(string)) {
16281          return castSlice(stringToArray(string), 0, limit);
16282        }
16283      }
16284      return string.split(separator, limit);
16285    }
16286
16287    /**
16288     * Converts `string` to
16289     * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
16290     *
16291     * @static
16292     * @memberOf _
16293     * @since 3.1.0
16294     * @category String
16295     * @param {string} [string=''] The string to convert.
16296     * @returns {string} Returns the start cased string.
16297     * @example
16298     *
16299     * _.startCase('--foo-bar--');
16300     * // => 'Foo Bar'
16301     *
16302     * _.startCase('fooBar');
16303     * // => 'Foo Bar'
16304     *
16305     * _.startCase('__FOO_BAR__');
16306     * // => 'FOO BAR'
16307     */
16308    var startCase = createCompounder(function(result, word, index) {
16309      return result + (index ? ' ' : '') + upperFirst(word);
16310    });
16311
16312    /**
16313     * Checks if `string` starts with the given target string.
16314     *
16315     * @static
16316     * @memberOf _
16317     * @since 3.0.0
16318     * @category String
16319     * @param {string} [string=''] The string to inspect.
16320     * @param {string} [target] The string to search for.
16321     * @param {number} [position=0] The position to search from.
16322     * @returns {boolean} Returns `true` if `string` starts with `target`,
16323     *  else `false`.
16324     * @example
16325     *
16326     * _.startsWith('abc', 'a');
16327     * // => true
16328     *
16329     * _.startsWith('abc', 'b');
16330     * // => false
16331     *
16332     * _.startsWith('abc', 'b', 1);
16333     * // => true
16334     */
16335    function startsWith(string, target, position) {
16336      string = toString(string);
16337      position = position == null
16338        ? 0
16339        : baseClamp(toInteger(position), 0, string.length);
16340
16341      target = baseToString(target);
16342      return string.slice(position, position + target.length) == target;
16343    }
16344
16345    /**
16346     * Creates a compiled template function that can interpolate data properties
16347     * in "interpolate" delimiters, HTML-escape interpolated data properties in
16348     * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
16349     * properties may be accessed as free variables in the template. If a setting
16350     * object is given, it takes precedence over `_.templateSettings` values.
16351     *
16352     * **Note:** In the development build `_.template` utilizes
16353     * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
16354     * for easier debugging.
16355     *
16356     * For more information on precompiling templates see
16357     * [lodash's custom builds documentation](https://lodash.com/custom-builds).
16358     *
16359     * For more information on Chrome extension sandboxes see
16360     * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
16361     *
16362     * @static
16363     * @since 0.1.0
16364     * @memberOf _
16365     * @category String
16366     * @param {string} [string=''] The template string.
16367     * @param {Object} [options={}] The options object.
16368     * @param {RegExp} [options.escape=_.templateSettings.escape]
16369     *  The HTML "escape" delimiter.
16370     * @param {RegExp} [options.evaluate=_.templateSettings.evaluate]
16371     *  The "evaluate" delimiter.
16372     * @param {Object} [options.imports=_.templateSettings.imports]
16373     *  An object to import into the template as free variables.
16374     * @param {RegExp} [options.interpolate=_.templateSettings.interpolate]
16375     *  The "interpolate" delimiter.
16376     * @param {string} [options.sourceURL='lodash.templateSources[n]']
16377     *  The sourceURL of the compiled template.
16378     * @param {string} [options.variable='obj']
16379     *  The data object variable name.
16380     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
16381     * @returns {Function} Returns the compiled template function.
16382     * @example
16383     *
16384     * // Use the "interpolate" delimiter to create a compiled template.
16385     * var compiled = _.template('hello <%= user %>!');
16386     * compiled({ 'user': 'fred' });
16387     * // => 'hello fred!'
16388     *
16389     * // Use the HTML "escape" delimiter to escape data property values.
16390     * var compiled = _.template('<b><%- value %></b>');
16391     * compiled({ 'value': '<script>' });
16392     * // => '<b>&lt;script&gt;</b>'
16393     *
16394     * // Use the "evaluate" delimiter to execute JavaScript and generate HTML.
16395     * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
16396     * compiled({ 'users': ['fred', 'barney'] });
16397     * // => '<li>fred</li><li>barney</li>'
16398     *
16399     * // Use the internal `print` function in "evaluate" delimiters.
16400     * var compiled = _.template('<% print("hello " + user); %>!');
16401     * compiled({ 'user': 'barney' });
16402     * // => 'hello barney!'
16403     *
16404     * // Use the ES template literal delimiter as an "interpolate" delimiter.
16405     * // Disable support by replacing the "interpolate" delimiter.
16406     * var compiled = _.template('hello ${ user }!');
16407     * compiled({ 'user': 'pebbles' });
16408     * // => 'hello pebbles!'
16409     *
16410     * // Use backslashes to treat delimiters as plain text.
16411     * var compiled = _.template('<%= "\\<%- value %\\>" %>');
16412     * compiled({ 'value': 'ignored' });
16413     * // => '<%- value %>'
16414     *
16415     * // Use the `imports` option to import `jQuery` as `jq`.
16416     * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
16417     * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
16418     * compiled({ 'users': ['fred', 'barney'] });
16419     * // => '<li>fred</li><li>barney</li>'
16420     *
16421     * // Use the `sourceURL` option to specify a custom sourceURL for the template.
16422     * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
16423     * compiled(data);
16424     * // => Find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector.
16425     *
16426     * // Use the `variable` option to ensure a with-statement isn't used in the compiled template.
16427     * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
16428     * compiled.source;
16429     * // => function(data) {
16430     * //   var __t, __p = '';
16431     * //   __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
16432     * //   return __p;
16433     * // }
16434     *
16435     * // Use custom template delimiters.
16436     * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
16437     * var compiled = _.template('hello {{ user }}!');
16438     * compiled({ 'user': 'mustache' });
16439     * // => 'hello mustache!'
16440     *
16441     * // Use the `source` property to inline compiled templates for meaningful
16442     * // line numbers in error messages and stack traces.
16443     * fs.writeFileSync(path.join(process.cwd(), 'jst.js'), '\
16444     *   var JST = {\
16445     *     "main": ' + _.template(mainText).source + '\
16446     *   };\
16447     * ');
16448     */
16449    function template(string, options, guard) {
16450      // Based on John Resig's `tmpl` implementation
16451      // (http://ejohn.org/blog/javascript-micro-templating/)
16452      // and Laura Doktorova's doT.js (https://github.com/olado/doT).
16453      var settings = lodash.templateSettings;
16454
16455      if (guard && isIterateeCall(string, options, guard)) {
16456        options = undefined;
16457      }
16458      string = toString(string);
16459      options = assignInWith({}, options, settings, customDefaultsAssignIn);
16460
16461      var imports = assignInWith({}, options.imports, settings.imports, customDefaultsAssignIn),
16462          importsKeys = keys(imports),
16463          importsValues = baseValues(imports, importsKeys);
16464
16465      var isEscaping,
16466          isEvaluating,
16467          index = 0,
16468          interpolate = options.interpolate || reNoMatch,
16469          source = "__p += '";
16470
16471      // Compile the regexp to match each delimiter.
16472      var reDelimiters = RegExp(
16473        (options.escape || reNoMatch).source + '|' +
16474        interpolate.source + '|' +
16475        (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
16476        (options.evaluate || reNoMatch).source + '|$'
16477      , 'g');
16478
16479      // Use a sourceURL for easier debugging.
16480      // The sourceURL gets injected into the source that's eval-ed, so be careful
16481      // to normalize all kinds of whitespace, so e.g. newlines (and unicode versions of it) can't sneak in
16482      // and escape the comment, thus injecting code that gets evaled.
16483      var sourceURL = '//# sourceURL=' +
16484        (hasOwnProperty.call(options, 'sourceURL')
16485          ? (options.sourceURL + '').replace(/\s/g, ' ')
16486          : ('lodash.templateSources[' + (++templateCounter) + ']')
16487        ) + '\n';
16488
16489      string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
16490        interpolateValue || (interpolateValue = esTemplateValue);
16491
16492        // Escape characters that can't be included in string literals.
16493        source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
16494
16495        // Replace delimiters with snippets.
16496        if (escapeValue) {
16497          isEscaping = true;
16498          source += "' +\n__e(" + escapeValue + ") +\n'";
16499        }
16500        if (evaluateValue) {
16501          isEvaluating = true;
16502          source += "';\n" + evaluateValue + ";\n__p += '";
16503        }
16504        if (interpolateValue) {
16505          source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
16506        }
16507        index = offset + match.length;
16508
16509        // The JS engine embedded in Adobe products needs `match` returned in
16510        // order to produce the correct `offset` value.
16511        return match;
16512      });
16513
16514      source += "';\n";
16515
16516      // If `variable` is not specified wrap a with-statement around the generated
16517      // code to add the data object to the top of the scope chain.
16518      var variable = hasOwnProperty.call(options, 'variable') && options.variable;
16519      if (!variable) {
16520        source = 'with (obj) {\n' + source + '\n}\n';
16521      }
16522      // Throw an error if a forbidden character was found in `variable`, to prevent
16523      // potential command injection attacks.
16524      else if (reForbiddenIdentifierChars.test(variable)) {
16525        throw new Error(INVALID_TEMPL_VAR_ERROR_TEXT);
16526      }
16527
16528      // Cleanup code by stripping empty strings.
16529      source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
16530        .replace(reEmptyStringMiddle, '$1')
16531        .replace(reEmptyStringTrailing, '$1;');
16532
16533      // Frame code as the function body.
16534      source = 'function(' + (variable || 'obj') + ') {\n' +
16535        (variable
16536          ? ''
16537          : 'obj || (obj = {});\n'
16538        ) +
16539        "var __t, __p = ''" +
16540        (isEscaping
16541           ? ', __e = _.escape'
16542           : ''
16543        ) +
16544        (isEvaluating
16545          ? ', __j = Array.prototype.join;\n' +
16546            "function print() { __p += __j.call(arguments, '') }\n"
16547          : ';\n'
16548        ) +
16549        source +
16550        'return __p\n}';
16551
16552      var result = attempt(function() {
16553        return Function(importsKeys, sourceURL + 'return ' + source)
16554          .apply(undefined, importsValues);
16555      });
16556
16557      // Provide the compiled function's source by its `toString` method or
16558      // the `source` property as a convenience for inlining compiled templates.
16559      result.source = source;
16560      if (isError(result)) {
16561        throw result;
16562      }
16563      return result;
16564    }
16565
16566    /**
16567     * Converts `string`, as a whole, to lower case just like
16568     * [String#toLowerCase](https://mdn.io/toLowerCase).
16569     *
16570     * @static
16571     * @memberOf _
16572     * @since 4.0.0
16573     * @category String
16574     * @param {string} [string=''] The string to convert.
16575     * @returns {string} Returns the lower cased string.
16576     * @example
16577     *
16578     * _.toLower('--Foo-Bar--');
16579     * // => '--foo-bar--'
16580     *
16581     * _.toLower('fooBar');
16582     * // => 'foobar'
16583     *
16584     * _.toLower('__FOO_BAR__');
16585     * // => '__foo_bar__'
16586     */
16587    function toLower(value) {
16588      return toString(value).toLowerCase();
16589    }
16590
16591    /**
16592     * Converts `string`, as a whole, to upper case just like
16593     * [String#toUpperCase](https://mdn.io/toUpperCase).
16594     *
16595     * @static
16596     * @memberOf _
16597     * @since 4.0.0
16598     * @category String
16599     * @param {string} [string=''] The string to convert.
16600     * @returns {string} Returns the upper cased string.
16601     * @example
16602     *
16603     * _.toUpper('--foo-bar--');
16604     * // => '--FOO-BAR--'
16605     *
16606     * _.toUpper('fooBar');
16607     * // => 'FOOBAR'
16608     *
16609     * _.toUpper('__foo_bar__');
16610     * // => '__FOO_BAR__'
16611     */
16612    function toUpper(value) {
16613      return toString(value).toUpperCase();
16614    }
16615
16616    /**
16617     * Removes leading and trailing whitespace or specified characters from `string`.
16618     *
16619     * @static
16620     * @memberOf _
16621     * @since 3.0.0
16622     * @category String
16623     * @param {string} [string=''] The string to trim.
16624     * @param {string} [chars=whitespace] The characters to trim.
16625     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
16626     * @returns {string} Returns the trimmed string.
16627     * @example
16628     *
16629     * _.trim('  abc  ');
16630     * // => 'abc'
16631     *
16632     * _.trim('-_-abc-_-', '_-');
16633     * // => 'abc'
16634     *
16635     * _.map(['  foo  ', '  bar  '], _.trim);
16636     * // => ['foo', 'bar']
16637     */
16638    function trim(string, chars, guard) {
16639      string = toString(string);
16640      if (string && (guard || chars === undefined)) {
16641        return baseTrim(string);
16642      }
16643      if (!string || !(chars = baseToString(chars))) {
16644        return string;
16645      }
16646      var strSymbols = stringToArray(string),
16647          chrSymbols = stringToArray(chars),
16648          start = charsStartIndex(strSymbols, chrSymbols),
16649          end = charsEndIndex(strSymbols, chrSymbols) + 1;
16650
16651      return castSlice(strSymbols, start, end).join('');
16652    }
16653
16654    /**
16655     * Removes trailing whitespace or specified characters from `string`.
16656     *
16657     * @static
16658     * @memberOf _
16659     * @since 4.0.0
16660     * @category String
16661     * @param {string} [string=''] The string to trim.
16662     * @param {string} [chars=whitespace] The characters to trim.
16663     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
16664     * @returns {string} Returns the trimmed string.
16665     * @example
16666     *
16667     * _.trimEnd('  abc  ');
16668     * // => '  abc'
16669     *
16670     * _.trimEnd('-_-abc-_-', '_-');
16671     * // => '-_-abc'
16672     */
16673    function trimEnd(string, chars, guard) {
16674      string = toString(string);
16675      if (string && (guard || chars === undefined)) {
16676        return string.slice(0, trimmedEndIndex(string) + 1);
16677      }
16678      if (!string || !(chars = baseToString(chars))) {
16679        return string;
16680      }
16681      var strSymbols = stringToArray(string),
16682          end = charsEndIndex(strSymbols, stringToArray(chars)) + 1;
16683
16684      return castSlice(strSymbols, 0, end).join('');
16685    }
16686
16687    /**
16688     * Removes leading whitespace or specified characters from `string`.
16689     *
16690     * @static
16691     * @memberOf _
16692     * @since 4.0.0
16693     * @category String
16694     * @param {string} [string=''] The string to trim.
16695     * @param {string} [chars=whitespace] The characters to trim.
16696     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
16697     * @returns {string} Returns the trimmed string.
16698     * @example
16699     *
16700     * _.trimStart('  abc  ');
16701     * // => 'abc  '
16702     *
16703     * _.trimStart('-_-abc-_-', '_-');
16704     * // => 'abc-_-'
16705     */
16706    function trimStart(string, chars, guard) {
16707      string = toString(string);
16708      if (string && (guard || chars === undefined)) {
16709        return string.replace(reTrimStart, '');
16710      }
16711      if (!string || !(chars = baseToString(chars))) {
16712        return string;
16713      }
16714      var strSymbols = stringToArray(string),
16715          start = charsStartIndex(strSymbols, stringToArray(chars));
16716
16717      return castSlice(strSymbols, start).join('');
16718    }
16719
16720    /**
16721     * Truncates `string` if it's longer than the given maximum string length.
16722     * The last characters of the truncated string are replaced with the omission
16723     * string which defaults to "...".
16724     *
16725     * @static
16726     * @memberOf _
16727     * @since 4.0.0
16728     * @category String
16729     * @param {string} [string=''] The string to truncate.
16730     * @param {Object} [options={}] The options object.
16731     * @param {number} [options.length=30] The maximum string length.
16732     * @param {string} [options.omission='...'] The string to indicate text is omitted.
16733     * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
16734     * @returns {string} Returns the truncated string.
16735     * @example
16736     *
16737     * _.truncate('hi-diddly-ho there, neighborino');
16738     * // => 'hi-diddly-ho there, neighbo...'
16739     *
16740     * _.truncate('hi-diddly-ho there, neighborino', {
16741     *   'length': 24,
16742     *   'separator': ' '
16743     * });
16744     * // => 'hi-diddly-ho there,...'
16745     *
16746     * _.truncate('hi-diddly-ho there, neighborino', {
16747     *   'length': 24,
16748     *   'separator': /,? +/
16749     * });
16750     * // => 'hi-diddly-ho there...'
16751     *
16752     * _.truncate('hi-diddly-ho there, neighborino', {
16753     *   'omission': ' [...]'
16754     * });
16755     * // => 'hi-diddly-ho there, neig [...]'
16756     */
16757    function truncate(string, options) {
16758      var length = DEFAULT_TRUNC_LENGTH,
16759          omission = DEFAULT_TRUNC_OMISSION;
16760
16761      if (isObject(options)) {
16762        var separator = 'separator' in options ? options.separator : separator;
16763        length = 'length' in options ? toInteger(options.length) : length;
16764        omission = 'omission' in options ? baseToString(options.omission) : omission;
16765      }
16766      string = toString(string);
16767
16768      var strLength = string.length;
16769      if (hasUnicode(string)) {
16770        var strSymbols = stringToArray(string);
16771        strLength = strSymbols.length;
16772      }
16773      if (length >= strLength) {
16774        return string;
16775      }
16776      var end = length - stringSize(omission);
16777      if (end < 1) {
16778        return omission;
16779      }
16780      var result = strSymbols
16781        ? castSlice(strSymbols, 0, end).join('')
16782        : string.slice(0, end);
16783
16784      if (separator === undefined) {
16785        return result + omission;
16786      }
16787      if (strSymbols) {
16788        end += (result.length - end);
16789      }
16790      if (isRegExp(separator)) {
16791        if (string.slice(end).search(separator)) {
16792          var match,
16793              substring = result;
16794
16795          if (!separator.global) {
16796            separator = RegExp(separator.source, toString(reFlags.exec(separator)) + 'g');
16797          }
16798          separator.lastIndex = 0;
16799          while ((match = separator.exec(substring))) {
16800            var newEnd = match.index;
16801          }
16802          result = result.slice(0, newEnd === undefined ? end : newEnd);
16803        }
16804      } else if (string.indexOf(baseToString(separator), end) != end) {
16805        var index = result.lastIndexOf(separator);
16806        if (index > -1) {
16807          result = result.slice(0, index);
16808        }
16809      }
16810      return result + omission;
16811    }
16812
16813    /**
16814     * The inverse of `_.escape`; this method converts the HTML entities
16815     * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to
16816     * their corresponding characters.
16817     *
16818     * **Note:** No other HTML entities are unescaped. To unescape additional
16819     * HTML entities use a third-party library like [_he_](https://mths.be/he).
16820     *
16821     * @static
16822     * @memberOf _
16823     * @since 0.6.0
16824     * @category String
16825     * @param {string} [string=''] The string to unescape.
16826     * @returns {string} Returns the unescaped string.
16827     * @example
16828     *
16829     * _.unescape('fred, barney, &amp; pebbles');
16830     * // => 'fred, barney, & pebbles'
16831     */
16832    function unescape(string) {
16833      string = toString(string);
16834      return (string && reHasEscapedHtml.test(string))
16835        ? string.replace(reEscapedHtml, unescapeHtmlChar)
16836        : string;
16837    }
16838
16839    /**
16840     * Converts `string`, as space separated words, to upper case.
16841     *
16842     * @static
16843     * @memberOf _
16844     * @since 4.0.0
16845     * @category String
16846     * @param {string} [string=''] The string to convert.
16847     * @returns {string} Returns the upper cased string.
16848     * @example
16849     *
16850     * _.upperCase('--foo-bar');
16851     * // => 'FOO BAR'
16852     *
16853     * _.upperCase('fooBar');
16854     * // => 'FOO BAR'
16855     *
16856     * _.upperCase('__foo_bar__');
16857     * // => 'FOO BAR'
16858     */
16859    var upperCase = createCompounder(function(result, word, index) {
16860      return result + (index ? ' ' : '') + word.toUpperCase();
16861    });
16862
16863    /**
16864     * Converts the first character of `string` to upper case.
16865     *
16866     * @static
16867     * @memberOf _
16868     * @since 4.0.0
16869     * @category String
16870     * @param {string} [string=''] The string to convert.
16871     * @returns {string} Returns the converted string.
16872     * @example
16873     *
16874     * _.upperFirst('fred');
16875     * // => 'Fred'
16876     *
16877     * _.upperFirst('FRED');
16878     * // => 'FRED'
16879     */
16880    var upperFirst = createCaseFirst('toUpperCase');
16881
16882    /**
16883     * Splits `string` into an array of its words.
16884     *
16885     * @static
16886     * @memberOf _
16887     * @since 3.0.0
16888     * @category String
16889     * @param {string} [string=''] The string to inspect.
16890     * @param {RegExp|string} [pattern] The pattern to match words.
16891     * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
16892     * @returns {Array} Returns the words of `string`.
16893     * @example
16894     *
16895     * _.words('fred, barney, & pebbles');
16896     * // => ['fred', 'barney', 'pebbles']
16897     *
16898     * _.words('fred, barney, & pebbles', /[^, ]+/g);
16899     * // => ['fred', 'barney', '&', 'pebbles']
16900     */
16901    function words(string, pattern, guard) {
16902      string = toString(string);
16903      pattern = guard ? undefined : pattern;
16904
16905      if (pattern === undefined) {
16906        return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
16907      }
16908      return string.match(pattern) || [];
16909    }
16910
16911    /*------------------------------------------------------------------------*/
16912
16913    /**
16914     * Attempts to invoke `func`, returning either the result or the caught error
16915     * object. Any additional arguments are provided to `func` when it's invoked.
16916     *
16917     * @static
16918     * @memberOf _
16919     * @since 3.0.0
16920     * @category Util
16921     * @param {Function} func The function to attempt.
16922     * @param {...*} [args] The arguments to invoke `func` with.
16923     * @returns {*} Returns the `func` result or error object.
16924     * @example
16925     *
16926     * // Avoid throwing errors for invalid selectors.
16927     * var elements = _.attempt(function(selector) {
16928     *   return document.querySelectorAll(selector);
16929     * }, '>_>');
16930     *
16931     * if (_.isError(elements)) {
16932     *   elements = [];
16933     * }
16934     */
16935    var attempt = baseRest(function(func, args) {
16936      try {
16937        return apply(func, undefined, args);
16938      } catch (e) {
16939        return isError(e) ? e : new Error(e);
16940      }
16941    });
16942
16943    /**
16944     * Binds methods of an object to the object itself, overwriting the existing
16945     * method.
16946     *
16947     * **Note:** This method doesn't set the "length" property of bound functions.
16948     *
16949     * @static
16950     * @since 0.1.0
16951     * @memberOf _
16952     * @category Util
16953     * @param {Object} object The object to bind and assign the bound methods to.
16954     * @param {...(string|string[])} methodNames The object method names to bind.
16955     * @returns {Object} Returns `object`.
16956     * @example
16957     *
16958     * var view = {
16959     *   'label': 'docs',
16960     *   'click': function() {
16961     *     console.log('clicked ' + this.label);
16962     *   }
16963     * };
16964     *
16965     * _.bindAll(view, ['click']);
16966     * jQuery(element).on('click', view.click);
16967     * // => Logs 'clicked docs' when clicked.
16968     */
16969    var bindAll = flatRest(function(object, methodNames) {
16970      arrayEach(methodNames, function(key) {
16971        key = toKey(key);
16972        baseAssignValue(object, key, bind(object[key], object));
16973      });
16974      return object;
16975    });
16976
16977    /**
16978     * Creates a function that iterates over `pairs` and invokes the corresponding
16979     * function of the first predicate to return truthy. The predicate-function
16980     * pairs are invoked with the `this` binding and arguments of the created
16981     * function.
16982     *
16983     * @static
16984     * @memberOf _
16985     * @since 4.0.0
16986     * @category Util
16987     * @param {Array} pairs The predicate-function pairs.
16988     * @returns {Function} Returns the new composite function.
16989     * @example
16990     *
16991     * var func = _.cond([
16992     *   [_.matches({ 'a': 1 }),           _.constant('matches A')],
16993     *   [_.conforms({ 'b': _.isNumber }), _.constant('matches B')],
16994     *   [_.stubTrue,                      _.constant('no match')]
16995     * ]);
16996     *
16997     * func({ 'a': 1, 'b': 2 });
16998     * // => 'matches A'
16999     *
17000     * func({ 'a': 0, 'b': 1 });
17001     * // => 'matches B'
17002     *
17003     * func({ 'a': '1', 'b': '2' });
17004     * // => 'no match'
17005     */
17006    function cond(pairs) {
17007      var length = pairs == null ? 0 : pairs.length,
17008          toIteratee = getIteratee();
17009
17010      pairs = !length ? [] : arrayMap(pairs, function(pair) {
17011        if (typeof pair[1] != 'function') {
17012          throw new TypeError(FUNC_ERROR_TEXT);
17013        }
17014        return [toIteratee(pair[0]), pair[1]];
17015      });
17016
17017      return baseRest(function(args) {
17018        var index = -1;
17019        while (++index < length) {
17020          var pair = pairs[index];
vendor: 10,296 bytes, lines 17021-17353
17021          if (apply(pair[0], this, args)) {
17022            return apply(pair[1], this, args);
17023          }
17024        }
17025      });
17026    }
17027
17028    /**
17029     * Creates a function that invokes the predicate properties of `source` with
17030     * the corresponding property values of a given object, returning `true` if
17031     * all predicates return truthy, else `false`.
17032     *
17033     * **Note:** The created function is equivalent to `_.conformsTo` with
17034     * `source` partially applied.
17035     *
17036     * @static
17037     * @memberOf _
17038     * @since 4.0.0
17039     * @category Util
17040     * @param {Object} source The object of property predicates to conform to.
17041     * @returns {Function} Returns the new spec function.
17042     * @example
17043     *
17044     * var objects = [
17045     *   { 'a': 2, 'b': 1 },
17046     *   { 'a': 1, 'b': 2 }
17047     * ];
17048     *
17049     * _.filter(objects, _.conforms({ 'b': function(n) { return n > 1; } }));
17050     * // => [{ 'a': 1, 'b': 2 }]
17051     */
17052    function conforms(source) {
17053      return baseConforms(baseClone(source, CLONE_DEEP_FLAG));
17054    }
17055
17056    /**
17057     * Creates a function that returns `value`.
17058     *
17059     * @static
17060     * @memberOf _
17061     * @since 2.4.0
17062     * @category Util
17063     * @param {*} value The value to return from the new function.
17064     * @returns {Function} Returns the new constant function.
17065     * @example
17066     *
17067     * var objects = _.times(2, _.constant({ 'a': 1 }));
17068     *
17069     * console.log(objects);
17070     * // => [{ 'a': 1 }, { 'a': 1 }]
17071     *
17072     * console.log(objects[0] === objects[1]);
17073     * // => true
17074     */
17075    function constant(value) {
17076      return function() {
17077        return value;
17078      };
17079    }
17080
17081    /**
17082     * Checks `value` to determine whether a default value should be returned in
17083     * its place. The `defaultValue` is returned if `value` is `NaN`, `null`,
17084     * or `undefined`.
17085     *
17086     * @static
17087     * @memberOf _
17088     * @since 4.14.0
17089     * @category Util
17090     * @param {*} value The value to check.
17091     * @param {*} defaultValue The default value.
17092     * @returns {*} Returns the resolved value.
17093     * @example
17094     *
17095     * _.defaultTo(1, 10);
17096     * // => 1
17097     *
17098     * _.defaultTo(undefined, 10);
17099     * // => 10
17100     */
17101    function defaultTo(value, defaultValue) {
17102      return (value == null || value !== value) ? defaultValue : value;
17103    }
17104
17105    /**
17106     * Creates a function that returns the result of invoking the given functions
17107     * with the `this` binding of the created function, where each successive
17108     * invocation is supplied the return value of the previous.
17109     *
17110     * @static
17111     * @memberOf _
17112     * @since 3.0.0
17113     * @category Util
17114     * @param {...(Function|Function[])} [funcs] The functions to invoke.
17115     * @returns {Function} Returns the new composite function.
17116     * @see _.flowRight
17117     * @example
17118     *
17119     * function square(n) {
17120     *   return n * n;
17121     * }
17122     *
17123     * var addSquare = _.flow([_.add, square]);
17124     * addSquare(1, 2);
17125     * // => 9
17126     */
17127    var flow = createFlow();
17128
17129    /**
17130     * This method is like `_.flow` except that it creates a function that
17131     * invokes the given functions from right to left.
17132     *
17133     * @static
17134     * @since 3.0.0
17135     * @memberOf _
17136     * @category Util
17137     * @param {...(Function|Function[])} [funcs] The functions to invoke.
17138     * @returns {Function} Returns the new composite function.
17139     * @see _.flow
17140     * @example
17141     *
17142     * function square(n) {
17143     *   return n * n;
17144     * }
17145     *
17146     * var addSquare = _.flowRight([square, _.add]);
17147     * addSquare(1, 2);
17148     * // => 9
17149     */
17150    var flowRight = createFlow(true);
17151
17152    /**
17153     * This method returns the first argument it receives.
17154     *
17155     * @static
17156     * @since 0.1.0
17157     * @memberOf _
17158     * @category Util
17159     * @param {*} value Any value.
17160     * @returns {*} Returns `value`.
17161     * @example
17162     *
17163     * var object = { 'a': 1 };
17164     *
17165     * console.log(_.identity(object) === object);
17166     * // => true
17167     */
17168    function identity(value) {
17169      return value;
17170    }
17171
17172    /**
17173     * Creates a function that invokes `func` with the arguments of the created
17174     * function. If `func` is a property name, the created function returns the
17175     * property value for a given element. If `func` is an array or object, the
17176     * created function returns `true` for elements that contain the equivalent
17177     * source properties, otherwise it returns `false`.
17178     *
17179     * @static
17180     * @since 4.0.0
17181     * @memberOf _
17182     * @category Util
17183     * @param {*} [func=_.identity] The value to convert to a callback.
17184     * @returns {Function} Returns the callback.
17185     * @example
17186     *
17187     * var users = [
17188     *   { 'user': 'barney', 'age': 36, 'active': true },
17189     *   { 'user': 'fred',   'age': 40, 'active': false }
17190     * ];
17191     *
17192     * // The `_.matches` iteratee shorthand.
17193     * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
17194     * // => [{ 'user': 'barney', 'age': 36, 'active': true }]
17195     *
17196     * // The `_.matchesProperty` iteratee shorthand.
17197     * _.filter(users, _.iteratee(['user', 'fred']));
17198     * // => [{ 'user': 'fred', 'age': 40 }]
17199     *
17200     * // The `_.property` iteratee shorthand.
17201     * _.map(users, _.iteratee('user'));
17202     * // => ['barney', 'fred']
17203     *
17204     * // Create custom iteratee shorthands.
17205     * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
17206     *   return !_.isRegExp(func) ? iteratee(func) : function(string) {
17207     *     return func.test(string);
17208     *   };
17209     * });
17210     *
17211     * _.filter(['abc', 'def'], /ef/);
17212     * // => ['def']
17213     */
17214    function iteratee(func) {
17215      return baseIteratee(typeof func == 'function' ? func : baseClone(func, CLONE_DEEP_FLAG));
17216    }
17217
17218    /**
17219     * Creates a function that performs a partial deep comparison between a given
17220     * object and `source`, returning `true` if the given object has equivalent
17221     * property values, else `false`.
17222     *
17223     * **Note:** The created function is equivalent to `_.isMatch` with `source`
17224     * partially applied.
17225     *
17226     * Partial comparisons will match empty array and empty object `source`
17227     * values against any array or object value, respectively. See `_.isEqual`
17228     * for a list of supported value comparisons.
17229     *
17230     * **Note:** Multiple values can be checked by combining several matchers
17231     * using `_.overSome`
17232     *
17233     * @static
17234     * @memberOf _
17235     * @since 3.0.0
17236     * @category Util
17237     * @param {Object} source The object of property values to match.
17238     * @returns {Function} Returns the new spec function.
17239     * @example
17240     *
17241     * var objects = [
17242     *   { 'a': 1, 'b': 2, 'c': 3 },
17243     *   { 'a': 4, 'b': 5, 'c': 6 }
17244     * ];
17245     *
17246     * _.filter(objects, _.matches({ 'a': 4, 'c': 6 }));
17247     * // => [{ 'a': 4, 'b': 5, 'c': 6 }]
17248     *
17249     * // Checking for several possible values
17250     * _.filter(objects, _.overSome([_.matches({ 'a': 1 }), _.matches({ 'a': 4 })]));
17251     * // => [{ 'a': 1, 'b': 2, 'c': 3 }, { 'a': 4, 'b': 5, 'c': 6 }]
17252     */
17253    function matches(source) {
17254      return baseMatches(baseClone(source, CLONE_DEEP_FLAG));
17255    }
17256
17257    /**
17258     * Creates a function that performs a partial deep comparison between the
17259     * value at `path` of a given object to `srcValue`, returning `true` if the
17260     * object value is equivalent, else `false`.
17261     *
17262     * **Note:** Partial comparisons will match empty array and empty object
17263     * `srcValue` values against any array or object value, respectively. See
17264     * `_.isEqual` for a list of supported value comparisons.
17265     *
17266     * **Note:** Multiple values can be checked by combining several matchers
17267     * using `_.overSome`
17268     *
17269     * @static
17270     * @memberOf _
17271     * @since 3.2.0
17272     * @category Util
17273     * @param {Array|string} path The path of the property to get.
17274     * @param {*} srcValue The value to match.
17275     * @returns {Function} Returns the new spec function.
17276     * @example
17277     *
17278     * var objects = [
17279     *   { 'a': 1, 'b': 2, 'c': 3 },
17280     *   { 'a': 4, 'b': 5, 'c': 6 }
17281     * ];
17282     *
17283     * _.find(objects, _.matchesProperty('a', 4));
17284     * // => { 'a': 4, 'b': 5, 'c': 6 }
17285     *
17286     * // Checking for several possible values
17287     * _.filter(objects, _.overSome([_.matchesProperty('a', 1), _.matchesProperty('a', 4)]));
17288     * // => [{ 'a': 1, 'b': 2, 'c': 3 }, { 'a': 4, 'b': 5, 'c': 6 }]
17289     */
17290    function matchesProperty(path, srcValue) {
17291      return baseMatchesProperty(path, baseClone(srcValue, CLONE_DEEP_FLAG));
17292    }
17293
17294    /**
17295     * Creates a function that invokes the method at `path` of a given object.
17296     * Any additional arguments are provided to the invoked method.
17297     *
17298     * @static
17299     * @memberOf _
17300     * @since 3.7.0
17301     * @category Util
17302     * @param {Array|string} path The path of the method to invoke.
17303     * @param {...*} [args] The arguments to invoke the method with.
17304     * @returns {Function} Returns the new invoker function.
17305     * @example
17306     *
17307     * var objects = [
17308     *   { 'a': { 'b': _.constant(2) } },
17309     *   { 'a': { 'b': _.constant(1) } }
17310     * ];
17311     *
17312     * _.map(objects, _.method('a.b'));
17313     * // => [2, 1]
17314     *
17315     * _.map(objects, _.method(['a', 'b']));
17316     * // => [2, 1]
17317     */
17318    var method = baseRest(function(path, args) {
17319      return function(object) {
17320        return baseInvoke(object, path, args);
17321      };
17322    });
17323
17324    /**
17325     * The opposite of `_.method`; this method creates a function that invokes
17326     * the method at a given path of `object`. Any additional arguments are
17327     * provided to the invoked method.
17328     *
17329     * @static
17330     * @memberOf _
17331     * @since 3.7.0
17332     * @category Util
17333     * @param {Object} object The object to query.
17334     * @param {...*} [args] The arguments to invoke the method with.
17335     * @returns {Function} Returns the new invoker function.
17336     * @example
17337     *
17338     * var array = _.times(3, _.constant),
17339     *     object = { 'a': array, 'b': array, 'c': array };
17340     *
17341     * _.map(['a[2]', 'c[0]'], _.methodOf(object));
17342     * // => [2, 0]
17343     *
17344     * _.map([['a', '2'], ['c', '0']], _.methodOf(object));
17345     * // => [2, 0]
17346     */
17347    var methodOf = baseRest(function(object, args) {
17348      return function(path) {
17349        return baseInvoke(object, path, args);
17350      };
17351    });
17352
17353    /**
vendor: 10,734 bytes, lines 17354-17741
17354     * Adds all own enumerable string keyed function properties of a source
17355     * object to the destination object. If `object` is a function, then methods
17356     * are added to its prototype as well.
17357     *
17358     * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
17359     * avoid conflicts caused by modifying the original.
17360     *
17361     * @static
17362     * @since 0.1.0
17363     * @memberOf _
17364     * @category Util
17365     * @param {Function|Object} [object=lodash] The destination object.
17366     * @param {Object} source The object of functions to add.
17367     * @param {Object} [options={}] The options object.
17368     * @param {boolean} [options.chain=true] Specify whether mixins are chainable.
17369     * @returns {Function|Object} Returns `object`.
17370     * @example
17371     *
17372     * function vowels(string) {
17373     *   return _.filter(string, function(v) {
17374     *     return /[aeiou]/i.test(v);
17375     *   });
17376     * }
17377     *
17378     * _.mixin({ 'vowels': vowels });
17379     * _.vowels('fred');
17380     * // => ['e']
17381     *
17382     * _('fred').vowels().value();
17383     * // => ['e']
17384     *
17385     * _.mixin({ 'vowels': vowels }, { 'chain': false });
17386     * _('fred').vowels();
17387     * // => ['e']
17388     */
17389    function mixin(object, source, options) {
17390      var props = keys(source),
17391          methodNames = baseFunctions(source, props);
17392
17393      if (options == null &&
17394          !(isObject(source) && (methodNames.length || !props.length))) {
17395        options = source;
17396        source = object;
17397        object = this;
17398        methodNames = baseFunctions(source, keys(source));
17399      }
17400      var chain = !(isObject(options) && 'chain' in options) || !!options.chain,
17401          isFunc = isFunction(object);
17402
17403      arrayEach(methodNames, function(methodName) {
17404        var func = source[methodName];
17405        object[methodName] = func;
17406        if (isFunc) {
17407          object.prototype[methodName] = function() {
17408            var chainAll = this.__chain__;
17409            if (chain || chainAll) {
17410              var result = object(this.__wrapped__),
17411                  actions = result.__actions__ = copyArray(this.__actions__);
17412
17413              actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
17414              result.__chain__ = chainAll;
17415              return result;
17416            }
17417            return func.apply(object, arrayPush([this.value()], arguments));
17418          };
17419        }
17420      });
17421
17422      return object;
17423    }
17424
17425    /**
17426     * Reverts the `_` variable to its previous value and returns a reference to
17427     * the `lodash` function.
17428     *
17429     * @static
17430     * @since 0.1.0
17431     * @memberOf _
17432     * @category Util
17433     * @returns {Function} Returns the `lodash` function.
17434     * @example
17435     *
17436     * var lodash = _.noConflict();
17437     */
17438    function noConflict() {
17439      if (root._ === this) {
17440        root._ = oldDash;
17441      }
17442      return this;
17443    }
17444
17445    /**
17446     * This method returns `undefined`.
17447     *
17448     * @static
17449     * @memberOf _
17450     * @since 2.3.0
17451     * @category Util
17452     * @example
17453     *
17454     * _.times(2, _.noop);
17455     * // => [undefined, undefined]
17456     */
17457    function noop() {
17458      // No operation performed.
17459    }
17460
17461    /**
17462     * Creates a function that gets the argument at index `n`. If `n` is negative,
17463     * the nth argument from the end is returned.
17464     *
17465     * @static
17466     * @memberOf _
17467     * @since 4.0.0
17468     * @category Util
17469     * @param {number} [n=0] The index of the argument to return.
17470     * @returns {Function} Returns the new pass-thru function.
17471     * @example
17472     *
17473     * var func = _.nthArg(1);
17474     * func('a', 'b', 'c', 'd');
17475     * // => 'b'
17476     *
17477     * var func = _.nthArg(-2);
17478     * func('a', 'b', 'c', 'd');
17479     * // => 'c'
17480     */
17481    function nthArg(n) {
17482      n = toInteger(n);
17483      return baseRest(function(args) {
17484        return baseNth(args, n);
17485      });
17486    }
17487
17488    /**
17489     * Creates a function that invokes `iteratees` with the arguments it receives
17490     * and returns their results.
17491     *
17492     * @static
17493     * @memberOf _
17494     * @since 4.0.0
17495     * @category Util
17496     * @param {...(Function|Function[])} [iteratees=[_.identity]]
17497     *  The iteratees to invoke.
17498     * @returns {Function} Returns the new function.
17499     * @example
17500     *
17501     * var func = _.over([Math.max, Math.min]);
17502     *
17503     * func(1, 2, 3, 4);
17504     * // => [4, 1]
17505     */
17506    var over = createOver(arrayMap);
17507
17508    /**
17509     * Creates a function that checks if **all** of the `predicates` return
17510     * truthy when invoked with the arguments it receives.
17511     *
17512     * Following shorthands are possible for providing predicates.
17513     * Pass an `Object` and it will be used as an parameter for `_.matches` to create the predicate.
17514     * Pass an `Array` of parameters for `_.matchesProperty` and the predicate will be created using them.
17515     *
17516     * @static
17517     * @memberOf _
17518     * @since 4.0.0
17519     * @category Util
17520     * @param {...(Function|Function[])} [predicates=[_.identity]]
17521     *  The predicates to check.
17522     * @returns {Function} Returns the new function.
17523     * @example
17524     *
17525     * var func = _.overEvery([Boolean, isFinite]);
17526     *
17527     * func('1');
17528     * // => true
17529     *
17530     * func(null);
17531     * // => false
17532     *
17533     * func(NaN);
17534     * // => false
17535     */
17536    var overEvery = createOver(arrayEvery);
17537
17538    /**
17539     * Creates a function that checks if **any** of the `predicates` return
17540     * truthy when invoked with the arguments it receives.
17541     *
17542     * Following shorthands are possible for providing predicates.
17543     * Pass an `Object` and it will be used as an parameter for `_.matches` to create the predicate.
17544     * Pass an `Array` of parameters for `_.matchesProperty` and the predicate will be created using them.
17545     *
17546     * @static
17547     * @memberOf _
17548     * @since 4.0.0
17549     * @category Util
17550     * @param {...(Function|Function[])} [predicates=[_.identity]]
17551     *  The predicates to check.
17552     * @returns {Function} Returns the new function.
17553     * @example
17554     *
17555     * var func = _.overSome([Boolean, isFinite]);
17556     *
17557     * func('1');
17558     * // => true
17559     *
17560     * func(null);
17561     * // => true
17562     *
17563     * func(NaN);
17564     * // => false
17565     *
17566     * var matchesFunc = _.overSome([{ 'a': 1 }, { 'a': 2 }])
17567     * var matchesPropertyFunc = _.overSome([['a', 1], ['a', 2]])
17568     */
17569    var overSome = createOver(arraySome);
17570
17571    /**
17572     * Creates a function that returns the value at `path` of a given object.
17573     *
17574     * @static
17575     * @memberOf _
17576     * @since 2.4.0
17577     * @category Util
17578     * @param {Array|string} path The path of the property to get.
17579     * @returns {Function} Returns the new accessor function.
17580     * @example
17581     *
17582     * var objects = [
17583     *   { 'a': { 'b': 2 } },
17584     *   { 'a': { 'b': 1 } }
17585     * ];
17586     *
17587     * _.map(objects, _.property('a.b'));
17588     * // => [2, 1]
17589     *
17590     * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
17591     * // => [1, 2]
17592     */
17593    function property(path) {
17594      return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
17595    }
17596
17597    /**
17598     * The opposite of `_.property`; this method creates a function that returns
17599     * the value at a given path of `object`.
17600     *
17601     * @static
17602     * @memberOf _
17603     * @since 3.0.0
17604     * @category Util
17605     * @param {Object} object The object to query.
17606     * @returns {Function} Returns the new accessor function.
17607     * @example
17608     *
17609     * var array = [0, 1, 2],
17610     *     object = { 'a': array, 'b': array, 'c': array };
17611     *
17612     * _.map(['a[2]', 'c[0]'], _.propertyOf(object));
17613     * // => [2, 0]
17614     *
17615     * _.map([['a', '2'], ['c', '0']], _.propertyOf(object));
17616     * // => [2, 0]
17617     */
17618    function propertyOf(object) {
17619      return function(path) {
17620        return object == null ? undefined : baseGet(object, path);
17621      };
17622    }
17623
17624    /**
17625     * Creates an array of numbers (positive and/or negative) progressing from
17626     * `start` up to, but not including, `end`. A step of `-1` is used if a negative
17627     * `start` is specified without an `end` or `step`. If `end` is not specified,
17628     * it's set to `start` with `start` then set to `0`.
17629     *
17630     * **Note:** JavaScript follows the IEEE-754 standard for resolving
17631     * floating-point values which can produce unexpected results.
17632     *
17633     * @static
17634     * @since 0.1.0
17635     * @memberOf _
17636     * @category Util
17637     * @param {number} [start=0] The start of the range.
17638     * @param {number} end The end of the range.
17639     * @param {number} [step=1] The value to increment or decrement by.
17640     * @returns {Array} Returns the range of numbers.
17641     * @see _.inRange, _.rangeRight
17642     * @example
17643     *
17644     * _.range(4);
17645     * // => [0, 1, 2, 3]
17646     *
17647     * _.range(-4);
17648     * // => [0, -1, -2, -3]
17649     *
17650     * _.range(1, 5);
17651     * // => [1, 2, 3, 4]
17652     *
17653     * _.range(0, 20, 5);
17654     * // => [0, 5, 10, 15]
17655     *
17656     * _.range(0, -4, -1);
17657     * // => [0, -1, -2, -3]
17658     *
17659     * _.range(1, 4, 0);
17660     * // => [1, 1, 1]
17661     *
17662     * _.range(0);
17663     * // => []
17664     */
17665    var range = createRange();
17666
17667    /**
17668     * This method is like `_.range` except that it populates values in
17669     * descending order.
17670     *
17671     * @static
17672     * @memberOf _
17673     * @since 4.0.0
17674     * @category Util
17675     * @param {number} [start=0] The start of the range.
17676     * @param {number} end The end of the range.
17677     * @param {number} [step=1] The value to increment or decrement by.
17678     * @returns {Array} Returns the range of numbers.
17679     * @see _.inRange, _.range
17680     * @example
17681     *
17682     * _.rangeRight(4);
17683     * // => [3, 2, 1, 0]
17684     *
17685     * _.rangeRight(-4);
17686     * // => [-3, -2, -1, 0]
17687     *
17688     * _.rangeRight(1, 5);
17689     * // => [4, 3, 2, 1]
17690     *
17691     * _.rangeRight(0, 20, 5);
17692     * // => [15, 10, 5, 0]
17693     *
17694     * _.rangeRight(0, -4, -1);
17695     * // => [-3, -2, -1, 0]
17696     *
17697     * _.rangeRight(1, 4, 0);
17698     * // => [1, 1, 1]
17699     *
17700     * _.rangeRight(0);
17701     * // => []
17702     */
17703    var rangeRight = createRange(true);
17704
17705    /**
17706     * This method returns a new empty array.
17707     *
17708     * @static
17709     * @memberOf _
17710     * @since 4.13.0
17711     * @category Util
17712     * @returns {Array} Returns the new empty array.
17713     * @example
17714     *
17715     * var arrays = _.times(2, _.stubArray);
17716     *
17717     * console.log(arrays);
17718     * // => [[], []]
17719     *
17720     * console.log(arrays[0] === arrays[1]);
17721     * // => false
17722     */
17723    function stubArray() {
17724      return [];
17725    }
17726
17727    /**
17728     * This method returns `false`.
17729     *
17730     * @static
17731     * @memberOf _
17732     * @since 4.13.0
17733     * @category Util
17734     * @returns {boolean} Returns `false`.
17735     * @example
17736     *
17737     * _.times(2, _.stubFalse);
17738     * // => [false, false]
17739     */
17740    function stubFalse() {
17741      return false;
vendor: 1,044 bytes, lines 17742-17795
17742    }
17743
17744    /**
17745     * This method returns a new empty object.
17746     *
17747     * @static
17748     * @memberOf _
17749     * @since 4.13.0
17750     * @category Util
17751     * @returns {Object} Returns the new empty object.
17752     * @example
17753     *
17754     * var objects = _.times(2, _.stubObject);
17755     *
17756     * console.log(objects);
17757     * // => [{}, {}]
17758     *
17759     * console.log(objects[0] === objects[1]);
17760     * // => false
17761     */
17762    function stubObject() {
17763      return {};
17764    }
17765
17766    /**
17767     * This method returns an empty string.
17768     *
17769     * @static
17770     * @memberOf _
17771     * @since 4.13.0
17772     * @category Util
17773     * @returns {string} Returns the empty string.
17774     * @example
17775     *
17776     * _.times(2, _.stubString);
17777     * // => ['', '']
17778     */
17779    function stubString() {
17780      return '';
17781    }
17782
17783    /**
17784     * This method returns `true`.
17785     *
17786     * @static
17787     * @memberOf _
17788     * @since 4.13.0
17789     * @category Util
17790     * @returns {boolean} Returns `true`.
17791     * @example
17792     *
17793     * _.times(2, _.stubTrue);
17794     * // => [true, true]
17795     */
vendor: 9,081 bytes, lines 17796-18139
17796    function stubTrue() {
17797      return true;
17798    }
17799
17800    /**
17801     * Invokes the iteratee `n` times, returning an array of the results of
17802     * each invocation. The iteratee is invoked with one argument; (index).
17803     *
17804     * @static
17805     * @since 0.1.0
17806     * @memberOf _
17807     * @category Util
17808     * @param {number} n The number of times to invoke `iteratee`.
17809     * @param {Function} [iteratee=_.identity] The function invoked per iteration.
17810     * @returns {Array} Returns the array of results.
17811     * @example
17812     *
17813     * _.times(3, String);
17814     * // => ['0', '1', '2']
17815     *
17816     *  _.times(4, _.constant(0));
17817     * // => [0, 0, 0, 0]
17818     */
17819    function times(n, iteratee) {
17820      n = toInteger(n);
17821      if (n < 1 || n > MAX_SAFE_INTEGER) {
17822        return [];
17823      }
17824      var index = MAX_ARRAY_LENGTH,
17825          length = nativeMin(n, MAX_ARRAY_LENGTH);
17826
17827      iteratee = getIteratee(iteratee);
17828      n -= MAX_ARRAY_LENGTH;
17829
17830      var result = baseTimes(length, iteratee);
17831      while (++index < n) {
17832        iteratee(index);
17833      }
17834      return result;
17835    }
17836
17837    /**
17838     * Converts `value` to a property path array.
17839     *
17840     * @static
17841     * @memberOf _
17842     * @since 4.0.0
17843     * @category Util
17844     * @param {*} value The value to convert.
17845     * @returns {Array} Returns the new property path array.
17846     * @example
17847     *
17848     * _.toPath('a.b.c');
17849     * // => ['a', 'b', 'c']
17850     *
17851     * _.toPath('a[0].b.c');
17852     * // => ['a', '0', 'b', 'c']
17853     */
17854    function toPath(value) {
17855      if (isArray(value)) {
17856        return arrayMap(value, toKey);
17857      }
17858      return isSymbol(value) ? [value] : copyArray(stringToPath(toString(value)));
17859    }
17860
17861    /**
17862     * Generates a unique ID. If `prefix` is given, the ID is appended to it.
17863     *
17864     * @static
17865     * @since 0.1.0
17866     * @memberOf _
17867     * @category Util
17868     * @param {string} [prefix=''] The value to prefix the ID with.
17869     * @returns {string} Returns the unique ID.
17870     * @example
17871     *
17872     * _.uniqueId('contact_');
17873     * // => 'contact_104'
17874     *
17875     * _.uniqueId();
17876     * // => '105'
17877     */
17878    function uniqueId(prefix) {
17879      var id = ++idCounter;
17880      return toString(prefix) + id;
17881    }
17882
17883    /*------------------------------------------------------------------------*/
17884
17885    /**
17886     * Adds two numbers.
17887     *
17888     * @static
17889     * @memberOf _
17890     * @since 3.4.0
17891     * @category Math
17892     * @param {number} augend The first number in an addition.
17893     * @param {number} addend The second number in an addition.
17894     * @returns {number} Returns the total.
17895     * @example
17896     *
17897     * _.add(6, 4);
17898     * // => 10
17899     */
17900    var add = createMathOperation(function(augend, addend) {
17901      return augend + addend;
17902    }, 0);
17903
17904    /**
17905     * Computes `number` rounded up to `precision`.
17906     *
17907     * @static
17908     * @memberOf _
17909     * @since 3.10.0
17910     * @category Math
17911     * @param {number} number The number to round up.
17912     * @param {number} [precision=0] The precision to round up to.
17913     * @returns {number} Returns the rounded up number.
17914     * @example
17915     *
17916     * _.ceil(4.006);
17917     * // => 5
17918     *
17919     * _.ceil(6.004, 2);
17920     * // => 6.01
17921     *
17922     * _.ceil(6040, -2);
17923     * // => 6100
17924     */
17925    var ceil = createRound('ceil');
17926
17927    /**
17928     * Divide two numbers.
17929     *
17930     * @static
17931     * @memberOf _
17932     * @since 4.7.0
17933     * @category Math
17934     * @param {number} dividend The first number in a division.
17935     * @param {number} divisor The second number in a division.
17936     * @returns {number} Returns the quotient.
17937     * @example
17938     *
17939     * _.divide(6, 4);
17940     * // => 1.5
17941     */
17942    var divide = createMathOperation(function(dividend, divisor) {
17943      return dividend / divisor;
17944    }, 1);
17945
17946    /**
17947     * Computes `number` rounded down to `precision`.
17948     *
17949     * @static
17950     * @memberOf _
17951     * @since 3.10.0
17952     * @category Math
17953     * @param {number} number The number to round down.
17954     * @param {number} [precision=0] The precision to round down to.
17955     * @returns {number} Returns the rounded down number.
17956     * @example
17957     *
17958     * _.floor(4.006);
17959     * // => 4
17960     *
17961     * _.floor(0.046, 2);
17962     * // => 0.04
17963     *
17964     * _.floor(4060, -2);
17965     * // => 4000
17966     */
17967    var floor = createRound('floor');
17968
17969    /**
17970     * Computes the maximum value of `array`. If `array` is empty or falsey,
17971     * `undefined` is returned.
17972     *
17973     * @static
17974     * @since 0.1.0
17975     * @memberOf _
17976     * @category Math
17977     * @param {Array} array The array to iterate over.
17978     * @returns {*} Returns the maximum value.
17979     * @example
17980     *
17981     * _.max([4, 2, 8, 6]);
17982     * // => 8
17983     *
17984     * _.max([]);
17985     * // => undefined
17986     */
17987    function max(array) {
17988      return (array && array.length)
17989        ? baseExtremum(array, identity, baseGt)
17990        : undefined;
17991    }
17992
17993    /**
17994     * This method is like `_.max` except that it accepts `iteratee` which is
17995     * invoked for each element in `array` to generate the criterion by which
17996     * the value is ranked. The iteratee is invoked with one argument: (value).
17997     *
17998     * @static
17999     * @memberOf _
18000     * @since 4.0.0
18001     * @category Math
18002     * @param {Array} array The array to iterate over.
18003     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
18004     * @returns {*} Returns the maximum value.
18005     * @example
18006     *
18007     * var objects = [{ 'n': 1 }, { 'n': 2 }];
18008     *
18009     * _.maxBy(objects, function(o) { return o.n; });
18010     * // => { 'n': 2 }
18011     *
18012     * // The `_.property` iteratee shorthand.
18013     * _.maxBy(objects, 'n');
18014     * // => { 'n': 2 }
18015     */
18016    function maxBy(array, iteratee) {
18017      return (array && array.length)
18018        ? baseExtremum(array, getIteratee(iteratee, 2), baseGt)
18019        : undefined;
18020    }
18021
18022    /**
18023     * Computes the mean of the values in `array`.
18024     *
18025     * @static
18026     * @memberOf _
18027     * @since 4.0.0
18028     * @category Math
18029     * @param {Array} array The array to iterate over.
18030     * @returns {number} Returns the mean.
18031     * @example
18032     *
18033     * _.mean([4, 2, 8, 6]);
18034     * // => 5
18035     */
18036    function mean(array) {
18037      return baseMean(array, identity);
18038    }
18039
18040    /**
18041     * This method is like `_.mean` except that it accepts `iteratee` which is
18042     * invoked for each element in `array` to generate the value to be averaged.
18043     * The iteratee is invoked with one argument: (value).
18044     *
18045     * @static
18046     * @memberOf _
18047     * @since 4.7.0
18048     * @category Math
18049     * @param {Array} array The array to iterate over.
18050     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
18051     * @returns {number} Returns the mean.
18052     * @example
18053     *
18054     * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
18055     *
18056     * _.meanBy(objects, function(o) { return o.n; });
18057     * // => 5
18058     *
18059     * // The `_.property` iteratee shorthand.
18060     * _.meanBy(objects, 'n');
18061     * // => 5
18062     */
18063    function meanBy(array, iteratee) {
18064      return baseMean(array, getIteratee(iteratee, 2));
18065    }
18066
18067    /**
18068     * Computes the minimum value of `array`. If `array` is empty or falsey,
18069     * `undefined` is returned.
18070     *
18071     * @static
18072     * @since 0.1.0
18073     * @memberOf _
18074     * @category Math
18075     * @param {Array} array The array to iterate over.
18076     * @returns {*} Returns the minimum value.
18077     * @example
18078     *
18079     * _.min([4, 2, 8, 6]);
18080     * // => 2
18081     *
18082     * _.min([]);
18083     * // => undefined
18084     */
18085    function min(array) {
18086      return (array && array.length)
18087        ? baseExtremum(array, identity, baseLt)
18088        : undefined;
18089    }
18090
18091    /**
18092     * This method is like `_.min` except that it accepts `iteratee` which is
18093     * invoked for each element in `array` to generate the criterion by which
18094     * the value is ranked. The iteratee is invoked with one argument: (value).
18095     *
18096     * @static
18097     * @memberOf _
18098     * @since 4.0.0
18099     * @category Math
18100     * @param {Array} array The array to iterate over.
18101     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
18102     * @returns {*} Returns the minimum value.
18103     * @example
18104     *
18105     * var objects = [{ 'n': 1 }, { 'n': 2 }];
18106     *
18107     * _.minBy(objects, function(o) { return o.n; });
18108     * // => { 'n': 1 }
18109     *
18110     * // The `_.property` iteratee shorthand.
18111     * _.minBy(objects, 'n');
18112     * // => { 'n': 1 }
18113     */
18114    function minBy(array, iteratee) {
18115      return (array && array.length)
18116        ? baseExtremum(array, getIteratee(iteratee, 2), baseLt)
18117        : undefined;
18118    }
18119
18120    /**
18121     * Multiply two numbers.
18122     *
18123     * @static
18124     * @memberOf _
18125     * @since 4.7.0
18126     * @category Math
18127     * @param {number} multiplier The first number in a multiplication.
18128     * @param {number} multiplicand The second number in a multiplication.
18129     * @returns {number} Returns the product.
18130     * @example
18131     *
18132     * _.multiply(6, 4);
18133     * // => 24
18134     */
18135    var multiply = createMathOperation(function(multiplier, multiplicand) {
18136      return multiplier * multiplicand;
18137    }, 1);
18138
18139    /**
vendor: 13,137 bytes, lines 18140-18578
18140     * Computes `number` rounded to `precision`.
18141     *
18142     * @static
18143     * @memberOf _
18144     * @since 3.10.0
18145     * @category Math
18146     * @param {number} number The number to round.
18147     * @param {number} [precision=0] The precision to round to.
18148     * @returns {number} Returns the rounded number.
18149     * @example
18150     *
18151     * _.round(4.006);
18152     * // => 4
18153     *
18154     * _.round(4.006, 2);
18155     * // => 4.01
18156     *
18157     * _.round(4060, -2);
18158     * // => 4100
18159     */
18160    var round = createRound('round');
18161
18162    /**
18163     * Subtract two numbers.
18164     *
18165     * @static
18166     * @memberOf _
18167     * @since 4.0.0
18168     * @category Math
18169     * @param {number} minuend The first number in a subtraction.
18170     * @param {number} subtrahend The second number in a subtraction.
18171     * @returns {number} Returns the difference.
18172     * @example
18173     *
18174     * _.subtract(6, 4);
18175     * // => 2
18176     */
18177    var subtract = createMathOperation(function(minuend, subtrahend) {
18178      return minuend - subtrahend;
18179    }, 0);
18180
18181    /**
18182     * Computes the sum of the values in `array`.
18183     *
18184     * @static
18185     * @memberOf _
18186     * @since 3.4.0
18187     * @category Math
18188     * @param {Array} array The array to iterate over.
18189     * @returns {number} Returns the sum.
18190     * @example
18191     *
18192     * _.sum([4, 2, 8, 6]);
18193     * // => 20
18194     */
18195    function sum(array) {
18196      return (array && array.length)
18197        ? baseSum(array, identity)
18198        : 0;
18199    }
18200
18201    /**
18202     * This method is like `_.sum` except that it accepts `iteratee` which is
18203     * invoked for each element in `array` to generate the value to be summed.
18204     * The iteratee is invoked with one argument: (value).
18205     *
18206     * @static
18207     * @memberOf _
18208     * @since 4.0.0
18209     * @category Math
18210     * @param {Array} array The array to iterate over.
18211     * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
18212     * @returns {number} Returns the sum.
18213     * @example
18214     *
18215     * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
18216     *
18217     * _.sumBy(objects, function(o) { return o.n; });
18218     * // => 20
18219     *
18220     * // The `_.property` iteratee shorthand.
18221     * _.sumBy(objects, 'n');
18222     * // => 20
18223     */
18224    function sumBy(array, iteratee) {
18225      return (array && array.length)
18226        ? baseSum(array, getIteratee(iteratee, 2))
18227        : 0;
18228    }
18229
18230    /*------------------------------------------------------------------------*/
18231
18232    // Add methods that return wrapped values in chain sequences.
18233    lodash.after = after;
18234    lodash.ary = ary;
18235    lodash.assign = assign;
18236    lodash.assignIn = assignIn;
18237    lodash.assignInWith = assignInWith;
18238    lodash.assignWith = assignWith;
18239    lodash.at = at;
18240    lodash.before = before;
18241    lodash.bind = bind;
18242    lodash.bindAll = bindAll;
18243    lodash.bindKey = bindKey;
18244    lodash.castArray = castArray;
18245    lodash.chain = chain;
18246    lodash.chunk = chunk;
18247    lodash.compact = compact;
18248    lodash.concat = concat;
18249    lodash.cond = cond;
18250    lodash.conforms = conforms;
18251    lodash.constant = constant;
18252    lodash.countBy = countBy;
18253    lodash.create = create;
18254    lodash.curry = curry;
18255    lodash.curryRight = curryRight;
18256    lodash.debounce = debounce;
18257    lodash.defaults = defaults;
18258    lodash.defaultsDeep = defaultsDeep;
18259    lodash.defer = defer;
18260    lodash.delay = delay;
18261    lodash.difference = difference;
18262    lodash.differenceBy = differenceBy;
18263    lodash.differenceWith = differenceWith;
18264    lodash.drop = drop;
18265    lodash.dropRight = dropRight;
18266    lodash.dropRightWhile = dropRightWhile;
18267    lodash.dropWhile = dropWhile;
18268    lodash.fill = fill;
18269    lodash.filter = filter;
18270    lodash.flatMap = flatMap;
18271    lodash.flatMapDeep = flatMapDeep;
18272    lodash.flatMapDepth = flatMapDepth;
18273    lodash.flatten = flatten;
18274    lodash.flattenDeep = flattenDeep;
18275    lodash.flattenDepth = flattenDepth;
18276    lodash.flip = flip;
18277    lodash.flow = flow;
18278    lodash.flowRight = flowRight;
18279    lodash.fromPairs = fromPairs;
18280    lodash.functions = functions;
18281    lodash.functionsIn = functionsIn;
18282    lodash.groupBy = groupBy;
18283    lodash.initial = initial;
18284    lodash.intersection = intersection;
18285    lodash.intersectionBy = intersectionBy;
18286    lodash.intersectionWith = intersectionWith;
18287    lodash.invert = invert;
18288    lodash.invertBy = invertBy;
18289    lodash.invokeMap = invokeMap;
18290    lodash.iteratee = iteratee;
18291    lodash.keyBy = keyBy;
18292    lodash.keys = keys;
18293    lodash.keysIn = keysIn;
18294    lodash.map = map;
18295    lodash.mapKeys = mapKeys;
18296    lodash.mapValues = mapValues;
18297    lodash.matches = matches;
18298    lodash.matchesProperty = matchesProperty;
18299    lodash.memoize = memoize;
18300    lodash.merge = merge;
18301    lodash.mergeWith = mergeWith;
18302    lodash.method = method;
18303    lodash.methodOf = methodOf;
18304    lodash.mixin = mixin;
18305    lodash.negate = negate;
18306    lodash.nthArg = nthArg;
18307    lodash.omit = omit;
18308    lodash.omitBy = omitBy;
18309    lodash.once = once;
18310    lodash.orderBy = orderBy;
18311    lodash.over = over;
18312    lodash.overArgs = overArgs;
18313    lodash.overEvery = overEvery;
18314    lodash.overSome = overSome;
18315    lodash.partial = partial;
18316    lodash.partialRight = partialRight;
18317    lodash.partition = partition;
18318    lodash.pick = pick;
18319    lodash.pickBy = pickBy;
18320    lodash.property = property;
18321    lodash.propertyOf = propertyOf;
18322    lodash.pull = pull;
18323    lodash.pullAll = pullAll;
18324    lodash.pullAllBy = pullAllBy;
18325    lodash.pullAllWith = pullAllWith;
18326    lodash.pullAt = pullAt;
18327    lodash.range = range;
18328    lodash.rangeRight = rangeRight;
18329    lodash.rearg = rearg;
18330    lodash.reject = reject;
18331    lodash.remove = remove;
18332    lodash.rest = rest;
18333    lodash.reverse = reverse;
18334    lodash.sampleSize = sampleSize;
18335    lodash.set = set;
18336    lodash.setWith = setWith;
18337    lodash.shuffle = shuffle;
18338    lodash.slice = slice;
18339    lodash.sortBy = sortBy;
18340    lodash.sortedUniq = sortedUniq;
18341    lodash.sortedUniqBy = sortedUniqBy;
18342    lodash.split = split;
18343    lodash.spread = spread;
18344    lodash.tail = tail;
18345    lodash.take = take;
18346    lodash.takeRight = takeRight;
18347    lodash.takeRightWhile = takeRightWhile;
18348    lodash.takeWhile = takeWhile;
18349    lodash.tap = tap;
18350    lodash.throttle = throttle;
18351    lodash.thru = thru;
18352    lodash.toArray = toArray;
18353    lodash.toPairs = toPairs;
18354    lodash.toPairsIn = toPairsIn;
18355    lodash.toPath = toPath;
18356    lodash.toPlainObject = toPlainObject;
18357    lodash.transform = transform;
18358    lodash.unary = unary;
18359    lodash.union = union;
18360    lodash.unionBy = unionBy;
18361    lodash.unionWith = unionWith;
18362    lodash.uniq = uniq;
18363    lodash.uniqBy = uniqBy;
18364    lodash.uniqWith = uniqWith;
18365    lodash.unset = unset;
18366    lodash.unzip = unzip;
18367    lodash.unzipWith = unzipWith;
18368    lodash.update = update;
18369    lodash.updateWith = updateWith;
18370    lodash.values = values;
18371    lodash.valuesIn = valuesIn;
18372    lodash.without = without;
18373    lodash.words = words;
18374    lodash.wrap = wrap;
18375    lodash.xor = xor;
18376    lodash.xorBy = xorBy;
18377    lodash.xorWith = xorWith;
18378    lodash.zip = zip;
18379    lodash.zipObject = zipObject;
18380    lodash.zipObjectDeep = zipObjectDeep;
18381    lodash.zipWith = zipWith;
18382
18383    // Add aliases.
18384    lodash.entries = toPairs;
18385    lodash.entriesIn = toPairsIn;
18386    lodash.extend = assignIn;
18387    lodash.extendWith = assignInWith;
18388
18389    // Add methods to `lodash.prototype`.
18390    mixin(lodash, lodash);
18391
18392    /*------------------------------------------------------------------------*/
18393
18394    // Add methods that return unwrapped values in chain sequences.
18395    lodash.add = add;
18396    lodash.attempt = attempt;
18397    lodash.camelCase = camelCase;
18398    lodash.capitalize = capitalize;
18399    lodash.ceil = ceil;
18400    lodash.clamp = clamp;
18401    lodash.clone = clone;
18402    lodash.cloneDeep = cloneDeep;
18403    lodash.cloneDeepWith = cloneDeepWith;
18404    lodash.cloneWith = cloneWith;
18405    lodash.conformsTo = conformsTo;
18406    lodash.deburr = deburr;
18407    lodash.defaultTo = defaultTo;
18408    lodash.divide = divide;
18409    lodash.endsWith = endsWith;
18410    lodash.eq = eq;
18411    lodash.escape = escape;
18412    lodash.escapeRegExp = escapeRegExp;
18413    lodash.every = every;
18414    lodash.find = find;
18415    lodash.findIndex = findIndex;
18416    lodash.findKey = findKey;
18417    lodash.findLast = findLast;
18418    lodash.findLastIndex = findLastIndex;
18419    lodash.findLastKey = findLastKey;
18420    lodash.floor = floor;
18421    lodash.forEach = forEach;
18422    lodash.forEachRight = forEachRight;
18423    lodash.forIn = forIn;
18424    lodash.forInRight = forInRight;
18425    lodash.forOwn = forOwn;
18426    lodash.forOwnRight = forOwnRight;
18427    lodash.get = get;
18428    lodash.gt = gt;
18429    lodash.gte = gte;
18430    lodash.has = has;
18431    lodash.hasIn = hasIn;
18432    lodash.head = head;
18433    lodash.identity = identity;
18434    lodash.includes = includes;
18435    lodash.indexOf = indexOf;
18436    lodash.inRange = inRange;
18437    lodash.invoke = invoke;
18438    lodash.isArguments = isArguments;
18439    lodash.isArray = isArray;
18440    lodash.isArrayBuffer = isArrayBuffer;
18441    lodash.isArrayLike = isArrayLike;
18442    lodash.isArrayLikeObject = isArrayLikeObject;
18443    lodash.isBoolean = isBoolean;
18444    lodash.isBuffer = isBuffer;
18445    lodash.isDate = isDate;
18446    lodash.isElement = isElement;
18447    lodash.isEmpty = isEmpty;
18448    lodash.isEqual = isEqual;
18449    lodash.isEqualWith = isEqualWith;
18450    lodash.isError = isError;
18451    lodash.isFinite = isFinite;
18452    lodash.isFunction = isFunction;
18453    lodash.isInteger = isInteger;
18454    lodash.isLength = isLength;
18455    lodash.isMap = isMap;
18456    lodash.isMatch = isMatch;
18457    lodash.isMatchWith = isMatchWith;
18458    lodash.isNaN = isNaN;
18459    lodash.isNative = isNative;
18460    lodash.isNil = isNil;
18461    lodash.isNull = isNull;
18462    lodash.isNumber = isNumber;
18463    lodash.isObject = isObject;
18464    lodash.isObjectLike = isObjectLike;
18465    lodash.isPlainObject = isPlainObject;
18466    lodash.isRegExp = isRegExp;
18467    lodash.isSafeInteger = isSafeInteger;
18468    lodash.isSet = isSet;
18469    lodash.isString = isString;
18470    lodash.isSymbol = isSymbol;
18471    lodash.isTypedArray = isTypedArray;
18472    lodash.isUndefined = isUndefined;
18473    lodash.isWeakMap = isWeakMap;
18474    lodash.isWeakSet = isWeakSet;
18475    lodash.join = join;
18476    lodash.kebabCase = kebabCase;
18477    lodash.last = last;
18478    lodash.lastIndexOf = lastIndexOf;
18479    lodash.lowerCase = lowerCase;
18480    lodash.lowerFirst = lowerFirst;
18481    lodash.lt = lt;
18482    lodash.lte = lte;
18483    lodash.max = max;
18484    lodash.maxBy = maxBy;
18485    lodash.mean = mean;
18486    lodash.meanBy = meanBy;
18487    lodash.min = min;
18488    lodash.minBy = minBy;
18489    lodash.stubArray = stubArray;
18490    lodash.stubFalse = stubFalse;
18491    lodash.stubObject = stubObject;
18492    lodash.stubString = stubString;
18493    lodash.stubTrue = stubTrue;
18494    lodash.multiply = multiply;
18495    lodash.nth = nth;
18496    lodash.noConflict = noConflict;
18497    lodash.noop = noop;
18498    lodash.now = now;
18499    lodash.pad = pad;
18500    lodash.padEnd = padEnd;
18501    lodash.padStart = padStart;
18502    lodash.parseInt = parseInt;
18503    lodash.random = random;
18504    lodash.reduce = reduce;
18505    lodash.reduceRight = reduceRight;
18506    lodash.repeat = repeat;
18507    lodash.replace = replace;
18508    lodash.result = result;
18509    lodash.round = round;
18510    lodash.runInContext = runInContext;
18511    lodash.sample = sample;
18512    lodash.size = size;
18513    lodash.snakeCase = snakeCase;
18514    lodash.some = some;
18515    lodash.sortedIndex = sortedIndex;
18516    lodash.sortedIndexBy = sortedIndexBy;
18517    lodash.sortedIndexOf = sortedIndexOf;
18518    lodash.sortedLastIndex = sortedLastIndex;
18519    lodash.sortedLastIndexBy = sortedLastIndexBy;
18520    lodash.sortedLastIndexOf = sortedLastIndexOf;
18521    lodash.startCase = startCase;
18522    lodash.startsWith = startsWith;
18523    lodash.subtract = subtract;
18524    lodash.sum = sum;
18525    lodash.sumBy = sumBy;
18526    lodash.template = template;
18527    lodash.times = times;
18528    lodash.toFinite = toFinite;
18529    lodash.toInteger = toInteger;
18530    lodash.toLength = toLength;
18531    lodash.toLower = toLower;
18532    lodash.toNumber = toNumber;
18533    lodash.toSafeInteger = toSafeInteger;
18534    lodash.toString = toString;
18535    lodash.toUpper = toUpper;
18536    lodash.trim = trim;
18537    lodash.trimEnd = trimEnd;
18538    lodash.trimStart = trimStart;
18539    lodash.truncate = truncate;
18540    lodash.unescape = unescape;
18541    lodash.uniqueId = uniqueId;
18542    lodash.upperCase = upperCase;
18543    lodash.upperFirst = upperFirst;
18544
18545    // Add aliases.
18546    lodash.each = forEach;
18547    lodash.eachRight = forEachRight;
18548    lodash.first = head;
18549
18550    mixin(lodash, (function() {
18551      var source = {};
18552      baseForOwn(lodash, function(func, methodName) {
18553        if (!hasOwnProperty.call(lodash.prototype, methodName)) {
18554          source[methodName] = func;
18555        }
18556      });
18557      return source;
18558    }()), { 'chain': false });
18559
18560    /*------------------------------------------------------------------------*/
18561
18562    /**
18563     * The semantic version number.
18564     *
18565     * @static
18566     * @memberOf _
18567     * @type {string}
18568     */
18569    lodash.VERSION = VERSION;
18570
18571    // Assign default placeholders.
18572    arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
18573      lodash[methodName].placeholder = lodash;
18574    });
18575
18576    // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
18577    arrayEach(['drop', 'take'], function(methodName, index) {
18578      LazyWrapper.prototype[methodName] = function(n) {
vendor: 7,434 bytes, lines 18579-18796
18579        n = n === undefined ? 1 : nativeMax(toInteger(n), 0);
18580
18581        var result = (this.__filtered__ && !index)
18582          ? new LazyWrapper(this)
18583          : this.clone();
18584
18585        if (result.__filtered__) {
18586          result.__takeCount__ = nativeMin(n, result.__takeCount__);
18587        } else {
18588          result.__views__.push({
18589            'size': nativeMin(n, MAX_ARRAY_LENGTH),
18590            'type': methodName + (result.__dir__ < 0 ? 'Right' : '')
18591          });
18592        }
18593        return result;
18594      };
18595
18596      LazyWrapper.prototype[methodName + 'Right'] = function(n) {
18597        return this.reverse()[methodName](n).reverse();
18598      };
18599    });
18600
18601    // Add `LazyWrapper` methods that accept an `iteratee` value.
18602    arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
18603      var type = index + 1,
18604          isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG;
18605
18606      LazyWrapper.prototype[methodName] = function(iteratee) {
18607        var result = this.clone();
18608        result.__iteratees__.push({
18609          'iteratee': getIteratee(iteratee, 3),
18610          'type': type
18611        });
18612        result.__filtered__ = result.__filtered__ || isFilter;
18613        return result;
18614      };
18615    });
18616
18617    // Add `LazyWrapper` methods for `_.head` and `_.last`.
18618    arrayEach(['head', 'last'], function(methodName, index) {
18619      var takeName = 'take' + (index ? 'Right' : '');
18620
18621      LazyWrapper.prototype[methodName] = function() {
18622        return this[takeName](1).value()[0];
18623      };
18624    });
18625
18626    // Add `LazyWrapper` methods for `_.initial` and `_.tail`.
18627    arrayEach(['initial', 'tail'], function(methodName, index) {
18628      var dropName = 'drop' + (index ? '' : 'Right');
18629
18630      LazyWrapper.prototype[methodName] = function() {
18631        return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
18632      };
18633    });
18634
18635    LazyWrapper.prototype.compact = function() {
18636      return this.filter(identity);
18637    };
18638
18639    LazyWrapper.prototype.find = function(predicate) {
18640      return this.filter(predicate).head();
18641    };
18642
18643    LazyWrapper.prototype.findLast = function(predicate) {
18644      return this.reverse().find(predicate);
18645    };
18646
18647    LazyWrapper.prototype.invokeMap = baseRest(function(path, args) {
18648      if (typeof path == 'function') {
18649        return new LazyWrapper(this);
18650      }
18651      return this.map(function(value) {
18652        return baseInvoke(value, path, args);
18653      });
18654    });
18655
18656    LazyWrapper.prototype.reject = function(predicate) {
18657      return this.filter(negate(getIteratee(predicate)));
18658    };
18659
18660    LazyWrapper.prototype.slice = function(start, end) {
18661      start = toInteger(start);
18662
18663      var result = this;
18664      if (result.__filtered__ && (start > 0 || end < 0)) {
18665        return new LazyWrapper(result);
18666      }
18667      if (start < 0) {
18668        result = result.takeRight(-start);
18669      } else if (start) {
18670        result = result.drop(start);
18671      }
18672      if (end !== undefined) {
18673        end = toInteger(end);
18674        result = end < 0 ? result.dropRight(-end) : result.take(end - start);
18675      }
18676      return result;
18677    };
18678
18679    LazyWrapper.prototype.takeRightWhile = function(predicate) {
18680      return this.reverse().takeWhile(predicate).reverse();
18681    };
18682
18683    LazyWrapper.prototype.toArray = function() {
18684      return this.take(MAX_ARRAY_LENGTH);
18685    };
18686
18687    // Add `LazyWrapper` methods to `lodash.prototype`.
18688    baseForOwn(LazyWrapper.prototype, function(func, methodName) {
18689      var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName),
18690          isTaker = /^(?:head|last)$/.test(methodName),
18691          lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName],
18692          retUnwrapped = isTaker || /^find/.test(methodName);
18693
18694      if (!lodashFunc) {
18695        return;
18696      }
18697      lodash.prototype[methodName] = function() {
18698        var value = this.__wrapped__,
18699            args = isTaker ? [1] : arguments,
18700            isLazy = value instanceof LazyWrapper,
18701            iteratee = args[0],
18702            useLazy = isLazy || isArray(value);
18703
18704        var interceptor = function(value) {
18705          var result = lodashFunc.apply(lodash, arrayPush([value], args));
18706          return (isTaker && chainAll) ? result[0] : result;
18707        };
18708
18709        if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
18710          // Avoid lazy use if the iteratee has a "length" value other than `1`.
18711          isLazy = useLazy = false;
18712        }
18713        var chainAll = this.__chain__,
18714            isHybrid = !!this.__actions__.length,
18715            isUnwrapped = retUnwrapped && !chainAll,
18716            onlyLazy = isLazy && !isHybrid;
18717
18718        if (!retUnwrapped && useLazy) {
18719          value = onlyLazy ? value : new LazyWrapper(this);
18720          var result = func.apply(value, args);
18721          result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
18722          return new LodashWrapper(result, chainAll);
18723        }
18724        if (isUnwrapped && onlyLazy) {
18725          return func.apply(this, args);
18726        }
18727        result = this.thru(interceptor);
18728        return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result;
18729      };
18730    });
18731
18732    // Add `Array` methods to `lodash.prototype`.
18733    arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
18734      var func = arrayProto[methodName],
18735          chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
18736          retUnwrapped = /^(?:pop|shift)$/.test(methodName);
18737
18738      lodash.prototype[methodName] = function() {
18739        var args = arguments;
18740        if (retUnwrapped && !this.__chain__) {
18741          var value = this.value();
18742          return func.apply(isArray(value) ? value : [], args);
18743        }
18744        return this[chainName](function(value) {
18745          return func.apply(isArray(value) ? value : [], args);
18746        });
18747      };
18748    });
18749
18750    // Map minified method names to their real names.
18751    baseForOwn(LazyWrapper.prototype, function(func, methodName) {
18752      var lodashFunc = lodash[methodName];
18753      if (lodashFunc) {
18754        var key = lodashFunc.name + '';
18755        if (!hasOwnProperty.call(realNames, key)) {
18756          realNames[key] = [];
18757        }
18758        realNames[key].push({ 'name': methodName, 'func': lodashFunc });
18759      }
18760    });
18761
18762    realNames[createHybrid(undefined, WRAP_BIND_KEY_FLAG).name] = [{
18763      'name': 'wrapper',
18764      'func': undefined
18765    }];
18766
18767    // Add methods to `LazyWrapper`.
18768    LazyWrapper.prototype.clone = lazyClone;
18769    LazyWrapper.prototype.reverse = lazyReverse;
18770    LazyWrapper.prototype.value = lazyValue;
18771
18772    // Add chain sequence methods to the `lodash` wrapper.
18773    lodash.prototype.at = wrapperAt;
18774    lodash.prototype.chain = wrapperChain;
18775    lodash.prototype.commit = wrapperCommit;
18776    lodash.prototype.next = wrapperNext;
18777    lodash.prototype.plant = wrapperPlant;
18778    lodash.prototype.reverse = wrapperReverse;
18779    lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
18780
18781    // Add lazy aliases.
18782    lodash.prototype.first = lodash.prototype.head;
18783
18784    if (symIterator) {
18785      lodash.prototype[symIterator] = wrapperToIterator;
18786    }
18787    return lodash;
18788  });
18789
18790  /*--------------------------------------------------------------------------*/
18791
18792  // Export lodash.
18793  var _ = runInContext();
18794
18795  // Some AMD build optimizers, like r.js, check for condition patterns like:
18796  if (t
18796ypeof define == 'function' && typeof define.amd == 'object' && define.amd) {
18797    // Expose Lodash on the global object to prevent errors when Lodash is
18798    // loaded by a script tag in the presence of an AMD loader.
18799    // See http://requirejs.org/docs/errors.html#mismatch for more details.
18800    // Use `_.noConflict` to remove Lodash from the global object.
18801    root._ = _;
18802
18803    // Define as an anonymous module so, through path mapping, it can be
18804    // referenced as the "underscore" module.
18805    define(function() {
18806      return _;
18807    });
18808  }
18809  // Check for `exports` after `define` in case a build optimizer adds it.
18810  else if (freeModule) {
18811    // Export for Node.js.
18812    (freeModule.exports = _)._ = _;
18813    // Export for CommonJS support.
18814    freeExports._ = _;
18815  }
18816  else {
18817    // Export to the global object.
18818    root._ = _;
18819  }
18820}.call(this));
18821/*globals define,module */
18822
18823/*!
18824 * simple-namespace
18825 * https://github.com/drzax/simple-namespace
18826 *
18827 * @version 0.2.0
18828 * @copyright Simon Elvery
18829 * @license MIT
18830 * 
18831 */
18832(function(){
18833
18834	// most likely `window`
18835	var _this = this;
18836
18837	// the main function
18838	function main(ns, root) {
18839		var parts, part, space;
18840
18841		root = root || _this;
18842		parts = ns.split('.');
18843		part = parts.shift();
18844		while (part) {
18845			space = root[part] || {};
18846			root = root[part] = space;
18847			part = parts.shift();
18848		}
18849		return space;
18850	}
18851
18852	// export
18853	if (typeof define === "function" && define.amd) {
18854		define(main);
18855	} else if (typeof module === "object" && module.exports) {
18856		module.exports = main;
18857	} else {
18858		_this.ns = main;
18859	}
18860
18861}());
18862
18863/**
18864 * isMobile.js v0.4.1
18865 *
18866 * A simple library to detect Apple phones and tablets,
18867 * Android phones and tablets, other mobile devices (like blackberry, mini-opera and windows phone),
18868 * and any kind of seven inch device, via user agent sniffing.
18869 *
18870 * @author: Kai Mallea ([email protected])
18871 *
18872 * @license: http://creativecommons.org/publicdomain/zero/1.0/
18873 */
18874(function (global) {
18875
18876    var apple_phone         = /iPhone/i,
18877        apple_ipod          = /iPod/i,
18878        apple_tablet        = /iPad/i,
18879        android_phone       = /(?=.*\bAndroid\b)(?=.*\bMobile\b)/i, // Match 'Android' AND 'Mobile'
18880        android_tablet      = /Android/i,
18881        amazon_phone        = /(?=.*\bAndroid\b)(?=.*\bSD4930UR\b)/i,
18882        amazon_tablet       = /(?=.*\bAndroid\b)(?=.*\b(?:KFOT|KFTT|KFJWI|KFJWA|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|KFARWI|KFASWI|KFSAWI|KFSAWA)\b)/i,
18883        windows_phone       = /Windows Phone/i,
18884        windows_tablet      = /(?=.*\bWindows\b)(?=.*\bARM\b)/i, // Match 'Windows' AND 'ARM'
18885        other_blackberry    = /BlackBerry/i,
18886        other_blackberry_10 = /BB10/i,
18887        other_opera         = /Opera Mini/i,
18888        other_chrome        = /(CriOS|Chrome)(?=.*\bMobile\b)/i,
18889        other_firefox       = /(?=.*\bFirefox\b)(?=.*\bMobile\b)/i, // Match 'Firefox' AND 'Mobile'
18890        seven_inch = new RegExp(
18891            '(?:' +         // Non-capturing group
18892
18893            'Nexus 7' +     // Nexus 7
18894
18895            '|' +           // OR
18896
18897            'BNTV250' +     // B&N Nook Tablet 7 inch
18898
18899            '|' +           // OR
18900
18901            'Kindle Fire' + // Kindle Fire
18902
18903            '|' +           // OR
18904
18905            'Silk' +        // Kindle Fire, Silk Accelerated
18906
18907            '|' +           // OR
18908
18909            'GT-P1000' +    // Galaxy Tab 7 inch
18910
18911            ')',            // End non-capturing group
18912
18913            'i');           // Case-insensitive matching
18914
18915    var match = function(regex, userAgent) {
18916        return regex.test(userAgent);
18917    };
18918
18919    var IsMobileClass = function(userAgent) {
18920        var ua = userAgent || navigator.userAgent;
18921
18922        // Facebook mobile app's integrated browser adds a bunch of strings that
18923        // match everything. Strip it out if it exists.
18924        var tmp = ua.split('[FBAN');
18925        if (typeof tmp[1] !== 'undefined') {
18926            ua = tmp[0];
18927        }
18928
18929        // Twitter mobile app's integrated browser on iPad adds a "Twitter for
18930        // iPhone" string. Same probable happens on other tablet platforms.
18931        // This will confuse detection so strip it out if it exists.
18932        tmp = ua.split('Twitter');
18933        if (typeof tmp[1] !== 'undefined') {
18934            ua = tmp[0];
18935        }
18936
18937        this.apple = {
18938            phone:  match(apple_phone, ua),
18939            ipod:   match(apple_ipod, ua),
18940            tablet: !match(apple_phone, ua) && match(apple_tablet, ua),
18941            device: match(apple_phone, ua) || match(apple_ipod, ua) || match(apple_tablet, ua)
18942        };
18943        this.amazon = {
18944            phone:  match(amazon_phone, ua),
18945            tablet: !match(amazon_phone, ua) && match(amazon_tablet, ua),
18946            device: match(amazon_phone, ua) || match(amazon_tablet, ua)
18947        };
18948        this.android = {
18949            phone:  match(amazon_phone, ua) || match(android_phone, ua),
18950            tablet: !match(amazon_phone, ua) && !match(android_phone, ua) && (match(amazon_tablet, ua) || match(android_tablet, ua)),
18951            device: match(amazon_phone, ua) || match(amazon_tablet, ua) || match(android_phone, ua) || match(android_tablet, ua)
18952        };
18953        this.windows = {
18954            phone:  match(windows_phone, ua),
18955            tablet: match(windows_tablet, ua),
18956            device: match(windows_phone, ua) || match(windows_tablet, ua)
18957        };
18958        this.other = {
18959            blackberry:   match(other_blackberry, ua),
18960            blackberry10: match(other_blackberry_10, ua),
18961            opera:        match(other_opera, ua),
18962            firefox:      match(other_firefox, ua),
18963            chrome:       match(other_chrome, ua),
18964            device:       match(other_blackberry, ua) || match(other_blackberry_10, ua) || match(other_opera, ua) || match(other_firefox, ua) || match(other_chrome, ua)
18965        };
18966        this.seven_inch = match(seven_inch, ua);
18967        this.any = this.apple.device || this.android.device || this.windows.device || this.other.device || this.seven_inch;
18968
18969        // excludes 'other' devices and ipods, targeting touchscreen phones
18970        this.phone = this.apple.phone || this.android.phone || this.windows.phone;
18971
18972        // excludes 7 inch devices, classifying as phone or tablet is left to the user
18973        this.tablet = this.apple.tablet || this.android.tablet || this.windows.tablet;
18974
18975        if (typeof window === 'undefined') {
18976            return this;
18977        }
18978    };
18979
18980    var instantiate = function() {
18981        var IM = new IsMobileClass();
18982        IM.Class = IsMobileClass;
18983        return IM;
18984    };
18985
18986    if (typeof module !== 'undefined' && module.exports && typeof window === 'undefined') {
18987        //node
18988        module.exports = IsMobileClass;
18989    } else if (typeof module !== 'undefined' && module.exports && typeof window !== 'undefined') {
18990        //browserify
18991        module.exports = instantiate();
18992    } else if (typeof define === 'function' && define.amd) {
18993        //AMD
18994        define('isMobile', [], global.isMobile = instantiate());
18995    } else {
18996        global.isMobile = instantiate();
18997    }
18998
18999})(this);
19000
19001// HumanizeDuration.js - http://git.io/j0HgmQ
19002// This has been modified for the purposes of SpectrumLocalNews.com
19003// the original can be found at the URL above
19004;(function () {
19005    var languages = {
19006        en: {
19007            y: function (c) {
19008                return 'year' + (c !== 1 ? 's' : '')
19009            },
19010            mo: function (c) {
19011                return 'month' + (c !== 1 ? 's' : '')
19012            },
19013            w: function (c) {
19014                return 'week' + (c !== 1 ? 's' : '')
19015            },
19016            d: function (c) {
19017                return 'day' + (c !== 1 ? 's' : '')
19018            },
19019            h: function (c) {
19020                return 'hour' + (c !== 1 ? 's' : '')
19021            },
19022            m: function (c) {
19023                return 'minute' + (c !== 1 ? 's' : '')
19024            },
19025            s: function (c) {
19026                return 'second' + (c !== 1 ? 's' : '')
19027            },
19028            ms: function (c) {
19029                return 'millisecond' + (c !== 1 ? 's' : '')
19030            },
19031            decimal: '.'
19032        },
19033        es: {
19034            y: function (c) {
19035                return (c === 1 ? 'un ' : '') + 'año' + (c !== 1 ? 's' : '')
19036            },
19037            mo: function (c) {
19038                return (c === 1 ? 'un ' : '') + 'mes' + (c !== 1 ? 'es' : '')
19039            },
19040            w: function (c) {
19041                return (c === 1 ? 'una ' : '') + 'semana' + (c !== 1 ? 's' : '')
19042            },
19043            d: function (c) {
19044                return (c === 1 ? 'un ' : '') + 'día' + (c !== 1 ? 's' : '')
19045            },
19046            h: function (c) {
19047                return (c === 1 ? 'una ' : '') + 'hora' + (c !== 1 ? 's' : '')
19048            },
19049            m: function (c) {
19050                return (c === 1 ? 'un ' : '') + 'minuto' + (c !== 1 ? 's' : '')
19051            },
19052            s: function (c) {
19053                return (c === 1 ? 'un ' : '') + 'segundo' + (c !== 1 ? 's' : '')
19054            },
19055            ms: function (c) {
19056                return (c === 1 ? 'un ' : '') + 'milisegundo' + (c !== 1 ? 's' : '')
19057            },
19058            decimal: ','
19059        }
19060    }
19061
19062    // You can create a humanizer, which returns a function with default
19063    // parameters.
19064    function humanizer(passedOptions) {
19065        var result = function humanizer(ms, humanizerOptions) {
19066            var options = extend({}, result, humanizerOptions || {})
19067            return doHumanization(ms, options)
19068        }
19069
19070        return extend(result, {
19071            language: 'en',
19072            delimiter: ', ',
19073            spacer: ' ',
19074            conjunction: '',
19075            serialComma: true,
19076            units: ['y', 'mo', 'w', 'd', 'h', 'm', 's'],
19077            languages: {},
19078            round: false,
19079            unitMeasures: {
19080                y: 31557600000,
19081                mo: 2629800000,
19082                w: 604800000,
19083                d: 86400000,
19084                h: 3600000,
19085                m: 60000,
19086                s: 1000,
19087                ms: 1
19088            }
19089        }, passedOptions)
19090    }
19091
19092    // The main function is just a wrapper around a default humanizer.
19093    var humanizeDuration = humanizer({})
19094
19095    // doHumanization does the bulk of the work.
19096    function doHumanization(ms, options) {
19097        var i, len, piece
19098
19099        // Make sure we have a positive number.
19100        // Has the nice sideffect of turning Number objects into primitives.
19101        ms = Math.abs(ms)
19102
19103        var dictionary = options.languages[options.language] || languages[options.language]
19104        if (!dictionary) {
19105            throw new Error('No language ' + dictionary + '.')
19106        }
19107
19108        var pieces = []
19109
19110        // Start at the top and keep removing units, bit by bit.
19111        var unitName, unitMS, unitCount
19112        for (i = 0, len = options.units.length; i < len; i++) {
19113            unitName = options.units[i]
19114            unitMS = options.unitMeasures[unitName]
19115
19116            // What's the number of full units we can fit?
19117            if (i + 1 === len) {
19118                unitCount = ms / unitMS
19119            } else {
19120                unitCount = Math.floor(ms / unitMS)
19121            }
19122
19123            // Add the string.
19124            pieces.push({
19125                unitCount: unitCount,
19126                unitName: unitName
19127            })
19128
19129            // Remove what we just figured out.
19130            ms -= unitCount * unitMS
19131        }
19132
19133        var firstOccupiedUnitIndex = 0
19134        for (i = 0; i < pieces.length; i++) {
19135            if (pieces[i].unitCount) {
19136                firstOccupiedUnitIndex = i
19137                break
19138            }
19139        }
19140
19141        if (options.round) {
19142            var ratioToLargerUnit, previousPiece
19143            for (i = pieces.length - 1; i >= 0; i--) {
19144                piece = pieces[i]
19145                piece.unitCount = Math.round(piece.unitCount)
19146
19147                if (i === 0) {
19148                    break
19149                }
19150
19151                previousPiece = pieces[i - 1]
19152
19153                ratioToLargerUnit = options.unitMeasures[previousPiece.unitName] / options.unitMeasures[piece.unitName]
19154                if ((piece.unitCount % ratioToLargerUnit) === 0 || (options.largest && ((options.largest - 1) < (i - firstOccupiedUnitIndex)))) {
19155                    previousPiece.unitCount += piece.unitCount / ratioToLargerUnit
19156                    piece.unitCount = 0
19157                }
19158            }
19159        }
19160
19161        var result = []
19162        for (i = 0, pieces.length; i < len; i++) {
19163            piece = pieces[i]
19164            if (piece.unitCount) {
19165                result.push(render(piece.unitCount, piece.unitName, dictionary, options))
19166            }
19167
19168            if (result.length === options.largest) {
19169                break
19170            }
19171        }
19172
19173        if (result.length) {
19174            if (!options.conjunction || result.length === 1) {
19175                return result.join(options.delimiter)
19176            } else if (result.length === 2) {
19177                return result.join(options.conjunction)
19178            } else if (result.length > 2) {
19179                return result.slice(0, -1).join(options.delimiter) + (options.serialComma ? ',' : '') + options.conjunction + result.slice(-1)
19180            }
19181        } else {
19182            return render(0, options.units[options.units.length - 1], dictionary, options)
19183        }
19184    }
19185
19186    function render(count, type, dictionary, options) {
19187        var decimal
19188        if (options.decimal === void 0) {
19189            decimal = dictionary.decimal
19190        } else {
19191            decimal = options.decimal
19192        }
19193
19194        var countStr = count.toString().replace('.', decimal)
19195
19196        var dictionaryValue = dictionary[type]
19197        var word
19198        if (typeof dictionaryValue === 'function') {
19199            word = dictionaryValue(count)
19200        } else {
19201            word = dictionaryValue
19202        }
19203        if (options.language === 'en' && options.ago) {
19204            word = word + ' ago';
19205        } else if (options.language === 'es' && options.ago) {
19206            // TWCNEWS-3370: NY1Noticias Added handling
19207            countStr = countStr === '1' ? 'hace ' : 'hace ' + countStr;
19208        }
19209        return countStr + options.spacer + word
19210    }
19211
19212    function extend(destination) {
19213        var source
19214        for (var i = 1; i < arguments.length; i++) {
19215            source = arguments[i]
19216            for (var prop in source) {
19217                if (source.hasOwnProperty(prop)) {
19218                    destination[prop] = source[prop]
19219                }
19220            }
19221        }
19222        return destination
19223    }
19224
19225    humanizeDuration.getSupportedLanguages = function getSupportedLanguages() {
19226        var result = []
19227        for (var language in languages) {
19228            if (languages.hasOwnProperty(language)) {
19229                result.push(language)
19230            }
19231        }
19232        return result
19233    }
19234
19235    humanizeDuration.humanizer = humanizer
19236
19237    if (typeof define === 'function' && define.amd) {
19238        define(function () {
19239            return humanizeDuration
19240        })
19241    } else if (typeof module !== 'undefined' && module.exports) {
19242        module.exports = humanizeDuration
19243    } else {
19244        this.humanizeDuration = humanizeDuration
19245    }
19246})();  // eslint-disable-line semi
19247
19248/*! =======================================================
19249                      VERSION  9.8.0              
19250========================================================= */
19251"use strict";
19252
19253var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
19254
19255/*! =========================================================
19256 * bootstrap-slider.js
19257 *
19258 * Maintainers:
19259 *		Kyle Kemp
19260 *			- Twitter: @seiyria
19261 *			- Github:  seiyria
19262 *		Rohit Kalkur
19263 *			- Twitter: @Rovolutionary
19264 *			- Github:  rovolution
19265 *
19266 * =========================================================
19267 *
19268 * bootstrap-slider is released under the MIT License
19269 * Copyright (c) 2017 Kyle Kemp, Rohit Kalkur, and contributors
19270 *
19271 * Permission is hereby granted, free of charge, to any person
19272 * obtaining a copy of this software and associated documentation
19273 * files (the "Software"), to deal in the Software without
19274 * restriction, including without limitation the rights to use,
19275 * copy, modify, merge, publish, distribute, sublicense, and/or sell
19276 * copies of the Software, and to permit persons to whom the
19277 * Software is furnished to do so, subject to the following
19278 * conditions:
19279 *
19280 * The above copyright notice and this permission notice shall be
19281 * included in all copies or substantial portions of the Software.
19282 *
19283 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19284 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19285 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19286 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19287 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19288 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19289 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
19290 * OTHER DEALINGS IN THE SOFTWARE.
19291 *
19292 * ========================================================= */
19293
19294/**
19295 * Bridget makes jQuery widgets
19296 * v1.0.1
19297 * MIT license
19298 */
19299var windowIsDefined = (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object";
19300
19301(function (factory) {
19302	if (typeof define === "function" && define.amd) {
19303		define(["jquery"], factory);
19304	} else if ((typeof module === "undefined" ? "undefined" : _typeof(module)) === "object" && module.exports) {
19305		var jQuery;
19306		try {
19307			jQuery = require("jquery");
19308		} catch (err) {
19309			jQuery = null;
19310		}
19311		module.exports = factory(jQuery);
19312	} else if (window) {
19313		window.Slider = factory(window.jQuery);
19314	}
19315})(function ($) {
19316	// Constants
19317	var NAMESPACE_MAIN = 'slider';
19318	var NAMESPACE_ALTERNATE = 'bootstrapSlider';
19319
19320	// Polyfill console methods
19321	if (windowIsDefined && !window.console) {
19322		window.console = {};
19323	}
19324	if (windowIsDefined && !window.console.log) {
19325		window.console.log = function () {};
19326	}
19327	if (windowIsDefined && !window.console.warn) {
19328		window.console.warn = function () {};
19329	}
19330
19331	// Reference to Slider constructor
19332	var Slider;
19333
19334	(function ($) {
19335
19336		'use strict';
19337
19338		// -------------------------- utils -------------------------- //
19339
19340		var slice = Array.prototype.slice;
19341
19342		function noop() {}
19343
19344		// -------------------------- definition -------------------------- //
19345
19346		function defineBridget($) {
19347
19348			// bail if no jQuery
19349			if (!$) {
19350				return;
19351			}
19352
19353			// -------------------------- addOptionMethod -------------------------- //
19354
19355			/**
19356    * adds option method -> $().plugin('option', {...})
19357    * @param {Function} PluginClass - constructor class
19358    */
19359			function addOptionMethod(PluginClass) {
19360				// don't overwrite original option method
19361				if (PluginClass.prototype.option) {
19362					return;
19363				}
19364
19365				// option setter
19366				PluginClass.prototype.option = function (opts) {
19367					// bail out if not an object
19368					if (!$.isPlainObject(opts)) {
19369						return;
19370					}
19371					this.options = $.extend(true, this.options, opts);
19372				};
19373			}
19374
19375			// -------------------------- plugin bridge -------------------------- //
19376
19377			// helper function for logging errors
19378			// $.error breaks jQuery chaining
19379			var logError = typeof console === 'undefined' ? noop : function (message) {
19380				console.error(message);
19381			};
19382
19383			/**
19384    * jQuery plugin bridge, access methods like $elem.plugin('method')
19385    * @param {String} namespace - plugin name
19386    * @param {Function} PluginClass - constructor class
19387    */
19388			function bridge(namespace, PluginClass) {
19389				// add to jQuery fn namespace
19390				$.fn[namespace] = function (options) {
19391					if (typeof options === 'string') {
19392						// call plugin method when first argument is a string
19393						// get arguments for method
19394						var args = slice.call(arguments, 1);
19395
19396						for (var i = 0, len = this.length; i < len; i++) {
19397							var elem = this[i];
19398							var instance = $.data(elem, namespace);
19399							if (!instance) {
19400								logError("cannot call methods on " + namespace + " prior to initialization; " + "attempted to call '" + options + "'");
19401								continue;
19402							}
19403							if (!$.isFunction(instance[options]) || options.charAt(0) === '_') {
19404								logError("no such method '" + options + "' for " + namespace + " instance");
19405								continue;
19406							}
19407
19408							// trigger method with arguments
19409							var returnValue = instance[options].apply(instance, args);
19410
19411							// break look and return first value if provided
19412							if (returnValue !== undefined && returnValue !== instance) {
19413								return returnValue;
19414							}
19415						}
19416						// return this if no return value
19417						return this;
19418					} else {
19419						var objects = this.map(function () {
19420							var instance = $.data(this, namespace);
19421							if (instance) {
19422								// apply options & init
19423								instance.option(options);
19424								instance._init();
19425							} else {
19426								// initialize new instance
19427								instance = new PluginClass(this, options);
19428								$.data(this, namespace, instance);
19429							}
19430							return $(this);
19431						});
19432
19433						if (!objects || objects.length > 1) {
19434							return objects;
19435						} else {
19436							return objects[0];
19437						}
19438					}
19439				};
19440			}
19441
19442			// -------------------------- bridget -------------------------- //
19443
19444			/**
19445    * converts a Prototypical class into a proper jQuery plugin
19446    *   the class must have a ._init method
19447    * @param {String} namespace - plugin name, used in $().pluginName
19448    * @param {Function} PluginClass - constructor class
19449    */
19450			$.bridget = function (namespace, PluginClass) {
19451				addOptionMethod(PluginClass);
19452				bridge(namespace, PluginClass);
19453			};
19454
19455			return $.bridget;
19456		}
19457
19458		// get jquery from browser global
19459		defineBridget($);
19460	})($);
19461
19462	/*************************************************
19463 			BOOTSTRAP-SLIDER SOURCE CODE
19464 	**************************************************/
19465
19466	(function ($) {
19467
19468		var ErrorMsgs = {
19469			formatInvalidInputErrorMsg: function formatInvalidInputErrorMsg(input) {
19470				return "Invalid input value '" + input + "' passed in";
19471			},
19472			callingContextNotSliderInstance: "Calling context element does not have instance of Slider bound to it. Check your code to make sure the JQuery object returned from the call to the slider() initializer is calling the method"
19473		};
19474
19475		var SliderScale = {
19476			linear: {
19477				toValue: function toValue(percentage) {
19478					var rawValue = percentage / 100 * (this.options.max - this.options.min);
19479					var shouldAdjustWithBase = true;
19480					if (this.options.ticks_positions.length > 0) {
19481						var minv,
19482						    maxv,
19483						    minp,
19484						    maxp = 0;
19485						for (var i = 1; i < this.options.ticks_positions.length; i++) {
19486							if (percentage <= this.options.ticks_positions[i]) {
19487								minv = this.options.ticks[i - 1];
19488								minp = this.options.ticks_positions[i - 1];
19489								maxv = this.options.ticks[i];
19490								maxp = this.options.ticks_positions[i];
19491
19492								break;
19493							}
19494						}
19495						var partialPercentage = (percentage - minp) / (maxp - minp);
19496						rawValue = minv + partialPercentage * (maxv - minv);
19497						shouldAdjustWithBase = false;
19498					}
19499
19500					var adjustment = shouldAdjustWithBase ? this.options.min : 0;
19501					var value = adjustment + Math.round(rawValue / this.options.step) * this.options.step;
19502					if (value < this.options.min) {
19503						return this.options.min;
19504					} else if (value > this.options.max) {
19505						return this.options.max;
19506					} else {
19507						return value;
19508					}
19509				},
19510				toPercentage: function toPercentage(value) {
19511					if (this.options.max === this.options.min) {
19512						return 0;
19513					}
19514
19515					if (this.options.ticks_positions.length > 0) {
19516						var minv,
19517						    maxv,
19518						    minp,
19519						    maxp = 0;
19520						for (var i = 0; i < this.options.ticks.length; i++) {
19521							if (value <= this.options.ticks[i]) {
19522								minv = i > 0 ? this.options.ticks[i - 1] : 0;
19523								minp = i > 0 ? this.options.ticks_positions[i - 1] : 0;
19524								maxv = this.options.ticks[i];
19525								maxp = this.options.ticks_positions[i];
19526
19527								break;
19528							}
19529						}
19530						if (i > 0) {
19531							var partialPercentage = (value - minv) / (maxv - minv);
19532							return minp + partialPercentage * (maxp - minp);
19533						}
19534					}
19535
19536					return 100 * (value - this.options.min) / (this.options.max - this.options.min);
19537				}
19538			},
19539
19540			logarithmic: {
19541				/* Based on http://stackoverflow.com/questions/846221/logarithmic-slider */
19542				toValue: function toValue(percentage) {
19543					var min = this.options.min === 0 ? 0 : Math.log(this.options.min);
19544					var max = Math.log(this.options.max);
19545					var value = Math.exp(min + (max - min) * percentage / 100);
19546					value = this.options.min + Math.round((value - this.options.min) / this.options.step) * this.options.step;
19547					/* Rounding to the nearest step could exceed the min or
19548      * max, so clip to those values. */
19549					if (value < this.options.min) {
19550						return this.options.min;
19551					} else if (value > this.options.max) {
19552						return this.options.max;
19553					} else {
19554						return value;
19555					}
19556				},
19557				toPercentage: function toPercentage(value) {
19558					if (this.options.max === this.options.min) {
19559						return 0;
19560					} else {
19561						var max = Math.log(this.options.max);
19562						var min = this.options.min === 0 ? 0 : Math.log(this.options.min);
19563						var v = value === 0 ? 0 : Math.log(value);
19564						return 100 * (v - min) / (max - min);
19565					}
19566				}
19567			}
19568		};
19569
19570		/*************************************************
19571  						CONSTRUCTOR
19572  	**************************************************/
19573		Slider = function (element, options) {
19574			createNewSlider.call(this, element, options);
19575			return this;
19576		};
19577
19578		function createNewSlider(element, options) {
19579
19580			/*
19581   	The internal state object is used to store data about the current 'state' of slider.
19582   	This includes values such as the `value`, `enabled`, etc...
19583   */
19584			this._state = {
19585				value: null,
19586				enabled: null,
19587				offset: null,
19588				size: null,
19589				percentage: null,
19590				inDrag: false,
19591				over: false
19592			};
19593
19594			// The objects used to store the reference to the tick methods if ticks_tooltip is on
19595			this.ticksCallbackMap = {};
19596			this.handleCallbackMap = {};
19597
19598			if (typeof element === "string") {
19599				this.element = document.querySelector(element);
19600			} else if (element instanceof HTMLElement) {
19601				this.element = element;
19602			}
19603
19604			/*************************************************
19605   					Process Options
19606   	**************************************************/
19607			options = options ? options : {};
19608			var optionTypes = Object.keys(this.defaultOptions);
19609
19610			for (var i = 0; i < optionTypes.length; i++) {
19611				var optName = optionTypes[i];
19612
19613				// First check if an option was passed in via the constructor
19614				var val = options[optName];
19615				// If no data attrib, then check data atrributes
19616				val = typeof val !== 'undefined' ? val : getDataAttrib(this.element, optName);
19617				// Finally, if nothing was specified, use the defaults
19618				val = val !== null ? val : this.defaultOptions[optName];
19619
19620				// Set all options on the instance of the Slider
19621				if (!this.options) {
19622					this.options = {};
19623				}
19624				this.options[optName] = val;
19625			}
19626
19627			// Check options.rtl
19628			if (this.options.rtl === 'auto') {
19629				this.options.rtl = window.getComputedStyle(this.element).direction === 'rtl';
19630			}
19631
19632			/*
19633   	Validate `tooltip_position` against 'orientation`
19634   	- if `tooltip_position` is incompatible with orientation, swith it to a default compatible with specified `orientation`
19635   		-- default for "vertical" -> "right", "left" if rtl
19636   		-- default for "horizontal" -> "top"
19637   */
19638			if (this.options.orientation === "vertical" && (this.options.tooltip_position === "top" || this.options.tooltip_position === "bottom")) {
19639				if (this.options.rtl) {
19640					this.options.tooltip_position = "left";
19641				} else {
19642					this.options.tooltip_position = "right";
19643				}
19644			} else if (this.options.orientation === "horizontal" && (this.options.tooltip_position === "left" || this.options.tooltip_position === "right")) {
19645
19646				this.options.tooltip_position = "top";
19647			}
19648
19649			function getDataAttrib(element, optName) {
19650				var dataName = "data-slider-" + optName.replace(/_/g, '-');
19651				var dataValString = element.getAttribute(dataName);
19652
19653				try {
19654					return JSON.parse(dataValString);
19655				} catch (err) {
19656					return dataValString;
19657				}
19658			}
19659
19660			/*************************************************
19661   					Create Markup
19662   	**************************************************/
19663
19664			var origWidth = this.element.style.width;
19665			var updateSlider = false;
19666			var parent = this.element.parentNode;
19667			var sliderTrackSelection;
19668			var sliderTrackLow, sliderTrackHigh;
19669			var sliderMinHandle;
19670			var sliderMaxHandle;
19671
19672			if (this.sliderElem) {
19673				updateSlider = true;
19674			} else {
19675				/* Create elements needed for slider */
19676				this.sliderElem = document.createElement("div");
19677				this.sliderElem.className = "slider";
19678
19679				/* Create slider track elements */
19680				var sliderTrack = document.createElement("div");
19681				sliderTrack.className = "slider-track";
19682
19683				sliderTrackLow = document.createElement("div");
19684				sliderTrackLow.className = "slider-track-low";
19685
19686				sliderTrackSelection = document.createElement("div");
19687				sliderTrackSelection.className = "slider-selection";
19688
19689				sliderTrackHigh = document.createElement("div");
19690				sliderTrackHigh.className = "slider-track-high";
19691
19692				sliderMinHandle = document.createElement("div");
19693				sliderMinHandle.className = "slider-handle min-slider-handle";
19694				sliderMinHandle.setAttribute('role', 'slider');
19695				sliderMinHandle.setAttribute('aria-valuemin', this.options.min);
19696				sliderMinHandle.setAttribute('aria-valuemax', this.options.max);
19697
19698				sliderMaxHandle = document.createElement("div");
19699				sliderMaxHandle.className = "slider-handle max-slider-handle";
19700				sliderMaxHandle.setAttribute('role', 'slider');
19701				sliderMaxHandle.setAttribute('aria-valuemin', this.options.min);
19702				sliderMaxHandle.setAttribute('aria-valuemax', this.options.max);
19703
19704				sliderTrack.appendChild(sliderTrackLow);
19705				sliderTrack.appendChild(sliderTrackSelection);
19706				sliderTrack.appendChild(sliderTrackHigh);
19707
19708				/* Create highlight range elements */
19709				this.rangeHighlightElements = [];
19710				var rangeHighlightsOpts = this.options.rangeHighlights;
19711				if (Array.isArray(rangeHighlightsOpts) && rangeHighlightsOpts.length > 0) {
19712					for (var j = 0; j < rangeHighlightsOpts.length; j++) {
19713						var rangeHighlightElement = document.createElement("div");
19714						var customClassString = rangeHighlightsOpts[j]['class'] || "";
19715						rangeHighlightElement.className = "slider-rangeHighlight slider-selection " + customClassString;
19716						this.rangeHighlightElements.push(rangeHighlightElement);
19717						sliderTrack.appendChild(rangeHighlightElement);
19718					}
19719				}
19720
19721				/* Add aria-labelledby to handle's */
19722				var isLabelledbyArray = Array.isArray(this.options.labelledby);
19723				if (isLabelledbyArray && this.options.labelledby[0]) {
19724					sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby[0]);
19725				}
19726				if (isLabelledbyArray && this.options.labelledby[1]) {
19727					sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby[1]);
19728				}
19729				if (!isLabelledbyArray && this.options.labelledby) {
19730					sliderMinHandle.setAttribute('aria-labelledby', this.options.labelledby);
19731					sliderMaxHandle.setAttribute('aria-labelledby', this.options.labelledby);
19732				}
19733
19734				/* Create ticks */
19735				this.ticks = [];
19736				if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
19737					this.ticksContainer = document.createElement('div');
19738					this.ticksContainer.className = 'slider-tick-container';
19739
19740					for (i = 0; i < this.options.ticks.length; i++) {
19741						var tick = document.createElement('div');
19742						tick.className = 'slider-tick';
19743						if (this.options.ticks_tooltip) {
19744							var tickListenerReference = this._addTickListener();
19745							var enterCallback = tickListenerReference.addMouseEnter(this, tick, i);
19746							var leaveCallback = tickListenerReference.addMouseLeave(this, tick);
19747
19748							this.ticksCallbackMap[i] = {
19749								mouseEnter: enterCallback,
19750								mouseLeave: leaveCallback
19751							};
19752						}
19753						this.ticks.push(tick);
19754						this.ticksContainer.appendChild(tick);
19755					}
19756
19757					sliderTrackSelection.className += " tick-slider-selection";
19758				}
19759
19760				this.tickLabels = [];
19761				if (Array.isArray(this.options.ticks_labels) && this.options.ticks_labels.length > 0) {
19762					this.tickLabelContainer = document.createElement('div');
19763					this.tickLabelContainer.className = 'slider-tick-label-container';
19764
19765					for (i = 0; i < this.options.ticks_labels.length; i++) {
19766						var label = document.createElement('div');
19767						var noTickPositionsSpecified = this.options.ticks_positions.length === 0;
19768						var tickLabelsIndex = this.options.reversed && noTickPositionsSpecified ? this.options.ticks_labels.length - (i + 1) : i;
19769						label.className = 'slider-tick-label';
19770						label.innerHTML = this.options.ticks_labels[tickLabelsIndex];
19771
19772						this.tickLabels.push(label);
19773						this.tickLabelContainer.appendChild(label);
19774					}
19775				}
19776
19777				var createAndAppendTooltipSubElements = function createAndAppendTooltipSubElements(tooltipElem) {
19778					var arrow = document.createElement("div");
19779					arrow.className = "tooltip-arrow";
19780
19781					var inner = document.createElement("div");
19782					inner.className = "tooltip-inner";
19783
19784					tooltipElem.appendChild(arrow);
19785					tooltipElem.appendChild(inner);
19786				};
19787
19788				/* Create tooltip elements */
19789				var sliderTooltip = document.createElement("div");
19790				sliderTooltip.className = "tooltip tooltip-main";
19791				sliderTooltip.setAttribute('role', 'presentation');
19792				createAndAppendTooltipSubElements(sliderTooltip);
19793
19794				var sliderTooltipMin = document.createElement("div");
19795				sliderTooltipMin.className = "tooltip tooltip-min";
19796				sliderTooltipMin.setAttribute('role', 'presentation');
19797				createAndAppendTooltipSubElements(sliderTooltipMin);
19798
19799				var sliderTooltipMax = document.createElement("div");
19800				sliderTooltipMax.className = "tooltip tooltip-max";
19801				sliderTooltipMax.setAttribute('role', 'presentation');
19802				createAndAppendTooltipSubElements(sliderTooltipMax);
19803
19804				/* Append components to sliderElem */
19805				this.sliderElem.appendChild(sliderTrack);
19806				this.sliderElem.appendChild(sliderTooltip);
19807				this.sliderElem.appendChild(sliderTooltipMin);
19808				this.sliderElem.appendChild(sliderTooltipMax);
19809
19810				if (this.tickLabelContainer) {
19811					this.sliderElem.appendChild(this.tickLabelContainer);
19812				}
19813				if (this.ticksContainer) {
19814					this.sliderElem.appendChild(this.ticksContainer);
19815				}
19816
19817				this.sliderElem.appendChild(sliderMinHandle);
19818				this.sliderElem.appendChild(sliderMaxHandle);
19819
19820				/* Append slider element to parent container, right before the original <input> element */
19821				parent.insertBefore(this.sliderElem, this.element);
19822
19823				/* Hide original <input> element */
19824				this.element.style.display = "none";
19825			}
19826			/* If JQuery exists, cache JQ references */
19827			if ($) {
19828				this.$element = $(this.element);
19829				this.$sliderElem = $(this.sliderElem);
19830			}
19831
19832			/*************************************************
19833   						Setup
19834   	**************************************************/
19835			this.eventToCallbackMap = {};
19836			this.sliderElem.id = this.options.id;
19837
19838			this.touchCapable = 'ontouchstart' in window || window.DocumentTouch && document instanceof window.DocumentTouch;
19839
19840			this.touchX = 0;
19841			this.touchY = 0;
19842
19843			this.tooltip = this.sliderElem.querySelector('.tooltip-main');
19844			this.tooltipInner = this.tooltip.querySelector('.tooltip-inner');
19845
19846			this.tooltip_min = this.sliderElem.querySelector('.tooltip-min');
19847			this.tooltipInner_min = this.tooltip_min.querySelector('.tooltip-inner');
19848
19849			this.tooltip_max = this.sliderElem.querySelector('.tooltip-max');
19850			this.tooltipInner_max = this.tooltip_max.querySelector('.tooltip-inner');
19851
19852			if (SliderScale[this.options.scale]) {
19853				this.options.scale = SliderScale[this.options.scale];
19854			}
19855
19856			if (updateSlider === true) {
19857				// Reset classes
19858				this._removeClass(this.sliderElem, 'slider-horizontal');
19859				this._removeClass(this.sliderElem, 'slider-vertical');
19860				this._removeClass(this.sliderElem, 'slider-rtl');
19861				this._removeClass(this.tooltip, 'hide');
19862				this._removeClass(this.tooltip_min, 'hide');
19863				this._removeClass(this.tooltip_max, 'hide');
19864
19865				// Undo existing inline styles for track
19866				["left", "right", "top", "width", "height"].forEach(function (prop) {
19867					this._removeProperty(this.trackLow, prop);
19868					this._removeProperty(this.trackSelection, prop);
19869					this._removeProperty(this.trackHigh, prop);
19870				}, this);
19871
19872				// Undo inline styles on handles
19873				[this.handle1, this.handle2].forEach(function (handle) {
19874					this._removeProperty(handle, 'left');
19875					this._removeProperty(handle, 'right');
19876					this._removeProperty(handle, 'top');
19877				}, this);
19878
19879				// Undo inline styles and classes on tooltips
19880				[this.tooltip, this.tooltip_min, this.tooltip_max].forEach(function (tooltip) {
19881					this._removeProperty(tooltip, 'left');
19882					this._removeProperty(tooltip, 'right');
19883					this._removeProperty(tooltip, 'top');
19884					this._removeProperty(tooltip, 'margin-left');
19885					this._removeProperty(tooltip, 'margin-right');
19886					this._removeProperty(tooltip, 'margin-top');
19887
19888					this._removeClass(tooltip, 'right');
19889					this._removeClass(tooltip, 'left');
19890					this._removeClass(tooltip, 'top');
19891				}, this);
19892			}
19893
19894			if (this.options.orientation === 'vertical') {
19895				this._addClass(this.sliderElem, 'slider-vertical');
19896				this.stylePos = 'top';
19897				this.mousePos = 'pageY';
19898				this.sizePos = 'offsetHeight';
19899			} else {
19900				this._addClass(this.sliderElem, 'slider-horizontal');
19901				this.sliderElem.style.width = origWidth;
19902				this.options.orientation = 'horizontal';
19903				if (this.options.rtl) {
19904					this.stylePos = 'right';
19905				} else {
19906					this.stylePos = 'left';
19907				}
19908				this.mousePos = 'pageX';
19909				this.sizePos = 'offsetWidth';
19910			}
19911			// specific rtl class
19912			if (this.options.rtl) {
19913				this._addClass(this.sliderElem, 'slider-rtl');
19914			}
19915			this._setTooltipPosition();
19916			/* In case ticks are specified, overwrite the min and max bounds */
19917			if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
19918				this.options.max = Math.max.apply(Math, this.options.ticks);
19919				this.options.min = Math.min.apply(Math, this.options.ticks);
19920			}
19921
19922			if (Array.isArray(this.options.value)) {
19923				this.options.range = true;
19924				this._state.value = this.options.value;
19925			} else if (this.options.range) {
19926				// User wants a range, but value is not an array
19927				this._state.value = [this.options.value, this.options.max];
19928			} else {
19929				this._state.value = this.options.value;
19930			}
19931
19932			this.trackLow = sliderTrackLow || this.trackLow;
19933			this.trackSelection = sliderTrackSelection || this.trackSelection;
19934			this.trackHigh = sliderTrackHigh || this.trackHigh;
19935
19936			if (this.options.selection === 'none') {
19937				this._addClass(this.trackLow, 'hide');
19938				this._addClass(this.trackSelection, 'hide');
19939				this._addClass(this.trackHigh, 'hide');
19940			} else if (this.options.selection === 'after' || this.options.selection === 'before') {
19941				this._removeClass(this.trackLow, 'hide');
19942				this._removeClass(this.trackSelection, 'hide');
19943				this._removeClass(this.trackHigh, 'hide');
19944			}
19945
19946			this.handle1 = sliderMinHandle || this.handle1;
19947			this.handle2 = sliderMaxHandle || this.handle2;
19948
19949			if (updateSlider === true) {
19950				// Reset classes
19951				this._removeClass(this.handle1, 'round triangle');
19952				this._removeClass(this.handle2, 'round triangle hide');
19953
19954				for (i = 0; i < this.ticks.length; i++) {
19955					this._removeClass(this.ticks[i], 'round triangle hide');
19956				}
19957			}
19958
19959			var availableHandleModifiers = ['round', 'triangle', 'custom'];
19960			var isValidHandleType = availableHandleModifiers.indexOf(this.options.handle) !== -1;
19961			if (isValidHandleType) {
19962				this._addClass(this.handle1, this.options.handle);
19963				this._addClass(this.handle2, this.options.handle);
19964
19965				for (i = 0; i < this.ticks.length; i++) {
19966					this._addClass(this.ticks[i], this.options.handle);
19967				}
19968			}
19969
19970			this._state.offset = this._offset(this.sliderElem);
19971			this._state.size = this.sliderElem[this.sizePos];
19972			this.setValue(this._state.value);
19973
19974			/******************************************
19975   				Bind Event Listeners
19976   	******************************************/
19977
19978			// Bind keyboard handlers
19979			this.handle1Keydown = this._keydown.bind(this, 0);
19980			this.handle1.addEventListener("keydown", this.handle1Keydown, false);
19981
19982			this.handle2Keydown = this._keydown.bind(this, 1);
19983			this.handle2.addEventListener("keydown", this.handle2Keydown, false);
19984
19985			this.mousedown = this._mousedown.bind(this);
19986			this.touchstart = this._touchstart.bind(this);
19987			this.touchmove = this._touchmove.bind(this);
19988
19989			if (this.touchCapable) {
19990				// Test for passive event support
19991				var supportsPassive = false;
19992				try {
19993					var opts = Object.defineProperty({}, 'passive', {
19994						get: function get() {
19995							supportsPassive = true;
19996						}
19997					});
19998					window.addEventListener("test", null, opts);
19999				} catch (e) {}
20000				// Use our detect's results. passive applied if supported, capture will be false either way.
20001				var eventOptions = supportsPassive ? { passive: true } : false;
20002				// Bind touch handlers
20003				this.sliderElem.addEventListener("touchstart", this.touchstart, eventOptions);
20004				this.sliderElem.addEventListener("touchmove", this.touchmove, eventOptions);
20005			}
20006			this.sliderElem.addEventListener("mousedown", this.mousedown, false);
20007
20008			// Bind window handlers
20009			this.resize = this._resize.bind(this);
20010			window.addEventListener("resize", this.resize, false);
20011
20012			// Bind tooltip-related handlers
20013			if (this.options.tooltip === 'hide') {
20014				this._addClass(this.tooltip, 'hide');
20015				this._addClass(this.tooltip_min, 'hide');
20016				this._addClass(this.tooltip_max, 'hide');
20017			} else if (this.options.tooltip === 'always') {
20018				this._showTooltip();
20019				this._alwaysShowTooltip = true;
20020			} else {
20021				this.showTooltip = this._showTooltip.bind(this);
20022				this.hideTooltip = this._hideTooltip.bind(this);
20023
20024				if (this.options.ticks_tooltip) {
20025					var callbackHandle = this._addTickListener();
20026					//create handle1 listeners and store references in map
20027					var mouseEnter = callbackHandle.addMouseEnter(this, this.handle1);
20028					var mouseLeave = callbackHandle.addMouseLeave(this, this.handle1);
20029					this.handleCallbackMap.handle1 = {
20030						mouseEnter: mouseEnter,
20031						mouseLeave: mouseLeave
20032					};
20033					//create handle2 listeners and store references in map
20034					mouseEnter = callbackHandle.addMouseEnter(this, this.handle2);
20035					mouseLeave = callbackHandle.addMouseLeave(this, this.handle2);
20036					this.handleCallbackMap.handle2 = {
20037						mouseEnter: mouseEnter,
20038						mouseLeave: mouseLeave
20039					};
20040				} else {
20041					this.sliderElem.addEventListener("mouseenter", this.showTooltip, false);
20042					this.sliderElem.addEventListener("mouseleave", this.hideTooltip, false);
20043				}
20044
20045				this.handle1.addEventListener("focus", this.showTooltip, false);
20046				this.handle1.addEventListener("blur", this.hideTooltip, false);
20047
20048				this.handle2.addEventListener("focus", this.showTooltip, false);
20049				this.handle2.addEventListener("blur", this.hideTooltip, false);
20050			}
20051
20052			if (this.options.enabled) {
20053				this.enable();
20054			} else {
20055				this.disable();
20056			}
20057		}
20058
20059		/*************************************************
20060  				INSTANCE PROPERTIES/METHODS
20061  	- Any methods bound to the prototype are considered
20062  part of the plugin's `public` interface
20063  	**************************************************/
20064		Slider.prototype = {
20065			_init: function _init() {}, // NOTE: Must exist to support bridget
20066
20067			constructor: Slider,
20068
20069			defaultOptions: {
20070				id: "",
20071				min: 0,
20072				max: 10,
20073				step: 1,
20074				precision: 0,
20075				orientation: 'horizontal',
20076				value: 5,
20077				range: false,
20078				selection: 'before',
20079				tooltip: 'show',
20080				tooltip_split: false,
20081				handle: 'round',
20082				reversed: false,
20083				rtl: 'auto',
20084				enabled: true,
20085				formatter: function formatter(val) {
20086					if (Array.isArray(val)) {
20087						return val[0] + " : " + val[1];
20088					} else {
20089						return val;
20090					}
20091				},
20092				natural_arrow_keys: false,
20093				ticks: [],
20094				ticks_positions: [],
20095				ticks_labels: [],
20096				ticks_snap_bounds: 0,
20097				ticks_tooltip: false,
20098				scale: 'linear',
20099				focus: false,
20100				tooltip_position: null,
20101				labelledby: null,
20102				rangeHighlights: []
20103			},
20104
20105			getElement: function getElement() {
20106				return this.sliderElem;
20107			},
20108
20109			getValue: function getValue() {
20110				if (this.options.range) {
20111					return this._state.value;
20112				} else {
20113					return this._state.value[0];
20114				}
20115			},
20116
20117			setValue: function setValue(val, triggerSlideEvent, triggerChangeEvent) {
20118				if (!val) {
20119					val = 0;
20120				}
20121				var oldValue = this.getValue();
20122				this._state.value = this._validateInputValue(val);
20123				var applyPrecision = this._applyPrecision.bind(this);
20124
20125				if (this.options.range) {
20126					this._state.value[0] = applyPrecision(this._state.value[0]);
20127					this._state.value[1] = applyPrecision(this._state.value[1]);
20128
20129					this._state.value[0] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[0]));
20130					this._state.value[1] = Math.max(this.options.min, Math.min(this.options.max, this._state.value[1]));
20131				} else {
20132					this._state.value = applyPrecision(this._state.value);
20133					this._state.value = [Math.max(this.options.min, Math.min(this.options.max, this._state.value))];
20134					this._addClass(this.handle2, 'hide');
20135					if (this.options.selection === 'after') {
20136						this._state.value[1] = this.options.max;
20137					} else {
20138						this._state.value[1] = this.options.min;
20139					}
20140				}
20141
20142				if (this.options.max > this.options.min) {
20143					this._state.percentage = [this._toPercentage(this._state.value[0]), this._toPercentage(this._state.value[1]), this.options.step * 100 / (this.options.max - this.options.min)];
20144				} else {
20145					this._state.percentage = [0, 0, 100];
20146				}
20147
20148				this._layout();
20149				var newValue = this.options.range ? this._state.value : this._state.value[0];
20150
20151				this._setDataVal(newValue);
20152				if (triggerSlideEvent === true) {
20153					this._trigger('slide', newValue);
20154				}
20155				if (oldValue !== newValue && triggerChangeEvent === true) {
20156					this._trigger('change', {
20157						oldValue: oldValue,
20158						newValue: newValue
20159					});
20160				}
20161
20162				return this;
20163			},
20164
20165			destroy: function destroy() {
20166				// Remove event handlers on slider elements
20167				this._removeSliderEventHandlers();
20168
20169				// Remove the slider from the DOM
20170				this.sliderElem.parentNode.removeChild(this.sliderElem);
20171				/* Show original <input> element */
20172				this.element.style.display = "";
20173
20174				// Clear out custom event bindings
20175				this._cleanUpEventCallbacksMap();
20176
20177				// Remove data values
20178				this.element.removeAttribute("data");
20179
20180				// Remove JQuery handlers/data
20181				if ($) {
20182					this._unbindJQueryEventHandlers();
20183					this.$element.removeData('slider');
20184				}
20185			},
20186
20187			disable: function disable() {
20188				this._state.enabled = false;
20189				this.handle1.removeAttribute("tabindex");
20190				this.handle2.removeAttribute("tabindex");
20191				this._addClass(this.sliderElem, 'slider-disabled');
20192				this._trigger('slideDisabled');
20193
20194				return this;
20195			},
20196
20197			enable: function enable() {
20198				this._state.enabled = true;
20199				this.handle1.setAttribute("tabindex", 0);
20200				this.handle2.setAttribute("tabindex", 0);
20201				this._removeClass(this.sliderElem, 'slider-disabled');
20202				this._trigger('slideEnabled');
20203
20204				return this;
20205			},
20206
20207			toggle: function toggle() {
20208				if (this._state.enabled) {
20209					this.disable();
20210				} else {
20211					this.enable();
20212				}
20213				return this;
20214			},
20215
20216			isEnabled: function isEnabled() {
20217				return this._state.enabled;
20218			},
20219
20220			on: function on(evt, callback) {
20221				this._bindNonQueryEventHandler(evt, callback);
20222				return this;
20223			},
20224
20225			off: function off(evt, callback) {
20226				if ($) {
20227					this.$element.off(evt, callback);
20228					this.$sliderElem.off(evt, callback);
20229				} else {
20230					this._unbindNonQueryEventHandler(evt, callback);
20231				}
20232			},
20233
20234			getAttribute: function getAttribute(attribute) {
20235				if (attribute) {
20236					return this.options[attribute];
20237				} else {
20238					return this.options;
20239				}
20240			},
20241
20242			setAttribute: function setAttribute(attribute, value) {
20243				this.options[attribute] = value;
20244				return this;
20245			},
20246
20247			refresh: function refresh() {
20248				this._removeSliderEventHandlers();
20249				createNewSlider.call(this, this.element, this.options);
20250				if ($) {
20251					// Bind new instance of slider to the element
20252					$.data(this.element, 'slider', this);
20253				}
20254				return this;
20255			},
20256
20257			relayout: function relayout() {
20258				this._resize();
20259				this._layout();
20260				return this;
20261			},
20262
20263			/******************************+
20264   				HELPERS
20265   	- Any method that is not part of the public interface.
20266   - Place it underneath this comment block and write its signature like so:
20267   		_fnName : function() {...}
20268   	********************************/
20269			_removeSliderEventHandlers: function _removeSliderEventHandlers() {
20270				// Remove keydown event listeners
20271				this.handle1.removeEventListener("keydown", this.handle1Keydown, false);
20272				this.handle2.removeEventListener("keydown", this.handle2Keydown, false);
20273
20274				//remove the listeners from the ticks and handles if they had their own listeners
20275				if (this.options.ticks_tooltip) {
20276					var ticks = this.ticksContainer.getElementsByClassName('slider-tick');
20277					for (var i = 0; i < ticks.length; i++) {
20278						ticks[i].removeEventListener('mouseenter', this.ticksCallbackMap[i].mouseEnter, false);
20279						ticks[i].removeEventListener('mouseleave', this.ticksCallbackMap[i].mouseLeave, false);
20280					}
20281					this.handle1.removeEventListener('mouseenter', this.handleCallbackMap.handle1.mouseEnter, false);
20282					this.handle2.removeEventListener('mouseenter', this.handleCallbackMap.handle2.mouseEnter, false);
20283					this.handle1.removeEventListener('mouseleave', this.handleCallbackMap.handle1.mouseLeave, false);
20284					this.handle2.removeEventListener('mouseleave', this.handleCallbackMap.handle2.mouseLeave, false);
20285				}
20286
20287				this.handleCallbackMap = null;
20288				this.ticksCallbackMap = null;
20289
20290				if (this.showTooltip) {
20291					this.handle1.removeEventListener("focus", this.showTooltip, false);
20292					this.handle2.removeEventListener("focus", this.showTooltip, false);
20293				}
20294				if (this.hideTooltip) {
20295					this.handle1.removeEventListener("blur", this.hideTooltip, false);
20296					this.handle2.removeEventListener("blur", this.hideTooltip, false);
20297				}
20298
20299				// Remove event listeners from sliderElem
20300				if (this.showTooltip) {
20301					this.sliderElem.removeEventListener("mouseenter", this.showTooltip, false);
20302				}
20303				if (this.hideTooltip) {
20304					this.sliderElem.removeEventListener("mouseleave", this.hideTooltip, false);
20305				}
20306				this.sliderElem.removeEventListener("touchstart", this.touchstart, false);
20307				this.sliderElem.removeEventListener("touchmove", this.touchmove, false);
20308				this.sliderElem.removeEventListener("mousedown", this.mousedown, false);
20309
20310				// Remove window event listener
20311				window.removeEventListener("resize", this.resize, false);
20312			},
20313			_bindNonQueryEventHandler: function _bindNonQueryEventHandler(evt, callback) {
20314				if (this.eventToCallbackMap[evt] === undefined) {
20315					this.eventToCallbackMap[evt] = [];
20316				}
20317				this.eventToCallbackMap[evt].push(callback);
20318			},
20319			_unbindNonQueryEventHandler: function _unbindNonQueryEventHandler(evt, callback) {
20320				var callbacks = this.eventToCallbackMap[evt];
20321				if (callbacks !== undefined) {
20322					for (var i = 0; i < callbacks.length; i++) {
20323						if (callbacks[i] === callback) {
20324							callbacks.splice(i, 1);
20325							break;
20326						}
20327					}
20328				}
20329			},
20330			_cleanUpEventCallbacksMap: function _cleanUpEventCallbacksMap() {
20331				var eventNames = Object.keys(this.eventToCallbackMap);
20332				for (var i = 0; i < eventNames.length; i++) {
20333					var eventName = eventNames[i];
20334					delete this.eventToCallbackMap[eventName];
20335				}
20336			},
20337			_showTooltip: function _showTooltip() {
20338				if (this.options.tooltip_split === false) {
20339					this._addClass(this.tooltip, 'in');
20340					this.tooltip_min.style.display = 'none';
20341					this.tooltip_max.style.display = 'none';
20342				} else {
20343					this._addClass(this.tooltip_min, 'in');
20344					this._addClass(this.tooltip_max, 'in');
20345					this.tooltip.style.display = 'none';
20346				}
20347				this._state.over = true;
20348			},
20349			_hideTooltip: function _hideTooltip() {
20350				if (this._state.inDrag === false && this.alwaysShowTooltip !== true) {
20351					this._removeClass(this.tooltip, 'in');
20352					this._removeClass(this.tooltip_min, 'in');
20353					this._removeClass(this.tooltip_max, 'in');
20354				}
20355				this._state.over = false;
20356			},
20357			_setToolTipOnMouseOver: function _setToolTipOnMouseOver(tempState) {
20358				var formattedTooltipVal = this.options.formatter(!tempState ? this._state.value[0] : tempState.value[0]);
20359				var positionPercentages = !tempState ? getPositionPercentages(this._state, this.options.reversed) : getPositionPercentages(tempState, this.options.reversed);
20360				this._setText(this.tooltipInner, formattedTooltipVal);
20361
20362				this.tooltip.style[this.stylePos] = positionPercentages[0] + "%";
20363				if (this.options.orientation === 'vertical') {
20364					this._css(this.tooltip, "margin-" + this.stylePos, -this.tooltip.offsetHeight / 2 + "px");
20365				} else {
20366					this._css(this.tooltip, "margin-" + this.stylePos, -this.tooltip.offsetWidth / 2 + "px");
20367				}
20368
20369				function getPositionPercentages(state, reversed) {
20370					if (reversed) {
20371						return [100 - state.percentage[0], this.options.range ? 100 - state.percentage[1] : state.percentage[1]];
20372					}
20373					return [state.percentage[0], state.percentage[1]];
20374				}
20375			},
20376			_addTickListener: function _addTickListener() {
20377				return {
20378					addMouseEnter: function addMouseEnter(reference, tick, index) {
20379						var enter = function enter() {
20380							var tempState = reference._state;
20381							var idString = index >= 0 ? index : this.attributes['aria-valuenow'].value;
20382							var hoverIndex = parseInt(idString, 10);
20383							tempState.value[0] = hoverIndex;
20384							tempState.percentage[0] = reference.options.ticks_positions[hoverIndex];
20385							reference._setToolTipOnMouseOver(tempState);
20386							reference._showTooltip();
20387						};
20388						tick.addEventListener("mouseenter", enter, false);
20389						return enter;
20390					},
20391					addMouseLeave: function addMouseLeave(reference, tick) {
20392						var leave = function leave() {
20393							reference._hideTooltip();
20394						};
20395						tick.addEventListener("mouseleave", leave, false);
20396						return leave;
20397					}
20398				};
20399			},
20400			_layout: function _layout() {
20401				var positionPercentages;
20402
20403				if (this.options.reversed) {
20404					positionPercentages = [100 - this._state.percentage[0], this.options.range ? 100 - this._state.percentage[1] : this._state.percentage[1]];
20405				} else {
20406					positionPercentages = [this._state.percentage[0], this._state.percentage[1]];
20407				}
20408
20409				this.handle1.style[this.stylePos] = positionPercentages[0] + "%";
20410				this.handle1.setAttribute('aria-valuenow', this._state.value[0]);
20411				if (isNaN(this.options.formatter(this._state.value[0]))) {
20412					this.handle1.setAttribute('aria-valuetext', this.options.formatter(this._state.value[0]));
20413				}
20414
20415				this.handle2.style[this.stylePos] = positionPercentages[1] + "%";
20416				this.handle2.setAttribute('aria-valuenow', this._state.value[1]);
20417				if (isNaN(this.options.formatter(this._state.value[1]))) {
20418					this.handle2.setAttribute('aria-valuetext', this.options.formatter(this._state.value[1]));
20419				}
20420
20421				/* Position highlight range elements */
20422				if (this.rangeHighlightElements.length > 0 && Array.isArray(this.options.rangeHighlights) && this.options.rangeHighlights.length > 0) {
20423					for (var _i = 0; _i < this.options.rangeHighlights.length; _i++) {
20424						var startPercent = this._toPercentage(this.options.rangeHighlights[_i].start);
20425						var endPercent = this._toPercentage(this.options.rangeHighlights[_i].end);
20426
20427						if (this.options.reversed) {
20428							var sp = 100 - endPercent;
20429							endPercent = 100 - startPercent;
20430							startPercent = sp;
20431						}
20432
20433						var currentRange = this._createHighlightRange(startPercent, endPercent);
20434
20435						if (currentRange) {
20436							if (this.options.orientation === 'vertical') {
20437								this.rangeHighlightElements[_i].style.top = currentRange.start + "%";
20438								this.rangeHighlightElements[_i].style.height = currentRange.size + "%";
20439							} else {
20440								if (this.options.rtl) {
20441									this.rangeHighlightElements[_i].style.right = currentRange.start + "%";
20442								} else {
20443									this.rangeHighlightElements[_i].style.left = currentRange.start + "%";
20444								}
20445								this.rangeHighlightElements[_i].style.width = currentRange.size + "%";
20446							}
20447						} else {
20448							this.rangeHighlightElements[_i].style.display = "none";
20449						}
20450					}
20451				}
20452
20453				/* Position ticks and labels */
20454				if (Array.isArray(this.options.ticks) && this.options.ticks.length > 0) {
20455
20456					var styleSize = this.options.orientation === 'vertical' ? 'height' : 'width';
20457					var styleMargin;
20458					if (this.options.orientation === 'vertical') {
20459						styleMargin = 'marginTop';
20460					} else {
20461						if (this.options.rtl) {
20462							styleMargin = 'marginRight';
20463						} else {
20464							styleMargin = 'marginLeft';
20465						}
20466					}
20467					var labelSize = this._state.size / (this.options.ticks.length - 1);
20468
20469					if (this.tickLabelContainer) {
20470						var extraMargin = 0;
20471						if (this.options.ticks_positions.length === 0) {
20472							if (this.options.orientation !== 'vertical') {
20473								this.tickLabelContainer.style[styleMargin] = -labelSize / 2 + "px";
20474							}
20475
20476							extraMargin = this.tickLabelContainer.offsetHeight;
20477						} else {
20478							/* Chidren are position absolute, calculate height by finding the max offsetHeight of a child */
20479							for (i = 0; i < this.tickLabelContainer.childNodes.length; i++) {
20480								if (this.tickLabelContainer.childNodes[i].offsetHeight > extraMargin) {
20481									extraMargin = this.tickLabelContainer.childNodes[i].offsetHeight;
20482								}
20483							}
20484						}
20485						if (this.options.orientation === 'horizontal') {
20486							this.sliderElem.style.marginBottom = extraMargin + "px";
20487						}
20488					}
20489					for (var i = 0; i < this.options.ticks.length; i++) {
20490
20491						var percentage = this.options.ticks_positions[i] || this._toPercentage(this.options.ticks[i]);
20492
20493						if (this.options.reversed) {
20494							percentage = 100 - percentage;
20495						}
20496
20497						this.ticks[i].style[this.stylePos] = percentage + "%";
20498
20499						/* Set class labels to denote whether ticks are in the selection */
20500						this._removeClass(this.ticks[i], 'in-selection');
20501						if (!this.options.range) {
20502							if (this.options.selection === 'after' && percentage >= positionPercentages[0]) {
20503								this._addClass(this.ticks[i], 'in-selection');
20504							} else if (this.options.selection === 'before' && percentage <= positionPercentages[0]) {
20505								this._addClass(this.ticks[i], 'in-selection');
20506							}
20507						} else if (percentage >= positionPercentages[0] && percentage <= positionPercentages[1]) {
20508							this._addClass(this.ticks[i], 'in-selection');
20509						}
20510
20511						if (this.tickLabels[i]) {
20512							this.tickLabels[i].style[styleSize] = labelSize + "px";
20513
20514							if (this.options.orientation !== 'vertical' && this.options.ticks_positions[i] !== undefined) {
20515								this.tickLabels[i].style.position = 'absolute';
20516								this.tickLabels[i].style[this.stylePos] = percentage + "%";
20517								this.tickLabels[i].style[styleMargin] = -labelSize / 2 + 'px';
20518							} else if (this.options.orientation === 'vertical') {
20519								if (this.options.rtl) {
20520									this.tickLabels[i].style['marginRight'] = this.sliderElem.offsetWidth + "px";
20521								} else {
20522									this.tickLabels[i].style['marginLeft'] = this.sliderElem.offsetWidth + "px";
20523								}
20524								this.tickLabelContainer.style[styleMargin] = this.sliderElem.offsetWidth / 2 * -1 + 'px';
20525							}
20526						}
20527					}
20528				}
20529
20530				var formattedTooltipVal;
20531
20532				if (this.options.range) {
20533					formattedTooltipVal = this.options.formatter(this._state.value);
20534					this._setText(this.tooltipInner, formattedTooltipVal);
20535					this.tooltip.style[this.stylePos] = (positionPercentages[1] + positionPercentages[0]) / 2 + "%";
20536
20537					if (this.options.orientation === 'vertical') {
20538						this._css(this.tooltip, "margin-" + this.stylePos, -this.tooltip.offsetHeight / 2 + "px");
20539					} else {
20540						this._css(this.tooltip, "margin-" + this.stylePos, -this.tooltip.offsetWidth / 2 + "px");
20541					}
20542
20543					var innerTooltipMinText = this.options.formatter(this._state.value[0]);
20544					this._setText(this.tooltipInner_min, innerTooltipMinText);
20545
20546					var innerTooltipMaxText = this.options.formatter(this._state.value[1]);
20547					this._setText(this.tooltipInner_max, innerTooltipMaxText);
20548
20549					this.tooltip_min.style[this.stylePos] = positionPercentages[0] + "%";
20550
20551					if (this.options.orientation === 'vertical') {
20552						this._css(this.tooltip_min, "margin-" + this.stylePos, -this.tooltip_min.offsetHeight / 2 + "px");
20553					} else {
20554						this._css(this.tooltip_min, "margin-" + this.stylePos, -this.tooltip_min.offsetWidth / 2 + "px");
20555					}
20556
20557					this.tooltip_max.style[this.stylePos] = positionPercentages[1] + "%";
20558
20559					if (this.options.orientation === 'vertical') {
20560						this._css(this.tooltip_max, "margin-" + this.stylePos, -this.tooltip_max.offsetHeight / 2 + "px");
20561					} else {
20562						this._css(this.tooltip_max, "margin-" + this.stylePos, -this.tooltip_max.offsetWidth / 2 + "px");
20563					}
20564				} else {
20565					formattedTooltipVal = this.options.formatter(this._state.value[0]);
20566					this._setText(this.tooltipInner, formattedTooltipVal);
20567
20568					this.tooltip.style[this.stylePos] = positionPercentages[0] + "%";
20569					if (this.options.orientation === 'vertical') {
20570						this._css(this.tooltip, "margin-" + this.stylePos, -this.tooltip.offsetHeight / 2 + "px");
20571					} else {
20572						this._css(this.tooltip, "margin-" + this.stylePos, -this.tooltip.offsetWidth / 2 + "px");
20573					}
20574				}
20575
20576				if (this.options.orientation === 'vertical') {
20577					this.trackLow.style.top = '0';
20578					this.trackLow.style.height = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
20579
20580					this.trackSelection.style.top = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
20581					this.trackSelection.style.height = Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
20582
20583					this.trackHigh.style.bottom = '0';
20584					this.trackHigh.style.height = 100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
20585				} else {
20586					if (this.stylePos === 'right') {
20587						this.trackLow.style.right = '0';
20588					} else {
20589						this.trackLow.style.left = '0';
20590					}
20591					this.trackLow.style.width = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
20592
20593					if (this.stylePos === 'right') {
20594						this.trackSelection.style.right = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
20595					} else {
20596						this.trackSelection.style.left = Math.min(positionPercentages[0], positionPercentages[1]) + '%';
20597					}
20598					this.trackSelection.style.width = Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
20599
20600					if (this.stylePos === 'right') {
20601						this.trackHigh.style.left = '0';
20602					} else {
20603						this.trackHigh.style.right = '0';
20604					}
20605					this.trackHigh.style.width = 100 - Math.min(positionPercentages[0], positionPercentages[1]) - Math.abs(positionPercentages[0] - positionPercentages[1]) + '%';
20606
20607					var offset_min = this.tooltip_min.getBoundingClientRect();
20608					var offset_max = this.tooltip_max.getBoundingClientRect();
20609
20610					if (this.options.tooltip_position === 'bottom') {
20611						if (offset_min.right > offset_max.left) {
20612							this._removeClass(this.tooltip_max, 'bottom');
20613							this._addClass(this.tooltip_max, 'top');
20614							this.tooltip_max.style.top = '';
20615							this.tooltip_max.style.bottom = 22 + 'px';
20616						} else {
20617							this._removeClass(this.tooltip_max, 'top');
20618							this._addClass(this.tooltip_max, 'bottom');
20619							this.tooltip_max.style.top = this.tooltip_min.style.top;
20620							this.tooltip_max.style.bottom = '';
20621						}
20622					} else {
20623						if (offset_min.right > offset_max.left) {
20624							this._removeClass(this.tooltip_max, 'top');
20625							this._addClass(this.tooltip_max, 'bottom');
20626							this.tooltip_max.style.top = 18 + 'px';
20627						} else {
20628							this._removeClass(this.tooltip_max, 'bottom');
20629							this._addClass(this.tooltip_max, 'top');
20630							this.tooltip_max.style.top = this.tooltip_min.style.top;
20631						}
20632					}
20633				}
20634			},
20635			_createHighlightRange: function _createHighlightRange(start, end) {
20636				if (this._isHighlightRange(start, end)) {
20637					if (start > end) {
20638						return { 'start': end, 'size': start - end };
20639					}
20640					return { 'start': start, 'size': end - start };
20641				}
20642				return null;
20643			},
20644			_isHighlightRange: function _isHighlightRange(start, end) {
20645				if (0 <= start && start <= 100 && 0 <= end && end <= 100) {
20646					return true;
20647				} else {
20648					return false;
20649				}
20650			},
20651			_resize: function _resize(ev) {
20652				/*jshint unused:false*/
20653				this._state.offset = this._offset(this.sliderElem);
20654				this._state.size = this.sliderElem[this.sizePos];
20655				this._layout();
20656			},
20657			_removeProperty: function _removeProperty(element, prop) {
20658				if (element.style.removeProperty) {
20659					element.style.removeProperty(prop);
20660				} else {
20661					element.style.removeAttribute(prop);
20662				}
20663			},
20664			_mousedown: function _mousedown(ev) {
20665				if (!this._state.enabled) {
20666					return false;
20667				}
20668
20669				this._state.offset = this._offset(this.sliderElem);
20670				this._state.size = this.sliderElem[this.sizePos];
20671
20672				var percentage = this._getPercentage(ev);
20673
20674				if (this.options.range) {
20675					var diff1 = Math.abs(this._state.percentage[0] - percentage);
20676					var diff2 = Math.abs(this._state.percentage[1] - percentage);
20677					this._state.dragged = diff1 < diff2 ? 0 : 1;
20678					this._adjustPercentageForRangeSliders(percentage);
20679				} else {
20680					this._state.dragged = 0;
20681				}
20682
20683				this._state.percentage[this._state.dragged] = percentage;
20684				this._layout();
20685
20686				if (this.touchCapable) {
20687					document.removeEventListener("touchmove", this.mousemove, false);
20688					document.removeEventListener("touchend", this.mouseup, false);
20689				}
20690
20691				if (this.mousemove) {
20692					document.removeEventListener("mousemove", this.mousemove, false);
20693				}
20694				if (this.mouseup) {
20695					document.removeEventListener("mouseup", this.mouseup, false);
20696				}
20697
20698				this.mousemove = this._mousemove.bind(this);
20699				this.mouseup = this._mouseup.bind(this);
20700
20701				if (this.touchCapable) {
20702					// Touch: Bind touch events:
20703					document.addEventListener("touchmove", this.mousemove, false);
20704					document.addEventListener("touchend", this.mouseup, false);
20705				}
20706				// Bind mouse events:
20707				document.addEventListener("mousemove", this.mousemove, false);
20708				document.addEventListener("mouseup", this.mouseup, false);
20709
20710				this._state.inDrag = true;
20711				var newValue = this._calculateValue();
20712
20713				this._trigger('slideStart', newValue);
20714
20715				this._setDataVal(newValue);
20716				this.setValue(newValue, false, true);
20717
20718				ev.returnValue = false;
20719
20720				if (this.options.focus) {
20721					this._triggerFocusOnHandle(this._state.dragged);
20722				}
20723
20724				return true;
20725			},
20726			_touchstart: function _touchstart(ev) {
20727				if (ev.changedTouches === undefined) {
20728					this._mousedown(ev);
20729					return;
20730				}
20731
20732				var touch = ev.changedTouches[0];
20733				this.touchX = touch.pageX;
20734				this.touchY = touch.pageY;
20735			},
20736			_triggerFocusOnHandle: function _triggerFocusOnHandle(handleIdx) {
20737				if (handleIdx === 0) {
20738					this.handle1.focus();
20739				}
20740				if (handleIdx === 1) {
20741					this.handle2.focus();
20742				}
20743			},
20744			_keydown: function _keydown(handleIdx, ev) {
20745				if (!this._state.enabled) {
20746					return false;
20747				}
20748
20749				var dir;
20750				switch (ev.keyCode) {
20751					case 37: // left
20752					case 40:
20753						// down
20754						dir = -1;
20755						break;
20756					case 39: // right
20757					case 38:
20758						// up
20759						dir = 1;
20760						break;
20761				}
20762				if (!dir) {
20763					return;
20764				}
20765
20766				// use natural arrow keys instead of from min to max
20767				if (this.options.natural_arrow_keys) {
20768					var ifVerticalAndNotReversed = this.options.orientation === 'vertical' && !this.options.reversed;
20769					var ifHorizontalAndReversed = this.options.orientation === 'horizontal' && this.options.reversed; // @todo control with rtl
20770
20771					if (ifVerticalAndNotReversed || ifHorizontalAndReversed) {
20772						dir = -dir;
20773					}
20774				}
20775
20776				var val = this._state.value[handleIdx] + dir * this.options.step;
20777				var percentage = val / this.options.max * 100;
20778				this._state.keyCtrl = handleIdx;
20779				if (this.options.range) {
20780					this._adjustPercentageForRangeSliders(percentage);
20781					var val1 = !this._state.keyCtrl ? val : this._state.value[0];
20782					var val2 = this._state.keyCtrl ? val : this._state.value[1];
20783					val = [val1, val2];
20784				}
20785
20786				this._trigger('slideStart', val);
20787				this._setDataVal(val);
20788				this.setValue(val, true, true);
20789
20790				this._setDataVal(val);
20791				this._trigger('slideStop', val);
20792				this._layout();
20793
20794				this._pauseEvent(ev);
20795				delete this._state.keyCtrl;
20796
20797				return false;
20798			},
20799			_pauseEvent: function _pauseEvent(ev) {
20800				if (ev.stopPropagation) {
20801					ev.stopPropagation();
20802				}
20803				if (ev.preventDefault) {
20804					ev.preventDefault();
20805				}
20806				ev.cancelBubble = true;
20807				ev.returnValue = false;
20808			},
20809			_mousemove: function _mousemove(ev) {
20810				if (!this._state.enabled) {
20811					return false;
20812				}
20813
20814				var percentage = this._getPercentage(ev);
20815				this._adjustPercentageForRangeSliders(percentage);
20816				this._state.percentage[this._state.dragged] = percentage;
20817				this._layout();
20818
20819				var val = this._calculateValue(true);
20820				this.setValue(val, true, true);
20821
20822				return false;
20823			},
20824			_touchmove: function _touchmove(ev) {
20825				if (ev.changedTouches === undefined) {
20826					return;
20827				}
20828
20829				var touch = ev.changedTouches[0];
20830
20831				var xDiff = touch.pageX - this.touchX;
20832				var yDiff = touch.pageY - this.touchY;
20833
20834				if (!this._state.inDrag) {
20835					// Vertical Slider
20836					if (this.options.orientation === 'vertical' && xDiff <= 5 && xDiff >= -5 && (yDiff >= 15 || yDiff <= -15)) {
20837						this._mousedown(ev);
20838					}
20839					// Horizontal slider.
20840					else if (yDiff <= 5 && yDiff >= -5 && (xDiff >= 15 || xDiff <= -15)) {
20841							this._mousedown(ev);
20842						}
20843				}
20844			},
20845			_adjustPercentageForRangeSliders: function _adjustPercentageForRangeSliders(percentage) {
20846				if (this.options.range) {
20847					var precision = this._getNumDigitsAfterDecimalPlace(percentage);
20848					precision = precision ? precision - 1 : 0;
20849					var percentageWithAdjustedPrecision = this._applyToFixedAndParseFloat(percentage, precision);
20850					if (this._state.dragged === 0 && this._applyToFixedAndParseFloat(this._state.percentage[1], precision) < percentageWithAdjustedPrecision) {
20851						this._state.percentage[0] = this._state.percentage[1];
20852						this._state.dragged = 1;
20853					} else if (this._state.dragged === 1 && this._applyToFixedAndParseFloat(this._state.percentage[0], precision) > percentageWithAdjustedPrecision) {
20854						this._state.percentage[1] = this._state.percentage[0];
20855						this._state.dragged = 0;
20856					} else if (this._state.keyCtrl === 0 && this._state.value[1] / this.options.max * 100 < percentage) {
20857						this._state.percentage[0] = this._state.percentage[1];
20858						this._state.keyCtrl = 1;
20859						this.handle2.focus();
20860					} else if (this._state.keyCtrl === 1 && this._state.value[0] / this.options.max * 100 > percentage) {
20861						this._state.percentage[1] = this._state.percentage[0];
20862						this._state.keyCtrl = 0;
20863						this.handle1.focus();
20864					}
20865				}
20866			},
20867			_mouseup: function _mouseup() {
20868				if (!this._state.enabled) {
20869					return false;
20870				}
20871				if (this.touchCapable) {
20872					// Touch: Unbind touch event handlers:
20873					document.removeEventListener("touchmove", this.mousemove, false);
20874					document.removeEventListener("touchend", this.mouseup, false);
20875				}
20876				// Unbind mouse event handlers:
20877				document.removeEventListener("mousemove", this.mousemove, false);
20878				document.removeEventListener("mouseup", this.mouseup, false);
20879
20880				this._state.inDrag = false;
20881				if (this._state.over === false) {
20882					this._hideTooltip();
20883				}
20884				var val = this._calculateValue(true);
20885
20886				this._layout();
20887				this._setDataVal(val);
20888				this._trigger('slideStop', val);
20889
20890				return false;
20891			},
20892			_calculateValue: function _calculateValue(snapToClosestTick) {
20893				var val;
20894				if (this.options.range) {
20895					val = [this.options.min, this.options.max];
20896					if (this._state.percentage[0] !== 0) {
20897						val[0] = this._toValue(this._state.percentage[0]);
20898						val[0] = this._applyPrecision(val[0]);
20899					}
20900					if (this._state.percentage[1] !== 100) {
20901						val[1] = this._toValue(this._state.percentage[1]);
20902						val[1] = this._applyPrecision(val[1]);
20903					}
20904				} else {
20905					val = this._toValue(this._state.percentage[0]);
20906					val = parseFloat(val);
20907					val = this._applyPrecision(val);
20908				}
20909
20910				if (snapToClosestTick) {
20911					var min = [val, Infinity];
20912					for (var i = 0; i < this.options.ticks.length; i++) {
20913						var diff = Math.abs(this.options.ticks[i] - val);
20914						if (diff <= min[1]) {
20915							min = [this.options.ticks[i], diff];
20916						}
20917					}
20918					if (min[1] <= this.options.ticks_snap_bounds) {
20919						return min[0];
20920					}
20921				}
20922
20923				return val;
20924			},
20925			_applyPrecision: function _applyPrecision(val) {
20926				var precision = this.options.precision || this._getNumDigitsAfterDecimalPlace(this.options.step);
20927				return this._applyToFixedAndParseFloat(val, precision);
20928			},
20929			_getNumDigitsAfterDecimalPlace: function _getNumDigitsAfterDecimalPlace(num) {
20930				var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
20931				if (!match) {
20932					return 0;
20933				}
20934				return Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
20935			},
20936			_applyToFixedAndParseFloat: function _applyToFixedAndParseFloat(num, toFixedInput) {
20937				var truncatedNum = num.toFixed(toFixedInput);
20938				return parseFloat(truncatedNum);
20939			},
20940			/*
20941   	Credits to Mike Samuel for the following method!
20942   	Source: http://stackoverflow.com/questions/10454518/javascript-how-to-retrieve-the-number-of-decimals-of-a-string-number
20943   */
20944			_getPercentage: function _getPercentage(ev) {
20945				if (this.touchCapable && (ev.type === 'touchstart' || ev.type === 'touchmove')) {
20946					ev = ev.touches[0];
20947				}
20948
20949				var eventPosition = ev[this.mousePos];
20950				var sliderOffset = this._state.offset[this.stylePos];
20951				var distanceToSlide = eventPosition - sliderOffset;
20952				if (this.stylePos === 'right') {
20953					distanceToSlide = -distanceToSlide;
20954				}
20955				// Calculate what percent of the length the slider handle has slid
20956				var percentage = distanceToSlide / this._state.size * 100;
20957				percentage = Math.round(percentage / this._state.percentage[2]) * this._state.percentage[2];
20958				if (this.options.reversed) {
20959					percentage = 100 - percentage;
20960				}
20961
20962				// Make sure the percent is within the bounds of the slider.
20963				// 0% corresponds to the 'min' value of the slide
20964				// 100% corresponds to the 'max' value of the slide
20965				return Math.max(0, Math.min(100, percentage));
20966			},
20967			_validateInputValue: function _validateInputValue(val) {
20968				if (!isNaN(+val)) {
20969					return +val;
20970				} else if (Array.isArray(val)) {
20971					this._validateArray(val);
20972					return val;
20973				} else {
20974					throw new Error(ErrorMsgs.formatInvalidInputErrorMsg(val));
20975				}
20976			},
20977			_validateArray: function _validateArray(val) {
20978				for (var i = 0; i < val.length; i++) {
20979					var input = val[i];
20980					if (typeof input !== 'number') {
20981						throw new Error(ErrorMsgs.formatInvalidInputErrorMsg(input));
20982					}
20983				}
20984			},
20985			_setDataVal: function _setDataVal(val) {
20986				this.element.setAttribute('data-value', val);
20987				this.element.setAttribute('value', val);
20988				this.element.value = val;
20989			},
20990			_trigger: function _trigger(evt, val) {
20991				val = val || val === 0 ? val : undefined;
20992
20993				var callbackFnArray = this.eventToCallbackMap[evt];
20994				if (callbackFnArray && callbackFnArray.length) {
20995					for (var i = 0; i < callbackFnArray.length; i++) {
20996						var callbackFn = callbackFnArray[i];
20997						callbackFn(val);
20998					}
20999				}
21000
21001				/* If JQuery exists, trigger JQuery events */
21002				if ($) {
21003					this._triggerJQueryEvent(evt, val);
21004				}
21005			},
21006			_triggerJQueryEvent: function _triggerJQueryEvent(evt, val) {
21007				var eventData = {
21008					type: evt,
21009					value: val
21010				};
21011				this.$element.trigger(eventData);
21012				this.$sliderElem.trigger(eventData);
21013			},
21014			_unbindJQueryEventHandlers: function _unbindJQueryEventHandlers() {
21015				this.$element.off();
21016				this.$sliderElem.off();
21017			},
21018			_setText: function _setText(element, text) {
21019				if (typeof element.textContent !== "undefined") {
21020					element.textContent = text;
21021				} else if (typeof element.innerText !== "undefined") {
21022					element.innerText = text;
21023				}
21024			},
21025			_removeClass: function _removeClass(element, classString) {
21026				var classes = classString.split(" ");
21027				var newClasses = element.className;
21028
21029				for (var i = 0; i < classes.length; i++) {
21030					var classTag = classes[i];
21031					var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)");
21032					newClasses = newClasses.replace(regex, " ");
21033				}
21034
21035				element.className = newClasses.trim();
21036			},
21037			_addClass: function _addClass(element, classString) {
21038				var classes = classString.split(" ");
21039				var newClasses = element.className;
21040
21041				for (var i = 0; i < classes.length; i++) {
21042					var classTag = classes[i];
21043					var regex = new RegExp("(?:\\s|^)" + classTag + "(?:\\s|$)");
21044					var ifClassExists = regex.test(newClasses);
21045
21046					if (!ifClassExists) {
21047						newClasses += " " + classTag;
21048					}
21049				}
21050
21051				element.className = newClasses.trim();
21052			},
21053			_offsetLeft: function _offsetLeft(obj) {
21054				return obj.getBoundingClientRect().left;
21055			},
21056			_offsetRight: function _offsetRight(obj) {
21057				return obj.getBoundingClientRect().right;
21058			},
21059			_offsetTop: function _offsetTop(obj) {
21060				var offsetTop = obj.offsetTop;
21061				while ((obj = obj.offsetParent) && !isNaN(obj.offsetTop)) {
21062					offsetTop += obj.offsetTop;
21063					if (obj.tagName !== 'BODY') {
21064						offsetTop -= obj.scrollTop;
21065					}
21066				}
21067				return offsetTop;
21068			},
21069			_offset: function _offset(obj) {
21070				return {
21071					left: this._offsetLeft(obj),
21072					right: this._offsetRight(obj),
21073					top: this._offsetTop(obj)
21074				};
21075			},
21076			_css: function _css(elementRef, styleName, value) {
21077				if ($) {
21078					$.style(elementRef, styleName, value);
21079				} else {
21080					var style = styleName.replace(/^-ms-/, "ms-").replace(/-([\da-z])/gi, function (all, letter) {
21081						return letter.toUpperCase();
21082					});
21083					elementRef.style[style] = value;
21084				}
21085			},
21086			_toValue: function _toValue(percentage) {
21087				return this.options.scale.toValue.apply(this, [percentage]);
21088			},
21089			_toPercentage: function _toPercentage(value) {
21090				return this.options.scale.toPercentage.apply(this, [value]);
21091			},
21092			_setTooltipPosition: function _setTooltipPosition() {
21093				var tooltips = [this.tooltip, this.tooltip_min, this.tooltip_max];
21094				if (this.options.orientation === 'vertical') {
21095					var tooltipPos;
21096					if (this.options.tooltip_position) {
21097						tooltipPos = this.options.tooltip_position;
21098					} else {
21099						if (this.options.rtl) {
21100							tooltipPos = 'left';
21101						} else {
21102							tooltipPos = 'right';
21103						}
21104					}
21105					var oppositeSide = tooltipPos === 'left' ? 'right' : 'left';
21106					tooltips.forEach(function (tooltip) {
21107						this._addClass(tooltip, tooltipPos);
21108						tooltip.style[oppositeSide] = '100%';
21109					}.bind(this));
21110				} else if (this.options.tooltip_position === 'bottom') {
21111					tooltips.forEach(function (tooltip) {
21112						this._addClass(tooltip, 'bottom');
21113						tooltip.style.top = 22 + 'px';
21114					}.bind(this));
21115				} else {
21116					tooltips.forEach(function (tooltip) {
21117						this._addClass(tooltip, 'top');
21118						tooltip.style.top = -this.tooltip.outerHeight - 14 + 'px';
21119					}.bind(this));
21120				}
21121			}
21122		};
21123
21124		/*********************************
21125  		Attach to global namespace
21126  	*********************************/
21127		if ($ && $.fn) {
21128			var autoRegisterNamespace = void 0;
21129
21130			if (!$.fn.slider) {
21131				$.bridget(NAMESPACE_MAIN, Slider);
21132				autoRegisterNamespace = NAMESPACE_MAIN;
21133			} else {
21134				if (windowIsDefined) {
21135					window.console.warn("bootstrap-slider.js - WARNING: $.fn.slider namespace is already bound. Use the $.fn.bootstrapSl
21135ider namespace instead.");
21136				}
21137				autoRegisterNamespace = NAMESPACE_ALTERNATE;
21138			}
21139			$.bridget(NAMESPACE_ALTERNATE, Slider);
21140
21141			// Auto-Register data-provide="slider" Elements
21142			$(function () {
21143				$("input[data-provide=slider]")[autoRegisterNamespace]();
21144			});
21145		}
21146	})($);
21147
21148	return Slider;
21149});
21150
21151+function() {
21152    ns('News.Utils').guid = function guid() {
21153        function s4() {
21154            return Math.floor((1 + Math.random()) * 0x10000)
21155                .toString(16)
21156                .substring(1);
21157        }
21158        return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
21159            s4() + '-' + s4() + s4() + s4();
21160    };
21161}();
21162+function() {
21163    //If browser does not support str.startWith (i.e. IE), create it manually
21164    if (!String.prototype.startsWith) {
21165         String.prototype.startsWith = function(searchString, position) {
21166            position = position || 0;
21167            return this.indexOf(searchString, position) === position;
21168         };
21169    }
21170}();
21171+function() {
21172    ns('News.Utils').electionBopSeats = function(officeID) {
21173
21174            if (officeID === "H") {
21175                return 435;
21176            } else if (officeID === "S") {
21177                return 100;
21178            } else if (officeID === "G") {
21179                return 50;
21180            }
21181            return 0;
21182    };
21183
21184
21185}();
21186(function($){
21187
21188    "use strict";
21189
21190    ns('News.App').TabletOrientationCheck = {
21191
21192        mql: window.matchMedia("(orientation: portrait)"),
21193        viewport: jQuery("meta[name=viewport]"),
21194        metaContentAttr: "width=device-width,initial-scale=",
21195
21196        load: function() {
21197
21198            // Only applies to tablets
21199            if (isMobile.tablet) {
21200                this.updateMetaViewport(this.mql);
21201                this.bindings(this.mql);
21202            }
21203
21204        },
21205
21206        // Orientation change event listener
21207        bindings: function(mql) {
21208            mql.addListener(function(m) {
21209                News.App.TabletOrientationCheck.updateMetaViewport(mql)
21210            });
21211        },
21212
21213        updateMetaViewport: function(mql) {
21214
21215            // Default scale is always 1
21216            var scale = 1;
21217
21218            // Orientation is "Portrait" change to .74;
21219            if(mql.matches) {
21220                scale = ".7499";
21221            }
21222
21223            this.viewport.attr("content",this.metaContentAttr + scale);
21224
21225        }
21226    }
21227
21228    News.App.TabletOrientationCheck.load();
21229
21230})(jQuery);
21231/**
21232 * Owl Carousel v2.2.1
21233 * Copyright 2013-2017 David Deutsch
21234 * Licensed under  ()
21235 */
21236/**
21237 * Owl carousel
vendor: 36,851 bytes, lines 21238-22645
21238 * @version 2.1.6
21239 * @author Bartosz Wojciechowski
21240 * @author David Deutsch
21241 * @license The MIT License (MIT)
21242 * @todo Lazy Load Icon
21243 * @todo prevent animationend bubling
21244 * @todo itemsScaleUp
21245 * @todo Test Zepto
21246 * @todo stagePadding calculate wrong active classes
21247 */
21248;(function($, window, document, undefined) {
21249
21250	/**
21251	 * Creates a carousel.
21252	 * @class The Owl Carousel.
21253	 * @public
21254	 * @param {HTMLElement|jQuery} element - The element to create the carousel for.
21255	 * @param {Object} [options] - The options
21256	 */
21257	function Owl(element, options) {
21258
21259		/**
21260		 * Current settings for the carousel.
21261		 * @public
21262		 */
21263		this.settings = null;
21264
21265		/**
21266		 * Current options set by the caller including defaults.
21267		 * @public
21268		 */
21269		this.options = $.extend({}, Owl.Defaults, options);
21270
21271		/**
21272		 * Plugin element.
21273		 * @public
21274		 */
21275		this.$element = $(element);
21276
21277		/**
21278		 * Proxied event handlers.
21279		 * @protected
21280		 */
21281		this._handlers = {};
21282
21283		/**
21284		 * References to the running plugins of this carousel.
21285		 * @protected
21286		 */
21287		this._plugins = {};
21288
21289		/**
21290		 * Currently suppressed events to prevent them from beeing retriggered.
21291		 * @protected
21292		 */
21293		this._supress = {};
21294
21295		/**
21296		 * Absolute current position.
21297		 * @protected
21298		 */
21299		this._current = null;
21300
21301		/**
21302		 * Animation speed in milliseconds.
21303		 * @protected
21304		 */
21305		this._speed = null;
21306
21307		/**
21308		 * Coordinates of all items in pixel.
21309		 * @todo The name of this member is missleading.
21310		 * @protected
21311		 */
21312		this._coordinates = [];
21313
21314		/**
21315		 * Current breakpoint.
21316		 * @todo Real media queries would be nice.
21317		 * @protected
21318		 */
21319		this._breakpoint = null;
21320
21321		/**
21322		 * Current width of the plugin element.
21323		 */
21324		this._width = null;
21325
21326		/**
21327		 * All real items.
21328		 * @protected
21329		 */
21330		this._items = [];
21331
21332		/**
21333		 * All cloned items.
21334		 * @protected
21335		 */
21336		this._clones = [];
21337
21338		/**
21339		 * Merge values of all items.
21340		 * @todo Maybe this could be part of a plugin.
21341		 * @protected
21342		 */
21343		this._mergers = [];
21344
21345		/**
21346		 * Widths of all items.
21347		 */
21348		this._widths = [];
21349
21350		/**
21351		 * Invalidated parts within the update process.
21352		 * @protected
21353		 */
21354		this._invalidated = {};
21355
21356		/**
21357		 * Ordered list of workers for the update process.
21358		 * @protected
21359		 */
21360		this._pipe = [];
21361
21362		/**
21363		 * Current state information for the drag operation.
21364		 * @todo #261
21365		 * @protected
21366		 */
21367		this._drag = {
21368			time: null,
21369			target: null,
21370			pointer: null,
21371			stage: {
21372				start: null,
21373				current: null
21374			},
21375			direction: null
21376		};
21377
21378		/**
21379		 * Current state information and their tags.
21380		 * @type {Object}
21381		 * @protected
21382		 */
21383		this._states = {
21384			current: {},
21385			tags: {
21386				'initializing': [ 'busy' ],
21387				'animating': [ 'busy' ],
21388				'dragging': [ 'interacting' ]
21389			}
21390		};
21391
21392		$.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
21393			this._handlers[handler] = $.proxy(this[handler], this);
21394		}, this));
21395
21396		$.each(Owl.Plugins, $.proxy(function(key, plugin) {
21397			this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
21398				= new plugin(this);
21399		}, this));
21400
21401		$.each(Owl.Workers, $.proxy(function(priority, worker) {
21402			this._pipe.push({
21403				'filter': worker.filter,
21404				'run': $.proxy(worker.run, this)
21405			});
21406		}, this));
21407
21408		this.setup();
21409		this.initialize();
21410	}
21411
21412	/**
21413	 * Default options for the carousel.
21414	 * @public
21415	 */
21416	Owl.Defaults = {
21417		items: 3,
21418		loop: false,
21419		center: false,
21420		rewind: false,
21421
21422		mouseDrag: true,
21423		touchDrag: true,
21424		pullDrag: true,
21425		freeDrag: false,
21426
21427		margin: 0,
21428		stagePadding: 0,
21429
21430		merge: false,
21431		mergeFit: true,
21432		autoWidth: false,
21433
21434		startPosition: 0,
21435		rtl: false,
21436
21437		smartSpeed: 250,
21438		fluidSpeed: false,
21439		dragEndSpeed: false,
21440
21441		responsive: {},
21442		responsiveRefreshRate: 200,
21443		responsiveBaseElement: window,
21444
21445		fallbackEasing: 'swing',
21446
21447		info: false,
21448
21449		nestedItemSelector: false,
21450		itemElement: 'div',
21451		stageElement: 'div',
21452
21453		refreshClass: 'owl-refresh',
21454		loadedClass: 'owl-loaded',
21455		loadingClass: 'owl-loading',
21456		rtlClass: 'owl-rtl',
21457		responsiveClass: 'owl-responsive',
21458		dragClass: 'owl-drag',
21459		itemClass: 'owl-item',
21460		stageClass: 'owl-stage',
21461		stageOuterClass: 'owl-stage-outer',
21462		grabClass: 'owl-grab'
21463	};
21464
21465	/**
21466	 * Enumeration for width.
21467	 * @public
21468	 * @readonly
21469	 * @enum {String}
21470	 */
21471	Owl.Width = {
21472		Default: 'default',
21473		Inner: 'inner',
21474		Outer: 'outer'
21475	};
21476
21477	/**
21478	 * Enumeration for types.
21479	 * @public
21480	 * @readonly
21481	 * @enum {String}
21482	 */
21483	Owl.Type = {
21484		Event: 'event',
21485		State: 'state'
21486	};
21487
21488	/**
21489	 * Contains all registered plugins.
21490	 * @public
21491	 */
21492	Owl.Plugins = {};
21493
21494	/**
21495	 * List of workers involved in the update process.
21496	 */
21497	Owl.Workers = [ {
21498		filter: [ 'width', 'settings' ],
21499		run: function() {
21500			this._width = this.$element.width();
21501		}
21502	}, {
21503		filter: [ 'width', 'items', 'settings' ],
21504		run: function(cache) {
21505			cache.current = this._items && this._items[this.relative(this._current)];
21506		}
21507	}, {
21508		filter: [ 'items', 'settings' ],
21509		run: function() {
21510			this.$stage.children('.cloned').remove();
21511		}
21512	}, {
21513		filter: [ 'width', 'items', 'settings' ],
21514		run: function(cache) {
21515			var margin = this.settings.margin || '',
21516				grid = !this.settings.autoWidth,
21517				rtl = this.settings.rtl,
21518				css = {
21519					'width': 'auto',
21520					'margin-left': rtl ? margin : '',
21521					'margin-right': rtl ? '' : margin
21522				};
21523
21524			!grid && this.$stage.children().css(css);
21525
21526			cache.css = css;
21527		}
21528	}, {
21529		filter: [ 'width', 'items', 'settings' ],
21530		run: function(cache) {
21531			var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
21532				merge = null,
21533				iterator = this._items.length,
21534				grid = !this.settings.autoWidth,
21535				widths = [];
21536
21537			cache.items = {
21538				merge: false,
21539				width: width
21540			};
21541
21542			while (iterator--) {
21543				merge = this._mergers[iterator];
21544				merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
21545
21546				cache.items.merge = merge > 1 || cache.items.merge;
21547
21548				widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
21549			}
21550
21551			this._widths = widths;
21552		}
21553	}, {
21554		filter: [ 'items', 'settings' ],
21555		run: function() {
21556			var clones = [],
21557				items = this._items,
21558				settings = this.settings,
21559				// TODO: Should be computed from number of min width items in stage
21560				view = Math.max(settings.items * 2, 4),
21561				size = Math.ceil(items.length / 2) * 2,
21562				repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
21563				append = '',
21564				prepend = '';
21565
21566			repeat /= 2;
21567
21568			while (repeat--) {
21569				// Switch to only using appended clones
21570				clones.push(this.normalize(clones.length / 2, true));
21571				append = append + items[clones[clones.length - 1]][0].outerHTML;
21572				clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
21573				prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
21574			}
21575
21576			this._clones = clones;
21577
21578			$(append).addClass('cloned').appendTo(this.$stage);
21579			$(prepend).addClass('cloned').prependTo(this.$stage);
21580		}
21581	}, {
21582		filter: [ 'width', 'items', 'settings' ],
21583		run: function() {
21584			var rtl = this.settings.rtl ? 1 : -1,
21585				size = this._clones.length + this._items.length,
21586				iterator = -1,
21587				previous = 0,
21588				current = 0,
21589				coordinates = [];
21590
21591			while (++iterator < size) {
21592				previous = coordinates[iterator - 1] || 0;
21593				current = this._widths[this.relative(iterator)] + this.settings.margin;
21594				coordinates.push(previous + current * rtl);
21595			}
21596
21597			this._coordinates = coordinates;
21598		}
21599	}, {
21600		filter: [ 'width', 'items', 'settings' ],
21601		run: function() {
21602			var padding = this.settings.stagePadding,
21603				coordinates = this._coordinates,
21604				css = {
21605					'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
21606					'padding-left': padding || '',
21607					'padding-right': padding || ''
21608				};
21609
21610			this.$stage.css(css);
21611		}
21612	}, {
21613		filter: [ 'width', 'items', 'settings' ],
21614		run: function(cache) {
21615			var iterator = this._coordinates.length,
21616				grid = !this.settings.autoWidth,
21617				items = this.$stage.children();
21618
21619			if (grid && cache.items.merge) {
21620				while (iterator--) {
21621					cache.css.width = this._widths[this.relative(iterator)];
21622					items.eq(iterator).css(cache.css);
21623				}
21624			} else if (grid) {
21625				cache.css.width = cache.items.width;
21626				items.css(cache.css);
21627			}
21628		}
21629	}, {
21630		filter: [ 'items' ],
21631		run: function() {
21632			this._coordinates.length < 1 && this.$stage.removeAttr('style');
21633		}
21634	}, {
21635		filter: [ 'width', 'items', 'settings' ],
21636		run: function(cache) {
21637			cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
21638			cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
21639			this.reset(cache.current);
21640		}
21641	}, {
21642		filter: [ 'position' ],
21643		run: function() {
21644			this.animate(this.coordinates(this._current));
21645		}
21646	}, {
21647		filter: [ 'width', 'position', 'items', 'settings' ],
21648		run: function() {
21649			var rtl = this.settings.rtl ? 1 : -1,
21650				padding = this.settings.stagePadding * 2,
21651				begin = this.coordinates(this.current()) + padding,
21652				end = begin + this.width() * rtl,
21653				inner, outer, matches = [], i, n;
21654
21655			for (i = 0, n = this._coordinates.length; i < n; i++) {
21656				inner = this._coordinates[i - 1] || 0;
21657				outer = Math.abs(this._coordinates[i]) + padding * rtl;
21658
21659				if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
21660					|| (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
21661					matches.push(i);
21662				}
21663			}
21664
21665			this.$stage.children('.active').removeClass('active');
21666			this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
21667
21668			if (this.settings.center) {
21669				this.$stage.children('.center').removeClass('center');
21670				this.$stage.children().eq(this.current()).addClass('center');
21671			}
21672		}
21673	} ];
21674
21675	/**
21676	 * Initializes the carousel.
21677	 * @protected
21678	 */
21679	Owl.prototype.initialize = function() {
21680		this.enter('initializing');
21681		this.trigger('initialize');
21682
21683		this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
21684
21685		if (this.settings.autoWidth && !this.is('pre-loading')) {
21686			var imgs, nestedSelector, width;
21687			imgs = this.$element.find('img');
21688			nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
21689			width = this.$element.children(nestedSelector).width();
21690
21691			if (imgs.length && width <= 0) {
21692				this.preloadAutoWidthImages(imgs);
21693			}
21694		}
21695
21696		this.$element.addClass(this.options.loadingClass);
21697
21698		// create stage
21699		this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
21700			.wrap('<div class="' + this.settings.stageOuterClass + '"/>');
21701
21702		// append stage
21703		this.$element.append(this.$stage.parent());
21704
21705		// append content
21706		this.replace(this.$element.children().not(this.$stage.parent()));
21707
21708		// check visibility
21709		if (this.$element.is(':visible')) {
21710			// update view
21711			this.refresh();
21712		} else {
21713			// invalidate width
21714			this.invalidate('width');
21715		}
21716
21717		this.$element
21718			.removeClass(this.options.loadingClass)
21719			.addClass(this.options.loadedClass);
21720
21721		// register event handlers
21722		this.registerEventHandlers();
21723
21724		this.leave('initializing');
21725		this.trigger('initialized');
21726	};
21727
21728	/**
21729	 * Setups the current settings.
21730	 * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
21731	 * @todo Support for media queries by using `matchMedia` would be nice.
21732	 * @public
21733	 */
21734	Owl.prototype.setup = function() {
21735		var viewport = this.viewport(),
21736			overwrites = this.options.responsive,
21737			match = -1,
21738			settings = null;
21739
21740		if (!overwrites) {
21741			settings = $.extend({}, this.options);
21742		} else {
21743			$.each(overwrites, function(breakpoint) {
21744				if (breakpoint <= viewport && breakpoint > match) {
21745					match = Number(breakpoint);
21746				}
21747			});
21748
21749			settings = $.extend({}, this.options, overwrites[match]);
21750			if (typeof settings.stagePadding === 'function') {
21751				settings.stagePadding = settings.stagePadding();
21752			}
21753			delete settings.responsive;
21754
21755			// responsive class
21756			if (settings.responsiveClass) {
21757				this.$element.attr('class',
21758					this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
21759				);
21760			}
21761		}
21762
21763		this.trigger('change', { property: { name: 'settings', value: settings } });
21764		this._breakpoint = match;
21765		this.settings = settings;
21766		this.invalidate('settings');
21767		this.trigger('changed', { property: { name: 'settings', value: this.settings } });
21768	};
21769
21770	/**
21771	 * Updates option logic if necessery.
21772	 * @protected
21773	 */
21774	Owl.prototype.optionsLogic = function() {
21775		if (this.settings.autoWidth) {
21776			this.settings.stagePadding = false;
21777			this.settings.merge = false;
21778		}
21779	};
21780
21781	/**
21782	 * Prepares an item before add.
21783	 * @todo Rename event parameter `content` to `item`.
21784	 * @protected
21785	 * @returns {jQuery|HTMLElement} - The item container.
21786	 */
21787	Owl.prototype.prepare = function(item) {
21788		var event = this.trigger('prepare', { content: item });
21789
21790		if (!event.data) {
21791			event.data = $('<' + this.settings.itemElement + '/>')
21792				.addClass(this.options.itemClass).append(item)
21793		}
21794
21795		this.trigger('prepared', { content: event.data });
21796
21797		return event.data;
21798	};
21799
21800	/**
21801	 * Updates the view.
21802	 * @public
21803	 */
21804	Owl.prototype.update = function() {
21805		var i = 0,
21806			n = this._pipe.length,
21807			filter = $.proxy(function(p) { return this[p] }, this._invalidated),
21808			cache = {};
21809
21810		while (i < n) {
21811			if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
21812				this._pipe[i].run(cache);
21813			}
21814			i++;
21815		}
21816
21817		this._invalidated = {};
21818
21819		!this.is('valid') && this.enter('valid');
21820	};
21821
21822	/**
21823	 * Gets the width of the view.
21824	 * @public
21825	 * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
21826	 * @returns {Number} - The width of the view in pixel.
21827	 */
21828	Owl.prototype.width = function(dimension) {
21829		dimension = dimension || Owl.Width.Default;
21830		switch (dimension) {
21831			case Owl.Width.Inner:
21832			case Owl.Width.Outer:
21833				return this._width;
21834			default:
21835				return this._width - this.settings.stagePadding * 2 + this.settings.margin;
21836		}
21837	};
21838
21839	/**
21840	 * Refreshes the carousel primarily for adaptive purposes.
21841	 * @public
21842	 */
21843	Owl.prototype.refresh = function() {
21844		this.enter('refreshing');
21845		this.trigger('refresh');
21846
21847		this.setup();
21848
21849		this.optionsLogic();
21850
21851		this.$element.addClass(this.options.refreshClass);
21852
21853		this.update();
21854
21855		this.$element.removeClass(this.options.refreshClass);
21856
21857		this.leave('refreshing');
21858		this.trigger('refreshed');
21859	};
21860
21861	/**
21862	 * Checks window `resize` event.
21863	 * @protected
21864	 */
21865	Owl.prototype.onThrottledResize = function() {
21866		window.clearTimeout(this.resizeTimer);
21867		this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
21868	};
21869
21870	/**
21871	 * Checks window `resize` event.
21872	 * @protected
21873	 */
21874	Owl.prototype.onResize = function() {
21875		if (!this._items.length) {
21876			return false;
21877		}
21878
21879		if (this._width === this.$element.width()) {
21880			return false;
21881		}
21882
21883		if (!this.$element.is(':visible')) {
21884			return false;
21885		}
21886
21887		this.enter('resizing');
21888
21889		if (this.trigger('resize').isDefaultPrevented()) {
21890			this.leave('resizing');
21891			return false;
21892		}
21893
21894		this.invalidate('width');
21895
21896		this.refresh();
21897
21898		this.leave('resizing');
21899		this.trigger('resized');
21900	};
21901
21902	/**
21903	 * Registers event handlers.
21904	 * @todo Check `msPointerEnabled`
21905	 * @todo #261
21906	 * @protected
21907	 */
21908	Owl.prototype.registerEventHandlers = function() {
21909		if ($.support.transition) {
21910			this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
21911		}
21912
21913		if (this.settings.responsive !== false) {
21914			this.on(window, 'resize', this._handlers.onThrottledResize);
21915		}
21916
21917		if (this.settings.mouseDrag) {
21918			this.$element.addClass(this.options.dragClass);
21919			this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
21920			this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
21921		}
21922
21923		if (this.settings.touchDrag){
21924			this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
21925			this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
21926		}
21927	};
21928
21929	/**
21930	 * Handles `touchstart` and `mousedown` events.
21931	 * @todo Horizontal swipe threshold as option
21932	 * @todo #261
21933	 * @protected
21934	 * @param {Event} event - The event arguments.
21935	 */
21936	Owl.prototype.onDragStart = function(event) {
21937		var stage = null;
21938
21939		if (event.which === 3) {
21940			return;
21941		}
21942
21943		if ($.support.transform) {
21944			stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
21945			stage = {
21946				x: stage[stage.length === 16 ? 12 : 4],
21947				y: stage[stage.length === 16 ? 13 : 5]
21948			};
21949		} else {
21950			stage = this.$stage.position();
21951			stage = {
21952				x: this.settings.rtl ?
21953					stage.left + this.$stage.width() - this.width() + this.settings.margin :
21954					stage.left,
21955				y: stage.top
21956			};
21957		}
21958
21959		if (this.is('animating')) {
21960			$.support.transform ? this.animate(stage.x) : this.$stage.stop()
21961			this.invalidate('position');
21962		}
21963
21964		this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
21965
21966		this.speed(0);
21967
21968		this._drag.time = new Date().getTime();
21969		this._drag.target = $(event.target);
21970		this._drag.stage.start = stage;
21971		this._drag.stage.current = stage;
21972		this._drag.pointer = this.pointer(event);
21973
21974		$(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
21975
21976		$(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
21977			var delta = this.difference(this._drag.pointer, this.pointer(event));
21978
21979			$(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
21980
21981			if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
21982				return;
21983			}
21984
21985			event.preventDefault();
21986
21987			this.enter('dragging');
21988			this.trigger('drag');
21989		}, this));
21990	};
21991
21992	/**
21993	 * Handles the `touchmove` and `mousemove` events.
21994	 * @todo #261
21995	 * @protected
21996	 * @param {Event} event - The event arguments.
21997	 */
21998	Owl.prototype.onDragMove = function(event) {
21999		var minimum = null,
22000			maximum = null,
22001			pull = null,
22002			delta = this.difference(this._drag.pointer, this.pointer(event)),
22003			stage = this.difference(this._drag.stage.start, delta);
22004
22005		if (!this.is('dragging')) {
22006			return;
22007		}
22008
22009		event.preventDefault();
22010
22011		if (this.settings.loop) {
22012			minimum = this.coordinates(this.minimum());
22013			maximum = this.coordinates(this.maximum() + 1) - minimum;
22014			stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
22015		} else {
22016			minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
22017			maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
22018			pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
22019			stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
22020		}
22021
22022		this._drag.stage.current = stage;
22023
22024		this.animate(stage.x);
22025	};
22026
22027	/**
22028	 * Handles the `touchend` and `mouseup` events.
22029	 * @todo #261
22030	 * @todo Threshold for click event
22031	 * @protected
22032	 * @param {Event} event - The event arguments.
22033	 */
22034	Owl.prototype.onDragEnd = function(event) {
22035		var delta = this.difference(this._drag.pointer, this.pointer(event)),
22036			stage = this._drag.stage.current,
22037			direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
22038
22039		$(document).off('.owl.core');
22040
22041		this.$element.removeClass(this.options.grabClass);
22042
22043		if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
22044			this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
22045			this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
22046			this.invalidate('position');
22047			this.update();
22048
22049			this._drag.direction = direction;
22050
22051			if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
22052				this._drag.target.one('click.owl.core', function() { return false; });
22053			}
22054		}
22055
22056		if (!this.is('dragging')) {
22057			return;
22058		}
22059
22060		this.leave('dragging');
22061		this.trigger('dragged');
22062	};
22063
22064	/**
22065	 * Gets absolute position of the closest item for a coordinate.
22066	 * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
22067	 * @protected
22068	 * @param {Number} coordinate - The coordinate in pixel.
22069	 * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
22070	 * @return {Number} - The absolute position of the closest item.
22071	 */
22072	Owl.prototype.closest = function(coordinate, direction) {
22073		var position = -1,
22074			pull = 30,
22075			width = this.width(),
22076			coordinates = this.coordinates();
22077
22078		if (!this.settings.freeDrag) {
22079			// check closest item
22080			$.each(coordinates, $.proxy(function(index, value) {
22081				// on a left pull, check on current index
22082				if (direction === 'left' && coordinate > value - pull && coordinate < value + pull) {
22083					position = index;
22084				// on a right pull, check on previous index
22085				// to do so, subtract width from value and set position = index + 1
22086				} else if (direction === 'right' && coordinate > value - width - pull && coordinate < value - width + pull) {
22087					position = index + 1;
22088				} else if (this.op(coordinate, '<', value)
22089					&& this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
22090					position = direction === 'left' ? index + 1 : index;
22091				}
22092				return position === -1;
22093			}, this));
22094		}
22095
22096		if (!this.settings.loop) {
22097			// non loop boundries
22098			if (this.op(coordinate, '>', coordinates[this.minimum()])) {
22099				position = coordinate = this.minimum();
22100			} else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
22101				position = coordinate = this.maximum();
22102			}
22103		}
22104
22105		return position;
22106	};
22107
22108	/**
22109	 * Animates the stage.
22110	 * @todo #270
22111	 * @public
22112	 * @param {Number} coordinate - The coordinate in pixels.
22113	 */
22114	Owl.prototype.animate = function(coordinate) {
22115		var animate = this.speed() > 0;
22116
22117		this.is('animating') && this.onTransitionEnd();
22118
22119		if (animate) {
22120			this.enter('animating');
22121			this.trigger('translate');
22122		}
22123
22124		if ($.support.transform3d && $.support.transition) {
22125			this.$stage.css({
22126				transform: 'translate3d(' + coordinate + 'px,0px,0px)',
22127				transition: (this.speed() / 1000) + 's'
22128			});
22129		} else if (animate) {
22130			this.$stage.animate({
22131				left: coordinate + 'px'
22132			}, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
22133		} else {
22134			this.$stage.css({
22135				left: coordinate + 'px'
22136			});
22137		}
22138	};
22139
22140	/**
22141	 * Checks whether the carousel is in a specific state or not.
22142	 * @param {String} state - The state to check.
22143	 * @returns {Boolean} - The flag which indicates if the carousel is busy.
22144	 */
22145	Owl.prototype.is = function(state) {
22146		return this._states.current[state] && this._states.current[state] > 0;
22147	};
22148
22149	/**
22150	 * Sets the absolute position of the current item.
22151	 * @public
22152	 * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
22153	 * @returns {Number} - The absolute position of the current item.
22154	 */
22155	Owl.prototype.current = function(position) {
22156		if (position === undefined) {
22157			return this._current;
22158		}
22159
22160		if (this._items.length === 0) {
22161			return undefined;
22162		}
22163
22164		position = this.normalize(position);
22165
22166		if (this._current !== position) {
22167			var event = this.trigger('change', { property: { name: 'position', value: position } });
22168
22169			if (event.data !== undefined) {
22170				position = this.normalize(event.data);
22171			}
22172
22173			this._current = position;
22174
22175			this.invalidate('position');
22176
22177			this.trigger('changed', { property: { name: 'position', value: this._current } });
22178		}
22179
22180		return this._current;
22181	};
22182
22183	/**
22184	 * Invalidates the given part of the update routine.
22185	 * @param {String} [part] - The part to invalidate.
22186	 * @returns {Array.<String>} - The invalidated parts.
22187	 */
22188	Owl.prototype.invalidate = function(part) {
22189		if ($.type(part) === 'string') {
22190			this._invalidated[part] = true;
22191			this.is('valid') && this.leave('valid');
22192		}
22193		return $.map(this._invalidated, function(v, i) { return i });
22194	};
22195
22196	/**
22197	 * Resets the absolute position of the current item.
22198	 * @public
22199	 * @param {Number} position - The absolute position of the new item.
22200	 */
22201	Owl.prototype.reset = function(position) {
22202		position = this.normalize(position);
22203
22204		if (position === undefined) {
22205			return;
22206		}
22207
22208		this._speed = 0;
22209		this._current = position;
22210
22211		this.suppress([ 'translate', 'translated' ]);
22212
22213		this.animate(this.coordinates(position));
22214
22215		this.release([ 'translate', 'translated' ]);
22216	};
22217
22218	/**
22219	 * Normalizes an absolute or a relative position of an item.
22220	 * @public
22221	 * @param {Number} position - The absolute or relative position to normalize.
22222	 * @param {Boolean} [relative=false] - Whether the given position is relative or not.
22223	 * @returns {Number} - The normalized position.
22224	 */
22225	Owl.prototype.normalize = function(position, relative) {
22226		var n = this._items.length,
22227			m = relative ? 0 : this._clones.length;
22228
22229		if (!this.isNumeric(position) || n < 1) {
22230			position = undefined;
22231		} else if (position < 0 || position >= n + m) {
22232			position = ((position - m / 2) % n + n) % n + m / 2;
22233		}
22234
22235		return position;
22236	};
22237
22238	/**
22239	 * Converts an absolute position of an item into a relative one.
22240	 * @public
22241	 * @param {Number} position - The absolute position to convert.
22242	 * @returns {Number} - The converted position.
22243	 */
22244	Owl.prototype.relative = function(position) {
22245		position -= this._clones.length / 2;
22246		return this.normalize(position, true);
22247	};
22248
22249	/**
22250	 * Gets the maximum position for the current item.
22251	 * @public
22252	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
22253	 * @returns {Number}
22254	 */
22255	Owl.prototype.maximum = function(relative) {
22256		var settings = this.settings,
22257			maximum = this._coordinates.length,
22258			iterator,
22259			reciprocalItemsWidth,
22260			elementWidth;
22261
22262		if (settings.loop) {
22263			maximum = this._clones.length / 2 + this._items.length - 1;
22264		} else if (settings.autoWidth || settings.merge) {
22265			iterator = this._items.length;
22266			reciprocalItemsWidth = this._items[--iterator].width();
22267			elementWidth = this.$element.width();
22268			while (iterator--) {
22269				reciprocalItemsWidth += this._items[iterator].width() + this.settings.margin;
22270				if (reciprocalItemsWidth > elementWidth) {
22271					break;
22272				}
22273			}
22274			maximum = iterator + 1;
22275		} else if (settings.center) {
22276			maximum = this._items.length - 1;
22277		} else {
22278			maximum = this._items.length - settings.items;
22279		}
22280
22281		if (relative) {
22282			maximum -= this._clones.length / 2;
22283		}
22284
22285		return Math.max(maximum, 0);
22286	};
22287
22288	/**
22289	 * Gets the minimum position for the current item.
22290	 * @public
22291	 * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
22292	 * @returns {Number}
22293	 */
22294	Owl.prototype.minimum = function(relative) {
22295		return relative ? 0 : this._clones.length / 2;
22296	};
22297
22298	/**
22299	 * Gets an item at the specified relative position.
22300	 * @public
22301	 * @param {Number} [position] - The relative position of the item.
22302	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
22303	 */
22304	Owl.prototype.items = function(position) {
22305		if (position === undefined) {
22306			return this._items.slice();
22307		}
22308
22309		position = this.normalize(position, true);
22310		return this._items[position];
22311	};
22312
22313	/**
22314	 * Gets an item at the specified relative position.
22315	 * @public
22316	 * @param {Number} [position] - The relative position of the item.
22317	 * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
22318	 */
22319	Owl.prototype.mergers = function(position) {
22320		if (position === undefined) {
22321			return this._mergers.slice();
22322		}
22323
22324		position = this.normalize(position, true);
22325		return this._mergers[position];
22326	};
22327
22328	/**
22329	 * Gets the absolute positions of clones for an item.
22330	 * @public
22331	 * @param {Number} [position] - The relative position of the item.
22332	 * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
22333	 */
22334	Owl.prototype.clones = function(position) {
22335		var odd = this._clones.length / 2,
22336			even = odd + this._items.length,
22337			map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
22338
22339		if (position === undefined) {
22340			return $.map(this._clones, function(v, i) { return map(i) });
22341		}
22342
22343		return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
22344	};
22345
22346	/**
22347	 * Sets the current animation speed.
22348	 * @public
22349	 * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
22350	 * @returns {Number} - The current animation speed in milliseconds.
22351	 */
22352	Owl.prototype.speed = function(speed) {
22353		if (speed !== undefined) {
22354			this._speed = speed;
22355		}
22356
22357		return this._speed;
22358	};
22359
22360	/**
22361	 * Gets the coordinate of an item.
22362	 * @todo The name of this method is missleanding.
22363	 * @public
22364	 * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
22365	 * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
22366	 */
22367	Owl.prototype.coordinates = function(position) {
22368		var multiplier = 1,
22369			newPosition = position - 1,
22370			coordinate;
22371
22372		if (position === undefined) {
22373			return $.map(this._coordinates, $.proxy(function(coordinate, index) {
22374				return this.coordinates(index);
22375			}, this));
22376		}
22377
22378		if (this.settings.center) {
22379			if (this.settings.rtl) {
22380				multiplier = -1;
22381				newPosition = position + 1;
22382			}
22383
22384			coordinate = this._coordinates[position];
22385			coordinate += (this.width() - coordinate + (this._coordinates[newPosition] || 0)) / 2 * multiplier;
22386		} else {
22387			coordinate = this._coordinates[newPosition] || 0;
22388		}
22389
22390		coordinate = Math.ceil(coordinate);
22391
22392		return coordinate;
22393	};
22394
22395	/**
22396	 * Calculates the speed for a translation.
22397	 * @protected
22398	 * @param {Number} from - The absolute position of the start item.
22399	 * @param {Number} to - The absolute position of the target item.
22400	 * @param {Number} [factor=undefined] - The time factor in milliseconds.
22401	 * @returns {Number} - The time in milliseconds for the translation.
22402	 */
22403	Owl.prototype.duration = function(from, to, factor) {
22404		if (factor === 0) {
22405			return 0;
22406		}
22407
22408		return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
22409	};
22410
22411	/**
22412	 * Slides to the specified item.
22413	 * @public
22414	 * @param {Number} position - The position of the item.
22415	 * @param {Number} [speed] - The time in milliseconds for the transition.
22416	 */
22417	Owl.prototype.to = function(position, speed) {
22418		var current = this.current(),
22419			revert = null,
22420			distance = position - this.relative(current),
22421			direction = (distance > 0) - (distance < 0),
22422			items = this._items.length,
22423			minimum = this.minimum(),
22424			maximum = this.maximum();
22425
22426		if (this.settings.loop) {
22427			if (!this.settings.rewind && Math.abs(distance) > items / 2) {
22428				distance += direction * -1 * items;
22429			}
22430
22431			position = current + distance;
22432			revert = ((position - minimum) % items + items) % items + minimum;
22433
22434			if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
22435				current = revert - distance;
22436				position = revert;
22437				this.reset(current);
22438			}
22439		} else if (this.settings.rewind) {
22440			maximum += 1;
22441			position = (position % maximum + maximum) % maximum;
22442		} else {
22443			position = Math.max(minimum, Math.min(maximum, position));
22444		}
22445
22446		this.speed(this.duration(current, position, speed));
22447		this.current(position);
22448
22449		if (this.$element.is(':visible')) {
22450			this.update();
22451		}
22452	};
22453
22454	/**
22455	 * Slides to the next item.
22456	 * @public
22457	 * @param {Number} [speed] - The time in milliseconds for the transition.
22458	 */
22459	Owl.prototype.next = function(speed) {
22460		speed = speed || false;
22461		this.to(this.relative(this.current()) + 1, speed);
22462	};
22463
22464	/**
22465	 * Slides to the previous item.
22466	 * @public
22467	 * @param {Number} [speed] - The time in milliseconds for the transition.
22468	 */
22469	Owl.prototype.prev = function(speed) {
22470		speed = speed || false;
22471		this.to(this.relative(this.current()) - 1, speed);
22472	};
22473
22474	/**
22475	 * Handles the end of an animation.
22476	 * @protected
22477	 * @param {Event} event - The event arguments.
22478	 */
22479	Owl.prototype.onTransitionEnd = function(event) {
22480
22481		// if css2 animation then event object is undefined
22482		if (event !== undefined) {
22483			event.stopPropagation();
22484
22485			// Catch only owl-stage transitionEnd event
22486			if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
22487				return false;
22488			}
22489		}
22490
22491		this.leave('animating');
22492		this.trigger('translated');
22493	};
22494
22495	/**
22496	 * Gets viewport width.
22497	 * @protected
22498	 * @return {Number} - The width in pixel.
22499	 */
22500	Owl.prototype.viewport = function() {
22501		var width;
22502		if (this.options.responsiveBaseElement !== window) {
22503			width = $(this.options.responsiveBaseElement).width();
22504		} else if (window.innerWidth) {
22505			width = window.innerWidth;
22506		} else if (document.documentElement && document.documentElement.clientWidth) {
22507			width = document.documentElement.clientWidth;
22508		} else {
22509			console.warn('Can not detect viewport width.');
22510		}
22511		return width;
22512	};
22513
22514	/**
22515	 * Replaces the current content.
22516	 * @public
22517	 * @param {HTMLElement|jQuery|String} content - The new content.
22518	 */
22519	Owl.prototype.replace = function(content) {
22520		this.$stage.empty();
22521		this._items = [];
22522
22523		if (content) {
22524			content = (content instanceof jQuery) ? content : $(content);
22525		}
22526
22527		if (this.settings.nestedItemSelector) {
22528			content = content.find('.' + this.settings.nestedItemSelector);
22529		}
22530
22531		content.filter(function() {
22532			return this.nodeType === 1;
22533		}).each($.proxy(function(index, item) {
22534			item = this.prepare(item);
22535			this.$stage.append(item);
22536			this._items.push(item);
22537			this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
22538		}, this));
22539
22540		this.reset(this.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
22541
22542		this.invalidate('items');
22543	};
22544
22545	/**
22546	 * Adds an item.
22547	 * @todo Use `item` instead of `content` for the event arguments.
22548	 * @public
22549	 * @param {HTMLElement|jQuery|String} content - The item content to add.
22550	 * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
22551	 */
22552	Owl.prototype.add = function(content, position) {
22553		var current = this.relative(this._current);
22554
22555		position = position === undefined ? this._items.length : this.normalize(position, true);
22556		content = content instanceof jQuery ? content : $(content);
22557
22558		this.trigger('add', { content: content, position: position });
22559
22560		content = this.prepare(content);
22561
22562		if (this._items.length === 0 || position === this._items.length) {
22563			this._items.length === 0 && this.$stage.append(content);
22564			this._items.length !== 0 && this._items[position - 1].after(content);
22565			this._items.push(content);
22566			this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
22567		} else {
22568			this._items[position].before(content);
22569			this._items.splice(position, 0, content);
22570			this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
22571		}
22572
22573		this._items[current] && this.reset(this._items[current].index());
22574
22575		this.invalidate('items');
22576
22577		this.trigger('added', { content: content, position: position });
22578	};
22579
22580	/**
22581	 * Removes an item by its position.
22582	 * @todo Use `item` instead of `content` for the event arguments.
22583	 * @public
22584	 * @param {Number} position - The relative position of the item to remove.
22585	 */
22586	Owl.prototype.remove = function(position) {
22587		position = this.normalize(position, true);
22588
22589		if (position === undefined) {
22590			return;
22591		}
22592
22593		this.trigger('remove', { content: this._items[position], position: position });
22594
22595		this._items[position].remove();
22596		this._items.splice(position, 1);
22597		this._mergers.splice(position, 1);
22598
22599		this.invalidate('items');
22600
22601		this.trigger('removed', { content: null, position: position });
22602	};
22603
22604	/**
22605	 * Preloads images with auto width.
22606	 * @todo Replace by a more generic approach
22607	 * @protected
22608	 */
22609	Owl.prototype.preloadAutoWidthImages = function(images) {
22610		images.each($.proxy(function(i, element) {
22611			this.enter('pre-loading');
22612			element = $(element);
22613			$(new Image()).one('load', $.proxy(function(e) {
22614				element.attr('src', e.target.src);
22615				element.css('opacity', 1);
22616				this.leave('pre-loading');
22617				!this.is('pre-loading') && !this.is('initializing') && this.refresh();
22618			}, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
22619		}, this));
22620	};
22621
22622	/**
22623	 * Destroys the carousel.
22624	 * @public
22625	 */
22626	Owl.prototype.destroy = function() {
22627
22628		this.$element.off('.owl.core');
22629		this.$stage.off('.owl.core');
22630		$(document).off('.owl.core');
22631
22632		if (this.settings.responsive !== false) {
22633			window.clearTimeout(this.resizeTimer);
22634			this.off(window, 'resize', this._handlers.onThrottledResize);
22635		}
22636
22637		for (var i in this._plugins) {
22638			this._plugins[i].destroy();
22639		}
22640
22641		this.$stage.children('.cloned').remove();
22642
22643		this.$stage.unwrap();
22644		this.$stage.children().contents().unwrap();
22645		this.$stage.children().unwrap();
vendor: 8,263 bytes, lines 22646-22931
22646
22647		this.$element
22648			.removeClass(this.options.refreshClass)
22649			.removeClass(this.options.loadingClass)
22650			.removeClass(this.options.loadedClass)
22651			.removeClass(this.options.rtlClass)
22652			.removeClass(this.options.dragClass)
22653			.removeClass(this.options.grabClass)
22654			.attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
22655			.removeData('owl.carousel');
22656	};
22657
22658	/**
22659	 * Operators to calculate right-to-left and left-to-right.
22660	 * @protected
22661	 * @param {Number} [a] - The left side operand.
22662	 * @param {String} [o] - The operator.
22663	 * @param {Number} [b] - The right side operand.
22664	 */
22665	Owl.prototype.op = function(a, o, b) {
22666		var rtl = this.settings.rtl;
22667		switch (o) {
22668			case '<':
22669				return rtl ? a > b : a < b;
22670			case '>':
22671				return rtl ? a < b : a > b;
22672			case '>=':
22673				return rtl ? a <= b : a >= b;
22674			case '<=':
22675				return rtl ? a >= b : a <= b;
22676			default:
22677				break;
22678		}
22679	};
22680
22681	/**
22682	 * Attaches to an internal event.
22683	 * @protected
22684	 * @param {HTMLElement} element - The event source.
22685	 * @param {String} event - The event name.
22686	 * @param {Function} listener - The event handler to attach.
22687	 * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
22688	 */
22689	Owl.prototype.on = function(element, event, listener, capture) {
22690		if (element.addEventListener) {
22691			element.addEventListener(event, listener, capture);
22692		} else if (element.attachEvent) {
22693			element.attachEvent('on' + event, listener);
22694		}
22695	};
22696
22697	/**
22698	 * Detaches from an internal event.
22699	 * @protected
22700	 * @param {HTMLElement} element - The event source.
22701	 * @param {String} event - The event name.
22702	 * @param {Function} listener - The attached event handler to detach.
22703	 * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
22704	 */
22705	Owl.prototype.off = function(element, event, listener, capture) {
22706		if (element.removeEventListener) {
22707			element.removeEventListener(event, listener, capture);
22708		} else if (element.detachEvent) {
22709			element.detachEvent('on' + event, listener);
22710		}
22711	};
22712
22713	/**
22714	 * Triggers a public event.
22715	 * @todo Remove `status`, `relatedTarget` should be used instead.
22716	 * @protected
22717	 * @param {String} name - The event name.
22718	 * @param {*} [data=null] - The event data.
22719	 * @param {String} [namespace=carousel] - The event namespace.
22720	 * @param {String} [state] - The state which is associated with the event.
22721	 * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
22722	 * @returns {Event} - The event arguments.
22723	 */
22724	Owl.prototype.trigger = function(name, data, namespace, state, enter) {
22725		var status = {
22726			item: { count: this._items.length, index: this.current() }
22727		}, handler = $.camelCase(
22728			$.grep([ 'on', name, namespace ], function(v) { return v })
22729				.join('-').toLowerCase()
22730		), event = $.Event(
22731			[ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
22732			$.extend({ relatedTarget: this }, status, data)
22733		);
22734
22735		if (!this._supress[name]) {
22736			$.each(this._plugins, function(name, plugin) {
22737				if (plugin.onTrigger) {
22738					plugin.onTrigger(event);
22739				}
22740			});
22741
22742			this.register({ type: Owl.Type.Event, name: name });
22743			this.$element.trigger(event);
22744
22745			if (this.settings && typeof this.settings[handler] === 'function') {
22746				this.settings[handler].call(this, event);
22747			}
22748		}
22749
22750		return event;
22751	};
22752
22753	/**
22754	 * Enters a state.
22755	 * @param name - The state name.
22756	 */
22757	Owl.prototype.enter = function(name) {
22758		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
22759			if (this._states.current[name] === undefined) {
22760				this._states.current[name] = 0;
22761			}
22762
22763			this._states.current[name]++;
22764		}, this));
22765	};
22766
22767	/**
22768	 * Leaves a state.
22769	 * @param name - The state name.
22770	 */
22771	Owl.prototype.leave = function(name) {
22772		$.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
22773			this._states.current[name]--;
22774		}, this));
22775	};
22776
22777	/**
22778	 * Registers an event or state.
22779	 * @public
22780	 * @param {Object} object - The event or state to register.
22781	 */
22782	Owl.prototype.register = function(object) {
22783		if (object.type === Owl.Type.Event) {
22784			if (!$.event.special[object.name]) {
22785				$.event.special[object.name] = {};
22786			}
22787
22788			if (!$.event.special[object.name].owl) {
22789				var _default = $.event.special[object.name]._default;
22790				$.event.special[object.name]._default = function(e) {
22791					if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
22792						return _default.apply(this, arguments);
22793					}
22794					return e.namespace && e.namespace.indexOf('owl') > -1;
22795				};
22796				$.event.special[object.name].owl = true;
22797			}
22798		} else if (object.type === Owl.Type.State) {
22799			if (!this._states.tags[object.name]) {
22800				this._states.tags[object.name] = object.tags;
22801			} else {
22802				this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
22803			}
22804
22805			this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
22806				return $.inArray(tag, this._states.tags[object.name]) === i;
22807			}, this));
22808		}
22809	};
22810
22811	/**
22812	 * Suppresses events.
22813	 * @protected
22814	 * @param {Array.<String>} events - The events to suppress.
22815	 */
22816	Owl.prototype.suppress = function(events) {
22817		$.each(events, $.proxy(function(index, event) {
22818			this._supress[event] = true;
22819		}, this));
22820	};
22821
22822	/**
22823	 * Releases suppressed events.
22824	 * @protected
22825	 * @param {Array.<String>} events - The events to release.
22826	 */
22827	Owl.prototype.release = function(events) {
22828		$.each(events, $.proxy(function(index, event) {
22829			delete this._supress[event];
22830		}, this));
22831	};
22832
22833	/**
22834	 * Gets unified pointer coordinates from event.
22835	 * @todo #261
22836	 * @protected
22837	 * @param {Event} - The `mousedown` or `touchstart` event.
22838	 * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
22839	 */
22840	Owl.prototype.pointer = function(event) {
22841		var result = { x: null, y: null };
22842
22843		event = event.originalEvent || event || window.event;
22844
22845		event = event.touches && event.touches.length ?
22846			event.touches[0] : event.changedTouches && event.changedTouches.length ?
22847				event.changedTouches[0] : event;
22848
22849		if (event.pageX) {
22850			result.x = event.pageX;
22851			result.y = event.pageY;
22852		} else {
22853			result.x = event.clientX;
22854			result.y = event.clientY;
22855		}
22856
22857		return result;
22858	};
22859
22860	/**
22861	 * Determines if the input is a Number or something that can be coerced to a Number
22862	 * @protected
22863	 * @param {Number|String|Object|Array|Boolean|RegExp|Function|Symbol} - The input to be tested
22864	 * @returns {Boolean} - An indication if the input is a Number or can be coerced to a Number
22865	 */
22866	Owl.prototype.isNumeric = function(number) {
22867		return !isNaN(parseFloat(number));
22868	};
22869
22870	/**
22871	 * Gets the difference of two vectors.
22872	 * @todo #261
22873	 * @protected
22874	 * @param {Object} - The first vector.
22875	 * @param {Object} - The second vector.
22876	 * @returns {Object} - The difference.
22877	 */
22878	Owl.prototype.difference = function(first, second) {
22879		return {
22880			x: first.x - second.x,
22881			y: first.y - second.y
22882		};
22883	};
22884
22885	/**
22886	 * The jQuery Plugin for the Owl Carousel
22887	 * @todo Navigation plugin `next` and `prev`
22888	 * @public
22889	 */
22890	$.fn.owlCarousel = function(option) {
22891		var args = Array.prototype.slice.call(arguments, 1);
22892
22893		return this.each(function() {
22894			var $this = $(this),
22895				data = $this.data('owl.carousel');
22896
22897			if (!data) {
22898				data = new Owl(this, typeof option == 'object' && option);
22899				$this.data('owl.carousel', data);
22900
22901				$.each([
22902					'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
22903				], function(i, event) {
22904					data.register({ type: Owl.Type.Event, name: event });
22905					data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
22906						if (e.namespace && e.relatedTarget !== this) {
22907							this.suppress([ event ]);
22908							data[event].apply(this, [].slice.call(arguments, 1));
22909							this.release([ event ]);
22910						}
22911					}, data));
22912				});
22913			}
22914
22915			if (typeof option == 'string' && option.charAt(0) !== '_') {
22916				data[option].apply(data, args);
22917			}
22918		});
22919	};
22920
22921	/**
22922	 * The constructor for the jQuery Plugin
22923	 * @public
22924	 */
22925	$.fn.owlCarousel.Constructor = Owl;
22926
22927})(window.Zepto || window.jQuery, window, document);
22928
22929/**
22930 * AutoRefresh Plugin
22931 * @version 2.
vendor: 22,802 bytes, lines 22931-23831
229311.0
22932 * @author Artus Kolanowski
22933 * @author David Deutsch
22934 * @license The MIT License (MIT)
22935 */
22936;(function($, window, document, undefined) {
22937
22938	/**
22939	 * Creates the auto refresh plugin.
22940	 * @class The Auto Refresh Plugin
22941	 * @param {Owl} carousel - The Owl Carousel
22942	 */
22943	var AutoRefresh = function(carousel) {
22944		/**
22945		 * Reference to the core.
22946		 * @protected
22947		 * @type {Owl}
22948		 */
22949		this._core = carousel;
22950
22951		/**
22952		 * Refresh interval.
22953		 * @protected
22954		 * @type {number}
22955		 */
22956		this._interval = null;
22957
22958		/**
22959		 * Whether the element is currently visible or not.
22960		 * @protected
22961		 * @type {Boolean}
22962		 */
22963		this._visible = null;
22964
22965		/**
22966		 * All event handlers.
22967		 * @protected
22968		 * @type {Object}
22969		 */
22970		this._handlers = {
22971			'initialized.owl.carousel': $.proxy(function(e) {
22972				if (e.namespace && this._core.settings.autoRefresh) {
22973					this.watch();
22974				}
22975			}, this)
22976		};
22977
22978		// set default options
22979		this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
22980
22981		// register event handlers
22982		this._core.$element.on(this._handlers);
22983	};
22984
22985	/**
22986	 * Default options.
22987	 * @public
22988	 */
22989	AutoRefresh.Defaults = {
22990		autoRefresh: true,
22991		autoRefreshInterval: 500
22992	};
22993
22994	/**
22995	 * Watches the element.
22996	 */
22997	AutoRefresh.prototype.watch = function() {
22998		if (this._interval) {
22999			return;
23000		}
23001
23002		this._visible = this._core.$element.is(':visible');
23003		this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
23004	};
23005
23006	/**
23007	 * Refreshes the element.
23008	 */
23009	AutoRefresh.prototype.refresh = function() {
23010		if (this._core.$element.is(':visible') === this._visible) {
23011			return;
23012		}
23013
23014		this._visible = !this._visible;
23015
23016		this._core.$element.toggleClass('owl-hidden', !this._visible);
23017
23018		this._visible && (this._core.invalidate('width') && this._core.refresh());
23019	};
23020
23021	/**
23022	 * Destroys the plugin.
23023	 */
23024	AutoRefresh.prototype.destroy = function() {
23025		var handler, property;
23026
23027		window.clearInterval(this._interval);
23028
23029		for (handler in this._handlers) {
23030			this._core.$element.off(handler, this._handlers[handler]);
23031		}
23032		for (property in Object.getOwnPropertyNames(this)) {
23033			typeof this[property] != 'function' && (this[property] = null);
23034		}
23035	};
23036
23037	$.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
23038
23039})(window.Zepto || window.jQuery, window, document);
23040
23041/**
23042 * Lazy Plugin
23043 * @version 2.1.0
23044 * @author Bartosz Wojciechowski
23045 * @author David Deutsch
23046 * @license The MIT License (MIT)
23047 */
23048;(function($, window, document, undefined) {
23049
23050	/**
23051	 * Creates the lazy plugin.
23052	 * @class The Lazy Plugin
23053	 * @param {Owl} carousel - The Owl Carousel
23054	 */
23055	var Lazy = function(carousel) {
23056
23057		/**
23058		 * Reference to the core.
23059		 * @protected
23060		 * @type {Owl}
23061		 */
23062		this._core = carousel;
23063
23064		/**
23065		 * Already loaded items.
23066		 * @protected
23067		 * @type {Array.<jQuery>}
23068		 */
23069		this._loaded = [];
23070
23071		/**
23072		 * Event handlers.
23073		 * @protected
23074		 * @type {Object}
23075		 */
23076		this._handlers = {
23077			'initialized.owl.carousel change.owl.carousel resized.owl.carousel': $.proxy(function(e) {
23078				if (!e.namespace) {
23079					return;
23080				}
23081
23082				if (!this._core.settings || !this._core.settings.lazyLoad) {
23083					return;
23084				}
23085
23086				if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
23087					var settings = this._core.settings,
23088						n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
23089						i = ((settings.center && n * -1) || 0),
23090						position = (e.property && e.property.value !== undefined ? e.property.value : this._core.current()) + i,
23091						clones = this._core.clones().length,
23092						load = $.proxy(function(i, v) { this.load(v) }, this);
23093
23094					while (i++ < n) {
23095						this.load(clones / 2 + this._core.relative(position));
23096						clones && $.each(this._core.clones(this._core.relative(position)), load);
23097						position++;
23098					}
23099				}
23100			}, this)
23101		};
23102
23103		// set the default options
23104		this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
23105
23106		// register event handler
23107		this._core.$element.on(this._handlers);
23108	};
23109
23110	/**
23111	 * Default options.
23112	 * @public
23113	 */
23114	Lazy.Defaults = {
23115		lazyLoad: false
23116	};
23117
23118	/**
23119	 * Loads all resources of an item at the specified position.
23120	 * @param {Number} position - The absolute position of the item.
23121	 * @protected
23122	 */
23123	Lazy.prototype.load = function(position) {
23124		var $item = this._core.$stage.children().eq(position),
23125			$elements = $item && $item.find('.owl-lazy');
23126
23127		if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
23128			return;
23129		}
23130
23131		$elements.each($.proxy(function(index, element) {
23132			var $element = $(element), image,
23133				url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
23134
23135			this._core.trigger('load', { element: $element, url: url }, 'lazy');
23136
23137			if ($element.is('img')) {
23138				$element.one('load.owl.lazy', $.proxy(function() {
23139					$element.css('opacity', 1);
23140					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
23141				}, this)).attr('src', url);
23142			} else {
23143				image = new Image();
23144				image.onload = $.proxy(function() {
23145					$element.css({
23146						'background-image': 'url("' + url + '")',
23147						'opacity': '1'
23148					});
23149					this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
23150				}, this);
23151				image.src = url;
23152			}
23153		}, this));
23154
23155		this._loaded.push($item.get(0));
23156	};
23157
23158	/**
23159	 * Destroys the plugin.
23160	 * @public
23161	 */
23162	Lazy.prototype.destroy = function() {
23163		var handler, property;
23164
23165		for (handler in this.handlers) {
23166			this._core.$element.off(handler, this.handlers[handler]);
23167		}
23168		for (property in Object.getOwnPropertyNames(this)) {
23169			typeof this[property] != 'function' && (this[property] = null);
23170		}
23171	};
23172
23173	$.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
23174
23175})(window.Zepto || window.jQuery, window, document);
23176
23177/**
23178 * AutoHeight Plugin
23179 * @version 2.1.0
23180 * @author Bartosz Wojciechowski
23181 * @author David Deutsch
23182 * @license The MIT License (MIT)
23183 */
23184;(function($, window, document, undefined) {
23185
23186	/**
23187	 * Creates the auto height plugin.
23188	 * @class The Auto Height Plugin
23189	 * @param {Owl} carousel - The Owl Carousel
23190	 */
23191	var AutoHeight = function(carousel) {
23192		/**
23193		 * Reference to the core.
23194		 * @protected
23195		 * @type {Owl}
23196		 */
23197		this._core = carousel;
23198
23199		/**
23200		 * All event handlers.
23201		 * @protected
23202		 * @type {Object}
23203		 */
23204		this._handlers = {
23205			'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
23206				if (e.namespace && this._core.settings.autoHeight) {
23207					this.update();
23208				}
23209			}, this),
23210			'changed.owl.carousel': $.proxy(function(e) {
23211				if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
23212					this.update();
23213				}
23214			}, this),
23215			'loaded.owl.lazy': $.proxy(function(e) {
23216				if (e.namespace && this._core.settings.autoHeight
23217					&& e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
23218					this.update();
23219				}
23220			}, this)
23221		};
23222
23223		// set default options
23224		this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
23225
23226		// register event handlers
23227		this._core.$element.on(this._handlers);
23228	};
23229
23230	/**
23231	 * Default options.
23232	 * @public
23233	 */
23234	AutoHeight.Defaults = {
23235		autoHeight: false,
23236		autoHeightClass: 'owl-height'
23237	};
23238
23239	/**
23240	 * Updates the view.
23241	 */
23242	AutoHeight.prototype.update = function() {
23243		var start = this._core._current,
23244			end = start + this._core.settings.items,
23245			visible = this._core.$stage.children().toArray().slice(start, end),
23246			heights = [],
23247			maxheight = 0;
23248
23249		$.each(visible, function(index, item) {
23250			heights.push($(item).height());
23251		});
23252
23253		maxheight = Math.max.apply(null, heights);
23254
23255		this._core.$stage.parent()
23256			.height(maxheight)
23257			.addClass(this._core.settings.autoHeightClass);
23258	};
23259
23260	AutoHeight.prototype.destroy = function() {
23261		var handler, property;
23262
23263		for (handler in this._handlers) {
23264			this._core.$element.off(handler, this._handlers[handler]);
23265		}
23266		for (property in Object.getOwnPropertyNames(this)) {
23267			typeof this[property] != 'function' && (this[property] = null);
23268		}
23269	};
23270
23271	$.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
23272
23273})(window.Zepto || window.jQuery, window, document);
23274
23275/**
23276 * Video Plugin
23277 * @version 2.1.0
23278 * @author Bartosz Wojciechowski
23279 * @author David Deutsch
23280 * @license The MIT License (MIT)
23281 */
23282;(function($, window, document, undefined) {
23283
23284	/**
23285	 * Creates the video plugin.
23286	 * @class The Video Plugin
23287	 * @param {Owl} carousel - The Owl Carousel
23288	 */
23289	var Video = function(carousel) {
23290		/**
23291		 * Reference to the core.
23292		 * @protected
23293		 * @type {Owl}
23294		 */
23295		this._core = carousel;
23296
23297		/**
23298		 * Cache all video URLs.
23299		 * @protected
23300		 * @type {Object}
23301		 */
23302		this._videos = {};
23303
23304		/**
23305		 * Current playing item.
23306		 * @protected
23307		 * @type {jQuery}
23308		 */
23309		this._playing = null;
23310
23311		/**
23312		 * All event handlers.
23313		 * @todo The cloned content removale is too late
23314		 * @protected
23315		 * @type {Object}
23316		 */
23317		this._handlers = {
23318			'initialized.owl.carousel': $.proxy(function(e) {
23319				if (e.namespace) {
23320					this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
23321				}
23322			}, this),
23323			'resize.owl.carousel': $.proxy(function(e) {
23324				if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
23325					e.preventDefault();
23326				}
23327			}, this),
23328			'refreshed.owl.carousel': $.proxy(function(e) {
23329				if (e.namespace && this._core.is('resizing')) {
23330					this._core.$stage.find('.cloned .owl-video-frame').remove();
23331				}
23332			}, this),
23333			'changed.owl.carousel': $.proxy(function(e) {
23334				if (e.namespace && e.property.name === 'position' && this._playing) {
23335					this.stop();
23336				}
23337			}, this),
23338			'prepared.owl.carousel': $.proxy(function(e) {
23339				if (!e.namespace) {
23340					return;
23341				}
23342
23343				var $element = $(e.content).find('.owl-video');
23344
23345				if ($element.length) {
23346					$element.css('display', 'none');
23347					this.fetch($element, $(e.content));
23348				}
23349			}, this)
23350		};
23351
23352		// set default options
23353		this._core.options = $.extend({}, Video.Defaults, this._core.options);
23354
23355		// register event handlers
23356		this._core.$element.on(this._handlers);
23357
23358		this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
23359			this.play(e);
23360		}, this));
23361	};
23362
23363	/**
23364	 * Default options.
23365	 * @public
23366	 */
23367	Video.Defaults = {
23368		video: false,
23369		videoHeight: false,
23370		videoWidth: false
23371	};
23372
23373	/**
23374	 * Gets the video ID and the type (YouTube/Vimeo/vzaar only).
23375	 * @protected
23376	 * @param {jQuery} target - The target containing the video data.
23377	 * @param {jQuery} item - The item containing the video.
23378	 */
23379	Video.prototype.fetch = function(target, item) {
23380			var type = (function() {
23381					if (target.attr('data-vimeo-id')) {
23382						return 'vimeo';
23383					} else if (target.attr('data-vzaar-id')) {
23384						return 'vzaar'
23385					} else {
23386						return 'youtube';
23387					}
23388				})(),
23389				id = target.attr('data-vimeo-id') || target.attr('data-youtube-id') || target.attr('data-vzaar-id'),
23390				width = target.attr('data-width') || this._core.settings.videoWidth,
23391				height = target.attr('data-height') || this._core.settings.videoHeight,
23392				url = target.attr('href');
23393
23394		if (url) {
23395
23396			/*
23397					Parses the id's out of the following urls (and probably more):
23398					https://www.youtube.com/watch?v=:id
23399					https://youtu.be/:id
23400					https://vimeo.com/:id
23401					https://vimeo.com/channels/:channel/:id
23402					https://vimeo.com/groups/:group/videos/:id
23403					https://app.vzaar.com/videos/:id
23404
23405					Visual example: https://regexper.com/#(http%3A%7Chttps%3A%7C)%5C%2F%5C%2F(player.%7Cwww.%7Capp.)%3F(vimeo%5C.com%7Cyoutu(be%5C.com%7C%5C.be%7Cbe%5C.googleapis%5C.com)%7Cvzaar%5C.com)%5C%2F(video%5C%2F%7Cvideos%5C%2F%7Cembed%5C%2F%7Cchannels%5C%2F.%2B%5C%2F%7Cgroups%5C%2F.%2B%5C%2F%7Cwatch%5C%3Fv%3D%7Cv%5C%2F)%3F(%5BA-Za-z0-9._%25-%5D*)(%5C%26%5CS%2B)%3F
23406			*/
23407
23408			id = url.match(/(http:|https:|)\/\/(player.|www.|app.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com)|vzaar\.com)\/(video\/|videos\/|embed\/|channels\/.+\/|groups\/.+\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
23409
23410			if (id[3].indexOf('youtu') > -1) {
23411				type = 'youtube';
23412			} else if (id[3].indexOf('vimeo') > -1) {
23413				type = 'vimeo';
23414			} else if (id[3].indexOf('vzaar') > -1) {
23415				type = 'vzaar';
23416			} else {
23417				throw new Error('Video URL not supported.');
23418			}
23419			id = id[6];
23420		} else {
23421			throw new Error('Missing video URL.');
23422		}
23423
23424		this._videos[url] = {
23425			type: type,
23426			id: id,
23427			width: width,
23428			height: height
23429		};
23430
23431		item.attr('data-video', url);
23432
23433		this.thumbnail(target, this._videos[url]);
23434	};
23435
23436	/**
23437	 * Creates video thumbnail.
23438	 * @protected
23439	 * @param {jQuery} target - The target containing the video data.
23440	 * @param {Object} info - The video info object.
23441	 * @see `fetch`
23442	 */
23443	Video.prototype.thumbnail = function(target, video) {
23444		var tnLink,
23445			icon,
23446			path,
23447			dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
23448			customTn = target.find('img'),
23449			srcType = 'src',
23450			lazyClass = '',
23451			settings = this._core.settings,
23452			create = function(path) {
23453				icon = '<div class="owl-video-play-icon"></div>';
23454
23455				if (settings.lazyLoad) {
23456					tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
23457				} else {
23458					tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
23459				}
23460				target.after(tnLink);
23461				target.after(icon);
23462			};
23463
23464		// wrap video content into owl-video-wrapper div
23465		target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
23466
23467		if (this._core.settings.lazyLoad) {
23468			srcType = 'data-src';
23469			lazyClass = 'owl-lazy';
23470		}
23471
23472		// custom thumbnail
23473		if (customTn.length) {
23474			create(customTn.attr(srcType));
23475			customTn.remove();
23476			return false;
23477		}
23478
23479		if (video.type === 'youtube') {
23480			path = "//img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
23481			create(path);
23482		} else if (video.type === 'vimeo') {
23483			$.ajax({
23484				type: 'GET',
23485				url: '//vimeo.com/api/v2/video/' + video.id + '.json',
23486				jsonp: 'callback',
23487				dataType: 'jsonp',
23488				success: function(data) {
23489					path = data[0].thumbnail_large;
23490					create(path);
23491				}
23492			});
23493		} else if (video.type === 'vzaar') {
23494			$.ajax({
23495				type: 'GET',
23496				url: '//vzaar.com/api/videos/' + video.id + '.json',
23497				jsonp: 'callback',
23498				dataType: 'jsonp',
23499				success: function(data) {
23500					path = data.framegrab_url;
23501					create(path);
23502				}
23503			});
23504		}
23505	};
23506
23507	/**
23508	 * Stops the current video.
23509	 * @public
23510	 */
23511	Video.prototype.stop = function() {
23512		this._core.trigger('stop', null, 'video');
23513		this._playing.find('.owl-video-frame').remove();
23514		this._playing.removeClass('owl-video-playing');
23515		this._playing = null;
23516		this._core.leave('playing');
23517		this._core.trigger('stopped', null, 'video');
23518	};
23519
23520	/**
23521	 * Starts the current video.
23522	 * @public
23523	 * @param {Event} event - The event arguments.
23524	 */
23525	Video.prototype.play = function(event) {
23526		var target = $(event.target),
23527			item = target.closest('.' + this._core.settings.itemClass),
23528			video = this._videos[item.attr('data-video')],
23529			width = video.width || '100%',
23530			height = video.height || this._core.$stage.height(),
23531			html;
23532
23533		if (this._playing) {
23534			return;
23535		}
23536
23537		this._core.enter('playing');
23538		this._core.trigger('play', null, 'video');
23539
23540		item = this._core.items(this._core.relative(item.index()));
23541
23542		this._core.reset(item.index());
23543
23544		if (video.type === 'youtube') {
23545			html = '<iframe width="' + width + '" height="' + height + '" src="//www.youtube.com/embed/' +
23546				video.id + '?autoplay=1&rel=0&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
23547		} else if (video.type === 'vimeo') {
23548			html = '<iframe src="//player.vimeo.com/video/' + video.id +
23549				'?autoplay=1" width="' + width + '" height="' + height +
23550				'" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
23551		} else if (video.type === 'vzaar') {
23552			html = '<iframe frameborder="0"' + 'height="' + height + '"' + 'width="' + width +
23553				'" allowfullscreen mozallowfullscreen webkitAllowFullScreen ' +
23554				'src="//view.vzaar.com/' + video.id + '/player?autoplay=true"></iframe>';
23555		}
23556
23557		$('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
23558
23559		this._playing = item.addClass('owl-video-playing');
23560	};
23561
23562	/**
23563	 * Checks whether an video is currently in full screen mode or not.
23564	 * @todo Bad style because looks like a readonly method but changes members.
23565	 * @protected
23566	 * @returns {Boolean}
23567	 */
23568	Video.prototype.isInFullScreen = function() {
23569		var element = document.fullscreenElement || document.mozFullScreenElement ||
23570				document.webkitFullscreenElement;
23571
23572		return element && $(element).parent().hasClass('owl-video-frame');
23573	};
23574
23575	/**
23576	 * Destroys the plugin.
23577	 */
23578	Video.prototype.destroy = function() {
23579		var handler, property;
23580
23581		this._core.$element.off('click.owl.video');
23582
23583		for (handler in this._handlers) {
23584			this._core.$element.off(handler, this._handlers[handler]);
23585		}
23586		for (property in Object.getOwnPropertyNames(this)) {
23587			typeof this[property] != 'function' && (this[property] = null);
23588		}
23589	};
23590
23591	$.fn.owlCarousel.Constructor.Plugins.Video = Video;
23592
23593})(window.Zepto || window.jQuery, window, document);
23594
23595/**
23596 * Animate Plugin
23597 * @version 2.1.0
23598 * @author Bartosz Wojciechowski
23599 * @author David Deutsch
23600 * @license The MIT License (MIT)
23601 */
23602;(function($, window, document, undefined) {
23603
23604	/**
23605	 * Creates the animate plugin.
23606	 * @class The Navigation Plugin
23607	 * @param {Owl} scope - The Owl Carousel
23608	 */
23609	var Animate = function(scope) {
23610		this.core = scope;
23611		this.core.options = $.extend({}, Animate.Defaults, this.core.options);
23612		this.swapping = true;
23613		this.previous = undefined;
23614		this.next = undefined;
23615
23616		this.handlers = {
23617			'change.owl.carousel': $.proxy(function(e) {
23618				if (e.namespace && e.property.name == 'position') {
23619					this.previous = this.core.current();
23620					this.next = e.property.value;
23621				}
23622			}, this),
23623			'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
23624				if (e.namespace) {
23625					this.swapping = e.type == 'translated';
23626				}
23627			}, this),
23628			'translate.owl.carousel': $.proxy(function(e) {
23629				if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
23630					this.swap();
23631				}
23632			}, this)
23633		};
23634
23635		this.core.$element.on(this.handlers);
23636	};
23637
23638	/**
23639	 * Default options.
23640	 * @public
23641	 */
23642	Animate.Defaults = {
23643		animateOut: false,
23644		animateIn: false
23645	};
23646
23647	/**
23648	 * Toggles the animation classes whenever an translations starts.
23649	 * @protected
23650	 * @returns {Boolean|undefined}
23651	 */
23652	Animate.prototype.swap = function() {
23653
23654		if (this.core.settings.items !== 1) {
23655			return;
23656		}
23657
23658		if (!$.support.animation || !$.support.transition) {
23659			return;
23660		}
23661
23662		this.core.speed(0);
23663
23664		var left,
23665			clear = $.proxy(this.clear, this),
23666			previous = this.core.$stage.children().eq(this.previous),
23667			next = this.core.$stage.children().eq(this.next),
23668			incoming = this.core.settings.animateIn,
23669			outgoing = this.core.settings.animateOut;
23670
23671		if (this.core.current() === this.previous) {
23672			return;
23673		}
23674
23675		if (outgoing) {
23676			left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
23677			previous.one($.support.animation.end, clear)
23678				.css( { 'left': left + 'px' } )
23679				.addClass('animated owl-animated-out')
23680				.addClass(outgoing);
23681		}
23682
23683		if (incoming) {
23684			next.one($.support.animation.end, clear)
23685				.addClass('animated owl-animated-in')
23686				.addClass(incoming);
23687		}
23688	};
23689
23690	Animate.prototype.clear = function(e) {
23691		$(e.target).css( { 'left': '' } )
23692			.removeClass('animated owl-animated-out owl-animated-in')
23693			.removeClass(this.core.settings.animateIn)
23694			.removeClass(this.core.settings.animateOut);
23695		this.core.onTransitionEnd();
23696	};
23697
23698	/**
23699	 * Destroys the plugin.
23700	 * @public
23701	 */
23702	Animate.prototype.destroy = function() {
23703		var handler, property;
23704
23705		for (handler in this.handlers) {
23706			this.core.$element.off(handler, this.handlers[handler]);
23707		}
23708		for (property in Object.getOwnPropertyNames(this)) {
23709			typeof this[property] != 'function' && (this[property] = null);
23710		}
23711	};
23712
23713	$.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
23714
23715})(window.Zepto || window.jQuery, window, document);
23716
23717/**
23718 * Autoplay Plugin
23719 * @version 2.1.0
23720 * @author Bartosz Wojciechowski
23721 * @author Artus Kolanowski
23722 * @author David Deutsch
23723 * @license The MIT License (MIT)
23724 */
23725;(function($, window, document, undefined) {
23726
23727	/**
23728	 * Creates the autoplay plugin.
23729	 * @class The Autoplay Plugin
23730	 * @param {Owl} scope - The Owl Carousel
23731	 */
23732	var Autoplay = function(carousel) {
23733		/**
23734		 * Reference to the core.
23735		 * @protected
23736		 * @type {Owl}
23737		 */
23738		this._core = carousel;
23739
23740		/**
23741		 * The autoplay timeout.
23742		 * @type {Timeout}
23743		 */
23744		this._timeout = null;
23745
23746		/**
23747		 * Indicates whenever the autoplay is paused.
23748		 * @type {Boolean}
23749		 */
23750		this._paused = false;
23751
23752		/**
23753		 * All event handlers.
23754		 * @protected
23755		 * @type {Object}
23756		 */
23757		this._handlers = {
23758			'changed.owl.carousel': $.proxy(function(e) {
23759				if (e.namespace && e.property.name === 'settings') {
23760					if (this._core.settings.autoplay) {
23761						this.play();
23762					} else {
23763						this.stop();
23764					}
23765				} else if (e.namespace && e.property.name === 'position') {
23766					//console.log('play?', e);
23767					if (this._core.settings.autoplay) {
23768						this._setAutoPlayInterval();
23769					}
23770				}
23771			}, this),
23772			'initialized.owl.carousel': $.proxy(function(e) {
23773				if (e.namespace && this._core.settings.autoplay) {
23774					this.play();
23775				}
23776			}, this),
23777			'play.owl.autoplay': $.proxy(function(e, t, s) {
23778				if (e.namespace) {
23779					this.play(t, s);
23780				}
23781			}, this),
23782			'stop.owl.autoplay': $.proxy(function(e) {
23783				if (e.namespace) {
23784					this.stop();
23785				}
23786			}, this),
23787			'mouseover.owl.autoplay': $.proxy(function() {
23788				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
23789					this.pause();
23790				}
23791			}, this),
23792			'mouseleave.owl.autoplay': $.proxy(function() {
23793				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
23794					this.play();
23795				}
23796			}, this),
23797			'touchstart.owl.core': $.proxy(function() {
23798				if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
23799					this.pause();
23800				}
23801			}, this),
23802			'touchend.owl.core': $.proxy(function() {
23803				if (this._core.settings.autoplayHoverPause) {
23804					this.play();
23805				}
23806			}, this)
23807		};
23808
23809		// register event handlers
23810		this._core.$element.on(this._handlers);
23811
23812		// set default options
23813		this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
23814	};
23815
23816	/**
23817	 * Default options.
23818	 * @public
23819	 */
23820	Autoplay.Defaults = {
23821		autoplay: false,
23822		autoplayTimeout: 5000,
23823		autoplayHoverPause: false,
23824		autoplaySpeed: false
23825	};
23826
23827	/**
23828	 * Starts the autoplay.
23829	 * @public
23830	 * @param {Number} [timeout] - The interval before the next animation starts.
23831	 * @param {Number}
23831 [speed] - The animation speed for the animations.
23832	 */
23833	Autoplay.prototype.play = function(timeout, speed) {
23834		this._paused = false;
23835
23836		if (this._core.is('rotating')) {
23837			return;
23838		}
23839
23840		this._core.enter('rotating');
23841
23842		this._setAutoPlayInterval();
23843	};
23844
23845	/**
23846	 * Gets a new timeout
23847	 * @private
23848	 * @param {Number} [timeout] - The interval before the next animation starts.
23849	 * @param {Number} [speed] - The animation speed for the animations.
23850	 * @return {Timeout}
23851	 */
23852	Autoplay.prototype._getNextTimeout = function(timeout, speed) {
23853		if ( this._timeout ) {
23854			window.clearTimeout(this._timeout);
23855		}
23856		return window.setTimeout($.proxy(function() {
23857			if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
23858				return;
23859			}
23860			this._core.next(speed || this._core.settings.autoplaySpeed);
23861		}, this), timeout || this._core.settings.autoplayTimeout);
23862	};
23863
23864	/**
23865	 * Sets autoplay in motion.
23866	 * @private
23867	 */
23868	Autoplay.prototype._setAutoPlayInterval = function() {
23869		this._timeout = this._getNextTimeout();
23870	};
23871
23872	/**
23873	 * Stops the autoplay.
23874	 * @public
23875	 */
23876	Autoplay.prototype.stop = function() {
23877		if (!this._core.is('rotating')) {
23878			return;
23879		}
23880
23881		window.clearTimeout(this._timeout);
23882		this._core.leave('rotating');
23883	};
23884
23885	/**
23886	 * Stops the autoplay.
23887	 * @public
23888	 */
23889	Autoplay.prototype.pause = function() {
23890		if (!this._core.is('rotating')) {
23891			return;
23892		}
23893
23894		this._paused = true;
23895	};
23896
23897	/**
23898	 * Destroys the plugin.
23899	 */
23900	Autoplay.prototype.destroy = function() {
23901		var handler, property;
23902
23903		this.stop();
23904
23905		for (handler in this._handlers) {
23906			this._core.$element.off(handler, this._handlers[handler]);
23907		}
23908		for (property in Object.getOwnPropertyNames(this)) {
23909			typeof this[property] != 'function' && (this[property] = null);
23910		}
23911	};
23912
23913	$.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
23914
23915})(window.Zepto || window.jQuery, window, document);
23916
23917/**
23918 * Navigation Plugin
23919 * @version 2.1.0
23920 * @author Artus Kolanowski
23921 * @author David Deutsch
23922 * @license The MIT License (MIT)
23923 */
23924;(function($, window, document, undefined) {
23925	'use strict';
23926
23927	/**
23928	 * Creates the navigation plugin.
23929	 * @class The Navigation Plugin
23930	 * @param {Owl} carousel - The Owl Carousel.
23931	 */
23932	var Navigation = function(carousel) {
23933		/**
23934		 * Reference to the core.
23935		 * @protected
23936		 * @type {Owl}
23937		 */
23938		this._core = carousel;
23939
23940		/**
23941		 * Indicates whether the plugin is initialized or not.
23942		 * @protected
23943		 * @type {Boolean}
23944		 */
23945		this._initialized = false;
23946
23947		/**
23948		 * The current paging indexes.
23949		 * @protected
23950		 * @type {Array}
23951		 */
23952		this._pages = [];
23953
23954		/**
23955		 * All DOM elements of the user interface.
23956		 * @protected
23957		 * @type {Object}
23958		 */
23959		this._controls = {};
23960
23961		/**
23962		 * Markup for an indicator.
23963		 * @protected
23964		 * @type {Array.<String>}
23965		 */
23966		this._templates = [];
23967
23968		/**
23969		 * The carousel element.
23970		 * @type {jQuery}
23971		 */
23972		this.$element = this._core.$element;
23973
23974		/**
23975		 * Overridden methods of the carousel.
23976		 * @protected
23977		 * @type {Object}
23978		 */
23979		this._overrides = {
23980			next: this._core.next,
23981			prev: this._core.prev,
23982			to: this._core.to
23983		};
23984
23985		/**
23986		 * All event handlers.
23987		 * @protected
23988		 * @type {Object}
23989		 */
23990		this._handlers = {
23991			'prepared.owl.carousel': $.proxy(function(e) {
23992				if (e.namespace && this._core.settings.dotsData) {
23993					this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
23994						$(e.content).find('[data-dot]').addBack('[data-dot]').attr('data-dot') + '</div>');
23995				}
23996			}, this),
23997			'added.owl.carousel': $.proxy(function(e) {
23998				if (e.namespace && this._core.settings.dotsData) {
23999					this._templates.splice(e.position, 0, this._templates.pop());
24000				}
24001			}, this),
24002			'remove.owl.carousel': $.proxy(function(e) {
24003				if (e.namespace && this._core.settings.dotsData) {
24004					this._templates.splice(e.position, 1);
24005				}
24006			}, this),
24007			'changed.owl.carousel': $.proxy(function(e) {
24008				if (e.namespace && e.property.name == 'position') {
24009					this.draw();
24010				}
24011			}, this),
24012			'initialized.owl.carousel': $.proxy(function(e) {
24013				if (e.namespace && !this._initialized) {
24014					this._core.trigger('initialize', null, 'navigation');
24015					this.initialize();
24016					this.update();
24017					this.draw();
24018					this._initialized = true;
24019					this._core.trigger('initialized', null, 'navigation');
24020				}
24021			}, this),
24022			'refreshed.owl.carousel': $.proxy(function(e) {
24023				if (e.namespace && this._initialized) {
24024					this._core.trigger('refresh', null, 'navigation');
24025					this.update();
24026					this.draw();
24027					this._core.trigger('refreshed', null, 'navigation');
24028				}
24029			}, this)
24030		};
24031
24032		// set default options
24033		this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
24034
24035		// register event handlers
24036		this.$element.on(this._handlers);
24037	};
24038
24039	/**
24040	 * Default options.
24041	 * @public
24042	 * @todo Rename `slideBy` to `navBy`
24043	 */
24044	Navigation.Defaults = {
24045		nav: false,
24046		navText: [ 'prev', 'next' ],
24047		navSpeed: false,
24048		navElement: 'div',
24049		navContainer: false,
24050		navContainerClass: 'owl-nav',
24051		navClass: [ 'owl-prev', 'owl-next' ],
24052		slideBy: 1,
24053		dotClass: 'owl-dot',
24054		dotsClass: 'owl-dots',
24055		dots: true,
24056		dotsEach: false,
24057		dotsData: false,
24058		dotsSpeed: false,
24059		dotsContainer: false
24060	};
24061
24062	/**
24063	 * Initializes the layout of the plugin and extends the carousel.
24064	 * @protected
24065	 */
24066	Navigation.prototype.initialize = function() {
24067		var override,
24068			settings = this._core.settings;
24069
24070		// create DOM structure for relative navigation
24071		this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
24072			: $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
24073
24074		this._controls.$previous = $('<' + settings.navElement + '>')
24075			.addClass(settings.navClass[0])
vendor: 10,907 bytes, lines 24076-24476
24076			.html(settings.navText[0])
24077			.prependTo(this._controls.$relative)
24078			.on('click', $.proxy(function(e) {
24079				this.prev(settings.navSpeed);
24080			}, this));
24081		this._controls.$next = $('<' + settings.navElement + '>')
24082			.addClass(settings.navClass[1])
24083			.html(settings.navText[1])
24084			.appendTo(this._controls.$relative)
24085			.on('click', $.proxy(function(e) {
24086				this.next(settings.navSpeed);
24087			}, this));
24088
24089		// create DOM structure for absolute navigation
24090		if (!settings.dotsData) {
24091			this._templates = [ $('<div>')
24092				.addClass(settings.dotClass)
24093				.append($('<span>'))
24094				.prop('outerHTML') ];
24095		}
24096
24097		this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
24098			: $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
24099
24100		this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
24101			var index = $(e.target).parent().is(this._controls.$absolute)
24102				? $(e.target).index() : $(e.target).parent().index();
24103
24104			e.preventDefault();
24105
24106			this.to(index, settings.dotsSpeed);
24107		}, this));
24108
24109		// override public methods of the carousel
24110		for (override in this._overrides) {
24111			this._core[override] = $.proxy(this[override], this);
24112		}
24113	};
24114
24115	/**
24116	 * Destroys the plugin.
24117	 * @protected
24118	 */
24119	Navigation.prototype.destroy = function() {
24120		var handler, control, property, override;
24121
24122		for (handler in this._handlers) {
24123			this.$element.off(handler, this._handlers[handler]);
24124		}
24125		for (control in this._controls) {
24126			this._controls[control].remove();
24127		}
24128		for (override in this.overides) {
24129			this._core[override] = this._overrides[override];
24130		}
24131		for (property in Object.getOwnPropertyNames(this)) {
24132			typeof this[property] != 'function' && (this[property] = null);
24133		}
24134	};
24135
24136	/**
24137	 * Updates the internal state.
24138	 * @protected
24139	 */
24140	Navigation.prototype.update = function() {
24141		var i, j, k,
24142			lower = this._core.clones().length / 2,
24143			upper = lower + this._core.items().length,
24144			maximum = this._core.maximum(true),
24145			settings = this._core.settings,
24146			size = settings.center || settings.autoWidth || settings.dotsData
24147				? 1 : settings.dotsEach || settings.items;
24148
24149		if (settings.slideBy !== 'page') {
24150			settings.slideBy = Math.min(settings.slideBy, settings.items);
24151		}
24152
24153		if (settings.dots || settings.slideBy == 'page') {
24154			this._pages = [];
24155
24156			for (i = lower, j = 0, k = 0; i < upper; i++) {
24157				if (j >= size || j === 0) {
24158					this._pages.push({
24159						start: Math.min(maximum, i - lower),
24160						end: i - lower + size - 1
24161					});
24162					if (Math.min(maximum, i - lower) === maximum) {
24163						break;
24164					}
24165					j = 0, ++k;
24166				}
24167				j += this._core.mergers(this._core.relative(i));
24168			}
24169		}
24170	};
24171
24172	/**
24173	 * Draws the user interface.
24174	 * @todo The option `dotsData` wont work.
24175	 * @protected
24176	 */
24177	Navigation.prototype.draw = function() {
24178		var difference,
24179			settings = this._core.settings,
24180			disabled = this._core.items().length <= settings.items,
24181			index = this._core.relative(this._core.current()),
24182			loop = settings.loop || settings.rewind;
24183
24184		this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
24185
24186		if (settings.nav) {
24187			this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
24188			this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
24189		}
24190
24191		this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
24192
24193		if (settings.dots) {
24194			difference = this._pages.length - this._controls.$absolute.children().length;
24195
24196			if (settings.dotsData && difference !== 0) {
24197				this._controls.$absolute.html(this._templates.join(''));
24198			} else if (difference > 0) {
24199				this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
24200			} else if (difference < 0) {
24201				this._controls.$absolute.children().slice(difference).remove();
24202			}
24203
24204			this._controls.$absolute.find('.active').removeClass('active');
24205			this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
24206		}
24207	};
24208
24209	/**
24210	 * Extends event data.
24211	 * @protected
24212	 * @param {Event} event - The event object which gets thrown.
24213	 */
24214	Navigation.prototype.onTrigger = function(event) {
24215		var settings = this._core.settings;
24216
24217		event.page = {
24218			index: $.inArray(this.current(), this._pages),
24219			count: this._pages.length,
24220			size: settings && (settings.center || settings.autoWidth || settings.dotsData
24221				? 1 : settings.dotsEach || settings.items)
24222		};
24223	};
24224
24225	/**
24226	 * Gets the current page position of the carousel.
24227	 * @protected
24228	 * @returns {Number}
24229	 */
24230	Navigation.prototype.current = function() {
24231		var current = this._core.relative(this._core.current());
24232		return $.grep(this._pages, $.proxy(function(page, index) {
24233			return page.start <= current && page.end >= current;
24234		}, this)).pop();
24235	};
24236
24237	/**
24238	 * Gets the current succesor/predecessor position.
24239	 * @protected
24240	 * @returns {Number}
24241	 */
24242	Navigation.prototype.getPosition = function(successor) {
24243		var position, length,
24244			settings = this._core.settings;
24245
24246		if (settings.slideBy == 'page') {
24247			position = $.inArray(this.current(), this._pages);
24248			length = this._pages.length;
24249			successor ? ++position : --position;
24250			position = this._pages[((position % length) + length) % length].start;
24251		} else {
24252			position = this._core.relative(this._core.current());
24253			length = this._core.items().length;
24254			successor ? position += settings.slideBy : position -= settings.slideBy;
24255		}
24256
24257		return position;
24258	};
24259
24260	/**
24261	 * Slides to the next item or page.
24262	 * @public
24263	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
24264	 */
24265	Navigation.prototype.next = function(speed) {
24266		$.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
24267	};
24268
24269	/**
24270	 * Slides to the previous item or page.
24271	 * @public
24272	 * @param {Number} [speed=false] - The time in milliseconds for the transition.
24273	 */
24274	Navigation.prototype.prev = function(speed) {
24275		$.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
24276	};
24277
24278	/**
24279	 * Slides to the specified item or page.
24280	 * @public
24281	 * @param {Number} position - The position of the item or page.
24282	 * @param {Number} [speed] - The time in milliseconds for the transition.
24283	 * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
24284	 */
24285	Navigation.prototype.to = function(position, speed, standard) {
24286		var length;
24287
24288		if (!standard && this._pages.length) {
24289			length = this._pages.length;
24290			$.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
24291		} else {
24292			$.proxy(this._overrides.to, this._core)(position, speed);
24293		}
24294	};
24295
24296	$.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
24297
24298})(window.Zepto || window.jQuery, window, document);
24299
24300/**
24301 * Hash Plugin
24302 * @version 2.1.0
24303 * @author Artus Kolanowski
24304 * @author David Deutsch
24305 * @license The MIT License (MIT)
24306 */
24307;(function($, window, document, undefined) {
24308	'use strict';
24309
24310	/**
24311	 * Creates the hash plugin.
24312	 * @class The Hash Plugin
24313	 * @param {Owl} carousel - The Owl Carousel
24314	 */
24315	var Hash = function(carousel) {
24316		/**
24317		 * Reference to the core.
24318		 * @protected
24319		 * @type {Owl}
24320		 */
24321		this._core = carousel;
24322
24323		/**
24324		 * Hash index for the items.
24325		 * @protected
24326		 * @type {Object}
24327		 */
24328		this._hashes = {};
24329
24330		/**
24331		 * The carousel element.
24332		 * @type {jQuery}
24333		 */
24334		this.$element = this._core.$element;
24335
24336		/**
24337		 * All event handlers.
24338		 * @protected
24339		 * @type {Object}
24340		 */
24341		this._handlers = {
24342			'initialized.owl.carousel': $.proxy(function(e) {
24343				if (e.namespace && this._core.settings.startPosition === 'URLHash') {
24344					$(window).trigger('hashchange.owl.navigation');
24345				}
24346			}, this),
24347			'prepared.owl.carousel': $.proxy(function(e) {
24348				if (e.namespace) {
24349					var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
24350
24351					if (!hash) {
24352						return;
24353					}
24354
24355					this._hashes[hash] = e.content;
24356				}
24357			}, this),
24358			'changed.owl.carousel': $.proxy(function(e) {
24359				if (e.namespace && e.property.name === 'position') {
24360					var current = this._core.items(this._core.relative(this._core.current())),
24361						hash = $.map(this._hashes, function(item, hash) {
24362							return item === current ? hash : null;
24363						}).join();
24364
24365					if (!hash || window.location.hash.slice(1) === hash) {
24366						return;
24367					}
24368
24369					window.location.hash = hash;
24370				}
24371			}, this)
24372		};
24373
24374		// set default options
24375		this._core.options = $.extend({}, Hash.Defaults, this._core.options);
24376
24377		// register the event handlers
24378		this.$element.on(this._handlers);
24379
24380		// register event listener for hash navigation
24381		$(window).on('hashchange.owl.navigation', $.proxy(function(e) {
24382			var hash = window.location.hash.substring(1),
24383				items = this._core.$stage.children(),
24384				position = this._hashes[hash] && items.index(this._hashes[hash]);
24385
24386			if (position === undefined || position === this._core.current()) {
24387				return;
24388			}
24389
24390			this._core.to(this._core.relative(position), false, true);
24391		}, this));
24392	};
24393
24394	/**
24395	 * Default options.
24396	 * @public
24397	 */
24398	Hash.Defaults = {
24399		URLhashListener: false
24400	};
24401
24402	/**
24403	 * Destroys the plugin.
24404	 * @public
24405	 */
24406	Hash.prototype.destroy = function() {
24407		var handler, property;
24408
24409		$(window).off('hashchange.owl.navigation');
24410
24411		for (handler in this._handlers) {
24412			this._core.$element.off(handler, this._handlers[handler]);
24413		}
24414		for (property in Object.getOwnPropertyNames(this)) {
24415			typeof this[property] != 'function' && (this[property] = null);
24416		}
24417	};
24418
24419	$.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
24420
24421})(window.Zepto || window.jQuery, window, document);
24422
24423/**
24424 * Support Plugin
24425 *
24426 * @version 2.1.0
24427 * @author Vivid Planet Software GmbH
24428 * @author Artus Kolanowski
24429 * @author David Deutsch
24430 * @license The MIT License (MIT)
24431 */
24432;(function($, window, document, undefined) {
24433
24434	var style = $('<support>').get(0).style,
24435		prefixes = 'Webkit Moz O ms'.split(' '),
24436		events = {
24437			transition: {
24438				end: {
24439					WebkitTransition: 'webkitTransitionEnd',
24440					MozTransition: 'transitionend',
24441					OTransition: 'oTransitionEnd',
24442					transition: 'transitionend'
24443				}
24444			},
24445			animation: {
24446				end: {
24447					WebkitAnimation: 'webkitAnimationEnd',
24448					MozAnimation: 'animationend',
24449					OAnimation: 'oAnimationEnd',
24450					animation: 'animationend'
24451				}
24452			}
24453		},
24454		tests = {
24455			csstransforms: function() {
24456				return !!test('transform');
24457			},
24458			csstransforms3d: function() {
24459				return !!test('perspective');
24460			},
24461			csstransitions: function() {
24462				return !!test('transition');
24463			},
24464			cssanimations: function() {
24465				return !!test('animation');
24466			}
24467		};
24468
24469	function test(property, prefixed) {
24470		var result = false,
24471			upper = property.charAt(0).toUpperCase() + property.slice(1);
24472
24473		$.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
24474			if (style[property] !== undefined) {
24475				result = prefixed ? property : true;
24476				return false;
24477			}
24478		});
24479
24480		return result;
24481	}
24482
24483	function prefixed(property) {
24484		return test(property, true);
24485	}
24486
24487	if (tests.csstransitions()) {
24488		/* jshint -W053 */
24489		$.support.transition = new String(prefixed('transition'))
24490		$.support.transition.end = events.transition.end[ $.support.transition ];
24491	}
24492
24493	if (tests.cssanimations()) {
24494		/* jshint -W053 */
24495		$.support.animation = new String(prefixed('animation'))
24496		$.support.animation.end = events.animation.end[ $.support.animation ];
24497	}
24498
24499	if (tests.csstransforms()) {
24500		/* jshint -W053 */
24501		$.support.transform = new String(prefixed('transform'));
24502		$.support.transform3d = tests.csstransforms3d();
24503	}
24504
24505})(window.Zepto || window.jQuery, window, document);
24506
24507//Use this class for front-end JS needed to create Richtext based on styles or formatting applied in the RTE.
24508(function($){
24509
24510    "use strict";
24511
24512    ns('News.App').RichText = {
24513
24514        load: function() {
24515
24516            //Clone <span class=pullquote> into a pulleDquote
24517            News.App.RichText.createPulledQuote();
24518            //edit <span class=blockquote> into a blockedquote
24519            News.App.RichText.editBlockedQuote();
24520            // News.App.RichText.editKeypointBlock();
24521
24522        },
24523        createPulledQuote: function() {
24524            $('span.pullquote').each(function() {
24525                var $parentParagraph = $(this).closest('p');
24526                $parentParagraph.css('position', 'relative');
24527                $(this).clone().addClass('pulledquote').prependTo($parentParagraph);
24528            });
24529        },
24530        editBlockedQuote: function() {
24531            $('span.blockquote').each(function() {
24532                $('<blockquote>' + $(this).html() + '</blockquote>').insertAfter($(this));
24533                $(this).remove();
24534            });
24535        },
24536
24537        // editKeypointBlock: function () {
24538        //     $('span.hrule').each(function() {
24539        //         $('<hr class="'+ $(this).attr('class') +'" />').insertAfter($(this));
24540        //         $(this).remove();
24541        //     });
24542        //     $('span.keypointtitle').each(function() {
24543        //         $('<div class="'+ $(this).attr('class') +'" >'+ $(this).html() + '</div>').insertAfter($(this));
24544        //         $(this).remove();
24545        //     });
24546        // }
24547    };
24548
24549    News.App.RichText.load();
24550
24551})(jQuery);
24552
24553/* Live Edit functionality */
24554function isAuthorMode() {
24555    if (typeof CQ != "undefined") {
24556        if (CQ && CQ.WCM && CQ.WCM.isEditMode) {
24557            return CQ.WCM.isEditMode('True')
24558        }
24559    }
24560}
24561
24562
24563
24564// Browser Close Event
24565if (isAuthorMode()) {
24566    let TRACK_OPEN_COMPONENT;
24567
24568    window.addEventListener("load", () => {
24569        let dialogs = ns('News.dialogs')
24570        editButton = $('.cq-editbar .x-btn-text');
24571
24572        // Checking the live edit event triggering while clicking on each component */
24573        editButton.on('click',function(){
24574
24575            let componentListener = {
24576                pageUrl: window.CQURLInfo.requestPath,
24577                pageUserId: window.CQ.User.getCurrentUser().getUserID(),
24578                userName: window.CQ.User.getCurrentUser().data.userName,
24579                componentPath:''
24580            }
24581
24582            let liveEventFn = {
24583
24584                // Sending the event listener to cq:listener
24585                liveInit: function(comp) {
24586                    let postRequestData = {
24587                        pageUrl: componentListener.pageUrl,
24588                        pageUserId: componentListener.pageUserId,
24589                        userName:  componentListener.userName,
24590                        componentPath: comp.path,
24591                        releaseFlag: true,
24592                        liveusers:[]
24593                    }
24594                    componentListener.componentPath = comp.path;
24595                    var isLockedCheck,
24596                    idWrapper;
24597
24598                    // Sending the POST request to java model and saved the values into JCR
24599                    function postReq(flagVal){
24600                        $.ajax({
24601                            type: "POST",
24602                            url: "/services/news/liveDetails?path="+postRequestData.componentPath+"&userId="+postRequestData.pageUserId+"&isLocked="+flagV
24602al+"&firstName="+postRequestData.userName,
24603                            dataType: "html",
24604                            contentType:"html/plain; charset=utf-8",
24605                            success: function(data, textStatus, xhr) {
24606                                if(xhr.status == 200){
24607                                    liveEditFn();
24608                                }
24609                            }
24610                        });
24611                    }
24612                    postReq(true);
24613
24614                    function liveEditFn(){
24615
24616                        // Fetching the liveData values from the JCR properties and manipulate the functionalities.
24617                        $.ajax({
24618                            url: "/services/news/liveDetails?path="+postRequestData.componentPath,
24619                            type: 'GET',
24620                            dataType: 'json',
24621                            success: function(res) {
24622                                if(res !== null){
24623                                    postRequestData.liveusers = [];
24624                                    res.userId.forEach(function(value){
24625                                        if(( value.userId !== postRequestData.pageUserId) && value.isLocked == true && postRequestData.componentPath == res.path  ){
24626                                            postRequestData.liveusers.push("<li>"+value.firstName+"</li>");
24627                                            isLockedCheck = true;
24628                                        }
24629                                        $('.live-editing-wrapper li').innerHTML += value.userId;
24630                                        return true;
24631                                    })
24632                                }
24633
24634                                // Assign the dialog markups.
24635                                let dialogHTML = `
24636                                <div class="live-editing-container">
24637                                <div class="live-editing-wrapper">
24638                                <h3>Another user is currently editing this component. Do you want to proceed?</h3>                        
24639                                <ul>`+postRequestData.liveusers+`</ul>                        
24640                                <div class="btn-wrapper">
24641                                <button class="liveedit-yes">Yes</button>
24642                                <button class="liveedit-no">No</button>
24643                                </div>
24644                                </div>
24645                                </div>
24646                                `
24647                                // Executed a single function for dialogue visiblity.
24648                                function containerVisiblity(_wrapperId,displayItem){
24649                                    if(_wrapperId.querySelector('.live-editing-container') !== null){
24650                                        _wrapperId.querySelector('.live-editing-container').style.display = displayItem;
24651                                    }
24652                                }
24653
24654                                setTimeout(()=>{
24655                                    let getComID = comp.bwrap.id;
24656                                    idWrapper = document.querySelector('#'+getComID).closest('.x-window-bwrap');
24657                                },10);
24658
24659
24660                                // Dialogue close button execution
24661                                $('.x-window .x-tool-close').off('click');
24662                                $('.x-window .x-tool-close').on('click',()=>{
24663                                    isLockedCheck == false;
24664                                    $('.live-editing-container').remove();                                      
24665                                    postReq(false);
24666                                });
24667
24668
24669                                // Dialogue cancel button execution
24670                                $('.x-panel-fbar .cq-btn-cancel .x-btn-text').off('click');
24671                                $('.x-panel-fbar .cq-btn-cancel .x-btn-text').on('click',()=>{
24672                                    isLockedCheck == false;
24673                                    $('.live-editing-container').remove();
24674                                    postReq(false);
24675                                });
24676
24677                                // Dialogue ok button execution
24678                                $(".x-window .cq-btn-ok").off('click');
24679                                $(".x-window .cq-btn-ok").on('click',()=>{                                    
24680                                    setTimeout(function(){                                        
24681                                        if($('.ext-mb-content').length < 1){
24682                                            $.ajax({
24683                                                type: "POST",
24684                                                url: "/services/news/liveDetails?path="+postRequestData.componentPath+"&userId="+postRequestData.pageUserId+"&isLocked=false&firstName="+postRequestData.userName,
24685                                                dataType: "html",
24686                                                contentType:"html/plain; charset=utf-8",
24687                                                success: function(res) {}
24688                                            });
24689                                        }
24690                                    },1000);                                    
24691                                });
24692
24693                                // Dialogue Proceed Button execution
24694                                function proceedBtn(){
24695
24696                                    $( document ).delegate( ".liveedit-yes", "click", function() {                                        
24697                                        $('.live-editing-container').remove();
24698                                        containerVisiblity(idWrapper,"none");
24699                                    })
24700                                };
24701
24702                                // Dialogue Not-Proceed Button execution
24703                                function notProceedBtn(){
24704                                    $(document).off("click", ".liveedit-no");
24705                                    $(document).on("click", ".liveedit-no", function() {                                        
24706                                        $('.live-editing-container').remove();
24707                                        idWrapper.closest('.x-window').querySelector('.cq-btn-cancel').click();
24708                                        postReq(false);
24709                                    })
24710                                }
24711
24712                                // Checking the live edit condition and appending the dialogue scenarios.
24713                                setTimeout(()=>{
24714                                    proceedBtn();
24715                                    notProceedBtn();
24716                                    if(isLockedCheck == true){
24717                                        let shadow = document.querySelector('.x-shadow');
24718                                        if(shadow != undefined || shadow != null){shadow.style.display = 'none'}
24719                                        $(idWrapper).append(dialogHTML);
24720                                    }else{
24721                                        containerVisiblity(idWrapper,"block");
24722                                        $('.live-editing-container').remove();
24723                                    }
24724                                },500);
24725                            },
24726                        });
24727                    };
24728                }
24729            }
24730
24731            // Invoke the entire functionality
24732            dialogs.liveEditEvent =  {
24733                liveInit: liveEventFn.liveInit,
24734            }
24735
24736            return TRACK_OPEN_COMPONENT = componentListener;
24737        })
24738    });
24739    
24740    $(window).bind('beforeunload', ()=> {
24741
24742        if(TRACK_OPEN_COMPONENT && TRACK_OPEN_COMPONENT.componentPath !== ""){
24743            $.ajax({
24744                type: "POST",
24745                url: "/services/news/liveDetails?path="+TRACK_OPEN_COMPONENT.componentPath+"&userId="+TRACK_OPEN_COMPONENT.pageUserId+"&isLocked=false&firstName="+TRACK_OPEN_COMPONENT.userName,
24746                dataType: "html",
24747                contentType:"html/plain; charset=utf-8"
24748            });
24749        }
24750        // To handle browsers alert messages.
24751        let checkBrowserCloseAlert = 0;
24752        let interval = setInterval(function(){
24753            checkBrowserCloseAlert += 1;
24754            if(checkBrowserCloseAlert === 3){
24755                if(TRACK_OPEN_COMPONENT.componentPath !== ""){   
24756                    $.ajax({
24757                        type: "POST",
24758                        url: "/services/news/liveDetails?path="+TRACK_OPEN_COMPONENT.componentPath+"&userId="+TRACK_OPEN_COMPONENT.pageUserId+"&isLocked=true&firstName="+TRACK_OPEN_COMPONENT.userName,
24759                        dataType: "html",
24760                        contentType:"html/plain; charset=utf-8"
24761                    });
24762                }
24763                clearInterval(interval);
24764            }        
24765        }, 1500); 
24766        // fallback solution for firefox.
24767        let browser = navigator.userAgent;
24768        if(browser.includes('Firefox') == true){
24769            console.log('For Firefox');
24770        }
24771    });
24772}
24773
24774
24775try {
24776    _.templateSettings = {
24777        interpolate: /\<\@\=(.+?)\@\>/gim,
24778        evaluate: /\<\@(.+?)\@\>/gim
24779    };
24780} catch (e) {}
24781+function($) {
24782    News.core = News.core || {
24783        URL: function(urlData) {
24784            if (!News.core.URL.reg) {
24785                // Creating the regex object as a static object (Allows for it to only need to be 'compiled' once)
24786                // Regex splits the hostname from the pathname
24787                News.core.URL.reg = new RegExp(/(http(s)?:\/\/[^\/]+)?(\/.+)/);
24788            }
24789            var matches = News.core.URL.reg.exec(urlData);
24790            // 4 is the expected matcher length (0 for 'all,' 1 for hostname, 2 for 's' match, and 3 for pathname)
24791            // If it doesn't match that, then the region good is bad/corrupted/etc
24792            if (matches !== null && matches.length == 4) {
24793                // Doing checks to make sure we don't return any undefined variables,
24794                // else we could end up with "undefined/content/news/ny/buffalo" as a URL we try to redirect to
24795                this.hostname = matches[1] !== undefined ? matches[1] : '';
24796                this.pathname = matches[3] !== undefined ? matches[3] : '';
24797            } else {
24798                this.hostname = '';
24799                this.pathname = '';
24800            }
24801        },
24802        getRavenid: function() {
24803            var ravenid = $('.region-data').first().data('ravenid') || $('body').data('ravenid');
24804            return ravenid
24805        },
24806        getTimestamp: function() {
24807            var date = new Date();
24808            var offset = $('body').data('timezone-offset');
24809            // Making sure we don't hit an exception with an undefined value
24810            if (!isNaN(offset)) {
24811                // offset is a negative number, so addition is required
24812                date.setUTCMilliseconds(date.getUTCMilliseconds() + offset);
24813            }
24814            var month = date.getUTCMonth() + 1;
24815            var day = date.getUTCDate();
24816            var year = date.getUTCFullYear();
24817            return year + "/" + month + "/" + day;
24818        }
24819    };
24820    News.adBlocker = News.adBlocker || {
24821        isAdBlockEnabled: function() {
24822            return typeof window.isAdBlockerEnabled === 'undefined';
24823        }
24824    };
24825}(jQuery);
24826+function ($) {
24827
24828    function Megamenu(element, options) {
24829        this.$element = $(element);
24830        this.options = $.extend({}, Megamenu.DEFAULTS, options);
24831        this.$trigger = $('[data-toggle="megamenu"][href="#' + element.id + '"],' +
24832            '[data-toggle="megamenu"][data-target="#' + element.id + '"]');
24833
24834        this.addAriaAndCollapsedClass(this.$element, this.$trigger);
24835    }
24836
24837    Megamenu.OPEN_DURATION = 350;
24838
24839    Megamenu.DEFAULTS = { };
24840
24841    Megamenu.prototype.show = function () {
24842        var startEvent = $.Event('show.news.megamenu');
24843        this.$element.trigger(startEvent);
24844        if (startEvent.isDefaultPrevented()) return;
24845
24846        // Hide other megamenus before showing this one
24847        var megamenuContainerIds = _($('[data-toggle="megamenu"]'))
24848            .map(_.unary(_.partialRight(
24849                $.attr, 'data-target'
24850            )))
24851            .join(',')
24852
24853        _($(megamenuContainerIds).not(this.$element)).each(function(container) {
24854            Plugin.call($(container), 'hide');
24855        });
24856
24857        // Show element and set up event handling
24858        this.$element
24859            .removeClass('collapse')
24860            .addClass('collapse in')
24861            .attr('aria-expanded', true)
24862            .trigger('shown.news.megamenu');
24863
24864        this.$trigger
24865            .removeClass('collapsed')
24866            .attr('aria-expanded', true);
24867
24868        function keepOpen() {
24869            this.closeTimeout && clearTimeout(this.closeTimeout);
24870        }
24871
24872        var keepOpenHandler = $.proxy(keepOpen, this);
24873
24874        var closeHandler = $.proxy(function setCloseTimeout() {
24875            keepOpen.call(this);
24876            this.closeTimeout = setTimeout(this.hide.bind(this), Megamenu.OPEN_DURATION);
24877        }, this);
24878
24879        this.$trigger
24880            .on('mouseout.news.megamenu.data-api', closeHandler)
24881            .on('mouseover.news.megamenu.data-api', keepOpenHandler);
24882
24883        this.$element
24884            .on('mouseout.news.megamenu.data-api', closeHandler)
24885            .on('mouseover.news.megamenu.data-api', keepOpenHandler);
24886
24887        this.$element.trigger('shown.news.megamenu');
24888    }
24889
24890    Megamenu.prototype.hide = function() {
24891         this.$element
24892             .removeClass('collapse in')
24893             .addClass('collapse')
24894             .attr('aria-expanded', false)
24895             .trigger('hidden.news.megamenu');
24896
24897         this.$trigger
24898             .addClass('collapsed')
24899             .attr('aria-expanded', false);
24900
24901         clearTimeout(this.closeTimeout);
24902
24903         this.$element.off('.news.megamenu');
24904         this.$trigger.off('.news.megamenu');
24905    }
24906
24907    Megamenu.prototype.toggle = function() {
24908        var isOpen = this.$element.hasClass('in');
24909        this[isOpen ? 'hide' : 'show']();
24910    }
24911
24912    Megamenu.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
24913        var isOpen = $element.hasClass('in');
24914
24915        $element.attr('aria-expanded', isOpen);
24916        $trigger
24917          .addClass('collapsed', !isOpen)
24918          .attr('aria-expanded', isOpen);
24919      }
24920
24921    function getTargetFromTrigger($trigger) {
24922        var href
24923        var target = $trigger.attr('data-target')
24924          || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
24925
24926        return $(target)
24927    }
24928
24929    function Plugin(option) {
24930        return this.each(function () {
24931            var $this = $(this);
24932            var data = $this.data('news.megamenu');
24933            if (!data) $this.data('news.megamenu', (data = new Megamenu(this)));
24934            data[option]();
24935        })
24936    }
24937
24938    var old = $.fn.megamenu
24939
24940    $.fn.megamenu = Plugin
24941    $.fn.megamenu.Constructor = Megamenu
24942
24943
24944    // MEGAMENU NO CONFLICT
24945    // ====================
24946
24947    $.fn.megamenu.noConflict = function () {
24948        $.fn.megamenu = old
24949        return this
24950    }
24951
24952    $(document).on('click.news.megamenu.data-api', '[data-toggle="megamenu"]', function(e) {
24953        var $this = $(this)
24954
24955        if($this.attr('href')==='#') e.preventDefault();
24956
24957        var $target = getTargetFromTrigger($this);
24958        Plugin.call($target, 'toggle');
24959    })
24960
24961    $(document).on('mouseenter.news.megamenu.data-api', '[data-toggle="megamenu"]', function (e) {
24962        var $this = $(this)
24963
24964        if($this.attr('href')==='#') e.preventDefault();
24965
24966        if(isMobile.any) {
24967            e.preventDefault();
24968            return;
24969        }
24970
24971        var $target = getTargetFromTrigger($this);
24972        Plugin.call($target, 'show');
24973    })
24974}(jQuery);
24975
24976$(function () {
24977    News.region = News.region || {
24978       
24979        ravenApi : $('.redirect').data('ravenapi'),
24980        regionPath:null,
24981         regionName:null,
24982
24983
24984        setCookie: function (name, value) {
24985            Cookies.set(name, value, {expires: 365, path: '/'});
24986        },
24987        cookieFactory: function (path) {
24988            // Getting just the path and prepending /content/news if needed
24989            // ('Private' function)
24990            var getPathname = function (url) {
24991                var pathname = url.pathname;
24992                pathname = pathname.replace('/content/news','');
24993                // regular expression to remove the article path and just take the region path
24994                var path = pathname.match('/([^/]+)(?:/([^/]+))?')
24995                if(path){
24996                    pathname =  path[0] 
24997                }
24998                // Only adding /content/news if it's not already there
24999                if (pathname.indexOf('/content/news') == -1) {
25000                    pathname = '/content/news' + pathname;
25001                }
25002                return pathname
25003            };
25004            path = path.replace(/.html\b/, '');
25005            var url = new News.core.URL(path);
25006            var pathname = getPathname(url);
25007            var newCookieVal = url.hostname + pathname;
25008            return newCookieVal;
25009        },
25010        getRegionCookieVal: function () {
25011            return new Promise( async resolve => {
25012                var locationCookie = Cookies.get('region'),
25013                    languageCode;
25014                if (typeof locationCookie === 'string') {
25015                    if(locationCookie === "/content/news/us/nacional"){
25016                        locationCookie = "/content/news/us/noticias";
25017                        News.region.setCookie('region', locationCookie);
25018                    }
25019
25020                    if(locationCookie === "/content/news/us/national"){
25021                        locationCookie = "/content/news/us/snplus";
25022                        News.region.setCookie('region', locationCookie);
25023                    }
25024                    regionPath = locationCookie
25025                } else {
25026                    languageCode = News.region.getLanguageCode();
25027                    regionPath = await News.region.getRegionPath(languageCode,News.region.ravenApi);
25028                    
25029                    if (regionPath) {
25030                        localStorage.setItem('displayIPRegionalizationModal', 'true');
25031                    }
25032                }
25033
25034                resolve(regionPath === null ? false : regionPath)
25035            })
25036        },
25037        getLanguageCode: function(){
25038            if(window.location.host.includes('spectrumnoticias.com') || window.location.host.includes('spectrumnoticias1.com')){
25039                return 'es';
25040            }else{
25041                if(navigator.language.startsWith('es')){
25042                    return 'es'
25043                }else {
25044                    return 'en'
25045                }
25046            }
25047        },
25048
25049        isRegionalized: function () {
25050            // If the current page has a navigation on it, then it was able to be regionalized
25051            return $('nav').length > 0;
25052        },
25053        // To regionalize articles that don't have region information, this method looks at cookies and canonical links.
25054        getPreferredRegionalization: async function () {
25055            var href = window.location.href;
25056
25057            // When we are not regionalized, find a regionalized URL.
25058            if (!News.region.isRegionalized()) {
25059
25060                var cookieRegion = await News.region.cookieRegionPath();
25061
25062                // If the user has a region cookie, we will use it
25063
25064                if (cookieRegion) {
25065                    // Look for the cookieregion in the path already
25066                    var cookieIdx = window.location.pathname.indexOf(cookieRegion)
25067                    // If href does not already start with the cookie region, then rebuild the URL with the cookie region and the normalized path.
25068
25069                    if (cookieIdx < 0) {
25070                        var pathname = News.region.normalizeArticlePath(window.location.pathname);
25071                        href = window.location.protocol + '//' + window.location.host + cookieRegion + pathname;
25072                    }
25073                }
25074                // Else use the current page canonical link directly
25075                else {
25076                    href = document.querySelector("link[rel='canonical']").getAttribute("href");
25077                }
25078            }
25079            return href;
25080        },
25081        // Function to obtain a region from the user's region cookie
25082        cookieRegionPath: function () {
25083            return new Promise( async resolve => {
25084                let cookieRegion = await News.region.getRegionCookieVal();
25085
25086                // If the user has a region cookie, we will use it
25087                if (cookieRegion) {
25088
25089                    // Locate the start of the content news path
25090                    var regionIdx = cookieRegion.indexOf('/content/news');
25091
25092                    // Use the cookie region as the region, after trimming the beginning
25093
25094                    if (regionIdx == 0) {
25095                        cookieRegion = cookieRegion.substring('/content/news'.length);
25096                    }
25097                }
25098                resolve(cookieRegion);
25099            })
25100        },
25101        // To obtain the minimum length article path from an article path
25102        //   Article Path input may or may not be regionalized. Output is unregionalized.
25103        //    e.g. /nyc/all-boroughs/news/2017/12/11/test
25104        //    e.g. /news/2017/12/11/myArticle
25105        //    e.g. /nyc/dne/crime/2018/02/28/balloon-heist
25106        normalizeArticlePath: function (path) {
25107
25108            var re = /(\/[^\/]+)+(\/\d{4}\/\d{1,2}\/\d{1,2}){1}\/(\S([^\.]+)*)/
25109            var matches = path.match(re)
25110            if (matches && matches.length > 3) {
25111                return matches[1] + matches[2] + "/" + matches[3]
25112            } else {
25113                return path
25114            }
25115        },
25116
25117        // Highlight all service area states
25118        highlightServiceAreas: function () {
25119            jQuery('div .state').each(function () {
25120                var stateId = this.getAttribute('data-state-id');
25121                $('#' + stateId).attr('class', 'state__icon-highlighted');
25122            });
25123        },
25124
25125        //When list is selected, highlight that state and remove all other highlighting
25126     highlightSelectedState: function (stateId) {
25127            // Remove all selections
25128            $('svg .state__icon-selected').removeClass('state__icon-selected').addClass('state__icon-highlighted');
25129    // Highlight the selected one
25130    var $state = document.getElementById(stateId);
25131    if ($state) {
25132                $($state).removeClass('state__icon-highlighted').addClass('state__icon-selected');
25133    }
25134    },
25135
25136        getRegionPath: function (languageCode,ravenApi) {
25137            return new Promise(async (resolve) => {
25138            let regionAPIPath;
25139            regionAPIPath = ravenApi +'/v1/regionalization/paths?lang='+ languageCode;
25140           
25141            $.ajax({
25142                type: 'GET',
25143                url: regionAPIPath,
25144                contentType: "application/json",
25145                success: function (data) {
25146                    let paths = data.paths;
25147                    let enLevel,enPath;
25148                    if(languageCode === "es"){
25149                        $.each(paths, function (i, e) {
25150                            if(e.language === "en" && e.consumer === "web"){
25151                                enLevel = e.level;
25152                                if(e.path === "/us/national"){
25153                                    e.path = "/us/snplus";
25154                                }
25155                                enPath = e.path;
25156                            }
25157                        })
25158                    }
25159                   
25160                    $.each(paths, function (i, e) {
25161 
25162                        if(languageCode === "en"){
25163                            News.region.setCookie("ipSourceSelectionModalDefaultLang", 'en'); // save language and use it for rendring the ip-reg 2nd modal
25164                            if (e.language === "en" && e.consumer === "web") {
25165                                News.region.regionName = e.ravenDisplayName;
25166                                if(e.path === "/us/national"){
25167                                    e.path = "/us/snplus";
25168                                }
25169                                News.region.regionPath = e.path;
25170                            }
25171                            if(e.language === "sp" && e.consumer === "web"){
25172                                let redirectCookiePath = null;
25173                                News.region.setCookie('redirectRegionName', e.ravenDisplayName)
25174                                if(e.path){
25175                                    if(e.path === "/us/nacional"){
25176                                        e.path = "/us/noticias";
25177                                    }
25178                                    redirectCookiePath = News.region.cookieFactory(e.path)
25179                                }
25180                                News.region.setCookie("redirectRegionPath", redirectCookiePath)
25181                                // consider sp web path and save it in redirectCookie and use this cookie while calling 'services/api/region/onboarding?pagePath=/'
25182                            }
25183                        }
25184                        if(languageCode === "es"){
25185                            News.region.setCookie("ipSourceSelectionModalDefaultLang", 'es');
25186                            
25187                            if (e.language === "sp" && e.consumer === "web") {
25188                                if(e.level === "NATIONAL" && enLevel !== "NATIONAL" && !(window.location.host.includes('spectrumnoticias.com'))){ 
25189                                    News.region.regionName = e.ravenDisplayName;
25190                                    News.region.regionPath = enPath;
25191                                    News.region.setCookie("ipSourceSelectionModalDefaultLang", 'en');
25192                                    let redirectCookiePath = null;
25193                                    if(e.path){
25194                                        if(e.path === "/us/nacional"){
25195                                            e.path = "/us/noticias";
25196                                        }
25197                                        redirectCookiePath = News.region.cookieFactory(e.path);
25198                                        News.region.setCookie("redirectRegionPath", redirectCookiePath);
25199                                        News.region.setCookie('redirectRegionName', e.ravenDisplayName)
25200                                    }
25201                                    return false;
25202                                }else{
25203                                    News.region.regionName = e.ravenDisplayName;
25204                                    if(e.path === "/us/nacional"){
25205                                            e.path = "/us/noticias";
25206                                    }
25207                                    News.region.regionPath = e.path;
25208                                }
25209                            }
25210                            if(e.language === "en" && e.consumer === "web"){
25211                                let redirectCookiePath = null
25212                                if(e.path){
25213                                    if(e.path === "/us/national"){
25214                                        e.path = "/us/snplus";
25215                                    }
25216                                    redirectCookiePath = News.region.cookieFactory(e.path)
25217                                }
25218                                News.region.setCookie("redirectRegionPath", redirectCookiePath);
25219                                News.region.setCookie('redirectRegionName', e.ravenDisplayName)
25220                            }
25221                        }
25222                    })
25223                    
25224                    if (News.region.regionPath) {
25225                        News.region.regionPath = News.region.cookieFactory(News.region.regionPath)
25226                        News.region.setCookie('region', News.region.regionPath);
25227                        News.region.setCookie('regionName', News.region.regionName)
25228                    }
25229                    resolve(News.region.regionPath);
25230                },
25231                error: function (errResp) {
25232                    console.error("Error in Regionalization API " + JSON.stringify(errResp))
25233                    resolve(News.region.regionPath);
25234                }
25235            })
25236            })
25237        },
25238
25239        removeHighlighting: function () {
25240            jQuery('div .state').each(function () {
25241                var stateId = this.getAttribute('data-state-id'),
25242                    $state = document.getElementById(stateId),
25243                    classList = $state.getAttribute('class');
25244                classList = classList.replace('state__icon-highlighted', '');
25245                $state.setAttribute('class', classList);
25246            });
25247        }
25248    };
25249
25250    // --- Utility: Debounce to prevent rapid-fire clicks ---
25251    function debounce(func, wait) {
25252        let timeout;
25253        return function (...args) {
25254            clearTimeout(timeout);
25255            timeout = setTimeout(() => func.apply(this, args), wait);
25256        };
25257    }
25258
25259    // --- COLLAPSE EVENTS ---
25260
25261    // Only allow one region list open at a time
25262    $('.region-selection__list').on('show.bs.collapse', '.collapse', function () {
25263            $('.region-selection__list').find('.collapse.in').each(function () {
25264                $(this).collapse('hide'); //close all other open lists
25265            });
25266        });
25267
25268    // Highlight the state when its panel is fully shown
25269    $('.region-selection__list').on('shown.bs.collapse', '.collapse', function () {
25270        var stateId = $(this).parent().attr('data-state-id');
25271        News.region.highlightSelectedState(stateId);
25272    });
25273
25274    // If all panels are closed, highlight all service areas
25275    $('.region-selection__list').on('hidden.bs.collapse', '.collapse', function () {
25276        if ($('.panel-collapse.in').length === 0) {
25277             News.region.highlightServiceAreas();
25278        }
25279    });
25280          
25281    // --- PANEL HEADING CLICK ---
25282
25283    // Use debounce to prevent race conditions on rapid clicks
25284    $('.panel-heading').click(debounce(function () {
25285    var stateId = $(this).attr('data-state-id');
25286        if (!stateId) return;
25287        // The highlighting is handled in the shown.bs.collapse event above
25288    }, 100)); // 100ms debounce
25289
25290    // --- MAP CLICK ---
25291
25292    // When a state on the map is clicked, select and highlight it
25293    $(".region-selection__map path").click(function (event) {
25294        if (!$(event.target).hasClass('state__icon-highlighted')) {
25295            return;
25296        }
25297        // Remove all selections
25298        $('svg .state__icon-selected').removeClass('state__icon-selected').addClass('state__icon-highlighted');
25299        var state = event.target.id;
25300        // Close all panels
25301        $('.region-selection__list').find('.collapse.in').each(function () {
25302            $(this).parent().find('.panel-title').attr('aria-expanded', 'false');
25303            $(this).removeClass('in').attr('style', 'height: 0px;');
25304            //remove selection from previous state
25305            News.region.highlightSelectedState(this.parentElement.getAttribute('data-state-id'));
25306        });
25307        // Highlight the selected state
25308        News.region.highlightSelectedState(state);
25309        // Open the relevant panel and update UI
25310        $('div .state').each(function () {
25311            var statePath = this.getAttribute('data-state-path').toLowerCase();
25312            var stateId = this.getAttribute('data-state-id');
25313            if (stateId.toLowerCase() === state.toLowerCase() || statePath.indexOf(state.toLowerCase()) != -1) {
25314                $('#' + stateId).removeClass('state__icon-highlighted').addClass('state__icon-selected');
25315                $(this).find('.panel-title').attr('aria-expanded', 'true');
25316                $(this).find('.panel-collapse').addClass('in').attr('style', '');
25317                //$(this).find('.panel-collapse').addClass('in');
25318            } else {
25319                if ($('#' + stateId).is('.state__icon-selected')) {
25320                    $('#' + stateId).removeClass('state__icon-selected').addClass('state__icon-highlighted');
25321                }
25322            }
25323        });
25324        // If nothing is selected, highlight all service areas
25325        if ($('.state__icon-selected').length == 0) {
25326            News.region.highlightServiceAreas();
25327        }
25328    });
25329
25330    // --- REGION SELECTION FROM SPLASH PAGE ---
25331
25332    // When a region is selected from the splash page, set cookie and redirect
25333    $('.region-selection .panel-body a').each(function () {
25334
25335        $(this).on('click', function (e) {
25336           e.preventDefault();
25337            // NEWS-7819 Adobe Analytics locationSelect event
25338            let originalHref = $(this).attr('href');
25339            let locationName = $(this).text().trim();
25340            let region = $(this).parents('.panel-collapse').siblings('.panel-title').text().trim();
25341
25342            let eventPayload = {
25343                    action: "locationSelect",
25344                    actionPageName: "Splash",
25345                    newsMarket: region.includes('National') || region.includes('Nationwide') ? 'U.S.' : locationName,
25346                    selectedLocation: locationName + ', ' + region,
25347                    selectedNewsLocation: originalHref
25348            }
25349            console.log('locationSelect', eventPayload);
25350            window._satellite && window._satellite.track('trackAction', eventPayload);
25351
25352            // // determine if we'll handle a redirect according to selectors in the URL
25353            // var willRedirect = false;
25354            // var indexOfDotInPathname = window.location.pathname.indexOf('.');
25355            // if (indexOfDotInPathname > -1) {
25356            //     willRedirect = true;
25357            //     e.preventDefault();
25358            // }
25359            let regionPath = News.region.cookieFactory($(this).attr('href'))
25360            regionPath = regionPath.split('?')[0];
25361
25362            News.region.setCookie('region', regionPath);
25363
25364            // // early return if no redirect will occur
25365            // if (!willRedirect) {
25366            //     return;
25367            // }
25368
25369            // // redirect based on selectors
25370            // var selectorString = window.location.pathname.substring(indexOfDotInPathname) + window.location.search;
25371            // var newLocation = selectorString.replace('.', '/');
25372            if ($(this).attr('target') === '_blank') {
25373                window.open($(this).attr('href'), '_blank');
25374            } else {
25375                window.location = $(this).attr('href');
25376            }
25377        });
25378    });
25379    var state = window.location.hash.substr(1);
25380    if (state) {
25381        jQuery('div .state').each(function () {
25382            var statePath = this.getAttribute('data-state-path');
25383            var stateId = this.getAttribute('data-state-id');
25384            if (stateId && stateId.toLowerCase() === state.toLowerCase() || state.toLowerCase().indexOf(statePath) != -1) {
25385                $('#' + stateId).removeClass('state__icon-highlighted').addClass('state__icon-selected');
25386                $(this).find('.panel-title').attr('aria-expanded', 'true');
25387                $(this).find('.panel-collapse').addClass('in');
25388            } else {
25389                if (!$('#' + stateId).is('.state__icon-selected')) {
25390                    $('#' + stateId).removeClass('state__icon-selected').removeClass('state__icon-highlighted');
25391                }
25392            }
25393        });
25394    } else {
25395        News.region.highlightServiceAreas();
25396    }
25397});
25398+function ($) {
25399    $('.navbar .follow-button').hover(function(){
25400        var gridFloatBreakpoint = 1200;
25401
25402        //If on desktop view, position Header Social Icon Container below Follow Button
25403        if(window.innerWidth > gridFloatBreakpoint){
25404            $('.header-social-container').css({
25405                top: $('.follow-button').position().top + 65,
25406                left: $('.follow-button').position().left - 150,
25407            });
25408        }
25409        //If not on desktop view, reset position of Header Social Icon Container
25410        else {
25411            $('.header-social-container').css({
25412                top: 0, left: 0,
25413            });
25414        }
25415    });
25416}(jQuery);
25417
25418;(function ($) {
25419
25420    /* Relative Time jQuery Plugin
25421     *
25422     * On page load, queries for ".relative-time" elements and displays the date/time in the `data-time` property as
25423     * a relative time from now. ("3 minutes ago", "9 days ago", etc.)
25424     *
25425     * Currently only accepts the date format from java.util.Date#toString() (see https://goo.gl/dm0H7Y).
25426     *
25427     * This plugin depends on humanize-duration (http://evanhahn.github.io/HumanizeDuration.js/) being loaded beforehand.
25428     */
25429
25430    function RelativeTime(element /*, options */) {
25431        this.$element = $(element);
25432    }
25433
25434    RelativeTime.prototype.render = function render() {
25435
25436        var time = this.$element.data('time');
25437
25438        if (!time) {
25439            return;
25440        }
25441
25442        var duration = Date.now() - time;
25443        
25444        if (duration < 3600000) {
25445            //adds data-recent attribute in order to decorate via CSS
25446            this.$element.attr('data-recent','true');
25447        }
25448
25449        var duration = Date.now() - time,
25450            language = $('html').attr('lang'),
25451            text = humanizeDuration(duration, { largest: 1 , language: language, ago: true}); // get relative time text (1 week, etc)
25452        this.$element.text(text);
25453    }
25454
25455    function Plugin(/* option */) {
25456        return this.each(function () {
25457            var $this = $(this),
25458                data = $this.data('news.relativeTime');
25459
25460            if (!data) $this.data('news.relativeTime', (data = new RelativeTime(this)));
25461            data.render();
25462        })
25463    }
25464
25465    var old = $.fn.relativeTime;
25466
25467    $.fn.relativeTime = Plugin;
25468    $.fn.relativeTime.Constructor = RelativeTime;
25469
25470    // RELATIVE TIME NO CONFLICT
25471    // ====================
25472
25473    $.fn.relativeTime.noConflict = function () {
25474        $.fn.relativeTime = old
25475        return this
25476    }
25477
25478    // RELATIVE TIME DATA-API
25479    // ====================
25480    $(document).ready(function () {
25481        $('.relative-time, .article__relative-time').each(function () {
25482            Plugin.call($(this));
25483        });
25484    });
25485
25486    // call plugin on articles added after initial page load
25487    $(window).on('article-append', function(e) {
25488        $(e.target).find('.relative-time, .article__relative-time').each(function() {
25489            Plugin.call($(this));
25490        });
25491    })
25492
25493}(jQuery));
25494
25495/* Tests whether a URL in an article matches our format for other article urls */
25496
25497function isArticleUrl (url) {
25498    // Requires format: /state/loc/vertical/yyyy/mm/dd
25499    const articleRE = /(\/([^\/]*)){3}(\/\d{4}\/(\d{1,2})\/(\d{1,2})\/)/;
25500    var m = void 0;
25501
25502    if (m = articleRE.exec(url) !== null) {
25503        return true;
25504    }
25505    return false;
25506}
25507
25508;(function ($) {
25509    var regionRegex = /(\/[^\/\.]+){2}/;
25510    var locURL = location.pathname;
25511    var m = void 0;
25512    var locationRegion = null;
25513    if ((m = regionRegex.exec(locURL)) !== null) {
25514        locationRegion = m[0];
25515    }
25516    $.fn.regionalizeURL = function () {
25517        $(this).filter(function (locationRegion) {
25518                    return $(this).prop('href').indexOf(location.origin) === 0;
25519             }).each(function(index, el){
25520                    try {
25521                        var linkURL = new URL($(el).prop("href"));
25522                        var m = void 0;
25523                        var href = $(el).attr("href");
25524                        if ((m = regionRegex.exec(linkURL)) !== null) {
25525                            $(el).attr("href", href.replace(/(\/[^\/]+){2}/, locationRegion));
25526                        }
25527                    } catch (err) {
25528                    }
25529                    return this;
25530            });
25531    };
25532})(jQuery);
25533
25534$(document).ready(function () {
25535    $('.content-list-layout a,.wxAlertBar a').filter(function (locationRegion) {
25536        // Filter links to ensure:
25537        // the link is relative 
25538        // the link is not on a view more button.
25539        //   Note: .attr can detect relative links, .prop can not
25540
25541        return $(this).attr('href') &&
25542               $(this).attr('href').indexOf('/') === 0 && 
25543               $(this).closest("a[class*='view-more']").length === 0;
25544    }).regionalizeURL();
25545    // For article-body links, apply an additional filter to determine if the URL is to an article or not
25546    $('.article-body a').filter(function(){
25547        return isArticleUrl($(this).attr('href'))
25548    }).filter(function (locationRegion) {
25549        // Filter links to ensure:
25550        // the link is relative 
25551        // the link is not on a view more button.
25552        //   Note: .attr can detect relative links, .prop can not
25553
25554        return $(this).attr('href') &&
25555               $(this).attr('href').indexOf('/') === 0 && 
25556               $(this).closest("a[class*='view-more']").length === 0;
25557    }).regionalizeURL();
25558
25559    // call plugin on articles added after initial page load
25560    $(window).on('article-append', function(e) {
25561        if(document.querySelector('.site-header')){
25562            $(e.target).find('a').regionalizeURL();
25563        }
25564    })
25565
25566});
25567
25568/*
25569 * Looks for inline CSS divs and appends them to the head.
25570 */
25571+function($) {
25572    $("div[data-clientlibsource]").each(function(){
25573        var cssClientLibSrc = $(this).attr("data-clientlibsource");
25574        $('head').append('<link rel="stylesheet" href="' + cssClientLibSrc + '" type="text/css" />');
25575        $(this).remove();
25576    });
25577}(jQuery);
25578
25579"use strict";
25580$(function() {
25581
25582    if (! isMobile.any) {
25583        var href = $('#login-button').attr('href');
25584        var loginText = $('#login-button').text();
25585
25586        $('#spectrumSignup .signup-title').html($('.signup-title').data('logintitle'));
25587        $('#spectrumSignup .signup-body').html($('.signup-body').data('logintext'));
25588        $('#spectrumSignup .signupButton a').html($('.signupButton').data('buttontext'));
25589        $('#spectrumSignup .loginwrapper a').attr('href', href);
25590        $('#spectrumSignup .loginwrapper a').html(loginText);
25591    }
25592    else {
25593        var url;
25594        if(isMobile.apple.device) {
25595            url = $('.signupButton').data('app-store-url') || 'https://itunes.apple.com/us/app/twc-news/id740948885?ls=1&mt=8';
25596        }  
25597        else {
25598            url = $('.signupButton').data('play-store-url') || 'https://play.google.com/store/apps/details?id=com.twcable.twcnews';
25599        }
25600        
25601        $('#spectrumSignup .signupButton a').attr('href', url);
25602    }
25603
25604});
25605/**
25606 * CSS hides flair when div empty via :empty pseudo class
25607 * applyFlair() checks off time and places flair-text in div.
25608 *
25609 * @param $
25610 * @returns {Object} this
25611 */
25612+(function ($) {
25613    $(document).ready(function () {
25614        $('.flair').applyFlair();
25615    });
25616
25617    // Apply flair on articles added after initial page load
25618    $(window).on('article-append', function(e) {
25619        $(e.target).find('.flair').applyFlair();
25620    })
25621
25622    $.fn.applyFlair = function () {
25623        var currentUTC  = new Date().getTime();
25624
25625        $(this).each(function (index, element) {
25626            var offTime   = $(element).data("flair-off-time") || 0,
25627                flairText = $(element).data("flair-text") || "";
25628
25629            if ((offTime === 0 || (currentUTC < offTime)) && flairText.length > 0) {
25630                if ($(element).css('display') == 'none') {
25631                    // if element was hidden by this function on first run, unhide it
25632                    $(element).show();
25633                }
25634                $(element).text(flairText);
25635            } else {
25636                $(element).hide();
25637            }
25638        });
25639        return this;
25640    }
25641})(jQuery);
25642"use strict";
25643$(function() {
25644      // This function is needed for backward compatibility and may be removed in the future
25645    $('span._rte_replace_tag').each(function(){
25646        var tmpTag = this.innerText.replace("<_", "<"),
25647        _html = $.parseHTML(tmpTag, true),
25648		_tag = document.createElement(_html[0].tagName),
25649		_attrs = _html[0].attributes;
25650        if(_attrs){
25651        	for(var i = _attrs.length - 1; i >= 0; i--){
25652            	_tag.setAttribute(_attrs[i].name, _attrs[i].value);
25653            }
25654        }
25655
25656        $('body').append(_tag);
25657        this.parentNode.removeChild(this);
25658    });
25659
25660    $('.embedcode iframe:not([id*="twitter"])').each(function(){
25661        var element = this,
25662        instagramRegEx = /(http(s)?:)?\/\/.*instagram.*/,
25663        facebookPostRegEx = /(http(s)?:)?\/\/.*facebook.com\/plugins\/post.php*/,
25664        threadsRegEx = /(http(s)?:)?\/\/.*threads.*/,
25665        truthSocialRegEx = /(http(s)?:)?\/\/.*truthsocial.com\/.*/,
25666        infogramRegEx = /(http(s)?:)?\/\/.*infogram.com\/.*/;
25667
25668        if(facebookPostRegEx.test(element.src) == true && element.parentNode.nodeName == 'CENTER'){
25669            element.style.minWidth='unset';
25670            element.style.width = element.width+'px';
25671        }
25672
25673        //  Don't do anything for Instagram, FB, or Infogram
25674        if (instagramRegEx.test(element.src) == true) return;
25675        else if (threadsRegEx.test(element.src) == true) return;
25676        else if (truthSocialRegEx.test(element.src) == true) return;
25677        else if (facebookPostRegEx.test(element.src) == true) return;
25678        else if (infogramRegEx.test(element.src) == true) return;
25679
25680        //If height/width is already 100%, skip setting manually.
25681        if(element.width == '100%' || element.height == '100%'){
25682            return;
25683        }
25684        var parentCss = "",
25685            cssText = 'height: 100%;';
25686
25687            var ratio = ((element.height/element.width)*100).toPrecision(4) + '%;';
25688            parentCss += "height:0;padding-bottom:" + ratio;
25689            if(element.src.includes('youtube')){
25690                parentCss = parentCss+'clear:both;'
25691            }
25692            cssText += 'position:absolute;';
25693
25694        element.style.cssText += cssText;
25695        element.parentNode.style.cssText += parentCss;
25696
25697    });
25698});
25699
25700/** @license Hyphenator 5.3.0 - client side hyphenation for webbrowsers
25701 *  Copyright (C) 2017  Mathias Nater, Zürich (mathiasnater at gmail dot com)
25702 *  https://github.com/mnater/Hyphenator
25703 *
25704 *  Released under the MIT license
25705 *  http://mnater.github.io/Hyphenator/LICENSE.txt
25706 */
25707
25708/*
25709 * Comments are jsdoc3 formatted. See http://usejsdoc.org
25710 * Use mergeAndPack.html to get rid of the comments and to reduce the file size of this script!
25711 */
25712
25713/* The following comment is for JSLint: */
25714/*jslint browser: true, multivar: true, eval: true*/
25715/*global Hyphenator window*/
25716
25717/**
25718 * @desc Provides all functionality to do hyphenation, except the patterns that are loaded externally
25719 * @global
25720 * @namespace Hyphenator
25721 * @author Mathias Nater, <[email protected]>
25722 * @version 5.3.0
25723 * @example
25724 * &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
25725 * &lt;script type = "text/javascript"&gt;
25726 *   Hyphenator.run();
25727 * &lt;/script&gt;
25728 */
25729var Hyphenator;
25730Hyphenator = (function (window) {
25731    "use strict";
25732
25733    /**
25734     * @member Hyphenator~contextWindow
25735     * @access private
25736     * @desc
25737     * contextWindow stores the window for the actual document to be hyphenated.
25738     * If there are frames this will change.
25739     * So use contextWindow instead of window!
25740     */
25741    var contextWindow = window;
25742
25743
25744    /**
25745     * @member {Object.<string, Hyphenator~supportedLangs~supportedLanguage>} Hyphenator~supportedLangs
25746     * @desc
25747     * A generated key-value object that stores supported languages and meta data.
25748     * The key is the {@link http://tools.ietf.org/rfc/bcp/bcp47.txt bcp47} code of the language and the value
25749     * is an object of type {@link Hyphenator~supportedLangs~supportedLanguage}
25750     * @namespace Hyphenator~supportedLangs
25751     * @access private
25752     * //Check if language lang is supported:
25753     * if (supportedLangs.hasOwnProperty(lang))
25754     */
25755    var supportedLangs = (function () {
25756        /**
25757         * @typedef {Object} Hyphenator~supportedLangs~supportedLanguage
25758         * @property {string} file - The name of the pattern file
25759         * @property {number} script - The script type of the language (e.g. "latin" for english), this type is abbreviated by an id
25760         * @property {string} prompt - The sentence prompted to the user, if Hyphenator.js doesn"t find a language hint
25761         */
25762
25763        /**
25764         * @lends Hyphenator~supportedLangs
25765         */
25766        var r = {},
25767            /**
25768             * @method Hyphenator~supportedLangs~o
25769             * @desc
25770             * Sets a value of Hyphenator~supportedLangs
25771             * @access protected
25772             * @param {string} code The {@link http://tools.ietf.org/rfc/bcp/bcp47.txt bcp47} code of the language
25773             * @param {string} file The name of the pattern file
25774             * @param {Number} script A shortcut for a specific script: latin:0, cyrillic: 1, arabic: 2, armenian:3, bengali: 4, devangari: 5, greek: 6
25775             * gujarati: 7, kannada: 8, lao: 9, malayalam: 10, oriya: 11, persian: 12, punjabi: 13, tamil: 14, telugu: 15, georgian: 16
25776             * @param {string} prompt The sentence prompted to the user, if Hyphenator.js doesn"t find a language hint
25777             */
25778            o = function (code, file, script, prompt) {
25779                r[code] = {"file": file, "script": script, "prompt": prompt};
25780            };
25781
25782        o("be", "be.js", 1, "Мова гэтага сайта не можа быць вызначаны аўтаматычна. Калі ласка пакажыце мову:");
25783        o("ca", "ca.js", 0, "");
25784        o("cs", "cs.js", 0, "Jazyk této internetové stránky nebyl automaticky rozpoznán. Určete prosím její jazyk:");
25785        o("cu", "cu.js", 1, "Ꙗ҆зы́къ сегѡ̀ са́йта не мо́жетъ ѡ҆предѣле́нъ бы́ти. Прошꙋ́ тѧ ᲂу҆каза́ти ꙗ҆зы́къ:");
25786        o("da", "da.js", 0, "Denne websides sprog kunne ikke bestemmes. Angiv venligst sprog:");
25787        o("bn", "bn.js", 4, "");
25788        o("de", "de.js", 0, "Die Sprache dieser Webseite konnte nicht automatisch bestimmt werden. Bitte Sprache angeben:");
25789        o("el", "el-monoton.js", 6, "");
25790        o("el-monoton", "el-monoton.js", 6, "");
25791        o("el-polyton", "el-polyton.js", 6, "");
25792        o("en", "en-us.js", 0, "The language of this website could not be determined automatically. Please indicate the main language:");
25793        o("en-gb", "en-gb.js", 0, "The language of this website could not be determined automatically. Please indicate the main language:");
25794        o("en-us", "en-us.js", 0, "The language of this website could not be determined automatically. Please indicate the main language:");
25795        o("eo", "eo.js", 0, "La lingvo de ĉi tiu retpaĝo ne rekoneblas aŭtomate. Bonvolu indiki ĝian ĉeflingvon:");
25796        o("es", "es.js", 0, "El idioma del sitio no pudo determinarse autom%E1ticamente. Por favor, indique el idioma principal:");
25797        o("et", "et.js", 0, "Veebilehe keele tuvastamine ebaõnnestus, palun valige kasutatud keel:");
25798        o("fi", "fi.js", 0, "Sivun kielt%E4 ei tunnistettu automaattisesti. M%E4%E4rit%E4 sivun p%E4%E4kieli:");
25799        o("fr", "fr.js", 0, "La langue de ce site n%u2019a pas pu %EAtre d%E9termin%E9e automatiquement. Veuillez indiquer une langue, s.v.p.%A0:");
25800        o("ga", "ga.js", 0, "Níorbh fhéidir teanga an tsuímh a fháil go huathoibríoch. Cuir isteach príomhtheanga an tsuímh:");
25801        o("grc", "grc.js", 6, "");
25802        o("gu", "gu.js", 7, "");
25803        o("hi", "hi.js", 5, "");
25804        o("hu", "hu.js", 0, "A weboldal nyelvét nem sikerült automatikusan megállapítani. Kérem adja meg a nyelvet:");
25805        o("hy", "hy.js", 3, "Չհաջողվեց հայտնաբերել Õ¡Õ
25805µÕ½ կայքի լեզուն։ Խնդրում ենք նշեք Õ°Õ«Õ´Õ¶Õ¡Õ¯Õ¡Õ¶ լեզուն՝");
25806        o("it", "it.js", 0, "Lingua del sito sconosciuta. Indicare una lingua, per favore:");
25807        o("ka", "ka.js", 16, "");
25808        o("kn", "kn.js", 8, "ಜಾಲ ತಾಣದ ಭಾಷೆಯನ್ನು ನಿರ್ಧರಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ. ದಯವಿಟ್ಟು ಮುಖ್ಯ ಭಾಷೆಯನ್ನು ಸೂಚಿಸಿ:");
25809        o("la", "la.js", 0, "");
25810        o("lt", "lt.js", 0, "Nepavyko automatiškai nustatyti šios svetainės kalbos. Prašome įvesti kalbą:");
25811        o("lv", "lv.js", 0, "Šīs lapas valodu nevarēja noteikt automātiski. Lūdzu norādiet pamata valodu:");
25812        o("ml", "ml.js", 10, "ഈ വെ%u0D2C%u0D4D%u200Cസൈറ്റിന്റെ ഭാഷ കണ്ടുപിടിയ്ക്കാ%u0D28%u0D4D%u200D കഴിഞ്ഞില്ല. ഭാഷ ഏതാണെന്നു തിരഞ്ഞെടുക്കുക:");
25813        o("nb", "nb-no.js", 0, "Nettstedets språk kunne ikke finnes automatisk. Vennligst oppgi språk:");
25814        o("no", "nb-no.js", 0, "Nettstedets språk kunne ikke finnes automatisk. Vennligst oppgi språk:");
25815        o("nb-no", "nb-no.js", 0, "Nettstedets språk kunne ikke finnes automatisk. Vennligst oppgi språk:");
25816        o("nl", "nl.js", 0, "De taal van deze website kan niet automatisch worden bepaald. Geef de hoofdtaal op:");
25817        o("or", "or.js", 11, "");
25818        o("pa", "pa.js", 13, "");
25819        o("pl", "pl.js", 0, "Języka tej strony nie można ustalić automatycznie. Proszę wskazać język:");
25820        o("pt", "pt.js", 0, "A língua deste site não pôde ser determinada automaticamente. Por favor indique a língua principal:");
25821        o("ru", "ru.js", 1, "Язык этого сайта не может быть определен автоматически. Пожалуйста укажите язык:");
25822        o("sk", "sk.js", 0, "");
25823        o("sl", "sl.js", 0, "Jezika te spletne strani ni bilo mogoče samodejno določiti. Prosim navedite jezik:");
25824        o("sr-cyrl", "sr-cyrl.js", 1, "Језик овог сајта није детектован аутоматски. Молим вас наведите језик:");
25825        o("sr-latn", "sr-latn.js", 0, "Jezika te spletne strani ni bilo mogoče samodejno določiti. Prosim navedite jezik:");
25826        o("sv", "sv.js", 0, "Spr%E5ket p%E5 den h%E4r webbplatsen kunde inte avg%F6ras automatiskt. V%E4nligen ange:");
25827        o("ta", "ta.js", 14, "");
25828        o("te", "te.js", 15, "");
25829        o("tr", "tr.js", 0, "Bu web sitesinin dili otomatik olarak tespit edilememiştir. Lütfen dökümanın dilini seçiniz%A0:");
25830        o("uk", "uk.js", 1, "Мова цього веб-сайту не може бути визначена автоматично. Будь ласка, вкажіть головну мову:");
25831        o("ro", "ro.js", 0, "Limba acestui sit nu a putut fi determinată automat. Alege limba principală:");
25832
25833        return r;
25834    }());
25835
25836
25837
25838    /**
25839     * @member {Object} Hyphenator~locality
25840     * @desc
25841     * An object storing isBookmarklet, basePath and isLocal
25842     * @access private
25843     * @see {@link Hyphenator~loadPatterns}
25844     */
25845    var locality = (function getLocality() {
25846        var r = {
25847            isBookmarklet: false,
25848            basePath: "//mnater.github.io/Hyphenator/",
25849            isLocal: false
25850        };
25851        var fullPath;
25852        function getBasePath(path) {
25853            if (!path) {
25854                return r.basePath;
25855            }
25856            return path.substring(0, path.lastIndexOf("/") + 1);
25857        }
25858        function findCurrentScript() {
25859            var scripts = contextWindow.document.getElementsByTagName("script");
25860            var num = scripts.length - 1;
25861            var currScript;
25862            var src;
25863            while (num >= 0) {
25864                currScript = scripts[num];
25865                if ((currScript.src || currScript.hasAttribute("src")) && currScript.src.indexOf("Hyphenator") !== -1) {
25866                    src = currScript.src;
25867                    break;
25868                }
25869                num -= 1;
25870            }
25871            return src;
25872        }
25873        if (!!document.currentScript) {
25874            fullPath = document.currentScript.src;
25875        } else {
25876            fullPath = findCurrentScript();
25877        }
25878        r.basePath = getBasePath(fullPath);
25879        if (fullPath && fullPath.indexOf("bm=true") !== -1) {
25880            r.isBookmarklet = true;
25881        }
25882        if (window.location.href.indexOf(r.basePath) !== -1) {
25883            r.isLocal = true;
25884        }
25885        return r;
25886    }());
25887
25888    /**
25889     * @member {string} Hyphenator~basePath
25890     * @desc
25891     * A string storing the basepath from where Hyphenator.js was loaded.
25892     * This is used to load the pattern files.
25893     * The basepath is determined dynamically in getLocality by searching all script-tags for Hyphenator.js
25894     * If the path cannot be determined {@link http://mnater.github.io/Hyphenator/} is used as fallback.
25895     * @access private
25896     * @see {@link Hyphenator~loadPatterns}
25897     */
25898    var basePath = locality.basePath;
25899
25900    /**
25901     * @member {boolean} Hyphenator~isLocal
25902     * @access private
25903     * @desc
25904     * This is computed by getLocality.
25905     * isLocal is true, if Hyphenator is loaded from the same domain, as the webpage, but false, if
25906     * it"s loaded from an external source (i.e. directly from github)
25907     */
25908    var isLocal = locality.isLocal;
25909
25910    /**
25911     * @member {boolean} Hyphenator~documentLoaded
25912     * @access private
25913     * @desc
25914     * documentLoaded is true, when the DOM has been loaded. This is set by {@link Hyphenator~runWhenLoaded}
25915     */
25916    var documentLoaded = false;
25917
25918    /**
25919     * @member {boolean} Hyphenator~persistentConfig
25920     * @access private
25921     * @desc
25922     * if persistentConfig is set to true (defaults to false), config options and the state of the
25923     * toggleBox are stored in DOM-storage (according to the storage-setting). So they haven"t to be
25924     * set for each page.
25925     * @default false
25926     * @see {@link Hyphenator.config}
25927     */
25928    var persistentConfig = false;
25929
25930    /**
25931     * @member {boolean} Hyphenator~doFrames
25932     * @access private
25933     * @desc
25934     * switch to control if frames/iframes should be hyphenated, too.
25935     * defaults to false (frames are a bag of hurt!)
25936     * @default false
25937     * @see {@link Hyphenator.config}
25938     */
25939    var doFrames = false;
25940
25941    /**
25942     * @member {Object.<string,boolean>} Hyphenator~dontHyphenate
25943     * @desc
25944     * A key-value object containing all html-tags whose content should not be hyphenated
25945     * @access private
25946     */
25947    var dontHyphenate = {"video": true, "audio": true, "script": true, "code": true, "pre": true, "img": true, "br": true, "samp": true, "kbd": true, "var": true, "abbr": true, "acronym": true, "sub": true, "sup": true, "button": true, "option": true, "label": true, "textarea": true, "input": true, "math": true, "svg": true, "style": true};
25948
25949    /**
25950     * @member {boolean} Hyphenator~enableCache
25951     * @desc
25952     * A variable to set if caching is enabled or not
25953     * @default true
25954     * @access private
25955     * @see {@link Hyphenator.config}
25956     */
25957    var enableCache = true;
25958
25959    /**
25960     * @member {string} Hyphenator~storageType
25961     * @desc
25962     * A variable to define what html5-DOM-Storage-Method is used ("none", "local" or "session")
25963     * @default "local"
25964     * @access private
25965     * @see {@link Hyphenator.config}
25966     */
25967    var storageType = "local";
25968
25969    /**
25970     * @member {Object|undefined} Hyphenator~storage
25971     * @desc
25972     * An alias to the storage defined in storageType. This is set by {@link Hyphenator~createStorage}.
25973     * Set by {@link Hyphenator.run}
25974     * @default null
25975     * @access private
25976     * @see {@link Hyphenator~createStorage}
25977     */
25978    var storage;
25979
25980    /**
25981     * @member {boolean} Hyphenator~enableReducedPatternSet
25982     * @desc
25983     * A variable to set if storing the used patterns is set
25984     * @default false
25985     * @access private
25986     * @see {@link Hyphenator.config}
25987     * @see {@link Hyphenator.getRedPatternSet}
25988     */
25989    var enableReducedPatternSet = false;
25990
25991    /**
25992     * @member {boolean} Hyphenator~enableRemoteLoading
25993     * @desc
25994     * A variable to set if pattern files should be loaded remotely or not
25995     * @default true
25996     * @access private
25997     * @see {@link Hyphenator.config}
25998     */
25999    var enableRemoteLoading = true;
26000
26001    /**
26002     * @member {boolean} Hyphenator~displayToggleBox
26003     * @desc
26004     * A variable to set if the togglebox should be displayed or not
26005     * @default false
26006     * @access private
26007     * @see {@link Hyphenator.config}
26008     */
26009    var displayToggleBox = false;
26010
26011    /**
26012     * @method Hyphenator~onError
26013     * @desc
26014     * A function that can be called upon an error.
26015     * @see {@link Hyphenator.config}
26016     * @access private
26017     */
26018    var onError = function (e) {
26019        window.alert("Hyphenator.js says:\n\nAn Error occurred:\n" + e.message);
26020    };
26021
26022    /**
26023     * @method Hyphenator~onWarning
26024     * @desc
26025     * A function that can be called upon a warning.
26026     * @see {@link Hyphenator.config}
26027     * @access private
26028     */
26029    var onWarning = function (e) {
26030        window.console.log(e.message);
26031    };
26032
26033    /**
26034     * @method Hyphenator~createElem
26035     * @desc
26036     * A function alias to document.createElementNS or document.createElement
26037     * @access private
26038     */
26039    function createElem(tagname, context) {
26040        context = context || contextWindow;
26041        var el;
26042        if (window.document.createElementNS) {
26043            el = context.document.createElementNS("http://www.w3.org/1999/xhtml", tagname);
26044        } else if (window.document.createElement) {
26045            el = context.document.createElement(tagname);
26046        }
26047        return el;
26048    }
26049    /**
26050     * @method Hyphenator~forEachKey
26051     * @desc
26052     * Calls the function f on every property of o
26053     * @access private
26054     */
26055    function forEachKey(o, f) {
26056        var k;
26057        if (Object.hasOwnProperty("keys")) {
26058            Object.keys(o).forEach(f);
26059        } else {
26060            for (k in o) {
26061                if (o.hasOwnProperty(k)) {
26062                    f(k);
26063                }
26064            }
26065        }
26066    }
26067
26068    /**
26069     * @member {boolean} Hyphenator~css3
26070     * @desc
26071     * A variable to set if css3 hyphenation should be used
26072     * @default false
26073     * @access private
26074     * @see {@link Hyphenator.config}
26075     */
26076    var css3 = false;
26077
26078    /**
26079     * @method Hyphenator~css3_gethsupport
26080     * @desc
26081     * This function returns a {@link Hyphenator~css3_hsupport} object for the current UA
26082     * @type function
26083     * @access private
26084     * @see Hyphenator~css3_h9n
26085     */
26086    function css3_gethsupport() {
26087        var support = false,
26088            supportedBrowserLangs = {},
26089            property = "",
26090            checkLangSupport,
26091            createLangSupportChecker = function (prefix) {
26092                var testStrings = [
26093                        //latin: 0
26094                        "aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz",
26095                        //cyrillic: 1
26096                        "абвгдеёжзийклмнопрстуфхцчшщъыьэюя",
26097                        //arabic: 2
26098                        "أبتثجحخدذرزسشصضطظعغفقكلمنهوي",
26099                        //armenian: 3
26100                        "աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆ",
26101                        //bengali: 4
26102                        "ঁংঃঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ঽািীুূৃৄেৈোৌ্ৎৗড়ঢ়য়ৠৡৢৣ",
26103                        //devangari: 5
26104                        "ँंःअआइईउऊऋऌएऐओऔकखगघङचछजझञटठडढणतथदधनपफबभमयरलळवशषसहऽािीुूृॄेैोौ्॒॑ॠॡॢॣ",
26105                        //greek: 6
26106                        "αβγδεζηθικλμνξοπρσςτυφχψω",
26107                        //gujarati: 7
26108                        "બહઅઆઇઈઉઊઋૠએઐઓઔાિીુૂૃૄૢૣેૈોૌકખગઘઙચછજઝઞટઠડઢણતથદધનપફસભમયરલળવશષ",
26109                        //kannada: 8
26110                        "ಂಃಅಆಇಈಉಊಋಌಎಏಐಒಓಔಕಖಗಘಙಚಛಜಝಞಟಠಡಢಣತಥದಧನಪಫಬಭಮಯರಱಲಳವಶಷಸಹಽಾಿೀುೂೃೄೆೇೈೊೋೌ್ೕೖೞೠೡ",
26111                        //lao: 9
26112                        "ກຂຄງຈຊຍດຕຖທນບປຜຝພຟມຢຣລວສຫອຮະັາິີຶືຸູົຼເແໂໃໄ່້໊໋ໜໝ",
26113                        //malayalam: 10
26114                        "ംഃഅആഇഈഉഊഋഌഎഏഐഒഓഔകഖഗഘങചഛജഝഞടഠഡഢണതഥദധനപഫബഭമയരറലളഴവശഷസഹാിീുൂൃെേൈൊോൌ്ൗൠൡൺൻർൽൾൿ",
26115                        //oriya: 11
26116                        "ଁଂଃଅଆଇଈଉଊଋଌଏଐଓଔକଖଗଘଙଚଛଜଝଞଟଠଡଢଣତଥଦଧନପଫବଭମଯରଲଳଵଶଷସହାିୀୁୂୃେୈୋୌ୍ୗୠୡ",
26117                        //persian: 12
26118                        "أبتثجحخدذرزسشصضطظعغفقكلمنهوي",
26119                        //punjabi: 13
26120                        "ਁਂਃਅਆਇਈਉਊਏਐਓਔਕਖਗਘਙਚਛਜਝਞਟਠਡਢਣਤਥਦਧਨਪਫਬਭਮਯਰਲਲ਼ਵਸ਼ਸਹਾਿ
26120ੀੁੂੇੈੋੌ੍ੰੱ",
26121                        //tamil: 14
26122                        "ஃஅஆஇஈஉஊஎஏஐஒஓஔகஙசஜஞடணதநனபமயரறலளழவஷஸஹாிீுூெேைொோௌ்ௗ",
26123                        //telugu: 15
26124                        "ఁంఃఅఆఇఈఉఊఋఌఎఏఐఒఓఔకఖగఘఙచఛజఝఞటఠడఢణతథదధనపఫబభమయరఱలళవశషసహాిీుూృౄెేైొోౌ్ౕౖౠౡ",
26125                        //georgian: 16
26126                        "აიერთხტუფბლდნვკწსგზმქყშჩცძჭჯოღპჟჰ"
26127                    ],
26128                    f = function (lang) {
26129                        var shadow,
26130                            computedHeight,
26131                            bdy,
26132                            r = false;
26133
26134                        //check if lang has already been tested
26135                        if (supportedBrowserLangs.hasOwnProperty(lang)) {
26136                            r = supportedBrowserLangs[lang];
26137                        } else if (supportedLangs.hasOwnProperty(lang)) {
26138                            //create and append shadow-test-element
26139                            bdy = window.document.getElementsByTagName("body")[0];
26140                            shadow = createElem("div", window);
26141                            shadow.id = "Hyphenator_LanguageChecker";
26142                            shadow.style.width = "5em";
26143                            shadow.style.padding = "0";
26144                            shadow.style.border = "none";
26145                            shadow.style[prefix] = "auto";
26146                            shadow.style.hyphens = "auto";
26147                            shadow.style.fontSize = "12px";
26148                            shadow.style.lineHeight = "12px";
26149                            shadow.style.wordWrap = "normal";
26150                            shadow.style.wordBreak = "normal";
26151                            shadow.style.visibility = "hidden";
26152                            shadow.lang = lang;
26153                            shadow.style["-webkit-locale"] = "\"" + lang + "\"";
26154                            shadow.innerHTML = testStrings[supportedLangs[lang].script];
26155                            bdy.appendChild(shadow);
26156                            //measure its height
26157                            computedHeight = shadow.offsetHeight;
26158                            //remove shadow element
26159                            bdy.removeChild(shadow);
26160                            r = !!(computedHeight > 12);
26161                            supportedBrowserLangs[lang] = r;
26162                        } else {
26163                            r = false;
26164                        }
26165                        return r;
26166                    };
26167                return f;
26168            },
26169            s;
26170
26171        if (window.getComputedStyle) {
26172            s = window.getComputedStyle(window.document.getElementsByTagName("body")[0], null);
26173            if (s.hyphens !== undefined) {
26174                support = true;
26175                property = "hyphens";
26176                checkLangSupport = createLangSupportChecker("hyphens");
26177            } else if (s["-webkit-hyphens"] !== undefined) {
26178                support = true;
26179                property = "-webkit-hyphens";
26180                checkLangSupport = createLangSupportChecker("-webkit-hyphens");
26181            } else if (s.MozHyphens !== undefined) {
26182                support = true;
26183                property = "-moz-hyphens";
26184                checkLangSupport = createLangSupportChecker("MozHyphens");
26185            } else if (s["-ms-hyphens"] !== undefined) {
26186                support = true;
26187                property = "-ms-hyphens";
26188                checkLangSupport = createLangSupportChecker("-ms-hyphens");
26189            }
26190        } //else we just return the initial values because ancient browsers don"t support css3 anyway
26191
26192
26193        return {
26194            support: support,
26195            property: property,
26196            supportedBrowserLangs: supportedBrowserLangs,
26197            checkLangSupport: checkLangSupport
26198        };
26199    }
26200
26201    /**
26202     * @typedef {Object} Hyphenator~css3_hsupport
26203     * @property {boolean} support - if css3-hyphenation is supported
26204     * @property {string} property - the css property name to access hyphen-settings (e.g. -webkit-hyphens)
26205     * @property {Object.<string, boolean>} supportedBrowserLangs - an object caching tested languages
26206     * @property {function} checkLangSupport - a method that checks if the browser supports a requested language
26207     */
26208
26209    /**
26210     * @member {Hyphenator~css3_h9n} Hyphenator~css3_h9n
26211     * @desc
26212     * A generated object containing information for CSS3-hyphenation support
26213     * This is set by {@link Hyphenator~css3_gethsupport}
26214     * @default undefined
26215     * @access private
26216     * @see {@link Hyphenator~css3_gethsupport}
26217     * @example
26218     * //Check if browser supports a language
26219     * css3_h9n.checkLangSupport(&lt;lang&gt;)
26220     */
26221    var css3_h9n;
26222
26223    /**
26224     * @member {string} Hyphenator~hyphenateClass
26225     * @desc
26226     * A string containing the css-class-name for the hyphenate class
26227     * @default "hyphenate"
26228     * @access private
26229     * @example
26230     * &lt;p class = "hyphenate"&gt;Text&lt;/p&gt;
26231     * @see {@link Hyphenator.config}
26232     */
26233    var hyphenateClass = "hyphenate";
26234
26235    /**
26236     * @member {string} Hyphenator~urlHyphenateClass
26237     * @desc
26238     * A string containing the css-class-name for the urlhyphenate class
26239     * @default "urlhyphenate"
26240     * @access private
26241     * @example
26242     * &lt;p class = "urlhyphenate"&gt;Text&lt;/p&gt;
26243     * @see {@link Hyphenator.config}
26244     */
26245    var urlHyphenateClass = "urlhyphenate";
26246
26247    /**
26248     * @member {string} Hyphenator~classPrefix
26249     * @desc
26250     * A string containing a unique className prefix to be used
26251     * whenever Hyphenator sets a CSS-class
26252     * @access private
26253     */
26254    var classPrefix = "Hyphenator" + Math.round(Math.random() * 1000);
26255
26256    /**
26257     * @member {string} Hyphenator~hideClass
26258     * @desc
26259     * The name of the class that hides elements
26260     * @access private
26261     */
26262    var hideClass = classPrefix + "hide";
26263
26264    /**
26265     * @member {RegExp} Hyphenator~hideClassRegExp
26266     * @desc
26267     * RegExp to remove hideClass from a list of classes
26268     * @access private
26269     */
26270    var hideClassRegExp = new RegExp("\\s?\\b" + hideClass + "\\b", "g");
26271
26272    /**
26273     * @member {string} Hyphenator~hideClass
26274     * @desc
26275     * The name of the class that unhides elements
26276     * @access private
26277     */
26278    var unhideClass = classPrefix + "unhide";
26279
26280    /**
26281     * @member {RegExp} Hyphenator~hideClassRegExp
26282     * @desc
26283     * RegExp to remove unhideClass from a list of classes
26284     * @access private
26285     */
26286    var unhideClassRegExp = new RegExp("\\s?\\b" + unhideClass + "\\b", "g");
26287
26288    /**
26289     * @member {string} Hyphenator~css3hyphenateClass
26290     * @desc
26291     * The name of the class that hyphenates elements with css3
26292     * @access private
26293     */
26294    var css3hyphenateClass = classPrefix + "css3hyphenate";
26295
26296    /**
26297     * @member {CSSEdit} Hyphenator~css3hyphenateClass
26298     * @desc
26299     * The var where CSSEdit class is stored
26300     * @access private
26301     */
26302    var css3hyphenateClassHandle;
26303
26304    /**
26305     * @member {string} Hyphenator~dontHyphenateClass
26306     * @desc
26307     * A string containing the css-class-name for elements that should not be hyphenated
26308     * @default "donthyphenate"
26309     * @access private
26310     * @example
26311     * &lt;p class = "donthyphenate"&gt;Text&lt;/p&gt;
26312     * @see {@link Hyphenator.config}
26313     */
26314    var dontHyphenateClass = "donthyphenate";
26315
26316    /**
26317     * @member {number} Hyphenator~min
26318     * @desc
26319     * A number wich indicates the minimal length of words to hyphenate.
26320     * @default 6
26321     * @access private
26322     * @see {@link Hyphenator.config}
26323     */
26324    var min = 6;
26325
26326    /**
26327     * @member {number} Hyphenator~leftmin
26328     * @desc
26329     * A number wich indicates the minimal length of characters before the first hyphenation.
26330     * This value is only used if it is greater than the value in the pattern file.
26331     * @default given by pattern file
26332     * @access private
26333     * @see {@link Hyphenator.config}
26334     */
26335    var leftmin = 0;
26336
26337    /**
26338     * @member {number} Hyphenator~rightmin
26339     * @desc
26340     * A number wich indicates the minimal length of characters after the last hyphenation.
26341     * This value is only used if it is greater than the value in the pattern file.
26342     * @default given by pattern file
26343     * @access private
26344     * @see {@link Hyphenator.config}
26345     */
26346    var rightmin = 0;
26347
26348    /**
26349     * @member {number} Hyphenator~rightmin
26350     * @desc
26351     * Control how compound words are hyphenated.
26352     * "auto": factory-made -> fac-tory-made ("old" behaviour of Hyphenator.js)
26353     * "all": factory-made -> fac-tory-[ZWSP]made ("made".length < minWordLength)
26354     * "hyphen": factory-made -> factory-[ZWSP]made (Zero Width Space inserted after "-" to provide line breaking opportunity)
26355     * @default "auto"
26356     * @access private
26357     * @see {@link Hyphenator.config}
26358     */
26359    var compound = "auto";
26360
26361    /**
26362     * @member {number} Hyphenator~orphanControl
26363     * @desc
26364     * Control how the last words of a line are handled:
26365     * level 1 (default): last word is hyphenated
26366     * level 2: last word is not hyphenated
26367     * level 3: last word is not hyphenated and last space is non breaking
26368     * @default 1
26369     * @access private
26370     */
26371    var orphanControl = 1;
26372
26373    /**
26374     * @member {boolean} Hyphenator~isBookmarklet
26375     * @desc
26376     * This is computed by getLocality.
26377     * True if Hyphanetor runs as bookmarklet.
26378     * @access private
26379     */
26380    var isBookmarklet = locality.isBookmarklet;
26381
26382    /**
26383     * @member {string|null} Hyphenator~mainLanguage
26384     * @desc
26385     * The general language of the document. In contrast to {@link Hyphenator~defaultLanguage},
26386     * mainLanguage is defined by the client (i.e. by the html or by a prompt).
26387     * @access private
26388     * @see {@link Hyphenator~autoSetMainLanguage}
26389     */
26390    var mainLanguage = null;
26391
26392    /**
26393     * @member {string|null} Hyphenator~defaultLanguage
26394     * @desc
26395     * The language defined by the developper. This language setting is defined by a config option.
26396     * It is overwritten by any html-lang-attribute and only taken in count, when no such attribute can
26397     * be found (i.e. just before the prompt).
26398     * @access private
26399     * @see {@link Hyphenator.config}
26400     * @see {@link Hyphenator~autoSetMainLanguage}
26401     */
26402    var defaultLanguage = "";
26403
26404    /**
26405     * @member {ElementCollection} Hyphenator~elements
26406     * @desc
26407     * A class representing all elements (of type Element) that have to be hyphenated. This var is filled by
26408     * {@link Hyphenator~gatherDocumentInfos}
26409     * @access private
26410     */
26411    var elements = (function () {
26412        /**
26413         * @constructor Hyphenator~elements~ElementCollection~Element
26414         * @desc represents a DOM Element with additional information
26415         * @access private
26416         */
26417        var makeElement = function (element) {
26418                return {
26419                    /**
26420                     * @member {Object} Hyphenator~elements~ElementCollection~Element~element
26421                     * @desc A DOM Element
26422                     * @access protected
26423                     */
26424                    element: element,
26425                    /**
26426                     * @member {boolean} Hyphenator~elements~ElementCollection~Element~hyphenated
26427                     * @desc Marks if the element has been hyphenated
26428                     * @access protected
26429                     */
26430                    hyphenated: false,
26431                    /**
26432                     * @member {boolean} Hyphenator~elements~ElementCollection~Element~treated
26433                     * @desc Marks if information of the element has been collected but not hyphenated (e.g. dohyphenation is off)
26434                     * @access protected
26435                     */
26436                    treated: false
26437                };
26438            },
26439            /**
26440             * @constructor Hyphenator~elements~ElementCollection
26441             * @desc A collection of Elements to be hyphenated
26442             * @access protected
26443             */
26444            makeElementCollection = function () {
26445                /**
26446                 * @member {number} Hyphenator~elements~ElementCollection~counters
26447                 * @desc Array of [number of collected elements, number of hyphenated elements]
26448                 * @access protected
26449                 */
26450                var counters = [0, 0],
26451                    /**
26452                     * @member {Object.<string, Array.<Element>>} Hyphenator~elements~ElementCollection~list
26453                     * @desc The collection of elements, where the key is a language code and the value is an array of elements
26454                     * @access protected
26455                     */
26456                    list = {},
26457                    /**
26458                     * @method Hyphenator~elements~ElementCollection.prototype~add
26459                     * @augments Hyphenator~elements~ElementCollection
26460                     * @access protected
26461                     * @desc adds a DOM element to the collection
26462                     * @param {Object} el - The DOM element
26463                     * @param {string} lang - The language of the element
26464                     */
26465                    add = function (el, lang) {
26466                        var elo = makeElement(el);
26467                        if (!list.hasOwnProperty(lang)) {
26468                            list[lang] = [];
26469                        }
26470                        list[lang].push(elo);
26471                        counters[0] += 1;
26472                        return elo;
26473                    },
26474                    /**
26475                     * @callback Hyphenator~elements~ElementCollection.prototype~each~callback fn - The callback that is executed for each element
26476                     * @param {string} [k] The key (i.e. language) of the collection
26477                     * @param {Hyphenator~elements~ElementCollection~Element} element
26478                     */
26479
26480                    /**
26481                     * @method Hyphenator~elements~ElementCollection.prototype~each
26482                     * @augments Hyphenator~elements~ElementCollection
26483                     * @access protected
26484                     * @desc takes each element of the collection as an argument of fn
26485                     * @param {Hyphenator~elements~ElementCollection.prototype~each~callback} fn - A function that takes an element as an argument
26486                     */
26487                    each = function (fn) {
26488                        forEachKey(list, function (k) {
26489                            if (fn.length === 2) {
26490                                fn(k, list[k]);
26491                            } else {
26492                                fn(list[k]);
26493                            }
26494                        });
26495                    };
26496
26497                return {
26498                    counters: counters,
26499                    list: list,
26500                    add: add,
26501                    each: each
26502                };
26503
26504            };
26505        return makeElementCollection();
26506    }());
26507
26508
26509    /**
26510     * @member {Object.<sting, string>} Hyphenator~exceptions
26511     * @desc
26512     * An object containing exceptions as comma separated strings for each language.
26513     * When the language-objects are loaded, their exceptions are processed, copied here and then deleted.
26514     * Exceptions can also be set by the user.
26515     * @see {@link Hyphenator~prepareLanguagesObj}
26516     * @access private
26517     */
26518    var exceptions = {};
26519
26520    /**
26521     * @member {Object.<string, boolean>} Hyphenator~docLanguages
26522     * @desc
26523     * An object holding all languages used in the document. This is filled by
26524     * {@link Hyphenator~gatherDocumentInfos}
26525     * @access private
26526     */
26527    var docLanguages = {};
26528
26529    /**
26530     * @member {string} Hyphenator~url
26531     * @desc
26532     * A string containing a insane RegularExpression to match URL"s
26533     * @access private
26534     */
26535    var url = "(?:\\w*:\/\/)?(?:(?:\\w*:)?(?:\\w*)@)?(?:(?:(?:[\\d]{1,3}\\.){3}(?:[\\d]{1,3}))|(?:(?:www\\.|[a-zA-Z]\\.)?[a-zA-Z0-9\\-]+(?:\\.[a-z]{2,})+))(?::\\d*)?(?:\/[\\w#!:\\.?\\+=&%@!\\-]*)*";
26536    //            protocoll     usr     pwd                    ip                             or                       host                        tld          port               path
26537
26538    /**
26539     * @member {string} Hyphenator~mail
26540     * @desc
26541     * A string containing a RegularExpression to match mail-adresses
26542     * @access private
26543     */
26544    var mail = "[\\w-\\.]+@[\\w\\.]+";
26545
26546    /**
26547     * @member {string} Hyphenator~zeroWidthSpace
26548     * @desc
26549     * A string that holds a char.
26550     * Depending on the browser, this is the zero with space or an empty string.
26551     * zeroWidthSpace is used to break URLs
26552     * @access private
26553     */
26554    var zeroWidthSpace = (function () {
26555        var zws, ua = window.navigator.userAgent.toLowerCase();
26556        zws = String.fromCharCode(8203); //Unicode zero width space
26557        if (ua.indexOf("msie 6") !== -1) {
26558            zws = ""; //IE6 doesn"t support zws
26559        }
26560        if (ua.indexOf("opera") !== -1 && ua.indexOf("version/10.00") !== -1) {
26561            zws = ""; //opera 10 on XP doesn"t support zws
26562        }
26563        return zws;
26564    }());
26565
26566    /**
26567     * @method Hyphenator~onBeforeWordHyphenation
26568     * @desc
26569     * This method is called just before a word is hyphenated.
26570     * It is called with two parameters: the word and its language.
26571     * The method must return a string (aka the word).
26572     * @see {@link Hyphenator.config}
26573     * @access private
26574     * @param {string} word
26575     * @param {string} lang
26576     * @return {string} The word that goes into hyphenation
26577     */
26578    var onBeforeWordHyphenation = function (word) {
26579        return word;
26580    };
26581
26582    /**
26583     * @method Hyphenator~onAfterWordHyphenation
26584     * @desc
26585     * This method is called for each word after it is hyphenated.
26586     * Takes the word as a first parameter and its language as a second parameter.
26587     * Returns a string that will replace the word that has been hyphenated.
26588     * @see {@link Hyphenator.config}
26589     * @access private
26590     * @param {string} word
26591     * @param {string} lang
26592     * @return {string} The word that goes into hyphenation
26593     */
26594    var onAfterWordHyphenation = function (word) {
26595        return word;
26596    };
26597
26598    /**
26599     * @method Hyphenator~onHyphenationDone
26600     * @desc
26601     * A method to be called, when the last element has been hyphenated.
26602     * If there are frames the method is called for each frame.
26603     * Therefore the location.href of the contextWindow calling this method is given as a parameter
26604     * @see {@link Hyphenator.config}
26605     * @param {string} context
26606     * @access private
26607     */
26608    var onHyphenationDone = function (context) {
26609        return context;
26610    };
26611
26612    /**
26613     * @name Hyphenator~selectorFunction
26614     * @desc
26615     * A function set by the user that has to return a HTMLNodeList or array of Elements to be hyphenated.
26616     * By default this is set to false so we can check if a selectorFunction is set…
26617     * @see {@link Hyphenator.config}
26618     * @see {@link Hyphenator~mySelectorFunction}
26619     * @default false
26620     * @type {function|boolean}
26621     * @access private
26622     */
26623    var selectorFunction = false;
26624
26625    /**
26626     * @name Hyphenator~flattenNodeList
26627     * @desc
26628     * Takes a nodeList and returns an array with all elements that are not contained by another element in the nodeList
26629     * By using this function the elements returned by selectElements can be "flattened".
26630     * @see {@link Hyphenator~selectElements}
26631     * @param {nodeList} nl
26632     * @return {Array} Array of "parent"-elements
26633     * @access private
26634     */
26635    function flattenNodeList(nl) {
26636        var parentElements = [],
26637            i = 1,
26638            j = 0,
26639            isParent = true;
26640
26641        parentElements.push(nl[0]); //add the first item, since this is always an parent
26642
26643        while (i < nl.length) { //cycle through nodeList
26644            while (j < parentElements.length) { //cycle through parentElements
26645                if (parentElements[j].contains(nl[i])) {
26646                    isParent = false;
26647                    break;
26648                }
26649                j += 1;
26650            }
26651            if (isParent) {
26652                parentElements.push(nl[i]);
26653            }
26654            isParent = true;
26655            i += 1;
26656        }
26657
26658        return parentElements;
26659    }
26660
26661    /**
26662     * @method Hyphenator~mySelectorFunction
26663     * @desc
26664     * A function that returns a HTMLNodeList or array of Elements to be hyphenated.
26665     * By default it uses the classname ("hyphenate") to select the elements.
26666     * @access private
26667     */
26668    function mySelectorFunction(hyphenateClass) {
26669        var tmp,
26670            el = [],
26671            i = 0;
26672        if (window.document.getElementsByClassName) {
26673            el = contextWindow.document.getElementsByClassName(hyphenateClass);
26674        } else if (window.document.querySelectorAll) {
26675            el = contextWindow.document.querySelectorAll("." + hyphenateClass);
26676        } else {
26677            tmp = contextWindow.document.getElementsByTagName("*");
26678            while (i < tmp.length) {
26679                if (tmp[i].className.indexOf(hyphenateClass) !== -1 && tmp[i].className.indexOf(dontHyphenateClass) === -1) {
26680                    el.push(tmp[i]);
26681                }
26682                i += 1;
26683            }
26684        }
26685        return el;
26686    }
26687
26688    /**
26689     * @method Hyphenator~selectElements
26690     * @desc
26691     * A function that uses either selectorFunction set by the user
26692     * or the default mySelectorFunction.
26693     * @access private
26694     */
26695    function selectElements() {
26696        var elems;
26697        if (selectorFunction) {
26698            elems = selectorFunction();
26699        } else {
26700            elems = mySelectorFunction(hyphenateClass);
26701        }
26702        if (elems.length !== 0) {
26703            elems = flattenNodeList(elems);
26704        }
26705        return elems;
26706    }
26707
26708    /**
26709     * @member {string} Hyphenator~intermediateState
26710     * @desc
26711     * The visibility of elements while they are hyphenated:
26712     * "visible": unhyphenated text is visible and then redrawn when hyphenated.
26713     * "hidden": unhyphenated text is made invisible as soon as possible and made visible after hyphenation.
26714     * @default "hidden"
26715     * @see {@link Hyphenator.config}
26716     * @access private
26717     */
26718    var intermediateState = "hidden";
26719
26720    /**
26721     * @member {string} Hyphenator~unhide
26722     * @desc
26723     * How hidden elements unhide: either simultaneous (default: "wait") or progressively.
26724     * "wait" makes Hyphenator.js to wait until all elements are hyphenated (one redraw)
26725     * With "progressive" Hyphenator.js unhides elements as soon as they are hyphenated.
26726     * @see {@link Hyphenator.config}
26727     * @access private
26728     */
26729    var unhide = "wait";
26730
26731    /**
26732     * @member {Array.<Hyphenator~CSSEdit>} Hyphenator~CSSEditors
26733     * @desc A container array that holds CSSEdit classes
26734     * For each window object one CSSEdit class is inserted
26735     * @access private
26736     */
26737    var CSSEditors = [];
26738
26739    /**
26740     * @constructor Hyphenator~CSSEdit
26741     * @desc
26742     * This class handles access and editing of StyleSheets.
26743     * Thanks to this styles (e.g. hiding and unhiding elements upon hyphenation)
26744     * can be changed in one place instead for each element.
26745     * @access private
26746     */
26747    function makeCSSEdit(w) {
26748        w = w || window;
26749        var doc = w.document,
26750            /**
26751             * @member {Object} Hyphenator~CSSEdit~sheet
26752             * @desc
26753             * A StyleSheet, where Hyphenator can write to.
26754             * If no StyleSheet can be found, lets create one.
26755             * @access private
26756             */
26757            sheet = (function () {
26758                var i = 0,
26759                    l = doc.styleSheets.length,
26760                    s,
26761                    element,
26762                    r = false;
26763                while (i < l) {
26764                    s = doc.styleSheets[i];
26765                    try {
26766                        if (!!s.cssRules) {
26767                            r = s;
26768                            break;
26769                        }
26770                    } catch (ignore) {}
26771                    i += 1;
26772                }
26773                if (r === false) {
26774                    element = doc.createElement("style");
26775                    element.type = "text/css";
26776                    doc.getElementsByTagName("head")[0].appendChild(element);
26777                    r = doc.styleSheets[doc.styleSheets.length - 1];
26778                }
26779                return r;
26780            }()),
26781
26782            /**
26783             * @typedef {Object} Hyphenator~CSSEdit~changes
26784             * @property {Object} sheet - The StyleSheet where the change was made
26785             * @property {number} index - The index of the changed rule
26786             */
26787
26788            /**
26789             * @member {Array.<changes>} Hyphenator~CSSEdit~changes
26790             * @desc
26791             * Sets a CSS rule for a specified selector
26792             * @access private
26793             */
26794            changes = [],
26795
26796            /**
26797             * @typedef Hyphenator~CSSEdit~rule
26798             * @property {number} index - The index of the rule
26799             * @property {Object} rule - The style rule
26800             */
26801            /**
26802             * @method Hyphenator~CSSEdit~findRule
26803             * @desc
26804             * Searches the StyleSheets for a given selector and returns an object containing the rule.
26805             * If nothing can be found, false is returned.
26806             * @param {string} sel
26807             * @return {Hyphenator~CSSEdit~rule|false}
26808             * @access private
26809             */
26810            findRule = function (sel) {
26811                var s,
26812                    rule,
26813                    sheets = w.document.styleSheets,
26814                    rules,
26815                    i = 0,
26816                    j = 0,
26817                    r = false;
26818                while (i < sheets.length) {
26819                    s = sheets[i];
26820                    try { //FF has issues here with external CSS (s.o.p)
26821                        if (!!s.cssRules) {
26822                            rules = s.cssRules;
26823                        } else if (!!s.rules) {
26824                            // IE < 9
26825                            rules = s.rules;
26826                        }
26827                    } catch (ignore) {}
26828                    if (!!rules && !!rules.length) {
26829                        while (j < rules.length) {
26830                            rule = rules[j];
26831                            if (rule.selectorText === sel) {
26832                                r = {
26833                                    index: j,
26834                                    rule: rule
26835                                };
26836                            }
26837                            j += 1;
26838                        }
26839                    }
26840                    i += 1;
26841                }
26842                return r;
26843            },
26844            /**
26845             * @method Hyphenator~CSSEdit~addRule
26846             * @desc
26847             * Adds a rule to the {@link Hyphenator~CSSEdit~sheet}
26848             * @param {string} sel - The selector to be added
26849             * @param {string} rulesStr - The rules for the specified selector
26850             * @return {number} index of the new rule
26851             * @access private
26852             */
26853            addRule = function (sel, rulesStr) {
26854                var i, r;
26855                if (!!sheet.insertRule) {
26856                    if (!!sheet.cssRules) {
26857                        i = sheet.cssRules.length;
26858                    } else {
26859                        i = 0;
26860                    }
26861                    r = sheet.insertRule(sel + "{" + rulesStr + "}", i);
26862                } else if (!!sheet.addRule) {
26863                    // IE < 9
26864                    if (!!sheet.rules) {
26865                        i = sheet.rules.length;
26866                    } else {
26867                        i = 0;
26868                    }
26869                    sheet.addRule(sel, rulesStr, i);
26870                    r = i;
26871                }
26872                return r;
26873            },
26874            /**
26875             * @method Hyphenator~CSSEdit~removeRule
26876             * @desc
26877             * Removes a rule with the specified index from the specified sheet
26878             * @param {Object} sheet - The style sheet
26879             * @param {number} index - the index of the rule
26880             * @access private
26881             */
26882            removeRule = function (sheet, index) {
26883                if (sheet.deleteRule) {
26884                    sheet.deleteRule(index);
26885                } else {
26886                    // IE < 9
26887                    sheet.removeRule(index);
26888                }
26889            };
26890
26891        return {
26892            /**
26893             * @method Hyphenator~CSSEdit.setRule
26894             * @desc
26895             * Sets a CSS rule for a specified selector
26896             * @access public
26897             * @param {string} sel - Selector
26898             * @param {string} rulesString - CSS-Rules
26899             */
26900            setRule: function (sel, rulesString) {
26901                var i, existingRule, cssText;
26902                existingRule = findRule(sel);
26903                if (!!existingRule) {
26904                    if (!!existingRule.rule.cssText) {
26905                        cssText = existingRule.rule.cssText;
26906                    } else {
26907                        // IE < 9
26908                        cssText = existingRule.rule.style.cssText.toLowerCase();
26909                    }
26910                    if (cssText !== sel + " { " + rulesString + " }") {
26911                        //cssText of the found rule is not uniquely selector + rulesString,
26912                        if (cssText.indexOf(rulesString) !== -1) {
26913                            //maybe there are other rules or IE < 9
26914                            //clear existing def
26915                            existingRule.rule.style.visibility = "";
26916                        }
26917                        //add rule and register for later removal
26918                        i = addRule(sel, rulesString);
26919                        changes.push({sheet: sheet, index: i});
26920                    }
26921                } else {
26922                    i = addRule(sel, rulesString);
26923                    changes.push({sheet: sheet, index: i});
26924                }
26925            },
26926            /**
26927             * @method Hyphenator~CSSEdit.clearChanges
26928             * @desc
26929             * Removes all changes Hyphenator has made from the StyleSheets
26930             * @access public
26931             */
26932            clearChanges: function () {
26933                var change = changes.pop();
26934                while (!!change) {
26935                    removeRule(change.sheet, change.index);
26936                    change = changes.pop();
26937                }
26938            }
26939        };
26940    }
26941
26942    /**
26943     * @member {string} Hyphenator~hyphen
26944     * @desc
26945     * A string containing the character for in-word-hyphenation
26946     * @default the soft hyphen
26947     * @access private
26948     * @see {@link Hyphenator.config}
26949     */
26950    var hyphen = String.fromCharCode(173);
26951
26952    /**
26953     * @member {string} Hyphenator~urlhyphen
26954     * @desc
26955     * A string containing the character for url/mail-hyphenation
26956     * @default the zero width space
26957     * @access private
26958     * @see {@link Hyphenator.config}
26959     * @see {@link Hyphenator~zeroWidthSpace}
26960     */
26961    var urlhyphen = zeroWidthSpace;
26962
26963    /**
26964     * @method Hyphenator~hyphenateURL
26965     * @desc
26966     * Puts {@link Hyphenator~urlhyphen} (default: zero width space) after each no-alphanumeric char that my be in a URL.
26967     * @param {string} url to hyphenate
26968     * @returns string the hyphenated URL
26969     * @access public
26970     */
26971    function hyphenateURL(url) {
26972        var tmp = url.replace(/([:\/.?#&\-_,;!@]+)/gi, "$&" + urlhyphen),
26973            parts = tmp.split(urlhyphen),
26974            i = 0;
26975        while (i < parts.length) {
26976            if (parts[i].length > (2 * min)) {
26977                parts[i] = parts[i].replace(/(\w{3})(\w)/gi, "$1" + urlhyphen + "$2");
26978            }
26979            i += 1;
26980        }
26981        if (parts[parts.length - 1] === "") {
26982            parts.pop();
26983        }
26984        return parts.join(urlhyphen);
26985    }
26986
26987    /**
26988     * @member {boolean} Hyphenator~safeCopy
26989     * @desc
26990     * Defines wether work-around for copy issues is active or not
26991     * @default true
26992     * @access private
26993     * @see {@link Hyphenator.config}
26994     * @see {@link Hyphenator~registerOnCopy}
26995     */
26996    var safeCopy = true;
26997
26998    /**
26999     * @method Hyphenator~zeroTimeOut
27000     * @desc
27001     * defer execution of a function on the call stack
27002     * Analog to window.setTimeout(fn, 0) but without a clamped delay if postMessage is supported
27003     * @access private
27004     * @see {@link http://dbaron.org/log/20100309-faster-timeouts}
27005     */
27006    var zeroTimeOut = (function () {
27007        if (window.postMessage && window.addEventListener) {
27008            return (function () {
27009                var timeouts = [],
27010                    msg = "Hyphenator_zeroTimeOut_message",
27011                    setZeroTimeOut = function (fn) {
27012                        timeouts.push(fn);
27013                        window.postMessage(msg, "*");
27014                    },
27015                    handleMessage = function (event) {
27016                        if (event.source === window && event.data === msg) {
27017                            event.stopPropagation();
27018                            if (timeouts.length > 0) {
27019                                //var efn = timeouts.shift();
27020                                //efn();
27021                                timeouts.shift()();
27022                            }
27023                        }
27024                    };
27025                window.addEventListener("message", handleMessage, true);
27026                return setZeroTimeOut;
27027            }());
27028        }
27029        return function (fn) {
27030            window.setTimeout(fn, 0);
27031        };
27032    }());
27033
27034    /**
27035     * @member {Object} Hyphenator~hyphRunFor
27036     * @desc
27037     * stores location.href for documents where run() has been executed
27038     * to warn when Hyphenator.run() executed multiple times
27039     * @access private
27040     * @see {@link Hyphenator~runWhenLoaded}
27041     */
27042    var hyphRunFor = {};
27043
27044    /**
27045     * @method Hyphenator~removeHyphenationFromElement
27046     * @desc
27047     * Removes all hyphens from the element. If there are other elements, the function is
27048     * called recursively.
27049     * Removing hyphens is usefull if you like to copy text. Some browsers are buggy when the copy hyphenated texts.
27050     * @param {Object} el The element where to remove hyphenation.
27051     * @access public
27052     */
27053    function removeHyphenationFromElement(el) {
27054        var h, u, i = 0, n;
27055        //escape hyphen
27056        if (".\\+*?[^]$(){}=!<>|:-".indexOf(hyphen) !== -1) {
27057            h = "\\" + hyphen;
27058        } else {
27059            h = hyphen;
27060        }
27061        //escape hyphen
27062        if (".\\+*?[^]$(){}=!<>|:-".indexOf(urlhyphen) !== -1) {
27063            u = "\\" + urlhyphen;
27064        } else {
27065            u = urlhyphen;
27066        }
27067        n = el.childNodes[i];
27068        while (!!n) {
27069            if (n.nodeType === 3) {
27070                n.data = n.data.replace(new RegExp(h, "g"), "");
27071                n.data = n.data.replace(new RegExp(u, "g"), "");
27072            } else if (n.nodeType === 1) {
27073                removeHyphenationFromElement(n);
27074            }
27075            i += 1;
27076            n = el.childNodes[i];
27077        }
27078    }
27079
27080    /**
27081     * @member {Object} Hyphenator~hyphRunFor
27082     * @desc
27083     * stores location.href for documents where run() has been executed
27084     * to warn when Hyphenator.run() executed multiple times
27085     * @access private
27086     * @see {@link Hyphenator~runWhenLoaded}
27087     */
27088    var copy = (function () {
27089        var factory = function () {
27090            var registeredElements = [];
27091            var oncopyHandler = function (e) {
27092                e = e || window.event;
27093                var shadow,
27094                    selection,
27095                    range,
27096                    rangeShadow,
27097                    restore,
27098                    target = e.target || e.srcElement,
27099                    currDoc = target.ownerDocument,
27100                    bdy = currDoc.getElementsByTagName("body")[0],
27101                    targetWindow = currDoc.defaultView || currDoc.parentWindow;
27102                if (target.tagName && dontHyphenate[target.tagName.toLowerCase()]) {
27103                    //Safari needs this
27104                    return;
27105                }
27106                //create a hidden shadow element
27107                shadow = currDoc.createElement("div");
27108                shadow.style.color = window.getComputedStyle
27109                    ? targetWindow.getComputedStyle(bdy, null).backgroundColor
27110                    : "#FFFFFF";
27111                shadow.style.fontSize = "0px";
27112                bdy.appendChild(shadow);
27113                if (!!window.getSelection) {
27114                    //FF3, Webkit, IE9
27115                    selection = targetWindow.getSelection();
27116                    range = selection.getRangeAt(0);
27117                    shadow.appendChild(range.cloneContents());
27118                    removeHyphenationFromElement(shadow);
27119                    selection.selectAllChildren(shadow);
27120                    restore = function () {
27121                        shadow.parentNode.removeChild(shadow);
27122                        selection.removeAllRanges(); //IE9 needs that
27123                        selection.addRange(range);
27124                    };
27125                } else {
27126                    // IE<9
27127                    selection = targetWindow.document.selection;
27128                    range = selection.createRange();
27129                    shadow.innerHTML = range.htmlText;
27130                    removeHyphenationFromElement(shadow);
27131                    rangeShadow = bdy.createTextRange();
27132                    rangeShadow.moveToElementText(shadow);
27133                    rangeShadow.select();
27134                    restore = function () {
27135                        shadow.parentNode.removeChild(shadow);
27136                        if (range.text !== "") {
27137                            range.select();
27138                        }
27139                    };
27140                }
27141                zeroTimeOut(restore);
27142            };
27143            var removeOnCopy = function () {
27144                var i = registeredElements.length - 1;
27145                while (i >= 0) {
27146                    if (window.removeEventListener) {
27147                        registeredElements[i].removeEventListener("copy", oncopyHandler, true);
27148                    } else {
27149                        registeredElements[i].detachEvent("oncopy", oncopyHandler);
27150                    }
27151                    i -= 1;
27152                }
27153            };
27154            var reactivateOnCopy = function () {
27155                var i = registeredElements.length - 1;
27156                while (i >= 0) {
27157                    if (window.addEventListener) {
27158                        registeredElements[i].addEventListener("copy", oncopyHandler, true);
27159                    } else {
27160                        registeredElements[i].attachEvent("oncopy", oncopyHandler);
27161                    }
27162                    i -= 1;
27163                }
27164            };
27165            var registerOnCopy = function (el) {
27166                registeredElements.push(el);
27167                if (window.addEventListener) {
27168                    el.addEventListener("copy", oncopyHandler, true);
27169                } else {
27170                    el.attachEvent("oncopy", oncopyHandler);
27171                }
27172            };
27173            return {
27174                oncopyHandler: oncopyHandler,
27175                removeOnCopy: removeOnCopy,
27176                registerOnCopy: registerOnCopy,
27177                reactivateOnCopy: reactivateOnCopy
27178            };
27179        };
27180        return (safeCopy
27181            ? factory()
27182            : false);
27183    }());
27184
27185    /**
27186     * @method Hyphenator~runWhenLoaded
27187     * @desc
27188     * A crossbrowser solution for the DOMContentLoaded-Event based on
27189     * <a href = "http://jquery.com/">jQuery</a>
27190     * I added some functionality: e.g. support for frames and iframes…
27191     * @param {Object} w the window-object
27192     * @param {function()} f the function to call when the document is ready
27193     * @access private
27194     */
27195    function runWhenLoaded(w, f) {
27196        var toplevel,
27197            add = window.document.addEventListener
27198                ? "addEventListener"
27199                : "attachEvent",
27200            rem = window.document.addEventListener
27201                ? "removeEventListener"
27202                : "detachEvent",
27203            pre = window.document.addEventListener
27204                ? ""
27205                : "on";
27206
27207        function init(context) {
27208            if (hyphRunFor[context.location.href]) {
27209                onWarning(new Error("Warning: multiple execution of Hyphenator.run() – This may slow down the script!"));
27210            }
27211            contextWindow = context || window;
27212            f();
27213            hyphRunFor[contextWindow.location.href] = true;
27214        }
27215
27216        function doScrollCheck() {
27217            try {
27218                // If IE is used, use the trick by Diego Perini
27219                // http://javascript.nwbox.com/IEContentLoaded/
27220                w.document.documentElement.doScroll("left");
27221            } catch (ignore) {
27222                window.setTimeout(doScrollCheck, 1);
27223                return;
27224            }
27225            //maybe modern IE fired DOMContentLoaded
27226            if (!hyphRunFor[w.location.href]) {
27227                documentLoaded = true;
27228                init(w);
27229            }
27230        }
27231
27232        function doOnEvent(e) {
27233            var i = 0,
27234                fl,
27235                haveAccess;
27236            if (!!e && e.type === "readystatechange" && w.document.readyState !== "interactive" && w.document.readyState !== "complete") {
27237                return;
27238            }
27239
27240            //DOM is ready/interactive, but frames may not be loaded yet!
27241            //cleanup events
27242            w.document[rem](pre + "DOMContentLoaded", doOnEvent, false);
27243            w.document[rem](pre + "readystatechange", doOnEvent, false);
27244
27245            //check frames
27246            fl = w.frames.length;
27247            if (fl === 0 || !doFrames) {
27248                //there are no frames!
27249                //cleanup events
27250                w[rem](pre + "load", doOnEvent, false);
27251                documentLoaded = true;
27252                init(w);
27253            } else if (doFrames && fl > 0) {
27254                //we have frames, so wait for onload and then initiate runWhenLoaded recursevly for each frame:
27255                if (!!e && e.type === "load") {
27256                    //cleanup events
27257                    w[rem](pre + "load", doOnEvent, false);
27258                    while (i < fl) {
27259                        haveAccess = undefined;
27260                        //try catch isn"t enough for webkit
27261                        try {
27262                            //opera throws only on document.toString-access
27263                            haveAccess = w.frames[i].document.toString();
27264                        } catch (ignore) {
27265                            haveAccess = undefined;
27266                        }
27267                        if (!!haveAccess) {
27268                            runWhenLoaded(w.frames[i], f);
27269                        }
27270                        i += 1;
27271                    }
27272                    init(w);
27273                }
27274            }
27275        }
27276
27277        if (documentLoaded || w.document.readyState === "complete") {
27278            //Hyphenator has run already (documentLoaded is true) or
27279            //it has been loaded after onLoad
27280            documentLoaded = true;
27281            doOnEvent({type: "load"});
27282        } else {
27283            //register events
27284            w.document[add](pre + "DOMContentLoaded", doOnEvent, false);
27285            w.document[add](pre + "readystatechange", doOnEvent, false);
27286            w[add](pre + "load", doOnEvent, false);
27287            toplevel = false;
27288            try {
27289                toplevel = !window.frameElement;
27290            } catch (ignore) {}
27291            if (toplevel && w.document.documentElement.doScroll) {
27292                doScrollCheck(); //calls init()
27293            }
27294        }
27295    }
27296
27297    /**
27298     * @method Hyphenator~getLang
27299     * @desc
27300     * Gets the language of an element. If no language is set, it may use the {@link Hyphenator~mainLanguage}.
27301     * @param {Object} el The first parameter is an DOM-Element-Object
27302     * @param {boolean} fallback The second parameter is a boolean to tell if the function should return the {@link Hyphenator~mainLanguage}
27303     * if there"s no language found for the element.
27304     * @return {string} The language of the element
27305     * @access private
27306     */
27307    function getLang(el, fallback) {
27308        try {
27309            return !!el.getAttribute("lang")
27310                ? el.getAttribute("lang").toLowerCase()
27311                : !!el.getAttribute("xml:lang")
27312                    ? el.getAttribute("xml:lang").toLowerCase()
27313                    : el.tagName.toLowerCase() !== "html"
27314                        ? getLang(el.parentNode, fallback)
27315                        : fallback
27316                            ? mainLanguage
27317                            : null;
27318        } catch (ignore) {
27319            return fallback
27320                ? mainLanguage
27321                : null;
27322        }
27323    }
27324
27325    /**
27326     * @method Hyphenator~autoSetMainLanguage
27327     * @desc
27328     * Retrieves the language of the document from the DOM and sets the lang attribute of the html-tag.
27329     * The function looks in the following places:
27330     * <ul>
27331     * <li>lang-attribute in the html-tag</li>
27332     * <li>&lt;meta http-equiv = "content-language" content = "xy" /&gt;</li>
27333     * <li>&lt;meta name = "DC.Language" content = "xy" /&gt;</li>
27334     * <li>&lt;meta name = "language" content = "xy" /&gt;</li>
27335     * </li>
27336     * If nothing can be found a prompt using {@link Hyphenator~languageHint} and a prompt-string is displayed.
27337     * If the retrieved language is in the object {@link Hyphenator~supportedLangs} it is copied to {@link Hyphenator~mainLanguage}
27338     * @access private
27339     */
27340    function autoSetMainLanguage(w) {
27341        w = w || contextWindow;
27342        var el = w.document.getElementsByTagName("html")[0],
27343            m = w.document.getElementsByTagName("meta"),
27344            i = 0,
27345            getLangFromUser = function () {
27346                var text = "";
27347                var ul = "";
27348                var languageHint = (function () {
27349                    var r = "";
27350                    forEachKey(supportedLangs, function (k) {
27351                        r += k + ", ";
27352                    });
27353                    r = r.substring(0, r.length - 2);
27354                    return r;
27355                }());
27356                ul = window.navigator.language || window.navigator.userLanguage;
27357                ul = ul.substring(0, 2);
27358                if (!!supportedLangs[ul] && supportedLangs[ul].prompt !== "") {
27359                    text = supportedLangs[ul].prompt;
27360                } else {
27361                    text = supportedLangs.en.prompt;
27362                }
27363                text += " (ISO 639-1)\n\n" + languageHint;
27364                return window.prompt(window.unescape(text), ul).toLowerCase();
27365            };
27366        mainLanguage = getLang(el, false);
27367        if (!mainLanguage) {
27368            while (i < m.length) {
27369                //<meta http-equiv = "content-language" content="xy">
27370                if (!!m[i].getAttribute("http-equiv") && (m[i].getAttribute("http-equiv").toLowerCase() === "content-language")) {
27371                    mainLanguage = m[i].getAttribute("content").toLowerCase();
27372                }
27373                //<meta name = "DC.Language" content="xy">
27374                if (!!m[i].getAttribute("name") && (m[i].getAttribute("name").toLowerCase() === "dc.language")) {
27375                    mainLanguage = m[i].getAttribute("content").toLowerCase();
27376                }
27377                //<meta name = "language" content = "xy">
27378                if (!!m[i].getAttribute("name") && (m[i].getAttribute("name").toLowerCase() === "language")) {
27379                    mainLanguage = m[i].getAttribute("content").toLowerCase();
27380                }
27381                i += 1;
27382            }
27383        }
27384        //get lang for frame from enclosing document
27385        if (!mainLanguage && doFrames && (!!contextWindow.frameElement)) {
27386            autoSetMainLanguage(window.parent);
27387        }
27388        //fallback to defaultLang if set
27389        if (!mainLanguage && defaultLanguage !== "") {
27390            mainLanguage = defaultLanguage;
27391        }
27392        //ask user for lang
27393        if (!mainLanguage) {
27394            mainLanguage = getLangFromUser();
27395        }
27396        el.lang = mainLanguage;
27397    }
27398
27399    /**
27400     * @method Hyphenator~gatherDocumentInfos
27401     * @desc
27402     * This method runs through the DOM and executes the process()-function on:
27403     * - every node returned by the {@link Hyphenator~selectorFunction}.
27404     * @access private
27405     */
27406    function gatherDocumentInfos() {
27407        var elToProcess,
27408            urlhyphenEls,
27409            tmp,
27410            i = 0;
27411        /**
27412         * @method Hyphenator~gatherDocumentInfos
27413         * @desc
27414         * This method copies the element to the elements-variable, sets its visibility
27415         * to intermediateState, retrieves its language and recursivly descends the DOM-tree until
27416         * the child-Nodes aren"t of type 1
27417         * @param {Object} el a DOM element
27418         * @param {string} plang the language of the parent element
27419         * @param {boolean} isChild true, if the parent of el has been processed
27420         */
27421        function process(el, pLang, isChild) {
27422            var n,
27423                j = 0,
27424                hyphenate = true,
27425                eLang,
27426                useCSS3 = function () {
27427                    css3hyphenateClassHandle = makeCSSEdit(contextWindow);
27428                    css3hyphenateClassHandle.setRule("." + css3hyphenateClass, css3_h9n.property + ": auto;");
27429                    css3hyphenateClassHandle.setRule("." + dontHyphenateClass, css3_h9n.property + ": manual;");
27430                    if ((eLang !== pLang) && css3_h9n.property.indexOf("webkit") !== -1) {
27431                        css3hyphenateClassHandle.setRule("." + css3hyphenateClass, "-webkit-locale : " + eLang + ";");
27432                    }
27433                    el.className = el.className + " " + css3hyphenateClass;
27434                },
27435                useHyphenator = function () {
27436                    //quick fix for test111.html
27437                    //better: weight elements
27438                    if (isBookmarklet && eLang !== mainLanguage) {
27439                        return;
27440                    }
27441                    if (supportedLangs.hasOwnProperty(eLang)) {
27442                        docLanguages[eLang] = true;
27443                    } else {
27444                        if (supportedLangs.hasOwnProperty(eLang.split("-")[0])) { //try subtag
27445                            eLang = eLang.split("-")[0];
27446                            docLanguages[eLang] = true;
27447                        } else if (!isBookmarklet) {
27448                            hyphenate = false;
27449                            onError(new Error("Language \"" + eLang + "\" is not yet supported."));
27450                        }
27451                    }
27452                    if (hyphenate) {
27453                        if (intermediateState === "hidden") {
27454                            el.className = el.className + " " + hideClass;
27455                        }
27456                        elements.add(el, eLang);
27457                    }
27458                };
27459            isChild = isChild || false;
27460            if (el.lang && typeof el.lang === "string") {
27461                eLang = el.lang.toLowerCase(); //copy attribute-lang to internal eLang
27462            } else if (!!pLang && pLang !== "") {
27463                eLang = pLang.toLowerCase();
27464            } else {
27465                eLang = getLang(el, true);
27466            }
27467
27468            if (!isChild) {
27469                if (css3 && css3_h9n.support && !!css3_h9n.checkLangSupport(eLang)) {
27470                    useCSS3();
27471                } else {
27472                    if (safeCopy) {
27473                        copy.registerOnCopy(el);
27474                    }
27475                    useHyphenator();
27476                }
27477            } else {
27478                if (eLang !== pLang) {
27479                    if (css3 && css3_h9n.support && !!css3_h9n.checkLangSupport(eLang)) {
27480                        useCSS3();
27481                    } else {
27482                        useHyphenator();
27483                    }
27484                } else {
27485                    if (!css3 || !css3_h9n.support || !css3_h9n.checkLangSupport(eLang)) {
27486                        useHyphenator();
27487                    } // else do nothing
27488                }
27489            }
27490            n = el.childNodes[j];
27491            while (!!n) {
27492                if (
27493                    n.nodeType === 1 && !dontHyphenate[n.nodeName.toLowerCase()] &&
27494                    n.className.indexOf(dontHyphenateClass) === -1 &&
27495                    n.className.indexOf(urlHyphenateClass) === -1 && !elToProcess[n]
27496                ) {
27497                    process(n, eLang, true);
27498                }
27499                j += 1;
27500                n = el.childNodes[j];
27501            }
27502        }
27503        function processUrlStyled(el) {
27504            var n, j = 0;
27505
27506            n = el.childNodes[j];
27507            while (!!n) {
27508                if (
27509                    n.nodeType === 1 && !dontHyphenate[n.nodeName.toLowerCase()] &&
27510                    n.className.indexOf(dontHyphenateClass) === -1 &&
27511                    n.className.indexOf(hyphenateClass) === -1 && !urlhyphenEls[n]
27512                ) {
27513                    processUrlStyled(n);
27514                } else if (n.nodeType === 3) {
27515                    if (safeCopy) {
27516                        copy.registerOnCopy(n.parentNode);
27517                    }
27518                    //n.data = hyphenateURL(n.data);
27519                    elements.add(n.parentNode, "urlstyled");
27520                }
27521                j += 1;
27522                n = el.childNodes[j];
27523            }
27524        }
27525
27526        if (css3) {
27527            css3_h9n = css3_gethsupport();
27528        }
27529        if (isBookmarklet) {
27530            elToProcess = contextWindow.document.getElementsByTagName("body")[0];
27531            process(elToProcess, mainLanguage, false);
27532        } else {
27533            if (!css3 && intermediateState === "hidden") {
27534                CSSEditors.push(makeCSSEdit(contextWindow));
27535                CSSEditors[CSSEditors.length - 1].setRule("." + hyphenateClass, "visibility: hidden;");
27536                CSSEditors[CSSEditors.length - 1].setRule("." + hideClass, "visibility: hidden;");
27537                CSSEditors[CSSEditors.length - 1].setRule("." + unhideClass, "visibility: visible;");
27538            }
27539            elToProcess = selectElements();
27540            tmp = elToProcess[i];
27541            while (!!tmp) {
27542                process(tmp, "", false);
27543                i += 1;
27544                tmp = elToProcess[i];
27545            }
27546
27547            urlhyphenEls = mySelectorFunction(urlHyphenateClass);
27548            i = 0;
27549            tmp = urlhyphenEls[i];
27550            while (!!tmp) {
27551                processUrlStyled(tmp);
27552                i += 1;
27553                tmp = urlhyphenEls[i];
27554            }
27555        }
27556        if (elements.counters[0] === 0) {
27557            //nothing to hyphenate or all hyphenated by css3
27558            i = 0;
27559            while (i < CSSEditors.length) {
27560                CSSEditors[i].clearChanges();
27561                i += 1;
27562            }
27563            onHyphenationDone(contextWindow.location.href);
27564        }
27565    }
27566
27567    /**
27568     * @method Hyphenator~createCharMap
27569     * @desc
27570     * reads the charCodes from lo.characters and stores them in a bidi map:
27571     * charMap.int2code =  [0: 97, //a
27572     *                      1: 98, //b
27573     *                      2: 99] //c etc.
27574     * charMap.code2int = {"97": 0, //a
27575     *                     "98": 1, //b
27576     *                     "99": 2} //c etc.
27577     * @access private
27578     * @param {Object} language object
27579     */
27580    function makeCharMap() {
27581        var int2code = [],
27582            code2int = {},
27583            add = function (newValue) {
27584                if (!code2int[newValue]) {
27585                    int2code.push(newValue);
27586                    code2int[newValue] = int2code.length - 1;
27587                }
27588            };
27589        return {
27590            int2code: int2code,
27591            code2int: code2int,
27592            add: add
27593        };
27594    }
27595
27596    /**
27597     * @constructor Hyphenator~ValueStore
27598     * @desc Storage-Object for storing hyphenation points (aka values)
27599     * @access private
27600     */
27601    function makeValueStore(len) {
27602        var indexes = (function () {
27603                var arr;
27604                if (Object.prototype.hasOwnProperty.call(window, "Uint32Array")) { //IE<9 doesn"t have window.hasOwnProperty (host object)
27605                    arr = new window.Uint32Array(3);
27606                    arr[0] = 1; //start position of a value set
27607                    arr[1] = 1; //next index
27608                    arr[2] = 1; //last index with a significant value
27609                } else {
27610                    arr = [1, 1, 1];
27611                }
27612                return arr;
27613            }()),
27614            keys = (function () {
27615                var i, r;
27616                if (Object.prototype.hasOwnProperty.call(window, "Uint8Array")) { //IE<9 doesn"t have window.hasOwnProperty (host object)
27617                    return new window.Uint8Array(len);
27618                }
27619                r = [];
27620                r.length = len;
27621                i = r.length - 1;
27622                while (i >= 0) {
27623                    r[i] = 0;
27624                    i -= 1;
27625                }
27626                return r;
27627            }()),
27628            add = function (p) {
27629                keys[indexes[1]] = p;
27630                indexes[2] = indexes[1];
27631                indexes[1] += 1;
27632            },
27633            add0 = function () {
27634                //just do a step, since array is initialized with zeroe
27634s
27635                indexes[1] += 1;
27636            },
27637            finalize = function () {
27638                var start = indexes[0];
27639                keys[indexes[2] + 1] = 255; //mark end of pattern
27640                indexes[0] = indexes[2] + 2;
27641                indexes[1] = indexes[0];
27642                return start;
27643            };
27644        return {
27645            keys: keys,
27646            add: add,
27647            add0: add0,
27648            finalize: finalize
27649        };
27650    }
27651
27652    /**
27653     * @method Hyphenator~convertPatternsToArray
27654     * @desc
27655     * converts the patterns to a (typed, if possible) array as described by Liang:
27656     *
27657     * 1. Create the CharMap: an alphabet of used character codes mapped to an int (e.g. a: "97" -> 0)
27658     *    This map is bidirectional:
27659     *    charMap.code2int is an object with charCodes as keys and corresponging ints as values
27660     *    charMao.int2code is an array of charCodes at int indizes
27661     *    the length of charMao.int2code is equal the length of the alphabet
27662     *
27663     * 2. Create a ValueStore: (typed) array that holds "values", i.e. the digits extracted from the patterns
27664     *    The first value set starts at index 1 (since the trie is initialized with zeroes, starting at 0 would create errors)
27665     *    Each value set ends with a value of 255; trailing 0"s are not stored. So pattern values like e.g. "010200" will become […,0,1,0,2,255,…]
27666     *    The ValueStore-Object manages handling of indizes automatically. Use ValueStore.add(p) to add a running value.
27667     *    Use ValueStore.finalize() when the last value of a pattern is added. It will add the final 255, prepare the valueStore for new values
27668     *    and return the starting index of the pattern.
27669     *    To prevent doubles we could temporarly store the values in a object {value: startIndex} and only add new values,
27670     *    but this object deoptimizes very fast (new hidden map for each entry); here we gain speed and pay memory
27671     *
27672     * 3. Create and zero initialize a (typed) array to store the trie. The trie uses two slots for each entry/node:
27673     *    i: a link to another position in the array or -1 if the pattern ends here or more rows have to be added.
27674     *    i + 1: a link to a value in the ValueStore or 0 if there"s no value for the path to this node.
27675     *    Although the array is one-dimensional it can be described as an array of "rows",
27676     *    where each "row" is an array of length trieRowLength (see below).
27677     *    The first entry of this "row" represents the first character of the alphabet, the second a possible link to value store,
27678     *    the third represents the second character of the alphabet and so on…
27679     *
27680     * 4. Initialize trieRowLength (length of the alphabet * 2)
27681     *
27682     * 5. Now we apply extract to each pattern collection (patterns of the same length are collected and concatenated to one string)
27683     *    extract goes through these pattern collections char by char and adds them either to the ValueStore (if they are digits) or
27684     *    to the trie (adding more "rows" if necessary, i.e. if the last link pointed to -1).
27685     *    So the first "row" holds all starting characters, where the subsequent rows hold the characters that follow the
27686     *    character that link to this row. Therefor the array is dense at the beginning and very sparse at the end.
27687     *
27688     *
27689     * @access private
27690     * @param {Object} language object
27691     */
27692    function convertPatternsToArray(lo) {
27693        var trieNextEmptyRow = 0,
27694            i,
27695            charMapc2i,
27696            valueStore,
27697            indexedTrie,
27698            trieRowLength,
27699
27700            extract = function (patternSizeInt, patterns) {
27701                var charPos = 0,
27702                    charCode = 0,
27703                    mappedCharCode = 0,
27704                    rowStart = 0,
27705                    nextRowStart = 0,
27706                    prevWasDigit = false;
27707                while (charPos < patterns.length) {
27708                    charCode = patterns.charCodeAt(charPos);
27709                    if ((charPos + 1) % patternSizeInt !== 0) {
27710                        //more to come…
27711                        if (charCode <= 57 && charCode >= 49) {
27712                            //charCode is a digit
27713                            valueStore.add(charCode - 48);
27714                            prevWasDigit = true;
27715                        } else {
27716                            //charCode is alphabetical
27717                            if (!prevWasDigit) {
27718                                valueStore.add0();
27719                            }
27720                            prevWasDigit = false;
27721                            if (nextRowStart === -1) {
27722                                nextRowStart = trieNextEmptyRow + trieRowLength;
27723                                trieNextEmptyRow = nextRowStart;
27724                                indexedTrie[rowStart + mappedCharCode * 2] = nextRowStart;
27725                            }
27726                            mappedCharCode = charMapc2i[charCode];
27727                            rowStart = nextRowStart;
27728                            nextRowStart = indexedTrie[rowStart + mappedCharCode * 2];
27729                            if (nextRowStart === 0) {
27730                                indexedTrie[rowStart + mappedCharCode * 2] = -1;
27731                                nextRowStart = -1;
27732                            }
27733                        }
27734                    } else {
27735                        //last part of pattern
27736                        if (charCode <= 57 && charCode >= 49) {
27737                            //the last charCode is a digit
27738                            valueStore.add(charCode - 48);
27739                            indexedTrie[rowStart + mappedCharCode * 2 + 1] = valueStore.finalize();
27740                        } else {
27741                            //the last charCode is alphabetical
27742                            if (!prevWasDigit) {
27743                                valueStore.add0();
27744                            }
27745                            valueStore.add0();
27746                            if (nextRowStart === -1) {
27747                                nextRowStart = trieNextEmptyRow + trieRowLength;
27748                                trieNextEmptyRow = nextRowStart;
27749                                indexedTrie[rowStart + mappedCharCode * 2] = nextRowStart;
27750                            }
27751                            mappedCharCode = charMapc2i[charCode];
27752                            rowStart = nextRowStart;
27753                            if (indexedTrie[rowStart + mappedCharCode * 2] === 0) {
27754                                indexedTrie[rowStart + mappedCharCode * 2] = -1;
27755                            }
27756                            indexedTrie[rowStart + mappedCharCode * 2 + 1] = valueStore.finalize();
27757                        }
27758                        rowStart = 0;
27759                        nextRowStart = 0;
27760                        prevWasDigit = false;
27761                    }
27762                    charPos += 1;
27763                }
27764            };/*,
27765         prettyPrintIndexedTrie = function (rowLength) {
27766         var s = "0: ",
27767         idx;
27768         for (idx = 0; idx < indexedTrie.length; idx += 1) {
27769         s += indexedTrie[idx];
27770         s += ",";
27771         if ((idx + 1) % rowLength === 0) {
27772         s += "\n" + (idx + 1) + ": ";
27773         }
27774         }
27775         console.log(s);
27776         };*/
27777
27778        lo.charMap = makeCharMap();
27779        i = 0;
27780        while (i < lo.patternChars.length) {
27781            lo.charMap.add(lo.patternChars.charCodeAt(i));
27782            i += 1;
27783        }
27784        charMapc2i = lo.charMap.code2int;
27785
27786        valueStore = makeValueStore(lo.valueStoreLength);
27787        lo.valueStore = valueStore;
27788
27789        if (Object.prototype.hasOwnProperty.call(window, "Int32Array")) { //IE<9 doesn"t have window.hasOwnProperty (host object)
27790            lo.indexedTrie = new window.Int32Array(lo.patternArrayLength * 2);
27791        } else {
27792            lo.indexedTrie = [];
27793            lo.indexedTrie.length = lo.patternArrayLength * 2;
27794            i = lo.indexedTrie.length - 1;
27795            while (i >= 0) {
27796                lo.indexedTrie[i] = 0;
27797                i -= 1;
27798            }
27799        }
27800        indexedTrie = lo.indexedTrie;
27801        trieRowLength = lo.charMap.int2code.length * 2;
27802
27803        forEachKey(lo.patterns, function (i) {
27804            extract(parseInt(i, 10), lo.patterns[i]);
27805        });
27806        //prettyPrintIndexedTrie(lo.charMap.int2code.length * 2);
27807    }
27808
27809    /**
27810     * @method Hyphenator~recreatePattern
27811     * @desc
27812     * Recreates the pattern for the reducedPatternSet
27813     * @param {string} pattern The pattern (chars)
27814     * @param {string} nodePoints The nodePoints (integers)
27815     * @access private
27816     * @return {string} The pattern (chars and numbers)
27817     */
27818    function recreatePattern(pattern, nodePoints) {
27819        var r = [],
27820            c = pattern.split(""),
27821            i = 0;
27822        while (i <= c.length) {
27823            if (nodePoints[i] && nodePoints[i] !== 0) {
27824                r.push(nodePoints[i]);
27825            }
27826            if (c[i]) {
27827                r.push(c[i]);
27828            }
27829            i += 1;
27830        }
27831        return r.join("");
27832    }
27833
27834    /**
27835     * @method Hyphenator~convertExceptionsToObject
27836     * @desc
27837     * Converts a list of comma seprated exceptions to an object:
27838     * "Fortran,Hy-phen-a-tion" -> {"Fortran":"Fortran","Hyphenation":"Hy-phen-a-tion"}
27839     * @access private
27840     * @param {string} exc a comma separated string of exceptions (without spaces)
27841     * @return {Object.<string, string>}
27842     */
27843    function convertExceptionsToObject(exc) {
27844        var w = exc.split(", "),
27845            r = {},
27846            i = 0,
27847            l = w.length,
27848            key;
27849        while (i < l) {
27850            key = w[i].replace(/-/g, "");
27851            if (!r.hasOwnProperty(key)) {
27852                r[key] = w[i];
27853            }
27854            i += 1;
27855        }
27856        return r;
27857    }
27858
27859    /**
27860     * @method Hyphenator~loadPatterns
27861     * @desc
27862     * Checks if the requested file is available in the network.
27863     * Adds a &lt;script&gt;-Tag to the DOM to load an externeal .js-file containing patterns and settings for the given language.
27864     * If the given language is not in the {@link Hyphenator~supportedLangs}-Object it returns.
27865     * One may ask why we are not using AJAX to load the patterns. The XMLHttpRequest-Object
27866     * has a same-origin-policy. This makes the Bookmarklet impossible.
27867     * @param {string} lang The language to load the patterns for
27868     * @access private
27869     * @see {@link Hyphenator~basePath}
27870     */
27871    function loadPatterns(lang, cb) {
27872        var location, xhr, head, script, done = false;
27873        function getXHRforIElt6() {
27874            try {
27875                //IE>=5
27876                xhr = new window.ActiveXObject("Msxml2.XMLHTTP");
27877            } catch (ignore) {
27878                xhr = null;
27879            }
27880        }
27881        function getXHRforIElt10() {
27882            try {
27883                //IE>=6
27884                xhr = new window.ActiveXObject("Microsoft.XMLHTTP");
27885            } catch (ignore) {
27886                getXHRforIElt6();
27887            }
27888        }
27889        if (supportedLangs.hasOwnProperty(lang) && !Hyphenator.languages[lang]) {
27890            location = basePath + "patterns/" + supportedLangs[lang].file;
27891        } else {
27892            return;
27893        }
27894        if (isLocal && !isBookmarklet) {
27895            //check if "location" is available:
27896            xhr = null;
27897            try {
27898                // Mozilla, Opera, Safari and Internet Explorer (ab v7)
27899                xhr = new window.XMLHttpRequest();
27900            } catch (ignore) {
27901                getXHRforIElt10();
27902            }
27903
27904            if (xhr) {
27905                xhr.open("HEAD", location, true);
27906                xhr.setRequestHeader("Cache-Control", "no-cache");
27907                xhr.onreadystatechange = function () {
27908                    if (xhr.readyState === 2) {
27909                        if (xhr.status >= 400) {
27910                            onError(new Error("Could not load\n" + location));
27911                            delete docLanguages[lang];
27912                            return;
27913                        }
27914                        xhr.abort();
27915                    }
27916                };
27917                xhr.send(null);
27918            }
27919        }
27920        if (createElem) {
27921            head = window.document.getElementsByTagName("head").item(0);
27922            script = createElem("script", window);
27923            script.src = location;
27924            script.type = "text/javascript";
27925            script.charset = "utf8";
27926            script.onreadystatechange = function () {
27927                if (!done && (!script.readyState || script.readyState === "loaded" || script.readyState === "complete")) {
27928                    done = true;
27929
27930                    cb();
27931
27932                    // Handle memory leak in IE
27933                    script.onreadystatechange = null;
27934                    script.onload = null;
27935                    if (head && script.parentNode) {
27936                        head.removeChild(script);
27937                    }
27938                }
27939            };
27940            script.onload = script.onreadystatechange;
27941            head.appendChild(script);
27942        }
27943    }
27944
27945    /**
27946     * @method Hyphenator~createWordRegExp
27947     * @desc
27948     * build a regexp string for finding a word of a given languate
27949     * @access private
27950     * @param {string} lang The language
27951     * @return {string}
27952     */
27953    function createWordRegExp(lang) {
27954        var lo = Hyphenator.languages[lang],
27955            wrd = "";
27956        if (String.prototype.normalize) {
27957            wrd = "[\\w" + lo.specialChars + lo.specialChars.normalize("NFD") + hyphen + String.fromCharCode(8204) + "-]{" + min + ",}(?!:\\/\\/)";
27958        } else {
27959            wrd = "[\\w" + lo.specialChars + hyphen + String.fromCharCode(8204) + "-]{" + min + ",}(?!:\\/\\/)";
27960        }
27961        return wrd;
27962    }
27963
27964    /**
27965     * @method Hyphenator~prepareLanguagesObj
27966     * @desc
27967     * Adds some feature to the language object:
27968     * - cache
27969     * - exceptions
27970     * Converts the patterns to a trie using {@link Hyphenator~convertPatterns}
27970
27971     * @access private
27972     * @param {string} lang The language of the language object
27973     */
27974    function prepareLanguagesObj(lang) {
27975        var lo = Hyphenator.languages[lang];
27976
27977        if (!lo.prepared) {
27978            if (enableCache) {
27979                lo.cache = {};
27980                //Export
27981                //lo["cache"] = lo.cache;
27982            }
27983            if (enableReducedPatternSet) {
27984                lo.redPatSet = {};
27985            }
27986            if (leftmin > lo.leftmin) {
27987                lo.leftmin = leftmin;
27988            }
27989            if (rightmin > lo.rightmin) {
27990                lo.rightmin = rightmin;
27991            }
27992            //add exceptions from the pattern file to the local "exceptions"-obj
27993            if (lo.hasOwnProperty("exceptions")) {
27994                Hyphenator.addExceptions(lang, lo.exceptions);
27995                delete lo.exceptions;
27996            }
27997            //copy global exceptions to the language specific exceptions
27998            if (exceptions.hasOwnProperty("global")) {
27999                if (exceptions.hasOwnProperty(lang)) {
28000                    exceptions[lang] += ", " + exceptions.global;
28001                } else {
28002                    exceptions[lang] = exceptions.global;
28003                }
28004            }
28005            //move exceptions from the the local "exceptions"-obj to the "language"-object
28006            if (exceptions.hasOwnProperty(lang)) {
28007                lo.exceptions = convertExceptionsToObject(exceptions[lang]);
28008                delete exceptions[lang];
28009            } else {
28010                lo.exceptions = {};
28011            }
28012            convertPatternsToArray(lo);
28013            lo.genRegExp = new RegExp("(" + createWordRegExp(lang) + ")|(" + url + ")|(" + mail + ")", "gi");
28014            lo.prepared = true;
28015        }
28016    }
28017
28018    /****
28019     * @method Hyphenator~prepare
28020     * @desc
28021     * This funtion prepares the Hyphenator~Object: If RemoteLoading is turned off, it assumes
28022     * that the patternfiles are loaded, all conversions are made and the callback is called.
28023     * If storage is active the object is retrieved there.
28024     * If RemoteLoading is on (default), it loads the pattern files and repeatedly checks Hyphenator.languages.
28025     * If a patternfile is loaded the patterns are stored in storage (if enabled),
28026     * converted to their object style and the lang-object extended.
28027     * Finally the callback is called.
28028     * @access private
28029     */
28030    function prepare(callback) {
28031        var tmp1;
28032
28033        function languagesLoaded() {
28034            forEachKey(docLanguages, function (l) {
28035                if (Hyphenator.languages.hasOwnProperty(l)) {
28036                    delete docLanguages[l];
28037                    if (!!storage) {
28038                        storage.setItem(l, window.JSON.stringify(Hyphenator.languages[l]));
28039                    }
28040                    prepareLanguagesObj(l);
28041                    callback(l);
28042                }
28043            });
28044        }
28045
28046        if (!enableRemoteLoading) {
28047            forEachKey(Hyphenator.languages, function (lang) {
28048                prepareLanguagesObj(lang);
28049            });
28050            callback("*");
28051            return;
28052        }
28053        callback("urlstyled");
28054        // get all languages that are used and preload the patterns
28055        forEachKey(docLanguages, function (lang) {
28056            if (!!storage && storage.test(lang)) {
28057                Hyphenator.languages[lang] = window.JSON.parse(storage.getItem(lang));
28058                prepareLanguagesObj(lang);
28059                if (exceptions.hasOwnProperty("global")) {
28060                    tmp1 = convertExceptionsToObject(exceptions.global);
28061                    forEachKey(tmp1, function (tmp2) {
28062                        Hyphenator.languages[lang].exceptions[tmp2] = tmp1[tmp2];
28063                    });
28064                }
28065                //Replace exceptions since they may have been changed:
28066                if (exceptions.hasOwnProperty(lang)) {
28067                    tmp1 = convertExceptionsToObject(exceptions[lang]);
28068                    forEachKey(tmp1, function (tmp2) {
28069                        Hyphenator.languages[lang].exceptions[tmp2] = tmp1[tmp2];
28070                    });
28071                    delete exceptions[lang];
28072                }
28073                //Replace genRegExp since it may have been changed:
28074                Hyphenator.languages[lang].genRegExp = new RegExp("(" + createWordRegExp(lang) + ")|(" + url + ")|(" + mail + ")", "gi");
28075                if (enableCache) {
28076                    if (!Hyphenator.languages[lang].cache) {
28077                        Hyphenator.languages[lang].cache = {};
28078                    }
28079                }
28080                delete docLanguages[lang];
28081                callback(lang);
28082            } else {
28083                loadPatterns(lang, languagesLoaded);
28084            }
28085        });
28086        //call languagesLoaded in case language has been loaded manually
28087        //and remoteLoading is on (onload won"t fire)
28088        languagesLoaded();
28089    }
28090
28091    /**
28092     * @method Hyphenator~toggleBox
28093     * @desc
28094     * Creates the toggleBox: a small button to turn off/on hyphenation on a page.
28095     * @see {@link Hyphenator.config}
28096     * @access private
28097     */
28098    var toggleBox = function () {
28099        var bdy,
28100            myTextNode,
28101            text = (Hyphenator.doHyphenation
28102                ? "Hy-phen-a-tion"
28103                : "Hyphenation"),
28104            myBox = contextWindow.document.getElementById("HyphenatorToggleBox");
28105        if (!!myBox) {
28106            myBox.firstChild.data = text;
28107        } else {
28108            bdy = contextWindow.document.getElementsByTagName("body")[0];
28109            myBox = createElem("div", contextWindow);
28110            myBox.setAttribute("id", "HyphenatorToggleBox");
28111            myBox.setAttribute("class", dontHyphenateClass);
28112            myTextNode = contextWindow.document.createTextNode(text);
28113            myBox.appendChild(myTextNode);
28114            myBox.onclick = Hyphenator.toggleHyphenation;
28115            myBox.style.position = "absolute";
28116            myBox.style.top = "0px";
28117            myBox.style.right = "0px";
28118            myBox.style.zIndex = "1000";
28119            myBox.style.margin = "0";
28120            myBox.style.backgroundColor = "#AAAAAA";
28121            myBox.style.color = "#FFFFFF";
28122            myBox.style.font = "6pt Arial";
28123            myBox.style.letterSpacing = "0.2em";
28124            myBox.style.padding = "3px";
28125            myBox.style.cursor = "pointer";
28126            myBox.style.WebkitBorderBottomLeftRadius = "4px";
28127            myBox.style.MozBorderRadiusBottomleft = "4px";
28128            myBox.style.borderBottomLeftRadius = "4px";
28129            bdy.appendChild(myBox);
28130        }
28131    };
28132
28133    /**
28134     * @method Hyphenator~doCharSubst
28135     * @desc
28136     * Replace chars in a word
28137     *
28138     * @param {Object} loCharSubst Map of substitutions ({"ä": "a", "ü": "u", …})
28139     * @param {string} w the word
28140     * @returns string The word with substituted characers
28141     * @access private
28142     */
28143    function doCharSubst(loCharSubst, w) {
28144        var r = w;
28145        forEachKey(loCharSubst, function (subst) {
28146            r = r.replace(new RegExp(subst, "g"), loCharSubst[subst]);
28147        });
28148        return r;
28149    }
28150
28151    /**
28152     * @member {Array} Hyphenator~wwAsMappedCharCodeStore
28153     * @desc
28154     * Array (typed if supported) container for charCodes
28155     * @access private
28156     * @see {@link Hyphenator~hyphenateWord}
28157     */
28158    var wwAsMappedCharCodeStore = (function () {
28159        if (Object.prototype.hasOwnProperty.call(window, "Int32Array")) {
28160            return new window.Int32Array(64);
28161        }
28162        return [];
28163    }());
28164
28165    /**
28166     * @member {Array} Hyphenator~wwhpStore
28167     * @desc
28168     * Array (typed if supported) container for hyphenation points
28169     * @access private
28170     * @see {@link Hyphenator~hyphenateWord}
28171     */
28172    var wwhpStore = (function () {
28173        var r;
28174        if (Object.prototype.hasOwnProperty.call(window, "Uint8Array")) {
28175            r = new window.Uint8Array(64);
28176        } else {
28177            r = [];
28178        }
28179        return r;
28180    }());
28181
28182    /**
28183     * @method Hyphenator~hyphenateCompound
28184     * @desc
28185     * Treats compound words accordingly to the "compound" setting
28186     *
28187     * @param {Object} lo A language object (containing the patterns)
28188     * @param {string} lang The language of the word
28189     * @param {string} word The word
28190     * @returns string The (hyphenated) compound word
28191     * @access private
28192     */
28193    function hyphenateCompound(lo, lang, word) {
28194        var hw, parts, i = 0;
28195        switch (compound) {
28196            case "auto":
28197                parts = word.split("-");
28198                while (i < parts.length) {
28199                    if (parts[i].length >= min) {
28200                        parts[i] = hyphenateWord(lo, lang, parts[i]);
28201                    }
28202                    i += 1;
28203                }
28204                hw = parts.join("-");
28205                break;
28206            case "all":
28207                parts = word.split("-");
28208                while (i < parts.length) {
28209                    if (parts[i].length >= min) {
28210                        parts[i] = hyphenateWord(lo, lang, parts[i]);
28211                    }
28212                    i += 1;
28213                }
28214                hw = parts.join("-" + zeroWidthSpace);
28215                break;
28216            case "hyphen":
28217                hw = word.replace("-", "-" + zeroWidthSpace);
28218                break;
28219            default:
28220                onError(new Error("Hyphenator.settings: compound setting \"" + compound + "\" not known."));
28221        }
28222        return hw;
28223    }
28224
28225    /**
28226     * @method Hyphenator~hyphenateWord
28227     * @desc
28228     * This function is the heart of Hyphenator.js. It returns a hyphenated word.
28229     *
28230     * If there"s already a {@link Hyphenator~hypen} in the word, the word is returned as it is.
28231     * If the word is in the exceptions list or in the cache, it is retrieved from it.
28232     * If there"s a "-" it calls Hyphenator~hyphenateCompound
28233     * The hyphenated word is returned and (if acivated) cached.
28234     * Both special Events onBeforeWordHyphenation and onAfterWordHyphenation are called for the word.
28235     * @param {Object} lo A language object (containing the patterns)
28236     * @param {string} lang The language of the word
28237     * @param {string} word The word
28238     * @returns string The hyphenated word
28239     * @access private
28240     */
28241    function hyphenateWord(lo, lang, word) {
28242        var pattern = "",
28243            ww,
28244            wwlen,
28245            wwhp = wwhpStore,
28246            pstart = 0,
28247            plen,
28248            hp,
28249            hpc,
28250            wordLength = word.length,
28251            hw = "",
28252            charMap = lo.charMap.code2int,
28253            charCode,
28254            mappedCharCode,
28255            row = 0,
28256            link = 0,
28257            value = 0,
28258            values,
28259            indexedTrie = lo.indexedTrie,
28260            valueStore = lo.valueStore.keys,
28261            wwAsMappedCharCode = wwAsMappedCharCodeStore;
28262        word = onBeforeWordHyphenation(word, lang);
28263        if (word === "") {
28264            hw = "";
28265        } else if (enableCache && lo.cache && lo.cache.hasOwnProperty(word)) { //the word is in the cache
28266            hw = lo.cache[word];
28267        } else if (word.indexOf(hyphen) !== -1) {
28268            //word already contains shy; -> leave at it is!
28269            hw = word;
28270        } else if (lo.exceptions.hasOwnProperty(word)) { //the word is in the exceptions list
28271            hw = lo.exceptions[word].replace(/-/g, hyphen);
28272        } else if (word.indexOf("-") !== -1) {
28273            hw = hyphenateCompound(lo, lang, word);
28274        } else {
28275            ww = word.toLowerCase();
28276            if (String.prototype.normalize) {
28277                ww = ww.normalize("NFC");
28278            }
28279            if (lo.hasOwnProperty("charSubstitution")) {
28280                ww = doCharSubst(lo.charSubstitution, ww);
28281            }
28282            if (word.indexOf("'") !== -1) {
28283                ww = ww.replace(/'/g, "’"); //replace APOSTROPHE with RIGHT SINGLE QUOTATION MARK (since the latter is used in the patterns)
28284            }
28285            ww = "_" + ww + "_";
28286            wwlen = ww.length;
28287            //prepare wwhp and wwAsMappedCharCode
28288            while (pstart < wwlen) {
28289                wwhp[pstart] = 0;
28290                charCode = ww.charCodeAt(pstart);
28291                wwAsMappedCharCode[pstart] = charMap.hasOwnProperty(charCode)
28292                    ? charMap[charCode]
28293                    : -1;
28294                pstart += 1;
28295            }
28296            //get hyphenation points for all substrings
28297            pstart = 0;
28298            while (pstart < wwlen) {
28299                row = 0;
28300                pattern = "";
28301                plen = pstart;
28302                while (plen < wwlen) {
28303                    mappedCharCode = wwAsMappedCharCode[plen];
28304                    if (mappedCharCode === -1) {
28305                        break;
28306                    }
28307                    if (enableReducedPatternSet) {
28308                        pattern += ww.charAt(plen);
28309                    }
28310                    link = indexedTrie[row + mappedCharCode * 2];
28311                    value = indexedTrie[row + mappedCharCode * 2 + 1];
28312                    if (value > 0) {
28313                        hpc = 0;
28314                        hp = valueStore[value + hpc];
28315                        while (hp !== 255) {
28316                            if (hp > wwhp[pstart + hpc]) {
28317                                wwhp[pstart + hpc] = hp;
28318                            }
28319                            hpc += 1;
28320                            hp = valueStore[value + hpc];
28321                        }
28322                        if (enableReducedPatternSet) {
28323                            if (!lo.redPatSet) {
28324                                lo.redPatSet = {};
28325                            }
28326                            if (valueStore.subarray) {
28327                                values = valueStore.subarray(value, value + hpc);
28328                            } else {
28329                                values = valueStore.slice(value, value + hpc);
28330                            }
28331                            lo.redPatSet[pattern] = recreatePattern(pattern, values);
28332                        }
28333                    }
28334                    if (link > 0) {
28335                        row = link;
28336                    } else {
28337                        break;
28338                    }
28339                    plen += 1;
28340                }
28341                pstart += 1;
28342            }
28343            //create hyphenated word
28344            hp = 0;
28345            while (hp < wordLength) {
28346                if (hp >= lo.leftmin && hp <= (wordLength - lo.rightmin) && (wwhp[hp + 1] % 2) !== 0) {
28347                    hw += hyphen + word.charAt(hp);
28348                } else {
28349                    hw += word.charAt(hp);
28350                }
28351                hp += 1;
28352            }
28353        }
28354        hw = onAfterWordHyphenation(hw, lang);
28355        if (enableCache) { //put the word in the cache
28356            lo.cache[word] = hw;
28357        }
28358        return hw;
28359    }
28360
28361
28362    /**
28363     * @method Hyphenator~checkIfAllDone
28364     * @desc
28365     * Checks if all elements in {@link Hyphenator~elements} are hyphenated, unhides them and fires onHyphenationDone()
28366     * @access private
28367     */
28368    function checkIfAllDone() {
28369        var allDone = true,
28370            i = 0,
28371            doclist = {};
28372        elements.each(function (ellist) {
28373            var j = 0,
28374                l = ellist.length;
28375            while (j < l) {
28376                allDone = allDone && ellist[j].hyphenated;
28377                if (!doclist.hasOwnProperty(ellist[j].element.baseURI)) {
28378                    doclist[ellist[j].element.ownerDocument.location.href] = true;
28379                }
28380                doclist[ellist[j].element.ownerDocument.location.href] = doclist[ellist[j].element.ownerDocument.location.href] && ellist[j].hyphenated;
28381                j += 1;
28382            }
28383        });
28384        if (allDone) {
28385            if (intermediateState === "hidden" && unhide === "progressive") {
28386                elements.each(function (ellist) {
28387                    var j = 0,
28388                        l = ellist.length,
28389                        el;
28390                    while (j < l) {
28391                        el = ellist[j].element;
28392                        el.className = el.className.replace(unhideClassRegExp, "");
28393                        if (el.className === "") {
28394                            el.removeAttribute("class");
28395                        }
28396                        j += 1;
28397                    }
28398                });
28399            }
28400            while (i < CSSEditors.length) {
28401                CSSEditors[i].clearChanges();
28402                i += 1;
28403            }
28404            forEachKey(doclist, function (doc) {
28405                onHyphenationDone(doc);
28406            });
28407            if (!!storage && storage.deferred.length > 0) {
28408                i = 0;
28409                while (i < storage.deferred.length) {
28410                    storage.deferred[i].call();
28411                    i += 1;
28412                }
28413                storage.deferred = [];
28414            }
28415        }
28416    }
28417
28418    /**
28419     * @method Hyphenator~controlOrphans
28420     * @desc
28421     * removes orphans depending on the "orphanControl"-setting:
28422     * orphanControl === 1: do nothing
28423     * orphanControl === 2: prevent last word to be hyphenated
28424     * orphanControl === 3: prevent one word on a last line (inserts a nobreaking space)
28425     * @param {string} part - The sring where orphans have to be removed
28426     * @access private
28427     */
28428    function controlOrphans(ignore, leadingWhiteSpace, lastWord, trailingWhiteSpace) {
28429        var h = hyphen;
28430        //escape hyphen
28431        if (".\\+*?[^]$(){}=!<>|:-".indexOf(hyphen) !== -1) {
28432            h = "\\" + hyphen;
28433        } else {
28434            h = hyphen;
28435        }
28436        if (orphanControl === 3 && leadingWhiteSpace === " ") {
28437            leadingWhiteSpace = String.fromCharCode(160);
28438        }
28439        return leadingWhiteSpace + lastWord.replace(new RegExp(h + "|" + zeroWidthSpace, "g"), "") + trailingWhiteSpace;
28440    }
28441
28442    /**
28443     * @method Hyphenator~hyphenateElement
28444     * @desc
28445     * Takes the content of the given element and - if there"s text - replaces the words
28446     * by hyphenated words. If there"s another element, the function is called recursively.
28447     * When all words are hyphenated, the visibility of the element is set to "visible".
28448     * @param {string} lang - The language-code of the element
28449     * @param {Element} elo - The element to hyphenate {@link Hyphenator~elements~ElementCollection~Element}
28450     * @access private
28451     */
28452    function hyphenateElement(lang, elo) {
28453        var el = elo.element,
28454            hyphenate,
28455            n,
28456            i,
28457            lo;
28458        if (lang === "urlstyled" && Hyphenator.doHyphenation) {
28459            i = 0;
28460            n = el.childNodes[i];
28461            while (!!n) {
28462                if (
28463                    n.nodeType === 3 //type 3 = #text
28464                    && (/\S/).test(n.data)
28465                ) { //not just white space
28466                    n.data = hyphenateURL(n.data);
28467                }
28468                i += 1;
28469                n = el.childNodes[i];
28470            }
28471        } else if (Hyphenator.languages.hasOwnProperty(lang) && Hyphenator.doHyphenation) {
28472            lo = Hyphenator.languages[lang];
28473            hyphenate = function (match, word, url, mail) {
28474                var r;
28475                if (!!url || !!mail) {
28476                    r = hyphenateURL(match);
28477                } else {
28478                    r = hyphenateWord(lo, lang, word);
28479                }
28480                return r;
28481            };
28482            i = 0;
28483            n = el.childNodes[i];
28484            while (!!n) {
28485                if (
28486                    n.nodeType === 3 //type 3 = #text
28487                    && (/\S/).test(n.data) //not just white space
28488                    && n.data.length >= min
28489                ) { //longer then min
28490                    n.data = n.data.replace(lo.genRegExp, hyphenate);
28491                    if (orphanControl !== 1) {
28492                        //prevent last word from being hyphenated
28493                        n.data = n.data.replace(/(\u0020*)(\S+)(\s*)$/, controlOrphans);
28494                    }
28495                }
28496                i += 1;
28497                n = el.childNodes[i];
28498            }
28499        }
28500        if (intermediateState === "hidden" && unhide === "wait") {
28501            el.className = el.className.replace(hideClassRegExp, "");
28502            if (el.className === "") {
28503                el.removeAttribute("class");
28504            }
28505        }
28506        if (intermediateState === "hidden" && unhide === "progressive") {
28507            el.className = el.className.replace(hideClassRegExp, " " + unhideClass);
28508        }
28509        elo.hyphenated = true;
28510        elements.counters[1] += 1;
28511        if (elements.counters[0] <= elements.counters[1]) {
28512            checkIfAllDone();
28513        }
28514    }
28515
28516    /**
28517     * @method Hyphenator~hyphenateLanguageElements
28518     * @desc
28519     * Calls hyphenateElement() for all elements of the specified language.
28520     * If the language is "*" then all elements are hyphenated.
28521     * This is done with a setTimout
28522     * to prevent a "long running Script"-alert when hyphenating large pages.
28523     * Therefore a tricky bind()-function was necessary.
28524     * @param {string} lang The language of the elements to hyphenate
28525     * @access private
28526     */
28527
28528    function hyphenateLanguageElements(lang) {
28529        /*function bind(fun, arg1, arg2) {
28530         return function () {
28531         return fun(arg1, arg2);
28532         };
28533         }*/
28534        var i = 0,
28535            l;
28536        if (lang === "*") {
28537            elements.each(function (lang, ellist) {
28538                var j = 0,
28539                    le = ellist.length;
28540                while (j < le) {
28541                    //zeroTimeOut(bind(hyphenateElement, lang, ellist[j]));
28542                    hyphenateElement(lang, ellist[j]);
28543                    j += 1;
28544                }
28545            });
28546        } else {
28547            if (elements.list.hasOwnProperty(lang)) {
28548                l = elements.list[lang].length;
28549                while (i < l) {
28550                    //zeroTimeOut(bind(hyphenateElement, lang, elements.list[lang][i]));
28551                    hyphenateElement(lang, elements.list[lang][i]);
28552                    i += 1;
28553                }
28554            }
28555        }
28556    }
28557
28558    /**
28559     * @method Hyphenator~removeHyphenationFromDocument
28560     * @desc
28561     * Does what it says and unregisters the onCopyEvent from the elements
28562     * @access private
28563     */
28564    function removeHyphenationFromDocument() {
28565        elements.each(function (ellist) {
28566            var i = 0,
28567                l = ellist.length;
28568            while (i < l) {
28569                removeHyphenationFromElement(ellist[i].element);
28570                ellist[i].hyphenated = false;
28571                i += 1;
28572            }
28573        });
28574    }
28575
28576    /**
28577     * @method Hyphenator~createStorage
28578     * @desc
28579     * inits the private var {@link Hyphenator~storage) depending of the setting in {@link Hyphenator~storageType}
28580     * and the supported features of the system.
28581     * @access private
28582     */
28583    function createStorage() {
28584        var s;
28585        function makeStorage(s) {
28586            var store = s,
28587                prefix = "Hyphenator_" + Hyphenator.version + "_",
28588                deferred = [],
28589                test = function (name) {
28590                    var val = store.getItem(prefix + name);
28591                    return !!val;
28592                },
28593                getItem = function (name) {
28594                    return store.getItem(prefix + name);
28595                },
28596                setItem = function (name, value) {
28597                    try {
28598                        store.setItem(prefix + name, value);
28599                    } catch (e) {
28600                        onError(e);
28601                    }
28602                };
28603            return {
28604                deferred: deferred,
28605                test: test,
28606                getItem: getItem,
28607                setItem: setItem
28608            };
28609        }
28610        try {
28611            if (
28612                storageType !== "none" &&
28613                window.JSON !== undefined &&
28614                window.localStorage !== undefined &&
28615                window.sessionStorage !== undefined &&
28616                window.JSON.stringify !== undefined &&
28617                window.JSON.parse !== undefined
28618            ) {
28619                switch (storageType) {
28620                    case "session":
28621                        s = window.sessionStorage;
28622                        break;
28623                    case "local":
28624                        s = window.localStorage;
28625                        break;
28626                    default:
28627                        s = undefined;
28628                }
28629                //check for private mode
28630                s.setItem("storageTest", "1");
28631                s.removeItem("storageTest");
28632            }
28633        } catch (ignore) {
28634            //FF throws an error if DOM.storage.enabled is set to false
28635            s = undefined;
28636        }
28637        if (s) {
28638            storage = makeStorage(s);
28639        } else {
28640            storage = undefined;
28641        }
28642    }
28643
28644    /**
28645     * @method Hyphenator~storeConfiguration
28646     * @desc
28647     * Stores the current config-options in DOM-Storage
28648     * @access private
28649     */
28650    function storeConfiguration() {
28651        if (!storage) {
28652            return;
28653        }
28654        var settings = {
28655            "STORED": true,
28656            "classname": hyphenateClass,
28657            "urlclassname": urlHyphenateClass,
28658            "donthyphenateclassname": dontHyphenateClass,
28659            "minwordlength": min,
28660            "hyphenchar": hyphen,
28661            "urlhyphenchar": urlhyphen,
28662            "togglebox": toggleBox,
28663            "displaytogglebox": displayToggleBox,
28664            "remoteloading": enableRemoteLoading,
28665            "enablecache": enableCache,
28666            "enablereducedpatternset": enableReducedPatternSet,
28667            "onhyphenationdonecallback": onHyphenationDone,
28668            "onerrorhandler": onError,
28669            "onwarninghandler": onWarning,
28670            "intermediatestate": intermediateState,
28671            "selectorfunction": selectorFunction || mySelectorFunction,
28672            "safecopy": safeCopy,
28673            "doframes": doFrames,
28674            "storagetype": storageType,
28675            "orphancontrol": orphanControl,
28676            "dohyphenation": Hyphenator.doHyphenation,
28677            "persistentconfig": persistentConfig,
28678            "defaultlanguage": defaultLanguage,
28679            "useCSS3hyphenation": css3,
28680            "unhide": unhide,
28681            "onbeforewordhyphenation": onBeforeWordHyphenation,
28682            "onafterwordhyphenation": onAfterWordHyphenation,
28683            "leftmin": leftmin,
28684            "rightmin": rightmin,
28685            "compound": compound
28686        };
28687        storage.setItem("config", window.JSON.stringify(settings));
28688    }
28689
28690    /**
28691     * @method Hyphenator~restoreConfiguration
28692     * @desc
28693     * Retrieves config-options from DOM-Storage and does configuration accordingly
28694     * @access private
28695     */
28696    function restoreConfiguration() {
28697        var settings;
28698        if (storage.test("config")) {
28699            settings = window.JSON.parse(storage.getItem("config"));
28700            Hyphenator.config(settings);
28701        }
28702    }
28703
28704    /**EXPORTED VALUES**/
28705
28706    /**
28707     * @member {string} Hyphenator.version
28708     * @desc
28709     * String containing the actual version of Hyphenator.js
28710     * [major release].[minor releas].[bugfix release]
28711     * major release: new API, new Features, big changes
28712     * minor release: new languages, improvements
28713     * @access public
28714     */
28715    var version = '5.3.0';
28716
28717    /**
28718     * @member {boolean} Hyphenator.doHyphenation
28719     * @desc
28720     * If doHyphenation is set to false, hyphenateDocument() isn"t called.
28721     * All other actions are performed.
28722     * @default true
28723     */
28724    var doHyphenation = true;
28725
28726    /**
28727     * @typedef {Object} Hyphenator.languages.language
28728     * @property {Number} leftmin - The minimum of chars to remain on the old line
28729     * @property {Number} rightmin - The minimum of chars to go on the new line
28730     * @property {string} specialChars - Non-ASCII chars in the alphabet.
28731     * @property {Object.<number, string>} patterns - the patterns in a compressed format. The key is the length of the patterns in the value string.
28732     * @property {Object.<string, string>} charSubstitution - optional: a hash table with chars that are replaced during hyphenation
28733     * @property {string | Object.<string, string>} exceptions - optional: a csv string containing exceptions
28734     */
28735
28736    /**
28737     * @member {Object.<string, Hyphenator.languages.language>} Hyphenator.languages
28738     * @desc
28739     * Objects that holds key-value pairs, where key is the language and the value is the
28740     * language-object loaded from (and set by) the pattern file.
28741     * @namespace Hyphenator.languages
28742     * @access public
28743     */
28744    var languages = {};
28745
28746    /**
28747     * @method Hyphenator.config
28748     * @desc
28749     * The Hyphenator.config() function that takes an object as an argument. The object contains key-value-pairs
28750     * containig Hyphenator-settings.
28751     * @param {Hyphenator.config} obj
28752     * @access public
28753     * @example
28754     * &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
28755      * &lt;script type = "text/javascript"&gt;
28756      *     Hyphenator.config({"minwordlength":4,"hyphenchar":"|"});
28757     *     Hyphenator.run();
28758      * &lt;/script&gt;
28759     */
28760    function config(obj) {
28761        var assert = function (name, type) {
28762            var r,
28763                t;
28764            t = typeof obj[name];
28765            if (t === type) {
28766                r = true;
28767            } else {
28768                onError(new Error("Config onError: " + name + " must be of type " + type));
28769                r = false;
28770            }
28771            return r;
28772        };
28773
28774        if (obj.hasOwnProperty("storagetype")) {
28775            if (assert("storagetype", "string")) {
28776                storageType = obj.storagetype;
28777            }
28778            if (!storage) {
28779                createStorage();
28780            }
28781        }
28782        if (!obj.hasOwnProperty("STORED") && storage && obj.hasOwnProperty("persistentconfig") && obj.persistentconfig === true) {
28783            restoreConfiguration();
28784        }
28785
28786        forEachKey(obj, function (key) {
28787            switch (key) {
28788                case "STORED":
28789                    break;
28790                case "classname":
28791                    if (assert("classname", "string")) {
28792                        hyphenateClass = obj[key];
28793                    }
28794                    break;
28795                case "urlclassname":
28796                    if (assert("urlclassname", "string")) {
28797                        urlHyphenateClass = obj[key];
28798                    }
28799                    break;
28800                case "donthyphenateclassname":
28801                    if (assert("donthyphenateclassname", "string")) {
28802                        dontHyphenateClass = obj[key];
28803                    }
28804                    break;
28805                case "minwordlength":
28806                    if (assert("minwordlength", "number")) {
28807                        min = obj[key];
28808                    }
28809                    break;
28810                case "hyphenchar":
28811                    if (assert("hyphenchar", "string")) {
28812                        if (obj.hyphenchar === "&shy;") {
28813                            obj.hyphenchar = String.fromCharCode(173);
28814                        }
28815                        hyphen = obj[key];
28816                    }
28817                    break;
28818                case "urlhyphenchar":
28819                    if (obj.hasOwnProperty("urlhyphenchar")) {
28820                        if (assert("urlhyphenchar", "string")) {
28821                            urlhyphen = obj[key];
28822                        }
28823                    }
28824                    break;
28825                case "togglebox":
28826                    if (assert("togglebox", "function")) {
28827                        toggleBox = obj[key];
28828                    }
28829                    break;
28830                case "displaytogglebox":
28831                    if (assert("displaytogglebox", "boolean")) {
28832                        displayToggleBox = obj[key];
28833                    }
28834                    break;
28835                case "remoteloading":
28836                    if (assert("remoteloading", "boolean")) {
28837                        enableRemoteLoading = obj[key];
28838                    }
28839                    break;
28840                case "enablecache":
28841                    if (assert("enablecache", "boolean")) {
28842                        enableCache = obj[key];
28843                    }
28844                    break;
28845                case "enablereducedpatternset":
28846                    if (assert("enablereducedpatternset", "boolean")) {
28847                        enableReducedPatternSet = obj[key];
28848                    }
28849                    break;
28850                case "onhyphenationdonecallback":
28851                    if (assert("onhyphenationdonecallback", "function")) {
28852                        onHyphenationDone = obj[key];
28853                    }
28854                    break;
28855                case "onerrorhandler":
28856                    if (assert("onerrorhandler", "function")) {
28857                        onError = obj[key];
28858                    }
28859                    break;
28860                case "onwarninghandler":
28861                    if (assert("onwarninghandler", "function")) {
28862                        onWarning = obj[key];
28863                    }
28864                    break;
28865                case "intermediatestate":
28866                    if (assert("intermediatestate", "string")) {
28867                        intermediateState = obj[key];
28868                    }
28869                    break;
28870                case "selectorfunction":
28871                    if (assert("selectorfunction", "function")) {
28872                        selectorFunction = obj[key];
28873                    }
28874                    break;
28875                case "safecopy":
28876                    if (assert("safecopy", "boolean")) {
28877                        safeCopy = obj[key];
28878                    }
28879                    break;
28880                case "doframes":
28881                    if (assert("doframes", "boolean")) {
28882                        doFrames = obj[key];
28883                    }
28884                    break;
28885                case "storagetype":
28886                    if (assert("storagetype", "string")) {
28887                        storageType = obj[key];
28888                    }
28889                    break;
28890                case "orphancontrol":
28891                    if (assert("orphancontrol", "number")) {
28892                        orphanControl = obj[key];
28893                    }
28894                    break;
28895                case "dohyphenation":
28896                    if (assert("dohyphenation", "boolean")) {
28897                        Hyphenator.doHyphenation = obj[key];
28898                    }
28899                    break;
28900                case "persistentconfig":
28901                    if (assert("persistentconfig", "boolean")) {
28902                        persistentConfig = obj[key];
28903                    }
28904                    break;
28905                case "defaultlanguage":
28906                    if (assert("defaultlanguage", "string")) {
28907                        defaultLanguage = obj[key];
28908                    }
28909                    break;
28910                case "useCSS3hyphenation":
28911                    if (assert("useCSS3hyphenation", "boolean")) {
28912                        css3 = obj[key];
28913                    }
28914                    break;
28915                case "unhide":
28916                    if (assert("unhide", "string")) {
28917                        unhide = obj[key];
28918                    }
28919                    break;
28920                case "onbeforewordhyphenation":
28921                    if (assert("onbeforewordhyphenation", "function")) {
28922                        onBeforeWordHyphenation = obj[key];
28923                    }
28924                    break;
28925                case "onafterwordhyphenation":
28926                    if (assert("onafterwordhyphenation", "function")) {
28927                        onAfterWordHyphenation = obj[key];
28928                    }
28929                    break;
28930                case "leftmin":
28931                    if (assert("leftmin", "number")) {
28932                        leftmin = obj[key];
28933                    }
28934                    break;
28935                case "rightmin":
28936                    if (assert("rightmin", "number")) {
28937                        rightmin = obj[key];
28938                    }
28939                    break;
28940                case "compound":
28941                    if (assert("compound", "string")) {
28942                        compound = obj[key];
28943                    }
28944                    break;
28945                default:
28946                    onError(new Error("Hyphenator.config: property " + key + " not known."));
28947            }
28948        });
28949        if (storage && persistentConfig) {
28950            storeConfiguration();
28951        }
28952    }
28953
28954    /**
28955     * @method Hyphenator.run
28956     * @desc
28957     * Bootstrap function that starts all hyphenation processes when called:
28958     * Tries to create storage if required and calls {@link Hyphenator~runWhenLoaded} on "window" handing over the callback "process"
28959     * @access public
28960     * @example
28961     * &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
28962      * &lt;script type = "text/javascript"&gt;
28963      *   Hyphenator.run();
28964      * &lt;/script&gt;
28965     */
28966    function run() {
28967        /**
28968         *@callback Hyphenator.run~process process - The function is called when the DOM has loaded (or called for each frame)
28969         */
28970        var process = function () {
28971            try {
28972                if (contextWindow.document.getElementsByTagName("frameset").length > 0) {
28973                    return; //we are in a frameset
28974                }
28975                autoSetMainLanguage(undefined);
28976                gatherDocumentInfos();
28977                if (displayToggleBox) {
28978                    toggleBox();
28979                }
28980                prepare(hyphenateLanguageElements);
28981            } catch (e) {
28982                onError(e);
28983            }
28984        };
28985
28986        if (!storage) {
28987            createStorage();
28988        }
28989        runWhenLoaded(window, process);
28990    }
28991
28992    /**
28993     * @method Hyphenator.addExceptions
28994     * @desc
28995     * Adds the exceptions from the string to the appropriate language in the
28996     * {@link Hyphenator~languages}-object
28997     * @param {string} lang The language
28998     * @param {string} words A comma separated string of hyphenated words WITH spaces.
28999     * @access public
29000     * @example &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
29001      * &lt;script type = "text/javascript"&gt;
29002      *   Hyphenator.addExceptions("de","ziem-lich, Wach-stube");
29003     *   Hyphenator.run();
29004      * &lt;/script&gt;
29005     */
29006    function addExceptions(lang, words) {
29007        if (lang === "") {
29008            lang = "global";
29009        }
29010        if (exceptions.hasOwnProperty(lang)) {
29011            exceptions[lang] += ", " + words;
29012        } else {
29013            exceptions[lang] = words;
29014        }
29015    }
29016
29017    /**
29018     * @method Hyphenator.hyphenate
29019     * @access public
29020     * @desc
29021     * Hyphenates the target. The language patterns must be loaded.
29022     * If the target is a string, the hyphenated string is returned,
29023     * if it"s an object, the values are hyphenated directly and undefined (aka nothing) is returned
29024     * @param {string|Object} target the target to be hyphenated
29025     * @param {string} lang the language of the target
29026     * @returns {string|undefined}
29027     * @example &lt;script src = "Hyphenator.js" type = "text/javascript"&gt;&lt;/script&gt;
29028     * &lt;script src = "patterns/en.js" type = "text/javascript"&gt;&lt;/script&gt;
29029      * &lt;script type = "text/javascript"&gt;
29030     * var t = Hyphenator.hyphenate("Hyphenation", "en"); //Hy|phen|ation
29031     * &lt;/script&gt;
29032     */
29033    function hyphenate(target, lang) {
29034        var turnout, n, i, lo;
29035        lo = Hyphenator.languages[lang];
29036        if (Hyphenator.languages.hasOwnProperty(lang)) {
29037            if (!lo.prepared) {
29038                prepareLanguagesObj(lang);
29039            }
29040            turnout = function (match, word, url, mail) {
29041                var r;
29042                if (!!url || !!mail) {
29043                    r = hyphenateURL(match);
29044                } else {
29045                    r = hyphenateWord(lo, lang, word);
29046                }
29047                return r;
29048            };
29049            if (typeof target === "object" && !(typeof target === "string" || target.constructor === String)) {
29050                i = 0;
29051                n = target.childNodes[i];
29052                while (!!n) {
29053                    if (
29054                        n.nodeType === 3 //type 3 = #text
29055                        && (/\S/).test(n.data) //not just white space
29056                        && n.data.length >= min
29057                    ) { //longer then min
29058                        n.data = n.data.replace(lo.genRegExp, turnout);
29059                    } else if (n.nodeType === 1) {
29060                        if (n.lang !== "") {
29061                            Hyphenator.hyphenate(n, n.lang);
29062                        } else {
29063                            Hyphenator.hyphenate(n, lang);
29064                        }
29065                    }
29066                    i += 1;
29067                    n = target.childNodes[i];
29068                }
29069            } else if (typeof target === "string" || target.constructor === String) {
29070                return target.replace(lo.genRegExp, turnout);
29071            }
29072        } else {
29073            onError(new Error("Language \"" + lang + "\" is not loaded."));
29074        }
29075    }
29076
29077    /**
29078     * @method Hyphenator.getRedPatternSet
29079     * @desc
29080     * Returns the reduced pattern set: an object looking like: {"patk": pat}
29081     * @param {string} lang the language patterns are stored for
29082     * @returns {Object.<string, string>}
29083     * @access public
29084     */
29085    function getRedPatternSet(lang) {
29086        return Hyphenator.languages[lang].redPatSet;
29087    }
29088
29089    /**
29090     * @method Hyphenator.getConfigFromURI
29091     * @desc
29092     * reads and sets configurations from GET parameters in the URI
29093     * @access public
29094     */
29095    function getConfigFromURI() {
29096        var loc = null,
29097            re = {},
29098            jsArray = contextWindow.document.getElementsByTagName("script"),
29099            i = 0,
29100            j = 0,
29101            l = jsArray.length,
29102            s,
29103            gp,
29104            option;
29105        while (i < l) {
29106            if (!!jsArray[i].getAttribute("src")) {
29107                loc = jsArray[i].getAttribute("src");
29108            }
29109            if (loc && (loc.indexOf("Hyphenator.js?") !== -1)) {
29110                s = loc.indexOf("Hyphenator.js?");
29111                gp = loc.substring(s + 14).split("&");
29112                while (j < gp.length) {
29113                    option = gp[j].split("=");
29114                    if (option[0] !== "bm") {
29115                        if (option[1] === "true") {
29116                            option[1] = true;
29117                        } else if (option[1] === "false") {
29118                            option[1] = false;
29119                        } else if (isFinite(option[1])) {
29120                            option[1] = parseInt(option[1], 10);
29121                        }
29122                        if (
29123                            option[0] === "togglebox" ||
29124                            option[0] === "onhyphenationdonecallback" ||
29125                            option[0] === "onerrorhandler" ||
29126                            option[0] === "selectorfunction" ||
29127                            option[0] === "onbeforewordhyphenation" ||
29128                            option[0] === "onafterwordhyphenation"
29129                        ) {
29130                            option[1] = new Function("", option[1]);
29131                        }
29132                        re[option[0]] = option[1];
29133                    }
29134                    j += 1;
29135                }
29136                break;
29137            }
29138            i += 1;
29139        }
29140        return re;
29141    }
29142
29143    /**
29144     * @method Hyphenator.toggleHyphenation
29145     * @desc
29146     * Checks the current state of Hyphenator.doHyphenation and removes or does hyphenation.
29147     * @access public
29148     */
29149    function toggleHyphenation() {
29150        if (Hyphenator.doHyphenation) {
29151            if (!!css3hyphenateClassHandle) {
29152                css3hyphenateClassHandle.setRule("." + css3hyphenateClass, css3_h9n.property + ": none;");
29153            }
29154            removeHyphenationFromDocument();
29155            if (safeCopy) {
29156                copy.removeOnCopy();
29157            }
29158            Hyphenator.doHyphenation = false;
29159            storeConfiguration();
29160            if (displayToggleBox) {
29161                toggleBox();
29162            }
29163        } else {
29164            if (!!css3hyphenateClassHandle) {
29165                css3hyphenateClassHandle.setRule("." + css3hyphenateClass, css3_h9n.property + ": auto;");
29166            }
29167            Hyphenator.doHyphenation = true;
29168            hyphenateLanguageElements("*");
29169            if (safeCopy) {
29170                copy.reactivateOnCopy();
29171            }
29172            storeConfiguration();
29173            if (displayToggleBox) {
29174                toggleBox();
29175            }
29176        }
29177    }
29178
29179    return {
29180        version: version,
29181        doHyphenation: doHyphenation,
29182        languages: languages,
29183        config: config,
29184        run: run,
29185        addExceptions: addExceptions,
29186        hyphenate: hyphenate,
29187        getRedPatternSet: getRedPatternSet,
29188        isBookmarklet: isBookmarklet,
29189        getConfigFromURI: getConfigFromURI,
29190        toggleHyphenation: toggleHyphenation
29191    };
29192
29193}(window));
29194
29195//Export properties/methods (for google closure compiler)
29196/**** to be moved to external file
29197 Hyphenator["languages"] = Hyphenator.languages;
29198 Hyphenator["config"] = Hyphenator.config;
29199 Hyphenator["run"] = Hyphenator.run;
29200 Hyphenator["addExceptions"] = Hyphenator.addExceptions;
29201 Hyphenator["hyphenate"] = Hyphenator.hyphenate;
29202 Hyphenator["getRedPatternSet"] = Hyphenator.getRedPatternSet;
29203 Hyphenator["isBookmarklet"] = Hyphenator.isBookmarklet;
29204 Hyphenator["getConfigFromURI"] = Hyphenator.getConfigFromURI;
29205 Hyphenator["toggleHyphenation"] = Hyphenator.toggleHyphenation;
29206 window["Hyphenator"] = Hyphenator;
29207 */
29208
29209/*
29210 * call Hyphenator if it is a Bookmarklet
29211 */
29212if (Hyphenator.isBookmarklet) {
29213    Hyphenator.config({displaytogglebox: true, intermediatestate: "visible", storagetype: "local", doframes: true, useCSS3hyphenation: true});
29214    Hyphenator.config(Hyphenator.getConfigFromURI());
29215    Hyphenator.run();
29216}
29217
29218
29219// The en-US hyphenation patterns are retrieved from
29220// http://tug.org/svn/texhyphen/trunk/collaboration/repository/hyphenator/
29221/*global Hyphenator*/
29222Hyphenator.languages['en-us'] = Hyphenator.languages['en'] = {
29223    leftmin: 2,
29224    rightmin: 3,
29225    specialChars: "",
29226    patterns: {
29227        3: "x1qei2e1je1f1to2tlou2w3c1tue1q4tvtw41tyo1q4tz4tcd2yd1wd1v1du1ta4eu1pas4y1droo2d1psw24sv1dod1m1fad1j1su4fdo2n4fh1fi4fm4fn1fopd42ft3fu1fy1ga2sss1ru5jd5cd1bg3bgd44uk2ok1cyo5jgl2g1m4pf4pg1gog3p1gr1soc1qgs2oi2g3w1gysk21coc5nh1bck1h1fh1h4hk1zo1ci4zms2hh1w2ch5zl2idc3c2us2igi3hi3j4ik1cab1vsa22btr1w4bp2io2ipu3u4irbk4b1j1va2ze2bf4oar1p4nz4zbi1u2iv4iy5ja1jeza1y1wk1bk3fkh4k1ikk4k1lk1mk5tk1w2ldr1mn1t2lfr1lr3j4ljl1l2lm2lp4ltn1rrh4v4yn1q1ly1maw1brg2r1fwi24ao2mhw4kr1cw5p4mkm1m1mo4wtwy4x1ar1ba2nn5mx1ex1h4mtx3i1muqu2p3wx3o4mwa1jx3p1naai2x1ua2fxx4y1ba2dn1jy1cn3fpr2y1dy1i",
29228        4: "4dryn2itni4on1inn1im_up3nik4ni4dy5giye4tyes4_ye44ab_nhe4nha4abe2n2gyn1guy1ery5eep2pe4abry3lay3lone4wne4v1nesy3chn1erne2q3neo1nenp2seps4hy2cey5lu2nedne2cyme44nk2y5at2adine2b2ne_y5ac2p1tp2ten1den1cun1cryn5dp2th4adup4twpub3ae4rxu3ayn5gaff4pue4n2au4p1ppuf4n2atag1ipu4mag1na2gon4asx3tix1t2pu2na4gya3haa3heah4la3ho_ti2a5ian2an5puspu2tnak4_th2n1kl_te4_ta4mu4u4mupmun23mum2alex4ob_sy25ynxal1i_st4y1o4xi5cxi5a4alm_si2_sh2m5sixhu4m4sh4m3r4amam2py2rabm2pixhi2yo5dr2ai4m1pmo2vmos2x2edmo2r4n1la2mor2asx3c2xas5yom4x4apxam3nme44mokrbi2nne44andy4osp4ot3noemn4omn4a4m1n4nog4m1l2angws4l1posw3shwri4wra4yp3iwom11wo2m2izrb4ow4nopo4pr2cem2isrd2iano4mig4y3pomi3awiz55mi_no4n4m1fme4v2re_wir42mes1menme2mme2gre1o2med4me_4nop4m5c4m1bwil21noureu2whi4w3ev4maprev2w1era2plpo4crfu4r4fyy5pu2maha3pu2mab2a2rn1p4npi44lyb4lya2p3nwam42l1w1lut4luplu3or1glluf4lu5a2wacltu2y3rol1tr4vv4r3guyr4rl1te4rh_nru4ar1il2sel4sc4l1rl5prl4plys4c4lovri3ar4ib4lof3lo_ar2par3q_os3ll4oll2i4as_ri1o3vokl2levoi44p1mlka35vo_ns4cas4ll1izr4iqr2is3vivl1it3lika2tan2sen2slrle42l3hlgo3l5gal5frns3mvi4p3ley_od2r2meles24athr4myle2al3drv1inldi4l2de2vilnt2il3civik4lce42l1b4lavv3ifrno4r3nua1trr2ocnt4sy4sok4syks4la2tuk4sck3ouko5ryss4a2tyau4b4klyys1tnu1akis4au3rki4pro4ek4ima2va5ki_nu4dn4umn3uokes4k1erav1irok2ke4g1keek2ed_me2aw3ikal4aws4k5agk3ab3ka_aye4ays4veg3jo4p5ba_4vedjew3n1v24ve_ja4pzar23vatizi4n1w41batba4z2b1bb2beix4o4i5w4b1d4be_rox5nym4nyp4n3za4ittr3por1r4i1ti1bel2ith2itei2su4rs2r1sars4cr2seis1p3betvag4i2sor1shbe3wr1sioad34b3hbi2bbi4d3bie3isf4ise2is_1bilr1sp5va_r5sw_le2uz4eir1ibi2tuxu3r1tiu1v2i1raze4nze4pb2l2uu4mo1biip3iz1eripe4b4louts44b1m4b3no3br3bodi4osbo4eru3aio4mi1ol4io_3booo1ce4inyin1u2insru2n2inn4inl4inkrv4e2inioch42iner3vo4indpi2np4idbt4lb4tob3trry4cry3t2in_o4elbu4ni2muim1i5saiil3v4ilnil1iil5fs1apo3er4b5w5by_bys4_in1sau4i1lazet4u2suo3ev2z1ii2go4igius1p5saw4s5bo2fi4ifti3fl4if_i3etsch2usc22ie4i2dui4dri2diid5dpi3au3ruz4ils1cuz4is4s5d4se_se4a2ce_2ici4ich3ceii1bri5bo1ceni1blse2g5seiibe43cepi2aniam4ur2li2al2i1acet4hy2scew41phy4ch_5phuhu4thu4gche2h4tyh4shur1durc44hr44h5p5sev5sexu1ra4s3fup3p2s3gph3t2sh_ho4g2h1n_he23ciau3pl4h1mci5ch2lozo4m4ciihi2vhi4p2cim2cin4phsu1peu1ouo1geu5osheu4sho4he4th1es4shwun5zun5ysi1bunu45cizo4glck3ihep5he2nh4ed1sioph2l5hazsi2rcly4zte4_ge21siscoe22cog5siu1siv5siz_ga24skes1l2s2leha4m2s1ms3ma1ogyo1h2u1ni3gus3gun2guegu4acov1gth3_eu3g4ros1n4_es3u2nez4zyum2pu1mi3som_ev2oig4cri2gov15goos4opgon2ul5v5goeu3lugob53go_2c1t4ph_g1nog1nic2te4sov4ulsgn4ag4myc4twcud5c4ufc4uipe2t3glo1gleul2igla4_eg23giz3cun5givgi4u3gir5gio1cusul4e2spagil4g1ic5gi__eb4cze41d2a5da_u1laggo44daf2dagg2gege4v1geo1gen2ged3dato1la2ge_ol2dol2i5daypek4p4eed1d42de_4gazol2tuiv3ol2vo2lys1sa2gamgaf4o2meui4n2ui2pe2cd4em4fugi4jku3fl3ufaf2tyf4to1denu4du4pe_2f3sfri2de1ps1si4f5pfos5d3eqs4sls4snfo2rss2tdes25fon4p1b_ci23payss5w2st_de1tf4l2de1v2fin4dey4d1fd4gast2idg1id2gyd1h25di_ud5dfi3au4cy_ch4pav43didu3cud1iff2fyu3crd1inst4r4f1ffev4fer11dio2fedfe4bdir2s2ty4fe_dis1on1au3
29228ca4f5bon1c2ondd5k25far4fagpa1peys45eyc1exps4ul2dlyp4ale3whon3s3do_e1wa5doee5vud4oge1visu2msu2nub4euav4su2rp4ai6rk_d4or3dosu1atdo4v3doxp4adoo4k4swoo2padre4eus4e3upe5un2ophet5z4syc3syl4y3hoy1ads4pd4swd4syd2tho4wo3ta_du2c4etn2tabta2luac4es4wdu4g2ess4uabdu4n4duptav4st5bow1io1pr5dyn2tawe1sp2t1bop1uead1tz4et4chopy5ea4l4t1d4te_2tyle1si4esh1tee4tyat1cr4twoteg4es2c4eru1teoer1s2eroea2tte4po1rat1wh3tusea2v3teu3texer1i2e1ber1h4tey2t1f4t1ge3br2th_th2e4thle1ce3tumec2i2ths2erb1tia4tueer1aou5vtud2tif22tige1potu1aou4lttu41timt5toos4le1cre2pat4swe5owe1cue4ottsh4eos4e1ort4sce3ol4edieo2ge5of1tio4eno4enn5tiq4edoti4u1tive3my1tiz4othee2ct5laee2ft5lo4t1mee2mtme4e1meem5bcoi4to3be5exo1ry2tof1effel2iel2ftos24t1pe1la1traos2ceig2ei5de5ico2soe1h45egyeg5n",
29229        5: "_ach4e4go_e4goseg1ule5gurtre5feg4iceher4eg5ibeger44egaltre4mei5gle3imbe3infe1ingtra3beir4deit3eei3the5ity5triae4jud3efiteki4nek4la2trime4la_e4lactri4v4toute4law5toure3leaefil45elece4ledto2rae5len4tonye1lestro3ve4fic4tonoto3mytom4bto2mato5ice5limto2gre3lioe2listru5i4todo4ellaee4tyello4e5locel5ogeest4el2shel4tae5ludel5uge4mace4mage5man2t1n2ee2s4ee4p1e2mele4metee4naemi4eee4lyeel3i3tled3tle_e4mistlan4eed3iem3iztrus4emo4gti3zaem3pie4mule4dulemu3ne4dritiv4aedon2e4dolti3tle5neae5neeen3emtis4pti5sotis4m3tisee3newti3sae5niee5nile3nioedi5zen3ite5niu5enized1ited3imeno4ge4nosen3oven4swti5oc4t1s2en3uaen5ufe3ny_4en3zed3ibe3diae4oi4ede4s3tini4ed3deo3ret2ina2e2dae4culeo4toe5outec4te4t3t2t4tes2t1ine5pel4timpe2corephe4e4plie2col5tigutu3arti5fytu4bie3pro3tienep4sh5tidie4putt4icoeci4t4tick2ti2bec3imera4bti4aber3ar4tuf45tu3ier4bler3che4cib2ere_4thooecca54thil3thet4thea3turethan4e4cade4bitere4qe4ben5turieret4tur5oeav5oeav5itu5ry4tess4tes_ter5ve1rio4eriter4iueri4v1terier3m4ter3cte5pe4t1waer3noeast3er5obe5rocero4rer1oue3assea5sp1tent4ertler3twtwis4eru4t3tende1s4a3tenc5telsear2te2scateli4e3scres5cue1s2ee2sec3tel_te5giear5kear4cte5diear3ae3sha2t1ede5ande2sice2sid5tecttece44teattype3ty5phesi4uea4gees4mie2sole3acte2sone1a4bdys5pdy4sedu4petaun4d3uleta5sytas4e4tare4tarctar4ata5pl2estrta5mo4talke2surtal3idu5eleta4bta5lae3teoua5naet1ic4taf4etin4ta5doe5tir4taciuan4id1ucad1u1ae3trae3tre2d1s2syn5ouar2d4drowet3uaet5ymdro4pdril4dri4b5dreneu3rouar3ieute44draieu5truar3te2vasdop4pe5veadoo3ddoni4u4belsum3iev1erdoli4do4laev3idevi4le4vinevi4ve5voc2d5ofdo5dee4wage5wee4d1n4ewil54d5lue3wit2d3lou3ber5eye_u1b4i3dledfa3blfab3rfa4ce3dle_fain4suit3su5issu2g34d5lasu4b3fa3tasu1al4fato1di1vd2iti5disiuci4bfeas4di1redi4pl4feca5fectdio5gfe3life4mofen2d4st3wuc4it5ferr5diniucle3f4fesf4fie4stry1dinaf4flydi3ge3dictd4icedia5bs4tops1tle5stirs3tifs4ties1ticfic4is5tias4ti_4ficsfi3cuud3ers3thefil5iste2w4filyudev45finas4tedfi2nes2talfin4ns2tagde2tode4suflin4u1dicf2ly5ud5isu5ditde1scd2es_der5sfon4tu4don5dermss4lid4erhfor4is4siede2pudepi4fra4tf5reade3pade3nufril4frol5ud4side3nou4eneuens4ug5infu5el5dem_s5setfu5nefu3rifusi4fus4s4futade5lode5if4dee_5gal_3galiga3lo2d1eds3selg5amos2s5cssas3u1ing4ganouir4mgass4gath3uita4deaf5dav5e5dav44dato4darygeez44spotspor4s4pon4gelydark5s4ply4spio4geno4genydard5ge3omg4ery5gesigeth54getoge4tydan3g4g1g2da2m2g3gergglu5dach4gh3inspil4gh4to4cutr1gi4agia5rula5bspho5g4icogien5s2pheulch42sperspa4n5spai3c4utu1lenul4gigir4lg3islcu5pycu3picu4mic3umecu2maso5vi5glasu5liagli4bg3lig5culiglo3r4ul3mctu4ru1l4og4na_c3terul1tig2ning4nio4ultug4noncta4b4c3s2cru4dul5ulsor5dgo3isum5absor5ccris4go3nic4rinson4gsona45gos_cri5fcre4vum4bi5credg4raigran25solvsoft3so4ceunat44graygre4nco5zi4gritcoz5egruf4cow5ag5stecove4cos4es5menun4ersmel44corbco4pl4gu4tco3pacon5tsman3gy5racon3ghach4hae4mhae4th5aguha3lac4onecon4aun4ims3latu2ninhan4gs3ket5colocol5ihan4kuni3vhap3lhap5ttras4co4grhar2dco5agsir5aclim45sionhas5shaun44clichaz3acle4m1head3hearun3s4s3ingun4sws2ina2s1in4silysil4eh5elohem4p4clarhena45sidiheo5r1c4l4h4eras5icc2c1itu4orsh3ernshor4h3eryci3phshon34cipecion45cinoc1ingc4inahi5anhi4cohigh5h4il2shiv5h4ina3ship3cilihir4lhi3rohir4phir4rsh3iohis4ssh1inci4lau5pia4h1l4hlan44cier5shevcia5rhmet4ch4tish1erh5ods3cho2hoge4chi2z3chitho4mahome3hon4aho5ny3hoodhoon45chiouptu44ura_ho5ruhos4esew4ihos1p1housu4ragses5tu4rasur4behree5se5shs1e4s4h1s24chedh4tarht1enht5esur4fru3rifser4os4erlhun4tsen5gur1inu3riosen4dhy3pehy3phu1ritces5tur3iz4cesa4sencur4no4iancian3i4semeia5peiass45selv5selfi4atu3centse1le4ceniib5iaib3inseg3ruros43cencib3li3cell5cel_s5edli5bun4icam5icap4icar4s4ed3secticas5i4cayiccu44iceour4pe4ced_i5cidsea5wi2cipseas4i4clyur4pi4i1cr5icrai4cryic4teictu2ccon4urti4ic4umic5uoi3curcci4ai4daicch
29229a5ca4thscof4ide4s4casys4cliscle5i5dieid3ios4choid1itid5iui3dlei4domid3owu5sadu5sanid5uous4apied4ecany4ield3s4cesien4ei5enn4sceii1er_i3esci1estus3ciuse5as4cedscav5if4frsca4pi3fieu5siau3siccan4eiga5bcan5d4calous5sli3gibig3ilig3inig3iti4g4lus1trig3orig5oti5greigu5iig1ur2c5ah4i5i44cag4cach4ca1blusur4sat3usa5tab5utoi3legil1erilev4uta4b4butail3iail2ibil3io3sanc2ilitil2izsal4t5bustil3oqil4tyil5uru3tati4magsa5losal4m4ute_4imetbu3res3act5sack2s1ab4imitim4nii3mon4utelbumi4bu3libu4ga4inav4utenbsor42b5s2u4tis4briti3neervi4vr3vic4inga4inger3vey4ingir3ven4ingo4inguu4t1li5ni_i4niain3ioin1isbo4tor5uscrunk5both5b5ota5bos42i1no5boriino4si4not5borein3seru3in2int_ru4glbor5di5nusut5of5bor_uto5gioge4io2grbon4au5tonru3enu4touion3iio5phior3ibod3iio5thi5otiio4toi4ourbne5gb3lisrt4shblen4ip4icr3triip3uli3quar4tivr3tigrti4db4le_b5itzira4bi4racird5ert5ibi4refbi3tri4resir5gibi5ourte5oir4isr3tebr4tagbin4diro4gvac3uir5ul2b3ifis5agis3arisas52is1cis3chbi4eris3erbi5enrson3be5yor5shais3ibisi4di5sisbe3tw4is4krs3es4ismsbe5trr3secva4geis2piis4py4is1sbe3sp4bes4be5nuval5ois1teis1tirrys4rros44be5mis5us4ita_rron4i4tagrri4vi3tani3tatbe3lorri4or4reoit4esbe1libe5gu4itiarre4frre4cbe3giit3igbe3dii2tim2itio4itisrp4h4r3pet4itonr4peait5rybe3debe3dai5tudit3ul4itz_4be2dbeat3beak4ro4varo4tyros4sro5roiv5ioiv1itror3i5root1roomval1ub3berva5mo4izarva5piron4eban3ijac4qban4ebal1ajer5srom4prom4iba4geazz5i5judgay5alax4idax4ickais4aw4ly3awaya1vorav5ocav3igke5liv3el_ve4lov4elyro1feke4tyv4erdv4e2sa5vanav3ag5k2ick4illkilo5au1thk4in_4ves_ro3crkin4gve4teaun5dk5ishau4l2au3gu4kleyaugh3ve4tyk5nes1k2noat3ulkosh4at5uekro5n4k1s2at5uaat4that5te5vianat4sk5vidil4abolaci4l4adela3dylag4nlam3o3landrob3la4tosr4noular4glar3ilas4ea4topr3nivr3nita2tomr5nica4toglbin44l1c2vi5gnat3ifat1ica5tiar3neyr5net4ati_ld5isat4hol4driv2incle4bileft55leg_5leggr4nerr3nel4len_3lencr4nar1lentle3phle4prvin5dler4e3lergr3mitl4eroat5evr4mio5lesq3lessr3menl3eva4vingrma5cvio3lvi1ou4leyevi5rovi3so4l1g4vi3sulgar3l4gesate5cat5apli4agli2amr3lo4li4asr4lisli5bir4ligr2led4lics4vitil4icul3icyl3idaat5ac3lidirk4lel4iffli4flr3ket3lighvit3r4vityriv3iri2tulim3ili4moris4pl4inar3ishris4clin3ir4is_li5og4l4iqlis4pas1trl2it_as4shas5phri2pla4socask3ia3sicl3kallka4ta3sibl4lawashi4l5leal3lecl3legl3lel5riphas4abar2shrin4grin4ear4
29229sarin4dr2inal5lowarre4l5met3rimol4modlmon42l1n2a3roorim5ilo4civo4la5rigil5ogo3loguri5et5longlon4iri1erlood5r4icolop3il3opmlora44ricir4icerib3a5los_v5oleri4agria4blos4tlo4taar2mi2loutar2izar3iolpa5bl3phal5phi4rhall3pit5voltar4im3volv2l1s2vom5ivori4l4siear4fllt5agar4fivo4rylten4vo4talth3ia3reeltis4ar4drw5ablrgo4naraw4lu3brluch4lu3cilu3enwag5olu5idlu4ma5lumia5raur5gitwait5luo3rw5al_luss4r5gisar4atl5venrgi4nara3pwar4tar3alwas4tly5mely3no2lys4l5ysewa1teaque5ma2car3gicma4clr3get5magnwed4nmaid54maldrg3erweet3wee5vwel4lapoc5re4whwest3ap3in4aphires2tr4es_mar3vre5rumas4emas1t5matemath3rero4r4eriap5atr1er4m5bilre1pumbi4vapar4a5nuran3ul4med_an3uare5lure1lian4twre5itmel4tan2trre4fy4antomen4are3fire2fe4menemen4imens4re1de3ment2r2edme5onre4awwin4g5reavme4tare3anme1tere1alm4etr3wiserdin4rdi4aan4stwith3an2span4snan2samid4amid4gan5otwl4esr4dalm4illmin4a3mindrcum3rc4itr3charcen4min4tm4inumiot4wl3ina3niumis5lan3ita3nip4mithan3ioan1gla3neuws4per2bina3nena5neem4ninw5s4tan1dl4mocrrbi4fmo2d1mo4gomois2xac5ex4agor4bagmo3mer4baba3narrau4ta5monrare4rar5cra5nor4aniam1inr2amiam5ifra4lomo3spmoth3m5ouf3mousam3icxer4ixe5roraf4tr5aclm3petra3bixhil5mpi4aam3ag3quetm5pirmp5is3quer2que_qua5vmpov5mp4tram5ab3alyz4m1s25alyt4alysa4ly_ali4exi5di5multx4ime4aldia4laral3adal5abak1enain5opu3trn4abu4nac_na4can5act5putexpe3dna4lia4i4n4naltai5lya3ic_pur4rag5ulnank4nar3c4narenar3inar4ln5arm3agognas4c4ag4l4ageupul3cage4oaga4na4gab3nautnav4e4n1b4ncar5ad5umn3chaa3ducptu4rpti3mnc1innc4itad4suad3owad4len4dain5dana5diua3ditndi4ba3dion1ditn3dizn5ducndu4rnd2we3yar4n3eara3dianeb3uac4um5neckac3ulp4siba3cio5negene4laac1inne5mine4moa3cie4nene4a2cine4poyc5erac1er2p1s2pro1tn2erepro3lner4rych4e2nes_4nesp2nest4neswpri4sycom4n5evea4carab3uln4gabn3gelpre3vpre3rycot4ng5han3gibng1inn5gitn4glangov4ng5shabi5an4gumy4erf4n1h4a5bannhab3a5bal3n4iani3anni4apni3bani4bl_us5ani5dini4erni2fip3petn5igr_ure3_un3up3per_un5op3pennin4g_un5k5nis_p5pel_un1en4ithp4ped_un1ani3tr_to4pympa3_til4n3ketnk3inyn5ic_se2ny4o5gy4onsnmet44n1n2_ru4d5pounnni4vnob4lpo4tan5ocly4ped_ro4qyper5noge4pos1s_ri4gpo4ry1p4or_res2no4mono3my_ree2po4ninon5ipoin2y4poc5po4gpo5em5pod_4noscnos4enos5tno5tayp2ta3noun_ra4cnowl3_pi2tyra5m_pi4eyr5ia_out3_oth32n1s2ns5ab_or3t_or1d_or3cplu4mnsid1nsig4y3s2eys3ion4socns4pen5spiploi4_odd5nta4bpli4n_ni4cn5tib4plignti2fpli3a3plannti4p1p2l23ysis2p3k2ys3ta_mis1nu5enpi2tun3uinp3ithysur4nu1men5umi3nu4nyt3icnu3trz5a2b_li4t_li3o_li2n_li4g_lev1_lep5_len4pion4oard3oas4e3pi1ooat5ip4inoo5barobe4l_la4mo2binpind4_ju3rob3ul_is4i_ir5rp4in_ocif3o4cil_in3so4codpi3lopi3enocre33piec5pidipi3dep5ida_in2kod3icodi3oo2do4odor3pi4cypian4_ine2o5engze3rooe4ta_im3m_id4l_hov5_hi3b_het3_hes3_go4r_gi4bpho4ro5geoo4gero3gie3phobog3it_gi5azo5ol3phizo4groogu5i4z1z22ogyn_fes3ohab5_eye55phieph1icoiff4_en3sph4ero3ing_en3go5ism_to2qans3v_el5d_eer4bbi4to3kenok5iebio5mo4lanper1v4chs_old1eol3erpe5ruo3letol4fi_du4co3liaper3op4ernp4erio5lilpe5ono5liop4encpe4la_do4tpee4do5livcin2q3pediolo4rol5pld3tabol3ub3pedeol3uno5lusedg1le1loaom5ahoma5l2p2edom2beom4bl_de3o3fich3pe4ao4met_co4ro3mia_co3ek3shao5midom1inll1fll3teapa2teo4monom3pi3pare_ca4tlue1pon4aco3nanm2an_pa4pum2en_on5doo3nenng1hoon4guon1ico3nioon1iso5niupa3nypan4ao3nou_bri2pain4ra1oronsu4rk1hopac4tpa4ceon5umonva5_ber4ood5eood5i6rks_oop3io3ordoost5rz1scope5dop1erpa4ca_ba4g_awn4_av4i_au1down5io3pito5pon1sync_as1s_as1p_as3ctch1c_ar5so5ra_ow3elo3visov4enore5auea1mor3eioun2d_ant4orew4or4guou5etou3blo5rilor1ino1rio_ang4o3riuor2miorn2eo5rofoto5sor5pe3orrhor4seo3tisorst4o3tif_an5cor4tyo5rum_al3tos3al_af1tos4ceo4teso4tano5scros2taos4poos4paz2z3wosi4ue3pai",
29230        6: "os3ityos3itoz3ian_os4i4ey1stroos5tilos5titxquis3_am5atot3er_ot5erso3scopor3thyweek1noth3i4ot3ic_ot5icao3ticeor3thiors5enor3ougor3ityor3icaouch5i4o5ria_ani5mv1ativore5sho5realus2er__an3teover3sov4erttot3icoviti4o5v4olow3dero4r3agow5esto4posiop3ingo5phero5phanthy3sc3operaontif5on3t4ionten45paganp3agattele2gonspi4on3omyon4odipan3elpan4tyon3keyon5est3oncil_ar4tyswimm6par5diompro5par5elp4a4ripar4isomo4gepa5terst5scrpa5thy_atom5sta1tio5miniom3icaom3ic_ss3hatsky1scpear4lom3ena_ba5naol3umer1veilpedia4ped4icolli4er1treuo5liteol3ishpeli4epe4nano5lis_pen4thol3ingp4era_r1thoup4erago3li4f_bas4er1krauperme5ol5id_o3liceper3tio3lescolass4oi3terpe5tenpe5tiz_be5raoi
292305son_be3smphar5iphe3nooi5letph4es_oi3deroic3esph5ingr3ial_3ognizo5g2ly1o1gis3phone5phonio5geneo4gatora3mour2amenofit4tof5itera3chupi4ciepoly1eod5dedo5cureoc3ula1pole_5ocritpee2v1param4oc3raco4clamo3chetob5ingob3a3boast5eoke1st3nu3itpi5thanuf4fentu3meoerst2o3chasplas5tn3tinepli5ernti4ernter3sntre1pn4s3esplum4bnsati4npre4cns4moonon1eqnor5abpo3et5n5lessn5oniz5pointpoly5tnon4agnk3rup3nomicng1sprno5l4inois5i4n3o2dno3blenni3aln5keroppa5ran3itor3nitionis4ta5nine_ni3miznd3thrmu2dron3geripray4e5precipre5copre3emm3ma1bpre4lan5gerep3rese3press_can5cmedi2c5pri4e_ce4la3neticpris3op3rocal3chain4er5ipros3en4erarnera5bnel5iz_cit5rne4gatn5d2ifpt5a4bjanu3aign4itn3chisn5chiln5cheon4ces_nau3seid4iosna3talnas5tinan4itnanci4na5mitna5liahnau3zput3er2n1a2bhex2a3hatch1multi3hair1sm4pousg1utanmpo3rim4p1inmp5iesmphas4rach4empar5iraf5figriev1mpara5mo5seyram3et4mora_rane5oran4gemo3ny_monol4rap3er3raphymo3nizgno5morar5ef4raril1g2nacg1leadmoni3ara5vairav3elra5ziemon5gemon5etght1wemoi5sege3o1dmma5ryr5bine3fluoren1dixmis4ti_de3ra_de3rie3chasrch4err4ci4bm4inglm5ineedu2al_3miliame3tryrdi4er_des4crd3ingdi2rerme5thimet3alre5arr3mestim5ersadi2rende2ticdes3icre4cremen4temensu5re3disred5itre4facmen4dede2mosmen5acmem1o3reg3ismel5onm5e5dyme3died2d5ibren4te5mediare5pindd5a5bdata1bmba4t5cle4arma3tisma5scemar4lyre4spichs3huma5riz_dumb5re3strre4terbrus4qre3tribio1rhre5utiman3izre4valrev3elbi1orbbe2vie_eas3ire5vilba1thyman5is5maniamal4tymal4lima5linma3ligmag5inav3ioul5vet4rg3inglus3teanti1dl5umn_ltur3a_el3emltera4ltane5lp5ingloun5dans5gra2cabllos5etlor5ouric5aslo5rie_enam35ricidri4cie5lope_rid5erri3encri3ent_semi5lom3errig5an3logicril3iz5rimanlob5allm3ingrim4pell5out5rina__er4ril5linal2lin4l3le4tl3le4nriph5eliv3er_ge5og_han5k_hi3er_hon3olin3ea1l4inel4im4p_idol3_in3ci_la4cy_lath5rit3iclim4blrit5urriv5elriv3et4l4i4lli4gra_leg5elif3errk4linlid5er4lict_li4cor5licioli4atorl5ish_lig5a_mal5o_man5a_mer3c5less_rm5ersrm3ingy3thinle5sco3l4erilera5b5lene__mon3ele4matld4erild4erela4v4ar1nis44lativ_mo3rola5tanlan4telan5etlan4dllab3ic_mu5takin4dek3est_ro5filk3en4dro5ker5role__of5te4jestyys3icaron4al5izont_os4tlron4tai4v3ot_pe5tero3pelrop3ici5voreiv5il__pio5n_pre3mro4the_ran4tiv3en_rov5eliv3ellit3uati4tramr5pentrp5er__rit5ui4tismrp3ingit5ill_ros5tit3ica4i2tici5terirre4stit3era4ita5mita4bi_row5dist4lyis4ta_is4sesrsa5tiissen4is4sal_sci3erse4crrs5er_islan4rse5v2yo5netish5opis3honr4si4bis5han5iron_ir4minrtach4_self5iri3turten4diri5dei4rel4ire4de_sell5r4tieriq3uidrtil3irtil4lr4tilyr4tistiq5uefip4re4_sing4_ting4yn3chrru3e4lion3at2in4th_tin5krum3pli4no4cin3ityrun4ty_ton4aruti5nymbol5rvel4i_top5irv5er_r5vestin5geni5ness_tou5s_un3cein3cerincel45ryngei4n3auim3ulai5miniimi5lesac3riim5ida_ve5rasalar4ima5ryim3ageill5abil4istsan4deila5rai2l5am_wil5ii4ladeil3a4bsa5voright3iig3eraab5erd4ific_iff5enif5eroi3entiien5a45ie5gaidi5ou3s4cieab5latidi4arid5ianide3al4scopyab5rogid5ancic3ulaac5ardi2c5ocic3ipaic5inase2c3oi4carai4car_se4d4ei2b5riib5iteib5it_ib5ertib3eraac5aroi4ativ4ian4tse4molsen5ata5ceouh4warts5enedhus3t4s5enin4sentd4sentlsep3a34s1er_hun5kehu4min4servohro3poa5chethov5el5se5umhouse3sev3enho5senhort3eho5rishor5at3hol4ehol5arh5odizhlo3riac5robhis3elhion4ehimer4het4edsh5oldhe2s5ph5eroushort5here5aher4bahera3p3side_5sideshen5atsi5diz4signahel4lyact5ifhe3l4ihe5do55sine_h5ecathe4canad4dinsion5aad5er_har4lehard3e3sitioha5rasha3ranhan4tead3icahang5oadi4ersk5inesk5ing5hand_han4cyhan4cislith5hala3mh3ab4lsmall32g5y3n5gui5t3guard5smithad5ranaeri4eag5ellag3onia5guerso4labsol3d2so3licain5in4grada3s4on_gor5ougo5rizgondo5xpan4dait5ens5ophyal3end3g4o4ggnet4tglad5i5g4insgin5ge3g4in_spen4d2s5peog3imen5gies_3spher5giciagh5outsp5ingge5nizge4natge5lizge5lisgel4inxi5miz4gativgar5n4a5le5oga3nizgan5isga5mets5sengs4ses_fu4minfres5cfort5assi4erss5ilyfore5tfor5ayfo5ratal4ia_fon4dessur5aflo3ref5lessfis4tif1in3gstam4i5stands4ta4p5stat_fin2d5al5levs5tero4allicstew5afight5fi5del5ficie5ficiafi3cer5stickf3icena5log_st3ingf3icanama5ra5stockstom3a5stone2f3ic_3storef2f5iss4tradam5ascs4trays4tridf5fin_fend5efeath3fault5fa3thefar5thfam5is4fa4mafall5eew3inge5verbeven4ie5vengevel3oev3ellev5asteva2p5euti5let5roset3roget5rifsy5rinet3ricet5onaam5eraam5ilyami4noamor5ieti4noe5tidetai5loethod3eten4dtal5enes5urramp5enan3ageta5loge5strotan4detanta3ta5pere3ston4es2toes5times3tigta3rizestan43analy4taticta4tures4prean3arces3pertax4ises5onaes3olue5skintch5etanar4ies4i4ntead4ie2s5ima3natiande4sesh5enan3disan4dowang5iete5geres5ences5ecres5cana4n1icte2ma2tem3at3tenanwrita45erwau4tenesert3era3nieser3set5erniz4erniter4nis5ter3de4rivaan3i3fter3isan4imewo5vener3ineeri4ere3rient3ess_teth5e5ericke1ria4er3ester5esser3ent4erenea5nimier5enaer3emoth3easthe5atthe3iser5el_th5ic_th5icaere3in5thinkere5coth5odea5ninee3realan3ishan4klier4che5anniz4erandti4atoanoth5equi3lep5utat4ic1uan4scoe4probep3rehe4predans3poe4precan4surantal4e3pe
29230nttim5ulep5anceo5rol3tine_eop3aran4tiewin4deap5eroen3ishen5icsen3etren5esten5esien5eroa3pheren3dicap3itae4nanten5amoem5ulaa3pituti3zen5emnize5missem5ishap5olaem5ine3tles_t5let_em1in2apor5iem3icaem5anael3op_el4labapos3te3liv3el5ishaps5esweath3e3lierel3icaar3actwa5verto3nate3libee4l1erel3egato3rietor5iza5radeelaxa4aran4gto3warelan4dej5udie5insttra5chtraci4ar5av4wa5gere5git5arbal4ar5easeg5ing4voteetrem5iar3enta5ressar5ial4tricsvor5abe3finetro5mitron5i4tronyar3iantro3sp5eficia3rieted5uloed3icae4d1erec3ulaec4tane4cremeco5roec3orae4concar5o5de4comme4cluse4clame5citeec5ifya5ronias3anta5sia_tu4nis2t3up_ecan5ce4belstur3ise4bel_eav3ene4a3tue5atifeath3ieat5eneart3eear4ilear4icear5eseam3ereal3oueal5erea5geread5iedum4be4ducts4duct_duc5eras3tenasur5adrea5rat3abl4d5outdo3natdom5izdo5lor4dlessu4bero3dles_at3alou3ble_d4is3tdirt5idi5niz3dine_at5ech5di3endi4cam1d4i3ad3ge4tud5estdev3ilde3strud3iedud3iesdes3tide2s5oat3egovis3itde4nardemor5at3en_uen4teuer4ilde5milat3eraugh3en3demicater5nuil5izdeli4ede5comde4cildecan4de4bonv3io4rdeb5it4dativ2d3a4bat3estu5laticu4tie5ulcheul3dercuss4icu5riaath5em3cultua5thenul3ingul5ishul4lar4vi4naul4liscu5ityctim3ic4ticuuls5esc5tantultra3ct5angcros4ecrop5ocro4pl5critiath5omum4blycre3at5vilitumor5oat5i5b5crat_cras5tcoro3ncop3iccom5ercol3orun5ishco3inc5clareat3ituunt3abat5ropun4tescit3iz4cisti4cista4cipicc5ing_cin3em3cinatuper5s5videsup3ingci2a5b5chini5videdupt5ib5vide_at4tag4ch1inch3ersch3er_ch5ene3chemiche5loure5atur4fercheap3vi5aliat3uravet3er4ch3abc5e4taau5sib3cessives4tece5ram2cen4e4cedenccou3turs5erur5tesur3theaut5enur4tiecav5al4cativave4nover3thcar5omca5percan4tycan3izcan5iscan4icus4lin3versecal4laver3ieca3latca5dencab3in3butiobuss4ebus5iebunt4iv4eresuten4i4u1t2iv3erenu3tineut3ingv4erelbroth35u5tizbound34b1orabon5at5vere_bom4bibol3icblun4t5blespblath5av3erav5enuebi3ogrbi5netven3om2v1a4bvac5ilbi3lizbet5izbe5strva5liebe5nigbbi4nabas4siva5nizbari4aav5ernbarbi5av5eryvel3liazi4eravi4er",
29231        7: "_dri5v4ban5dagvar5iedbina5r43bi3tio3bit5ua_ad4derution5auti5lizver5encbuf4ferus5terevermi4ncall5incast5ercas5tigccompa5z3o1phros5itiv5chanicuri4fico5stati5chine_y5che3dupport54v3iden5cific_un4ter_at5omiz4oscopiotele4g5craticu4m3ingv3i3liz4c3retaul4li4bcul4tiscur5a4b4c5utiva5ternauiv4er_del5i5qdem5ic_de4monsdenti5fdern5izdi4latou4b5ingdrag5on5drupliuar5ant5a5si4tec5essawo4k1enec5ifiee4compear5inate4f3eretro5phewide5sp5triciatri5cesefor5ese4fuse_oth5esiar5dinear4chantra5ventrac4tetrac4itar5ativa5ratioel5ativor5est_ar5adisel5ebraton4alie4l5ic_wea5rieel5igibe4l3ingto5cratem5igraem3i3niemoni5oench4erwave1g4a4pillavoice1ption5eewill5inent5age4enthesvaude3vtill5inep5recaep5ti5bva6guer4erati_tho5rizthor5it5thodicer5ence5ternitteri5zater5iesten4tage4sage_e4sagese4sert_an5est_e4sertse4servaes5idenes5ignaesis4tees5piraes4si4btal4lisestruc5e5titioounc5erxe4cutota5bleset5itiva4m5atoa4matis5stratu4f3ical5a5lyst4ficatefill5instern5isspend4gani5zasqual4la4lenti4g3o3nas5ophiz5sophicxpecto55graph_or5angeuri4al_4graphy4gress_smol5d4hang5erh5a5nizharp5enhar5terhel4lishith5erhro5niziam5eteia4tricic4t3uascour5au2r1al_5scin4dover4nescan4t55sa3tiou5do3ny_ven4de_under5ty2p5al_anti5sylla5bliner4arturn3ari5nite_5initioinsur5aion4eryiphras4_tim5o5_ten5an_sta5blrtroph4_se5rieiq3ui3t5i5r2izis5itiviso5mer4istral5i5ticki2t5o5mtsch3ie_re5mittro3fiti4v3er_i4vers_ros5per_pe5titiv3o3ro_ped5alro5n4is_or5ato4jestierom5ete_muta5bk5iness4latelitr4ial__mist5i_me5terr4ming_lev4er__mar5tilev4eralev4ers_mag5a5liar5iz5ligaterit5ers_lat5errit5er_r5ited__im5pinri3ta3blink5er_hon5ey5litica_hero5ior5aliz_hand5irip5lic_gen3t4tolo2gylloqui5_con5grt1li2erbad5ger4operag_eu4lertho3donter2ic__ar4tie_ge4ome_ge5ot1_he3mo1_he3p6a_he3roe_in5u2tpara5bl5tar2rht1a1mintalk1a5ta3gon_par5age_aster5_ne6o3f_noe1thstyl1is_poly1s5pathic_pre1ampa4tricl3o3niz_sem4ic_semid6_semip4_semir45ommend_semiv4lea4s1a_spin1oom5etryspher1o_to6poglo4ratospe3cio3s2paceso2lute_we2b1l_re1e4ca5bolicom5erseaf6fishside5swanal6ysano5a2cside5stl5ties_5lumniasid2ed_anti1reshoe1stscy4th1s4chitzsales5wsales3cat6tes_augh4tlau5li5fom5atizol5ogizo5litiorev5olure5vertre5versbi5d2ifbil2lab_earth5pera5blro1tronro3meshblan2d1blin2d1blon2d2bor1no5ro1bot1re4ti4zr5le5quperi5stper4malbut2ed_but4tedcad5e1moist5enre5stalress5ibchie5vocig3a3roint5er4matizariv1o1lcous2ticri3tie5phisti_be5stoog5ativo2g5a5rr3a3digm4b3ingre4posir4en4tade4als_od5uctsquasis6quasir6re5fer_p5trol3rec5olldic1aiddif5fra3pseu2dr5ebrat5metric2d1lead2d1li2epro2g1epre1neuod5uct_octor5apoin3came5triem5i5liepli5narpara3memin5glim5inglypi4grappal6matmis4er_m5istryeo3graporth1riop1ism__but4tio3normaonom1icfeb1ruafermi1o_de4moio5a5lesodit1icodel3lirb5ing_gen2cy_n4t3ingmo5lestration4get2ic_4g1lishobli2g1mon4ismnsta5blmon4istg2n1or_nov3el3ns5ceivno1vembmpa5rabno4rarymula5r4nom1a6lput4tinput4tedn5o5miz_cam4penag5er_nge5nesh2t1eoun1dieck2ne1skiifac1etncour5ane3backmono1s6mono3chmol1e5cpref5ac3militapre5tenith5i2lnge4n4end5est__capa5bje1re1mma1la1ply5styr1kovian_car5olprin4t3lo2ges_l2l3ishprof5it1s2tamp",
29232        8: "lead6er_url5ing_ces5si5bch5a5nis1le1noidlith1o5g_chill5ilar5ce1nym5e5trych5inessation5arload4ed_load6er_la4c3i5elth5i2lyneg5ativ1lunk3erwrit6er_wrap3arotrav5es51ke6linga5rameteman3u1scmar1gin1ap5illar5tisticamedio6c1me3gran3i1tesima3mi3da5bves1titemil2l1agv1er1eigmi6n3is_1verely_e4q3ui3s5tabolizg5rapher5graphicmo5e2lasinfra1s2mon4ey1lim3ped3amo4no1enab5o5liz_cor5nermoth4et2m1ou3sinm5shack2ppo5sitemul2ti5uab5it5abimenta5rignit1ernato5mizhypo1thani5ficatuad1ratu4n5i4an_ho6r1ic_ua3drati5nologishite3sidin5dling_trib5utin5glingnom5e1non1o1mistmpos5itenon1i4so_re5stattro1p2istrof4ic_g2norespgnet1ism5glo5binlem5aticflow2er_fla1g6elntrol5lifit5ted_treach1etra1versl5i5ticso3mecha6_for5mer_de5rivati2n3o1me3spac6i2t3i4an_thy4l1antho1k2er_eq5ui5to4s3phertha4l1amt3ess2es3ter1geiou3ba3dotele1r6ooxi6d1iceli2t1isonspir5apar4a1leed1ulingea4n3iesoc5ratiztch3i1er_kil2n3ipi2c1a3dpli2c1abt6ap6athdrom3e5d_le6icesdrif2t1a_me4ga1l1prema3cdren1a5lpres2plipro2cess_met4ala3do5word1syth3i2_non1e2m_post1ampto3mat4rec5ompepu5bes5cstrib5utqu6a3si31stor1ab_sem
292326is4star3tliqui3v4arr1abolic_sph6in1de5clar12d3aloneradi1o6gs3qui3tosports3wsports3cra5n2hascro5e2cor3bin1gespokes5wspi2c1il_te3legrcroc1o1d_un3at5t_dictio5cat1a1s2buss4ingbus6i2esbus6i2erbo2t1u1lro5e2las1s2pacinb1i3tivema5rine_r3pau5li_un5err5r5ev5er__vi2c3arback2er_ma5chinesi5resid5losophyan3ti1n2sca6p1ersca2t1olar2rangesep3temb1sci2uttse3mes1tar3che5tsem1a1ph",
29233        9: "re4t1ribuuto5maticl3chil6d1a4pe5able1lec3ta6bas5ymptotyes5ter1yl5mo3nell5losophizlo1bot1o1c5laratioba6r1onierse1rad1iro5epide1co6ph1o3nscrap4er_rec5t6angre2c3i1prlai6n3ess1lum5bia_3lyg1a1miec5ificatef5i5nites2s3i4an_1ki5neticjapan1e2smed3i3cinirre6v3ocde2c5linao3les3termil5li5listrat1a1gquain2t1eep5etitiostu1pi4d1v1oir5du1su2per1e6_mi1s4ers3di1methy_mim5i2c1i5nitely_5maph1ro15moc1ra1tmoro6n5isdu1op1o1l_ko6r1te1n3ar4chs_phi2l3ant_ga4s1om1teach4er_parag6ra4o6v3i4an_oth3e1o1sn3ch2es1to5tes3toro5test1eror5tively5nop5o5liha2p3ar5rttrib1ut1_eth1y6l1e2r3i4an_5nop1oly_graph5er_5eu2clid1o1lo3n4omtrai3tor1_ratio5na5mocratiz_rav5en1o",
29234        10: "se1mi6t5ic3tro1le1um5sa3par5iloli3gop1o1am1en3ta5bath3er1o1s3slova1kia3s2og1a1myo3no2t1o3nc2tro3me6c1cu2r1ance5noc3er1osth1o5gen1ih3i5pel1a4nfi6n3ites_ever5si5bs2s1a3chu1d1ri3pleg5_ta5pes1trproc3i3ty_s5sign5a3b3rab1o1loiitin5er5arwaste3w6a2mi1n2ut1erde3fin3itiquin5tes5svi1vip3a3r",
29235        11: "pseu3d6o3f2s2t1ant5shimi1n2ut1estpseu3d6o3d25tab1o1lismpo3lyph1onophi5lat1e3ltravers3a3bschro1ding12g1o4n3i1zat1ro1pol3it3trop1o5lis3trop1o5lesle3g6en2dreeth1y6l1eneor4tho3ni4t",
29236        12: "3ra4m5e1triz1e6p3i3neph1"
29237    },
29238    patternChars: "_abcdefghijklmnopqrstuvwxyz",
29239    patternArrayLength: 113949,
29240    valueStoreLength: 20195
29241};
29242
29243// For questions about the spanish hyphenation patterns
29244// ask Luis Pabon (lpabon at metagrama dot es)
29245/*global Hyphenator*/
29246Hyphenator.languages['es'] = {
29247    leftmin: 2,
29248    rightmin: 2,
29249    specialChars: "áéíóúñ",
29250    patterns: {
29251        2: "1b1c1d1f1g1j1k1l1m1n1ñ1p1q1r1s1t1v1w1x1y1z",
29252        3: "_a22bb2bc2bd2bf2bg2bj2bkb2l2bm2bn2bp2bqb2r2bs2bt2bv2bw2bx2by2bz2cb2cc2cd2cf2cgc4h2cjc2kc2l2cm2cn2cp2cqc2r2cs2ct2cv2cw2cx2cy2cz2db2dc2dd2df2dg2dj2dk2dl2dm2dn2dp2dqd2r2ds2dt2dv2dw2dx2dy2dz4e_4é_4és2fb2fc2fd2ff2fg2fj2fkf2l2fm2fn2fp2fqf2r2fs2ft2fv2fw2fx2fy2fz2gb2gc2gd2gf2gg2gj2gkg2l2gm2gn2gp2gqg2r2gs2gt2gv2gw2gx2gy2gz2hb2hc2hd2hf2hg2hj2hk2hl2hm2hn2hp2hq2hr2hs2ht2hv2hw2hx2hy2hz4í_2jb2jc2jd2jf2jg2jj2jk2jl2jm2jn2jp2jq2jr2js2jt2jv2jw2jx2jy2jz2kb2kc2kd2kf2kg2kj2kkk2l2km2kn2kp2kqk2r2ks2kt2kv2kw2kx2ky2kz2lb2lc2ld2lf2lg2lj2lkl4l2lm2ln2lp2lq2lr2ls2lt2lv2lw2lx2ly2lz2mb2mc2md2mf2mg2mj2mk2ml2mm2mn2mp2mq2mr2ms2mt2mv2mw2mx2my2mz2nb2nc2nd2nf2ng2nj2nk2nl2nm2nn2np2nq2nr2ns2nt2nv2nw2nx2ny2nz2o_2pb2pc2pd2pf2pg2pj2pkp2l2pm2pn2pp2pqp2r2ps2pt2pv2pw2px2py2pz2qb2qc2qd2qf2qg2qj2qk2ql2qm2qn2qp2qq2qr2qs2qt2qv2qw2qx2qy2qz2rb2rc2rd2rf2rg2rj2rk2rl2rm2rn2rp2rqr2r2rs2rt2rv2rw2rx2ry2rz2sb2sc2sd2sf2sg2sj2sk2sl2sm2sn2sp2sq2sr2ss2st2sv2sw2sx2sy2sz2tb2tc2td2tf2tg2tj2tk2tm2tn2tp2tqt2r2ts2tt2tv2twt2x2ty2tz2vb2vc2vd2vf2vg2vj2vkv2l2vm2vn2vp2vqv2r2vs2vt2vv2vw2vx2vy2vz2wb2wc2wd2wf2wg2wj2wkw2l2wm2wn2wp2wqw2r2ws2wt2wv2ww2wx2wy2wz2xb2xc2xd2xf2xg2xj2xk2xl2xm2xn2xp2xq2xr2xs2xt2xv2xw2xx2xy2xz2yb2yc2yd2yf2yg2yj2yk2yl2ym2yn2yp2yq2yr2ys2yt2yv2yw2yx2yy2yz2zb2zc2zd2zf2zg2zj2zk2zl2zm2zn2zp2zq2zr2zs2zt2zv2zw2zx2zy2zz",
29253        4: "4ad_2al_4an_4ar_4as_4ás_2b1h2bl_2br_2ch_2cl_4cn_2cr_4ct_4cz_2d1h2dr_4ed_4en_4er_4es_2f1h2fl_2fr_4ft_2g2h2gl_4gn_2gr_2h1hi2a_4ía_i2o_2j1h2k2h2kl_2kr_2l1h2ll_mal22m1h4mn_2n1h2no_4ón_2os_4pc_2p1h2pl_4pn_2pr_4pt_2q1h2r1h2rr_3sa_2s1h2t1h2t2l2tr_4ts_4tz_2v1h2vl_2vr_2w1h2wl_2wr_2x1h2y1h2z1h",
29254        5: "_an3h4áis_4ando4aos_bien2bio1heco1h4éis_4eos_geo1h4ían_i2as_4ías_i2os_iso1hmal3bmal3cmal3dmal3fmal3gmal3mmal3pmal3qmal3smal3tmal3v4meo_neo1ho2os_2ótic3sas_s3te_",
29255        6: "_an2a2_an2á2_an2e2_an2é2_an2i2_an2í2_ani3m_aniña_ani3q_an2o2_an2ó2_an2u2_anu3l_bi1ox_bi1un_co2a2_co2á2_co2e2_co2é2_co2i2_co2í2_co3o4_co2ó2_co2u2_co2ú2_en2a2_en2á2_en2e2_en2é2_en1ej_en2i2_en2í2_en2o2_en2ó2_en2u2_en2ú2_in2a2_in2á2_in2e2_in2é2_in2i2_in2í2_in2o2_in2ó2_in2u2_in2ú2_re2a2_re2á2_re3e4_re2é2_re2i2_re2í2_re2o2_re2ó2_re1oc_re1oj_re2u2_re2ú24a3ba_acto1h4a3da_4adle_4adlo_4adme_4a3do_4adte_aero1hafro1haí5so_2ales_ana3líanfi1hante1h4a3ra_4a3rá_4a3re_4a3ré_a3rio_4a3se_4aste_asu3b24ates_auto1h2b3c2n2b3c2t2b3c2z2b3f2t2b3g2nbien3hbien3mbien3qbien3tbien3vbio1a2bio1á2bio1e2bio1é2bio1i2bio1í2bio1o2bio1ó2bio1u2bio1ú22b3m2n2b3p2n2b3p2s2b3p2t2b3t2s2b3t2z4caca44caga44cago42c3c2n2c3c2t2c3c2z2c3f2t2c3g2ncito1h2c3m2nco4artco4ártco4ercco4erzco4optco4ord2c3p2n2c3p2s2c3p2t2c3t2s2c3t2z4culo42d3c2n2d3c2t2d3c2zdeca1hde3seo2d3f2t2d3g2n2d3m2n2d3p2n2d3p2s2d3p2t2d3t2s2d3t2zeco1a2eco1á2eco1e2eco1é2eco1i2eco1í2eco1o2eco1ó2eco1u2eco1ú24edle_4edlo_4edme_4edte_emi2o2endo1hento1h4e3rá_4e3ré_4erla_4erle_4erlo_4erme_4erse_4erte_euco1heuro1hfono1hfoto1hgeo1a2geo1á2geo1e2geo1é2geo1i2geo1í2geo1o2geo1ó2geo1u2geo1ú2hemi1hhemo1hhexa1hhomo1h4íais_2i3ca_2i3co_4í3da_4í3do_4i4er_4i3ga_4i3go_4ísmo_iso1a2iso1á2iso1e2
29255iso1é2iso1i2iso1í2iso1o2iso1ó2iso1u2iso1ú24ísta_kilo1h2l3c2n2l3c2t2l3c2z2l3f2t2l3g2n2l3m2n2l3p2n2l3p2s2l3p2t2l3t2s2l3t2zma4l3hmaxi1h2m3c2n2m3c2t2m3c2zmega1h2m3f2t2m3g2nmili1hmini1h2m3m2nmono1h2m3p2n2m3p2s2m3p2t2m3t2s2m3t2znamo1h2n3c2n2n3c2t2n3c2zneo1a2neo1á2neo1e2neo1é2neo1i2neo1í2neo1o2neo1ó2neo1u2neo1ú2neto1h2n3f2t2n3g2n2n3m2n2n3p2n2n3p2s2n3p2t2n3t2s2n3t2zocta1hocto1homni1h4ones_2o3sa_2o3so_para1h4pedo4poli1h3p2sic3p2siq4puta44puto42r3c2n2r3c2t2r3c2z2r3f2t2r3g2n2r3m2nromo1h2r3p2n2r3p2s2r3p2t2r3t2s2r3t2z2s3c2n2s3c2t2s3c2zsemi1h2s3f2t2s3g2n2s3m2n2s3p2n2s3p2s2s3p2ts3tal_s3tes_s3tor_2s3t2s2s3t2zsup6ra2t3c2n2t3c2t2t3c2ztele1h4teta_2t3f2t2t3g2n2t3m2ntopo1h2t3p2n2t3p2s2t3p2t2t3t2s2t3t2zu4teriwa3s4h2x3c2n2x3c2t2x3c2zxeno1h2x3f2t2x3g2n2x3m2n2x3p2n2x3p2s2x3p2t2x3t2s2x3t2z2y3c2n2y3c2t2y3c2z2y3f2t2y3g2n2y3m2n2y3p2n2y3p2s2y3p2t2y3t2s2y3t2z",
29256        7: "_ana3li_aná3li_ane3xa_ane3xá_ane3xe_ane3xé_ani3ll_ano5ta_ano3tá_anti1h_an2ú2__anua3l_anu3bl_anu3da_bi1aur_bi1ó2x_en1apa_en1arb_en1art_he4mee_hu4mea_hu4meo_mala1e_pre2a2_pre2á2_pre2e2_pre2é2_pre2h2_pre2i2_pre2í2_pre2o2_pre2ó2_pre2u2_pre2ú2_pro2a2_pro2á2_pro2e2_pro2é2_pro2h2_pro2i2_pro2í2_pro2o2_pro2ó2_pro2u2_pro2ú2_re3abr_re3ábr_re3a2q_re3a2z_re3i2m_re3inc_re3ing_re3ins_re3int_re3o2b_re1unt_so3a4s4a3ban_4a3bas_acante2acto1a2acto1á2acto1e2acto1é2acto1i2acto1í2acto1o2acto1ó2acto1u2acto1ú24a3das_4adlas_4adles_4adlos_4adnos_4a3dor_4a3dos_aero1a2aero1á2aero1e2aero1é2aero1i2aero1í2aero1o2aero1ó2aero1u2aero1ú2afro1a2afro1á2afro1e2afro1é2afro1i2afro1í2afro1o2afro1ó2afro1u2afro1ú2aí5sos_4a3mos_anfi1a2anfi1á2anfi1e2anfi1é2anfi1i2anfi1í2anfi1o2anfi1ó2anfi1u2anfi1ú2anglo1hante1a2ante1á2ante1e2ante1é2ante1i2ante1í2ante1o2ante1ó2ante1u2ante1ú24áosla_4áosle_4áoslo_4a3ran_4a3rán_4a3ras_4a3rás_archi1h4a3ren_4a3res_4a3rés_4a3ría_a3rios_4a3rís_4a4rme_4a3ron_4a3ros_4a3sen_4a3ses_4astes_auto1a2auto1á2auto1e2auto1é2auto1i2auto1í2auto1o2auto1ó2auto1u2auto1ú2bi1u2ní4cagas_centi1hciclo1hcito1a2cito1á2cito1e2cito1é2cito1i2cito1í2cito1o2cito1ó2cito1u2cito1ú23c2neorcnico1hco4accico4actico4adjuco4adyuco3agenco4e3táco3exisco4imbrco4incico4i3tocon1urbcrono1hdeca1a2deca1á2deca1e2deca1é2deca1i2deca1í2deca1o2deca1ó2deca1u2deca1ú2decimo1desa3fidesa3fídesa3güde4s3eqde3signde3sollea3cia_ea3cio_4eadla_ecano1hectro1h4edlas_4edles_4edlos_4ednos_4e3dro_4eedla_4emboca4e3mos_endo1a2endo1á2end
29256o1e2endo1é2endo1i2endo1í2endo1o2endo1ó2endo1u2endo1ú2ento1a2ento1á2ento1e2ento1é2ento1i2ento1í2ento1o2ento1ó2ento1u2ento1ú2entre1h4éosla_4éosle_4éoslo_e5r4ad_e5r4an_4e3rán_e5r4as_4e3rás_4e3rés_4e3ría_4e3rís_4erlas_4erles_4erlos_4ernos_4e3ros_euco1a2euco1á2euco1e2euco1é2euco1i2euco1í2euco1o2euco1ó2euco1u2euco1ú2euro1a2euro1á2euro1e2euro1é2euro1i2euro1í2euro1o2euro1ó2euro1u2euro1ú2expoli4extra1hfono1a2fono1á2fono1e2fono1é2fono1i2fono1í2fono1o2fono1ó2fono1u2fono1ú2foto1a2foto1á2foto1e2foto1é2foto1i2foto1í2foto1o2foto1ó2foto1u2foto1ú2gluco1hhecto1hhelio1hhemi1a2hemi1á2hemi1e2hemi1é2hemi1i2hemi1í2hemi1o2hemi1ó2hemi1u2hemi1ú2hemo1a2hemo1á2hemo1e2hemo1é2hemo1i2hemo1í2hemo1o2hemo1ó2hemo1u2hemo1ú2hexa1a2hexa1á2hexa1e2hexa1é2hexa1i2hexa1í2hexa1o2hexa1ó2hexa1u2hexa1ú2hidro1hhisto1hhomo1a2homo1á2homo1e2homo1é2homo1i2homo1í2homo1o2homo1ó2homo1u2homo1ú2ia5res_2i3cas_icono1h2i3cos_4i2dal_4í3das_4i3deo_4í3dos_4i3gas_4i3gás_4í3mos_infra1hintra1h4ísmos_4ístas_4í3tes_kilo1a2kilo1á2kilo1e2kilo1é2kilo1i2kilo1í2kilo1o2kilo1ó2kilo1u2kilo1ú2li5áreamacro1hmante4amaxi1a2maxi1á2maxi1e2maxi1é2maxi1i2maxi1í2maxi1o2maxi1ó2maxi1u2maxi1ú2mega1a2mega1á2mega1e2mega1é2mega1i2mega1í2mega1o2mega1ó2mega1u2mega1ú23mente_micro1hmili1a2mili1á2mili4armili1e2mili1é2mili1i2mili1í2mili1o2mili1ó2mili1u2mili1ú2mini1a2mini1á2mini1e2mini1é2mini1i2mini1í2mini1o2mini1ó2mini1u2mini1ú2miria1hmono1a2mono1á2mono1e2mono1é2mono1i2mono1í2mono1o2mono1ó2mono1u2mono1ú2multi1hnamo1a2namo1á2namo1e2namo1é2namo1i2namo1í2namo1o2namo1ó2namo1u2namo1ú2necro1hneto1a2neto1á2neto1e2neto1é2neto1i2neto1í2neto1o2neto1ó2neto1u2neto1ú2norte1hocta1a2octa1á2octa1e2octa1é2octa1i2octa1í2octa1o2octa1ó2octa1u2octa1ú2octo1a2octo1á2octo1e2octo1é2octo1i2octo1í2octo1o2octo1ó2octo1u2octo1ú24o2ica_4o2ico_oligo1homni1a2omni1á2omni1e2omni1é2omni1i2omni1í2omni1o2omni1ó2omni1u2omni1ú22o3sas_2o3sos_4ósteo_paleo1hpara1a2para1á2para1e2para1é2para1i2para1í2para1o2para1ó2para1u2para1ú2penta1hpiezo1hpluri1hpoi3de_poli1a2poli1á2poli1e2poli1é2poli1i2poli1í2poli1o2poli1ó2poli1u2poli1ú2pos3ta_pre3olíproto1hradio1hranco1hretro1hrmano1hromo1a2romo1á2romo1e2romo1é2romo1i2romo1í2romo1o2romo1ó2romo1u2romo1ú2san4c5tsemi1a2semi1á2semi1e2semi1é2semi1i2semi1í2semi1o2semi1ó2semi1u2semi1ú2seudo1hsobre1hsocio1hs3tora_supra1htalmo1htele1a2tele1á2tele1e2tele1é2tele1i2tele1í2tele1o2tele1ó2tele1u2tele1ú2termo1h4tetas_tetra1hti2o3coti2o3qutopo1a2topo1á2topo1e2topo1é2topo1i2topo1í2topo1o2topo1ó2topo1u2topo1ú2tropo1hultra1hxeno1a2xeno1á2xeno1e2xeno1é2xeno1i2xeno1í2xeno1o2xeno1ó2xeno1u2xeno1ú2",
29257        8: "_an3aero_ane3xio_ane3xió_ani3dar_ani3mad_ani3mád_an3i2so_an3i2só_ani3vel_ano5che_ano5din_ano5mal_anó5mal_ano5nad_ano5nim_anó3nim_anti1a2_anti1á2_anti1e2_anti1é2_anti1i2_anti1í2_anti1o2_anti1ó2_anti1u2_anti1ú2_anua4lm_de2s2a2_de2s2á2_de2s2e2_de2s2é2_de2s2i2_de2s2í2_de2s2o2_de2s2ó2_de2s2u2_de2s2ú2_en1aciy_en1anch_en2artr_eno3jar_hepta1e_ina3nic_in3anim_iná3nim_in3apel_iné3dit_in3efic_ini3cia_ini3ciá_ini3cie_ino3cua_ino3cuo_intra1o_intra1u_inú3til_mal1est_mal1int_pos3tin_pos3tín_re3a2eg_re3alim_re3anim_re3aním_re3orga_retro1a_re3unir_re3unír_re3usar_re3usár_su2b2a2_su2b2á2_sub3arr_su2b2e2_su2b2é2_su2b2i2_su2b2í2_sub3ími_sub3índ_su2b2o2_su2b2ó2_su2b2u2_su2b2ú2_sur1est_sur1oes_tra2s1a_tra2s1o_tri1ó2x4a3bais_4a3ción_4ádmele_4ádmelo_4a3dora_4ádsela_4ádsele_4ádselo_4ádtele_4ádtelo_4ándola_4ándole_4ándolo_4ándome_4ándoos_4ándose_4ándote_anglo1a2anglo1á2anglo1e2anglo1é2anglo1i2anglo1í2anglo1o2anglo1ó2anglo1u2anglo1ú24áoslas_4áosles_4áoslos_4a3rais_archi1a2archi1á2archi1e2archi1é2archi1i2archi1í2archi1o2archi1ó2archi1u2archi1ú24a3reis_4a3réis_4a3ríais4a3rían_4a3rías_4a4r3la_4a4r3le_4a4r3lo_4árosla_4árosle_4ároslo_4a4r3se_4a4r3te_4a3seis_4asteis_biblio1hcardio1hcefalo1hcenti1a2centi1á2centi1e2centi1é2centi1i2centi1í2centi1o2centi1ó2centi1u2centi1ú2ciclo1a2ciclo1á2ciclo1e2ciclo1é2ciclo1i2ciclo1í2ciclo1o2ciclo1ó2ciclo1u2ciclo1ú2cnico1a2cnico1á2cnico1e2cnico1é2cnico1i2cnico1í2cnico1o2cnico1ó2cnico1u2cnico1ú2co4a3dunco4a3gulco4á3gulco4a3licco4aptacco4e3ficcon1imbrcontra1hco4o3perco4o3pércripto1hcrono1a2crono1á2crono1e2crono1é2crono1i2crono1í2crono1o2crono1ó2crono1u2crono1ú2de4s3abrde4s3agudesa3lindesa3livde4s3almdesa3lojde4s3anddesa3pañdesa3pegde4s3armdes4armede4s3asndesa3tindesa3yundesa3zondesa3zónde3semejde4s3endde4s3enjde4s3enmde4s3enrde4s3ensde3s4ertde3s4
29257értde3siderde3sidiade3sidiode3siertde3socupde3solacde3soladde3soncede4s3ovade4s3ovide4s3oxide4s3oyede4s3oyéde3suelldodeca1hea3cias_ea3cios_ecano1a2ecano1á2ecano1e2ecano1é2ecano1i2ecano1í2ecano1o2ecano1ó2ecano1u2ecano1ú2ectro1a2ectro1á2ectro1e2ectro1é2ectro1i2ectro1í2ectro1o2ectro1ó2ectro1u2ectro1ú24édmele_4édmelo_4e3dros_4édsela_4édsele_4édselo_4édtele_4édtelo_entre1a2entre1á2entre1e2entre1é2entre1i2entre1í2entre1o2entre1ó2entre1u2entre1ú24éoslas_4éosles_4éoslos_e5r4áis_4e3réis_4e3rían_4e3rías_4e3rior_4érmele_4érmelo_4érsela_4érsele_4érselo_4értele_4értelo_extra1a2extra1á2extra1e2extra1é2extra1i2extra1í2extra1o2extra1ó2extra1u2extra1ú2gastro1hgluco1a2gluco1á2gluco1e2gluco1é2gluco1i2gluco1í2gluco1o2gluco1ó2gluco1u2gluco1ú2hecto1a2hecto1á2hecto1e2hecto1é2hecto1i2hecto1í2hecto1o2hecto1ó2hecto1u2hecto1ú2helio1a2helio1á2helio1e2helio1é2helio1i2helio1í2helio1o2helio1ó2helio1u2helio1ú2hemato1hhidro1a2hidro1á2hidro1e2hidro1é2hidro1i2hidro1í2hidro1o2hidro1ó2hidro1u2hidro1ú2hipe2r3rhisto1a2histo1á2histo1e2histo1é2histo1i2histo1í2histo1o2histo1ó2histo1u2histo1ú24ía3mos_icono1a2icono1á2icono1e2icono1é2icono1i2icono1í2icono1o2icono1ó2icono1u2icono1ú24i3deos_4i3gáis_infra1a2infra1á2infra1e2infra1é2infra1i2infra1í2infra1o2infra1ó2infra1u2infra1ú2inter4ésinter4inintra1a2intra1á2intra1e2intra1é2intra1i2intra1í2intra1o2intra1ó2intra1u2intra1ú24í4s3te_4ística_4ístico_macro1a2macro1á2macro1e2macro1é2macro1i2macro1í2macro1o2macro1ó2macro1u2macro1ú24meable_megalo1hmelano1hmicro1a2micro1á2micro1e2micro1é2micro1i2micro1í2micro1o2micro1ó2micro1u2micro1ú2miria1a2miria1á2miria1e2miria1é2miria1i2miria1í2miria1o2miria1ó2miria1u2miria1ú2multi1a2multi1á2multi1e2multi1é2multi1i2multi1í2multi1o2multi1ó2multi1u2multi1ú2necro1a2necro1á2necro1e2necro1é2necro1i2necro1í2necro1o2necro1ó2necro1u2necro1ú2norte1a2norte1á2norte1e2norte1é2norte1i2norte1í2norte1o2norte1ó2norte1u2norte1ú24o2icas_4o2icos_o4i3dal_4o2i3de_o4i3dea_oligo1a2oligo1á2oligo1e2oligo1é2oligo1i2oligo1í2oligo1o2oligo1ó2oligo1u2oligo1ú24ó3loga_4ó3logo_4ósteos_paleo1a2paleo1á2paleo1e2paleo1é2paleo1i2paleo1í2paleo1o2paleo1ó2paleo1u2paleo1ú2para2is_para4ísopenta1a2penta1á2penta1e2penta1é2penta1i2penta1í2penta1o2penta1ó2penta1u2penta1ú2piezo1a2piezo1á2piezo1e2piezo1é2piezo1i2piezo1í2piezo1o2piezo1ó2piezo1u2piezo1ú2plan4c5tpluri1a2pluri1á2pluri1e2pluri1é2pluri1i2pluri1í2pluri1o2pluri1ó2pluri1u2pluri1ú2poi3des_poli4arqpoli4árqpoli4u3rpos3tas_pre3eligpre3elijpre3eminpre3exispreo3cuppreo2cúppre3opinproto1a2proto1á2proto1e2proto1é2proto1i2proto1í2proto1o2proto1ó2proto1u2proto1ú2radio1a2radio1á2radio1e2radio1é2radio1i2radio1í2radio1o2radio1ó2radio1u2radio1ú2ranco1a2ranco1á2ranco1e2ranco1é2ranco1i2ranco1í2ranco1o2ranco1ó2ranco1u2ranco1ú2retro1a2retro1á2retro1e2retro1é2retro1i2retro1í2retro1o2retro1ó2retro1u2retro1ú2rmano1a2rmano1á2rmano1e2rmano1é2rmano1i2rmano1í2rmano1o2rmano1ó2rmano1u2rmano1ú2seudo1a2seudo1á2seudo1e2seudo1é2seudo1i2seudo1í2seudo1o2seudo1ó2seudo1u2seudo1ú2sobre1a2sobre1á2sobre1e2sobre1é2sobre1i2sobre1í2sobre1o2sobre1ó2sobre1u2sobre1ú2socio1a2socio1á2socio1e2socio1é2socio1i2socio1í2socio1o2socio1ó2socio1u2socio1ú2s3toras_s3tores_su4d3oessupe2r3rsupra1a2supra1á2supra1e2supra1é2supra1i2supra1í2supra1o2supra1ó2supra1u2supra1ú2talmo1a2talmo1á2talmo1e2talmo1é2talmo1i2talmo1í2talmo1o2talmo1ó2talmo1u2talmo1ú23te3ri3ntermo1a2termo1á2termo1e2termo1é2termo1i2termo1í2termo1o2termo1ó2termo1u2termo1ú2tetra1a2tetra1á2tetra1e2tetra1é2tetra1i2tetra1í2tetra1o2tetra1ó2tetra1u2tetra1ú2trans4artrans4ittropo1a2tropo1á2tropo1e2tropo1é2tropo1i2tropo1í2tropo1o2tropo1ó2tropo1u2tropo1ú2ultra1a2ultra1á2ultra1e2ultra1é2ultra1i2ultra1í2ultra1o2ultra1ó2ultra1u2ultra1ú2",
29258        9: "_bi1anual_bien1and_bien1apa_bien1ave_bien1est_bien1int_dieci1o2_en1aceit_en1aguaz_enu3mera_enu3merá_enu3mere_in3abarc_in3abord_in3acent_in3adapt_in3aplic_in3arrug_in3asist_in3efici_in3eludi_ine3narr_ino3cula_ino3culá_ino3cule_inte2r3r_mal1acon_mal1acos_pos2t2a2_pos2t2á2_pos2t2e2_pos2t2é2_pos3terg_pos2t2i2_pos2t2í2_post3ind_pos2t2o2_pos2t2ó2_post3ope_post3rev_pos2t2u2_pos2t2ú2_re3afirm_re3afírm_re3ajust_rea3júst_rea3lism_rea3list_rea3liza_rea3lizá_rea3líza_re3ubica_re3ubíca_reu3mati_reu3máti_su3b4ien_sub2i3ll_su4b3ray_sub3urba_su2d1est_sur1a2me_tele1imp_tele1obj_tra2s2oñ4á3bamos_4ád3mela_4ádmeles_4ádmelos_4ádnosla_4ádnosle_4ádnoslo_4a3doras_4a3dores_4ádselas_4ádseles_4ádselos_4ád3tela_4ádteles_4ádtelos_4a4i3gan_4ándolas_4ándoles_4ándolos_4ándonos_4á3ramos_4a3remos_4á3remos_4a4r3las_4a4r3les_4a4r3los_4á4rmele_4á4rmelo_4a4r3nos_4ároslas_4árosles_4ároslos_4á3semos_biblio1a2biblio1á2biblio1e2biblio1é2biblio1i2biblio1í2biblio1o2biblio1ó2biblio1u2biblio1ú2b4ien3do_cardio1a2cardio1á2cardio1e2cardio1é2cardio1i2cardio1í2cardio1o2cardio1ó2cardio1u2cardio1ú2cefalo1a2cefalo1á2
29258cefalo1e2cefalo1é2cefalo1i2cefalo1í2cefalo1o2cefalo1ó2cefalo1u2cefalo1ú2contra1a2contra1á2contra1e2contra1é2contra1i2contra1í2contra1o2contra1ó2contra1u2contra1ú2cripto1a2cripto1á2cripto1e2cripto1é2cripto1i2cripto1í2cripto1o2cripto1ó2cripto1u2cripto1ú2desa3briddesa3certde4s3acotde4s3aficde4s3afilde4s3afinde4s3afordesa3garrde4s3ahijde4s3aliñdesa3marrdesa3moblde4s3anidde4s3animde4s3anímde4s3anudde4s3apoyde4s3arende4s3avisde4s3empéde4s3enamde4s3enchde4s3enclde4s3encode4s3encrde4s3encude3senfadde3senfádde4s3enfide4s3enfode4s3enfóde3sengañde3sengáñde4s3enlode4s3entade4s3entode4s3entrde4s3entude3s4ercide4s3espade3sesperde3sigualde3siluside4s3imande3sinencde3sinfecde4s3inflde3sistende4s3odorde4s3ordede4s3órdede4s3orejde3s4osegde3su3dande3su3darde3su3dasde4s3unimde4s3unirdodeca1a2dodeca1á2dodeca1e2dodeca1é2dodeca1i2dodeca1í2dodeca1o2dodeca1ó2dodeca1u2dodeca1ú24éd3mela_4édmeles_4édmelos_4édnosla_4édnosle_4édnoslo_4é3drica_4é3drico_4édselas_4édseles_4édselos_4éd3tela_4édteles_4édtelos_e5r4a3ba_e5r4a3da_e5r4a3do_e5r4a3ra_e5r4a3rá_e5r4a3re_e5r4a3ré_e5r4a3se_e5r4aste_e5r4ates_4e3ríais_4e3riora_4ér3mela_4érmeles_4érmelos_4érnosla_4érnosle_4érnoslo_4é3rosla_4é3rosle_4é3roslo_4érselas_4érseles_4érselos_4ér3tela_4érteles_4értelos_gastro1a2gastro1á2gastro1e2gastro1é2gastro1i2gastro1í2gastro1o2gastro1ó2gastro1u2gastro1ú2hemato1a2hemato1á2hemato1e2hemato1é2hemato1i2hemato1í2hemato1o2hemato1ó2hemato1u2hemato1ú2hipe2r1a2hipe2r1á2hipe2r1e2hipe2r1é2hipe2r1i2hipe2r1í2hipe2r1o2hipe2r1ó2hipe2r1u2hipe2r1ú24i2dales_4i3gamos_inter4inointer4ior4ís3teis_4í4s3tes_4ísticas_4ísticos_4meables_megalo1a2megalo1á2megalo1e2megalo1é2megalo1i2megalo1í2megalo1o2megalo1ó2megalo1u2megalo1ú2melano1a2melano1á2melano1e2melano1é2melano1i2melano1í2melano1o2melano1ó2melano1u2melano1ú2mili4arioo4i3deas_4o2i3des_4ó3logas_4o3logía_4ó3logos_pe5r4antepoli4andrpoli4éstes3ta3les_s3ti3lla_supe2r1a2supe2r1á2supe2r1e2supe2r1é2supe2r1i2supe2r1í2super4iorsupe2r1o2supe2r1ó2supe2r1u2supe2r1ú2t4eo3nes_tran4sacctrans4ido",
29259        10: "_an3e2pigr_ante2o3je_en1aguach_in3aguant_ina3movib_in3analiz_in3apreci_in3aprens_inte2r1a2_inte2r1á2_inte2r1e2_inte2r1é2_inte2r1i2_inte2r1í2_inte2r1o2_inte2r1ó2_inte2r1u2_inte2r1ú2_inu3tiliz_ma4l3e4du_pa4n1afri_pa4n1ópti_post3elec_pos3te3ri_pos3ti3go_pos3ti3la_post3impr_pos3ti3ne_pos3ti3za_pos3ti3zo_pos3tó3ni_pos3tu3la_pos3tu3lá_pos3tu3le_pos3tu3lé_pos3tu3ra_re3a2grup_re3aparec_re3utiliz_re3utilíz_sub3aflue_sub3enten_sub3estim_sub3estím_sub3ofici_su2d1a2fr_su2d1a2me_tran2s1ur4a3ciones_4ád3melas_4ádnoslas_4ádnosles_4ádnoslos_4ád3telas_4ándomela_4ándomele_4ándomelo_4ándosela_4ándosele_4ándoselo_4ándoseme_4ándotela_4ándotele_4ándotelo_4ándoteme_4a3ríamos_4á4r3mela_4á4r3sela_4á4r3sele_4á4r3selo_4á4r3tela_4á4r3tele_4á4r3telo_b4ien3das_centi5áreaco3n4imbride4s3abastde4s3abollde4s3abotode4s3aceitdesa3ciertde4s3acompde4s3aconsde4s3acoplde4s3acorrde4s3activde4s3adeudde4s3adornde4s3aferrde4s3agradde4s3agregde4s3agrupde4s3aherrde4s3ajustde4s3alentde4s3alfomde4s3alforde4s3aliende4s3alinede4s3almidde4s3alterde4s3amoldde4s3amortde4s3angeldesa3pacibde4s3apadrde4s3aparedesa3parecdesa3paricde4s3aplicde4s3apretde4s3aprobde4s3arbolde4s3arrimdesa3rrollde4s3arropde4s3arrugde4s3asentde4s3asistdesa3sosegde4s3atencde4s3atendde4s3atentde4s3atornde4s3autorde4s3embalde4s3embálde4s3embarde4s3embárde4s3embotde4s3empacde4s3empañde4s3empáñde4s3empatde4s3empegde4s3emplede4s3empozde4s3encabde4s3encadde4s3encajde4s3encájde4s3encamde3sencantde4s3encapde4s3encarde4s3encárde3senfrende4s3enfurde4s3engarde4s3engasde4s3engomde4s3engozde4s3engrade4s3enladde4s3enlazde3sentendde4s3enterde3sentiende3sentiénde4s3estimde4s3imponde4s3inhibde3s4interde4s3intoxde4s3inverde4s3obligde4s3obstrde4s3ub4icde4s3unierde3s4ustane4a3miento4éd3melas_4édnoslas_4édnosles_4édnoslos_4é3dricas_4é3dricos_4éd3telas_e5r4a3ban_e5r4a3bas_4e3ra3ble_e5r4a3das_e5r4a3dor_e5r4a3dos_e5r4a3mos_e5r4a3ran_e5r4a3rán_e5r4a3ras_e5r4a3rás_e5r4a3ren_e5r4a3res_e5r4a3rés_e5r4a3ría_e5r4a3rís_e5r4a3ron_e5r4a3sen_e5r4a3ses_e5r4astes_4e3re3mos_4e3ríamos_4e3rioras_4e3riores_4ér3melas_4érnoslas_4érnosles_4érnoslos_4é3roslas_4é3rosles_4é3roslos_4ér3telas_familia3riinter4esarmini4a5turo4i3dales_4o3logías_4o3lógica_4o3lógico_para4ulatape3r4e3miaperpon5d6rpoli4anteapoli4o5mies3ti3llas_s3ti3llón_super4ablesupe4r4a3rsupe4r4á3rtrans4ibertrans4igentrans4igirtrans4itabultra4ísmo",
29260        11: "_mal1andant_mal1andanz_pa4n1europ_sub2i3mien_tran2s1alp_tran2s1and_tran2s1atl_tran2s1oce4ándomelas_4ándomeles_4ándomelos_4ándoselas_4ándoseles_4ándoselos_4ándosenos_4ándotelas_4ándoteles_4ándotelos_4ándotenos_4á4r3melas_4á4r3meles_4á4r3melos_4á4r3nosla_4á4r3nosle_4á4r3noslo_4á4r3selas_4á4r3seles_4á4r3selos_4á4r3telas_4á4r3teles_4á4r3telos_de4s3abrochde4s3acelerde4s3acobarde4s3acomoddesa3cralizde4s3acuartde4s3aderezde4s3adorarde4s3advertde4s3agracide4s3agravide4s3alagarde4s3alquilde4s3alumbrde4s3amuebldesa3percibde4s3aprenddesa3prenside4s3aprietde4s3apropide4s3arraigde4s3arreglde4s3arrenddesa3sosiegde4s3atiend
29260de4s3atrancde4s3embargde4s3embolsde4s3emborrde4s3emboscde4s3embragde4s3embrágde4s3embrujde4s3embrújde4s3empedrde4s3empeorde4s3empernde4s3empolvde4s3empotrde4s3encallde4s3encállde4s3enfundde4s3enhebrde4s3entierde4s3entiérde4s3envainde3sesperacde4s3imaginde4s3impresde4s3incentde4s3inclinde4s3incorpde4s3inflamde4s3informde4s3insectde4s3instalde3s4integrde4s3obedecde3s4ubstane5r4a3bais_4e3ra3bles_e5r4a3dora_e5r4a3rais_e5r4a3reis_e5r4a3réis_e5r4a3ríaise5r4a3rían_e5r4a3rías_e5r4a3seis_e5r4asteis_4i3gá3moos_4o3lógicas_4o3lógicos_2o3samente_super4ación4te4r5i4nsutrans4eúntetrans4icióntrans4istortrans4ubsta",
29261        12: "_in3ter2e3sa_in3ter2e3sá_in3ter2e3se_in3ter2e3sé_in3ter2e3so_in3ter2e3só_in3te3r4rog_pa4n1a4meri4á4r3noslas_4á4r3nosles_4á4r3noslos_deca2i3mientde4s3acostumde4s3acreditde4s3adormecdesa3guisadode4s3apolillde4s3articulde4s3embravede4s3embrávede4s3embrollde4s3embróllde4s3emparejde4s3emparéjde4s3emperezde4s3enganchde3senvolvimde4s3estabilde4s3impresXde4s3incruste5r4á3bamos_e5r4a3doras_e5r4a3dores_e5r4á3ramos_e5r4a3remos_e5r4á3remos_e5r4á3semos_4e3rioridad_4i3gá3monos_4i3gá3mosla_4i3gá3mosle_4i3gá3moslo_4i3gá3mosme_4i3gá3moste_s3ti3llones_trans4itorio",
29262        13: "_in3te3r4rump_in3te3r4rupc_in3te3r4ruptde4s3aprovechde4s3empaquetde4s3empaquétde4s3emparentde4s3esperanze5r4a3ríamos_4e3riormente_4i3gá3moosla_4i3gá3moosle_4i3gá3mooslo_4i3gá3mosela_4i3gá3mosele_4i3gá3moselo_4i3gá3moslas_4i3gá3mosles_4i3gá3moslos_supe3r4á3vit_",
29263        14: "4e3rioridades_4i3gá3monosla_4i3gá3monosle_4i3gá3monoslo_4i3gá3mooslas_4i3gá3moosles_4i3gá3mooslos_4i3gá3moselas_4i3gá3moseles_4i3gá3moselos_4i3gá3mosmele_4i3gá3mosmelo_4i3gá3mostele_4i3gá3mostelo_supe3r4á3vits_",
29264        15: "4e3ra3blemente_4i3gá3monoslas_4i3gá3monosles_4i3gá3monoslos_4i3gá3mos3mela_4i3gá3mosmeles_4i3gá3mosmelos_4i3gá3mos3tela_4i3gá3mosteles_4i3gá3mostelos_4o3lógicamente_",
29265        16: "4i3gá3mos3melas_4i3gá3mos3telas_",
29266        17: "_de3s4in3ter2e3sa_de3s4in3ter2e3sá_de3s4in3ter2e3se_de3s4in3ter2e3sé_de3s4in3ter2e3so_de3s4in3ter2e3só"
29267    },
29268    patternChars: "X_abcdefghijklmnopqrstuvwxyzáéíñóúü",
29269    patternArrayLength: 79623,
29270    valueStoreLength: 15424
29271};
29272
29273Hyphenator.config({
29274    classname : 'article-headline',
29275    minwordlength : 10,
29276    rightmin : 5,
29277    intermediatestate : 'visible',
29278    unhide : 'progressive'
29279});
29280
29281Hyphenator.run();
29282var topics = {};
29283
29284jQuery.Topic = function (id) {
29285    var callbacks, method,
29286        topic = id && topics[id];
29287
29288    if (!topic) {
29289        callbacks = jQuery.Callbacks();
29290        topic = {
29291            publish: callbacks.fire,
29292            subscribe: callbacks.add,
29293            unsubscribe: callbacks.remove
29294        };
29295        if (id) {
29296            topics[id] = topic;
29297        }
29298    }
29299    return topic;
29300};
29301(function ($) {
29302    ns('News').ContentList = {
29303        DYNAMIC: "tag-based-dynamic",
29304        HYBRID: "hybrid",
29305        MANUAL: "manual",
29306        TAG_MANUAL: "tag-based-manual",
29307        LANDING_PAGE_LAYOUT: "content-list-layout--landing-page",
29308        COMMAND_DYNAMIC: "tags",
29309        COMMAND_MANUAL: "path",
29310        SERVICE_DIR: "/services/",
29311        SERVICE_NAME: "articlelist",
29312        LANDING_PAGE_DISPLAY_COUNT: 9,
29313        LANDING_PAGE_AD_DISPLAY_COUNT: 11,
29314        AUTHOR_MODE_CLASS: "content-list-author-mode",
29315
29316        authorMode: false,
29317        ajaxTime: 0,
29318        layoutTypesForInlineVideos: ['hero', '1x1', 'landing-page'],
29319
29320        /**
29321         * Handles different content list loading strategies
29322         */
29323        loadContentList: function (index, element, callback) {
29324            if ($(element).hasClass("content-list__mode--" + News.ContentList.DYNAMIC)) {
29325                News.ContentList.loadDynamicContentList(index, element, callback)
29326            } else if ($(element).hasClass("content-list__mode--" + News.ContentList.HYBRID)) {
29327                News.ContentList.loadHybridContentList(index, element, callback)
29328            }  else {
29329                News.ContentList.loadManualContentList(index, element, callback)
29330            }
29331        },
29332
29333        /**
29334         * Primary entry point for loading dynamic content lists
29335         *
29336         * @param index - index from jQuery.each
29337         * @param element - the node of the dynamic content list component which stores our data properties
29338         */
29339        loadDynamicContentList: function (index, element, callback) {
29340            try {
29341                var limit = News.ContentList.getLimit(element)
29342                var requiredTags = News.ContentList.getRequiredTags(element)
29343                var optionalTags = News.ContentList.getOptionalTags(element)
29344                var excludedTags = News.ContentList.getExcludedTags(element)
29345                var daysLimit = News.ContentList.getDaysLimit(element)
29346                var daysLimitTimezone = News.ContentList.getDaysLimitTimezone(element)
29347                var path = News.ContentList.getPagePath(element)
29348                var uri = '/services/ms/articles?reqTags=' + requiredTags + '&optTags=' + optionalTags + '&exTags=' + excludedTags + '&path=' + path + '&daysLimit=' + daysLimit + '&daysLimitTimezone=' + daysLimitTimezone;
29349                var startTime = new Date().getTime();
29350                $.ajax({
29351                    url: uri
29352                })
29353                .done(function (data, textStatus, jqXHR) {
29354                    News.ContentList.ajaxLoadFinished(element, data)
29355                    News.App.QuantumAnalytics.quantumApiSuccessOrFailure(uri, jqXHR.status, "All_Generic_API_Call_Success", startTime, "GET", "", "", jqXHR);
29356                    if (callback) callback();
29357                })
29358                .fail(function (jqXHR, textStatus, errorThrown) {
29359                    let responseText = News.App.QuantumAnalytics.extractAjaxErrorMessage(jqXHR);
29360                    News.App.QuantumAnalytics.quantumApiSuccessOrFailure(uri, jqXHR.status, "All_Generic_API_Call_Failure", startTime, "GET", "", responseText, jqXHR);
29361                    if (callback) callback();
29362                })
29363            } catch (ex) {
29364                if (callback) callback();
29365            }
29366        },
29367
29368         /**
29369         * Primary entry point for loading Hybrid content lists
29370         *
29371         * @param index - index from jQuery.each
29372         * @param element - the node of the dynamic content list component which stores our data properties
29373         */
29374        loadHybridContentList: function (index, element, callback) {
29375            try {
29376                var limit = News.ContentList.getLimit(element)
29377                var requiredTags = News.ContentList.getRequiredTags(element)
29378                var optionalTags = News.ContentList.getOptionalTags(element)
29379                var excludedTags = News.ContentList.getExcludedTags(element)
29380                var daysLimit = News.ContentList.getDaysLimit(element)
29381                var daysLimitTimezone = News.ContentList.getDaysLimitTimezone(element)
29382                var path = News.ContentList.getPagePath(element)
29383                var compPath = News.ContentList.getResourcePath(element)
29384                var uri = '/services/ms/articles/hybrid?mode=hybrid&path='+ compPath;
29385                var startTime = new Date().getTime();
29386                let responseText = '';
29387                $.ajax({
29388                    url: uri
29389                })
29390                .done(function (data, textStatus, jqXHR) {
29391                    News.ContentList.ajaxLoadFinished(element, data)
29392                    News.App.QuantumAnalytics.quantumApiSuccessOrFailure(uri, jqXHR.status, "All_Generic_API_Call_Success", startTime, "GET", "", "", jqXHR);
29393                    if (callback) callback();
29394                })
29395                .fail(function (jqXHR) {
29396                    responseText = News.App.QuantumAnalytics.extractAjaxErrorMessage(jqXHR);
29397                    News.App.QuantumAnalytics.quantumApiSuccessOrFailure(uri, jqXHR.status, "All_Generic_API_Call_Failure", startTime, "GET", "", responseText, jqXHR);
29398                    if (callback) callback();
29399                })
29400            } catch (ex) {
29401                if (callback) callback();
29402            }
29403        },
29404
29405        /**
29406         * Primary entry point for loading manual content lists
29407         *
29408         * @param index - index from jQuery.each
29409         * @param element - the node of the manual content list component which stores our data properties
29410         */
29411        loadManualContentList: function (index, element, callback) {
29412            try {
29413                var path = News.ContentList.getPath(element)
29414                var uri = News.ContentList.manualListUri(path)
29415                var startTime = new Date().getTime();
29416                let responseText = '';
29417                $.ajax({
29418                       url: uri
29419                })
29420                .done(function (data, textStatus, jqXHR) {
29421                    News.ContentList.ajaxLoadFinished(element, data)
29422                    News.App.QuantumAnalytics.quantumApiSuccessOrFailure(uri, jqXHR.status, "All_Generic_API_Call_Success", startTime, "GET", "", "", jqXHR);
29423                    if (callback) callback();
29424                })
29425                .fail(function (jqXHR) {
29426                    responseText = News.App.QuantumAnalytics.extractAjaxErrorMessage(jqXHR);
29427                    News.App.QuantumAnalytics.quantumApiSuccessOrFailure(uri, jqXHR.status, "All_Generic_API_Call_Failure",startTime, "GET", "", responseText, jqXHR);
29428                    if (callback) callback();
29429                })
29430            } catch (ex) {
29431                if (callback) callback();
29432            }
29433        },
29434
29435        /**
29436         * When ajax completes successfully, load articles into the content list
29437         *
29438         * Parameters:
29439         *  contentList
29440         *  data - a response object with an array of results stored in "articles"
29441         */
29442        ajaxLoadFinished: function (contentList, data) {
29443            var articles = data["articles"]
29444
29445            // Filter articles to remove the current page from the list
29446            articles = $(articles).filter(News.ContentList.currentArticleExcludeFilter)
29447
29448            // Check if no articles are returned from the API
29449            if (articles.length === 0) {
29450                // Find the closest hero wrapper (may be the contentList itself or its parent)
29451                var contentListWrapper = contentList.closest('.content-list');
29452
29453                if (contentListWrapper) {
29454                    // Get heading and articles container inside the wrapper
29455                    var h1 = contentListWrapper.querySelector('.content-list-layout > h1');
29456                    var articlesContainer = contentListWrapper.querySelector('.content-list-layout > .articles-container');
29457                    var viewMoreDiv = contentListWrapper.querySelector('.view-more');
29458
29459                    // Helper function: returns true if a node is missing or only contains whitespace
29460                    function isEmptyOrWhitespace(node) {
29461                        return !node || !node.textContent.trim();
29462                    }
29463
29464                    // If both heading and articles container are empty
29465                    if (isEmptyOrWhitespace(h1) && isEmptyOrWhitespace(articlesContainer)) {
29466                        if (viewMoreDiv) {
29467                            // If view-more div exists, add 'link-noArticle' class
29468                            contentListWrapper.classList.add('view-more-no-article');
29469                        } else {
29470                            // Otherwise, add 'no-article' class
29471                            contentListWrapper.classList.add('no-article');
29472                        }
29473                    }
29474                }
29475
29476                // Stop execution early since there's nothing to render
29477                return;
29478            }
29479            
29480            // When the current page is not in the list, make sure we don't return more results than we should.
29481            if (articles.length > contentList.dataset.limit) {
29482                var limit = parseInt(contentList.dataset.limit);
29483                articles = articles.slice(0, limit)
29484            }
29485
29486            //When in author swap path to URL in order for links to remain JCR paths
29487            if (News.ContentList.authorMode) {
29488                articles = News.ContentList.modifyProperty(articles, "url", "path")
29489            }
29490
29491            /* Render articles in a landing page content list, with view more and lead article behavior */
29492            if (News.ContentList.isLandingPageContentList(contentList)) {
29493                News.ContentList.renderLandingPageArticles(contentList, articles)
29494            }
29495            /* Render articles in the hero or regular content list layouts */
29496            else {
29497                News.ContentList.renderContentListArticles(contentList, articles)
29498            }
29499
29500        },
29501
29502        /**
29503         * Used to determine whether the current content list is a landing page content list, for styling
29504         */
29505        isLandingPageContentList: function (contentList) {
29506            return $(contentList).hasClass(News.ContentList.LANDING_PAGE_LAYOUT)
29507        },
29508
29509        /**
29510         * Returns the path attribute of a manual content list
29511         *
29512         * Usually returns the number of items configured on 'element', but in
29513         * articles we need an extra element since we may filter it out.
29514         */
29515        getPath: function (element) {
29516            var path = element.dataset.path
29517
29518            return path
29519        },
29520
29521        /**
29522         * Returns how many articles to show in the content list
29523         *
29524         * Usually returns the number of items configured on 'element', but in
29525         * articles we need an extra element since we may filter it out.
29526         */
29527        getLimit: function (element) {
29528            var limit = parseInt(element.dataset.limit)
29529
29530            return limit
29531        },
29532        /**
29533         * Returns boolean
29534         *
29535         * to show canoncialUrl instead of page path when USe Canonical Urls is selected.
29536         */
29537        getCanonical: function (element) {
29538            var canonical = element.dataset.canonical
29539            return canonical
29540        },
29541
29542        getLandingPageCanonical: function (element) {
29543            var canonical = element.dataset.canonical
29544            return canonical
29545        },
29546
29547        /**
29548         * Returns boolean
29549         *
29550         * to show ad unit in landing page content list when Display Ad Unit is selected.
29551         */
29552        getLandingPageAdDisplay: function (element) {
29553            var displayAd = element.dataset.displayad
29554            return displayAd
29555        },
29556
29557        /**
29558         * Returns the current page path
29559         */
29560        getPagePath: function (element) {
29561            return element.dataset.pagepath || ""
29562        },
29563
29564        getResourcePath: function (element) {
29565            return element.dataset.resourcepath || ""
29566        },
29567        /**
29568         * Returns the required tags configured on 'element' to use in the query
29569         */
29570        getRequiredTags: function (element) {
29571            return element.dataset.requiredtags || ""
29572        },
29573        /**
29574         * Returns the required tags configured on 'element' to use in the query
29575         */
29576        getOptionalTags: function (element) {
29577            return element.dataset.optionaltags || ""
29578        },
29579
29580        getExcludedTags: function (element) {
29581            return element.dataset.excludedtags || ""
29582        },
29583
29584        getDaysLimit: function (element) {
29585            return element.dataset.dayslimit || ""
29586        },
29587
29588        getDaysLimitTimezone: function (element) {
29589                    return element.dataset.dayslimittimezone || ""
29590                },
29591
29592        /**
29593         * Returns the show inline video on 'element'
29594         */
29595        getShowInlineVideo: function (element,layout) {
29596            if(layout === '1x1' || layout === 'hero' || layout === 'landing-page'){
29597                return element.dataset.showinlinevideo || ""
29598            }
29599            return "";
29600        },
29601
29602        /**
29603         * Returns the query URI for a dynamic content list with the specified required/optional tags and limited to a certain number of results
29604         */
29605        dynamicListUri: function (required, optional, excluded, limit) {
29606
29607            // setting up limit to either 10 or 100 to reduce service call
29608            if (limit <= 10) {
29609                limit = 10
29610            } else if (limit > 10) {
29611                limit = 100
29612            }
29613
29614            var length = 0
29615            var serviceName = ""
29616            required = News.ContentList.formatTags(required)
29617            optional = News.ContentList.formatTags(optional)
29618            excluded = News.ContentList.formatTags(excluded)
29619            do {
29620                serviceName = News.ContentList.SERVICE_NAME + '.' + News.ContentList.COMMAND_DYNAMIC + '.' + required + '.' + optional + '.' + excluded + '.' + limit + '.json'
29621                length = serviceName.length
29622
29623                if (length > 255) {
29624                    if (optional.length > 2) {
29625                        optional = News.ContentList.removeTag(optional)
29626                    } else if (required.length > 2) {
29627                        required = News.ContentList.removeTag(required)
29628                    } else /* istanbul ignore else */ if (excluded.length > 2) {
29629                        excluded = News.ContentList.removeTag(excluded)
29630                    }
29631                }
29632            }
29633            while (length > 255);
29634
29635            return News.ContentList.SERVICE_DIR + serviceName
29636        },
29637        /**
29638         * Returns the query URI for a manual content list at a specific path
29639         *
29640         */
29641        manualListUri: function (path) {
29642            return News.ContentList.SERVICE_DIR + News.ContentList.SERVICE_NAME + '.' + News.ContentList.COMMAND_MANUAL + '.' + path + '.json'
29643        },
29644
29645        /** Filter which should return false when the article input is the current page.
29646         *
29647         * A duplicate article has the same article date in the path + same article name in the path
29648         */
29649        currentArticleExcludeFilter: function (index, article) {
29650            // Locate the name end of the article, which looks like /name
29651            var articleNameIdx = article.url.lastIndexOf('/')
29652
29653            // Format: .../YYYY/MM/DD/name
29654            // '/YYYY/MM/DD' is 11 characters, but we should allow for MM and DD to possibly be one character.
29655            // If we compare the last 9 characters of the article date, we would still be checking the century, decade, year, month, and date accurately.
29656            var dateLength = 9
29657            var articleDateName = article.url.substring(articleNameIdx - dateLength)
29658
29659            if (window.location.toString().indexOf(articleDateName) > 0) {
29660                return false;
29661            }
29662            return true;
29663        },
29664
29665        /** Default implementation of a filter: allow any content list to be retrieved
29666         *
29667         *  @param index - the index of the current content list in a loop of results based on selecotrs
29668         *  @param contentList - the contentList that may be valid
29669         *
29670         *  Returns: 'false' - suppress the current content list
29671         *           'true' - attempt to load the current content list
29672         */
29673        contentListFilter: function (index, contentList) {
29674            return true
29675        },
29676
29677        /** formatTags
29678         *
29679         * @param tagIds as a string
29680         *
29681         *  Returns: pipe-delimited tagIDs, sorted in alphabetic order, with each tagid surrounded in parentheses
29682         *
29683         *  e.g. input: "regions:nyc,regions:All/All-Regions,pageCategories:news"
29684         *       output: "(pageCategories:news)(regions:All|All-Regions)(regions:nyc)"
29685         */
29686        formatTags: function (tags) {
29687            var formatted = tags.replace(/(\/)/g, '|')
29688            formatted = formatted.replace(/pageCategories:/g, 'p:')
29689            formatted = formatted.replace(/regions:/g, 'r:')
29690
29691            // Split the tags up, sort them alphabetically, and rejoin the array back into a string
29692            formatted = formatted.split(',').sort().join(')(')
29693            return '(' + formatted + ')'
29694        },
29695
29696        /**
29697         * Removes a tag from the list of tags to avoid creating an uncacheable URI
29698         *
29699         * Params:
29700         *   tags - String of tags in the format (tagId)(tagId)
29701         *
29702         * TODO: Should it be: Last tag (alphabetic), or longest tag (could be overly specific)?
29703         *
29704         *       Last tag is easier to implement...
29705         */
29706        removeTag: function (tags) {
29707            var lastTagStart = tags.lastIndexOf('(')
29708            tags = tags.substring(0, lastTagStart)
29709            return tags
29710        },
29711
29712        /** pageIsArticle:
29713         * function to determine if the current page is an article (important for empire)
29714         *
29715         * Returns: true - current page is an article
29716         */
29717        pageIsArticle: function () {
29718            return $('#analyticsDataLayer').data('content-type') === 'article'
29719        },
29720
29721        modifyProperty: function (articles, propertyFrom, propertyTo) {
29722            articles.each(function (i, article) {
29723                articles[i][propertyFrom] = articles[i][propertyTo]
29724            })
29725            return articles;
29726        },
29727        /**
29728         * renderContentListArticles
29729         *
29730         * function to render hero and plain content lists via AJAX
29731         *
29732         * @param contentList - DOM object, the current content list component
29733         * @param articles - array of JSON objects returned from the service
29734         */
29735        renderContentListArticles: function (contentList, articles) {
29736            const articleContainer = $(contentList).find('.articles-container')
29737            const canonical = News.ContentList.getCanonical(contentList);
29738
29739            // Determine the layout type from the content list
29740            const layoutType = News.ContentList.getLayoutType(contentList);
29741
29742            // Get the inline video setting from the dialog
29743            let showInlineVideo = News.ContentList.getShowInlineVideo(contentList,layoutType);
29744
29745            // Remove the current articles and add new ones
29746            articleContainer.children().remove();
29747
29748            // Render articles on the content list
29749            if (articles.length > 0) {
29750                // Render the articles on the page
29751                articles.each(function (i, article) {
29752                    News.ContentList.renderArticleInContentList(i, article, articleContainer, canonical, layoutType, showInlineVideo)
29753                })
29754            }
29755            // Hide the heading when on an article, and in Empire, and no articles to display
29756            else if (News.design.getDesignName() == "empire" &&
29757                News.ContentList.pageIsArticle()) {
29758                $(contentList).find('h1').hide()
29759            }
29760        },
29761
29762        /**
29763         * renderLandingPageArticles
29764         *
29765         * function to render landing page content lists via AJAX
29766         *
29767         * @param contentList - DOM object, the current content list component
29768         * @param articles - array of JSON objects returned from the service
29769         *
29770         * This function is overridden in empire landing content lists
29771         */
29772        renderLandingPageArticles: function (contentList, articles) {
29773            // Remove the current lead object
29774            var leadItemContainer = $(contentList).find('.lead-item')
29775            leadItemContainer.children().remove()
29776
29777            // Remove the current articles and add new ones
29778            var articleContainer = $(contentList).find('.articles-container')
29779            articleContainer.children().remove();
29780
29781            var canonical = News.ContentList.getLandingPageCanonical(contentList);
29782            var layoutType = News.ContentList.getLayoutType(contentList);
29783            var showInlineVideo = News.ContentList.getShowInlineVideo(contentList,layoutType);
29784
29785            // Render the articles on the page
29786            articles.each(function (i, article) {
29787                if (i == 0) {
29788                    News.ContentList.renderArticleInLandingPageContentList(i, article, leadItemContainer, canonical, layoutType, showInlineVideo)
29789                } else {
29790                    News.ContentList.renderArticleInLandingPageContentList(i, article, articleContainer, canonical, layoutType, showInlineVideo)
29791                }
29792            })
29793        },
29794
29795        /**
29796         * Get layout type from content list element
29797         */
29798        getLayoutType: function(contentList) {
29799            const supportedLayoutTypes = ['hero', 'landing-page', '4x1-single-column-mobile', '1x1', 'landing-page']
29800            let contentListLayoutType = contentList.dataset.contentlistlayouttype || "";
29801
29802            if (!supportedLayoutTypes.includes(contentListLayoutType)) {
29803                contentListLayoutType = 'default';
29804            }
29805
29806            return contentListLayoutType
29807        },
29808
29809
29810        renderLandingPageAdHTML: function (container) {
29811            var html = News.ContentList.getAdHtml()
29812            var adTag = document.createElement("div")
29813            adTag.setAttribute('class', 'google-dfp-ads');
29814            adTag.innerHTML = html
29815            container.append(adTag)
29816            $(adTag).trigger('article-append')
29817        },
29818
29819        renderGoogleDFPAd: function () {
29820            googletag.cmd.push(function () {
29821                var adSlot = googletag.defineSlot(News.ContentList.getSitePage(), [300, 250], 'x35')
29822                    .setTargeting('pos', ['top']);
29823                adSlot.addService(googletag.pubads());
29824            });
29825            googletag.cmd.push(function () {
29826                googletag.pubads().enableSingleRequest();
29827                googletag.pubads().setCentering(true);
29828                googletag.pubads().enableAsyncRendering();
29829                googletag.pubads().collapseEmptyDivs();
29830                googletag.pubads().setTargeting('kvrefd', ['www.spectrumlocalnews.com']);
29831                googletag.enableServices();
29832            });
29833            googletag.cmd.push(function () {
29834                googletag.display('x35');
29835            });
29836        },
29837
29838        getSitePage: function () {
29839            let dfpSitePage = '';
29840            if (typeof dfpSiteId !== 'undefined') {
29841                const regionPlusVertRE = /(\/([^\/]*)){3}/;
29842                const regionRE = /(\/([^\/]*)){2}/;
29843                const articleRE = /(\/([^\/]*)){3}(\/\d{4}\/(\d{1,2})\/(\d{1,2})\/)/;
29844                const path = location.pathname.replace('/content/news', '').replace('.html', '');
29845                const articleAppender = articleRE.test(path) ? '/article' : '';
29846                const regionPlusVert = regionPlusVertRE.test(path) ? regionPlusVertRE.exec(path)[0] : null;
29847                const region = regionRE.exec(path)[0];
29848                const regionWithDash = region.replace(/\//g, '-');
29849                let adRegionPlusVert = regionPlusVert ? regionPlusVert.replace(region, regionWithDash) : regionWithDash;
29850                dfpSitePage = dfpSiteId + adRegionPlusVert + articleAppender;
29851            } else {
29852                return;
29853            }
29854            return dfpSitePage;
29855        },
29856
29857        getAdHtml: function () {
29858            return '<div id="x35" class="dfp-ad-tags" data-position="x35"></div><div class="icon-advertisement"></div>'
29859        },
29860        /**
29861         * renderArticleInContentList
29862         * @param i - index of the current article in the service response list
29863         * @param article - JSON object returned from the article service
29864         * @param articleContainer - DOM object, div where the article will be injected
29865         *  Sample Article Object:
29866         * {"date":"1536715020000","headline":"Florence heading our way for now","path":"/content/news/stories/2018/09/12/f/florence-heading-our-way-for-now","url":"/nc/charlotte/news/2018/09/12/florence-heading-our-way-for-now","image":"https://images.spectrumnews1.com/is/image/SpectrumNews/tropical_-_prob_of40windspng","damImage":"https://images.spectrumnews1.com/is/image/SpectrumNews/tropical_-_prob_of40windspng","altText":"Probs","previewText":"Florence heading our way for now","location":"Charlotte","categories":"WEATHER","flairText":"","flairType":"","utcFlareOffTime":0}
29867         */
29868        renderArticleInContentList: function (i, article, articleContainer, canonical, layoutType, showInlineVideo) {
29869            if (i > 0) {
29870                // don't show inline videos beyond the first item
29871                showInlineVideo = false;
29872            }
29873
29874            // URL with .html in author mode
29875            article.url = News.ContentList.fixStoryLinkInAuthorMode(article.url);
29876            
29877            var html = News.ContentList.getArticleHtml(article, layoutType, showInlineVideo)
29878
29879            // Now create an article node and place it into the content list
29880            var articleTag = document.createElement("article")
29881            if (showInlineVideo === 'true' && article.hasVideo && article.hasVideo !== 'videoHide') {
29882                articleTag.classList.add('showing-ivp');
29883            }
29884            articleTag.innerHTML = html
29885            articleContainer.append(articleTag)
29886            
29887            // Add "non-video-article" class to articleContainer and articleTag to avoid showing inline video player styling when IVP is enabled but the article has no video or is set to videoHide
29888            if (showInlineVideo === 'true' && (!article.hasVideo || article.hasVideo === 'videoHide')) {
29889                $(articleTag).addClass('non-video-article');
29890                $(articleContainer).addClass('non-video-article');
29891            }
29892
29893            // Handle video player initialization for articles with videos ONLY
29894            if (i === 0 && article.hasVideo && article.hasVideo !== 'videoHide' && this.layoutTypesForInlineVideos.includes(layoutType) && showInlineVideo === 'true') {
29895                News.ContentList.initializeVideoPlayer(articleTag, article.videoDetails)
29896            }
29897
29898            // Regionalize article URLs, Display Scene7 Images, Compute Relative Dates
29899            $(articleTag).trigger('article-append')
29900            if (canonical) {
29901                $(articleTag).find('a').each(function () {
29902                    $(this).prop("href", article['canonicalUrl']);
29903                });
29904            }
29905        },
29906
29907        /**
29908         * renderArticleInLandingPageContentList
29909         * @param i - index of the current article in the service response list
29910         * @param article - JSON object returned from the article service
29911         * @param container - DOM object, div where the article will be injected
29912         *  Sample Article Object:
29913         * {"date":"1536715020000","headline":"Florence heading our way for now","path":"/content/news/stories/2018/09/12/f/florence-heading-our-way-for-now","url":"/nc/charlotte/news/2018/09/12/florence-heading-our-way-for-now","image":"https://images.spectrumnews1.com/is/image/SpectrumNews/tropical_-_prob_of40windspng","damImage":"https://images.spectrumnews1.com/is/image/SpectrumNews/tropical_-_prob_of40windspng","altText":"Probs","previewText":"Florence heading our way for now","location":"Charlotte","categories":"WEATHER","flairText":"","flairType":"","utcFlareOffTime":0}
29914         */
29915        renderArticleInLandingPageContentList: function (i, article, container, displayAd, canonical, layoutType, showInlineVideo) {
29916            if (i > 0) {
29917                // don't show inline videos beyond the first item
29918                showInlineVideo = false;
29919            }
29920
29921            // URL with .html in author mode
29922            article.url = News.ContentList.fixStoryLinkInAuthorMode(article.url);
29923            var html = News.ContentList.getArticleHtml(article, layoutType, showInlineVideo)
29924            
29925
29926            // Now create an article node and place it into the content list
29927            var articleTag = document.createElement("article")
29928            if (showInlineVideo === 'true' && article.hasVideo && article.hasVideo !== 'videoHide') {
29929                articleTag.classList.add('showing-ivp', 'lp-cl');
29930            }
29931
29932            articleTag.innerHTML = html
29933            var listCount = displayAd ? News.ContentList.LANDING_PAGE_AD_DISPLAY_COUNT : News.ContentList.LANDING_PAGE_DISPLAY_COUNT
29934            if (i > listCount) {
29935                articleTag.className = "hide-landing-article"
29936            }
29937            container.append(articleTag)
29938
29939            // Handle video player initialization for articles with videos ONLY for hero and 1x1 layouts
29940            if (article.hasVideo && article.hasVideo !== 'videoHide' && this.layoutTypesForInlineVideos.includes(layoutType) && showInlineVideo === 'true') {
29941                News.ContentList.initializeVideoPlayer(articleTag, article.videoDetails)
29942            }
29943
29944            // Regionalize article URLs, Display Scene7 Images, Compute Relative Dates
29945            $(articleTag).trigger('article-append')
29946            if (canonical) {
29947                $(articleTag).find('a').each(function () {
29948                    $(this).prop("href", article['canonicalUrl']);
29949                });
29950            }
29951        },
29952
29953        /**
29954         * Initialize video player for articles with video content
29955         */
29956        initializeVideoPlayer: function (articleElement, videoDetails) {
29957            try {
29958                // Find the video player container within this article
29959                var videoContainer = $(articleElement).find('.video-player-container')
29960
29961                if (videoContainer.length > 0 && videoDetails.videoPid) {
29962                    // Create unique IDs for this video player instance
29963                    var uniqueId = 'video-player-' + videoDetails.videoPid
29964                    var vodPlayerId = 'vod-player-' + videoDetails.videoPid
29965
29966                    // Set the unique IDs
29967                    videoContainer.attr('id', uniqueId)
29968                    var videoElement = videoContainer.find('video')
29969                    videoElement.attr('id', vodPlayerId)
29970
29971                    // Set up platform-video-data attributes from article data
29972                    var platformVideoData = videoContainer.find('.platform-video-data')
29973                    if (platformVideoData.length === 0) {
29974                        // Create platform-video-data div if it doesn't exist
29975                        platformVideoData = $('<div class="platform-video-data"></div>')
29976                        videoContainer.find('.player-wrapper').append(platformVideoData)
29977                    }
29978
29979                    // Set data attributes that video-player.js expects
29980                    platformVideoData.attr({
29981                        'data-pid': videoDetails.videoPid || '',
29982                        'data-videothumbnail': videoDetails.videoThumbnail || '',
29983                        'data-autoplay': videoDetails.videoAutoPlay || 'false',
29984                        'data-logobranding': videoDetails.videoLogoBranding || '',
29985                        'data-authenticated': videoDetails.videoAuthentication || '',
29986                        'data-authtype': videoDetails.videoAuthType || 'openMode'
29987                    })
29988                    
29989                    if (videoDetails.videoThumbnail) {
29990                        videoElement.attr('poster', videoDetails.videoThumbnail);
29991                    }
29992                    
29993                    if (typeof News.VideoPlayer !== 'undefined' && News.VideoPlayer.init) {
29994                        News.VideoPlayer.init(uniqueId, vodPlayerId, videoDetails);
29995                    } else {
29996                        console.log('News.VideoPlayer.init is not available');
29997                    }
29998                }
29999            } catch (ex) {
30000                console.log('Error initializing video player:', ex)
30001            }
30002        },
30003         decodeHtmlEntities: function (str) {
30004                    if (!str) {
30005                        return "";
30006                    }
30007                    var txt = document.createElement("textarea");
30008                    txt.innerHTML = str;
30009                    return txt.value;
30010         },
30011         repairLostAposQ: function (s) {
30012                    if (!s || s.indexOf("?") < 0) {
30013                        return s || "";
30014                    }
30015                    s = s.replace(/^\?([^?]+?)\?(\s|$)/, "'$1'$2");
30016                    s = s.replace(/(\s)\?([^?]+?)\?(\s|$)/g, '$1‘$2’$3');
30017                    s = s.replace(/(\w)\?(\w)/g, "$1'$2");
30018                    s = s.replace(/(\d{2})\?s\b/g, "$1's");
30019                    return s;
30020         },
30021         cleanText: function (s) {
30022                    var t = News.ContentList.decodeHtmlEntities(s || "");
30023                    t = News.ContentList.repairLostAposQ(t);
30024                    return t;
30025         },
30026
30027        /**
30028         * Assembles and returns the article tag contents as a string, with placeholders swapped out for variables
30029         *
30030         *   @param article - JSON object with variables returned from the article service.
30031         *
30032         *   The HTML structure returned includes three sibling divs in one string, intended to be injected in an <article> tag.
30033         */
30034        getArticleHtml: function (article, layoutType, showInlineVideo) {
30035            article.image = article.image || ""
30036            article.altText = article.altText || ""
30037            article.location = article.location || ""
30038            article.headline = News.ContentList.cleanText(article.headline);
30039            article.previewText = News.ContentList.cleanText(article.previewText);
30040            article.flairText = News.ContentList.cleanText(article.flairText);
30041
30042            let isPodcastArticle = false;
30043            if (article.flairText.includes('PODCAST') || article.podcastDuration) {
30044                isPodcastArticle = true;
30045            }
30046
30047            // Check if article has video and should show video player instead of image
30048            let hasVideo = article.hasVideo && article.hasVideo !== 'videoHide' && this.layoutTypesForInlineVideos.includes(layoutType) && showInlineVideo === 'true';
30049
30050            // Determine poster image
30051            let posterImage = '';
30052            if (article.placeholderImage && article.placeholderImage.trim() !== '') {
30053                posterImage = article.placeholderImage;
30054            } else if (article.image) {
30055                posterImage = article.image;
30056            }
30057
30058            // Rules: .flair--single-column-mobile only displays flair in .content-list-layout--4x1-single-column-mobile
30059            let flair1Template = '<div class="flair--single-column-mobile"><a href="{url}"><div data-flair-text="{flairText}" data-flair-off-time="{utcFlareOffTime}" class="flair flair--{flairType}"></div></a></div>'
30060
30061            let articleImageTemplate = ''
30062
30063            // If article has video AND it's hero layout, render video player container instead of image
30064            if (hasVideo) {
30065                articleImageTemplate = News.ContentList.getVideoPlayerHtml(layoutType, posterImage)
30066            }
30067            // If article has image but no video OR not hero layout, render image
30068            else if (article.image != "") {
30069                articleImageTemplate = '<div class="article-image"><a href="{url}"><img alt="{altText}" class="img-responsive" width="1250" height="703" data-src="{image}" src="https://s7d2.scene7.com/is/image/TWCNews/1x1transparent" loading="lazy"><div class="{hasVideo}" data-video-duration="{videoDuration}"><a href="{url}"><div class="triangle"></div><div class="text"><span>{videoDuration}</span></div></a></div></a></div>'
30070            }
30071            // No image and no video
30072            else {
30073                articleImageTemplate = '<div class="article-image-none"></div>'
30074            }
30075
30076            var articleDetailsTemplate = '<div class="article__details list-details"><a class="flair--landing-page" href="{url}"><div data-flair-text="{flairText}" data-flair-off-time="{utcFlareOffTime}" class="flair flair--{flairType}"></div></a><h2 class="headline-only--small"><a href="{url}">{headline}</a></h2><p class="article-preview">{previewText}</p><p><span class="article__location">{location}</span><span class="article__relative-time" data-time="{date}"></span></p><div class="video-length-container"><div class="{hasVideo}" data-video-duration="{videoDuration}"><a href="{url}"><div class="triangle"></div><div class="text"><span>{videoDuration}</span></div></a></div></div></div>'
30077
30078            if(isPodcastArticle && (article.hasVideo === 'videoHide')){
30079                article.podcastDuration = News.ContentList.formatPodcastDuration(article.podcastDuration)
30080               articleDetailsTemplate = '<div class="article__details list-details"><a class="flair--landing-page" href="{url}"><div data-flair-text="{flairText}" data-flair-off-time="{utcFlareOffTime}" class="flair flair--{flairType}"></div></a><h2 class="headline-only--small"><a href="{url}">{headline}</a></h2><p class="article-preview">{previewText}</p><p><span class="article__location">{location}</span><span class="article__relative-time" data-time="{date}"></span></p><div class="podcast-icon-container"><div class="videoShow" ><a href="{url}"><img src="/etc/designs/news/clientlibs/css/images/icons/icon-microphone.svg" alt="podcast icon" style="width: 16px;height: 16px;flex-grow: 0;object-fit: contain;" /><div class="text"><span>{podcastDuration}</span></div></a></div></div><div class="video-length-container"><div class="{hasVideo}" data-video-duration="{videoDuration}"><a href="{url}"><div class="triangle"></div><div class="text"><span>{videoDuration}</span></div></a></div></div></div>'
30081            }
30082
30083            // Rules: .hide-landing-flair--single-column-mobile doesn't display in .content-list-layout--4x1-single-column-mobile and landing page content list
30084            var flairTemplate = '<a href="{url}"><div data-flair-text="{flairText}" data-flair-off-time="{utcFlareOffTime}" class="flair flair--{flairType} hide-landing-flair--single-column-mobile"></div></a>'
30085
30086            var allDivsTemplate = flair1Template + articleImageTemplate + flairTemplate + articleDetailsTemplate
30087            return News.ContentList.createStringFromTemplate(allDivsTemplate, article)
30088        },
30089
30090        formatPodcastDuration: function(podcastDuration){
30091            const time = podcastDuration.split(':').map(Number);
30092            let hr = 0 , min = 0 , sec = 0;
30093
30094            if(time.length === 3){
30095                [hr, min, sec] = time;
30096            }else if(time.length === 2){
30097                [min, sec] = time;
30098            }else{
30099                [sec] = time
30100            }
30101
30102            if(hr > 0){
30103                return `${hr}:${min.toString().padStart(2,'0')}:${sec.toString().padStart(2,'0')}`
30104            }else if(min > 0){
30105               return `${min}:${sec.toString().padStart(2,'0')}`  
30106            }else{
30107                return `0:${sec.toString().padStart(2,'0')}`
30108            }
30109
30110        },
30111
30112
30113        /**
30114        * Generate video player HTML container structure
30115        * Updated to ensure IVP thumbnail loads immediately like non-IVP articles
30116        */
30117        getVideoPlayerHtml(layoutType, posterImage) {
30118
30119            let playerHtml = '';
30120
30121            if (layoutType === 'landing-page' || layoutType === 'hero' || layoutType === '1x1') {
30122                playerHtml += '<div class="article-image">';
30123            }
30124
30125            // Use article image as poster (same as non-IVP logic)
30126            const transparentPixel =
30127                'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAA' +
30128                'AAC0lEQVR42mP8/x8AAwMBAAOH1YkAAAAASUVORK5CYII=';
30129
30130            const poster = (posterImage && posterImage.trim() !== '') ? posterImage : transparentPixel;
30131
30132            playerHtml +=
30133                '<div class="video-player-container">' +
30134                '<div class="header-player">' +
30135                '<div class="componentWrapper">' +
30136                '<div class="player-wrapper">' +
30137
30138                // preload thumbnail like normal article image
30139                '<link rel="preload" as="image" href="' + poster + '">' +
30140
30141                '<video playsinline webkit-playsinline ' +
30142                'width="1250" height="703" ' +
30143                'poster="' + poster + '" ' +
30144                'preload="metadata" ' +
30145                'style="width:100%;height:auto;" ' +
30146                'data-video-type="vod-inline-content-list">' +
30147                '</video>' +
30148
30149                '</div>' +
30150                '</div>' +
30151                '</div>' +
30152                '</div>';
30153
30154            if (layoutType === 'landing-page' || layoutType === 'hero' || layoutType === '1x1') {
30155                playerHtml += '</div>';
30156            }
30157
30158            return playerHtml;
30159        },
30160
30161        /**
30162         * Helper function to use string templates for rendering HTML
30163         *
30164         * Replaces placeholders of {name} format in template string, by looking for 'name' property in the variables object
30165         */
30166        createStringFromTemplate: function (template, variables) {
30167            return template.replace(new RegExp("\{([^\{]+)\}", "g"), function (_unused, varName) {
30168                return variables[varName] || "";
30169            });
30170        },
30171
30172        fixStoryLinkInAuthorMode: function (url) {
30173            if (!News.ContentList.authorMode) return url;
30174            if (!/^\/content\/news\/(stories|web-reference-templates)/i.test(location.pathname)) return url;
30175            if (/^\/content\/news\/stories\//i.test(url) && !url.endsWith('.html')) {
30176                return url + '.html';
30177            }
30178            return url;
30179        },
30180
30181        /**
30182         * Dynamically loads all content lists that specify using ajax to return results.
30183         *
30184         */
30185        init: function () {
30186            News.ContentList.authorMode = $("." + News.ContentList.AUTHOR_MODE_CLASS).length > 0;
30187            
30188            const contentLists = $('.content-list .ajax--true').filter(News.ContentList.contentListFilter);
30189            let completedCount = 0;
30190            const totalCount = contentLists.length;
30191            let timeoutTriggered = false;
30192            
30193            // Track completion of all content lists
30194            const triggerComplete = () => {
30195                if (!timeoutTriggered) {
30196                    timeoutTriggered = true;
30197                    window.contentListsComplete = true;
30198                    $(document).trigger('contentListsComplete');
30199                }
30200            };
30201            
30202            const checkAllComplete = () => {
30203                completedCount++;
30204                if (completedCount === totalCount) {
30205                    triggerComplete();
30206                }
30207            };
30208            
30209            if (totalCount === 0) {
30210                triggerComplete();
30211            } else {
30212                // Set 3-second timeout as fallback
30213                setTimeout(triggerComplete, 3000);
30214                
30215                contentLists.each(function(index) {
30216                    News.ContentList.loadContentList(index, this, checkAllComplete);
30217                });
30218            }
30219        } //  init: function() {
30220
30221    } // ns('News').ContentList
30222
30223// Load all the tag based dynamic content lists
30224    $(News.ContentList.init)
30225
30226})(jQuery);
30227(function ($) {
30228
30229    ns("News.App").Analytics = {
30230
30231        init: function () {
30232
30233            /*
30234             * Core variable for DTM to pull its tracking data
30235             */
30236
30237            var $adl = $('#analyticsDataLayer');
30238
30239            window.analyticsDataLayer = {
30240                region : $adl.data('region') != null ? $adl.data('region') : '',
30241                isInternal : $adl.data('is-internal') != null ? String($adl.data('is-internal')) : '',
30242                tags : $adl.data('tags') != null ? $adl.data('tags') : '',
30243                pageCategory : $adl.data('page-category') != null ? $adl.data('page-category') : '',
30244                author : $adl.data('author') != null ? $adl.data('author') : '',
30245                publicationDate : $adl.data('publication-date') != null ? $adl.data('publication-date') : '',
30246                headline : $adl.data('headline') != null ? $adl.data('headline') : '',
30247                hhid :  '',
30248                isAuthenticated : window.localStorage.getItem('authenticatedV2')? 'true' : 'false',
30249                contentType : $adl.data('content-type') != null ? $adl.data('content-type') : '',
30250                vodAuthType : $('div.platform-video-data').data('analytics-authtype') ? $('div.platform-video-data').data('analytics-authtype') :'closed',
30251                language : $adl.data('language') != null ? $adl.data('language') : ''
30252            };
30253
30254            /*
30255             * Added to accommodate the search results app handling its own analytics requests
30256             */
30257
30258            if (!window.searchapp) {
30259                try {
30260                    _satellite.pageBottom();
30261                } catch (e) {
30262                }
30263            }
30264
30265            this.bindLinkTracking();
30266
30267            //page view event listener for forward/back
30268            $(window).on("pageShow",function()
30269            {
30270                window.digitalData.event = "pageView";
30271            });
30272        },
30273
30274        bindLinkTracking: function () {
30275
30276            /*
30277             * Header component nav bar TWCNEWS-1329
30278             *
30279             */
30280            $(".site-header .navbar-nav").on("click", "a", function () {
30281                setWebEvent("navigationLinkTracking",
30282                    {
30283                        componentName: "header sub nav",
30284                        linkText: trim(this.text)
30285                    }
30286                );
30287            });
30288
30289            /*
30290             * Header component social buttons TWCNEWS-1329
30291             *
30292             */
30293            $(".site-header .social-icons").on("click", "a", function () {
30294                setWebEvent("postPageLoadAction",
30295                    {
30296                        componentName: "follow: header",
30297                        events: ["siteToolUsed"]
30298                    }
30299                );
30300            });
30301
30302            /*
30303             * Header component search icon TWCNEWS-1329
30304             *
30305             */
30306            $(".site-header .icon-SearchButton").on("click", function () {
30307                setWebEvent("postPageLoadAction",
30308                    {
30309                        componentName: "search: header",
30310                        events: ["siteToolUsed"]
30311                    }
30312                );
30313            });
30314
30315            /*
30316             * Footer component
30317             */
30318
30319            $("#footerLinks a").on("click", function () {
30320                setWebEvent("navigationLinkTracking",
30321                    {
30322                        componentName: "footer links",
30323                        linkText: trim(this.text)
30324                    }
30325                );
30326            });
30327
30328            /*
30329             * Footer component social links
30330             */
30331
30332            $("#footerSocialLinks a").on("click", function () {
30333                setWebEvent("postPageLoadAction",
30334                    {
30335                        siteTool: "social: follow",
30336                        mediaType: trim($(this).data("provider")),
30337                        events: ["siteToolUsed", "socialFollow"]
30338                    }
30339                );
30340            });
30341
30342            /*
30343             * Automated/Manual Weather/Closings alert component
30344             */
30345
30346            $(".wxAlerts a").on("click", function () {
30347
30348                var componentEle = $(this).closest(".wxAlerts > div")
30349                var componentName = componentEle.data("alertconfigtype") + " " + componentEle.data("alerttype") + " alert";
30350
30351                setWebEvent("navigationLinkTracking",
30352                    {
30353                        componentName: componentName,
30354                        linkText: trim(this.text),
30355                        linkType: "button"
30356                    }
30357                );
30358            });
30359
30360            /*
30361             * Weather Outlook component "Forecast Button"
30362             */
30363
30364            $('#wxOutlook').on('click', '#wxOutlookForecastBtn', function () {
30365                setWebEvent("navigationLinkTracking",
30366                    {
30367                        componentName: "7-day forecast",
30368                        linkText: "view 7-day forecast",
30369                        linkType: "button"
30370                    }
30371                );
30372            });
30373
30374            /*
30375             * Weather Outlook component "Radar Button"
30376             */
30377
30378            $('#wxOutlook').on('click', '#wxOutlookRadarBtn', function () {
30379                setWebEvent("navigationLinkTracking",
30380                    {
30381                        componentName: "Interactive Radar",
30382                        linkText: "Interactive Radar",
30383                        linkType: "button"
30384                    }
30385                );
30386            });
30387
30388            /*
30389             * Quick Links component
30390             */
30391
30392            $(".quickLinks a").on("click", function () {
30393                setWebEvent("navigationLinkTracking",
30394                    {
30395                        componentName: "Quick Links Bar",
30396                        linkText: trim(this.text)
30397                    }
30398                );
30399            });
30400
30401            /*
30402             * Section Header component
30403             */
30404
30405            $(".section-header a").on("click", function () {
30406                setWebEvent("navigationLinkTracking",
30407                    {
30408                        componentName: "Section Header",
30409                        linkText: trim(this.text)
30410                    }
30411                );
30412            });
30413
30414            /*
30415             * Hero Content List Component article headline link TWCNEWS-1344
30416             */
30417            $(".hero .article-headline").on("click", "a", function () {
30418                setWebEvent("navigationLinkTracking",
30419                    {
30420                        componentName: "Hero Content List",
30421                        linkText: trim(this.text)
30422                    });
30423            });
30424
30425            /*
30426             * Hero Content List Component article headline link TWCNEWS-1344
30427             */
30428            $(".hero  .article-image").on("click", "a", function () {
30429                setWebEvent("navigationLinkTracking",
30430                    {
30431                        componentName: "Hero Content List",
30432                        linkText: trim(this.href)
30433                    });
30434            });
30435
30436            /*
30437             * Hero Content List Component View More button TWCNEWS-1344
30438             */
30439            $(".hero").on("click", ".btn-view-more", function () {
30440                setWebEvent("navigationLinkTracking",
30441                    {
30442                        componentName: "Hero Content List",
30443                        linkText: "View More"
30444                    });
30445            });
30446
30447            /*
30448             *Content List component tracking headline TWCNEWS-1345
30449             */
30450            $("div[class='content-list'] .article-headline").on("click", "a", function () {
30451
30452                var position = $(this).closest(".content-list-item").index(".content-list-item") ;
30453                var text = trim(this.text) + " : " + position ;
30454
30455                setWebEvent("navigationLinkTracking",
30456                    {
30457                        componentName: "Content List",
30458                        linkText: trim(this.text)
30459                    });
30460            });
30461
30462            /*
30463             *Content List component tracking article image TWCNEWS-1345
30464             */
30465            $("div[class='content-list'] .article-image").on("click", "a", function () {
30466
30467                var position = $(this).closest(".content-list-item").index(".content-list-item") ;
30468                var text = trim(this.text) + " : " + position ;
30469
30470                setWebEvent("navigationLinkTracking",
30471                    {
30472                        componentName: "Content List",
30473                        linkText: trim(this.href)
30474                    });
30475            });
30476
30477            /*
30478             * Content List Component View More button tracking TWCNEWS-1345
30479             */
30480            $("div[class='content-list']").on("click", ".btn-view-more", function () {
30481                setWebEvent("navigationLinkTracking",
30482                    {
30483                        componentName: "Content List",
30484                        linkText: "View More"
30485                    });
30486            });
30487
30488            /*
30489             *Landing Page Content List component tracking headline TWCNEWS-1352
30490             */
30491            $(".landing-page .article-headline").on("click", "a", function () {
30492
30493                var position = $(this).closest(".content-list-item").index(".content-list-item") ;
30494                var text = trim(this.text) + " : " + position ;
30495
30496                setWebEvent("navigationLinkTracking",
30497                    {
30498                        componentName: "Landing Page Content List",
30499                        linkText: trim(this.text)
30500                    });
30501            });
30502
30503            /*
30504             *Landing Page Content List component tracking article image TWCNEWS-1352
30505             */
30506            $(".landing-page .article-image").on("click", "a", function () {
30507
30508                var position = $(this).closest(".content-list-item").index(".content-list-item") ;
30509                var text = trim(this.text) + " : " + position ;
30510
30511                setWebEvent("navigationLinkTracking",
30512                    {
30513                        componentName: "Landing Page Content List",
30514                        linkText: trim(this.href)
30515                    });
30516            });
30517
30518
30519            /*
30520             * Calendar component "Sharing"
30521             *
30522             * Using "delegate" to support dynamic calendar content
30523             */
30524            $("#community-calendar").delegate( "a.shareIcon", "click", function() {
30525                setWebEvent("postPageLoadAction",
30526                    {
30527                        siteTool: "social: share calendar",
30528                        mediaType: trim($(this).data("provider")),
30529                        events: ["siteToolUsed", "socialShare"]
30530                    }
30531                );
30532            });
30533
30534        },
30535
30536        changeEvents: {
30537
30538            /*
30539             * Weather Outlook component "Slider Change"
30540             * This gets called from function "initSlider" etc/designs/news/clientlibs/js/weather/js/wxOutlook.js
30541             */
30542
30543            onWxOutLookSlider: function () {
30544                setWebEvent("postPageLoadAction",
30545                    {
30546                        siteTool: "weather: interactive radar slider used",
30547                        events: ["siteToolUsed"]
30548                    }
30549                );
30550            },
30551            onPlaybackStreamStarted: function(streamAnalytics){
30552                setWebEvent("postPageLoadAction",
30553                    {
30554                        channelName : streamAnalytics.analyticsChannel,
30555                        videoTitle: streamAnalytics.analyticsTitle,
30556                        startTime:"",
30557                        products:";;;;event3=0",
30558                        events:["liveStreamTimeWatched","videoStart"]
30559                    }
30560                );
30561            },
30562
30563            continuousPlayback: function(streamAnalytics){
30564                setWebEvent("postPageLoadAction",
30565                    {
30566                        channelName: streamAnalytics.analyticsChannel,
30567                        videoTitle: streamAnalytics.analyticsTitle,
30568                        products:";;;;event3=300",
30569                        events:["liveStreamTimeWatched"]
30570                    }
30571                );
30572            },
30573
30574            onPlaybackStreamStopped: function(streamAnalytics){
30575                setWebEvent("postPageLoadAction",
30576                    {
30577                        channelName : streamAnalytics.analyticsChannel,
30578                        videoTitle: streamAnalytics.analyticsTitle,
30579                        products:";;;;event3=" + streamAnalytics.seconds_remaining,
30580                        events:["liveStreamTimeWatched"]
30581                    }
30582                );
30583            },
30584
30585            onBufferingBegan: function(streamAnalytics){
30586                setWebEvent("postPageLoadAction",
30587                    {
30588                        channelName : streamAnalytics.analyticsChannel,
30589                        videoTitle: streamAnalytics.analyticsTitle,
30590                        streamEventObject:"Buffering",
30591                        events:["streamEventObject"]
30592                    }
30593                );
30594            }
30595
30596        }
30597
30598    };
30599
30600    News.App.Analytics.init();
30601
30602})(jQuery);
30603
30604(function ($) {
30605    ns("News.App").QuantumAnalytics = {
30606
30607        APPLICATION_NAME: "application",
30608        APPLICATION_USER: "user",
30609        isPlayBackSelected: false,
30610        isPlayBackStarted: false,
30611        isPlaybackStartedAfterRetry: false,
30612        isPlayBackPause: false,
30613        isBufferStarted: false,
30614        isUriAcquired: false,
30615        isUriAcquiredFailed: false,
30616        isPlayBackStopped: false,
30617        isPlayBackExitedBeforeStartByUser: false,
30618        isPlayBackExitedBeforeStartByApp: false,
30619        isPlayBackFailed: false,
30620        isPlaybackFailedBeforeRetry: false,
30621        isPlaybackFailedAfterRetry: false,
30622        isPlaybackAttemptRestart: false,
30623        isPlaybackExitBeforeStartRetryByUser: false,
30624        isPlaybackStartRetrySuccess: false,
30625        isplayerUnmutedBefore: false,
30626        userConfigPostMVPFired: false,
30627        mediaDuration: "",
30628        streamType: "",
30629        videoCodec: "",
30630        pid: "",
30631        tmsId: "",
30632        csid: "",
30633        streamUrl: "",
30634        scrubbingCapability: "",
30635        callSign: "",
30636        detailsTitle: "",
30637        sourceMarket: "",
30638        pageRegion: "",
30639        networkStatus: "",
30640        connType: "",
30641        contentListPageMap: {'politics': 'politicsMain', 'public-safety': 'publicSafety', 'health': 'latestNews'},
30642        ourjournalists: ["staff-profiles", "bios", "ourteam"],
30643        browserSupportsBitrateTracking: undefined,
30644
30645        doSet: function (netStat) {
30646            var _timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
30647            if (window && window.Helix && window.Helix.track) {
30648                window.Helix.set("deviceLocation", {connectionDeviceLocation: "inHome"});
30649                window.Helix.set("entitlements", {entitlements: "canWatchLive, canWatchVod"});
30650                window.Helix.set("timeZone", {timeZone: _timeZone});
30651                window.Helix.set("networkStatus", {networkStatus: netStat});
30652                window.Helix.set("accountFeatures", {accessibility: true, cDvr: false, boxless: true});
30653            }
30654        },
30655
30656        showUnInitializedHelixMsg: function (eid, adhoc) {
30657            var msie = navigator.userAgent;
30658            if (msie.indexOf("MSIE") > -1 || msie.indexOf("Trident/") > -1) {
30659                // IE does not do console.error
30660            } else {
30661                console.warn("Helix wasn't initialized before **EID** was triggered  " + eid + ", " + adhoc);
30662            }
30663        },
30664
30665        setPageRegion: function () {
30666            var str = "";
30667            if (typeof window.digitalData !== "undefined" && window.digitalData) {
30668                if ((window.digitalData.page.pageRegionParent && window.digitalData.page.pageRegionParent.length !== 0)
30669                    && (window.digitalData.page.pageRegion && window.digitalData.page.pageRegion.length !== 0)) {
30670                    this.pageRegion = window.digitalData.page.pageRegionParent + "/" + window.digitalData.page.pageRegion
30671                } else {
30672                    str = window.digitalData.page.pageID
30673                    var res = str.split("/");
30674                    if (str.toLowerCase().indexOf('/content/news'.toLowerCase()) !== -1 && res.length > 4) {
30675                        this.pageRegion = res[3] + "/" + res[4]
30676                    }
30677                }
30678            }
30679        },
30680
30681
30682        firesQuantumLoginStart: function (hhid) {
30683            var eventCaseId = 'SpectrumLocal_loginStart_manualAuth';
30684            if (window && window.Helix && window.Helix.track) {
30685                window.Helix.track(eventCaseId, {
30686                    opUserText: hhid,
30687                    opType: 'manualAuth',
30688                    msgTriggeredBy: 'user',
30689                });
30690            } else {
30691                this.showUnInitializedHelixMsg(eventCaseId, "");
30692            }
30693        },
30694
30695        /**
30696         * this called from method: firesQuantumLoginStopSuccess
30697         */
30698        firesQuantumLoginStopFailure: function () {
30699            var eventCaseId = 'SpectrumLocal_loginStop_failure_manualAuth';
30700            if (window && window.Helix && window.Helix.track) {
30701                window.Helix.track(eventCaseId, {
30702                    opSuccess: false
30703                });
30704            } else {
30705                this.showUnInitializedHelixMsg(eventCaseId, "");
30706            }
30707        },
30708
30709        firesQuantumLoginStartResumeAuth: function () {
30710            var eventCaseId = 'SpectrumLocal_loginStart_resumeAuth';
30711            if (window && window.Helix && window.Helix.track) {
30712                window.Helix.track(eventCaseId, {
30713                    opType: 'resumeAuth'
30714                });
30715            } else {
30716                this.showUnInitializedHelixMsg(eventCaseId, "");
30717            }
30718        },
30719
30720        firesQuantumLoginStopSuccessResumeAuth: function () {
30721            var eventCaseId = 'SpectrumLocal_loginStop_success_resumeAuth';
30722            const authState = News.App.Pinxt.AuthState;
30723            let hhid = authState.hhid || Cookies.get('player-hhid');
30724            let mvpd = authState.mvpd || (authState.tempPass.isActive ? authState.tempPass.mvpd : null)
30725            if (window && window.Helix && window.Helix.track) {
30726                if (window.Helix.get('currentState') !== "initiating") {
30727                    this.firesQuantumLoginStartResumeAuth();
30728                    window.Helix.track(eventCaseId, {
30729                        accountGUID: hhid,
30730                        opSuccess: true,
30731                        tvProvider: mvpd,
30732                        opType: 'resumeAuth',
30733                        accountOauthToken: Cookies.get('login-token')
30734                    });
30735                }
30736                News.App.QuantumAnalytics.getNetworkStatus().then(netStat => {
30737                    this.networkStatus = netStat;
30738                    this.doSet(netStat);
30739                    this.firesQuantumUserConfigSetGuidTvProvider(hhid, mvpd);
30740                    this.firesQuantumUserConfigPostMVP(hhid, mvpd);
30741                })
30742            } else {
30743                this.showUnInitializedHelixMsg(eventCaseId, "");
30744            }
30745        },
30746
30747        firesQuantumLoginStopFailureResumeAuth: function () {
30748            var eventCaseId = "SpectrumLocal_loginStop_failure_resumeAuth";
30749            if (window && window.Helix && window.Helix.track) {
30750                window.Helix.track(eventCaseId, {
30751                    opSuccess: false,
30752                    appErrorType: 'authentication'
30753                });
30754            } else {
30755                this.showUnInitializedHelixMsg(eventCaseId, "");
30756            }
30757        },
30758
30759        /*
30760         *  NEWS-826
30761         *  This method will run when a user
30762         *  click one of the mvpd icons to go to the login
30763         *  page and login is successful
30764         */
30765        firesQuantumUserConfigSetGuidTvProvider: function (hhid, mvpd, identityGUID, bypassPageGuard) {
30766            var eventCaseId = 'SpectrumLocal_userConfigSet_guid_tvProvider';
30767            // Historically this event is page-guarded to the watch-live/login pages (a scope from
30768            // the manual-login flow). Auto auth (NEWS-9891) typically completes on the home page,
30769            // so the auto path passes bypassPageGuard=true to fire regardless of page and capture
30770            // visit.account.identityGUID. Manual/resume callers omit the flag and stay page-guarded.
30771            var isAllowedPage = window.digitalData.page && (window.digitalData.page.pageName === "watch_spectrum_news_live" ||
30772                window.digitalData.page.pageName === 'login');
30773            if (bypassPageGuard || isAllowedPage) {
30774
30775                if (window && window.Helix && window.Helix.track) {
30776                    var payload = {
30777                        accountGUID: hhid,
30778                        tvProvider: mvpd,
30779                        appName: 'SpectrumLocal',  // Example string
30780                    };
30781                    // COX analytics (NEWS-9891): legacy MVPD identity for auto auth. Only added
30782                    // when present; manual/resume-auth callers do not pass it and are unchanged.
30783                    // Quantum backend encrypts identityGUID and stores it as encIdentityGUID.
30784                    if (identityGUID) {
30785                        payload.identityGUID = identityGUID;
30786                    }
30787                    window.Helix.track(eventCaseId, payload)
30788                } else {
30789                    this.showUnInitializedHelixMsg(eventCaseId, "");
30790                }
30791            }
30792        },
30793
30794        /**
30795         * possible connectionDeviceLocation values: [inMarket or outOfMarket or inHome or unknown]
30796         */
30797        firesQuantumUserConfigPostMVP: function (hhid, mvpd) {
30798            var eventCaseId = 'SpectrumLocal_userConfigSet_postMVP';
30799            if (window && window.Helix && window.Helix.track) {
30800                window.Helix.track(eventCaseId, {
30801                    accountGUID: hhid,
30802                    tvProvider: mvpd,
30803                    appName: 'SpectrumLocal',
30804                })
30805            } else {
30806                this.showUnInitializedHelixMsg(eventCaseId, "");
30807            }
30808            this.userConfigPostMVPFired = true;
30809        },
30810
30811        /*
30812        *  This method will run when a user
30813        *  click one of the mvpd icons to go to the login
30814        *  page and login is successful
30815        *  called from launch.html
30816        */
30817        firesQuantumLoginStopSuccess: function (hhid, mvpd) {
30818            var eventCaseId = 'SpectrumLocal_loginStop_success_manualAuth';
30819            if (Cookies.get('LIVETVLOGIN-CLICKED') === 'QuantumTagLoginStart') {
30820                Cookies.remove('LIVETVLOGIN-CLICKED');
30821                if (window && window.Helix && window.Helix.track) {
30822                    if (window.Helix.get('currentState') !== "initiating") {
30823                        this.firesQuantumLoginStart(hhid);
30824                        window.Helix.track(eventCaseId, {
30825                            accountGUID: hhid,
30826                            accountOauthToken: Cookies.get('login-token'),
30827                            tvProvider: mvpd,
30828                            opType: 'manualAuth',
30829                            opSuccess: true
30830                        })
30831                    }
30832                    News.App.QuantumAnalytics.getNetworkStatus().then(netStat => {
30833                        this.networkStatus = netStat;
30834                        this.doSet(netStat)
30835                        this.firesQuantumUserConfigSetGuidTvProvider(hhid, mvpd);
30836                        this.firesQuantumUserConfigPostMVP(hhid, mvpd);
30837                    })
30838                } else {
30839                    this.showUnInitializedHelixMsg(eventCaseId, "");
30840                }
30841            }
30842        },
30843
30844        // Auto Auth Events
30845
30846        autoLoginStart: function () {
30847            if (window && window.Helix && window.Helix.track) {
30848                window.Helix.track('SpectrumLocal_AutoAccess_Login_Start')
30849            }
30850        },
30851
30852        autoLoginSuccess: function (hhid, mvpd) {
30853            if (window && window.Helix && window.Helix.track) {
30854                this.autoLoginStart();
30855                window.Helix.track('SpectrumLocal_Auto_Login_Success', {
30856                    loginCompletedTs: Date.now(),
30857                    loginAttemptId: News.App.Pinxt.AuthState.authXTraceId
30858                })
30859            }
30860
30861            // Set network as "OnNet" since we are behind the Modem
30862            this.doSet("onNet")
30863
30864            // COX analytics (NEWS-9891): emit legacy MVPD as visit.account.identityGUID on the
30865            // guid_tvProvider event for auto auth. Auto auth usually completes on the home page,
30866            // so bypass the watch-live/login page guard to fire wherever auto auth happened. Only
30867            // fired when a legacyMVPD value is resolved (MSO present); absent -> field/event omitted.
30868            var legacyMVPD = (News.App.Pinxt && News.App.Pinxt.AuthState && News.App.Pinxt.AuthState.legacyMVPD) || '';
30869            if (legacyMVPD) {
30870                this.firesQuantumUserConfigSetGuidTvProvider(hhid, mvpd, legacyMVPD, true);
30871            }
30872
30873            this.firesQuantumUserConfigPostMVP(hhid, mvpd);
30874            localStorage.setItem("autoAuth", "false")
30875        },
30876
30877
30878        isHomePage: function (digitalDataPg) {
30879            var retBool = false;
30880            var str = digitalDataPg.pageID;
30881            var newstr;
30882            if (str) {
30883                newstr = str.replace("/content/news/", "");
30884                if (typeof newstr !== 'undefined' && newstr) {
30885                    newstr = newstr.split("/");
30886                    // the on-air graphics at /section/On_Air_HTML_Overlay is not a home page
30887                    if (newstr.length == 2 && !newstr[1].toLowerCase().includes('overlay')) {
30888                        retBool = true
30889                    }
30890                }
30891
30892            }//if(str)
30893            return retBool;
30894        },
30895
30896        trackHomePage: function (digitalDataPg) {
30897            var eventCaseId = 'SpectrumLocal_pageView_home';
30898            if (window && window.Helix && window.Helix.track) {
30899                var parentMarket = digitalDataPg.pageRegionParent !== "" ? digitalDataPg.pageRegionParent : "none";
30900                var childMarket = digitalDataPg.pageRegion !== "" ? digitalDataPg.pageRegion : "none";
30901                var msgEventTypes = ["pageViewInit", "pageViewCompleted"];
30902                for (var i = 0; i < msgEventTypes.length; i++) {
30903                    var msgEventType = msgEventTypes[i];
30904                    window.Helix.track(eventCaseId ? eventCaseId : 'pageView', {
30905                        msgEventType: msgEventType,
30906                        currPageTitle: digitalDataPg.pageTitle,
30907                        msgTriggeredBy: 'user',
30908                        viewChildMarket: childMarket,
30909                        viewParentMarket: parentMarket,
30910                        currPageIsLazyLoad: false
30911                    })
30912                }
30913            } else {
30914                this.showUnInitializedHelixMsg(eventCaseId, "");
30915            }
30916        },
30917
30918        getHelixPageName: function (pgnamekey) {
30919            var pageName = pgnamekey;
30920            if (this.contentListPageMap.hasOwnProperty(pgnamekey)) {
30921                pageName = this.contentListPageMap[pgnamekey];
30922            }
30923            return pageName;
30924        },
30925
30926        triggerHelixPageviewEvent: function (digitalData) {
30927            var pgName = digitalData.pageName;
30928            var pgTitle = digitalData.pageTitle;
30929            var parentMarket = digitalData.pageRegionParent !== "" ? digitalData.pageRegionParent : "none";
30930            var childMarket = digitalData.pageRegion !== "" ? digitalData.pageRegion : "none";
30931            if (pgName && pgName.includes('politics')) {
30932                this.trackPageView(this.getHelixPageName("politicsMain"), "politics", {eventCaseId: "SpectrumLocal_pageView_politicsMain"}, digitalData)
30933            } else if (pgName && pgName.includes('public-safety')) {
30934                this.trackPageView(this.getHelixPageName(pgName), "latestNews", {eventCaseId: "SpectrumLocal_pageView_publicSafety"}, digitalData)
30935            } else if (pgName && pgName.includes('health')) {
30936                if (/exploring-your-health/i.test(pgName)) {
30937                    this.trackPageView("exploringYourHealth", "latestNews", {eventCaseId: "SpectrumLocal_pageView_exploringYourHealth"}, digitalData)
30938                } else {
30939                    this.trackPageView("health", "latestNews", {eventCaseId: "SpectrumLocal_pageView_health"}, digitalData)
30940                }
30941            } else if (pgName && this.ourjournalists.includes(pgName)) {
30942                this.trackPageView("ourJournalists", "ourJournalists", {eventCaseId: "SpectrumLocal_pageView_ourJournalists"}, digitalData)
30943            } else if (pgName && (pgName.includes('lotto') || pgName.includes('lottery'))) {
30944                this.trackPageView("lottery", "latestNews", {eventCaseId: "SpectrumLocal_pageView_lottery"}, digitalData)
30945            } else if (pgName && (pgName.includes('sports') || pgName.includes('pro'))) {
30946                this.trackPageView("sports", "latestNews", {eventCaseId: "SpectrumLocal_pageView_sports"}, digitalData)
30947            } else if (pgName && (pgName.includes('business'))) {
30948                this.trackPageView("business", "latestNews", {eventCaseId: "SpectrumLocal_pageView_business"}, digitalData)
30949            } else if (pgName && pgName === 'news') {
30950                this.trackPageView("newsMain", "latestNews", {eventCaseId: "SpectrumLocal_pageView_newsMain"}, digitalData)
30951            } else if (pgName && (pgName.includes('recalls'))) {
30952                this.trackPageView("recalls", "latestNews", {eventCaseId: "SpectrumLocal_pageView_recalls"}, digitalData)
30953            } else if (pgName && (pgName.includes('trending'))) {
30954                this.trackPageView("trending-topics", "latestNews", {eventCaseId: "SpectrumLocal_pageView_trendingTopics"}, digitalData)
30955            } else if (pgName && (pgName.includes('radar'))) {
30956                this.trackPageView("interactiveRadar", "weather", {eventCaseId: "SpectrumLocal_pageView_interactiveRadar"}, digitalData)
30957            } else if (pgName && (pgName.includes('live-video'))) {
30958                this.trackPageView("playerLiveTv", "liveTv", {eventCaseId: "SpectrumLocal_pageView_playerLiveTv"})
30959            } else if (pgName && (pgName.includes('splash'))) {
30960                this.trackPageView("splash", "splash", {eventCaseId: "SpectrumLocal_Web_pageView_splash"}, digitalData)
30961            } else if (pgName && /exploring-your-health/i.test(pgName)) {
30962                this.trackPageView("exploringYourHealth", "latestNews", {eventCaseId: "SpectrumLocal_pageView_exploringYourHealth"}, digitalData)
30963            } else if (pgName && (pgName.includes('7-day-forecast'))) {
30964                this.trackPageView("sevenDayForecast", "weather", {eventCaseId: "SpectrumLocal_pageView_sevenDayForecast"}, digitalData)
30965            } else if (pgName && (pgName.includes('weather'))) {
30966                if (/weather-blogs/i.test(pgName) || /weather-experts-blog/i.test(pgName)) {
30967                    this.trackPageView("weatherBlog", "weather", {eventCaseId: "SpectrumLocal_pageView_weatherBlog"}, digitalData)
30968                } else this.trackPageView("weatherMain", "weather", {eventCaseId: "SpectrumLocal_pageView_weatherMain"}, digitalData)
30969            } else if (pgName && (pgName.includes('watches-warnings'))) {
30970                this.trackPageView("watchesWarnings", "weather", {eventCaseId: "SpectrumLocal_pageView_watchesWarnings"}, digitalData)
30971            } else if (pgName && (/traffic/i.test(pgName) || /transit/i.test(pgName))) {
30972                if (/traffic-news/i.test(pgName) || /traffic-growth/i.test(pgName) || /transit/i.test(pgName) || pgName === "traffic") {
30973                    this.trackPageView("trafficNews", "traffic", {eventCaseId: "SpectrumLocal_pageView_trafficNews"}, digitalData)
30974                } else if (/traffic-map/i.test(pgName)) {
30975                    this.trackPageView("trafficMap", "traffic", {eventCaseId: "SpectrumLocal_pageView_trafficMap"}, digitalData)
30976                }
30977            } else {
30978                this.trackPageView(pgName, pgTitle, {eventCaseId: "SpectrumLocal_pageView_generic"}, digitalData)
30979            }
30980        },
30981
30982        trackPageView: function (pageName, pageTitle, adHocData, digitalData, pageUrl) {
30983            var eventCaseId = adHocData.eventCaseId;
30984            if (window && window.Helix && window.Helix.track) {
30985                var msgEventTypes = ["pageViewInit", "pageViewCompleted"];
30986                var parentMarket = (digitalData && digitalData.pageRegionParent !== "") ? digitalData.pageRegionParent : "none";
30987                var childMarket = (digitalData && digitalData.pageRegion !== "") ? digitalData.pageRegion : "none";
30988                for (var i = 0; i < msgEventTypes.length; i++) {
30989                    var msgEventType = msgEventTypes[i];
30990                    window.Helix.track(
30991                        eventCaseId ? eventCaseId : 'SpectrumLocal_pageView_generic',
30992                        Object.assign(
30993                            {
30994                                msgEventType: msgEventType,
30995                                currPageUrl: pageUrl || window.location.href,
30996                                currPageName: pageName,
30997                                currPageAppSection: pageTitle,
30998                                currPageId: digitalData ? digitalData.pageID : '',
30999                                currPageIsLazyLoad: true,
31000                                viewChildMarket: childMarket,
31001                                viewParentMarket: parentMarket,
31002                            },
31003                            adHocData
31004                        )
31005                    );
31006                }
31007            } else {
31008                this.showUnInitializedHelixMsg(eventCaseId, adHocData);
31009            }
31010        },
31011
31012        trackArticle: function (digitalDataPg) {
31013            var eventCaseId = 'SpectrumLocal_pageView_article';
31014            if (window && window.Helix && window.Helix.track) {
31015                var parentMarket = digitalDataPg.pageRegionParent !== "" ? digitalDataPg.pageRegionParent : "none";
31016                var childMarket = digitalDataPg.pageRegion !== "" ? digitalDataPg.pageRegion : "none";
31017                var msgEventTypes = ["pageViewInit", "pageViewCompleted"];
31018                for (var i = 0; i < msgEventTypes.length; i++) {
31019                    var msgEventType = msgEventTypes[i];
31020                    window.Helix.track(eventCaseId, {
31021                        msgEventType: msgEventType,
31022                        currPageAppSection: digitalDataPg.pageTitle,
31023                        currPageId: digitalDataPg.pageID,
31024                        msgTriggeredBy: 'user',
31025                        currPageName: digitalDataPg.pageName,
31026                        currPagePageType: digitalDataPg.pageFunction,
31027                        viewChildMarket: childMarket,
31028                        viewParentMarket: parentMarket,
31029                        currPageIsLazyLoad: false
31030                    })
31031                }
31032            } else {
31033                this.showUnInitializedHelixMsg(eventCaseId, "");
31034            }
31035        },
31036
31037        trackHelixPageviewEvents: function (digitalData) {
31038            if (typeof digitalData !== 'undefined' && digitalData) {
31039                if (typeof $('#analyticsDataLayer').data('headline') === 'undefined') {
31040                    if (this.isHomePage(digitalData.page)) {
31041                        this.trackHomePage(digitalData.page)
31042                    } else {
31043                        this.triggerHelixPageviewEvent(digitalData.page)
31044                    }
31045
31046                } else if (typeof $('#analyticsDataLayer').data('headline') !== 'undefined' && digitalData.page.pageID) {
31047                    const arr = digitalData.page.pageID.split("/");
31048                    if (arr.length > 4 && /stories/i.test(arr[4])) {
31049                        this.trackArticle(digitalData.page);
31050                    }
31051                }
31052            }
31053        },
31054
31055        /**
31056         *  will generate 'All_Generic_API_Call_Success' quantum events
31057         *  for each ajax api call or 'All_Generic_API_Call_Failure' quantum events
31058         *  for each unsuccessful ajax api call
31059         */
31060        quantumApiSuccessOrFailure: function (pathname, status, eventCaseId, ajaxTime, httpVerb, qp, responseText, responseObject, gqlOperationType) {
31061            // NEWS-9752: A response code of 0 means the request never received an
31062            // HTTP response — an offline/aborted request (interval pollers firing
31063            // while offline or backgrounded, or an in-flight call cancelled by page
31064            // navigation). These are not genuine API failures and must not be
31065            // reported to Quantum, where they distort the success-rate metric.
31066            if (status === 0 || status === '0') {
31067                return;
31068            }
31069
31070            let domain = "";
31071            const responseTime = (new Date().getTime() - ajaxTime);	
31072            const hasNoQueryStringParam = (!qp || qp.trim().length === 0 || qp === '{}');
31073            let traceId = News.App.QuantumAnalytics.extractTraceId(responseObject);
31074            let responseSize = News.App.QuantumAnalytics.extractResponseSize(responseObject);
31075
31076            if (typeof pathname !== 'undefined' && pathname.startsWith("http")) {
31077                // valid URL so we can parse using URL API
31078                const pathUrl = new URL(pathname);
31079                domain = pathUrl.host;
31080                
31081                // only use pathUrl.search for qp param value if not present in params
31082                if (hasNoQueryStringParam) {
31083                    qp = pathUrl.search;
31084                }
31085                pathname = pathUrl.pathname;
31086            } 
31087			else if (typeof pathname !== 'undefined') {
31088				// pathname doesn't start with http so try to parse out query string
31089				if (pathname.includes('?') && hasNoQueryStringParam) {
31090					qp = pathname.substring(pathname.indexOf('?'));
31091				}
31092			}
31093			
31094            // NEWS-3732 -- Setting any blank domain value to "spectrumlocalnews.com" to align with other applications.
31095            domain = domain ? domain : "spectrumlocalnews.com";
31096
31097            // For GQL events the qp parameter is a JSON-stringified request body, not a URL query string,
31098            // so the "must contain =" guard does not apply. For REST events keep the existing behaviour.
31099            // (NEWS-9788: fixes application.api.queryParameters being blanked for GQL events.)
31100            const isGqlEvent = eventCaseId === 'SpectrumLocal_apiCall_graphQL';
31101            if (!isGqlEvent && ( !qp || qp.length === 0 || qp === "{}" || !qp.includes("="))) {
31102                qp = '';
31103            }
31104
31105            let eventPayload = {    
31106                appApiHost: domain,
31107                appApiHttpVerb: httpVerb,
31108                appApiPath: pathname,
31109                appApiResponseTimeMs: responseTime,
31110                appApiQueryParameters: qp,
31111                appApiResponseCode: status,
31112                appApiResponseText: responseText ? responseText : '',
31113                appApiTraceId: traceId,
31114                appApiResponseSize: responseSize
31115            }
31116
31117            // Add apiArchitecture for all events and other required fields for graphQL events
31118            if (isGqlEvent) {
31119                const isCallSuccess = status && status.toString()[0] === '2';
31120                eventPayload.apiArchitecture = 'GQL';
31121                eventPayload.opSuccess = isCallSuccess ? true : false;
31122                eventPayload.clientServiceResult = isCallSuccess ? 'success' : 'failure';
31123                // the 'query' type call in getRecentActivityData() passes this parameter -- all others are mutations
31124                eventPayload.gqlOperationType = gqlOperationType ? gqlOperationType : 'mutation';
31125            } else {
31126                eventPayload.apiArchitecture = 'REST';
31127            }
31128                    
31129            if (window && window.Helix && window.Helix.track) {
31130                window.Helix.track(eventCaseId, eventPayload)
31131            }
31132        },
31133        extractAjaxErrorMessage(jqXHR) {
31134            // Try to use parsed JSON if available
31135            if (jqXHR.responseJSON && typeof jqXHR.responseJSON === 'object') {
31136                return JSON.stringify(jqXHR.responseJSON);
31137            }
31138            // If responseText exists, try parsing it manually
31139            if (jqXHR.responseText) {
31140                try {
31141                    const parsed = JSON.parse(jqXHR.responseText);
31142                    return JSON.stringify(parsed)
31143                } catch (e) {
31144                    // responseText wasn't valid JSON
31145                    return jqXHR.responseText;
31146                }
31147            }
31148            // Fallback - return blank string
31149            return '';
31150        },
31151        async extractFetchErrorMessage(response) {
31152            try {
31153                const contentType = response.headers.get('content-type') || '';
31154                if (contentType.includes('application/json')) {
31155                    const json = await response.json();
31156                    return JSON.stringify(json);
31157                } else {
31158                    const text = await response.text();
31159                    return text || `Request failed with status ${response.status}`;
31160                }
31161            } catch (err) {
31162                return `Request failed: ${err}`;
31163            }
31164        },
31165        extractTraceId(response) {
31166            let traceId = '';
31167            try {
31168                if (typeof Response !== 'undefined' && response instanceof Response) {
31169                    // Fetch API response object
31170                    if (response.headers.get('x-trace-id')) {
31171                        traceId = `x-trace-id:${response.headers.get('x-trace-id')}`;
31172                    } else if (response.headers.get('x-raven-request-id')) {
31173                        traceId = `x-raven-request-id:${response.headers.get('x-raven-request-id')}`;
31174                    }
31175                } else {
31176                    // jqXHR response object
31177                    if (response.getResponseHeader('x-trace-id')) {
31178                        traceId = `x-trace-id:${response.getResponseHeader('x-trace-id')}`;
31179                    } else if (response.getResponseHeader('x-raven-request-id')) {
31180                        traceId = `x-raven-request-id:${response.getResponseHeader('x-raven-request-id')}`;
31181                    }
31182                }
31183            } catch(e) {
31184                console.log('error getting traceID from response object', response)
31185            }
31186            return traceId;
31187        },
31188
31189        extractResponseSize(response) {
31190            let responseSize = '';
31191            try {
31192                if (typeof Response !== 'undefined' && response instanceof Response) {
31193                    responseSize = response.headers.get('Content-Length');
31194                } else {
31195                    // jqXHR response object
31196                    responseSize = response.getResponseHeader('Content-Length');
31197                    if (!responseSize) {
31198                        // header is absent, so use responseText.length
31199                        responseSize = response.responseText ? response.responseText.length : '';
31200                    }
31201                }
31202            } catch(e) {
31203                console.log('error getting responseSize from response object', response)
31204            }
31205            return responseSize;
31206        },
31207
31208        // Playback events
31209        setContent: function (data) {
31210            this.streamType = data.streamType;
31211            this.videoCodec = data.codec;
31212            this.mediaDuration = data.length;
31213            this.pid = data.pid;
31214            this.tmsId = data.tmsid;
31215            this.seriesId = data.seriesId;
31216            this.title = data.title;
31217            this.streamUrl = Cookies.get('stream-url')
31218            this.csid = data.csid || this.getCallSign("csid");
31219        },
31220
31221        getCallSign: function (name) {
31222            var match = RegExp('[?&]' + name + '=([^&]*)').exec(this.streamUrl);
31223            return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
31224        },
31225
31226        getDigitalDataContent: function () {
31227            if (typeof window.digitalData !== 'undefined' && window.digitalData) {
31228                this.detailsTitle = window.digitalData.page.pageTitle
31229                this.sourceMarket = window.digitalData.page.sourceMarketTag
31230            }
31231        },
31232
31233        drmType: function () {
31234            let result = bowser.getParser(navigator.userAgent).getResult();
31235            if (result.browser.name === "Safari") {
31236                return 'fairplay'
31237            } else {
31238                return 'widevine'
31239            }
31240        },
31241
31242        ccCapable: function () {
31243            return !(this.streamType === 'progressive');
31244        },
31245
31246        playbackSelect: function (event_id, type, bookMarkPos, contentUri,analyticsData) {
31247            return new Promise((resolve, reject) => {
31248                this.isPlayBackExitedBeforeStartByUser = false;
31249                // NEWS-7558 Prevent playback tracking events when bitrate tracking unsupported by browser
31250                if (this.doesBrowserSupportBitrateTracking() === false) {
31251                    console.log('browser does not support bitrate tracking. preventing playbackSelect event.');
31252                    let customEventDetails = {
31253                        customName: 'QuantumPlaybackSuppressed',
31254                        customDomain: 'AnalyticsSuppressed',
31255                        customLevel: 'info',
31256                        customMessage: {
31257                            "playbackType": type === 'vod' || type === 'replay' ? 'vod' : 'linear',
31258                            "reason": "Not possible to report bitRate for playback"
31259                        }
31260                    }
31261                    this.sendCustomEvent(customEventDetails);
31262                    return resolve(false);
31263                } else {
31264                    console.log('browser supports bitrate tracking.')
31265                }
31266
31267                const firePlaybackSelect = (eventDetails) => {
31268                    window.Helix && window.Helix.track && window.Helix.track(event_id, eventDetails);
31269                    this.isPlayBackSelected = true;
31270                    this.isPlaybackFailedAfterRetry = false;
31271                    this.isPlayBackStopped = false;
31272                    return resolve(true);
31273                }
31274
31275                const tryPlaybackSelect = (event_id, type, bookMarkPos, contentUri,analyticsData, retries) => {
31276                    this.getDigitalDataContent();
31277                    this.setPageRegion();
31278                    if (type === 'vod' || type === 'replay') {
31279                        this.scrubbingCapability = 'all'
31280                    } else {
31281                        this.scrubbingCapability = 'none'
31282                    }
31283                    let eventDetails = {
31284                        msgTriggeredBy: this.APPLICATION_NAME,
31285                        ctntContentFormat: 'HD',
31286                        ctntStrmingFormat: this.streamType,
31287                        ctntDetailsRuntime: this.mediaDuration,
31288                        ctntStrmCCCapable: this.ccCapable(),
31289                        ctntStrmEntitled: true,
31290                        ctntStrmSapCapable: false,
31291                        ctntStrmParntllyBlocked: true,
31292                        ctntStrmScrubbingCapability: this.scrubbingCapability
31293                    }
31294        
31295                    if (type === 'vod') {
31296                        eventDetails.ctntStrmBkmrkPosSec = bookMarkPos;
31297                        eventDetails.ctntIdProviderAssetId = this.pid;
31298                        eventDetails.ctntDetailsTitle = analyticsData.text;
31299                        eventDetails.sourceMarket = this.sourceMarket;
31300                    }
31301                    if (type === 'linear') {
31302                        eventDetails.ctntIdTmsGuideId = this.tmsId;
31303                        eventDetails.ctntStrmDrmType = this.drmType();
31304                        eventDetails.ctntStrmPgmrCallSign = this.csid;
31305                        eventDetails.ctntIdTmsSeriesId = this.tmsId;
31306                    }
31307                    if (type === 'live' || type === 'replay') {
31308                        eventDetails.ctntStrmDrmType = this.drmType();
31309                        eventDetails.ctntStrmPgmrCallSign = this.csid;
31310                        eventDetails.ctntIdProviderAssetId = this.pid;
31311                        eventDetails.ctntStrmCtntUri = contentUri;
31312                        eventDetails.opType = "playbackPlaySelected";
31313                    }
31314                    if (type === 'replay') {
31315                        eventDetails.ctntStrmBkmrkPosSec = 0;
31316                    }
31317
31318                    // When loading a linear video page, playbackSelect sometimes fires before userConfigSet, which violates state rules in Helix
31319                    // So we delay the playbackSelect event until userConfig event can fire
31320                    if (this.userConfigPostMVPFired || type !== 'linear') {
31321                        firePlaybackSelect(eventDetails);
31322                    } else {
31323                        let trackRetries = retries && typeof(retries) === 'number' ? retries + 1 : 1;
31324                        if (trackRetries < 5) {
31325                            // event not allowed with current Helix state, so retry again over next 2.5 seconds (5 x .5s)
31326                            setTimeout(() => {
31327                                tryPlaybackSelect(event_id, type, bookMarkPos, contentUri,analyticsData, trackRetries
31327);
31328                            }, 500)
31329                        } else {
31330                            firePlaybackSelect(eventDetails);
31331                        }
31332                    }
31333
31334                }
31335                tryPlaybackSelect(event_id, type, bookMarkPos, contentUri,analyticsData);
31336            })
31337            
31338        },
31339
31340        uriAcquiredSuccess: function (event_id, streamUrl) {
31341            if (this.isPlayBackSelected && !this.isPlayBackStarted && !(this.isPlayBackExitedBeforeStartByUser || this.isPlayBackExitedBeforeStartByApp)) {
31342                window.Helix && window.Helix.track && window.Helix.track(event_id, {
31343                    msgTriggeredBy: this.APPLICATION_NAME,
31344                    ctntStrmCtntUri: streamUrl,
31345                    videoCodec: this.videoCodec
31346                })
31347                this.isUriAcquired = true;
31348            }
31349        },
31350
31351        uriAcquiredFailure: function (event_id) {
31352            if (this.isPlayBackSelected && !(this.isPlayBackStarted || this.isPlaybackStartedAfterRetry) && !(this.isPlayBackExitedBeforeStartByUser || this.isPlayBackExitedBeforeStartByApp) && !this.isUriAcquiredFailed) {
31353                window.Helix && window.Helix.track && window.Helix.track(event_id, {
31354                    msgTriggeredBy: this.APPLICATION_NAME,
31355                    opSuccess: false,
31356                    videoCodec: this.videoCodec
31357                })
31358                this.isUriAcquiredFailed = true;
31359            }
31360        },
31361
31362        playbackStarted: function (event_id, bitRate) {
31363            if (event_id.includes('Boxcast') || event_id.includes('Hudl')) {
31364                // for HSS, the Uri Acquired event is not fired. Set it to true to allow following events to fire
31365                this.isUriAcquired = true;
31366            }
31367            if (this.isUriAcquired && !(this.isPlayBackExitedBeforeStartByUser || this.isPlayBackExitedBeforeStartByApp)) {
31368                let eventValues = {
31369                    msgTriggeredBy: this.APPLICATION_NAME,
31370                    plbkBtRtCurrBtRtBps: bitRate,
31371                }
31372
31373                // For HSS replay (VOD) events, include ctntDetailsActualRuntime
31374                if (event_id.includes('playbackStart_vod')) {
31375                    eventValues.ctntDetailsActualRuntime = this.mediaDuration;
31376                }
31377
31378                window.Helix && window.Helix.track && window.Helix.track(event_id, eventValues);
31379                News.App.QuantumAnalytics.getNetworkStatus().then(netStat => {
31380                    if (this.networkStatus !== netStat) {
31381                        this.fireNetworkChange(netStat)
31382                    }
31383                })
31384                this.isPlayBackStarted = true;
31385            }
31386        },
31387
31388        playbackFailed: function (event_id, errorMessage, errorCode, fullErrorObject) {
31389            if (this.isPlayBackSelected && !(this.isPlayBackExitedBeforeStartByUser || this.isPlayBackExitedBeforeStartByApp) && !this.isPlayBackFailed) {
31390                let category = fullErrorObject && fullErrorObject.category ? fullErrorObject.category : null;
31391                // errorParams were re-mapped in NEWS-2415
31392                let errorParams = {
31393                    msgTriggeredBy: this.APPLICATION_NAME,
31394                    // application.error.errorMessage
31395                    appErrorMessage: errorMessage,
31396                    // application.error.clientErrorCode
31397                    appClientErrorCode: this.getShakaClientErrorCodeDescription(category),
31398                    // application.error.errorCode
31399                    appErrorCode: errorCode,
31400                    // application.error.errorExtras.nativeErrorCode
31401                    nativeErrorCode: errorCode,
31402                    // application.error.errorExtras.nativeErrorName
31403                    nativeErrorName: fullErrorObject.data ? fullErrorObject.data : fullErrorObject ? fullErrorObject : ''
31404                }
31405                if (event_id?.includes("Playback_Failure")) {
31406                    errorParams.appErrorType = "playback";
31407                }
31408
31409                window.Helix && window.Helix.track && window.Helix.track(event_id, errorParam
31409s)
31410                this.isPlayBackFailed = true;
31411            }
31412        },
31413
31414        playbackStop: function (event_id) {
31415            if ((this.isPlayBackStarted || this.isPlaybackStartedAfterRetry) && !this.isPlayBackFailed && !this.isPlaybackFailedBeforeRetry && !this.isPlaybackFailedAfterRetry && !this.isPlayBackStopped) {
31416                window.Helix && window.Helix.track && window.Helix.track(event_id, {
31417                    msgTriggeredBy: this.APPLICATION_NAME,
31418                })
31419                this.isPlayBackStopped = true;
31420                this.isPlayBackStarted = false;
31421                return true;
31422            }
31423            return false;
31424        },
31425
31426        playbackExitBeforeStartByUser: function (event_id) {
31427            if (!this.isPlayBackFailed && !this.isPlayBackExitedBeforeStartByApp) {
31428                window.Helix && window.Helix.track && window.Helix.track(event_id, {
31429                    msgTriggeredBy: this.APPLICATION_NAME
31430                });
31431                this.isPlayBackExitedBeforeStartByUser = true;
31432            }
31433        },
31434
31435        playbackExitBeforeStartByApp: function (event_id, code, message) {
31436            if (News.App.QuantumAnalytics.isPlayBackSelected && !this.isPlayBackFailed) {
31437                window.Helix && window.Helix.track && window.Helix.track(event_id, {
31438                    msgTriggeredBy: this.APPLICATION_NAME,
31439                    appErrorCode: code,
31440                    appErrorMessage: message
31441                });
31442                this.isPlayBackExitedBeforeStartByApp = true;
31443            }
31444        },
31445
31446        // Retry Tags
31447
31448        playbackFailureBeforeRetry: function (event_id, errorMessage, errorCode, fullErrorObject) {
31449            let category = fullErrorObject && fullErrorObject.category ? fullErrorObject.category : null;
31450            // errorParams were re-mapped in NEWS-2415
31451            window.Helix && window.Helix.track && window.Helix.track(event_id, {
31452                msgTriggeredBy: this.APPLICATION_NAME,
31453                // application.error.errorMessage
31454                appErrorMessage: errorMessage,
31455                // application.error.clientErrorCode
31456                appClientErrorCode: this.getShakaClientErrorCodeDescription(category),
31457                // application.error.errorCode
31458                appErrorCode: errorCode,
31459                // application.error.errorExtras.nativeErrorCode
31460                nativeErrorCode: errorCode,
31461                // application.error.errorExtras.nativeErrorName
31462                nativeErrorName: fullErrorObject.data ? fullErrorObject.data : ''
31463            });
31464            this.playbackAttemptRestart("SpectrumLocal_attemptRestart_retryCount", "playbackRestartSelected")
31465            this.isPlaybackFailedBeforeRetry = true;
31466        },
31467
31468        playbackFailureAfterRetry: function (event_id, errorMessage, errorCode, fullErrorObject) {
31469            let category = fullErrorObject && fullErrorObject.category ? fullErrorObject.category : null;
31470            // errorParams were re-mapped in NEWS-2415
31471            if (!this.isPlaybackFailedAfterRetry) {
31472                window.Helix && window.Helix.track && window.Helix.track(event_id, {
31473                    msgTriggeredBy: this.APPLICATION_NAME,
31474                    // application.error.errorMessage
31475                    appErrorMessage: errorMessage,
31476                    // application.error.clientErrorCode
31477                    appClientErrorCode: this.getShakaClientErrorCodeDescription(category),
31478                    // application.error.errorCode
31479                    appErrorCode: errorCode,
31480                    // application.error.errorExtras.nativeErrorCode
31481                    nativeErrorCode: errorCode,
31482                    // application.error.errorExtras.nativeErrorName
31483                    nativeErrorName: fullErrorObject.data ? fullErrorObject.data : ''
31484                });
31485            }
31486
31487            this.isPlaybackFailedAfterRetry = true;
31488        },
31489
31490        playbackAttemptRestart: function (event_id, restartType) {
31491            window.Helix && window.Helix.track && window.Helix.track(event_id, {
31492                opType: restartType
31493            });
31494            this.isPlaybackAttemptRestart = true;
31495        },
31496
31497        playbackExitBeforeStartRetryByUser: function (event_id) {
31498            if (!(this.isPlayBackFailed || this.isPlaybackFailedAfterRetry) && !this.isPlayBackExitedBeforeStartByApp) {
31499                window.Helix && window.Helix.track && window.Helix.track(event_id, {
31500                    plbkRetryAttempts: 1
31501                });
31502                this.isPlaybackExitBeforeStartRetryByUser = true
31503            }
31504        },
31505
31506        playbackStartRetrySuccess: function (event_id, bitRate) {
31507            if (this.isUriAcquired && !(this.isPlayBackExitedBeforeStartByUser || this.isPlayBackExitedBeforeStartByApp)) {
31508                window.Helix && window.Helix.track && window.Helix.track(event_id, {
31509                    msgTriggeredBy: this.APPLICATION_NAME,
31510                    plbkBtRtCurrBtRtBps: bitRate,
31511                    plbkRetryMethod: "daiEnabledExistingStream"  // TODO:: retry method to be dynamic
31512                })
31513                this.isPlaybackStartRetrySuccess = true;
31514                News.App.QuantumAnalytics.getNetworkStatus().then(netStat => {
31515                    if (this.networkStatus !== netStat) {
31516                        this.fireNetworkChange(netStat)
31517                    }
31518                })
31519            }
31520        },
31521
31522        playbackStartAfterRetry: function (event_id, bitRate) {
31523            if (this.isUriAcquired && !(this.isPlayBackExitedBeforeStartByUser || this.isPlayBackExitedBeforeStartByApp)) {
31524                window.Helix && window.Helix.track && window.Helix.track(event_id, {
31525                    msgTriggeredBy: this.APPLICATION_NAME,
31526                    plbkBtRtCurrBtRtBps: bitRate,
31527                })
31528                News.App.QuantumAnalytics.getNetworkStatus().then(netStat => {
31529                    if (this.networkStatus !== netStat) {
31530                        this.fireNetworkChange(netStat)
31531                    }
31532                })
31533                this.isPlaybackStartedAfterRetry = true;
31534                this.isPlaybackFailedBeforeRetry = false;
31535            }
31536        },
31537
31538        bufferStart: function (event_id) {
31539            if (window.Helix && window.Helix.get('currentState') === "playing") {
31540                if (this.isPlayBackStarted) {
31541                    window.Helix && window.Helix.track && window.Helix.track(event_id, {
31542                        msgTriggeredBy: this.APPLICATION_NAME,
31543                    })
31544                    this.isBufferStarted = true;
31545                }
31546            }
31547        },
31548
31549        bufferStop: function (event_id) {
31550            if (window.Helix && window.Helix.get('currentState') === "buffering") {
31551                if (this.isBufferStarted) {
31552                    window.Helix && window.Helix.track && window.Helix.track(event_id, {
31553                        msgTriggeredBy: this.APPLICATION_NAME,
31554                    })
31555                    this.isBufferStarted = false;
31556                }
31557            }
31558        },
31559
31560        playbackPause: function (event_id) {
31561            if (window.Helix && window.Helix.get('currentState') === "playing") {
31562                if (this.isPlayBackStarted && !this.isPlayBackStopped && !this.isPlayBackFailed && !this.isPlayBackPause && !this.isPlaybackFailedAfterRetry) {
31563                    window.Helix && window.Helix.track && window.Helix.track(event_id, {
31564                        msgTriggeredBy: this.APPLICATION_NAME,
31565                    })
31566                    this.isPlayBackPause = true;
31567                }
31568            }
31569        },
31570
31571        playbackUnPause: function (event_id) {
31572            if (window.Helix && window.Helix.get('currentState') === "paused") {
31573                if (this.isPlayBackPause) {
31574                    window.Helix && window.Helix.track && window.Helix.track(event_id, {
31575                        msgTriggeredBy: this.APPLICATION_NAME,
31576                    })
31577                    this.isPlayBackPause = false;
31578                }
31579            }
31580        },
31581
31582        playbackBitRateShift: function (event_id, bitrate) {
31583            // These event must comes after a playbackStart event
31584            let eventSent = false;
31585            if (this.isPlayBackStarted && !this.isPlaybackFailedAfterRetry && !this.isPlayBackFailed) {
31586                if (window.Helix && window.Helix.get('currentState') === "playing") {
31587                    window.Helix && window.Helix.track && window.Helix.track(event_id, {
31588                        msgTriggeredBy: this.APPLICATION_NAME,
31589                        plbkBtRtCurrBtRtBps: bitrate
31590                    })
31591                    eventSent = true;
31592                }
31593                this.isPlayBackPause = false;
31594            }
31595            return eventSent;
31596        },
31597
31598        playbackTrackChange_audioCodec: function (event_id, audioCodec, availableAudioTracks) {
31599            if (this.isPlayBackStarted) {
31600                // availableAudioTracks is expected as a comma-separated string per Quantum schema
31601                var tracksValue = Array.isArray(availableAudioTracks)
31602                    ? availableAudioTracks.join(',')
31603                    : (availableAudioTracks || '');
31604                window.Helix && window.Helix.track && window.Helix.track(event_id, {
31605                    audioCodec: audioCodec,
31606                    availableAudioTracks: tracksValue
31607                });
31608            }
31609        },
31610
31611        playbackFastForwardSelect: function (pos) {
31612            window.Helix && window.Helix.track && window.Helix.track("SpectrumLocal_user_selects_fastForward_clipVOD", {
31613                plbkTrickPlayScrubType: "fastForward"
31614            })
31615        },
31616
31617        playbackFastForwardDeSelect: function (pos) {
31618            window.Helix && window.Helix.track && window.Helix.track("SpectrumLocal_user_deselects_fastForward_clipVOD", {
31619                plbkTrickPlayScrubType: "fastForward",
31620                plbkTrickPlayScrubEndPosSec: Math.round(pos)
31621            })
31622        },
31623
31624        playbackFFEvents: function (startPos, endPos) {
31625            if (this.isPlayBackStarted) {
31626                this.playbackFastForwardSelect(startPos)
31627                this.playbackFastForwardDeSelect(endPos)
31628            }
31629        },
31630
31631
31632        playbackRewindSelect: function (pos) {
31633            window.Helix && window.Helix.track && window.Helix.track("SpectrumLocal_user_selects_rewind_clipVOD", {
31634                plbkTrickPlayScrubType: "rewind"
31635            })
31636        },
31637
31638        playbackRewindDeSelect: function (pos) {
31639            window.Helix && window.Helix.track && window.Helix.track("SpectrumLocal_user_deselects_rewind_clipVOD", {
31640                plbkTrickPlayScrubType: "rewind",
31641                plbkTrickPlayScrubEndPosSec: Math.round(pos)
31642            })
31643        },
31644
31645
31646        playbackRWEvents: function (startPos, endPos) {
31647            if (this.isPlayBackStarted) {
31648                this.playbackRewindSelect(startPos)
31649                this.playbackRewindDeSelect(endPos)
31650            }
31651        },
31652
31653        /**
31654         * used to set the cookie for the login resume event' cookies
31655         * @param cookieType
31656         * @returns
31657         */
31658        setQuantumLoginResumeCookie: function () {
31659            if (typeof Cookies.get("login-resume") === 'undefined' || Cookies.get("login-resume") === undefined) {
31660                this.cookieGeneral("login-resume");
31661            }
31662        },
31663
31664        cookieGeneral: function (aCookieName) {
31665            var expireDate = new Date(); //get current date/time
31666            expireDate.setDate(expireDate.getDate() + 60); //add 60 days to today
31667            expireDate = new Date(expireDate.getFullYear(), expireDate.getMonth(), 0, 23, 59, 59); //set to midnight
31668            Cookies.set(aCookieName, true, {expires: expireDate, path: '/'});
31669        },
31670
31671        /**
31672         * called from footer-scripts.html
31673         */
31674        checkQuantumLoginResume: function () {
31675            var isResume = Cookies.get('login-resume')
31676            if (!this.userConfigPostMVPFired) {
31677                if (isResume && isResume === "true") {
31678                    this.firesQuantumLoginStopSuccessResumeAuth();
31679                    Cookies.remove('login-resume')
31680                }
31681            }
31682        },
31683
31684        startTveLoginFlow: function (operationType) {
31685            var eventCaseId = 'NewsAgency_applicationActivity_startTveLoginFlow';
31686            if (window && window.Helix && window.Helix.track) {
31687                window.Helix && window.Helix.track && window.Helix.track(eventCaseId, {
31688                    msgTriggeredBy: this.APPLICATION_NAME,
31689                    opType: operationType
31690                    //opType        : "manualAuth"
31691                })
31692            }
31693        },
31694
31695        fireNetworkChange: function (netStatus) {
31696            this.connType = this.getConnectionType();
31697            // https://prism.spectruminternal.com/SpectrumLocal@Web/quantum-resources/event-cases/SpectrumLocal_connectionChange_networkStatusChange/video?source=client
31698            window.Helix && window.Helix.track && window.Helix.track('SpectrumLocal_connectionChange_networkStatusChange', {
31699                networkConnectType: this.connType,
31700                networkStatus: netStatus
31701            })
31702        },
31703
31704        // Behind the modem call
31705        behindTheModemCall: function () {
31706            let api = $('body').data('onplantapi');
31707            let startTime = new Date().getTime();
31708            return fetch(api, {
31709                method: 'GET',
31710                headers: {
31711                    'Content-Type': 'application/json',
31712                    'Accept': 'application/json'
31713                },
31714            }).then(response => {
31715                if (response.ok) {
31716                    News.App.QuantumAnalytics.quantumApiSuccessOrFailure(response.url, response.status, "All_Generic_API_Call_Success", startTime, "GET", "", "", response);
31717                    return response.json();
31718                } else {
31719                    News.App.QuantumAnalytics.extractFetchErrorMessage(response).then(responseText => {
31720                        News.App.QuantumAnalytics.quantumApiSuccessOrFailure(response.url, response.status, "All_Generic_API_Call_Failure", startTime, "GET", "", responseText, response);
31721                    })
31722                    return "unknown"
31723                }
31724            }).catch(error => {
31725                console.error(error)
31726            })
31727        },
31728
31729        getNetworkStatus: function () {
31730            return this.behindTheModemCall().then(data => {
31731                if (data && data.WrappedResponse) {
31732                    if (data.WrappedResponse.IsOnPlant) {
31733                        return "onNet"
31734                    } else return "offNet"
31735                } else {
31736                    return "unknown"
31737                }
31738            });
31739        },
31740
31741        getConnectionType: function () {
31742
31743            if (!window.navigator.onLine) {
31744                return 'offline';
31745            }
31746            if (window.navigator.connection) {
31747                const connectionType = window.navigator.connection.type;
31748                if (!connectionType) {
31749                    return 'unknown';
31750                }
31751                switch (connectionType) {
31752                    case 'ethernet':
31753                        return 'wired';
31754                    case 'cellular':
31755                        return 'cell';
31756                    case 'none':
31757                        return 'offline';
31758                    default:
31759                        return connectionType;
31760                }
31761            }
31762        },
31763
31764        // Ad Events
31765        adBreakStarted: function (adBreakNumber) {
31766            this.isPlayBackSelected && window.Helix && window.Helix.track && window.Helix.track('SpectrumLocal_adBreakStart', {
31767                adBreakNumber: adBreakNumber
31768            })
31769        },
31770
31771        adBreakEnded: function () {
31772            this.isPlayBackSelected && window.Helix && window.Helix.track && window.Helix.track('SpectrumLocal_adBreakStop')
31773        },
31774
31775        adStarted: function (adId, adNbr, adTitle) {
31776            this.isPlayBackSelected && window.Helix && window.Helix.track && window.Helix.track('SpectrumLocal_adStart', {
31777                adId: adId,
31778                adNbr: adNbr,
31779                adTitle: adTitle,
31780            })
31781        },
31782
31783        adEnded: function (adDurSec, adStoppedReason) {
31784            this.isPlayBackSelected && window.Helix && window.Helix.track && window.Helix.track('SpectrumLocal_adStop', {
31785                adDurSec: adDurSec,
31786                adStoppedReason: adStoppedReason
31787            })
31788        },
31789
31790        // NEWS-7558 - Detect browsers that do not support bitrate (ex: webview / Facebook on iOS)
31791        doesBrowserSupportBitrateTracking: function () {
31792            // on subsequent runs, use last value since browser / ios doesn't change
31793            if (this.browserSupportsBitrateTracking !== undefined) {
31794                return this.browserSupportsBitrateTracking
31795            }
31796
31797            function alertBitrateSupportAndQuantumId(browserSupportsBitrateTracking) {
31798                // Safari UK/WKWebView doesn't allow inspection, so adding a mechanism for QA to find bitrateSupport status and the Helix visitId by using a string in the URL
31799                if (window.location.href.indexOf('qabitratesupportalert=true') !== -1){
31800                    alert(`Browser supports bitrate tracking: ${browserSupportsBitrateTracking}. Helix visitId: ${window.Helix.get("visitId")}`);
31801                }
31802            }
31803            let result = bowser.getParser(navigator.userAgent).getResult();
31804            if (result.os.name.indexOf('iOS') !== -1) {
31805                // on iOS devices, these userAgent strings represent UI/WKWebView in-app browsers where bitrate tracking is not possible
31806                const facebookRegex = /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i;
31807                const instagramRegex = /(chromium|instagram)[\/ ]([-\w\.]+)/i;
31808                const chromeMobileIOSRegex = /(CriOS)\/(\d+)(?:\.(\d+)|)(?:\.(\d+)|)(?:\.(\d+)|)/
31809                if (facebookRegex.test(navigator.userAgent) || instagramRegex.test(navigator.userAgent) || chromeMobileIOSRegex.test(navigator.userAgent)) {
31810                    this.browserSupportsBitrateTracking = false;
31811                    alertBitrateSupportAndQuantumId(false);
31812                    return false;
31813                }
31814            } 
31815            if ((result.os.name.indexOf('macOS') !== -1 || result.os.name.indexOf('iOS') !== -1 ) && location.protocol === 'https:' && 'serviceWorker' in navigator !== true){
31816                // HLS bitrate cannot be determined via serviceWorker because the browser (UIWebView or WKWebView) doesn't allow it
31817                // This will weed out the Safari UI/WKWebView in iOS and Apple Mail in Mac OS X
31818                // serviceWorker functionality is only available in https, so we can only check when page is https
31819                this.browserSupportsBitrateTracking = false;
31820                alertBitrateSupportAndQuantumId(false);
31821                return false;
31822            } else {
31823                this.browserSupportsBitrateTracking = true;
31824                alertBitrateSupportAndQuantumId(true);
31825                return true;
31826            }
31827        },
31828
31829        getShakaClientErrorCodeDescription: function(category) {
31830            const mapFirstDigitToErrorType = {
31831                "1": "Network",
31832                "2": "Text",
31833                "3": "Media",
31834                "4": "Manifest",
31835                "5": "Streaming",
31836                "6": "DRM",
31837                "7": "Player",
31838                "8": "Cast",
31839                "9": "Storage",
31840                "10": "Ads"
31841            }
31842            if (category && mapFirstDigitToErrorType[`${category}`] ) {
31843                return mapFirstDigitToErrorType[`${category}`]
31844            } else {
31845                return 'Unknown'
31846            }
31847        },
31848
31849        sendCustomEvent: function(eventDetails) {
31850            window.Helix && window.Helix.track && window.Helix.track("generic_customEvent_video", eventDetails);
31851        }
31852
31853    };
31854
31855})(jQuery);
31856
31857(function ($) {
31858
31859    ns("News.App").MediaAnalytics = {
31860        STREAMPLAYHEAD: 0,
31861        IsPaused: false,
31862
31863        initMediaAnalyticsData: function (Player, data, playhead) {
31864            this.STREAMPLAYHEAD = Number.isInteger(playhead) ? parseInt(playhead) : 0;
31865            function getParams(data) {
31866                if (data.contentType === "Replay" || data.contentType === "Live") {
31867                    // hss live or vod
31868                    return {
31869                        "media.name": data.text,
31870                        "media.id": data.pid,
31871                        "media.length": data.length,
31872                        "media.contentType": data.contentType === "Replay" ? "vod" : "live", // Replay or Live
31873                        "media.playerName": data.playerName,
31874                        "media.channel": "High School Sports",
31875                        "media.network": data.mediaNetwork,
31876                        "analytics.trackingServer": "metrics.timewarnercable.com",
31877                        "analytics.reportSuite": window.s ? window.s.account : 'tsgnewsglobal1',
31878                        "visitor.marketingCloudOrgId": "5BB1123F5245AE4E0A490D45@AdobeOrg",
31879                        "visitor.marketingCloudUserId": window.s ? window.s.marketingCloudVisitorID : '',
31880                        "media.sdkVersion": "ma-api-0.0.0",
31881                        "analytics.enableSSL": true,
31882                    }
31883
31884                } else {
31885                    // vod and linear
31886                    return {
31887                        "media.playerName": Player.getVersion(),
31888                        "analytics.trackingServer": "metrics.timewarnercable.com",
31889                        "analytics.reportSuite": window.s ? window.s.account : 'tsgnewsglobal1',
31890                        "media.contentType": data.contentType,
31891                        "media.length": data.length,
31892                        "media.id": data.contentType === "linear" ? data.tmsid : data.pid,
31893                        "visitor.marketingCloudOrgId": "5BB1123F5245AE4E0A490D45@AdobeOrg",
31894                        "visitor.marketingCloudUserId": window.s ? window.s.marketingCloudVisitorID : '',
31895                        "media.name": data.text,
31896                        "media.channel": "",
31897                        "media.sdkVersion": "ma-api-0.0.0",
31898                        "analytics.enableSSL": true,
31899                    }
31900                }
31901            }
31902
31903            const params = getParams(data);
31904
31905            const analyticsData = {
31906                "playerTime": {
31907                    "playhead": Number.isInteger(playhead) ? parseInt(playhead) : 0,
31908                    "ts": +new Date()
31909                },
31910                "eventType": "sessionStart",
31911                "params": params,
31912                "qoeData": News.App.MediaAnalytics.qoeData(Player),
31913                "customMetadata": News.App.MediaAnalytics.customMetaData(data)
31914            }
31915
31916            var promise = News.App.MediaAnalytics.createSession('/api/v1/sessions', analyticsData);
31917            return promise.done(function (res, status, xhr) {
31918                return xhr.getResponseHeader('Location');
31919            })
31920        },
31921
31922        getMediaAnalyticsApi: function () {
31923            let mediaAnalyticsApi = $('body').data('mediaanalyticsapi');
31924            return mediaAnalyticsApi;
31925        },
31926
31927        createSession: function (path, data) {
31928            return $.post({
31929                url: News.App.MediaAnalytics.getMediaAnalyticsApi() + path,
31930                data: JSON.stringify(data),
31931            })
31932        },
31933
31934        triggerEvent: function (location, data, useBeacon) {
31935            if (!useBeacon){
31936                $.post({
31937                    url: News.App.MediaAnalytics.getMediaAnalyticsApi() + location + "/events",
31938                    data: JSON.stringify(data)
31939                })
31940            } else {
31941                const url = News.App.MediaAnalytics.getMediaAnalyticsApi() + location + "/events";
31942                const beaconData = JSON.stringify(data);
31943                navigator.sendBeacon(url, beaconData);
31944            }
31945        },
31946
31947        customMetaData: function (data) {
31948            if (data.contentType === "linear") {
31949                if(data.playerState && data.playerState === 'webMiniPlayer'){
31950                    return {
31951                    "mvpd": window.digitalData.user.mvpd,
31952                    "hhid": window.digitalData.user.hhid,
31953                    "platformName": "web",
31954                    "tmsID": data.tmsid,
31955                    "tmsSeriesId": data.tmsSeriesId,
31956                    "liveStreamStartMode" : data.liveStreamStartMode,
31957                    "network" : data.network,
31958                    "platformName" : 'web',
31959                    "playerState" : data.playerState
31960                    }
31961
31962                }
31963                return {
31964                    "mvpd": window.digitalData.user.mvpd,
31965                    "hhid": window.digitalData.user.hhid,
31966                    "platformName": "web",
31967                    "network" : data.network,
31968                    "tmsID": data.tmsid
31969                }
31970            } else if (data.contentType === "vod") {
31971                return {
31972                    "mvpd": window.digitalData.user.mvpd,
31973                    "hhid": window.digitalData.user.hhid,
31974                    "platformName": "web",
31975                    "streamType": "video",
31976                    "vodAuthType": data.authType,
31977                    "network": "Spectrum News: " + window.location.hostname
31978                }
31979            } else if (data.contentType === "Replay" || data.contentType === "Live") {
31980                return {
31981                    "streamType": data.contentType === "Replay" ? "vod" : "video",
31982                    "mvpd": window.digitalData.user.mvpd,
31983                    "hhid": window.digitalData.user.hhid,
31984                    "platformName": "web",
31985                    "assetSelectContext": data.contentType === "Live" ? "High School Sports-Live" : "High School Sports-Replay"
31986                }
31987            }
31988        },
31989
31990        playEvent: function (Player, time) {
31991            if (time === undefined) {
31992                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
31993            }
31994            return {
31995                "playerTime": {
31996                    "playhead": time,
31997                    "ts": +new Date()
31998                },
31999                "qoeData": News.App.MediaAnalytics.qoeData(Player),
32000                "eventType": "play"
32001            }
32002        },
32003
32004        pauseStart: function (Player, time) {
32005            News.App.MediaAnalytics.IsPaused = true;
32006            if (time === undefined) {
32007                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32008            }
32009            return {
32010                "playerTime": {
32011                    "playhead": time,
32012                    "ts": +new Date()
32013                },
32014                "qoeData": News.App.MediaAnalytics.qoeData(Player),
32015                "eventType": "pauseStart"
32016            };
32017        },
32018
32019        unPause: function (Player, time) {
32020            News.App.MediaAnalytics.IsPaused = false;
32021            if (time === undefined) {
32022                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32023            }
32024            return {
32025                "playerTime": {
32026                    "playhead": time,
32027                    "ts": +new Date()
32028                },
32029                "qoeData": News.App.MediaAnalytics.qoeData(Player),
32030                "eventType": "play"
32031            }
32032        },
32033
32034        playbackMuteStart: function (time) {
32035            console.log('playbackMuteStart')
32036            if (time === undefined) {
32037                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32038            }
32039            return {
32040                "playerTime": {
32041                    "playhead": time,
32042                    "ts": +new Date()
32043                },
32044                "eventType": "stateStart",
32045                "params": {
32046                    "media.state.name": "mute"
32047                }
32048            }
32049        },
32050
32051        playbackMuteEnd: function (time) {
32052            console.log('playbackMuteEnd')
32053            if (time === undefined) {
32054                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32055            }
32056            return {
32057                "playerTime": {
32058                    "playhead": time,
32059                    "ts": +new Date()
32060                },
32061                "eventType": "stateEnd",
32062                "params": {
32063                    "media.state.name": "mute"
32064                }
32065            }
32066        },
32067
32068        miniPlayerStart: function (time) {
32069            News.App.MediaAnalytics.isMiniPlayerStarted = true;
32070            if (time === undefined) {
32071                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32072            }
32073            return {
32074                "playerTime": {
32075                    "playhead": time,
32076                    "ts": +new Date()
32077                },
32078                "eventType": "stateStart",
32079                "params": {
32080                    "media.state.name": "miniplayer"
32081                }
32082            }
32083        },
32084
32085        miniPlayerStop: function (time) {
32086            News.App.MediaAnalytics.isMiniPlayerStarted = false;
32087            if (time === undefined) {
32088                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32089            }
32090            return {
32091                "playerTime": {
32092                    "playhead": time,
32093                    "ts": +new Date()
32094                },
32095                "eventType": "stateEnd",
32096                "params": {
32097                    "media.state.name": "miniplayer"
32098                }
32099            }
32100        },
32101        fullscreenStart: function (time) {
32102            News.App.MediaAnalytics.isfullscreenStarted = true;
32103            if (time === undefined) {
32104                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32105            }
32106            return {
32107                "playerTime": {
32108                    "playhead": time,
32109                    "ts": +new Date()
32110                },
32111                "eventType": "stateStart",
32112                "params": {
32113                    "media.state.name": "fullscreen"
32114                }
32115            }
32116        },
32117
32118        fullscreenStop: function (time) {
32119            News.App.MediaAnalytics.isfullscreenStarted = false;
32120            if (time === undefined) {
32121                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32122            }
32123            return {
32124                "playerTime": {
32125                    "playhead": time,
32126                    "ts": +new Date()
32127                },
32128                "eventType": "stateEnd",
32129                "params": {
32130                    "media.state.name": "fullscreen"
32131                }
32132            }
32133        },
32134
32135        miniPlayerUnmutedStart: function(time) {
32136            console.log('miniPlayerUnmutedStart')
32137            News.App.MediaAnalytics.isMiniPlayerPlaybackUnmuted = true;
32138            if (time === undefined) {
32139                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32140            }
32141            return {
32142                "playerTime": {
32143                    "playhead": time,
32144                    "ts": +new Date()
32145                },
32146                "eventType": "stateStart",
32147                "params": {
32148                    "media.state.name": "miniPlayerUnmute"
32149                }
32150            }
32151        },
32152
32153        miniPlayerUnmutedEnd: function(time) {
32154            console.log('miniPlayerUnmutedEnd')
32155            News.App.MediaAnalytics.isMiniPlayerPlaybackUnmuted = false;
32156            if (time === undefined) {
32157                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32158            }
32159            return {
32160                "playerTime": {
32161                    "playhead": time,
32162                    "ts": +new Date()
32163                },
32164                "eventType": "stateEnd",
32165                "params": {
32166                    "media.state.name": "miniPlayerUnmute"
32167                }
32168            }
32169        },
32170
32171        playBackFinished: function (Player, time) {
32172            if (time === undefined) {
32173                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32174            }
32175            return {
32176                "playerTime": {
32177                    "playhead": time,
32178                    "ts": +new Date()
32179                },
32180                "qoeData": News.App.MediaAnalytics.qoeData(Player),
32181                "eventType": "sessionComplete"
32182            }
32183        },
32184
32185        mediaPing: function (Player, time) {
32186            if (time === undefined) {
32187                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32188            }
32189            return {
32190                "playerTime": {
32191                    "playhead": time,
32192                    "ts": +new Date()
32193                },
32194                "qoeData": News.App.MediaAnalytics.qoeData(Player),
32195                "eventType": "ping"
32196            }
32197        },
32198
32199        bufferStart: function (Player, time) {
32200            if (time === undefined) {
32201                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32202            }
32203            return {
32204                "playerTime": {
32205                    "playhead": time,
32206                    "ts": +new Date()
32207                },
32208                "qoeData": News.App.MediaAnalytics.qoeData(Player),
32209                "eventType": "bufferStart"
32210            };
32211        },
32212        sessionEnd: function (Player, time) {
32213            if (time === undefined) {
32214                time = News.App.MediaAnalytics.STREAMPLAYHEAD;
32215            }
32216            return {
32217                "playerTime": {
32218                    "playhead": time,
32219                    "ts": +new Date()
32220                },
32221                "qoeData": News.App.MediaAnalytics.qoeData(Player),
32222                "eventType": "sessionEnd"
32223            }
32224        },
32225
32226        adBreakStart: function (Player) {
32227            return {
32228                "playerTime": {
32229                    "playhead": 0,
32230                    "ts": +new Date()
32231                },
32232                "eventType": "adBreakStart",
32233                "params": {
32234                    "media.ad.podFriendlyName": "pre-roll",
32235                    "media.ad.podIndex": 1,
32236                    "media.ad.podSecond": 0
32237                },
32238                "qoeData": News.App.MediaAnalytics.qoeData(Player),
32239            }
32240        },
32241
32242        adStart: function (Player) {
32243            return {
32244                "playerTime": {
32245                    "playhead": 0,
32246                    "ts": +new Date()
32247                },
32248                "eventType": "adStart",
32249                "params": {
32250                    "media.ad.name": "pre-roll",
32251                    "media.ad.id": "pre-roll",
32252                    "media.ad.length": 0,
32253                    "media.ad.podPosition": 1,
32254                    "media.ad.playerName": "bitmovin " + Player.bitmovinVersion
32255                },
32256                "qoeData": News.App.MediaAnalytics.qoeData(Player),
32257            }
32258        },
32259
32260        adFinished: function (Player) {
32261            return {
32262                "playerTime": {
32263                    "playhead": 0,
32264                    "ts": +new Date()
32265                },
32266                "eventType": "adComplete",
32267                "qoeData": News.App.MediaAnalytics.qoeData(Player),
32268            }
32269        },
32270        adBreakFinished: function (Player) {
32271            return {
32272                "playerTime": {
32273                    "playhead": 0,
32274                    "ts": +new Date()
32275                },
32276                "eventType": "adBreakComplete",
32277                "qoeData": News.App.MediaAnalytics.qoeData(Player),
32278            }
32279        },
32280
32281        qoeData: function (Player) {
32282            let metrics = {};
32283            if (Player) {
32284                metrics = Player.getPlayerMetrics();
32285            }
32286            if (!metrics) {
32287                console.debug("currentMetrics are unavailable for player")
32288            }
32289            if (metrics.videoBitrate === 0 || metrics.videoBitrate === undefined || metrics.videoBitrate === null) {
32290                metrics.videoBitrate === 0;
32291                if (window?.shakaPlayerAdapter?.bitrate?.getFirstSegmentBitrate()) {
32292                    // for HLS, Shaka player metrics does not have the videoBitrate. Instead, service worker will provide bitrate by parsing the manifest file.
32293                    metrics.videoBitrate = window.shakaPlayerAdapter.bitrate.getFirstSegmentBitrate();
32294                    console.debug('metrics.videoBitrate was 0, using shakaPlayerAdapter.bitrate.getFirstSegmentBitrate() value: ' + metrics.videoBitrate);
32295                } else if (metrics.streamBandwidth) {
32296                    metrics.videoBitrate = metrics.streamBandwidth
32297                    console.debug('metrics.videoBitrate was 0, using metrics.streamBandwidth value: ' + metrics.videoBitrate);
32298                } else {
32299                    console.debug('metrics.videoBitrate was 0 and no other bitrate value was available for Adobe Media Analytics qoe');
32300                }
32301            }
32302
32303            let framesPerSecond = Math.round(metrics.videoFrameRate) || 0,
32304                timeToStart = Math.round(metrics.liveLatency) || 0,
32305                droppedFrames = metrics.droppedFrames || 0
32306            return {
32307                "media.qoe.droppedFrames": droppedFrames, // value returned from player ex. 15
32308                "media.qoe.timeToStart": timeToStart, // value returned from player ex. 5
32309                "media.qoe.framesPerSecond": framesPerSecond, // value returned from player ex. 40
32310                "media.qoe.bitrate": metrics.videoBitrate, // value returned from player ex. 1600
32311            }
32312        },
32313
32314        streamPingInterval: function (Player, location) {
32315            //set interval to track how long stream has been watched
32316            //store value in this.streamPlayhead
32317            if (!this.streamInterval) {
32318
32319                this.streamInterval = setInterval(function () {
32320                    ++News.App.MediaAnalytics.STREAMPLAYHEAD;
32321                }, 1000);
32322            }
32323            if (!this.mediaInterval) {
32324                this.mediaInterval = setInterval(function () {
32325                    News.App.MediaAnalytics.triggerEvent(location, News.App.MediaAnalytics.mediaPing(Player));
32326                }, 10000);
32327            }
32328        },
32329
32330        vodPingInterval: function (Player, location) {
32331            if (!this.mediaInterval) {
32332                this.mediaInterval = setInterval(function () {
32333                    News.App.MediaAnalytics.triggerEvent(location, News.App.MediaAnalytics.mediaPing(Player, Math.round(Player.lastCurrentTime)));
32334                }, 10000);
32335            }
32336
32337        },
32338
32339        pausePingInterval: function (Player, location) {
32340            if (!this.pauseInterval) {
32341                this.pauseInterval = setInterval(function () {
32342                    News.App.MediaAnalytics.triggerEvent(location, News.App.MediaAnalytics.mediaPing(Player, Math.round(Player.lastCurrentTime)));
32343                }, 10000);
32344            }
32345        },
32346
32347        bufferingPingInterval: function (Player, location) {
32348            if (!this.bufferInterval) {
32349                this.bufferInterval = setInterval(function () {
32350                    News.App.MediaAnalytics.triggerEvent(location, News.App.MediaAnalytics.mediaPing(Player, Math.round(Player.lastCurrentTime)));
32351                }, 10000);
32352            }
32353        },
32354
32355        adPing: function () {
32356            return {
32357                "playerTime": {
32358                    "playhead": 0,
32359                    "ts": +new Date()
32360                },
32361                "eventType": "ping"
32362            }
32363        },
32364
32365        adPingInterval: function (location) {
32366            this.adInterval = setInterval(function () {
32367                News.App.MediaAnalytics.triggerEvent(location, News.App.MediaAnalytics.adPing())
32368            }, 1000);
32369        },
32370
32371        clearAdPingInterval: function () {
32372            if (this.adInterval) {
32373                clearInterval(this.adInterval);
32374                this.adInterval = null;
32375            }
32376        },
32377
32378        clearMediaPingInterval: function () {
32379            if (this.mediaInterval) {
32380                clearInterval(this.mediaInterval);
32381                this.mediaInterval = null;
32382            }
32383        },
32384
32385        clearStreamPlayheadPingInterval: function () {
32386            if (this.streamInterval) {
32387                clearInterval(this.streamInterval);
32388                this.streamInterval = null;
32389            }
32390        },
32391
32392        clearBufferPingInterval: function () {
32393            if (this.bufferInterval) {
32394                clearInterval(this.bufferInterval);
32395                this.bufferInterval = null;
32396            }
32397        },
32398
32399        clearPausePingInterval: function () {
32400            if (this.pauseInterval) {
32401                clearInterval(this.pauseInterval);
32402                this.pauseInterval = null;
32403            }
32404        }
32405
32406    }
32407})(jQuery);
32408
32409$(function () {
32410   var pdfHostname = $('.body-container').data('pdfhost');
32411   var pdfPathname = $('.body-container').data('pdfpath');
32412   if (pdfPathname && pdfHostname) {
32413      $('.embedpdf').each(function (index, value) {
32414         $(this).hide();
32415         var currentElement = $(this);
32416         var pdfPath = $(this).find('iframe').attr('src');
32417         var pdfDocTitle = $(this).find('iframe').attr('alt');
32418         setTimeout(function () {
32419            if (pdfPath) {
32420               pdfPath = pdfPath.replace('#toolbar=0&navpanes=0', '');
32421               var serverUrl = pdfHostname + pdfPathname + "?file=" + pdfPath+"&title="+pdfDocTitle;
32422               var pdfElement = '<div class="embed-' + index + '" ><iframe src="' + serverUrl + '" allowfullscreen="allowfullscreen"></div>';
32423               currentElement.find('iframe').replaceWith(pdfElement);
32424            }
32425            currentElement.show();
32426         }, 500);
32427      });
32428   }
32429
32430}
32430);
32431
32432+function ($) {
32433
32434    let noticiasRegion = $('.site-header .header-ele').data('noticias-region');
32435
32436    if (noticiasRegion) {        
32437
32438        // Constants for Spanish translations
32439        const CONSTANTS = { 
32440            SEARCH_PLACEHOLDER: 'Buscar',
32441            LIVE_NOW: 'EN VIVO',
32442            CURRENTLY_PLAYING: 'REPRODUCIENDO ACTUALMENTE',
32443            ALL_SPECTRUM_NEWS_CHANNELS: 'TODOS LOS CANALES DE SPECTRUM NEWS',
32444            MOBILEACCOUNT: 'CUENTA',
32445            SOCIAL_SHARE: 'COMPARTIR',
32446            SUBMIT_EVENT:{
32447                EVENT_CALENDAR:{
32448                    MON: 'Lu',
32449                    TUE: 'Ma',
32450                    WED: 'Mi',
32451                    THU: 'Ju',
32452                    FRI: 'Vi',
32453                    SAT: 'Sà',
32454                    SUN: 'Do'
32455                },
32456                LIMIT: '65',
32457                SUBMIT_BTN: 'ENVIAR EVENTO DEL CALENDARIO',
32458                SUBMIT_BTN_CAL: 'ENVIAR EVENTO DEL CALENDARIO',
32459                EVENT_HEAD: 'Enviar evento',
32460                EVENT_INFO: 'Información del evento',
32461                CONT_INFO: 'Información de contacto',                
32462                EVENT_FORM: {
32463                    NAME: 'Nombre del evento *',
32464                    URL: 'URL del evento',
32465                    LOCATION: 'Vecindario *',
32466                    EVENT_TYPE: 'Tipo de evento *',                    
32467                    START_DATE: 'Fecha de inicio del evento *',
32468                    END_DATE: 'Fecha de finalización del evento *',
32469                    START_TIME: 'Hora de inicio del evento *',
32470                    END_TIME: 'Hora de finalización del evento *',
32471                    COST: 'Costo',
32472                    COST_RANGE: 'Rango de costos',
32473                    DESCRIPTION: 'Descripción del evento *',
32474                    VENUE: 'Nombre del lugar *',
32475                    VENUE_STREET: 'Nombre y número de la calle del lugar *',
32476                    VENUE_CITY:  'Ciudad/Vecindario del lugar *',
32477                    ZIPCODE: 'Código postal',
32478                    CONTACT_NAME: 'Nombre del contacto',
32479                    CONTACT_EMAIL: 'Correo electrónico del contacto',
32480                    CONTACT_PHONE: 'Número de teléfono del contacto',
32481                    VALIDATION_MESSAGE: 'Completa este campo' ,
32482                    REQUIRED: '* Obligatorio',                    
32483                    CHAR_LIMIT: (limit)=>{
32484                        return `Máximo ${limit} caracteres`
32485                    },
32486                    COST_VALIDATION: '* Se requiere el costo o el rango de costos',
32487                    FREQUENCY_OPTIONS: ['Frecuencia del evento', 'Semanal', 'Mensual'],
32488                    OR_LABEL: 'O',
32489                    COST_OPTION_FREE: 'Gratis',
32490                    CONTACT_INFO:`La información no se mostrará en la página del evento, pero nos brindará detalles sobre la mejor manera de comunicarnos con su organización.`,
32491                    REPEAT: 'Repetir cada',
32492                    MONTH: 'Mes',
32493                    DATEPICKER_PLACEHOLDER: 'dd/mm/yyyy'
32494                }
32495            }
32496            
32497        }
32498
32499        //Search placeholder - spanish changes
32500        $('.searchNav .empire-header-search-field').each(function () {
32501            $(this).attr('placeholder', CONSTANTS.SEARCH_PLACEHOLDER);
32502        })
32503
32504        //Watch Live component - spanish changes
32505        $('.live-tv .watch-live-card-container').each(function () {
32506            $(this).find('.live-status').text(CONSTANTS.LIVE_NOW);
32507            $(this).find('.currently-playing').text(CONSTANTS.CURRENTLY_PLAYING);
32508            $(this).find('.card-container h2').text(CONSTANTS.ALL_SPECTRUM_NEWS_CHANNELS);
32509        });
32510
32511        // Live Stream Promo component - spanish changes
32512        $('.live-stream-promo--container .live-stream-right-block').each(function () {
32513            $(this).find('.live-badge-text').text(CONSTANTS.LIVE_NOW);
32514        });
32515
32516        //Mini Live Player - spanish changes
32517        $('.live-tv.live-stream-promo--container.mini-player').each(function () {
32518            $(this).find('.show-when-authenticated.live-badge .live-badge-text').text(CONSTANTS.LIVE_NOW);
32519            $(this).find('.live-stream-right-block .live-badge .live-badge-text').text(CONSTANTS.LIVE_NOW);
32520            $(this).find('.mini-player-fallback__live-badge-text').text(CONSTANTS.LIVE_NOW);
32521            $(this).find('.mini-player-fallback__default-live-badge-text').text(CONSTANTS.LIVE_NOW);
32522        });
32523
32524        //Mobile Menu - spanish changes
32525        document.querySelectorAll('.empire-mobile-item-list .my-account').forEach(element =>{
32526            element.innerText = CONSTANTS.MOBILEACCOUNT
32527        })
32528        // Submit Event
32529        let eventForm = $('.event-submit-form');
32530            eventHead = $('.section-header-inner')[0],
32531            eventInfo = $('.event-info'),
32532            contactInfo = $('.contact-info');            
32533
32534        if (eventForm.length > 0) {
32535            $('#weeklyInput .checkbox .control-label span').each((index, value)=>{                
32536                value.innerText = Object.values(CONSTANTS.SUBMIT_EVENT.EVENT_CALENDAR)[index];            
32537            });  
32538
32539            eventHead.outerText == 'SUBMIT EVENT' ? eventHead.innerText = CONSTANTS.SUBMIT_EVENT.EVENT_HEAD : '';
32540            eventInfo.find('label')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_INFO;
32541            contactInfo.find('label')[0].innerText = CONSTANTS.SUBMIT_EVENT.CONT_INFO;
32542            eventForm.find('.btn')[0].value = CONSTANTS.SUBMIT_EVENT.SUBMIT_BTN;
32543
32544            !!$('#eventName')? $('#eventName').attr('placeholder', CONSTANTS.SUBMIT_EVENT.EVENT_FORM.NAME) : '';
32545            !!$('#eventUrl') ? $('#eventUrl').attr('placeholder', CONSTANTS.SUBMIT_EVENT.EVENT_FORM.URL) : '';
32546            !!$('#location')[0] ? $('#location')[0][0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.LOCATION : '';
32547            !!$('#location')[0] ? $('#location')[0].title = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.LOCATION : '';
32548            !!$('#eventType')[0] ? $('#eventType')[0][0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.EVENT_TYPE : '';
32549            !!$('#eventType')[0] ? $('#eventType')[0].title = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.EVENT_TYPE : '';
32550            !!$('#repeat option') ? $('#repeat option').each((index, value)=> value.innerText =  CONSTANTS.SUBMIT_EVENT.EVENT_FORM.FREQUENCY_OPTIONS[index]) : '';
32551            !!$('#repeat')[0] ? $('#repeat')[0].title = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.FREQUENCY_OPTIONS[0] : '';
32552            !!$('.start-date label')[0] ? $('.start-date label')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.START_DATE : '';
32553            !!$('.end-date label')[0] ? $('.end-date label')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.END_DATE : '';
32554            !!$('.start-time label')[0] ? $('.start-time label')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.START_TIME : '';
32555            !!$('.end-time label')[0] ? $('.end-time label')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.END_TIME : '';
32556            !!$('#costDefined') ? $('#costDefined').attr('placeholder', CONSTANTS.SUBMIT_EVENT.EVENT_FORM.COST) : '';
32557            !!$('.control-label[for="cost"]')[0] ? $('.control-label[for="cost"]')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.OR_LABEL : '';
32558            !!$('#cost')[0] ? $('#cost')[0][0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.COST_RANGE : '';
32559            !!$('#cost')[0] ? $('#cost')[0][1].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.COST_OPTION_FREE: '';
32560            !!$('#cost')[0] ? $('#cost')[0].title = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.COST_RANGE : '';
32561            !!$('#description') ? $('#description').attr('placeholder', CONSTANTS.SUBMIT_EVENT.EVENT_FORM.DESCRIPTION) : '';
32562            !!$('#venueName') ? $('#venueName').attr('placeholder', CONSTANTS.SUBMIT_EVENT.EVENT_FORM.VENUE) : '';
32563            !!$('#street') ? $('#street').attr('placeholder', CONSTANTS.SUBMIT_EVENT.EVENT_FORM.VENUE_STREET): '';
32564            !!$('#city') ? $('#city').attr('placeholder', CONSTANTS.SUBMIT_EVENT.EVENT_FORM.VENUE_CITY) : '';
32565            !!$('#zipcode') ? $('#zipcode').attr('placeholder', CONSTANTS.SUBMIT_EVENT.EVENT_FORM.ZIPCODE): '';
32566            !!$('#name') ? $('#name').attr('placeholder', CONSTANTS.SUBMIT_EVENT.EVENT_FORM.CONTACT_NAME): '';
32567            !!$('#email') ? $('#email').attr('placeholder', CONSTANTS.SUBMIT_EVENT.EVENT_FORM.CONTACT_EMAIL) : '';
32568            !!$('#phoneNumber') ? $('#phoneNumber').attr('placeholder', CONSTANTS.SUBMIT_EVENT.EVENT_FORM.CONTACT_PHONE) :'';
32569            !!$('.event-info .help-block')[0] ? $('.event-info .help-block')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.REQUIRED:'';
32570            !!$('.cost-validation')[0] ? $('.cost-validation')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.COST_VALIDATION : '';
32571            !!$('.contact-info .help-block')[0] ? $('.contact-info .help-block')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.CONTACT_INFO : '';
32572            !!$('#eventSubmissionUrl')[0] ? $('#eventSubmissionUrl')[0].innerText = CONSTANTS.SUBMIT_EVENT.SUBMIT_BTN_CAL : '';
32573            !!$('.share-text')[0] ? $('.share-text')[0].innerText = CONSTANTS.SOCIAL_SHARE : '';
32574            !!$('.event-name .help-block')[0] ? $('.event-name .help-block')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.CHAR_LIMIT('65') : '';
32575            !!$('.description .help-block')[0] ? $('.description .help-block')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.CHAR_LIMIT('300') : '';
32576            !!$('.venue-name .help-block')[0] ? $('.venue-name .help-block')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.CHAR_LIMIT('65') : '';
32577            !!$('.street .help-block')[0] ? $('.street .help-block')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.CHAR_LIMIT('32') : '';
32578            !!$('.city .help-block')[0] ? $('.city .help-block')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.CHAR_LIMIT('32') : '';                        
32579            !!$('#weeklyInput') ? $('#weeklyInput .label-first')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.REPEAT : '';
32580            !!$('#monthlyInput') ? $('#monthlyInput .label-first')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.REPEAT : '';
32581            !!$('#monthlyInput') ? $('#monthlyInput .label-last')[0].innerText = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.MONTH : '';
32582            $('.datepicker-field').each((index,value)=>{
32583                value.placeholder = CONSTANTS.SUBMIT_EVENT.EVENT_FORM.DATEPICKER_PLACEHOLDER
32584            });
32585        }
32586    }
32587
32588    if (!isAuthorMode()) {
32589        // Check if the host is for spectrumnoticias domain
32590        if (window.location.host.includes('spectrumnoticias')) {
32591            const searchParams = new URLSearchParams(window.location.search);
32592            const overrideLang = searchParams.get('lang');
32593            if (overrideLang === 'en') {
32594                // With lang=en param on spectrumnoticias domain, hide #es-404 and keep #en-404
32595                $('#es-404').hide();
32596            } else {
32597                // Without lang=en param on spectrumnoticias, keep #es-404 and hide #en-404
32598                $('#en-404').hide();
32599            }
32600           
32601        } else {
32602            //Hide Spanish 404 content for non-spectrumnoticias hosts
32603            $('#es-404').hide();
32604        }
32605    }
32606
32607    function isAuthorMode() {
32608        if (typeof CQ != "undefined") {
32609            if (CQ && CQ.WCM && CQ.WCM.isEditMode) {
32610                return CQ.WCM.isEditMode('True')
32611            }
32612        }
32613    }
32614
32615}(jQuery);
32616(function ($) {
32617    "use strict";
32618
32619    // EXIT IF NOT IN WCM MODE
32620    if (!window.CQ || !CQ.WCM) return;
32621
32622    // CONSTANTS
32623    var LOCK_PROPERTY = "isColumnLocked";
32624    var SERVLET_URL = "/services/columnlock/state";
32625
32626    var LOCKABLE_COMPONENTS = [
32627        ".row.news-column-control[data-path]"
32628    ];
32629
32630    var COMBINED_SELECTOR = LOCKABLE_COMPONENTS.join(", ");
32631
32632
32633    var LOCKABLE_BUTTON_TEXTS = ["Edit", "Delete"];
32634
32635    /**
32636     * Walk the EditBar toolbar items and disable/enable buttons whose
32637     * text matches LOCKABLE_BUTTON_TEXTS
32638     */
32639    function setEditBarButtonStates(editbar, locked) {
32640        if (!editbar || !editbar.items) return;
32641        // EditBar items[0] is the CQ.Ext.Toolbar
32642        var tbar = editbar.items.get(0);
32643        if (!tbar || !tbar.items) return;
32644
32645        tbar.items.each(function (item) {
32646            if (!item || typeof item.getText !== "function") return;
32647            var txt = (item.getText() || "").replace(/<[^>]*>/g, "").trim();
32648            if (LOCKABLE_BUTTON_TEXTS.indexOf(txt) !== -1) {
32649                if (locked) {
32650                    item.disable();
32651                } else {
32652                    item.enable();
32653                }
32654            }
32655        });
32656    }
32657
32658    /**
32659     * Disable/enable the physical drag handle on the EditBar.
32660     */
32661    function setEditBarDrag(editbar, locked) {
32662        if (!editbar) return;
32663        if (locked) {
32664            if (typeof editbar.disableDrag === "function") {
32665                editbar.disableDrag();
32666            }
32667        } else {
32668            if (typeof editbar.enableDrag === "function") {
32669                editbar.enableDrag();
32670            }
32671        }
32672    }
32673
32674    /**
32675     * Disable/enable the drop targets on the EditBar so nothing can
32676     * be dropped into a locked column control.
32677     */
32678    function setEditBarDropTargets(editbar, locked) {
32679        if (!editbar) return;
32680        if (locked) {
32681            if (typeof editbar.suspendDropTargets === "function") {
32682                editbar.suspendDropTargets();
32683            }
32684        } else {
32685            if (typeof editbar.resumeDropTargets === "function") {
32686                editbar.resumeDropTargets();
32687            }
32688        }
32689    }
32690
32691    /**
32692     * Apply or remove all OOTB-API-based restrictions on the EditBar
32693     * that corresponds to the given row's column control.
32694     * Resolves the EditBar via CQ.WCM.getEditable(path).
32695     */
32696    function applyEditBarRestrictions($row, locked) {
32697        var fullPath = $row.data("path");
32698        if (!fullPath) return;
32699
32700        // Resolve the EditBar instance
32701        // CQ.WCM.getEditable(path) returns the EditBar/EditRollover for that path.
32702        var editbar = CQ.WCM.getEditable(fullPath);
32703        if (!editbar) return;
32704
32705        setEditBarButtonStates(editbar, locked);
32706        setEditBarDrag(editbar, locked);
32707        setEditBarDropTargets(editbar, locked);
32708    }
32709
32710    // -------------------------------------------------------------------------
32711    // CHILD EDITBARS — find all child .cq-editbar elements that belong to
32712    // this column control using the CSS class prefix pattern.
32713    //
32714    // From the real HTML:
32715    //   Parent class : cq-element-main-content-area_47columns_47column0_47columns_95527713850
32716    //   Child classes: cq-element-main-content-area_47columns_47column0_47columns_95527713850_47column0_47content_95list_95547414340
32717    //                  cq-element-main-content-area_47columns_47column0_47columns_95527713850_47column1_47content_95list_951946654155
32718    //                  cq-element-main-content-area_47columns_47column0_47columns_95527713850_47column2_47content_95list
32719    //                  cq-element-main-content-area_47columns_47column0_47columns_95527713850_47column3_47campaign
32720    //
32721    // Every child class starts with the parent class + "_47" ("_47" = encoded "/").
32722    // -------------------------------------------------------------------------
32723
32724    /**
32725     * Given the parent column control's $editbar DOM element, return a jQuery
32726     * object of all child .cq-editbar elements on the page whose cq-element-*
32727     * class starts with the parent's cq-element-* class + "_47".
32728     */
32729    function findChildEditbars($parentEditbar) {
32730        if (!$parentEditbar || !$parentEditbar.length) return $();
32731
32732        // Extract the value after "cq-element-" from the parent editbar's class
32733        var parentClasses = $parentEditbar.attr("class") || "";
32734        var m = parentClasses.match(/cq-element-(\S+)/);
32735        if (!m) return $();
32736
32737        var parentElementClass = m[1];
32738        // Every child's cq-element-* class starts with this prefix
32739        var childPrefix = parentElementClass + "_47";
32740
32741        return $(".cq-editbar").filter(function () {
32742            var cls = $(this).attr("class") || "";
32743            var cm = cls.match(/cq-element-(\S+)/);
32744            if (!cm) return false;
32745            return cm[1].indexOf(childPrefix) === 0;
32746        });
32747    }
32748
32749
32750    /**
32751     * Find the cq-editbar DOM element for a given row using the placeholder
32752     * CSS class pattern. This is the existing approach kept unchanged.
32753     */
32754    function findEditbarForRow($row) {
32755        var $ph = $row.find('[class*="cq-placeholder-main-content-area"]').first();
32756        if (!$ph.length) return null;
32757
32758        var match = $ph.attr("class").match(/(main-content-area(?:_[^_]+)*_47columns(?:_\d+)?)_47column[^_]*$/);
32759        if (!match) return null;
32760
32761        var targetClass = "cq-element-" + match[1];
32762        var $editbar = $(".cq-editbar." + targetClass);
32763        return $editbar.length ? $editbar : null;
32764    }
32765
32766    // -------------------------------------------------------------------------
32767    // button disable/enable (kept as fallback for
32768    // cases where the OOTB EditBar instance is not yet available on the page)
32769    // -------------------------------------------------------------------------
32770
32771    function updateButtonStates(locked, $editbar) {
32772        if (!$editbar || !$editbar.length) return;
32773
32774        var buttons = $editbar.find("button.x-btn-text").filter(function () {
32775            var text = $(this).text().trim();
32776            return text === "Edit" || text === "Delete";
32777        });
32778
32779        buttons.each(function () {
32780            var $b = $(this);
32781            var $table = $b.closest("table.x-btn");
32782            if (locked) {
32783                $table.addClass("x-item-disabled");
32784                $b.prop("disabled", true);
32785            } else {
32786                $table.removeClass("x-item-disabled");
32787                $b.prop("disabled", false);
32788            }
32789        });
32790
32791
32792    }
32793
32794    function updateLockBtnUI($btnEl, locked) {
32795        if (locked) {
32796            $btnEl.text("Unlock").css({
32797                "color": "#d00",
32798                "font-weight": "bold"
32799            });
32800        } else {
32801            $btnEl.text("Lock").css({
32802                "color": "#d00",
32803                "font-weight": "bold"
32804            });
32805        }
32806    }
32807
32808
32809    // Add lock button to row
32810    function addLockButton($row, $parentColumn) {
32811        // AVOID DUPLICATES
32812        if ($row.data("lock-added")) return;
32813
32814        // VERIFY THIS IS A COLUMNS ROW
32815        var fullPath = $row.data("path");
32816        if (!fullPath || !fullPath.includes("columns")) return;
32817
32818        // FIND THE MAIN CONTENT AREA TO IDENTIFY THE CORRECT EDITBAR
32819        var $ph = $row.find('[class*="cq-placeholder-main-content-area"]').first();
32820        if (!$ph.length) return;
32821
32822        // EXTRACT THE TARGET CLASS FROM THE PLACEHOLDER
32823        var match = $ph.attr("class").match(/(main-content-area(?:_[^_]+)*_47columns(?:_\d+)?)_47column[^_]*$/);
32824        if (!match) return;
32825
32826        var targetClass = "cq-element-" + match[1];
32827        var $editbar = $(".cq-editbar." + targetClass);
32828        if (!$editbar.length) return;
32829
32830        // FIND THE PASTE BUTTON TO INSERT AFTER
32831        var $pasteCell = $editbar.find("button:contains('Paste')").closest("td.x-toolbar-cell").last();
32832        if (!$pasteCell.length) return;
32833
32834        // CREATE THE BUTTON
32835        var $btn = $('<td class="x-toolbar-cell">' +
32836            '<table cellspacing="0" class="x-btn x-btn-noicon" style="width:auto;">' +
32837            '<tbody class="x-btn-small x-btn-icon-small-left">' +
32838            '<tr><td class="x-btn-tl"><i></i></td><td class="x-btn-tc"></td><td class="x-btn-tr"><i></i></td></tr>' +
32839            '<tr>' +
32840            '<td class="x-btn-ml"><i></i></td>' +
32841            '<td class="x-btn-mc">' +
32842            '<em unselectable="on">' +
32843            '<button type="button" class="x-btn-text lock-toggle-btn" style="color:#d00;font-weight:bold;padding:0 12px;">' +
32844            'Loading...' +
32845            '</button>' +
32846            '</em>' +
32847            '</td>' +
32848            '<td class="x-btn-mr"><i></i></td>' +
32849            '</tr>' +
32850            '<tr><td class="x-btn-bl"><i></i></td><td class="x-btn-bc"></td><td class="x-btn-br"><i></i></td></tr>' +
32851            '</tbody>' +
32852            '</table>' +
32853            '</td>');
32854
32855        // INSERT THE BUTTON
32856        $pasteCell.after($btn);
32857        $row.data("lock-added", true);
32858
32859        var isLocked = false;
32860
32861        // READ STATE FROM SERVLET
32862        $.get(SERVLET_URL, { path: fullPath })
32863            .done(function (data) {
32864                isLocked = data.locked === true;
32865                $row.toggleClass("column-locked", isLocked);
32866                updateLockBtnUI($btn.find(".lock-toggle-btn"), isLocked);
32867
32868                // Apply to parent column control
32869                updateButtonStates(isLocked, $editbar);
32870
32871                if (isLocked) {
32872                    applyEditBarRestrictions($row, true);
32873                    // CHILD: apply same restrictions to all child editbars on load
32874                    applyToChildren($editbar, true);
32875                }
32876            })
32877            .fail(function () {
32878                $btn.find(".lock-toggle-btn").text("Error");
32879            });
32880
32881        // CLICK HANDLER
32882        $btn.find(".lock-toggle-btn").on("click", function () {
32883            var newLocked = !isLocked;
32884            var payload = { "_charset_": "utf-8" };
32885            payload[newLocked ? "./" + LOCK_PROPERTY : "./" + LOCK_PROPERTY + "@Delete"] = "true";
32886
32887            // SEND UPDATE TO SERVLET
32888            $.post(fullPath, payload)
32889                .done(function () {
32890                    isLocked = newLocked;
32891                    $row.toggleClass("column-locked", isLocked);
32892                    updateLockBtnUI($btn.find(".lock-toggle-btn"), isLocked);
32893
32894                    // Apply to parent column control
32895                    updateButtonStates(isLocked, $editbar);
32896                    applyEditBarRestrictions($row, isLocked);
32897
32898                    // CHILD: apply the same jQuery + OOTB restrictions to every
32899                    // child component editbar inside this column control
32900                    applyToChildren($editbar, isLocked);
32901                })
32902                .fail(function () {
32903                    $btn.find(".lock-toggle-btn").text("Error");
32904                });
32905        });
32906    }
32907
32908    // -------------------------------------------------------------------------
32909    // APPLY RESTRICTIONS TO ALL CHILD EDITBARS
32910    //
32911    // When a Column Control is locked, child components must remain EDITABLE
32912    // but must NOT be movable. So unlike the parent, we deliberately do NOT
32913    // disable the child Edit/Delete buttons — we only restrict movement by
32914    // disabling the drag handle and suspending the drop targets.
32915    // -------------------------------------------------------------------------
32916
32917    function applyToChildren($parentEditbar, locked) {
32918        var $children = findChildEditbars($parentEditbar);
32919        $children.each(function () {
32920            var $childEditbar = $(this);
32921
32922            // NOTE: Intentionally NOT calling updateButtonStates()/
32923            // setEditBarButtonStates() here so that Edit (and Delete) stay
32924            // enabled on child components even while the column is locked.
32925            // Ensure any previously disabled buttons are re-enabled.
32926            updateButtonStates(false, $childEditbar);
32927
32928            // Get the live CQ.Ext component instance directly from the child
32929            // editbar's DOM id using CQ.Ext.getCmp(id).
32930            var childDomId = $childEditbar.attr("id");
32931            if (!childDomId) return;
32932
32933            var childCmp = CQ.Ext.getCmp(childDomId);
32934            if (!childCmp) return;
32935
32936            // Keep the OOTB Edit/Delete buttons enabled on children.
32937            setEditBarButtonStates(childCmp, false);
32938
32939            // Restrict ONLY movement: disable drag handle and drop targets so
32940            // the child cannot be moved while the column control is locked.
32941            if (locked) {
32942                if (typeof childCmp.disableDrag === "function") {
32943                    childCmp.disableDrag();
32944                }
32945                if (typeof childCmp.suspendDropTargets === "function") {
32946                    childCmp.suspendDropTargets();
32947                }
32948            } else {
32949                if (typeof childCmp.enableDrag === "function") {
32950                    childCmp.enableDrag();
32951                }
32952                if (typeof childCmp.resumeDropTargets === "function") {
32953                    childCmp.resumeDropTargets();
32954                }
32955            }
32956        });
32957    }
32958
32959    // Update lock states
32960    function updateLockStates() {
32961        var $rows = $(COMBINED_SELECTOR);
32962        $rows.each(function () {
32963            var $row = $(this);
32964            var $editbar = findEditbarForRow($row);
32965            if (!$editbar) return;
32966
32967            var isLocked = $row.hasClass("column-locked");
32968
32969            // Parent column control
32970            updateButtonStates(isLocked, $editbar);
32971            applyEditBarRestrictions($row, isLocked);
32972
32973            // Children inside this column control
32974            applyToChildren($editbar, isLocked);
32975        });
32976    }
32977
32978    // -------------------------------------------------------------------------
32979    // SCAN - existing logic, enhanced with combined selector from registry
32980    // -------------------------------------------------------------------------
32981
32982    // -------------------------------------------------------------------------
32983    // SCAN WITH RETRY - keeps retrying until all rows have lock buttons
32984    // -------------------------------------------------------------------------
32985
32986    var MAX_RETRY_TIME = 30000; // 30 seconds max
32987    var RETRY_INTERVAL = 2000;  // retry every 2 seconds
32988    var _retryTimer = null;
32989    var _retryStart = null;
32990
32991    function scan() {
32992        var $rows = $(COMBINED_SELECTOR);
32993        var allAdded = true;
32994
32995        $rows.each(function () {
32996            var $row = $(this);
32997            if (!$row.data("lock-added")) {
32998                var $parentColumn = $row.closest(".columns");
32999                addLockButton($row, $parentColumn);
33000                if (!$row.data("lock-added")) {
33001                    allAdded = false;
33002                }
33003            }
33004        });
33005
33006        // If some rows didn't get their button, retry
33007        if (!allAdded && $rows.length > 0) {
33008            if (!_retryStart) _retryStart = Date.now();
33009            if (Date.now() - _retryStart < MAX_RETRY_TIME) {
33010                clearTimeout(_retryTimer);
33011                _retryTimer = setTimeout(scan, RETRY_INTERVAL);
33012            }
33013        } else {
33014            _retryStart = null;
33015        }
33016    }
33017
33018    // -------------------------------------------------------------------------
33019    // MUTATION OBSERVER — scoped to editbar containers, debounced
33020    // -------------------------------------------------------------------------
33021
33022    var _mutationDebounceTimer = null;
33023
33024    var observer = new MutationObserver(function (mutations) {
33025        var relevant = mutations.some(function (m) {
33026            return m.target && (m.target.className || "").indexOf("cq-editbar") !== -1;
33027        });
33028        if (!relevant) return;
33029
33030        clearTimeout(_mutationDebounceTimer);
33031        _mutationDebounceTimer = setTimeout(function () {
33032            updateLockStates();
33033        }, 250);
33034    });
33035    observer.observe(document.body, { childList: true, subtree: true });
33036
33037    // UPDATE LOCK STATES ON EDITBAR CLICK (scoped to editbars only)
33038    $(document).on("click", ".cq-editbar", function () {
33039        updateLockStates();
33040    });
33041
33042    // INITIALIZE (existing)
33043    $(document).ready(scan);
33044
33045    // RE-SCAN ON EDITOR EVENTS (existing)
33046    $(document).on("cq-editables-loaded cq-layer-activated foundation-contentloaded", function () {
33047        setTimeout(scan, 500);
33048    });
33049
33050    // ADDITIONAL SCAN AS FALLBACK
33051    setTimeout(scan, 2000);
33052
33053})(jQuery);
33054
33055
33056(function ($) {
33057  // ---- helpers: read dataset keys in both formats and normalize tag strings ----
33058  function val(el, k1, k2) {
33059    // read dataset in either camelCase or kebab-case data-*
33060    return el.dataset[k1] || el.dataset[k2] || "";
33061  }
33062  function normalizeTags(raw) {
33063    // Turn "[regions:fl, regions:fl/tampa]" OR "regions:fl,regions:fl/tampa" -> "regions:fl,regions:fl/tampa"
33064    if (!raw) return "";
33065    return String(raw).replace(/[\[\]\s]/g, "").trim();
33066  }
33067
33068  // ---- core: resolve latest article link for a single image component ----
33069  function resolveLatestForImage(container) {
33070    try {
33071      var $container = $(container);
33072      var $anchor = $container.find('a.dynamic-article-url').first();
33073      if (!$anchor.length) return;
33074
33075      var $src = $container.find('.js-latest-article-source').first();
33076      if (!$src.length) return;
33077
33078      // read tags and params from data-*; accept both existing and new names
33079      var required = normalizeTags(val($src[0], 'requiredtags', 'reqTags'));
33080      var optional = normalizeTags(val($src[0], 'optionaltags', 'optTags'));
33081      var excluded = normalizeTags(val($src[0], 'excludedtags', 'exTags'));
33082      var rootPath = val($src[0], 'rootPath', 'rootPath') || "/content/news/stories";
33083      var daysLimit = val($src[0], 'dayslimit', 'dayslimit') || "";
33084      var tz = val($src[0], 'dayslimittimezone', 'dayslimittimezone') || "";
33085
33086      // Build URI exactly like dynamic list service does
33087      var uri = '/services/ms/articles'
33088        + '?reqTags=' + encodeURIComponent(required)
33089        + '&optTags=' + encodeURIComponent(optional)
33090        + '&exTags=' + encodeURIComponent(excluded)
33091        + '&path=' + encodeURIComponent(rootPath)
33092        + (daysLimit ? '&daysLimit=' + encodeURIComponent(daysLimit) : '')
33093        + (tz ? '&daysLimitTimezone=' + encodeURIComponent(tz) : '');
33094
33095      var startTime = Date.now();
33096      $.ajax({ url: uri, dataType: 'json' })
33097        .done(function (data, textStatus, jqXHR) {
33098          News.ContentList.ajaxLoadFinished(container, data);
33099          try {
33100            var articles = (data && data.articles) ? data.articles : [];
33101            // filter out current page same as content list
33102            if (News && News.ContentList && typeof News.ContentList.currentArticleExcludeFilter === 'function') {
33103              articles = $(articles).filter(News.ContentList.currentArticleExcludeFilter);
33104            }
33105
33106            if (articles.length > 0) {
33107              var first = articles[0];
33108              var url = first.url;
33109              if(News.ContentList.authorMode) {url = url + ".html";}
33110              $anchor.attr('href', url).attr('data-dynamic-href', 'true');
33111            }
33112
33113            // optional analytics hook if present
33114            if (News && News.App && News.App.QuantumAnalytics && typeof News.App.QuantumAnalytics.quantumApiSuccessOrFailure === 'function') {
33115              News.App.QuantumAnalytics.quantumApiSuccessOrFailure(uri, jqXHR.status, "All_Generic_API_Call_Success", startTime, "GET", "", "", jqXHR);
33116            }
33117          } catch (e) {
33118            // swallow to avoid author breakage
33119          }
33120        })
33121        .fail(function (jqXHR) {
33122          // optional analytics
33123          if (News && News.App && News.App.QuantumAnalytics && typeof News.App.QuantumAnalytics.quantumApiSuccessOrFailure === 'function') {
33124            var msg = (News.App.QuantumAnalytics.extractAjaxErrorMessage) ? News.App.QuantumAnalytics.extractAjaxErrorMessage(jqXHR) : '';
33125            News.App.QuantumAnalytics.quantumApiSuccessOrFailure(uri, jqXHR.status, "All_Generic_API_Call_Failure", startTime, "GET", "", msg, jqXHR);
33126          }
33127        });
33128    } catch (ex) {
33129      // no-op
33130    }
33131  }
33132
33133  // ---- init ----
33134
33135  $(function () {
33136    $('.image').each(function () {
33137      var hasDynamic = $(this).find('a.dynamic-article-url').length > 0;
33138      if (hasDynamic) resolveLatestForImage(this);
33139    });
33140  });
33141
33142})(jQuery);
33143

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.